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
31 changes: 0 additions & 31 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 13 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ trash-move = ["trash"]
[dependencies]
clap = { version = "4.0.29", features = ["derive", "env"] }
clap_complete = "4.5.54"
jwalk = "0.8.1"
byte-unit = "4"
petgraph = "0.8.3"
itertools = "0.14.0"
Expand Down Expand Up @@ -90,4 +89,16 @@ pretty_assertions = "1.0.0"
tempfile = "3.27.0"

[lints.clippy]
all = "deny"
all = { level = "warn", priority = -2 }
pedantic = { level = "warn", priority = -1 }
enum_glob_use = "allow"
needless_pass_by_value = "allow"
redundant_closure_for_method_calls = "allow"
large_enum_variant = "allow"
missing_fields_in_debug = "allow"
missing_errors_doc = "allow"
cast_possible_truncation = "allow"
cast_precision_loss = "allow"
too_many_lines = "allow"
format_push_string = "allow"
fn_params_excessive_bools = "allow"
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,6 @@ Maintaining both backends seemed more cumbersome than it's worth and add complex
but I never liked that it seems to have dropped out of support.
Thus `crossterm` is the only remaining backend and it's very actively developed.

### Acknowledgements

Thanks to [jwalk][jwalk], all there was left to do is to write a command-line interface. As `jwalk` matures, **dua** should benefit instantly.

### Limitations

- Does not show symbolic links at all if no path is provided when invoking `dua`
Expand Down Expand Up @@ -281,5 +277,4 @@ Thanks to [jwalk][jwalk], all there was left to do is to write a command-line in

[petgraph]: https://crates.io/crates/petgraph
[rustup]: https://rustup.rs/
[jwalk]: https://crates.io/crates/jwalk
[tui]: https://github.com/fdehau/tui-rs
66 changes: 38 additions & 28 deletions src/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,22 @@ pub fn aggregate(
let mut inodes = InodeFilter::default();
let progress = Throttle::new(Duration::from_millis(100), Duration::from_secs(1).into());

for path in paths.into_iter() {
for path in paths {
num_roots += 1;
let mut num_bytes = 0u128;
let mut num_errors = 0u64;
let device_id = match crossdev::init(path.as_ref()) {
Ok(id) => id,
Err(_) => {
num_errors += 1;
res.num_errors += 1;
aggregates.push((path.as_ref().to_owned(), num_bytes, num_errors));
continue;
}
let Ok(device_id) = crossdev::init(path.as_ref()) else {
num_errors += 1;
res.num_errors += 1;
aggregates.push((path.as_ref().to_owned(), num_bytes, num_errors));
continue;
};
for entry in walk_options.iter_from_path(path.as_ref(), device_id, false) {
for entry in walk_options.iter_from_path(
path.as_ref(),
device_id,
false,
crate::walk::Order::Completion,
) {
stats.entries_traversed += 1;
progress.throttled(|| {
if let Some(err) = err.as_mut() {
Expand All @@ -50,8 +52,8 @@ pub fn aggregate(
});
match entry {
Ok(entry) => {
let file_size = match entry.client_state {
Some(Ok(ref m))
let file_size = u128::from(match &entry.metadata {
Ok(m)
if (walk_options.count_hard_links || inodes.add(m))
&& (walk_options.cross_filesystems
|| crossdev::is_same_device(device_id, m)) =>
Expand All @@ -65,13 +67,12 @@ pub fn aggregate(
})
}
}
Some(Ok(_)) => 0,
Some(Err(_)) => {
Ok(_) => 0,
Err(_) => {
num_errors += 1;
0
}
None => 0, // ignore directory
} as u128;
});
stats.largest_file_in_bytes = stats.largest_file_in_bytes.max(file_size);
stats.smallest_file_in_bytes = stats.smallest_file_in_bytes.min(file_size);
num_bytes += file_size;
Expand Down Expand Up @@ -105,17 +106,7 @@ pub fn aggregate(
}

if sort_by_size_in_bytes {
aggregates.sort_by_key(|&(_, num_bytes, _)| num_bytes);
for (path, num_bytes, num_errors) in aggregates.into_iter() {
output_colored_path(
&mut out,
&path,
num_bytes,
num_errors,
path_color_of(&path),
byte_format,
)?;
}
output_sorted(&mut out, aggregates, byte_format)?;
}

if num_roots > 1 && compute_total {
Expand All @@ -131,6 +122,25 @@ pub fn aggregate(
Ok((res, stats))
}

fn output_sorted(
out: &mut impl io::Write,
mut aggregates: Vec<(std::path::PathBuf, u128, u64)>,
byte_format: ByteFormat,
) -> std::result::Result<(), io::Error> {
aggregates.sort_by_key(|&(_, num_bytes, _)| num_bytes);
for (path, num_bytes, num_errors) in aggregates {
output_colored_path(
out,
&path,
num_bytes,
num_errors,
path_color_of(&path),
byte_format,
)?;
}
Ok(())
}

fn path_color_of(path: impl AsRef<Path>) -> Option<Color> {
(!path.as_ref().is_file()).then_some(Color::Cyan)
}
Expand All @@ -154,7 +164,7 @@ fn output_colored_path(
plural_s = if num_errors > 1 { "s" } else { "" }
)
} else {
"".into()
String::new()
};

if let Some(color) = path_color {
Expand Down
Loading
Loading