Skip to content

Commit 3399cfa

Browse files
committed
Add a du utility function.
This adds a very primitive `du` function for determining the disk usage in a directory. This should probably be improved or replaced at some point in the future, this is just a start for supporting tracking sizes of cache data.
1 parent 9304b02 commit 3399cfa

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cargo-util/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ anyhow.workspace = true
1313
sha2.workspace = true
1414
filetime.workspace = true
1515
hex.workspace = true
16+
ignore.workspace = true
1617
jobserver.workspace = true
1718
libc.workspace = true
1819
same-file.workspace = true

crates/cargo-util/src/du.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//! A simple disk usage estimator.
2+
3+
use anyhow::{Context, Result};
4+
use ignore::overrides::OverrideBuilder;
5+
use ignore::{WalkBuilder, WalkState};
6+
use std::path::Path;
7+
use std::sync::atomic::{AtomicU64, Ordering};
8+
use std::sync::{Arc, Mutex};
9+
10+
/// Determines the disk usage of all files in the given directory.
11+
///
12+
/// The given patterns are gitignore style patterns relative to the given
13+
/// path. If there are patterns, it will only count things matching that
14+
/// pattern. `!` can be used to exclude things. See [`OverrideBuilder::add`]
15+
/// for more info.
16+
///
17+
/// This is a primitive implementation that doesn't handle hard links, and
18+
/// isn't particularly fast (for example, not using `getattrlistbulk` on
19+
/// macOS). It also only uses actual byte sizes instead of block counts (and
20+
/// thus vastly undercounts directories with lots of small files). It would be
21+
/// nice to improve this or replace it with something better.
22+
pub fn du(path: &Path, patterns: &[&str]) -> Result<u64> {
23+
du_inner(path, patterns).with_context(|| format!("failed to walk `{}`", path.display()))
24+
}
25+
26+
fn du_inner(path: &Path, patterns: &[&str]) -> Result<u64> {
27+
let mut builder = OverrideBuilder::new(path);
28+
for pattern in patterns {
29+
builder.add(pattern)?;
30+
}
31+
let overrides = builder.build()?;
32+
33+
let mut builder = WalkBuilder::new(path);
34+
builder
35+
.overrides(overrides)
36+
.hidden(false)
37+
.parents(false)
38+
.ignore(false)
39+
.git_global(false)
40+
.git_ignore(false)
41+
.git_exclude(false);
42+
let walker = builder.build_parallel();
43+
let total = Arc::new(AtomicU64::new(0));
44+
// A slot used to indicate there was an error while walking.
45+
//
46+
// It is possible that more than one error happens (such as in different
47+
// threads). The error returned is arbitrary in that case.
48+
let err = Arc::new(Mutex::new(None));
49+
walker.run(|| {
50+
Box::new(|entry| {
51+
match entry {
52+
Ok(entry) => match entry.metadata() {
53+
Ok(meta) => {
54+
if meta.is_file() {
55+
total.fetch_add(meta.len(), Ordering::SeqCst);
56+
}
57+
}
58+
Err(e) => {
59+
*err.lock().unwrap() = Some(e.into());
60+
return WalkState::Quit;
61+
}
62+
},
63+
Err(e) => {
64+
*err.lock().unwrap() = Some(e.into());
65+
return WalkState::Quit;
66+
}
67+
}
68+
WalkState::Continue
69+
})
70+
});
71+
72+
if let Some(e) = err.lock().unwrap().take() {
73+
return Err(e);
74+
}
75+
76+
Ok(total.load(Ordering::SeqCst))
77+
}

crates/cargo-util/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
//! Miscellaneous support code used by Cargo.
22
33
pub use self::read2::read2;
4+
pub use du::du;
45
pub use process_builder::ProcessBuilder;
56
pub use process_error::{exit_status_to_string, is_simple_exit_code, ProcessError};
67
pub use sha256::Sha256;
78

9+
mod du;
810
pub mod paths;
911
mod process_builder;
1012
mod process_error;

0 commit comments

Comments
 (0)