diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 0f6cce6e714..2c0663c5698 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -770,6 +770,7 @@ unstable_cli_options!( dual_proc_macros: bool = ("Build proc-macros for both the host and the target"), features: Option>, gc: bool = ("Track cache usage and \"garbage collect\" unused files"), + git: Option = ("Enable support for shallow git fetch operations"), gitoxide: Option = ("Use gitoxide for the given git interactions, or all of them if no argument is given"), host_config: bool = ("Enable the `[host]` section in the .cargo/config.toml file"), lints: bool = ("Pass `[lints]` to the linting tools"), @@ -875,13 +876,47 @@ where } #[derive(Debug, Copy, Clone, Default, Deserialize)] -pub struct GitoxideFeatures { - /// All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index. - pub fetch: bool, +pub struct GitFeatures { /// When cloning the index, perform a shallow clone. Maintain shallowness upon subsequent fetches. pub shallow_index: bool, /// When cloning git dependencies, perform a shallow clone and maintain shallowness on subsequent fetches. pub shallow_deps: bool, +} + +impl GitFeatures { + fn all() -> Self { + GitFeatures { + shallow_index: true, + shallow_deps: true, + } + } +} + +fn parse_git(it: impl Iterator>) -> CargoResult> { + let mut out = GitFeatures::default(); + let GitFeatures { + shallow_index, + shallow_deps, + } = &mut out; + + for e in it { + match e.as_ref() { + "shallow-index" => *shallow_index = true, + "shallow-deps" => *shallow_deps = true, + _ => { + bail!( + "unstable 'git' only takes 'shallow-index' and 'shallow-deps' as valid inputs" + ) + } + } + } + Ok(Some(out)) +} + +#[derive(Debug, Copy, Clone, Default, Deserialize)] +pub struct GitoxideFeatures { + /// All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index. + pub fetch: bool, /// Checkout git dependencies using `gitoxide` (submodules are still handled by git2 ATM, and filters /// like linefeed conversions are unsupported). pub checkout: bool, @@ -895,9 +930,7 @@ impl GitoxideFeatures { fn all() -> Self { GitoxideFeatures { fetch: true, - shallow_index: true, checkout: true, - shallow_deps: true, internal_use_git2: false, } } @@ -907,9 +940,7 @@ impl GitoxideFeatures { fn safe() -> Self { GitoxideFeatures { fetch: true, - shallow_index: false, checkout: true, - shallow_deps: false, internal_use_git2: false, } } @@ -921,21 +952,17 @@ fn parse_gitoxide( let mut out = GitoxideFeatures::default(); let GitoxideFeatures { fetch, - shallow_index, checkout, - shallow_deps, internal_use_git2, } = &mut out; for e in it { match e.as_ref() { "fetch" => *fetch = true, - "shallow-index" => *shallow_index = true, - "shallow-deps" => *shallow_deps = true, "checkout" => *checkout = true, "internal-use-git2" => *internal_use_git2 = true, _ => { - bail!("unstable 'gitoxide' only takes `fetch`, 'shallow-index', 'shallow-deps' and 'checkout' as valid inputs") + bail!("unstable 'gitoxide' only takes `fetch` and 'checkout' as valid inputs") } } } @@ -1109,6 +1136,12 @@ impl CliUnstable { "doctest-xcompile" => self.doctest_xcompile = parse_empty(k, v)?, "dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?, "gc" => self.gc = parse_empty(k, v)?, + "git" => { + self.git = v.map_or_else( + || Ok(Some(GitFeatures::all())), + |v| parse_git(v.split(',')), + )? + } "gitoxide" => { self.gitoxide = v.map_or_else( || Ok(Some(GitoxideFeatures::all())), diff --git a/src/cargo/sources/git/mod.rs b/src/cargo/sources/git/mod.rs index 0b2cb9908e1..7ac0c40e8bb 100644 --- a/src/cargo/sources/git/mod.rs +++ b/src/cargo/sources/git/mod.rs @@ -16,7 +16,7 @@ mod utils; /// For `-Zgitoxide` integration. pub mod fetch { - use crate::core::features::GitoxideFeatures; + use crate::core::features::GitFeatures; use crate::Config; /// The kind remote repository to fetch. @@ -37,18 +37,19 @@ pub mod fetch { repo_is_shallow: bool, config: &Config, ) -> gix::remote::fetch::Shallow { - let has_feature = |cb: &dyn Fn(GitoxideFeatures) -> bool| { + let has_feature = |cb: &dyn Fn(GitFeatures) -> bool| { config .cli_unstable() - .gitoxide + .git .map_or(false, |features| cb(features)) }; // maintain shallow-ness and keep downloading single commits, or see if we can do shallow clones if !repo_is_shallow { match self { - RemoteKind::GitDependency if has_feature(&|git| git.shallow_deps) => {} - RemoteKind::Registry if has_feature(&|git| git.shallow_index) => {} + RemoteKind::GitDependency if has_feature(&|features| features.shallow_deps) => { + } + RemoteKind::Registry if has_feature(&|features| features.shallow_index) => {} _ => return gix::remote::fetch::Shallow::NoChange, } }; diff --git a/src/cargo/sources/git/oxide.rs b/src/cargo/sources/git/oxide.rs index 5fccdd0c6e6..3db404fefb0 100644 --- a/src/cargo/sources/git/oxide.rs +++ b/src/cargo/sources/git/oxide.rs @@ -29,10 +29,9 @@ pub fn with_retry_and_progress( ) -> CargoResult<()> { std::thread::scope(|s| { let mut progress_bar = Progress::new("Fetch", config); - let is_shallow = config - .cli_unstable() - .gitoxide - .map_or(false, |gix| gix.shallow_deps || gix.shallow_index); + let is_shallow = config.cli_unstable().git.map_or(false, |features| { + features.shallow_deps || features.shallow_index + }); network::retry::with_retry(config, || { let progress_root: Arc = gix::progress::tree::root::Options { diff --git a/src/cargo/sources/git/source.rs b/src/cargo/sources/git/source.rs index 7d303f0c25f..60d60bfc0d9 100644 --- a/src/cargo/sources/git/source.rs +++ b/src/cargo/sources/git/source.rs @@ -108,8 +108,8 @@ impl<'cfg> GitSource<'cfg> { &source_id, config .cli_unstable() - .gitoxide - .map_or(false, |gix| gix.fetch && gix.shallow_deps), + .git + .map_or(false, |features| features.shallow_deps), ); let source = GitSource { diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 7ce43d9bd1f..aae15262606 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -1117,6 +1117,9 @@ pub fn fetch( if tags { opts.download_tags(git2::AutotagOption::All); } + if let gix::remote::fetch::Shallow::DepthAtRemote(depth) = shallow { + opts.depth(0i32.saturating_add_unsigned(depth.get())); + } // The `fetch` operation here may fail spuriously due to a corrupt // repository. It could also fail, however, for a whole slew of other // reasons (aka network related reasons). We want Cargo to automatically diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index da5c9d3f065..487ca633306 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -476,8 +476,8 @@ impl<'cfg> RegistrySource<'cfg> { source_id, config .cli_unstable() - .gitoxide - .map_or(false, |gix| gix.fetch && gix.shallow_index) + .git + .map_or(false, |features| features.shallow_index) && !source_id.is_sparse(), ); let ops = if source_id.is_sparse() { diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 2a9916e1524..bea484651fb 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -1160,19 +1160,32 @@ to run with `gitoxide` with the `-Zgitoxide=operation[,operationN]` syntax. Valid operations are the following: * `fetch` - All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index. +* `checkout` *(planned)* - checkout the worktree, with support for filters and submodules. + +## git + +* Tracking Issue: [TODO]() + +With the 'git' unstable feature, both `gitoxide` and `git2` will perform shallow fetches of the crate +index and git dependencies. + +While `-Zgit` enables all currently implemented features, one can individually select when to perform +shallow fetches with the `-Zgit=operation[,operationN]` syntax. + +Valid operations are the following: + * `shallow-index` - perform a shallow clone of the index. * `shallow-deps` - perform a shallow clone of git dependencies. -* `checkout` *(planned)* - checkout the worktree, with support for filters and submodules. **Details on shallow clones** -* To enable shallow clones, add `-Zgitoxide=fetch,shallow_deps` for fetching git dependencies or `-Zgitoxide=fetch,shallow_index` for fetching registry index. +* To enable shallow clones, add `-Zgit=shallow-deps` for fetching git dependencies or `-Zgit=shallow-index` for fetching registry index. * Shallow-cloned and shallow-checked-out git repositories reside at their own `-shallow` suffixed directories, i.e, - `~/.cargo/registry/index/*-shallow` - `~/.cargo/git/db/*-shallow` - `~/.cargo/git/checkouts/*-shallow` * When the unstable feature is on, fetching/cloning a git repository is always a shallow fetch. This roughly equals to `git fetch --depth 1` everywhere. -* Even with the presence of `Cargo.lock` or specifying a commit `{ rev = "…" }`, gitoxide is still smart enough to shallow fetch without unshallowing the existing repository. +* Even with the presence of `Cargo.lock` or specifying a commit `{ rev = "…" }`, gitoxide is still smart enough to shallow fetch without unshallowing the existing repository. TODO: does this hold for libgit2? ## script diff --git a/tests/testsuite/git_shallow.rs b/tests/testsuite/git_shallow.rs index 8045880cfd4..ca27ccd644e 100644 --- a/tests/testsuite/git_shallow.rs +++ b/tests/testsuite/git_shallow.rs @@ -91,12 +91,14 @@ fn perform_two_revs_same_deps(shallow: bool) { .build(); let args = if shallow { - "build -v -Zgitoxide=fetch,shallow-deps" + "build -v -Zgitoxide=fetch -Zgit=shallow-deps" } else { "build -v" }; foo.cargo(args) - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); assert!(foo.bin("foo").is_file()); foo.process(&foo.bin("foo")).run(); @@ -126,8 +128,11 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch( .file("src/lib.rs", "") .build(); p.cargo("fetch") - .arg("-Zgitoxide=fetch,shallow-index") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-index") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); let shallow_repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; @@ -206,8 +211,11 @@ fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_fol .build(); p.cargo("update") - .arg("-Zgitoxide=fetch,shallow-deps") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); let db_clone = gix::open_opts( @@ -341,8 +349,11 @@ fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> .build(); p.cargo("update") - .arg("-Zgitoxide=fetch,shallow-deps") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); let shallow_db_clone = gix::open_opts( @@ -457,8 +468,11 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_ .file("src/lib.rs", "") .build(); p.cargo("fetch") - .arg("-Zgitoxide=fetch,shallow-index") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-index") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; @@ -474,8 +488,11 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_ Package::new("bar", "1.1.0").publish(); p.cargo("update") - .arg("-Zgitoxide=fetch,shallow-index") // NOTE: the flag needs to be consistent or else a different index is created - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-index") // NOTE: the flag needs to be consistent or else a different index is created + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); assert_eq!( @@ -491,8 +508,11 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_ Package::new("bar", "1.2.0").publish(); Package::new("bar", "1.3.0").publish(); p.cargo("update") - .arg("-Zgitoxide=fetch,shallow-index") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-index") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); assert_eq!( @@ -545,8 +565,11 @@ fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_sh Package::new("bar", "1.1.0").publish(); p.cargo("update") - .arg("-Zgitoxide=fetch,shallow-index") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-index") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); let shallow_repo = gix::open_opts( @@ -566,8 +589,11 @@ fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_sh Package::new("bar", "1.2.0").publish(); Package::new("bar", "1.3.0").publish(); p.cargo("update") - .arg("-Zgitoxide=fetch,shallow-index") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-index") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); assert_eq!( @@ -633,8 +659,11 @@ fn gitoxide_git_dependencies_switch_from_branch_to_rev() -> anyhow::Result<()> { .build(); p.cargo("check") - .arg("-Zgitoxide=fetch,shallow-deps") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); let db_clone = gix::open_opts( @@ -663,8 +692,11 @@ fn gitoxide_git_dependencies_switch_from_branch_to_rev() -> anyhow::Result<()> { .build(); p.cargo("check") - .arg("-Zgitoxide=fetch,shallow-deps") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); assert!( @@ -711,8 +743,11 @@ fn shallow_deps_work_with_revisions_and_branches_mixed_on_same_dependency() -> a .build(); p.cargo("check") - .arg("-Zgitoxide=fetch,shallow-deps") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); let db_paths = glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())? @@ -751,8 +786,11 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( .file("src/lib.rs", "") .build(); p.cargo("fetch") - .arg("-Zgitoxide=fetch,shallow-index") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-index") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; @@ -773,8 +811,11 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( Package::new("bar", "1.1.0").publish(); p.cargo("update") - .arg("-Zgitoxide=fetch,shallow-index") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-index") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]) .run(); assert!(!shallow_lock.is_file(), "the repository was re-initialized"); diff --git a/tests/testsuite/offline.rs b/tests/testsuite/offline.rs index e684253193f..edd2ced2248 100644 --- a/tests/testsuite/offline.rs +++ b/tests/testsuite/offline.rs @@ -433,9 +433,10 @@ fn compile_offline_with_cached_git_dep(shallow: bool) { let maybe_use_shallow = |mut cargo: Execs| -> Execs { if shallow { cargo - .arg("-Zgitoxide=fetch,shallow-deps") + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide", + "unstable features must be available for -Z gitoxide and -Z git", ]); } cargo diff --git a/tests/testsuite/patch.rs b/tests/testsuite/patch.rs index a4522e82219..55cab58c8b5 100644 --- a/tests/testsuite/patch.rs +++ b/tests/testsuite/patch.rs @@ -2531,8 +2531,11 @@ dependencies = [ let mut cargo = p.cargo("tree"); if shallow { cargo - .arg("-Zgitoxide=fetch,shallow-deps") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]); + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide and -Z git", + ]); } cargo // .env("CARGO_LOG", "trace")