diff --git a/crates/cargo-test-support/src/lib.rs b/crates/cargo-test-support/src/lib.rs index f282b3d9b..9eeb4eb00 100644 --- a/crates/cargo-test-support/src/lib.rs +++ b/crates/cargo-test-support/src/lib.rs @@ -1524,6 +1524,12 @@ impl ArgLineCommandExt for &mut ProcessBuilder { } } +impl ArgLineCommandExt for &mut Execs { + fn arg>(self, s: S) -> Self { + self.arg(s) + } +} + impl ArgLineCommandExt for snapbox::cmd::Command { fn arg>(self, s: S) -> Self { self.arg(s) diff --git a/tests/testsuite/git_shallow.rs b/tests/testsuite/git_shallow.rs index 6a45621e6..86291714c 100644 --- a/tests/testsuite/git_shallow.rs +++ b/tests/testsuite/git_shallow.rs @@ -4,17 +4,45 @@ use cargo_test_support::{basic_manifest, git, paths, project}; use crate::git_gc::find_index; +enum Backend { + Git2, + Gitoxide, +} + +impl Backend { + fn to_arg(&self) -> &'static str { + match self { + Backend::Git2 => "", + Backend::Gitoxide => "-Zgitoxide=fetch", + } + } +} + enum RepoMode { Shallow, Complete, } -#[cargo_test] -fn gitoxide_clones_shallow_two_revs_same_deps() { - perform_two_revs_same_deps(true) +impl RepoMode { + fn to_deps_arg(&self) -> &'static str { + match self { + RepoMode::Complete => "", + RepoMode::Shallow => "-Zgit=shallow-deps", + } + } } -fn perform_two_revs_same_deps(shallow: bool) { +#[cargo_test] +fn gitoxide_fetch_shallow_dep_two_revs() { + fetch_dep_two_revs(Backend::Gitoxide, RepoMode::Shallow) +} + +#[cargo_test] +fn git2_fetch_complete_dep_two_revs() { + fetch_dep_two_revs(Backend::Git2, RepoMode::Complete) +} + +fn fetch_dep_two_revs(backend: Backend, mode: RepoMode) { let bar = git::new("meta-dep", |project| { project .file("Cargo.toml", &basic_manifest("bar", "0.0.0")) @@ -92,28 +120,153 @@ fn perform_two_revs_same_deps(shallow: bool) { ) .build(); - let args = if shallow { - "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 and -Z git", - ]) + foo.cargo("check -v") + .arg_line(backend.to_arg()) + .arg_line(mode.to_deps_arg()) + .env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0") // respect `backend` + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-deps"]) .run(); - assert!(foo.bin("foo").is_file()); - foo.process(&foo.bin("foo")).run(); } #[cargo_test] -fn two_revs_same_deps() { - perform_two_revs_same_deps(false) +fn gitoxide_fetch_shallow_dep_branch_and_rev() -> anyhow::Result<()> { + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + // this commit would not be available in a shallow fetch. + let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar-renamed = {{ package = "bar", git = "{}", rev = "{}" }} + bar = {{ git = "{}", branch = "master" }} + "#, + bar.url(), + first_commit_pre_change, + bar.url(), + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-deps"]) + .run(); + + let db_paths = glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())? + .map(Result::unwrap) + .collect::>(); + assert_eq!( + db_paths.len(), + 1, + "only one db checkout source is used per dependency" + ); + let db_clone = gix::open_opts(&db_paths[0], gix::open::Options::isolated())?; + assert!( + db_clone.is_shallow(), + "the repo is shallow while having all data it needs" + ); + + Ok(()) } #[cargo_test] -fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch( -) -> anyhow::Result<()> { +fn gitoxide_fetch_shallow_dep_branch_to_rev() -> anyhow::Result<()> { + // db exists from previous build, then dependency changes to refer to revision that isn't + // available in the shallow fetch. + + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + // this commit would not be available in a shallow fetch. + let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ git = "{}", branch = "master" }} + "#, + bar.url(), + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-deps"]) + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert!(db_clone.is_shallow()); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ git = "{}", rev = "{}" }} + "#, + bar.url(), + first_commit_pre_change + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch") + .arg("-Zgit=shallow-deps") + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-deps"]) + .run(); + + assert!( + db_clone.is_shallow(), + "we maintain shallowness and never unshallow" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_fetch_shallow_index_then_git2_fetch_complete() -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let p = project() .file( @@ -132,9 +285,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch( p.cargo("fetch") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-index"]) .run(); let shallow_repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; @@ -145,7 +296,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch( .all()? .count(), 1, - "shallow clones always start at depth of 1 to minimize download size" + "shallow fetch always start at depth of 1 to minimize download size" ); assert!(shallow_repo.is_shallow()); @@ -164,15 +315,14 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch( .all()? .count(), 3, - "an entirely new repo was cloned which is never shallow" + "an entirely new repo was fetched which is never shallow" ); assert!(!repo.is_shallow()); Ok(()) } #[cargo_test] -fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_followup_fetches( -) -> anyhow::Result<()> { +fn gitoxide_fetch_shallow_dep_then_git2_fetch_complete() -> anyhow::Result<()> { // Example where an old lockfile with an explicit branch="master" in Cargo.toml. Package::new("bar", "1.0.0").publish(); let (bar, bar_repo) = git::new_repo("bar", |p| { @@ -215,9 +365,7 @@ fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_fol p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-deps"]) .run(); let db_clone = gix::open_opts( @@ -232,7 +380,7 @@ fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_fol .all()? .count(), 1, - "db clones are shallow and have a shortened history" + "db fetch are shallow and have a shortened history" ); let dep_checkout = gix::open_opts( @@ -243,7 +391,7 @@ fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_fol assert_eq!( dep_checkout.head_id()?.ancestors().all()?.count(), 1, - "db checkouts are hard-linked clones with the shallow file copied separately." + "db checkouts are hard-linked fetches with the shallow file copied separately." ); bar.change_file("src/lib.rs", "// another change"); @@ -311,7 +459,7 @@ fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_fol } #[cargo_test] -fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> { +fn gitoxide_fetch_shallow_dep_then_gitoxide_fetch_complete() -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let (bar, bar_repo) = git::new_repo("bar", |p| { p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) @@ -353,9 +501,7 @@ fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-deps") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-deps"]) .run(); let shallow_db_clone = gix::open_opts( @@ -370,7 +516,7 @@ fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> .all()? .count(), 1, - "db clones are shallow and have a shortened history" + "db fetches are shallow and have a shortened history" ); let dep_checkout = gix::open_opts( @@ -381,7 +527,7 @@ fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> assert_eq!( dep_checkout.head_id()?.ancestors().all()?.count(), 1, - "db checkouts are hard-linked clones with the shallow file copied separately." + "db checkouts are hard-linked fetches with the shallow file copied separately." ); bar.change_file("src/lib.rs", "// another change"); @@ -399,7 +545,7 @@ fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> p.cargo("update") .arg("-Zgitoxide=fetch") // shallow-deps is omitted intentionally - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch"]) .run(); let db_clone = gix::open_opts( @@ -452,8 +598,7 @@ fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> } #[cargo_test] -fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_shallowness( -) -> anyhow::Result<()> { +fn gitoxide_fetch_shallow_index_then_preserve_shallow() -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let p = project() .file( @@ -472,9 +617,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_ p.cargo("fetch") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-index"]) .run(); let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; @@ -484,7 +627,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_ .all()? .count(), 1, - "shallow clones always start at depth of 1 to minimize download size" + "shallow fetches always start at depth of 1 to minimize download size" ); assert!(repo.is_shallow()); @@ -492,9 +635,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_ p.cargo("update") .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", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-index"]) .run(); assert_eq!( @@ -512,9 +653,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_ p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-index"]) .run(); assert_eq!( @@ -530,10 +669,9 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_ Ok(()) } -/// If there is shallow *and* non-shallow clones, non-shallow will naturally be returned due to sort order. +/// If there is shallow *and* non-shallow fetches, non-shallow will naturally be returned due to sort order. #[cargo_test] -fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_shallowness( -) -> anyhow::Result<()> { +fn gitoxide_fetch_complete_index_then_shallow() -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let p = project() .file( @@ -551,7 +689,7 @@ fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_sh .build(); p.cargo("fetch") .arg("-Zgitoxide=fetch") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch"]) .run(); let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; @@ -569,9 +707,7 @@ fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_sh p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-index"]) .run(); let shallow_repo = gix::open_opts( @@ -584,7 +720,7 @@ fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_sh .all()? .count(), 1, - "the follow up clones an entirely new index which is now shallow and which is in its own location" + "the follow up fetch an entirely new index which is now shallow and which is in its own location" ); assert!(shallow_repo.is_shallow()); @@ -593,9 +729,7 @@ fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_sh p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-index"]) .run(); assert_eq!( @@ -611,7 +745,7 @@ fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_sh p.cargo("update") .arg("-Zgitoxide=fetch") - .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch"]) .run(); assert_eq!( @@ -627,151 +761,7 @@ fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_sh } #[cargo_test] -fn gitoxide_git_dependencies_switch_from_branch_to_rev() -> anyhow::Result<()> { - // db exists from previous build, then dependency changes to refer to revision that isn't - // available in the shallow clone. - - let (bar, bar_repo) = git::new_repo("bar", |p| { - p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) - .file("src/lib.rs", "") - }); - - // this commit would not be available in a shallow clone. - let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); - - bar.change_file("src/lib.rs", "// change"); - git::add(&bar_repo); - git::commit(&bar_repo); - let p = project() - .file( - "Cargo.toml", - &format!( - r#" - [package] - name = "foo" - version = "0.1.0" - - [dependencies] - bar = {{ git = "{}", branch = "master" }} - "#, - bar.url(), - ), - ) - .file("src/lib.rs", "") - .build(); - - p.cargo("check") - .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( - find_bar_db(RepoMode::Shallow), - gix::open::Options::isolated(), - )?; - assert!(db_clone.is_shallow()); - - let p = project() - .file( - "Cargo.toml", - &format!( - r#" - [package] - name = "foo" - version = "0.1.0" - - [dependencies] - bar = {{ git = "{}", rev = "{}" }} - "#, - bar.url(), - first_commit_pre_change - ), - ) - .file("src/lib.rs", "") - .build(); - - p.cargo("check") - .arg("-Zgitoxide=fetch") - .arg("-Zgit=shallow-deps") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) - .run(); - - assert!( - db_clone.is_shallow(), - "we maintain shallowness and never unshallow" - ); - - Ok(()) -} - -#[cargo_test] -fn shallow_deps_work_with_revisions_and_branches_mixed_on_same_dependency() -> anyhow::Result<()> { - let (bar, bar_repo) = git::new_repo("bar", |p| { - p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) - .file("src/lib.rs", "") - }); - - // this commit would not be available in a shallow clone. - let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); - - bar.change_file("src/lib.rs", "// change"); - git::add(&bar_repo); - git::commit(&bar_repo); - - let p = project() - .file( - "Cargo.toml", - &format!( - r#" - [package] - name = "foo" - version = "0.1.0" - - [dependencies] - bar-renamed = {{ package = "bar", git = "{}", rev = "{}" }} - bar = {{ git = "{}", branch = "master" }} - "#, - bar.url(), - first_commit_pre_change, - bar.url(), - ), - ) - .file("src/lib.rs", "") - .build(); - - p.cargo("check") - .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())? - .map(Result::unwrap) - .collect::>(); - assert_eq!( - db_paths.len(), - 1, - "only one db checkout source is used per dependency" - ); - let db_clone = gix::open_opts(&db_paths[0], gix::open::Options::isolated())?; - assert!( - db_clone.is_shallow(), - "the repo is shallow while having all data it needs" - ); - - Ok(()) -} - -#[cargo_test] -fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( -) -> anyhow::Result<()> { +fn gitoxide_fetch_shallow_index_then_abort_and_update() -> anyhow::Result<()> { Package::new("bar", "1.0.0").publish(); let p = project() .file( @@ -790,9 +780,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( p.cargo("fetch") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-index"]) .run(); let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; @@ -802,11 +790,11 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( .all()? .count(), 1, - "shallow clones always start at depth of 1 to minimize download size" + "shallow fetches always start at depth of 1 to minimize download size" ); assert!(repo.is_shallow()); let shallow_lock = repo.shallow_file().with_extension("lock"); - // adding a lock file and deleting the original simulates a left-over clone that was aborted, leaving a lock file + // adding a lock file and deleting the original simulates a left-over fetch that was aborted, leaving a lock file // in place without ever having moved it to the right location. std::fs::write(&shallow_lock, &[])?; std::fs::remove_file(repo.shallow_file())?; @@ -815,9 +803,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( p.cargo("update") .arg("-Zgitoxide=fetch") .arg("-Zgit=shallow-index") - .masquerade_as_nightly_cargo(&[ - "unstable features must be available for -Z gitoxide and -Z git", - ]) + .masquerade_as_nightly_cargo(&["gitoxide=fetch", "git=shallow-index"]) .run(); assert!(!shallow_lock.is_file(), "the repository was re-initialized"); @@ -828,7 +814,7 @@ fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( .all()? .count(), 1, - "it's a fresh shallow clone - otherwise it would have 2 commits if the previous shallow clone would still be present" + "it's a fresh shallow fetch - otherwise it would have 2 commits if the previous shallow fetch would still be present" ); Ok(())