Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/cargo/ops/cargo_package/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ pub fn package(ws: &Workspace<'_>, opts: &PackageOpts<'_>) -> CargoResult<Vec<Fi
for (pkg, _, src) in packaged {
let filename = pkg.package_id().tarball_name();
let dst = artifact_dir.open_rw_exclusive_create(filename, ws.gctx(), "uplifted package")?;
dst.file().set_len(0)?;
src.file().seek(SeekFrom::Start(0))?;
std::io::copy(&mut src.file(), &mut dst.file())?;
result.push(dst);
Expand Down Expand Up @@ -1157,6 +1158,7 @@ impl<'a> 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()?;
Expand Down Expand Up @@ -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(())
}
Expand Down
135 changes: 135 additions & 0 deletions tests/testsuite/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<serde_json::Value>(&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"
);
}