Skip to content

Commit da20496

Browse files
committed
Auto merge of #11270 - antonok-edm:report-packagesize, r=weihanglo
Report crate size on package and publish ### Motivation Fixes #11251. This adds a line like `Packaged 42 files, 727.0KiB (143.8KiB compressed)` to the output of `cargo package` and `cargo publish`. See the associated issue for more details. ### Test info I've updated associated tests to account for the new line in the output, including the file count where relevant. I've also added a few additional tests specifically to address the uncompressed and compressed file sizes. If you'd like to test this manually, simply run `cargo package` or `cargo publish` within a project of your choice. The new `Packaged` line will appear at the end of the stderr output, or directly before the `Uploaded` line, respectively. ### Review info This PR touches many test files to account for the additional line of stderr output. For convenience, I've split the PR into 4 commits. 1. contains the actual implementation 2. updates existing tests unrelated to `cargo package` and `cargo publish` 3. updates existing tests related to `cargo package` and `cargo publish`, including file counts where relevant 4. adds new tests specifically for the file sizes, which are generally not covered by existing tests ### Additional information The feature was discussed [on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/Report.20crate.20size.20when.20packaging) prior to implementation. Potential future extensions to explore include: - Report size per file when using `--verbose` - Compare to the size of the previously uploaded version to warn if the increase is sufficiently large - Consider designs that can draw more attention to the most important information - Warn if large binary files are included ([#9058](#9058))
2 parents 2d04bcd + 2450035 commit da20496

14 files changed

+441
-13
lines changed

