Compare commits

..

3 Commits

Author SHA1 Message Date
andy.boot 5c45ed344f Update version 2021-06-23 09:25:04 +01:00
andy.boot a8725711fa README: Add another tool to list of alternatives 2021-06-22 13:17:34 +01:00
andy.boot 811d3b065f README: Remove -x option
This behaviour was removed in previous commit
2021-06-22 13:17:26 +01:00
12 changed files with 92 additions and 146 deletions
+4 -4
View File
@@ -82,11 +82,11 @@ jobs:
job: job:
# { os, target, cargo-options, features, use-cross, toolchain } # { os, target, cargo-options, features, use-cross, toolchain }
- { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf , use-cross: use-cross } - { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf , use-cross: use-cross }
- { os: ubuntu-20.04 , target: i686-unknown-linux-gnu , use-cross: use-cross } - { os: ubuntu-18.04 , target: i686-unknown-linux-gnu , use-cross: use-cross }
- { os: ubuntu-20.04 , target: i686-unknown-linux-musl , use-cross: use-cross } - { os: ubuntu-18.04 , target: i686-unknown-linux-musl , use-cross: use-cross }
- { os: ubuntu-20.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross }
- { os: ubuntu-20.04 , target: x86_64-unknown-linux-musl , use-cross: use-cross }
- { os: ubuntu-18.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross } - { os: ubuntu-18.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross }
- { os: ubuntu-18.04 , target: x86_64-unknown-linux-musl , use-cross: use-cross }
- { os: ubuntu-16.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross }
- { os: macos-latest , target: x86_64-apple-darwin } - { os: macos-latest , target: x86_64-apple-darwin }
- { os: windows-latest , target: i686-pc-windows-gnu } - { os: windows-latest , target: i686-pc-windows-gnu }
- { os: windows-latest , target: i686-pc-windows-msvc } - { os: windows-latest , target: i686-pc-windows-msvc }
Generated
+14 -23
View File
@@ -31,9 +31,9 @@ dependencies = [
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "1.0.7" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d20831bd004dda4c7c372c19cdabff369f794a95e955b3f13fe460e3e1ae95f" checksum = "a88b6bd5df287567ffdf4ddf4d33060048e1068308e5f62d81c6f9824a045a48"
dependencies = [ dependencies = [
"bstr", "bstr",
"doc-comment", "doc-comment",
@@ -144,10 +144,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "difflib" name = "difference"
version = "0.4.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
[[package]] [[package]]
name = "doc-comment" name = "doc-comment"
@@ -157,12 +157,13 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]] [[package]]
name = "du-dust" name = "du-dust"
version = "0.6.2" version = "0.6.0"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"assert_cmd", "assert_cmd",
"clap", "clap",
"lscolors", "lscolors",
"num_cpus",
"rayon", "rayon",
"stfu8", "stfu8",
"tempfile", "tempfile",
@@ -191,22 +192,13 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "itertools"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
dependencies = [
"either",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@@ -215,9 +207,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.98" version = "0.2.97"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
[[package]] [[package]]
name = "lscolors" name = "lscolors"
@@ -261,12 +253,11 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]] [[package]]
name = "predicates" name = "predicates"
version = "2.0.0" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e46ca79eb4e21e2ec14430340c71250ab69332abf85521c95d3a8bc336aa76" checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df"
dependencies = [ dependencies = [
"difflib", "difference",
"itertools",
"predicates-core", "predicates-core",
] ]
+2 -1
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "du-dust" name = "du-dust"
description = "A more intuitive version of du" description = "A more intuitive version of du"
version = "0.6.2" version = "0.6.0"
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"] authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
edition = "2018" edition = "2018"
@@ -24,6 +24,7 @@ path = "src/main.rs"
ansi_term = "0.12" ansi_term = "0.12"
clap = { version = "=2.33", features = ["wrap_help"] } clap = { version = "=2.33", features = ["wrap_help"] }
lscolors = "0.7" lscolors = "0.7"
num_cpus = "1"
terminal_size = "0.1" terminal_size = "0.1"
unicode-width = "0.1" unicode-width = "0.1"
rayon="1" rayon="1"
+7 -11
View File
@@ -44,17 +44,13 @@ Dust will list a slightly-less-than-the-terminal-height number of the biggest su
Usage: dust Usage: dust
Usage: dust <dir> Usage: dust <dir>
Usage: dust <dir> <another_dir> <and_more> Usage: dust <dir> <another_dir> <and_more>
Usage: dust -p (full-path - Show fullpath of the subdirectories) Usage: dust -p <dir> (full-path - does not shorten the path of the subdirectories)
Usage: dust -s (apparent-size - shows the length of the file as opposed to the amount of disk space it uses) Usage: dust -s <dir> (apparent-size - shows the length of the file as opposed to the amount of disk space it uses)
Usage: dust -n 30 (shows 30 directories instead of the default [default is terminal height]) Usage: dust -n 30 <dir> (shows 30 directories instead of the default)
Usage: dust -d 3 (shows 3 levels of subdirectories) Usage: dust -d 3 <dir> (shows 3 levels of subdirectories)
Usage: dust -r (reverse order of output) Usage: dust -r <dir> (reverse order of output, with root at the lowest)
Usage: dust -X ignore (ignore all files and directories with the name 'ignore') Usage: dust -X ignore <dir> (ignore all files and directories with the name 'ignore')
Usage: dust -x (only show directories on the same filesystem) Usage: dust -b <dir> (do not show percentages or draw ASCII bars)
Usage: dust -b (do not show percentages or draw ASCII bars)
Usage: dust -i (do not show hidden files)
Usage: dust -c (No colors [monochrome])
Usage: dust -f (Count files instead of diskspace)
``` ```
+1 -1
View File
@@ -1,6 +1,6 @@
# ----------- To do a release --------- # ----------- To do a release ---------
# edit version in cargo.toml # edit version in cargo.toml
# tag a commit and push (increment version in Cargo.toml first): # tag a commit and push (increment version first):
# git tag v0.4.5 # git tag v0.4.5
# git push origin v0.4.5 # git push origin v0.4.5
+44 -40
View File
@@ -13,27 +13,30 @@ use std::collections::HashSet;
use crate::node::build_node; use crate::node::build_node;
use std::fs::DirEntry; use std::fs::DirEntry;
use crate::platform::get_metadata; pub fn walk_it(
dirs: HashSet<PathBuf>,
pub struct WalkData { ignore_directories: HashSet<PathBuf>,
pub ignore_directories: HashSet<PathBuf>, use_apparent_size: bool,
pub allowed_filesystems: HashSet<u64>, by_filecount: bool,
pub use_apparent_size: bool, ignore_hidden: bool,
pub by_filecount: bool, ) -> (Vec<Node>, bool) {
pub ignore_hidden: bool,
}
pub fn walk_it(dirs: HashSet<PathBuf>, walk_data: WalkData) -> (Vec<Node>, bool) {
let permissions_flag = AtomicBool::new(false); let permissions_flag = AtomicBool::new(false);
let top_level_nodes: Vec<_> = dirs let top_level_nodes: Vec<_> = dirs
.into_iter() .into_iter()
.filter_map(|d| { .filter_map(|d| {
let n = walk(d, &permissions_flag, &walk_data); let n = walk(
d,
&permissions_flag,
&ignore_directories,
use_apparent_size,
by_filecount,
ignore_hidden,
);
match n { match n {
Some(n) => { Some(n) => {
let mut inodes: HashSet<(u64, u64)> = HashSet::new(); let mut inodes: HashSet<(u64, u64)> = HashSet::new();
clean_inodes(n, &mut inodes, walk_data.use_apparent_size) clean_inodes(n, &mut inodes, use_apparent_size)
} }
None => None, None => None,
} }
@@ -71,23 +74,24 @@ fn clean_inodes(
}); });
} }
fn ignore_file(entry: &DirEntry, walk_data: &WalkData) -> bool { fn ignore_file(
entry: &DirEntry,
ignore_hidden: bool,
ignore_directories: &HashSet<PathBuf>,
) -> bool {
let is_dot_file = entry.file_name().to_str().unwrap_or("").starts_with('.'); 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 is_ignored_path = ignore_directories.contains(&entry.path());
(is_dot_file && ignore_hidden) || is_ignored_path
if !walk_data.allowed_filesystems.is_empty() {
let size_inode_device = get_metadata(&entry.path(), false);
if let Some((_size, Some((_id, dev)))) = size_inode_device {
if !walk_data.allowed_filesystems.contains(&dev) {
return true;
}
}
}
(is_dot_file && walk_data.ignore_hidden) || is_ignored_path
} }
fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Option<Node> { fn walk(
dir: PathBuf,
permissions_flag: &AtomicBool,
ignore_directories: &HashSet<PathBuf>,
use_apparent_size: bool,
by_filecount: bool,
ignore_hidden: bool,
) -> Option<Node> {
let mut children = vec![]; let mut children = vec![];
if let Ok(entries) = fs::read_dir(dir.clone()) { if let Ok(entries) = fs::read_dir(dir.clone()) {
@@ -100,19 +104,25 @@ fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Op
// rayon doesn't parallelise as well giving a 3X performance drop // rayon doesn't parallelise as well giving a 3X performance drop
// hence we unravel the recursion a bit // hence we unravel the recursion a bit
// return walk(entry.path(), permissions_flag, ignore_directories, allowed_filesystems, use_apparent_size, by_filecount, ignore_hidden); // return walk(entry.path(), permissions_flag, ignore_directories, use_apparent_size, by_filecount, ignore_hidden);
if !ignore_file(entry, walk_data) { if !ignore_file(&entry, ignore_hidden, &ignore_directories) {
if let Ok(data) = entry.file_type() { if let Ok(data) = entry.file_type() {
if data.is_dir() && !data.is_symlink() { if data.is_dir() && !data.is_symlink() {
return walk(entry.path(), permissions_flag, walk_data); return walk(
entry.path(),
permissions_flag,
ignore_directories,
use_apparent_size,
by_filecount,
ignore_hidden,
);
} }
return build_node( return build_node(
entry.path(), entry.path(),
vec![], vec![],
walk_data.use_apparent_size, use_apparent_size,
data.is_symlink(), by_filecount,
walk_data.by_filecount,
); );
} }
} }
@@ -125,13 +135,7 @@ fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Op
} else { } else {
permissions_flag.store(true, atomic::Ordering::Relaxed); permissions_flag.store(true, atomic::Ordering::Relaxed);
} }
build_node( build_node(dir, children, use_apparent_size, by_filecount)
dir,
children,
walk_data.use_apparent_size,
false,
walk_data.by_filecount,
)
} }
mod tests { mod tests {
+5 -5
View File
@@ -125,7 +125,7 @@ pub fn draw_it(
let root_node = option_root_node.unwrap(); let root_node = option_root_node.unwrap();
let num_chars_needed_on_left_most = if by_filecount { let num_chars_needed_on_left_most = if by_filecount {
let max_size = root_node.size; let max_size = root_node.children.iter().map(|n| n.size).fold(0, max);
max_size.separate_with_commas().chars().count() max_size.separate_with_commas().chars().count()
} else { } else {
5 // Under normal usage we need 5 chars to display the size of a directory 5 // Under normal usage we need 5 chars to display the size of a directory
@@ -265,9 +265,9 @@ fn pad_or_trim_filename(node: &DisplayNode, indent: &str, display_data: &Display
// Add spaces after the filename so we can draw the % used bar chart. // Add spaces after the filename so we can draw the % used bar chart.
let name_and_padding = name let name_and_padding = name
+ " " + &(repeat(" ")
.repeat(display_data.longest_string_length - width) .take(display_data.longest_string_length - width)
.as_str(); .collect::<String>());
maybe_trim_filename(name_and_padding, display_data) maybe_trim_filename(name_and_padding, display_data)
} }
@@ -320,7 +320,7 @@ fn get_pretty_size(node: &DisplayNode, is_biggest: bool, display_data: &DisplayD
let size_as_str = node.size.separate_with_commas(); let size_as_str = node.size.separate_with_commas();
let spaces_to_add = let spaces_to_add =
display_data.num_chars_needed_on_left_most - size_as_str.chars().count(); display_data.num_chars_needed_on_left_most - size_as_str.chars().count();
size_as_str + " ".repeat(spaces_to_add).as_str() size_as_str + &*repeat(' ').take(spaces_to_add).collect::<String>()
} else { } else {
format!("{:>5}", human_readable_number(node.size)) format!("{:>5}", human_readable_number(node.size))
}; };
+5 -6
View File
@@ -36,12 +36,11 @@ impl DisplayNode {
} }
pub fn get_children_from_node(&self, is_reversed: bool) -> impl Iterator<Item = DisplayNode> { pub fn get_children_from_node(&self, is_reversed: bool) -> impl Iterator<Item = DisplayNode> {
// we box to avoid the clippy lint warning if is_reversed {
let out: Box<dyn Iterator<Item = DisplayNode>> = if is_reversed { let children: Vec<DisplayNode> = self.children.clone().into_iter().rev().collect();
Box::new(self.children.clone().into_iter().rev()) children.into_iter()
} else { } else {
Box::new(self.children.clone().into_iter()) self.children.clone().into_iter()
}; }
out
} }
} }
+7 -25
View File
@@ -7,16 +7,14 @@ use std::collections::HashSet;
use self::display::draw_it; use self::display::draw_it;
use clap::{App, AppSettings, Arg}; use clap::{App, AppSettings, Arg};
use dir_walker::walk_it; use dirwalker::walk_it;
use dir_walker::WalkData;
use filter::{get_biggest, get_by_depth}; use filter::{get_biggest, get_by_depth};
use std::cmp::max; use std::cmp::max;
use std::path::PathBuf; use std::path::PathBuf;
use terminal_size::{terminal_size, Height, Width}; use terminal_size::{terminal_size, Height, Width};
use utils::get_filesystem_devices;
use utils::simplify_dir_names; use utils::simplify_dir_names;
mod dir_walker; mod dirwalker;
mod display; mod display;
mod display_node; mod display_node;
mod filter; mod filter;
@@ -109,12 +107,6 @@ fn main() {
.multiple(true) .multiple(true)
.help("Exclude any file or directory with this name"), .help("Exclude any file or directory with this name"),
) )
.arg(
Arg::with_name("limit_filesystem")
.short("x")
.long("limit-filesystem")
.help("Only count the files and directories on the same filesystem as the supplied directory"),
)
.arg( .arg(
Arg::with_name("display_apparent_size") Arg::with_name("display_apparent_size")
.short("s") .short("s")
@@ -149,7 +141,7 @@ fn main() {
Arg::with_name("ignore_hidden") Arg::with_name("ignore_hidden")
.short("i") // Do not use 'h' this is used by 'help' .short("i") // Do not use 'h' this is used by 'help'
.long("ignore_hidden") .long("ignore_hidden")
.help("Do not display hidden files"), .help("Obey .git_ignore rules & Do not display hidden files"),
) )
.arg( .arg(
Arg::with_name("width") Arg::with_name("width")
@@ -199,31 +191,21 @@ fn main() {
let by_filecount = options.is_present("by_filecount"); let by_filecount = options.is_present("by_filecount");
let ignore_hidden = options.is_present("ignore_hidden"); let ignore_hidden = options.is_present("ignore_hidden");
let limit_filesystem = options.is_present("limit_filesystem");
let simplified_dirs = simplify_dir_names(target_dirs); let simplified_dirs = simplify_dir_names(target_dirs);
let allowed_filesystems = {
if limit_filesystem {
get_filesystem_devices(simplified_dirs.iter())
} else {
HashSet::new()
}
};
let ignored_full_path: HashSet<PathBuf> = ignore_directories let ignored_full_path: HashSet<PathBuf> = ignore_directories
.into_iter() .into_iter()
.flat_map(|x| simplified_dirs.iter().map(move |d| d.join(x.clone()))) .flat_map(|x| simplified_dirs.iter().map(move |d| d.join(x.clone())))
.collect(); .collect();
let walk_data = WalkData { let (nodes, errors) = walk_it(
ignore_directories: ignored_full_path, simplified_dirs,
allowed_filesystems, ignored_full_path,
use_apparent_size, use_apparent_size,
by_filecount, by_filecount,
ignore_hidden, ignore_hidden,
}; );
let (nodes, errors) = walk_it(simplified_dirs, walk_data);
let tree = { let tree = {
match depth { match depth {
+1 -9
View File
@@ -15,19 +15,11 @@ pub fn build_node(
dir: PathBuf, dir: PathBuf,
children: Vec<Node>, children: Vec<Node>,
use_apparent_size: bool, use_apparent_size: bool,
is_symlink: bool,
by_filecount: bool, by_filecount: bool,
) -> Option<Node> { ) -> Option<Node> {
match get_metadata(&dir, use_apparent_size) { match get_metadata(&dir, use_apparent_size) {
Some(data) => { Some(data) => {
let (size, inode_device) = if by_filecount { let (size, inode_device) = if by_filecount { (1, data.1) } else { data };
(1, data.1)
} else if is_symlink && !use_apparent_size {
(0, None)
} else {
data
};
Some(Node { Some(Node {
name: dir, name: dir,
size, size,
+2 -2
View File
@@ -120,9 +120,9 @@ pub fn get_metadata(d: &Path, _use_apparent_size: bool) -> Option<(u64, Option<(
{ {
Some((md.len(), None)) Some((md.len(), None))
} else { } else {
get_metadata_expensive(d) get_metadata_expensive(&d)
} }
} }
_ => get_metadata_expensive(d), _ => get_metadata_expensive(&d),
} }
} }
-19
View File
@@ -1,9 +1,6 @@
use platform::get_metadata;
use std::collections::HashSet; use std::collections::HashSet;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use crate::platform;
fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool { fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool {
let parent = parent.as_ref(); let parent = parent.as_ref();
let child = child.as_ref(); let child = child.as_ref();
@@ -36,22 +33,6 @@ pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf>
top_level_names top_level_names
} }
pub fn get_filesystem_devices<'a, P: IntoIterator<Item = &'a PathBuf>>(paths: P) -> HashSet<u64> {
// Gets the device ids for the filesystems which are used by the argument paths
paths
.into_iter()
.filter_map(|p| {
let meta = get_metadata(p, false);
if let Some((_size, Some((_id, dev)))) = meta {
Some(dev)
} else {
None
}
})
.collect()
}
pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf { pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
// normalize path ... // normalize path ...
// 1. removing repeated separators // 1. removing repeated separators