Compare commits

...

10 Commits

Author SHA1 Message Date
andy.boot 9836ada41e fix: status mesages go to stderr not stdout
Progress spinner and status line are written to stderr
instead of stdout.

No longer any need to detect if stdout is being redirected.
2025-03-31 23:20:10 +01:00
Aidan Beggs 733abb2a3f feat: Abort immedietly when ^C is received. (#478)
Previously, we attempted to perform a clean shutdown, which could take a
significant period of time on slow filesystems. This commit changes the
shutdown logic to abort immedietly when ^C is received by the program.
2025-03-30 17:35:28 +01:00
andy.boot dd799706fb deps: cargo update (#474)
* deps: cargo update

* deps: Update edition 2024

and run cargo update
2025-03-11 00:38:38 +00:00
Teemu Pätsi b219981c52 rewrite: Reduce indentation with guard clause 2025-03-10 21:25:13 +00:00
Teemu Pätsi c31468b199 perf: Canonicalize ignored absolute path only once 2025-03-10 21:25:13 +00:00
Teemu Pätsi 28d409ea27 refactor: Extract is_ignored_path function 2025-03-10 21:25:13 +00:00
Teemu Pätsi aa319e3599 perf: Do not canonicalize non-absolute ignored path 2025-03-10 21:25:13 +00:00
Teemu Pätsi c2a4c4573a fix: Ignoring absolute path with -X option 2025-03-10 21:25:13 +00:00
andy.boot d876cc28a7 release: Increment version 2025-02-27 22:08:38 +00:00
andy.boot 137e366eca feat: Handle duplicate dir names better
If we run `dust /usr/*/Trash`
We see several 'Trash' directories in the output but do not know which
user they belong to.

This fix means if we see duplicate names in a directory we will display
the parent directory name as well
2025-02-20 22:08:06 +00:00
15 changed files with 215 additions and 111 deletions
Generated
+62 -56
View File
@@ -115,9 +115,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.8.0"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "bstr"
@@ -138,9 +138,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "cc"
version = "1.2.12"
version = "1.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2"
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
dependencies = [
"shlex",
]
@@ -159,32 +159,32 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.39"
version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets 0.52.6",
"windows-link",
]
[[package]]
name = "clap"
version = "4.5.28"
version = "4.5.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff"
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.27"
version = "4.5.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
dependencies = [
"anstream",
"anstyle",
@@ -194,9 +194,9 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.44"
version = "4.5.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375f9d8255adeeedd51053574fd8d4ba875ea5fa558e86617b07f09f1680c8b6"
checksum = "f5c5508ea23c5366f77e53f5a0070e5a84e51687ec3ef9e0464c86dc8d13ce98"
dependencies = [
"clap",
]
@@ -309,7 +309,7 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "du-dust"
version = "1.1.1"
version = "1.1.2"
dependencies = [
"ansi_term",
"assert_cmd",
@@ -338,9 +338,9 @@ dependencies = [
[[package]]
name = "either"
version = "1.13.0"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "errno"
@@ -438,9 +438,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itoa"
version = "1.0.14"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "js-sys"
@@ -454,9 +454,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.169"
version = "0.2.170"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
[[package]]
name = "libredox"
@@ -464,7 +464,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.8.0",
"bitflags 2.9.0",
"libc",
]
@@ -476,15 +476,15 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9"
[[package]]
name = "log"
version = "0.4.25"
version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
[[package]]
name = "lscolors"
@@ -508,7 +508,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.8.0",
"bitflags 2.9.0",
"cfg-if",
"cfg_aliases",
"libc",
@@ -544,9 +544,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.20.2"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]]
name = "overload"
@@ -556,9 +556,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "portable-atomic"
version = "1.10.0"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
[[package]]
name = "predicates"
@@ -589,18 +589,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.93"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.38"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
dependencies = [
"proc-macro2",
]
@@ -687,43 +687,43 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.44"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657"
dependencies = [
"bitflags 2.8.0",
"bitflags 2.9.0",
"errno",
"libc",
"linux-raw-sys 0.4.15",
"linux-raw-sys 0.9.2",
"windows-sys 0.59.0",
]
[[package]]
name = "rustversion"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "ryu"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "serde"
version = "1.0.217"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.217"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
@@ -732,9 +732,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.138"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
@@ -762,9 +762,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.98"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
@@ -788,15 +788,15 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.16.0"
version = "3.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567"
dependencies = [
"cfg-if",
"fastrand",
"getrandom 0.3.1",
"once_cell",
"rustix 0.38.44",
"rustix 1.0.1",
"windows-sys 0.59.0",
]
@@ -853,9 +853,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.16"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-width"
@@ -991,6 +991,12 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-link"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
[[package]]
name = "windows-sys"
version = "0.48.0"
@@ -1136,5 +1142,5 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags 2.8.0",
"bitflags 2.9.0",
]
+2 -2
View File
@@ -1,9 +1,9 @@
[package]
name = "du-dust"
description = "A more intuitive version of du"
version = "1.1.1"
version = "1.1.2"
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
edition = "2021"
edition = "2024"
readme = "README.md"
documentation = "https://github.com/bootandy/dust"
+2 -2
View File
@@ -1,6 +1,6 @@
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.TH Dust 1 "Dust 1.1.1"
.TH Dust 1 "Dust 1.1.2"
.SH NAME
Dust \- Like du but more intuitive
.SH SYNOPSIS
@@ -137,4 +137,4 @@ Print version
[\fIPATH\fR]
.SH VERSION
v1.1.1
v1.1.2
+1 -1
View File
@@ -1,4 +1,4 @@
use clap::{builder::PossibleValue, value_parser, Arg, Command};
use clap::{Arg, Command, builder::PossibleValue, value_parser};
// For single thread mode set this variable on your command line:
// export RAYON_NUM_THREADS=1
+2 -5
View File
@@ -4,7 +4,6 @@ use clap::ArgMatches;
use config_file::FromConfigFile;
use regex::Regex;
use serde::Deserialize;
use std::io::IsTerminal;
use std::path::Path;
use std::path::PathBuf;
@@ -54,9 +53,7 @@ impl Config {
Some(true) == self.force_colors || options.get_flag("force_colors")
}
pub fn get_disable_progress(&self, options: &ArgMatches) -> bool {
Some(true) == self.disable_progress
|| options.get_flag("disable_progress")
|| !std::io::stdout().is_terminal()
Some(true) == self.disable_progress || options.get_flag("disable_progress")
}
pub fn get_apparent_size(&self, options: &ArgMatches) -> bool {
Some(true) == self.display_apparent_size || options.get_flag("display_apparent_size")
@@ -291,7 +288,7 @@ mod tests {
use super::*;
use chrono::{Datelike, Timelike};
use clap::builder::PossibleValue;
use clap::{value_parser, Arg, ArgMatches, Command};
use clap::{Arg, ArgMatches, Command, value_parser};
#[test]
fn test_get_current_date_epoch_seconds() {
+27 -7
View File
@@ -5,10 +5,10 @@ use std::sync::Arc;
use std::sync::Mutex;
use crate::node::Node;
use crate::progress::ORDERING;
use crate::progress::Operation;
use crate::progress::PAtomicInfo;
use crate::progress::RuntimeErrors;
use crate::progress::ORDERING;
use crate::utils::is_filtered_out_due_to_file_time;
use crate::utils::is_filtered_out_due_to_invert_regex;
use crate::utils::is_filtered_out_due_to_regex;
@@ -125,9 +125,33 @@ fn sort_by_inode(a: &Node, b: &Node) -> std::cmp::Ordering {
}
}
// Check if `path` is inside ignored directory
fn is_ignored_path(path: &Path, walk_data: &WalkData) -> bool {
if walk_data.ignore_directories.contains(path) {
return true;
}
// Entry is inside an ignored absolute path
// Absolute paths should be canonicalized before being added to `WalkData.ignore_directories`
for ignored_path in walk_data.ignore_directories.iter() {
if !ignored_path.is_absolute() {
continue;
}
let absolute_entry_path = std::fs::canonicalize(path).unwrap_or_default();
if absolute_entry_path.starts_with(ignored_path) {
return true;
}
}
false
}
fn ignore_file(entry: &DirEntry, walk_data: &WalkData) -> bool {
if is_ignored_path(&entry.path(), walk_data) {
return true;
}
let is_dot_file = entry.file_name().to_str().unwrap_or("").starts_with('.');
let is_ignored_path = walk_data.ignore_directories.contains(&entry.path());
let follow_links = walk_data.follow_links && entry.file_type().is_ok_and(|ft| ft.is_symlink());
if !walk_data.allowed_filesystems.is_empty() {
@@ -175,17 +199,13 @@ fn ignore_file(entry: &DirEntry, walk_data: &WalkData) -> bool {
return true;
}
(is_dot_file && walk_data.ignore_hidden) || is_ignored_path
is_dot_file && walk_data.ignore_hidden
}
fn walk(dir: PathBuf, walk_data: &WalkData, depth: usize) -> Option<Node> {
let prog_data = &walk_data.progress_data;
let errors = &walk_data.errors;
if errors.lock().unwrap().abort {
return None;
}
let children = if dir.is_dir() {
let read_dir = fs::read_dir(&dir);
match read_dir {
+2 -6
View File
@@ -71,11 +71,7 @@ impl DisplayData {
fn percent_size(&self, node: &DisplayNode) -> f32 {
let result = node.size as f32 / self.base_size as f32;
if result.is_normal() {
result
} else {
0.0
}
if result.is_normal() { result } else { 0.0 }
}
}
@@ -273,7 +269,7 @@ fn clean_indentation_string(s: &str) -> String {
is
}
fn get_printable_name<P: AsRef<Path>>(dir_name: &P, short_paths: bool) -> String {
pub fn get_printable_name<P: AsRef<Path>>(dir_name: &P, short_paths: bool) -> String {
let dir_name = dir_name.as_ref();
let printable_name = {
if short_paths {
+65 -1
View File
@@ -1,3 +1,6 @@
use stfu8::encode_u8;
use crate::display::get_printable_name;
use crate::display_node::DisplayNode;
use crate::node::FileTime;
use crate::node::Node;
@@ -14,6 +17,7 @@ pub struct AggregateData {
pub number_of_lines: usize,
pub depth: usize,
pub using_a_filter: bool,
pub short_paths: bool,
}
pub fn get_biggest(
@@ -40,13 +44,17 @@ pub fn get_biggest(
} else {
top_level_nodes.iter().map(|node| node.size).sum()
};
let nodes = handle_duplicate_top_level_names(top_level_nodes, display_data.short_paths);
root = Node {
name: PathBuf::from("(total)"),
size,
children: top_level_nodes,
children: nodes,
inode_device: None,
depth: 0,
};
// Always include the base nodes if we add a 'parent' (total) node
heap = always_add_children(&display_data, &root, heap);
} else {
@@ -74,6 +82,8 @@ pub fn fill_remaining_lines<'a>(
let line = heap.pop();
match line {
Some(line) => {
// If we are not doing only_file OR if we are doing
// only_file and it has no children (ie is a file not a dir)
if !display_data.only_file || line.children.is_empty() {
allowed_nodes.insert(line.name.as_path(), line);
}
@@ -161,3 +171,57 @@ fn build_display_node(mut new_children: Vec<DisplayNode>, current: &Node) -> Dis
children: new_children,
}
}
fn names_have_dup(top_level_nodes: &Vec<Node>) -> bool {
let mut stored = HashSet::new();
for node in top_level_nodes {
let name = get_printable_name(&node.name, true);
if stored.contains(&name) {
return true;
}
stored.insert(name);
}
false
}
fn handle_duplicate_top_level_names(top_level_nodes: Vec<Node>, short_paths: bool) -> Vec<Node> {
// If we have top level names that are the same - we need to tweak them:
if short_paths && names_have_dup(&top_level_nodes) {
let mut new_top_nodes = top_level_nodes.clone();
let mut dir_walk_up_count = 0;
while names_have_dup(&new_top_nodes) && dir_walk_up_count < 10 {
dir_walk_up_count += 1;
let mut newer = vec![];
for node in new_top_nodes.iter() {
let mut folders = node.name.iter().rev();
// Get parent folder (if second time round get grandparent and so on)
for _ in 0..dir_walk_up_count {
folders.next();
}
match folders.next() {
// Add (parent_name) to path of Node
Some(data) => {
let parent = encode_u8(data.as_encoded_bytes());
let current_node = node.name.display();
let n = Node {
name: PathBuf::from(format!("{current_node}({parent})")),
size: node.size,
children: node.children.clone(),
inode_device: node.inode_device,
depth: node.depth,
};
newer.push(n)
}
// Node does not have a parent
None => newer.push(node.clone()),
}
}
new_top_nodes = newer;
}
new_top_nodes
} else {
top_level_nodes
}
}
+5 -16
View File
@@ -24,11 +24,10 @@ use std::fs::read_to_string;
use std::io;
use std::panic;
use std::process;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::sync::Mutex;
use sysinfo::{System, SystemExt};
use utils::canonicalize_absolute_path;
use self::display::draw_it;
use config::get_config;
@@ -39,7 +38,7 @@ use filter_type::get_all_file_types;
use regex::Regex;
use std::cmp::max;
use std::path::PathBuf;
use terminal_size::{terminal_size, Height, Width};
use terminal_size::{Height, Width, terminal_size};
use utils::get_filesystem_devices;
use utils::simplify_dir_names;
@@ -118,20 +117,13 @@ fn main() {
let errors = RuntimeErrors::default();
let error_listen_for_ctrlc = Arc::new(Mutex::new(errors));
let errors_for_rayon = error_listen_for_ctrlc.clone();
let errors_final = error_listen_for_ctrlc.clone();
let is_in_listing = Arc::new(AtomicBool::new(false));
let cloned_is_in_listing = Arc::clone(&is_in_listing);
ctrlc::set_handler(move || {
error_listen_for_ctrlc.lock().unwrap().abort = true;
println!("\nAborting");
if cloned_is_in_listing.load(Ordering::Relaxed) {
process::exit(1);
}
process::exit(1);
})
.expect("Error setting Ctrl-C handler");
is_in_listing.store(true, Ordering::Relaxed);
let target_dirs = match config.get_files_from(&options) {
Some(path) => {
if path == "-" {
@@ -161,7 +153,6 @@ fn main() {
None => vec![".".to_owned()],
},
};
is_in_listing.store(false, Ordering::Relaxed);
let summarize_file_types = options.get_flag("types");
@@ -198,6 +189,7 @@ fn main() {
Some(values) => values
.map(|v| v.as_str())
.map(PathBuf::from)
.map(canonicalize_absolute_path)
.collect::<Vec<PathBuf>>(),
None => vec![],
};
@@ -293,6 +285,7 @@ fn main() {
number_of_lines,
depth,
using_a_filter: !filter_regexs.is_empty() || !invert_filter_regexs.is_empty(),
short_paths: !config.get_full_paths(&options),
};
get_biggest(top_level_nodes, agg_data, &by_filetime, keep_collapsed)
}
@@ -301,10 +294,6 @@ fn main() {
// Must have stopped indicator before we print to stderr
indicator.stop();
if errors_final.lock().unwrap().abort {
return;
}
let final_errors = walk_data.errors.lock().unwrap();
if !final_errors.file_not_found.is_empty() {
let err = final_errors
+6 -6
View File
@@ -48,9 +48,9 @@ pub fn build_node(
|| is_filtered_out_due_to_invert_regex(walk_data.invert_filter_regex, &dir)
|| by_filecount && !is_file
|| [
(&walk_data.filter_modified_time, data.2 .0),
(&walk_data.filter_accessed_time, data.2 .1),
(&walk_data.filter_changed_time, data.2 .2),
(&walk_data.filter_modified_time, data.2.0),
(&walk_data.filter_accessed_time, data.2.1),
(&walk_data.filter_changed_time, data.2.2),
]
.iter()
.any(|(filter_time, actual_time)| {
@@ -61,9 +61,9 @@ pub fn build_node(
1
} else if by_filetime.is_some() {
match by_filetime {
Some(FileTime::Modified) => data.2 .0.unsigned_abs(),
Some(FileTime::Accessed) => data.2 .1.unsigned_abs(),
Some(FileTime::Changed) => data.2 .2.unsigned_abs(),
Some(FileTime::Modified) => data.2.0.unsigned_abs(),
Some(FileTime::Accessed) => data.2.1.unsigned_abs(),
Some(FileTime::Changed) => data.2.2.unsigned_abs(),
None => unreachable!(),
}
} else {
+11 -9
View File
@@ -3,9 +3,9 @@ use std::{
io::Write,
path::Path,
sync::{
Arc, RwLock,
atomic::{AtomicU8, AtomicUsize, Ordering},
mpsc::{self, RecvTimeoutError, Sender},
Arc, RwLock,
},
thread::JoinHandle,
time::Duration,
@@ -79,7 +79,6 @@ pub struct RuntimeErrors {
pub file_not_found: HashSet<String>,
pub unknown_error: HashSet<String>,
pub interrupted_error: i32,
pub abort: bool,
}
/* -------------------------------------------------------------------------- */
@@ -119,7 +118,7 @@ impl PIndicator {
let time_info_thread = std::thread::spawn(move || {
let mut progress_char_i: usize = 0;
let mut stdout = std::io::stdout();
let mut stderr = std::io::stderr();
let mut msg = "".to_string();
// While the timeout triggers we go round the loop
@@ -128,7 +127,8 @@ impl PIndicator {
receiver.recv_timeout(Duration::from_millis(SPINNER_SLEEP_TIME))
{
// Clear the text written by 'write!'& Return at the start of line
print!("\r{:width$}", " ", width = msg.len());
let clear = format!("\r{:width$}", " ", width = msg.len());
write!(stderr, "{clear}").unwrap();
let prog_char = PROGRESS_CHARS[progress_char_i];
msg = match data.state.load(ORDERING) {
@@ -137,15 +137,17 @@ impl PIndicator {
_ => panic!("Unknown State"),
};
write!(stdout, "\r{msg}").unwrap();
stdout.flush().unwrap();
write!(stderr, "\r{msg}").unwrap();
stderr.flush().unwrap();
progress_char_i += 1;
progress_char_i %= PROGRESS_CHARS_LEN;
}
print!("\r{:width$}", " ", width = msg.len());
print!("\r");
stdout.flush().unwrap();
let clear = format!("\r{:width$}", " ", width = msg.len());
write!(stderr, "{clear}").unwrap();
write!(stderr, "\r").unwrap();
stderr.flush().unwrap();
});
self.thread = Some((stop_handler, time_info_thread))
}
+11
View File
@@ -67,6 +67,17 @@ pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
path.as_ref().components().collect()
}
// Canonicalize the path only if it is an absolute path
pub fn canonicalize_absolute_path(path: PathBuf) -> PathBuf {
if !path.is_absolute() {
return path;
}
match std::fs::canonicalize(&path) {
Ok(canonicalized_path) => canonicalized_path,
Err(_) => path,
}
}
pub fn is_filtered_out_due_to_regex(filter_regex: &[Regex], dir: &Path) -> bool {
if filter_regex.is_empty() {
false
+19
View File
@@ -10,6 +10,9 @@ use std::str;
fn build_command<T: AsRef<OsStr>>(command_args: Vec<T>) -> String {
let mut cmd = &mut Command::cargo_bin("dust").unwrap();
// Hide progress bar
cmd = cmd.arg("-P");
for p in command_args {
cmd = cmd.arg(p);
}
@@ -261,3 +264,19 @@ pub fn test_collapse() {
assert!(output.contains("many"));
assert!(!output.contains("hello_file"));
}
#[test]
pub fn test_handle_duplicate_names() {
// Check that even if we run on a multiple directories with the same name
// we still show the distinct parent dir in the output
let output = build_command(vec![
"tests/test_dir_matching/dave/dup_name",
"tests/test_dir_matching/andy/dup_name",
"ci",
]);
assert!(output.contains("andy"));
assert!(output.contains("dave"));
assert!(output.contains("ci"));
assert!(output.contains("dup_name"));
assert!(!output.contains("test_dir_matching"));
}