crates/cargo-test-support/src/compare.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ fn substitute_macros(input: &str) -> String {
174174
("[REMOVING]", " Removing"),
175175
("[DOCTEST]", " Doc-tests"),
176176
("[PACKAGING]", " Packaging"),
177+
("[PACKAGED]", " Packaged"),
177178
("[DOWNLOADING]", " Downloading"),
178179
("[DOWNLOADED]", " Downloaded"),
179180
("[UPLOADING]", " Uploading"),

src/cargo/ops/cargo_package.rs

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::core::{Package, PackageId, PackageSet, Resolve, SourceId};
1414
use crate::sources::PathSource;
1515
use crate::util::errors::CargoResult;
1616
use crate::util::toml::TomlManifest;
17-
use crate::util::{self, restricted_names, Config, FileLock};
17+
use crate::util::{self, human_readable_bytes, restricted_names, Config, FileLock};
1818
use crate::{drop_println, ops};
1919
use anyhow::Context as _;
2020
use cargo_util::paths;
@@ -110,6 +110,8 @@ pub fn package_one(
110110

111111
let ar_files = build_ar_list(ws, pkg, src_files, vcs_info)?;
112112

113+
let filecount = ar_files.len();
114+
113115
if opts.list {
114116
for ar_file in ar_files {
115117
drop_println!(config, "{}", ar_file.rel_str);
@@ -138,7 +140,7 @@ pub fn package_one(
138140
.shell()
139141
.status("Packaging", pkg.package_id().to_string())?;
140142
dst.file().set_len(0)?;
141-
tar(ws, pkg, ar_files, dst.file(), &filename)
143+
let uncompressed_size = tar(ws, pkg, ar_files, dst.file(), &filename)
142144
.with_context(|| "failed to prepare local package for uploading")?;
143145
if opts.verify {
144146
dst.seek(SeekFrom::Start(0))?;
@@ -151,6 +153,22 @@ pub fn package_one(
151153
fs::rename(&src_path, &dst_path)
152154
.with_context(|| "failed to move temporary tarball into final location")?;
153155

156+
let dst_metadata = dst
157+
.file()
158+
.metadata()
159+
.with_context(|| format!("could not learn metadata for: `{}`", dst_path.display()))?;
160+
let compressed_size = dst_metadata.len();
161+
162+
let uncompressed = human_readable_bytes(uncompressed_size);
163+
let compressed = human_readable_bytes(compressed_size);
164+
165+
let message = format!(
166+
"{} files, {:.1}{} ({:.1}{} compressed)",
167+
filecount, uncompressed.0, uncompressed.1, compressed.0, compressed.1,
168+
);
169+
// It doesn't really matter if this fails.
170+
drop(config.shell().status("Packaged", message));
171+
154172
return Ok(Some(dst));
155173
}
156174

@@ -567,13 +585,16 @@ fn check_repo_state(
567585
}
568586
}
569587

588+
/// Compresses and packages a list of [`ArchiveFile`]s and writes into the given file.
589+
///
590+
/// Returns the uncompressed size of the contents of the new archive file.
570591
fn tar(
571592
ws: &Workspace<'_>,
572593
pkg: &Package,
573594
ar_files: Vec<ArchiveFile>,
574595
dst: &File,
575596
filename: &str,
576-
) -> CargoResult<()> {
597+
) -> CargoResult<u64> {
577598
// Prepare the encoder and its header.
578599
let filename = Path::new(filename);
579600
let encoder = GzBuilder::new()
@@ -586,6 +607,8 @@ fn tar(
586607

587608
let base_name = format!("{}-{}", pkg.name(), pkg.version());
588609
let base_path = Path::new(&base_name);
610+
611+
let mut uncompressed_size = 0;
589612
for ar_file in ar_files {
590613
let ArchiveFile {
591614
rel_path,
@@ -611,6 +634,7 @@ fn tar(
611634
.with_context(|| {
612635
format!("could not archive source file `{}`", disk_path.display())
613636
})?;
637+
uncompressed_size += metadata.len() as u64;
614638
}
615639
FileContents::Generated(generated_kind) => {
616640
let contents = match generated_kind {
@@ -626,13 +650,14 @@ fn tar(
626650
header.set_cksum();
627651
ar.append_data(&mut header, &ar_path, contents.as_bytes())
628652
.with_context(|| format!("could not archive source file `{}`", rel_str))?;
653+
uncompressed_size += contents.len() as u64;
629654
}
630655
}
631656
}
632657

633658
let encoder = ar.into_inner()?;
634659
encoder.finish()?;
635-
Ok(())
660+
Ok(uncompressed_size)
636661
}
637662

638663
/// Generate warnings when packaging Cargo.lock, and the resolve have changed.

src/cargo/sources/git/utils.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
use crate::core::GitReference;
55
use crate::util::errors::CargoResult;
6-
use crate::util::{network, Config, IntoUrl, MetricsCounter, Progress};
6+
use crate::util::{human_readable_bytes, network, Config, IntoUrl, MetricsCounter, Progress};
77
use anyhow::{anyhow, Context as _};
88
use cargo_util::{paths, ProcessBuilder};
99
use curl::easy::List;
@@ -755,13 +755,8 @@ pub fn with_fetch_options(
755755
counter.add(stats.received_bytes(), now);
756756
last_update = now;
757757
}
758-
fn format_bytes(bytes: f32) -> (&'static str, f32) {
759-
static UNITS: [&str; 5] = ["", "Ki", "Mi", "Gi", "Ti"];
760-
let i = (bytes.log2() / 10.0).min(4.0) as usize;
761-
(UNITS[i], bytes / 1024_f32.powi(i as i32))
762-
}
763-
let (unit, rate) = format_bytes(counter.rate());
764-
format!(", {:.2}{}B/s", rate, unit)
758+
let (rate, unit) = human_readable_bytes(counter.rate() as u64);
759+
format!(", {:.2}{}/s", rate, unit)
765760
};
766761
progress
767762
.tick(stats.indexed_objects(), stats.total_objects(), &msg)

src/cargo/util/mod.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,15 @@ pub fn elapsed(duration: Duration) -> String {
7373
}
7474
}
7575

76+
/// Formats a number of bytes into a human readable SI-prefixed size.
77+
/// Returns a tuple of `(quantity, units)`.
78+
pub fn human_readable_bytes(bytes: u64) -> (f32, &'static str) {
79+
static UNITS: [&str; 7] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"];
80+
let bytes = bytes as f32;
81+
let i = ((bytes.log2() / 10.0) as usize).min(UNITS.len() - 1);
82+
(bytes / 1024_f32.powi(i as i32), UNITS[i])
83+
}
84+
7685
pub fn iter_join_onto<W, I, T>(mut w: W, iter: I, delim: &str) -> fmt::Result
7786
where
7887
W: fmt::Write,
@@ -122,3 +131,37 @@ pub fn truncate_with_ellipsis(s: &str, max_width: usize) -> String {
122131
}
123132
prefix
124133
}
134+
135+
#[cfg(test)]
136+
mod test {
137+
use super::*;
138+
139+
#[test]
140+
fn test_human_readable_bytes() {
141+
assert_eq!(human_readable_bytes(0), (0., "B"));
142+
assert_eq!(human_readable_bytes(8), (8., "B"));
143+
assert_eq!(human_readable_bytes(1000), (1000., "B"));
144+
assert_eq!(human_readable_bytes(1024), (1., "KiB"));
145+
assert_eq!(human_readable_bytes(1024 * 420 + 512), (420.5, "KiB"));
146+
assert_eq!(human_readable_bytes(1024 * 1024), (1., "MiB"));
147+
assert_eq!(
148+
human_readable_bytes(1024 * 1024 + 1024 * 256),
149+
(1.25, "MiB")
150+
);
151+
assert_eq!(human_readable_bytes(1024 * 1024 * 1024), (1., "GiB"));
152+
assert_eq!(
153+
human_readable_bytes((1024. * 1024. * 1024. * 3.1415) as u64),
154+
(3.1415, "GiB")
155+
);
156+
assert_eq!(human_readable_bytes(1024 * 1024 * 1024 * 1024), (1., "TiB"));
157+
assert_eq!(
158+
human_readable_bytes(1024 * 1024 * 1024 * 1024 * 1024),
159+
(1., "PiB")
160+
);
161+
assert_eq!(
162+
human_readable_bytes(1024 * 1024 * 1024 * 1024 * 1024 * 1024),
163+
(1., "EiB")
164+
);
165+
assert_eq!(human_readable_bytes(u64::MAX), (16., "EiB"));
166+
}
167+
}

tests/testsuite/artifact_dep.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,6 +1919,7 @@ fn publish_artifact_dep() {
19191919
"\
19201920
[UPDATING] [..]
19211921
[PACKAGING] foo v0.1.0 [..]
1922+
[PACKAGED] [..]
19221923
[UPLOADING] foo v0.1.0 [..]
19231924
[UPDATING] [..]
19241925
",

tests/testsuite/credential_process.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ Only one of these values may be set, remove one or the other to proceed.
134134
"\
135135
[UPDATING] [..]
136136
[PACKAGING] foo v0.1.0 [..]
137+
[PACKAGED] [..]
137138
[UPLOADING] foo v0.1.0 [..]
138139
[UPDATING] [..]
139140
",
@@ -208,6 +209,7 @@ fn publish() {
208209
"\
209210
[UPDATING] [..]
210211
[PACKAGING] foo v0.1.0 [..]
212+
[PACKAGED] [..]
211213
[UPLOADING] foo v0.1.0 [..]
212214
[UPDATING] [..]
213215
",

tests/testsuite/cross_publish.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ fn simple_cross_package() {
4646
[VERIFYING] foo v0.0.0 ([CWD])
4747
[COMPILING] foo v0.0.0 ([CWD]/target/package/foo-0.0.0)
4848
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
49+
[PACKAGED] 4 files, [..] ([..] compressed)
4950
",
5051
)
5152
.run();
@@ -109,6 +110,7 @@ fn publish_with_target() {
109110
[VERIFYING] foo v0.0.0 ([CWD])
110111
[COMPILING] foo v0.0.0 ([CWD]/target/package/foo-0.0.0)
111112
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
113+
[PACKAGED] [..]
112114
[UPLOADING] foo v0.0.0 ([CWD])
113115
[UPDATING] crates.io index
114116
",

tests/testsuite/features_namespaced.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,7 @@ fn publish_no_implicit() {
902902
"\
903903
[UPDATING] [..]
904904
[PACKAGING] foo v0.1.0 [..]
905+
[PACKAGED] [..]
905906
[UPLOADING] foo v0.1.0 [..]
906907
[UPDATING] [..]
907908
",
@@ -1029,6 +1030,7 @@ fn publish() {
10291030
[VERIFYING] foo v0.1.0 [..]
10301031
[COMPILING] foo v0.1.0 [..]
10311032
[FINISHED] [..]
1033+
[PACKAGED] [..]
10321034
[UPLOADING] foo v0.1.0 [..]
10331035
[UPDATING] [..]
10341036
",

0 commit comments

Comments
 (0)