From d833d004066f4fbef42308700ddb067242230c9d Mon Sep 17 00:00:00 2001 From: Hamir Date: Sat, 11 Jul 2026 23:40:21 -0700 Subject: [PATCH 1/2] test: incorrect `duplicate package` warning --- tests/testsuite/git.rs | 74 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index 1d1b72b8c66..d5749f4a3cd 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -1250,6 +1250,80 @@ in favor of [ROOT]/home/.cargo/git/checkouts/dep-[HASH]/[..]/duplicate1/Cargo.to .run(); } +#[cargo_test] +fn no_duplicate_package_warning_with_dotdot_cargo_home() { + // Regression test for https://github.com/rust-lang/cargo/issues/15981. + // + // A `CARGO_HOME` containing a `..` segment can make the git checkout path retain + // the `..`, so a workspace member discovered by walking the checkout (raw path) + // and by following the root's `path` dependency (normalized path) looked + // like two different packages, producing an incorrect duplicate warning. + let git_project = git::new("dep", |project| { + project + .file( + "Cargo.toml", + r#" + [package] + name = "dep" + version = "0.1.0" + edition = "2015" + + [dependencies] + member = { path = "member" } + "#, + ) + .file("src/lib.rs", "") + .file( + "member/Cargo.toml", + r#" + [package] + name = "member" + version = "0.1.0" + edition = "2015" + "#, + ) + .file("member/src/lib.rs", "") + }); + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2015" + + [dependencies] + dep = {{ git = '{}' }} + "#, + git_project.url() + ), + ) + .file("src/main.rs", "fn main() {}") + .build(); + + // `paths::home()` is created by the test harness, so the `..` resolves on disk. + let cargo_home = paths::home().join("..").join("cargo-home"); + + p.cargo("check") + .env("CARGO_HOME", &cargo_home) + .with_stderr_data(str![[r#" +[UPDATING] git repository `[ROOTURL]/dep` +[WARNING] skipping duplicate package `member v0.1.0 ([ROOTURL]/dep#[..])`: + [ROOT]/home/../cargo-home/git/checkouts/dep-[HASH]/[..]/member/Cargo.toml +in favor of [ROOT]/cargo-home/git/checkouts/dep-[HASH]/[..]/member/Cargo.toml + +[LOCKING] 2 packages to latest compatible versions +[CHECKING] member v0.1.0 ([ROOTURL]/dep#[..]) +[CHECKING] dep v0.1.0 ([ROOTURL]/dep#[..]) +[CHECKING] foo v0.1.0 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s + +"#]]) + .run(); +} + #[cargo_test] fn unused_ambiguous_published_deps() { let project = project(); From af5e90b67078c4ae589dc74a60d3e6fbb094ef31 Mon Sep 17 00:00:00 2001 From: Hamir Date: Sat, 11 Jul 2026 23:45:44 -0700 Subject: [PATCH 2/2] fix(source): incorrect `duplicate package` warning --- src/cargo/sources/path.rs | 4 ++++ tests/testsuite/git.rs | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cargo/sources/path.rs b/src/cargo/sources/path.rs index 6296f088b1d..120a799f5b0 100644 --- a/src/cargo/sources/path.rs +++ b/src/cargo/sources/path.rs @@ -991,6 +991,10 @@ fn read_packages( source_id: SourceId, gctx: &GlobalContext, ) -> CargoResult>> { + // Normalize for consistency. + // See https://github.com/rust-lang/cargo/issues/15981 + // Otherwise, a `CARGO_HOME` with `..` can collect a package twice and incorrectly warn about a duplicate. + let path = &paths::normalize_path(path); let mut all_packages = HashMap::default(); let mut visited = HashSet::::default(); let mut errors = Vec::::new(); diff --git a/tests/testsuite/git.rs b/tests/testsuite/git.rs index d5749f4a3cd..3c4771eeada 100644 --- a/tests/testsuite/git.rs +++ b/tests/testsuite/git.rs @@ -1310,10 +1310,6 @@ fn no_duplicate_package_warning_with_dotdot_cargo_home() { .env("CARGO_HOME", &cargo_home) .with_stderr_data(str![[r#" [UPDATING] git repository `[ROOTURL]/dep` -[WARNING] skipping duplicate package `member v0.1.0 ([ROOTURL]/dep#[..])`: - [ROOT]/home/../cargo-home/git/checkouts/dep-[HASH]/[..]/member/Cargo.toml -in favor of [ROOT]/cargo-home/git/checkouts/dep-[HASH]/[..]/member/Cargo.toml - [LOCKING] 2 packages to latest compatible versions [CHECKING] member v0.1.0 ([ROOTURL]/dep#[..]) [CHECKING] dep v0.1.0 ([ROOTURL]/dep#[..])