diff --git a/src/cargo/ops/cargo_package/mod.rs b/src/cargo/ops/cargo_package/mod.rs index 472acf41cb1..63c0b139520 100644 --- a/src/cargo/ops/cargo_package/mod.rs +++ b/src/cargo/ops/cargo_package/mod.rs @@ -221,6 +221,7 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult TmpRegistry<'a> { self.gctx, "temporary package registry", )?; + tar_copy.file().set_len(0)?; tar.file().seek(SeekFrom::Start(0))?; std::io::copy(&mut tar.file(), &mut tar_copy)?; tar_copy.flush()?; @@ -1229,6 +1231,7 @@ impl<'a> TmpRegistry<'a> { self.gctx, "temporary package registry", )?; + dst.file().set_len(0)?; dst.write_all(index_line.as_bytes())?; Ok(()) } diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs index 80d3811e96f..1361abfd1da 100644 --- a/tests/testsuite/package.rs +++ b/tests/testsuite/package.rs @@ -7895,3 +7895,138 @@ fn package_dir_not_excluded_from_backups() { "CACHEDIR.TAG should exist in target directory to exclude it from backups" ); } + +#[cargo_test] +fn repackage_smaller_crate_has_trailing_garbage() { + // When a package is re-packaged and the new .crate file is smaller than + // the previous one, the artifact on disk should be smaller without trailing garbage bytes. + let big_file_contents = "x".repeat(100_000); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2021" + include = ["src/**", "Cargo.toml", "big.txt"] + "#, + ) + .file("src/lib.rs", "") + .file("big.txt", &big_file_contents) + .build(); + + // First package run: includes big.txt, so the .crate file is large. + p.cargo("package --no-verify").run(); + + let crate_path = p.root().join("target/package/foo-0.0.1.crate"); + let first_size = fs::metadata(&crate_path).unwrap().len(); + + // Remove big.txt from the project so the next package will be smaller. + fs::remove_file(p.root().join("big.txt")).unwrap(); + + // Update the manifest to no longer include big.txt. + p.change_file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2021" + include = ["src/**", "Cargo.toml"] + "#, + ); + + // Second package run: no big.txt, so the .crate file should be much smaller. + p.cargo("package --no-verify").run(); + + let second_size = fs::metadata(&crate_path).unwrap().len(); + + // The target .crate file *is* smaller. + assert!( + first_size > second_size, + "the .crate file should be smaller after removing big.txt" + ); +} + +#[cargo_test] +fn repackage_smaller_local_dep_tmp_registry_checksum_match() { + let reg = registry::init(); + let big_file_contents = "x".repeat(100_000); + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["foo", "bar"] + resolver = "2" + "#, + ) + .file( + "foo/Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2021" + + [dependencies] + bar = { path = "../bar", version = "0.0.1" } + "#, + ) + .file("foo/src/lib.rs", "pub fn foo() { bar::bar(); }") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.0.1" + edition = "2021" + include = ["src/**", "Cargo.toml", "big.txt"] + "#, + ) + .file("bar/src/lib.rs", "pub fn bar() {}") + .file("bar/big.txt", &big_file_contents) + .build(); + + p.cargo("package --workspace --no-verify") + .replace_crates_io(reg.index_url()) + .run(); + + fs::remove_file(p.root().join("bar/big.txt")).unwrap(); + p.change_file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.0.1" + edition = "2021" + include = ["src/**", "Cargo.toml"] + "#, + ); + p.cargo("package --workspace --no-verify") + .replace_crates_io(reg.index_url()) + .run(); + + let index_line = read_to_string(p.root().join("target/package/tmp-registry/index/3/b/bar")) + .unwrap() + .lines() + .last() + .unwrap() + .to_owned(); + let expected_cksum = serde_json::from_str::(&index_line) + .unwrap() + .get("cksum") + .and_then(|value| value.as_str()) + .unwrap() + .to_owned(); + + let crate_contents = + fs::read(p.root().join("target/package/tmp-registry/bar-0.0.1.crate")).unwrap(); + let actual_cksum = registry::cksum(&crate_contents); + + assert_eq!( + expected_cksum, actual_cksum, + "tmp-registry crate checksum should match index entry" + ); +}