diff --git a/Cargo.lock b/Cargo.lock index 82732a0..e05768c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,7 +17,7 @@ dependencies = [ "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "skeptic 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -26,7 +26,7 @@ name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -42,7 +42,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -51,8 +51,8 @@ name = "backtrace-sys" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -82,12 +82,12 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -105,7 +105,7 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -234,7 +234,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -248,7 +248,7 @@ name = "hermit-abi" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -272,7 +272,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.65" +version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -289,7 +289,7 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -327,7 +327,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -339,7 +339,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -483,12 +483,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.42" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -506,7 +506,7 @@ dependencies = [ "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -518,7 +518,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -541,7 +541,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -553,12 +553,12 @@ name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-width" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -629,7 +629,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bytecount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b92204551573580e078dc80017f36a213eb77a0450e4ddd8cfa0f3f2d1f0178f" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cargo_metadata 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e5d1b4d380e1bab994591a24c2bdd1b054f64b60bef483a8c598c7c345bc3bbe" -"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" +"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "433e7ac7d511768127ed85b0c4947f47a254131e37864b2dc13f52aa32cd37e5" @@ -651,7 +651,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3dbf0a8f61baee43a2918ff50ac6a2d3b2c105bc08ed53bc298779f1263409" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" "checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" @@ -679,14 +679,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" "checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" -"checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" +"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" "checksum skeptic 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fb8ed853fdc19ce09752d63f3a2e5b5158aeb261520cd75eb618bd60305165" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" diff --git a/src/display.rs b/src/display.rs index f7d6a49..752f12c 100644 --- a/src/display.rs +++ b/src/display.rs @@ -20,6 +20,7 @@ impl DisplayData { } } + #[allow(clippy::collapsible_if)] fn get_tree_chars( &self, num_siblings: u64, diff --git a/src/main.rs b/src/main.rs index fb28148..29c4642 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ extern crate clap; use self::display::draw_it; +use crate::utils::is_a_parent_of; use clap::{App, AppSettings, Arg}; use utils::{find_big_ones, get_dir_tree, simplify_dir_names, sort, trim_deep_ones, Node}; @@ -106,7 +107,6 @@ fn main() { } }; let tree = build_tree(biggest_ones, depth); - //println!("{:?}", tree); draw_it( permissions, @@ -126,7 +126,8 @@ fn build_tree(biggest_ones: Vec<(String, u64)>, depth: Option) -> Node { size: b.1, children: Vec::default(), }; - recursively_build_tree(&mut top_parent, n, depth) + recursively_build_tree(&mut top_parent, n, depth); + top_parent.children.sort_unstable() } top_parent } @@ -140,7 +141,7 @@ fn recursively_build_tree(parent_node: &mut Node, new_node: Node, depth: Option< if let Some(c) = parent_node .children .iter_mut() - .find(|c| new_node.name.starts_with(&c.name)) + .find(|c| is_a_parent_of(&c.name, &new_node.name)) { recursively_build_tree(c, new_node, new_depth); } else { diff --git a/src/test_dir2/dir/hello b/src/test_dir2/dir/hello new file mode 100644 index 0000000..b6fc4c6 --- /dev/null +++ b/src/test_dir2/dir/hello @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/src/test_dir2/dir_name_clash b/src/test_dir2/dir_name_clash new file mode 100644 index 0000000..b6fc4c6 --- /dev/null +++ b/src/test_dir2/dir_name_clash @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/src/test_dir2/dir_substring/hello b/src/test_dir2/dir_substring/hello new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/src/test_dir2/dir_substring/hello @@ -0,0 +1 @@ +hello diff --git a/src/tests.rs b/src/tests.rs index 12a7463..53c1c36 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -138,7 +138,7 @@ pub fn test_d_flag_works() { .unwrap(); } -fn build_temp_file(dir: &TempDir) -> (PathBuf) { +fn build_temp_file(dir: &TempDir) -> PathBuf { let file_path = dir.path().join("notes.txt"); let mut file = File::create(&file_path).unwrap(); writeln!(file, "I am a temp file").unwrap(); @@ -164,7 +164,7 @@ pub fn test_soft_sym_link() { let r = soft_sym_link_output(dir_s, file_path_s, link_name_s); // We cannot guarantee which version will appear first. - // TODO: Consider adding predictable itteration order (sort file entries by name?) + // TODO: Consider adding predictable iteration order (sort file entries by name?) assert_cli::Assert::main_binary() .with_args(&[dir_s]) .stdout() @@ -308,3 +308,45 @@ fn recursive_sym_link_output(dir: &str, link_name: &str) -> String { format_string(link_name, true, true, " 0B", " └──",), ) } + +// Check against directories and files whos names are substrings of each other +#[test] +#[cfg(target_os = "macos")] +pub fn test_substring_of_names() { + assert_cli::Assert::main_binary() + .with_args(&["src/test_dir2"]) + .stdout() + .contains(" ─┬ test_dir2") + .stdout() + .contains(" ├─┬ dir") + .stdout() + .contains(" │ └── hello") + .stdout() + .contains(" ├── dir_name_clash") + .stdout() + .contains(" └─┬ dir_substring") + .stdout() + .contains(" └── hello") + .unwrap(); +} + +// Check against directories and files whos names are substrings of each other +#[test] +#[cfg(target_os = "linux")] +pub fn test_substring_of_names() { + assert_cli::Assert::main_binary() + .with_args(&["src/test_dir2"]) + .stdout() + .contains(" ─┬ test_dir2") + .stdout() + .contains(" ├─┬ dir") + .stdout() + .contains(" │ └── hello") + .stdout() + .contains(" ├─┬ dir_substring") + .stdout() + .contains(" │ └── hello") + .stdout() + .contains(" └── dir_name_clash") + .unwrap(); +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 5e649d2..cfe84ce 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -7,26 +7,52 @@ use jwalk::WalkDir; mod platform; use self::platform::*; -#[derive(Debug, Default)] +#[derive(Debug, Default, Eq)] pub struct Node { pub name: String, pub size: u64, pub children: Vec, } +impl Ord for Node { + fn cmp(&self, other: &Self) -> Ordering { + if self.size == other.size { + self.name.cmp(&other.name) + } else { + self.size.cmp(&other.size) + } + } +} + +impl PartialOrd for Node { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl PartialEq for Node { + fn eq(&self, other: &Self) -> bool { + self.name == other.name && self.size == other.size && self.children == other.children + } +} + +pub fn is_a_parent_of(parent: &str, child: &str) -> bool { + child.starts_with(parent) && child.chars().nth(parent.chars().count()) == Some('/') +} + pub fn simplify_dir_names(filenames: Vec<&str>) -> HashSet { let mut top_level_names: HashSet = HashSet::with_capacity(filenames.len()); let mut to_remove: Vec = Vec::with_capacity(filenames.len()); for t in filenames { - let top_level_name = ensure_end_slash(t); + let top_level_name = strip_end_slash(t); let mut can_add = true; for tt in top_level_names.iter() { - if top_level_name.starts_with(tt) { - can_add = false; - } else if tt.starts_with(&top_level_name) { + if is_a_parent_of(&top_level_name, tt) { to_remove.push(tt.to_string()); + } else if is_a_parent_of(tt, &top_level_name) { + can_add = false; } } to_remove.sort_unstable(); @@ -62,14 +88,6 @@ pub fn get_dir_tree( (permissions == 0, data) } -pub fn ensure_end_slash(s: &str) -> String { - let mut new_name = String::from(s); - while new_name.ends_with('/') || new_name.ends_with("/.") { - new_name.pop(); - } - new_name + "/" -} - pub fn strip_end_slash(mut new_name: &str) -> &str { while (new_name.ends_with('/') || new_name.ends_with("/.")) && new_name.len() > 1 { new_name = &new_name[..new_name.len() - 1]; @@ -83,13 +101,13 @@ fn examine_dir( inodes: &mut HashSet<(u64, u64)>, data: &mut HashMap, file_count_no_permission: &mut u64, - cpus: Option, + threads: Option, ) { let mut iter = WalkDir::new(top_dir) .preload_metadata(true) .skip_hidden(false); - if let Some(cpus) = cpus { - iter = iter.num_threads(cpus); + if let Some(threads_to_start) = threads { + iter = iter.num_threads(threads_to_start); } for entry in iter { if let Ok(e) = entry { @@ -206,4 +224,12 @@ mod tests { correct.insert("src".to_string()); assert_eq!(simplify_dir_names(vec!["src/."]), correct); } + + #[test] + fn test_simplify_dir_substring_names() { + let mut correct = HashSet::new(); + correct.insert("src".to_string()); + correct.insert("src_v2".to_string()); + assert_eq!(simplify_dir_names(vec!["src/", "src_v2"]), correct); + } }