diff --git a/src/cargo/core/resolver/encode.rs b/src/cargo/core/resolver/encode.rs index 04d9ebd38b4..5966b24111e 100644 --- a/src/cargo/core/resolver/encode.rs +++ b/src/cargo/core/resolver/encode.rs @@ -132,7 +132,7 @@ impl EncodableResolve { /// `features`. Care should be taken when using this Resolve. One of the /// primary uses is to be used with `resolve_with_previous` to guide the /// resolver to create a complete Resolve. - pub fn into_resolve(self, ws: &Workspace<'_>) -> CargoResult { + pub fn into_resolve(self, original: &str, ws: &Workspace<'_>) -> CargoResult { let path_deps = build_path_deps(ws); let mut checksums = HashMap::new(); @@ -333,6 +333,30 @@ impl EncodableResolve { unused_patches.push(id); } + // We have a curious issue where in the "v1 format" we buggily had a + // trailing blank line at the end of lock files under some specific + // conditions. + // + // Cargo is trying to write new lockfies in the "v2 format" but if you + // have no dependencies, for example, then the lockfile encoded won't + // really have any indicator that it's in the new format (no + // dependencies or checksums listed). This means that if you type `cargo + // new` followed by `cargo build` it will generate a "v2 format" lock + // file since none previously existed. When reading this on the next + // `cargo build`, however, it generates a new lock file because when + // reading in that lockfile we think it's the v1 format. + // + // To help fix this issue we special case here. If our lockfile only has + // one trailing newline, not two, *and* it only has one package, then + // this is actually the v2 format. + if original.ends_with("\n") + && !original.ends_with("\n\n") + && version == ResolveVersion::V1 + && g.iter().count() == 1 + { + version = ResolveVersion::V2; + } + Ok(Resolve::new( g, replacements, diff --git a/src/cargo/ops/lockfile.rs b/src/cargo/ops/lockfile.rs index 4c7c03c1d18..db05e859014 100644 --- a/src/cargo/ops/lockfile.rs +++ b/src/cargo/ops/lockfile.rs @@ -22,7 +22,7 @@ pub fn load_pkg_lockfile(ws: &Workspace<'_>) -> CargoResult> { let resolve = (|| -> CargoResult> { let resolve: toml::Value = cargo_toml::parse(&s, f.path(), ws.config())?; let v: resolver::EncodableResolve = resolve.try_into()?; - Ok(Some(v.into_resolve(ws)?)) + Ok(Some(v.into_resolve(&s, ws)?)) })() .chain_err(|| format!("failed to parse lock file at: {}", f.path().display()))?; Ok(resolve) @@ -172,7 +172,7 @@ fn are_equal_lockfiles(mut orig: String, current: &str, ws: &Workspace<'_>) -> b let res: CargoResult = (|| { let old: resolver::EncodableResolve = toml::from_str(&orig)?; let new: resolver::EncodableResolve = toml::from_str(current)?; - Ok(old.into_resolve(ws)? == new.into_resolve(ws)?) + Ok(old.into_resolve(&orig, ws)? == new.into_resolve(current, ws)?) })(); if let Ok(true) = res { return true; diff --git a/tests/testsuite/new.rs b/tests/testsuite/new.rs index 345a2531034..49e059746e8 100644 --- a/tests/testsuite/new.rs +++ b/tests/testsuite/new.rs @@ -527,3 +527,14 @@ fn new_with_reference_link() { let contents = fs::read_to_string(paths::root().join("foo/Cargo.toml")).unwrap(); assert!(contents.contains("# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html")) } + +#[cargo_test] +fn lockfile_constant_during_new() { + cargo_process("new foo").env("USER", "foo").run(); + + cargo_process("build").cwd(&paths::root().join("foo")).run(); + let before = fs::read_to_string(paths::root().join("foo/Cargo.lock")).unwrap(); + cargo_process("build").cwd(&paths::root().join("foo")).run(); + let after = fs::read_to_string(paths::root().join("foo/Cargo.lock")).unwrap(); + assert_eq!(before, after); +}