diff --git a/Cargo.lock b/Cargo.lock index 1827dde7d99..cc4fcc365e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -357,6 +357,7 @@ dependencies = [ "cargo_toml", "crates-index", "env_logger", + "git-lock", "git-repository", "log", "semver 1.0.4", @@ -1068,7 +1069,7 @@ version = "0.0.0" [[package]] name = "git-lock" -version = "0.3.2" +version = "1.0.0" dependencies = [ "fastrand", "git-tempfile", @@ -1225,7 +1226,7 @@ dependencies = [ [[package]] name = "git-tempfile" -version = "0.6.1" +version = "1.0.0" dependencies = [ "dashmap", "libc", @@ -1609,7 +1610,7 @@ dependencies = [ [[package]] name = "lock_api" version = "0.4.4" -source = "git+https://github.com/Amanieu/parking_lot?branch=master#6bbf522dfe8c458909f8683b3f4b558b03e58b65" +source = "git+https://github.com/Amanieu/parking_lot?branch=master#c866ba80e4c38b0119823ab93f822f8e9dae2ce7" dependencies = [ "scopeguard", ] @@ -1859,7 +1860,7 @@ dependencies = [ [[package]] name = "parking_lot" version = "0.11.1" -source = "git+https://github.com/Amanieu/parking_lot?branch=master#6bbf522dfe8c458909f8683b3f4b558b03e58b65" +source = "git+https://github.com/Amanieu/parking_lot?branch=master#c866ba80e4c38b0119823ab93f822f8e9dae2ce7" dependencies = [ "instant", "lock_api 0.4.4 (git+https://github.com/Amanieu/parking_lot?branch=master)", @@ -1883,7 +1884,7 @@ dependencies = [ [[package]] name = "parking_lot_core" version = "0.8.3" -source = "git+https://github.com/Amanieu/parking_lot?branch=master#6bbf522dfe8c458909f8683b3f4b558b03e58b65" +source = "git+https://github.com/Amanieu/parking_lot?branch=master#c866ba80e4c38b0119823ab93f822f8e9dae2ce7" dependencies = [ "cfg-if", "instant", diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 0bd1ed58659..9abdd166392 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -4,24 +4,17 @@ * **test-first development** * protect against regression and make implementing features easy. - * user docker to test more elaborate user interactions + * user containers to test more elaborate user interactions * keep it practical, knowing the Rust compiler already has your back for the mundane things, like unhappy code paths. * *use git itself* as reference implementation, and use their test-cases and fixtures where - appropriate. - * *use libgit2* test fixtures and cases where appropriate. + appropriate. At the very least, try to learn from them. + * *use libgit2* test fixtures and cases where appropriate, or learn from them. * **safety first** * handle all errors, never `unwrap()`. If needed, `expect("why")`. - * provide an error chain and make it easy to understand what went wrong. - * **strive for an MVP and version 1.0 fast...** - * ...even if that includes only the most common usecases. - * **Prefer to increment major version rapidly...** - * ...instead of keeping major version zero for longer than needed. - * **stability** - * we adhere to semantic versioning - * while below 1.0, expect a greater amount of breaking changes, which are announced with minor versions - * From 1.0, we will try hardest to keep the API and user interface non-breaking the closer to the user a library is. Thus the CLI should remain at version - 1 for a long time. However, crates that make it up can change more rapidly and may see more major version changes over time. + * provide an error chain and make it easy to understand what went wrong. We use `quick-error` for non-generic errors and `thiserror` when generalization is + needed. + * Adhere to the [stability guide](https://github.com/Byron/gitoxide/blob/main/STABILITY.md) ## General diff --git a/LICENSE-APACHE b/LICENSE-APACHE index f12440887db..a51f59a06c9 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -176,7 +176,7 @@ END OF TERMS AND CONDITIONS - Copyright 2020 Sebastian Thiel + Copyright 2018-2021 Sebastian Thiel, and [contributors](https://github.com/byron/gitoxide/contributors) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 73fc000ff58..b58e818f138 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2020 Sebastian Thiel, and [others](https://github.com/byron/gitoxide/contributors). +Copyright (c) 2018-2021 Sebastian Thiel, and [contributors](https://github.com/byron/gitoxide/contributors). Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 07b30dd2522..f1148bb024d 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,14 @@ check: ## Build all code in suitable configurations && cargo check --features async-client cd git-protocol && if cargo check --all-features 2>/dev/null; then false; else true; fi cd git-repository && cargo check --all-features \ + && cargo check --no-default-features --features local \ + && cargo check --no-default-features --features network \ && cargo check --no-default-features + cd cargo-smart-release && cargo check + cd experiments/object-access && cargo check + cd experiments/diffing && cargo check + cd experiments/traversal && cargo check + cd experiments/hash-owned-borrowed && cargo check unit-tests: ## run all unit tests cargo test --all diff --git a/README.md b/README.md index 9d67d343aaf..0e758dfbd48 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,15 @@ Please see _'Development Status'_ for a listing of all crates and their capabili ### Crates -Follow linked crate name for detailed status. +Follow linked crate name for detailed status. Please note that all crates follow [semver] as well as the [stability guide]. +### Released + +* **Stability Tier 2** + - [git-tempfile](https://github.com/Byron/gitoxide/blob/main/git-tempfile/README.md) + - [git-lock](https://github.com/Byron/gitoxide/blob/main/git-lock/README.md) + +### In Development/Pre-Release * **usable** * [git-actor](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-actor) * [git-hash](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-hash) @@ -66,9 +73,8 @@ Follow linked crate name for detailed status. * [git-traverse](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-traverse) * [git-config](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-config) * [git-features](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-features) - * [git-tempfile](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-tempfile) - * [git-lock](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-lock) * [git-ref](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-ref) + * `gitoxide-core` * **very early** * [git-repository](https://github.com/Byron/gitoxide/blob/main/crate-status.md#git-repository) * **idea** @@ -83,39 +89,18 @@ Follow linked crate name for detailed status. * [x] Generate and verify large commit graphs * [ ] Generate huge pack from a lot of loose objects -### Ideas for Examples - - * [ ] `gix tool open-remote` open the URL of the remote, possibly after applying known transformations to go from `ssh` to `https`. - * [ ] Open up SQL for git using [sqlite virtual tables](https://github.com/rusqlite/rusqlite/blob/master/tests/vtab.rs). Check out gitqlite - as well. What would an MVP look like? Maybe even something that could ship with gitoxide. - * [ ] A truly awesome history rewriter which makes it easy to understand what happened while avoiding all pitfalls. Think BFG, but more awesome, if that's possible. - * [ ] `git-tui` should learn a lot from [fossil-scm] regarding the presentation of data. Maybe [this](https://github.com/Lutetium-Vanadium/requestty/) can be used for prompts. - * [ ] Can markdown be used as database so issue-trackers along with meta-data could just be markdown files which are mostly human-editable? Could user interfaces - be meta-data aware and just hide the meta-data chunks which are now editable in the GUI itself? Doing this would make conflicts easier to resolve than an `sqlite` - database. - * ~~A git-backend for `sqlite` which should allow embedding sqlite databases into git repositories, which in turn can be used for bug-trackers, wikis or other - features, making for a fully distributed github like experience, maybe.~~ - -### Ideas for Spin-Offs - -* [ ] A system to integrate tightly with `git-lfs` to allow a multi-tier architecture so that assets can be stored in git and are accessible quickly from an intranet location - (for example by accessing the storage read-only over the network) while changes are pushed immediately by the server to other edge locations, like _the cloud_ or backups. Sparse checkouts along with explorer/finder integrations - make it convenient to only work on a small subset of files locally. Clones can contain all configuration somebody would need to work efficiently from their location, - and authentication for the git history as well as LFS resources make the system secure. One could imagine encryption support for untrusted locations in _the cloud_ - even though more research would have to be done to make it truly secure. -* [ ] A [syncthing] like client/server application. This is to demonstrate how lower-level crates can be combined into custom applications that use - only part of git's technology to achieve their very own thing. Watch out for big file support, multi-device cross-syncing, the possibility for - untrusted destinations using full-encryption, case-insensitive and sensitive filesystems, and extended file attributes as well as ignore files. - -[syncthing]: https://github.com/syncthing/syncthing -[fossil-scm]: https://www.fossil-scm.org - ### Cargo features Many crates use feature flags to allow tuning the compiled result based on your needs. Have a [look at the guide][cargo-features] for more information. [cargo-features]: https://github.com/Byron/gitoxide/blob/main/cargo-features.md#git-config +### Stability + +Our [stability guide] helps to judge how much churn can be expected when depending on crates in this workspace. + +[stability guide]: https://github.com/Byron/gitoxide/blob/main/STABILITY.md + ## Installation ### Download a Binary Release @@ -208,7 +193,7 @@ Project non-goals can change over time as we learn more, and they can be challen long running operations. * When connecting or streaming over TCP connections, especially when receiving on the server, async seems like a must though, but behind a feature flag. - + ## Contributions If what you have seen so far sparked your interest to contribute, then let us say: We are happy to have you and help you to get started. @@ -218,6 +203,9 @@ We recommend running `make tests check-size` during the development process to a A backlog for work ready to be picked up is [available in the Project's Kanban board][project-board], which contains instructions on how to pick a task. If it's empty or you have other questions, feel free to [start a discussion][discussions] or reach out to @Byron [privately][keybase]. +For additional details, also take a look at the [collaboration guide]. + +[collaboration guide]: https://github.com/Byron/gitoxide/blob/main/COLLABORATING.md [project-board]: https://github.com/Byron/gitoxide/projects [discussions]: https://github.com/Byron/gitoxide/discussions [keybase]: https://keybase.io/byronbates @@ -234,7 +222,34 @@ Provide a CLI to for the most basic user journey: * [ ] add a remote * [ ] push * [ ] create (thin) pack - + +### Ideas for Examples + +* [ ] `gix tool open-remote` open the URL of the remote, possibly after applying known transformations to go from `ssh` to `https`. +* [ ] Open up SQL for git using [sqlite virtual tables](https://github.com/rusqlite/rusqlite/blob/master/tests/vtab.rs). Check out gitqlite + as well. What would an MVP look like? Maybe even something that could ship with gitoxide. +* [ ] A truly awesome history rewriter which makes it easy to understand what happened while avoiding all pitfalls. Think BFG, but more awesome, if that's possible. +* [ ] `git-tui` should learn a lot from [fossil-scm] regarding the presentation of data. Maybe [this](https://github.com/Lutetium-Vanadium/requestty/) can be used for prompts. +* [ ] Can markdown be used as database so issue-trackers along with meta-data could just be markdown files which are mostly human-editable? Could user interfaces + be meta-data aware and just hide the meta-data chunks which are now editable in the GUI itself? Doing this would make conflicts easier to resolve than an `sqlite` + database. + * ~~A git-backend for `sqlite` which should allow embedding sqlite databases into git repositories, which in turn can be used for bug-trackers, wikis or other + features, making for a fully distributed github like experience, maybe.~~ + +### Ideas for Spin-Offs + +* [ ] A system to integrate tightly with `git-lfs` to allow a multi-tier architecture so that assets can be stored in git and are accessible quickly from an intranet location + (for example by accessing the storage read-only over the network) while changes are pushed immediately by the server to other edge locations, like _the cloud_ or backups. Sparse checkouts along with explorer/finder integrations + make it convenient to only work on a small subset of files locally. Clones can contain all configuration somebody would need to work efficiently from their location, + and authentication for the git history as well as LFS resources make the system secure. One could imagine encryption support for untrusted locations in _the cloud_ + even though more research would have to be done to make it truly secure. +* [ ] A [syncthing] like client/server application. This is to demonstrate how lower-level crates can be combined into custom applications that use + only part of git's technology to achieve their very own thing. Watch out for big file support, multi-device cross-syncing, the possibility for + untrusted destinations using full-encryption, case-insensitive and sensitive filesystems, and extended file attributes as well as ignore files. + +[syncthing]: https://github.com/syncthing/syncthing +[fossil-scm]: https://www.fossil-scm.org + ## Shortcomings diff --git a/STABILITY.md b/STABILITY.md new file mode 100644 index 00000000000..fd3e2b4b779 --- /dev/null +++ b/STABILITY.md @@ -0,0 +1,138 @@ +# Stability + +Even though this project adheres to [semver], this guide aims to explain how semantic versioning is used exactly and how we aim to provide stability within an +ever-changing codebase. + +Please note that this guide isn't stable itself and may be adjusted to fit changes in requirements or new ways are discovered. + +## Terminology + +* _dependent crate_ + - A crate which depends on a crate in this workspace directly. +* _downstream crate_ + - A crate which directly or indirectly depends on a crate in this workspace. +* _workspace crate_ + - A crate which is a member of this workspace and hence is stored in this repository +* _breaking change_ + - A change in code that requires a `dependent crate` to adjust their code to fix compile errors. +* _release_ + - A new version of a crate is published to crates.io +* _development version_ + - A crate version whose _major_ version is 0. +* _release version_ + - A crate version whose _major_ version is 1 or higher. + +## Tiers + +The project uses three stability tiers for all of its crates, and all crates use [semver] for their version numbers. +Tiers differ primarily in the time between breaking changes, which always have to be announced with `PRs` as per +our [collaboration guide]. + +The following schematic helps to visualize what follows. + +``` + Release Software v1.X + Stability Tier 1 ═════════════════════════════╗ + ║ ║ + ║ gixp─────────────┐ gix──────────────┐ ║ + ║ │ plumbing app │ │ porcelain app │ ║ + ║ └────────────────┘ └────────────────┘ ║ + ║ │ │ ║ + ║ ▼ ▼ ║ + ║ gitoxide-core───────────────────────┐ ║ + ║ │ application functionality │ ║ + ║ └───────────────────────────────────┘ ║ + ║ │ ║ + ║ ▼ ║ + ║ git-repository──────────────────────┐ ║ + ║ │ application crate │─ ─ ╬ ─ + ║ └───────────────────────────────────┘ ║ │ + ║ │ ║ + ║ ▼ ║ │ + ║ Foundation Crates───────────────────┐ ║ + ║ │ ┌─────────────┐ ┌─────────────┐ │ ║ │ + ║ │ │ git-hash │ │ git-actor │ │ ║ + ║ │ └─────────────┘ └─────────────┘ │ ║ │ + ║ │ ┌─────────────┐ ┌─────────────┐ │ ║ + ║ │ │ git-ref │ │ git-config │ │ ║ │ + ║ │ └─────────────┘ └─────────────┘ │ ║ + ║ └───────────────────────────────────┘ ║ │ + ║ ║ + ╚═════════════════════════════════════════════╝ │ + Stability Tier 2 ─────────────────────────────┐ + │ │ │ + │ Plumbing Crates─────────────────────┐ │ + │ │ ┌─────────────┐ ┌─────────────┐ │ │ │ + │ │ │ git-odb │ │ git-diff │ │ │ + │ │ └─────────────┘ └─────────────┘ │ │ │ + │ │ ┌─────────────┐ ┌─────────────┐ │ │ + │ │ │git-traverse │ │ git-pack │ │◀─ ─│─ ┘ + │ │ └─────────────┘ └─────────────┘ │ │ + │ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ + │ │ …many more… │ │ + │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ + │ └───────────────────────────────────┘ │ + │ │ + └─────────────────────────────────────────────┘ +``` + +### Tier 3: pre-release crates + +Pre-release crates is marked with major version number zero, for example `0.1.4` and lives in stability tier 3 _(->ST3)_. + +It's acceptable to let each breaking change be immediately followed by a minor version release. + +### Tier 2: released plumbing crates + +Released plumbing crates are marked with major version number 1 or above, for example `1.2.4` and live in stability tier 2 _(->ST2)_. + +Breaking changes are collected and may be released no more often than every 4 weeks by incrementing the major version number. + +For example, `git-odb` and `git-ref` both have breaking changes, where `git-odb`'s change is on August 1st and `git-ref`'s dependent change +is on September 10th. `git-odb`'s breaking change can be released earliest on September 1st, whereas `git-ref` can be released earliest at October 10th. + +If there are additional breaking changes without a release, these push back the earliest release date accordingly. + +### Tier 1: released apps and application crates + +Released apps and application crates are marked with major version number 1 or above, like `2.3.0+21.06` and live in tier 1 _(->ST1)_, +with the build identifiers for year (`21`) and and month `06` appended, based on the actual release year and month. + +Breaking changes are collected and may be released no more often than every 6 months by incrementing the major version number. If there are additional breaking changes, +these push bac the release date so that they can be tested at least for 3 months. For example, a breaking change happens in January 01, and another breaking change in February 15. +The earliest release date is July 1st. Had the second breaking change happened in April 01, the release date would have to be pushed to August 1st. + +Intermediate pre-releases may be created at most every 4 weeks by appending `-alpha.X` where `X` is the sequential release number. These should help testing +breaking changes or new features without forcing the use of `git` sources for dependencies in cargo manifests. Pre-release releases must pin all the pre-release +crates they depend on to prevent automatic upgrades. Dependent external crates are advised to pin their `alpha` dependencies with `=` version requirements to avoid +automatic updates which may be breaking. + +Once breaking changes are known to be planned, deprecation warnings should be provided in intermediate pre-releases. + +Minor version updates for new features can be released when needed assuming there are no other breaking changes, updating the build identifiers for year and month accordingly. + +## The _Minimal Stable Rust Version_ (->MSRV) + +The MSRV is automatically assumed to be the latest stable version. + +Increasing the MSRV is not considered a breaking change and doesn't warrant a major version bump itself. + +Please let us know if you have other requirement and we see if we can provide stability guarantees for it or reduce the MSRV to a given version. + +## Transitioning from pre-release to release crates + +How do we avoid staying in pre-release mode forever? + +There is only two questions to ask and answer positively: + +- _Does the crate fulfill its intended purpose well enough?_ +- _Do the dependent workspace crates fulfill their intended purposes well enough?_ + +For plumbing crates, the intended purpose is narrow which would allow them to transition earlier. For plumbing crates, if in doubt or fear of future requirements +especially if dependent crates are still early in development, prefer to release them anyway and live with requirements of _ST2_. + +Apps and application crates may take longer as they are larger in scope. A good indicator for them to get to a release may be maturing plumbing crates they +use. Their scope shoud also be narrowed to a minimal viable product. + +[semver]: https://semver.org +[collaboration guide]: https://github.com/Byron/gitoxide/blob/main/COLLABORATING.md diff --git a/cargo-features.md b/cargo-features.md index 4b3b2879108..cc4adb2ebf7 100644 --- a/cargo-features.md +++ b/cargo-features.md @@ -177,6 +177,20 @@ be selected. details information about the error location will be collected. - Use it in applications which expect broken or invalid objects or for debugging purposes. Incorrectly formatted objects aren't at all common otherwise. + +### git-repository + +* **unstable** + - Re-export stability tier 2 crates for convenience and make `Repository` struct fields with types from these crates publicly accessible. + - Doing so is less stable than the stability tier 1 that `git-repository` is a member of. + +The following toggles can be used to reduce dependencies. + +* **local** + - Provide additional non-networked functionality +* **network** + - Provide networked functionality +* **one-stop-shop** = _local_ + _network_ ### Serialization Support diff --git a/cargo-smart-release/Cargo.toml b/cargo-smart-release/Cargo.toml index 7725ffc434b..89fd6524bfa 100644 --- a/cargo-smart-release/Cargo.toml +++ b/cargo-smart-release/Cargo.toml @@ -13,6 +13,7 @@ keywords = ["cargo"] [dependencies] git-repository = { version = "^0.7", path = "../git-repository" } +git-lock = { version ="^1.0.0", path = "../git-lock" } anyhow = "1.0.42" argh = { version = "0.1.5", default-features = false } env_logger = { version = "0.9.0", default-features = false, features = ["humantime", "termcolor", "atty"] } diff --git a/cargo-smart-release/README.md b/cargo-smart-release/README.md index 3f4e29b0528..1418a559225 100644 --- a/cargo-smart-release/README.md +++ b/cargo-smart-release/README.md @@ -32,6 +32,7 @@ instructions, one should end up with a fully automatic release of multiple crate * [x] automatically release dependent workspace pre-release crates along with the desired one if they changed since their last release * [x] automatically adjust manifest versions and update manifests of crates which use those whose versions were incremented * [x] use git tags to know if a crate changed at all, skipping publishes if there is no code change at all +* [ ] Handle pre-release versions and meta-data as per the [stability guide]. * [ ] Support other remote names than 'origin' - currently the latter name is assumed. Fix by getting the remote of the currently checked out branch. * [ ] handle version specifications correctly [(tables vs values)](https://github.com/Byron/cargo-release/blob/master/src/cargo.rs#L179:L207) * [ ] handle all version comparators correctly (see [here](https://github.com/Byron/cargo-release/blob/master/src/version.rs#L192:L226) for how it's done) @@ -64,3 +65,4 @@ Thanks to [cargo-release] for showing the way and for incredible fast response t [cargo-release]: https://github.com/sunng87/cargo-release/issues/224 [rustup]: https://rustup.rs/ +[stability guide]: https://github.com/Byron/gitoxide/blob/stability/STABILITY.md diff --git a/cargo-smart-release/src/command/release/git.rs b/cargo-smart-release/src/command/release/git.rs index 1de1427c44b..0e8407a3625 100644 --- a/cargo-smart-release/src/command/release/git.rs +++ b/cargo-smart-release/src/command/release/git.rs @@ -6,16 +6,10 @@ use cargo_metadata::{ camino::{Utf8Component, Utf8Path}, Package, }; -use git_repository::{ - easy::object, - hash::ObjectId, - lock, - prelude::ReferenceAccessExt, - refs::{self, file::loose::reference::peel}, -}; +use git_repository::easy::object; -use super::{Context, Options}; -use crate::command::release_impl::{tag_name_for, utils::will}; +use super::{tag_name_for, utils::will, Context, Oid, Options}; +use git_repository::{prelude::ReferenceAccessExt, refs}; fn is_top_level_package(manifest_path: &Utf8Path, shared: &git_repository::Easy) -> bool { manifest_path @@ -53,8 +47,8 @@ pub(in crate::command::release_impl) fn has_changed_since_last_release( .strip_prefix(&ctx.root) .expect("workspace members are releative to the root directory"); - let current_commit = ctx.git_easy.find_reference("HEAD")?.peel_to_object_in_place()?; - let released_target = tag_ref.peel_to_object_in_place()?; + let current_commit = ctx.git_easy.find_reference("HEAD")?.peel_to_oid_in_place()?; + let released_target = tag_ref.peel_to_oid_in_place()?; if repo_relative_crate_dir.as_os_str().is_empty() { Ok(current_commit != released_target) @@ -116,7 +110,7 @@ pub(in crate::command::release_impl) fn commit_changes( dry_run: bool, empty_commit_possible: bool, ctx: &Context, -) -> anyhow::Result { +) -> anyhow::Result>> { // TODO: replace with gitoxide one day let mut cmd = Command::new("git"); cmd.arg("commit").arg("-am").arg(message.as_ref()); @@ -127,25 +121,20 @@ pub(in crate::command::release_impl) fn commit_changes( log::info!("{} run {:?}", will(dry_run), cmd); } if dry_run { - return Ok(ObjectId::null_sha1()); + return Ok(None); } if !cmd.status()?.success() { bail!("Failed to commit changed manifests"); } - let repo = &ctx.git_easy.repo; - Ok(repo - .refs - .loose_find_existing("HEAD")? - .peel_to_id_in_place(&repo.refs, ctx.packed_refs.as_ref(), peel::none)? - .to_owned()) + Ok(Some(ctx.git_easy.find_reference("HEAD")?.peel_to_oid_in_place()?)) } -pub(in crate::command::release_impl) fn create_version_tag( +pub(in crate::command::release_impl) fn create_version_tag<'repo>( publishee: &Package, new_version: &str, - commit_id: ObjectId, - ctx: &Context, + commit_id: Option>, + ctx: &'repo Context, Options { verbose, dry_run, @@ -167,9 +156,12 @@ pub(in crate::command::release_impl) fn create_version_tag( } Ok(Some(format!("refs/tags/{}", tag_name).try_into()?)) } else { - let edits = ctx - .git_easy - .tag(tag_name, commit_id, lock::acquire::Fail::Immediately, false)?; + let edits = ctx.git_easy.tag( + tag_name, + commit_id.expect("set in --execute mode"), + git_lock::acquire::Fail::Immediately, + false, + )?; assert_eq!(edits.len(), 1, "We create only one tag and there is no expansion"); let tag = edits.into_iter().next().expect("the promised tag"); log::info!("Created tag {}", tag.name.as_bstr()); diff --git a/cargo-smart-release/src/command/release/manifest.rs b/cargo-smart-release/src/command/release/manifest.rs index 6ce03d7886b..b6e9755f626 100644 --- a/cargo-smart-release/src/command/release/manifest.rs +++ b/cargo-smart-release/src/command/release/manifest.rs @@ -2,25 +2,27 @@ use std::{collections::BTreeMap, str::FromStr}; use anyhow::bail; use cargo_metadata::{Metadata, Package}; -use git_repository::{hash::ObjectId, lock}; use semver::{Op, Version, VersionReq}; use super::{ cargo, git, utils::{names_and_versions, package_by_id, package_eq_dependency, will}, - Context, Options, + Context, Oid, Options, }; -pub(in crate::command::release_impl) fn edit_version_and_fixup_dependent_crates( +pub(in crate::command::release_impl) fn edit_version_and_fixup_dependent_crates<'repo>( meta: &Metadata, publishees: &[(&Package, String)], Options { verbose, dry_run, .. }: Options, - ctx: &Context, -) -> anyhow::Result { + ctx: &'repo Context, +) -> anyhow::Result>> { let mut locks_by_manifest_path = BTreeMap::new(); for (publishee, _) in publishees { - let lock = - lock::File::acquire_to_update_resource(&publishee.manifest_path, lock::acquire::Fail::Immediately, None)?; + let lock = git_lock::File::acquire_to_update_resource( + &publishee.manifest_path, + git_lock::acquire::Fail::Immediately, + None, + )?; locks_by_manifest_path.insert(&publishee.manifest_path, lock); } let mut packages_to_fix = Vec::new(); @@ -39,9 +41,9 @@ pub(in crate::command::release_impl) fn edit_version_and_fixup_dependent_crates( if locks_by_manifest_path.contains_key(&package_to_fix.manifest_path) { continue; } - let lock = lock::File::acquire_to_update_resource( + let lock = git_lock::File::acquire_to_update_resource( &package_to_fix.manifest_path, - lock::acquire::Fail::Immediately, + git_lock::acquire::Fail::Immediately, None, )?; locks_by_manifest_path.insert(&package_to_fix.manifest_path, lock); diff --git a/cargo-smart-release/src/command/release/mod.rs b/cargo-smart-release/src/command/release/mod.rs index 10fada4a69f..19253ebb2da 100644 --- a/cargo-smart-release/src/command/release/mod.rs +++ b/cargo-smart-release/src/command/release/mod.rs @@ -2,13 +2,11 @@ use std::collections::BTreeSet; use anyhow::bail; use cargo_metadata::{camino::Utf8PathBuf, Dependency, DependencyKind, Metadata, Package, Version}; -use git_repository::refs::packed; use crate::command::release::Options; mod utils; use crates_index::Index; -use git_repository::hash::ObjectId; use utils::{ is_dependency_with_version_requirement, is_workspace_member, names_and_versions, package_by_id, package_by_name, package_eq_dependency, package_for_dependency, tag_name_for, will, workspace_package_by_id, @@ -18,12 +16,13 @@ mod cargo; mod git; mod manifest; +type Oid<'repo> = git_repository::easy::Oid<'repo, git_repository::Easy>; + pub(in crate::command::release_impl) struct Context { root: Utf8PathBuf, meta: Metadata, git_easy: git_repository::Easy, - packed_refs: Option, - index: Index, + crates_index: Index, crate_names: Vec, bump: String, bump_dependencies: String, @@ -34,14 +33,12 @@ impl Context { let meta = cargo_metadata::MetadataCommand::new().exec()?; let root = meta.workspace_root.clone(); let repo = git_repository::discover(&root)?; - let packed_refs = repo.refs.packed_buffer()?; let index = Index::new_cargo_default(); Ok(Context { root, git_easy: repo.into(), meta, - packed_refs, - index, + crates_index: index, crate_names, bump, bump_dependencies, @@ -57,14 +54,14 @@ pub fn release(options: Options, crates: Vec, bump: String, bump_depende } let mut ctx = Context::new(crates, bump, bump_dependencies)?; if options.update_crates_index { - log::info!("Updating crates-io index at '{}'", ctx.index.path().display()); - ctx.index.update()?; + log::info!("Updating crates-io index at '{}'", ctx.crates_index.path().display()); + ctx.crates_index.update()?; } else if !options.no_bump_on_demand { log::warn!( "Consider running with --update-crates-index to assure bumping on demand uses the latest information" ); } - if !ctx.index.exists() { + if !ctx.crates_index.exists() { log::warn!("Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already"); } @@ -172,7 +169,7 @@ fn perforrm_multi_version_release( .collect(); cargo::publish_crate(publishee, &unpublished_crates, options)?; - if let Some(tag_name) = git::create_version_tag(publishee, &new_version, commit_id, ctx, options)? { + if let Some(tag_name) = git::create_version_tag(publishee, &new_version, commit_id.clone(), ctx, options)? { tag_names.push(tag_name); }; } @@ -447,12 +444,12 @@ fn select_publishee_bump_spec<'a>(name: &String, ctx: &'a Context) -> &'a str { } } -fn perform_single_release( +fn perform_single_release<'repo>( meta: &Metadata, publishee: &Package, options: Options, - ctx: &Context, -) -> anyhow::Result<(String, ObjectId)> { + ctx: &'repo Context, +) -> anyhow::Result<(String, Option>)> { let bump_spec = select_publishee_bump_spec(&publishee.name, ctx); let new_version = bump_to_valid_version(publishee, bump_spec, ctx, options.no_bump_on_demand)?; log::info!( @@ -481,7 +478,7 @@ fn bump_to_valid_version( no_bump_on_demand: bool, ) -> anyhow::Result { let bump_on_demand = !no_bump_on_demand; - match ctx.index.crate_(&publishee.name) { + match ctx.crates_index.crate_(&publishee.name) { Some(existing_release) => { let existing_version = semver::Version::parse(existing_release.latest_version().version())?; if existing_version >= new_version { @@ -526,7 +523,7 @@ fn bump_to_valid_version( }; Ok(new_version) } - use semver::{BuildMetadata, Prerelease}; + use semver::Prerelease; let mut v = publishee.version.clone(); match bump_spec { @@ -534,18 +531,15 @@ fn bump_to_valid_version( v.major += 1; v.minor = 0; v.patch = 0; - v.build = BuildMetadata::EMPTY; v.pre = Prerelease::EMPTY; } "minor" => { v.minor += 1; v.patch = 0; - v.build = BuildMetadata::EMPTY; v.pre = Prerelease::EMPTY; } "patch" => { v.patch += 1; - v.build = BuildMetadata::EMPTY; v.pre = Prerelease::EMPTY; } "keep" => {} diff --git a/crate-status.md b/crate-status.md index 4322815bad7..a1cc3d6e5ae 100644 --- a/crate-status.md +++ b/crate-status.md @@ -214,26 +214,11 @@ Check out the [performance discussion][git-traverse-performance] as well. ### git-tempfile -Use tempfiles to minimize the risk of resource leakage when preparing to overwrite or create a file with new content -in a signal-safe way, making the change atomic. - -Tempfiles can also be used as locks as only one tempfile can exist at a given path at a time. - -* [x] registered temporary files which are deleted automatically as the process terminates or on drop - * [x] write to temorary file and persist it under new name - * [x] close temporary files to convert them into a marker while saving system resources - * [x] mark paths with a closed temporary file -* [x] persist temporary files to prevent them from perishing. -* [x] signal-handler integration with `git-repository` to clean lockfiles before the process is aborted. -* [x] use a temporary file transparently due thanks to implementations of `std::io` traits +See its [README.md](https://github.com/Byron/gitoxide/blob/main/git-tempfile/README.md). ### git-lock -Use lock-files in the way git does with auto-cleanup being the most notable feature. - -* [ ] writable lock files that can be committed to atomically replace the resource they lock -* [ ] read-only markers that lock a resource without the intend to overwrite it -* [ ] auto-removal of the lockfiles and intermediate directories on drop or on signal +See its [README.md](https://github.com/Byron/gitoxide/blob/main/git-lock/README.md). ### git-config * [ ] read diff --git a/etc/check-package-size.sh b/etc/check-package-size.sh index 2bc21c53703..d1f0c73e2e3 100755 --- a/etc/check-package-size.sh +++ b/etc/check-package-size.sh @@ -18,8 +18,8 @@ echo "in root: gitoxide CLI" indent cargo diet -n --package-size-limit 25KB (enter cargo-smart-release && indent cargo diet -n --package-size-limit 15KB) (enter git-actor && indent cargo diet -n --package-size-limit 5KB) -(enter git-tempfile && indent cargo diet -n --package-size-limit 12KB) -(enter git-lock && indent cargo diet -n --package-size-limit 7KB) +(enter git-tempfile && indent cargo diet -n --package-size-limit 20KB) +(enter git-lock && indent cargo diet -n --package-size-limit 15KB) (enter git-config && indent cargo diet -n --package-size-limit 55KB) (enter git-hash && indent cargo diet -n --package-size-limit 5KB) (enter git-features && indent cargo diet -n --package-size-limit 20KB) diff --git a/etc/crate-structure.monopic b/etc/crate-structure.monopic new file mode 100644 index 00000000000..768eb25b20d Binary files /dev/null and b/etc/crate-structure.monopic differ diff --git a/experiments/diffing/Cargo.toml b/experiments/diffing/Cargo.toml index 19d307bcb98..d30614936d4 100644 --- a/experiments/diffing/Cargo.toml +++ b/experiments/diffing/Cargo.toml @@ -9,7 +9,7 @@ publish = false [dependencies] anyhow = "1" -git-repository = { version = "^0.7", path = "../../git-repository" } +git-repository = { version = "^0.7", path = "../../git-repository", features = ["unstable"] } git2 = "0.13" rayon = "1.5.0" memory-lru = "0.1.0" diff --git a/experiments/object-access/Cargo.toml b/experiments/object-access/Cargo.toml index 8d946ec526c..24ba3eb6e0c 100644 --- a/experiments/object-access/Cargo.toml +++ b/experiments/object-access/Cargo.toml @@ -9,6 +9,6 @@ publish = false [dependencies] anyhow = "1" -git-repository = { version = "^0.7", path = "../../git-repository" } +git-repository = { version = "^0.7", path = "../../git-repository", features = ["unstable"] } git2 = "0.13" rayon = "1.5.0" diff --git a/experiments/traversal/Cargo.toml b/experiments/traversal/Cargo.toml index f9e79cecab9..0310860afaa 100644 --- a/experiments/traversal/Cargo.toml +++ b/experiments/traversal/Cargo.toml @@ -9,7 +9,7 @@ publish = false [dependencies] anyhow = "1" -git-repository = { version = "^0.7", path = "../../git-repository" } +git-repository = { version = "^0.7", path = "../../git-repository", features = ["unstable"] } git2 = "0.13" rayon = "1.5.0" dashmap = "4.0.2" diff --git a/git-lock/CHANGELOG.md b/git-lock/CHANGELOG.md new file mode 100644 index 00000000000..5a01336df2d --- /dev/null +++ b/git-lock/CHANGELOG.md @@ -0,0 +1,3 @@ +### 1.0 (2021-08-25) + +- initial release diff --git a/git-lock/Cargo.toml b/git-lock/Cargo.toml index ec0f2708f8d..81e85300bd3 100644 --- a/git-lock/Cargo.toml +++ b/git-lock/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "git-lock" -version = "0.3.2" +version = "1.0.0" repository = "https://github.com/Byron/gitoxide" license = "MIT/Apache-2.0" description = "A git-style lock-file implementation" authors = ["Sebastian Thiel "] edition = "2018" -include = ["src/**/*"] +include = ["src/**/*", "LICENSE-*", "README.md", "CHANGELOG.md"] [lib] doctest = false @@ -16,7 +16,7 @@ test = true [dependencies] fastrand = "1.5.0" -git-tempfile = { version = "^0.6.0", path = "../git-tempfile" } +git-tempfile = { version ="^1.0.0", path = "../git-tempfile" } quick-error = "2.0.0" [dev-dependencies] diff --git a/git-lock/LICENSE-APACHE b/git-lock/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/git-lock/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/git-lock/LICENSE-MIT b/git-lock/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/git-lock/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/git-lock/README.md b/git-lock/README.md new file mode 100644 index 00000000000..436b918effc --- /dev/null +++ b/git-lock/README.md @@ -0,0 +1,5 @@ +Use lock-files in the way git does with auto-cleanup being the most notable feature. + +* [x] writable lock files that can be committed to atomically replace the resource they lock +* [x] read-only markers that lock a resource without the intend to overwrite it +* [x] auto-removal of the lockfiles and intermediate directories on drop or on signal diff --git a/git-pack/Cargo.toml b/git-pack/Cargo.toml index 3a8d201ba4c..d6c236f702e 100644 --- a/git-pack/Cargo.toml +++ b/git-pack/Cargo.toml @@ -37,7 +37,7 @@ git-hash = { version = "^0.5.0", path = "../git-hash" } git-object = { version ="0.12.0", path = "../git-object" } git-traverse = { version ="0.7.0", path = "../git-traverse" } git-diff = { version ="0.8.0", path = "../git-diff" } -git-tempfile = { version = "^0.6.0", path = "../git-tempfile" } +git-tempfile = { version ="^1.0.0", path = "../git-tempfile" } smallvec = "1.3.0" filebuffer = "0.4.0" diff --git a/git-protocol/Cargo.toml b/git-protocol/Cargo.toml index 10f82a28a11..7445fe069aa 100644 --- a/git-protocol/Cargo.toml +++ b/git-protocol/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT/Apache-2.0" description = "A WIP crate of the gitoxide project for implementing git protocols" authors = ["Sebastian Thiel "] edition = "2018" -include = ["src/**/*"] +include = ["src/**/*", "CHANGELOG.md", "!**/tests/**/*"] [lib] doctest = false diff --git a/git-ref/Cargo.toml b/git-ref/Cargo.toml index 995430d4862..dfeef727835 100644 --- a/git-ref/Cargo.toml +++ b/git-ref/Cargo.toml @@ -29,8 +29,8 @@ git-hash = { version = "^0.5.0", path = "../git-hash" } git-object = { version ="0.12.0", path = "../git-object" } git-validate = { version = "^0.5.0", path = "../git-validate" } git-actor = { version ="0.3.1", path = "../git-actor" } -git-lock = { version = "^0.3.0", path = "../git-lock" } -git-tempfile = { version = "^0.6.0", path = "../git-tempfile" } +git-lock = { version ="^1.0.0", path = "../git-lock" } +git-tempfile = { version ="^1.0.0", path = "../git-tempfile" } quick-error = "2.0.0" bstr = { version = "0.2.13", default-features = false, features = ["std"] } diff --git a/git-repository/Cargo.toml b/git-repository/Cargo.toml index 43c8af586d6..5996e7b430d 100644 --- a/git-repository/Cargo.toml +++ b/git-repository/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT/Apache-2.0" version = "0.7.2" authors = ["Sebastian Thiel "] edition = "2018" -include = ["src/**/*", "src/assets/**"] +include = ["src/**/*", "CHANGELOG.md"] [lib] doctest = false @@ -14,6 +14,7 @@ test = true [features] default = ["max-performance", "one-stop-shop"] +unstable = [] serde1 = ["git-pack/serde1", "git-object/serde1"] max-performance = ["git-features/zlib-ng-compat", "git-features/fast-sha1"] local = [ @@ -34,8 +35,8 @@ one-stop-shop = [ [dependencies] git-ref = { version ="^0.6.0", path = "../git-ref" } -git-tempfile = { version = "^0.6.0", path = "../git-tempfile" } -git-lock = { version = "^0.3.2", path = "../git-lock" } +git-tempfile = { version ="^1.0.0", path = "../git-tempfile" } +git-lock = { version ="^1.0.0", path = "../git-lock" } git-validate = { version = "^0.5.0", path = "../git-validate" } git-odb = { version ="0.20.0", path = "../git-odb" } diff --git a/git-repository/examples/interrupt-handler-allows-graceful-shutdown.rs b/git-repository/examples/interrupt-handler-allows-graceful-shutdown.rs index 03b019bfe87..b2d89087e08 100644 --- a/git-repository/examples/interrupt-handler-allows-graceful-shutdown.rs +++ b/git-repository/examples/interrupt-handler-allows-graceful-shutdown.rs @@ -1,13 +1,12 @@ use std::path::Path; -use git_repository::tempfile::{AutoRemove, ContainingDirectory}; +use git_tempfile::{AutoRemove, ContainingDirectory}; fn main() -> anyhow::Result<()> { git_repository::interrupt::init_handler(|| {})?; eprintln!("About to emit the first term signal"); let tempfile_path = Path::new("example-file.tmp"); - let _keep_tempfile = - git_repository::tempfile::mark_at(tempfile_path, ContainingDirectory::Exists, AutoRemove::Tempfile)?; + let _keep_tempfile = git_tempfile::mark_at(tempfile_path, ContainingDirectory::Exists, AutoRemove::Tempfile)?; signal_hook::low_level::raise(signal_hook::consts::SIGTERM)?; eprintln!( diff --git a/git-repository/src/easy/ext/object.rs b/git-repository/src/easy/ext/object.rs index b5a434f8736..8fe7804d26a 100644 --- a/git-repository/src/easy/ext/object.rs +++ b/git-repository/src/easy/ext/object.rs @@ -5,8 +5,8 @@ use git_hash::ObjectId; use crate::{ easy, easy::{object, ObjectRef}, - odb::{Find, FindExt}, }; +use git_odb::{Find, FindExt}; pub fn find_object( access: &A, diff --git a/git-repository/src/easy/ext/reference.rs b/git-repository/src/easy/ext/reference.rs index 8a09e278776..df9e06d6d57 100644 --- a/git-repository/src/easy/ext/reference.rs +++ b/git-repository/src/easy/ext/reference.rs @@ -3,15 +3,16 @@ use std::convert::TryInto; use git_hash::ObjectId; use crate::{ - actor, easy, + easy, easy::{reference, Reference}, - lock, - refs::{ - file::find::Error, - mutable::Target, - transaction::{Change, Create, RefEdit}, - PartialName, - }, +}; +use git_actor as actor; +use git_lock as lock; +use git_ref::{ + file::find::Error, + mutable::Target, + transaction::{Change, Create, RefEdit}, + PartialName, }; /// Obtain and alter references comfortably @@ -34,7 +35,7 @@ pub trait ReferenceAccessExt: easy::Access + Sized { }, new: Target::Peeled(target.into()), }, - name: format!("tags/refs/{}", name.as_ref()).try_into()?, + name: format!("refs/tags/{}", name.as_ref()).try_into()?, deref: false, }), lock_mode, diff --git a/git-repository/src/easy/mod.rs b/git-repository/src/easy/mod.rs index c76500f489d..5253d3e0922 100644 --- a/git-repository/src/easy/mod.rs +++ b/git-repository/src/easy/mod.rs @@ -18,7 +18,11 @@ use std::{ time::SystemTime, }; -use crate::{hash::ObjectId, objs, odb, refs, Repository}; +use crate::Repository; +use git_hash::ObjectId; +use git_object as objs; +use git_odb as odb; +use git_ref as refs; mod impls; @@ -31,6 +35,7 @@ pub mod reference; pub mod state; /// An [ObjectId] with access to a repository. +#[derive(Eq, Hash, Ord, PartialOrd, Clone, Copy)] pub struct Oid<'r, A> { id: ObjectId, access: &'r A, diff --git a/git-repository/src/easy/object/mod.rs b/git-repository/src/easy/object/mod.rs index 916e7982ea2..6dd04a646a2 100644 --- a/git-repository/src/easy/object/mod.rs +++ b/git-repository/src/easy/object/mod.rs @@ -6,10 +6,10 @@ pub use git_object::Kind; use crate::{ easy, easy::{Object, ObjectRef, TreeRef}, - hash::ObjectId, - objs::immutable, - odb, }; +use git_hash::ObjectId; +use git_object::immutable; +use git_odb as odb; mod impls; mod tree; @@ -61,7 +61,8 @@ where pub mod find { use quick_error::quick_error; - use crate::{easy, odb}; + use crate::easy; + use git_odb as odb; quick_error! { #[derive(Debug)] @@ -87,7 +88,8 @@ pub mod find { pub mod existing { use quick_error::quick_error; - use crate::{easy, odb}; + use crate::easy; + use git_odb as odb; quick_error! { #[derive(Debug)] diff --git a/git-repository/src/easy/object/tree.rs b/git-repository/src/easy/object/tree.rs index 3ba4581ce5c..84ddbb3aef0 100644 --- a/git-repository/src/easy/object/tree.rs +++ b/git-repository/src/easy/object/tree.rs @@ -1,9 +1,9 @@ use crate::{ easy, easy::{object::find, TreeRef}, - objs, - objs::{bstr::BStr, immutable}, }; +use git_object as objs; +use git_object::{bstr::BStr, immutable}; impl<'repo, A> TreeRef<'repo, A> where diff --git a/git-repository/src/easy/oid.rs b/git-repository/src/easy/oid.rs index 4d0ed18bf32..76b985639ea 100644 --- a/git-repository/src/easy/oid.rs +++ b/git-repository/src/easy/oid.rs @@ -1,8 +1,8 @@ use crate::{ easy, easy::{object::find, Object, ObjectRef, Oid}, - hash::{oid, ObjectId}, }; +use git_hash::{oid, ObjectId}; impl<'repo, A, B> PartialEq> for Oid<'repo, B> { fn eq(&self, other: &Oid<'repo, A>) -> bool { diff --git a/git-repository/src/easy/reference.rs b/git-repository/src/easy/reference.rs index 0144c8a6142..46a0e848907 100644 --- a/git-repository/src/easy/reference.rs +++ b/git-repository/src/easy/reference.rs @@ -4,16 +4,15 @@ use std::ops::DerefMut; use crate::{ easy, easy::{Oid, Reference}, - hash::ObjectId, - odb::Find, - refs, - refs::mutable, }; +use git_hash::ObjectId; +use git_odb::Find; +use git_ref as refs; pub(crate) enum Backing { OwnedPacked { /// The validated full name of the reference. - name: mutable::FullName, + name: refs::mutable::FullName, /// The target object id of the reference, hex encoded. target: ObjectId, /// The fully peeled object id, hex encoded, that the ref is ultimately pointing to @@ -26,7 +25,8 @@ pub(crate) enum Backing { pub mod edit { use quick_error::quick_error; - use crate::{easy, refs}; + use crate::easy; + use git_ref as refs; quick_error! { #[derive(Debug)] @@ -54,10 +54,11 @@ pub mod edit { } } -pub mod peel_to_id_in_place { +pub mod peel_to_oid_in_place { use quick_error::quick_error; - use crate::{easy, refs}; + use crate::easy; + use git_ref as refs; quick_error! { #[derive(Debug)] @@ -108,7 +109,7 @@ where } pub fn target(&self) -> refs::mutable::Target { match self.backing.as_ref().expect("always set") { - Backing::OwnedPacked { target, .. } => mutable::Target::Peeled(target.to_owned()), + Backing::OwnedPacked { target, .. } => refs::mutable::Target::Peeled(target.to_owned()), Backing::LooseFile(r) => r.target.clone(), } } @@ -121,7 +122,7 @@ where .borrow() } - pub fn peel_to_object_in_place(&mut self) -> Result, peel_to_id_in_place::Error> { + pub fn peel_to_oid_in_place(&mut self) -> Result, peel_to_oid_in_place::Error> { let repo = self.access.repo()?; match self.backing.take().expect("a ref must be set") { Backing::LooseFile(mut r) => { @@ -164,7 +165,8 @@ where pub mod find { use quick_error::quick_error; - use crate::{easy, refs}; + use crate::easy; + use git_ref as refs; pub mod existing { use quick_error::quick_error; diff --git a/git-repository/src/easy/state.rs b/git-repository/src/easy/state.rs index 28dc5be6f76..11418385c7e 100644 --- a/git-repository/src/easy/state.rs +++ b/git-repository/src/easy/state.rs @@ -4,8 +4,8 @@ use std::cell::{Ref, RefMut}; use crate::{ easy, easy::{borrow, PackCache}, - refs::{file, packed}, }; +use git_ref::{file, packed}; impl Clone for easy::State { fn clone(&self) -> Self { diff --git a/git-repository/src/lib.rs b/git-repository/src/lib.rs index 181ec190e8e..6ee64eac535 100644 --- a/git-repository/src/lib.rs +++ b/git-repository/src/lib.rs @@ -48,9 +48,10 @@ //! //! # Cargo-features //! -//! ## One-stop-shop +//! ## With the optional "unstable" cargo feature //! -//! To make using _sub-crates_ easier these are re-exported into the root of this crate. +//! To make using _sub-crates_ easier these are re-exported into the root of this crate. Note that these may change their major version +//! even if this crate doesn't, hence breaking downstream. //! //! `git_repository::` //! * [`hash`] @@ -66,6 +67,7 @@ //! * [`lock`] //! * [`traverse`] //! * [`diff`] +//! * [`parallel`] //! * [`Progress`] //! * [`progress`] //! * [`interrupt`] @@ -80,20 +82,25 @@ use std::{path::PathBuf, rc::Rc, sync::Arc}; // This also means that their major version changes affect our major version, but that's alright as we directly expose their // APIs/instances anyway. pub use git_actor as actor; -#[cfg(feature = "git-diff")] +#[cfg(all(feature = "unstable", feature = "git-diff"))] pub use git_diff as diff; +#[cfg(feature = "unstable")] pub use git_features::{parallel, progress, progress::Progress}; pub use git_hash as hash; +#[cfg(feature = "unstable")] pub use git_lock as lock; +#[cfg(feature = "unstable")] pub use git_object as objs; +#[cfg(feature = "unstable")] pub use git_odb as odb; -#[cfg(feature = "git-protocol")] +#[cfg(all(feature = "unstable", feature = "git-protocol"))] pub use git_protocol as protocol; pub use git_ref as refs; +#[cfg(feature = "unstable")] pub use git_tempfile as tempfile; -#[cfg(feature = "git-traverse")] +#[cfg(all(feature = "unstable", feature = "git-traverse"))] pub use git_traverse as traverse; -#[cfg(feature = "git-url")] +#[cfg(all(feature = "unstable", feature = "git-url"))] pub use git_url as url; pub use path::Path; @@ -128,7 +135,10 @@ pub struct Repository { /// A store for references to point at objects pub refs: git_ref::file::Store, /// A store for objects that contain data + #[cfg(feature = "unstable")] pub odb: git_odb::linked::Store, + #[cfg(not(feature = "unstable"))] + pub(crate) odb: git_odb::linked::Store, /// TODO: git-config should be here - it's read a lot but not written much in must applications, so shouldn't be in `State`. /// Probably it's best reload it on signal (in servers) or refresh it when it's known to have been changed similar to how /// packs are refreshed. This would be `git_config::fs::Config` when ready. diff --git a/git-repository/src/path/is_git.rs b/git-repository/src/path/is_git.rs index 63a695a952e..0e98ce7d16c 100644 --- a/git-repository/src/path/is_git.rs +++ b/git-repository/src/path/is_git.rs @@ -10,7 +10,7 @@ quick_error! { from() source(err) } - MisplacedHead(name: crate::objs::bstr::BString) { + MisplacedHead(name: git_object::bstr::BString) { display("Expected HEAD at '.git/HEAD', got '.git/{}'", name) } MissingObjectsDirectory(missing: PathBuf) { diff --git a/git-repository/tests/reference/mod.rs b/git-repository/tests/reference/mod.rs index 439ebbf4072..1917777b028 100644 --- a/git-repository/tests/reference/mod.rs +++ b/git-repository/tests/reference/mod.rs @@ -5,7 +5,8 @@ fn repo() -> crate::Result { mod find { use std::convert::TryInto; - use git_repository::{prelude::*, refs}; + use git_ref as refs; + use git_repository::prelude::*; use git_testtools::hex_to_id; use crate::reference::repo; @@ -22,27 +23,23 @@ mod find { "it points to a tag object" ); - let object = packed_tag_ref.peel_to_object_in_place().unwrap(); + let object = packed_tag_ref.peel_to_oid_in_place().unwrap(); let the_commit = hex_to_id("134385f6d781b7e97062102c6a483440bfda2a03"); assert_eq!(object, the_commit, "it is assumed to be fully peeled"); assert_eq!( object, - packed_tag_ref.peel_to_object_in_place().unwrap(), + packed_tag_ref.peel_to_oid_in_place().unwrap(), "peeling again yields the same object" ); let mut symbolic_ref = repo.find_reference("multi-link-target1").unwrap(); assert_eq!(symbolic_ref.name(), "refs/heads/multi-link-target1".try_into().unwrap()); - assert_eq!(symbolic_ref.peel_to_object_in_place().unwrap(), the_commit); + assert_eq!(symbolic_ref.peel_to_oid_in_place().unwrap(), the_commit); assert_eq!( symbolic_ref.name(), "refs/remotes/origin/multi-link-target3".try_into().unwrap(), "it follows symbolic refs, too" ); - assert_eq!( - symbolic_ref.peel_to_object_in_place().unwrap(), - the_commit, - "idempotency" - ); + assert_eq!(symbolic_ref.peel_to_oid_in_place().unwrap(), the_commit, "idempotency"); } } diff --git a/git-tempfile/CHANGELOG.md b/git-tempfile/CHANGELOG.md new file mode 100644 index 00000000000..5a01336df2d --- /dev/null +++ b/git-tempfile/CHANGELOG.md @@ -0,0 +1,3 @@ +### 1.0 (2021-08-25) + +- initial release diff --git a/git-tempfile/Cargo.toml b/git-tempfile/Cargo.toml index 456ee797865..2fd2dddc739 100644 --- a/git-tempfile/Cargo.toml +++ b/git-tempfile/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "git-tempfile" -version = "0.6.1" +version = "1.0.0" repository = "https://github.com/Byron/gitoxide" license = "MIT/Apache-2.0" description = "A tempfile implementation with a global registry to assure cleanup" authors = ["Sebastian Thiel "] edition = "2018" -include = ["src/**/*"] +include = ["src/**/*", "LICENSE-*", "README.md", "CHANGELOG.md"] [lib] doctest = false diff --git a/git-tempfile/LICENSE-APACHE b/git-tempfile/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/git-tempfile/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/git-tempfile/LICENSE-MIT b/git-tempfile/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/git-tempfile/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/git-tempfile/README.md b/git-tempfile/README.md new file mode 100644 index 00000000000..83a7cc64905 --- /dev/null +++ b/git-tempfile/README.md @@ -0,0 +1,12 @@ +Use tempfiles to minimize the risk of resource leakage when preparing to overwrite or create a file with new content +in a signal-safe way, making the change atomic. + +Tempfiles can also be used as locks as only one tempfile can exist at a given path at a time. + +* [x] registered temporary files which are deleted automatically as the process terminates or on drop + * [x] write to temorary file and persist it under new name + * [x] close temporary files to convert them into a marker while saving system resources + * [x] mark paths with a closed temporary file +* [x] persist temporary files to prevent them from perishing. +* [x] signal-handler integration with `git-repository` to clean lockfiles before the process is aborted. +* [x] use a temporary file transparently due thanks to implementations of `std::io` traits diff --git a/gitoxide-core/Cargo.toml b/gitoxide-core/Cargo.toml index a68dec8b398..0accbdc27e8 100644 --- a/gitoxide-core/Cargo.toml +++ b/gitoxide-core/Cargo.toml @@ -27,7 +27,7 @@ all-features = true [dependencies] # deselect everything else (like "performance") as this should be controllable by the parent application. -git-repository = { version = "^0.7.0", path = "../git-repository", default-features = false, features = ["local"]} +git-repository = { version = "^0.7.0", path = "../git-repository", default-features = false, features = ["local", "unstable"]} # TODO: eventually 'unstable' shouldn't be needed anymore git-protocol-for-configuration-only = { package = "git-protocol", version ="^0.9.0", path = "../git-protocol", optional = true } git-commitgraph = { version = "^0.4.0", path = "../git-commitgraph" } git-config = { version = "^0.1.0", path = "../git-config" } diff --git a/rust-toolchain.tml b/rust-toolchain.tml new file mode 100644 index 00000000000..292fe499e3b --- /dev/null +++ b/rust-toolchain.tml @@ -0,0 +1,2 @@ +[toolchain] +channel = "stable"