initial commit
commit
37b03d8fa0
|
@ -0,0 +1,344 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
"memoffset",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "fud"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.148"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9caece70c63bfba29ec2fed841a09851b14a235c60010fa4de58089b6c025668"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "fud"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.4.3", features = ["derive"] }
|
||||
rayon = "1.7.0"
|
|
@ -0,0 +1,128 @@
|
|||
use std::path::{PathBuf, Component};
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Directory {
|
||||
pub name: String,
|
||||
pub size: u64,
|
||||
children: Vec<Directory>,
|
||||
}
|
||||
impl Directory {
|
||||
pub fn new(name: String, size: u64) -> Self {
|
||||
Self {
|
||||
name,
|
||||
size,
|
||||
children: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, path: PathBuf, size: u64) {
|
||||
let components =
|
||||
path.components()
|
||||
.filter_map(
|
||||
|cmp| match cmp {
|
||||
Component::Normal(os_str) => os_str.to_str(),
|
||||
_ => None,
|
||||
}
|
||||
).map(ToOwned::to_owned);
|
||||
|
||||
let mut current = self;
|
||||
for next in components {
|
||||
if &next == ¤t.name {
|
||||
continue;
|
||||
}
|
||||
|
||||
let idx = if let Some(idx) = current.children.iter().position(|d| d.name == next) {
|
||||
idx
|
||||
} else {
|
||||
current.children.push(Directory::new(next, size));
|
||||
current.children.len()-1
|
||||
};
|
||||
current = &mut current.children[idx];
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursive function to find the greaest file size
|
||||
/// in this directory tree, used for formatting in the output
|
||||
fn find_max_size(&self) -> u64 {
|
||||
self.children.iter()
|
||||
.map(|d| d.find_max_size())
|
||||
.max()
|
||||
.unwrap_or(self.size)
|
||||
}
|
||||
|
||||
/// public-exposed print function, does the setup for the
|
||||
/// real print function, `print2`
|
||||
pub fn print(self) {
|
||||
// fake print function to give the depth param
|
||||
let max_size = self.find_max_size();
|
||||
let tabwidth = max_size.to_string().len() + 2;
|
||||
|
||||
let mut stack = Vec::new();
|
||||
self.print2(tabwidth as usize, &mut stack);
|
||||
}
|
||||
|
||||
/// real print function that makes the tree
|
||||
fn print2(self, tabwidth: usize, stack: &mut Vec<TreePart>) {
|
||||
let indent = build_indent(stack);
|
||||
println!("{:tabwidth$}{indent} {}", self.size.to_string(), self.name);
|
||||
|
||||
stack.push(TreePart::Edge);
|
||||
let mut iter = self.children.into_iter().peekable();
|
||||
while let Some(child) = iter.next() {
|
||||
if iter.peek().is_none() {
|
||||
let idx = stack.len()-1;
|
||||
stack[idx] = TreePart::Corner;
|
||||
};
|
||||
child.print2(tabwidth, stack);
|
||||
}
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
impl Extend<(PathBuf, u64)> for Directory {
|
||||
fn extend<T: IntoIterator<Item = (PathBuf, u64)>>(&mut self, iter: T) {
|
||||
for (p, s) in iter {
|
||||
self.insert(p, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
enum TreePart {
|
||||
/// Rightmost column, not the last in the directory
|
||||
Edge,
|
||||
/// Not rightmost, but dir not finished yet
|
||||
Line,
|
||||
/// Rightmost column in the last directory
|
||||
Corner,
|
||||
/// Not rightmost, but the dir has finished
|
||||
Blank
|
||||
}
|
||||
impl TreePart {
|
||||
/// convert to ascii art
|
||||
pub fn display(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Edge => "├──",
|
||||
Self::Line => "│ ",
|
||||
Self::Corner => "└──",
|
||||
Self::Blank => " ",
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Construct the indent string for the given stack.
|
||||
/// must be called at the top of the recursive function,
|
||||
/// and does mutate the stack
|
||||
fn build_indent(stack: &mut Vec<TreePart>) -> String {
|
||||
let mut indent = String::new();
|
||||
for (i, mut tp) in stack.iter().enumerate() {
|
||||
if i < stack.len()-1 && tp == &TreePart::Edge {
|
||||
tp = &TreePart::Line;
|
||||
}
|
||||
indent += tp.display();
|
||||
}
|
||||
// essentially, if the last time element on the stack was a corner,
|
||||
// make it blank for all future prints
|
||||
if let Some(last @ TreePart::Corner) = stack.last_mut() {
|
||||
*last = TreePart::Blank;
|
||||
}
|
||||
indent
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
use clap::Parser;
|
||||
|
||||
mod walk;
|
||||
mod directory;
|
||||
|
||||
use walk::walk;
|
||||
|
||||
use std::fs::File;
|
||||
use std::process::ExitCode;
|
||||
|
||||
#[derive(Parser, Debug, Clone)]
|
||||
pub struct Args {
|
||||
#[arg(
|
||||
short, long, default_value_t = false,
|
||||
help = "keep going if an error occurs",
|
||||
long_help = "keep going if an error occurs (ex. unreadable subdirectories in a readable directory)"
|
||||
)]
|
||||
persistant: bool,
|
||||
|
||||
#[arg(
|
||||
short, long,
|
||||
help = "minimize output",
|
||||
long_help = "like -t, but does not print \"total: \" before the summary or the newline after. It also surpresses all error messages",
|
||||
default_value_t = false,
|
||||
)]
|
||||
minimal: bool,
|
||||
|
||||
#[arg(
|
||||
short, long,
|
||||
help = "only display the total size",
|
||||
default_value_t = false,
|
||||
)]
|
||||
total_only: bool,
|
||||
|
||||
#[arg(value_parser = validate_path, default_value_t = String::from("."), help = "directory to begin search from")]
|
||||
path: String,
|
||||
}
|
||||
|
||||
fn validate_path(s: &str) -> Result<String, String> {
|
||||
let here = File::open(s).map_err(|e| e.to_string())?;
|
||||
let meta = here.metadata().map_err(|e| e.to_string())?;
|
||||
if meta.is_dir() {
|
||||
return Ok(s.to_owned())
|
||||
} else if meta.is_file() {
|
||||
return Err("this is a file (hint: use wc to view file sizes)".to_owned());
|
||||
} else {
|
||||
return Err("this is not a directory".to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let args = Args::parse();
|
||||
|
||||
let dir_structure = match walk(args.clone()) {
|
||||
Ok(dir) => dir,
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
if args.minimal {
|
||||
print!("{}", dir_structure.size);
|
||||
} else {
|
||||
let size = dir_structure.size; // copy size before print consumes dir_structure
|
||||
dir_structure.print();
|
||||
// looks like "print the total unless asked to", but "total: " is to prevent
|
||||
// the root from getting lost in massive outputs
|
||||
if !args.total_only {
|
||||
println!("total: {size}");
|
||||
}
|
||||
}
|
||||
|
||||
ExitCode::SUCCESS
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
use rayon::prelude::*;
|
||||
|
||||
use std::sync::mpsc::{Sender, channel};
|
||||
use std::fs::{read_dir, DirEntry};
|
||||
use std::io::Error;
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use crate::Args;
|
||||
use crate::directory::Directory;
|
||||
|
||||
pub fn walk<'a>(args: Args) -> Result<Directory, ExitCode> {
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let mut total = 0;
|
||||
for entry in read_dir(&args.path).unwrap() {
|
||||
let entry = match entry {
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
if !args.minimal {
|
||||
eprintln!("unable to open {}: {e}", args.path);
|
||||
}
|
||||
if args.persistant {
|
||||
continue;
|
||||
} else {
|
||||
return Err(ExitCode::FAILURE);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
total += match total_entry(entry, &args, &tx) {
|
||||
Ok(t) => t,
|
||||
Err((path, error)) => {
|
||||
if !args.minimal {
|
||||
eprintln!("error opening {}: {error}", path.display());
|
||||
}
|
||||
if args.persistant {
|
||||
continue;
|
||||
} else {
|
||||
return Err(ExitCode::FAILURE);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
// drop this to close the channel, so that into_iter() can end
|
||||
drop(tx);
|
||||
|
||||
let mut fs = Directory::new(args.path, total);
|
||||
fs.extend(rx);
|
||||
|
||||
Ok(fs)
|
||||
}
|
||||
|
||||
fn total_entry(entry: DirEntry, args: &Args, printer: &Sender<(PathBuf, u64)>) -> Result<u64, (PathBuf, Error)> {
|
||||
let path = entry.path();
|
||||
|
||||
match path.read_dir() {
|
||||
Ok(dir) => {
|
||||
let result = dir.par_bridge()
|
||||
.filter_map(Result::ok)
|
||||
.map(|entry| total_entry(entry, args, printer))
|
||||
.reduce(|| Ok(0), reduce_once);
|
||||
|
||||
if let Ok(size) = result {
|
||||
if !args.minimal && !args.total_only {
|
||||
let _ = printer.send((path, size));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
Err(_) if path.is_file() => {
|
||||
let size = unsafe { path.metadata().unwrap_unchecked() }.len();
|
||||
if !args.minimal && !args.total_only {
|
||||
let _ = printer.send((path, size));
|
||||
}
|
||||
return Ok(size);
|
||||
},
|
||||
Err(e) => Err((path, e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn reduce_once<E>(accum: Result<u64, E>, this: Result<u64, E>) -> Result<u64, E> {
|
||||
// reduction function for total_entry():
|
||||
// short-circuit Errs, propagate Oks
|
||||
// generic bc I'm lazy
|
||||
match (accum, this) {
|
||||
(Ok(n1), Ok(n2)) => Ok(n1 + n2),
|
||||
(Err(e), _) | (_, Err(e)) => Err(e),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue