Compare commits
4 Commits
0c157927b8
...
948d3763b5
Author | SHA1 | Date |
---|---|---|
nick | 948d3763b5 | |
nick | b68556ae7f | |
nick | d97f397afc | |
nick | 0ca5d93248 |
22
src/args.rs
22
src/args.rs
|
@ -5,6 +5,7 @@ use rayon::ThreadPoolBuilder;
|
||||||
use crate::unit::Unit;
|
use crate::unit::Unit;
|
||||||
|
|
||||||
use std::fs::{symlink_metadata, Metadata};
|
use std::fs::{symlink_metadata, Metadata};
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
use std::path::{Component, Path};
|
use std::path::{Component, Path};
|
||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
use std::iter::once_with;
|
use std::iter::once_with;
|
||||||
|
@ -31,7 +32,7 @@ pub struct Args {
|
||||||
#[arg(
|
#[arg(
|
||||||
short, long,
|
short, long,
|
||||||
help = "minimize output",
|
help = "minimize output",
|
||||||
long_help = "print nothing but the total size for all directories, without a newline. Also supresses all error messages",
|
long_help = "print nothing but the total size for all directories, without a newline or units. Also supresses all error messages",
|
||||||
conflicts_with = "total",
|
conflicts_with = "total",
|
||||||
default_value_t = false,
|
default_value_t = false,
|
||||||
)]
|
)]
|
||||||
|
@ -72,7 +73,7 @@ pub struct Args {
|
||||||
#[arg(
|
#[arg(
|
||||||
short, long,
|
short, long,
|
||||||
help = "unit to print in",
|
help = "unit to print in",
|
||||||
long_help = "printing unit (case insensitive): b = bytes, kb = kilobytes, ki = kibibytes, gb = gigabytes, gi = gibibytes, tb = terabytes, ti = tibibytes",
|
long_help = "printing unit (case insensitive): b = bytes, kb = kilobytes, ki = kibibytes, gb = gigabytes, gi = gibibytes, tb = terabytes, ti = tibibytes, blk/blks/blck/blcks/block/blocks = file system blocks",
|
||||||
value_parser = Unit::parse,
|
value_parser = Unit::parse,
|
||||||
default_value_t = Unit::Byte,
|
default_value_t = Unit::Byte,
|
||||||
conflicts_with_all = ["base_two","si"],
|
conflicts_with_all = ["base_two","si"],
|
||||||
|
@ -129,7 +130,7 @@ pub struct Args {
|
||||||
help = "items to summate",
|
help = "items to summate",
|
||||||
action = ArgAction::Append,
|
action = ArgAction::Append,
|
||||||
)]
|
)]
|
||||||
path: Vec<String>,
|
paths: Vec<String>,
|
||||||
}
|
}
|
||||||
impl Args {
|
impl Args {
|
||||||
/// utility method to chuck default values on the end.
|
/// utility method to chuck default values on the end.
|
||||||
|
@ -146,8 +147,8 @@ impl Args {
|
||||||
self.exclude_print.clear();
|
self.exclude_print.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.path.is_empty() {
|
if self.paths.is_empty() {
|
||||||
self.path = vec![ ".".to_owned() ];
|
self.paths = vec![ ".".to_owned() ];
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadPoolBuilder::new()
|
ThreadPoolBuilder::new()
|
||||||
|
@ -158,6 +159,13 @@ impl Args {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self, meta: &Metadata) -> u64 {
|
||||||
|
match self.unit {
|
||||||
|
Unit::Blocks => meta.blocks(),
|
||||||
|
_ => meta.len(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn should_exclude(&self, path: &Path, file: &Metadata) -> bool {
|
pub fn should_exclude(&self, path: &Path, file: &Metadata) -> bool {
|
||||||
if !self.follow_links
|
if !self.follow_links
|
||||||
&& file.is_symlink()
|
&& file.is_symlink()
|
||||||
|
@ -202,7 +210,7 @@ impl Args {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paths(&self) -> Iter<'_, String> {
|
pub fn paths(&self) -> Iter<'_, String> {
|
||||||
self.path.iter()
|
self.paths.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +236,7 @@ fn any_pattern_matches_any_component(patterns: &[Pattern], path: &Path) -> bool
|
||||||
continue
|
continue
|
||||||
};
|
};
|
||||||
let Some(s) = cmp.to_str() else {
|
let Some(s) = cmp.to_str() else {
|
||||||
// this is a code smell
|
// TODO: this is a code smell
|
||||||
// I don't believe it, but I can't think
|
// I don't believe it, but I can't think
|
||||||
// of anything worthwhile to do when
|
// of anything worthwhile to do when
|
||||||
// you can't get a usable &str
|
// you can't get a usable &str
|
||||||
|
|
|
@ -21,11 +21,6 @@ impl Directory {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn path(&self) -> &Path {
|
|
||||||
self.name.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new< P: AsRef<Path> >(path: P, args: &Args) -> Result<Option<Self>> {
|
pub fn new< P: AsRef<Path> >(path: P, args: &Args) -> Result<Option<Self>> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
// NOTE: I go back and forth on canonicalize()ing all the time.
|
// NOTE: I go back and forth on canonicalize()ing all the time.
|
||||||
|
@ -46,6 +41,7 @@ impl Directory {
|
||||||
|
|
||||||
// symlink_metadata() is the same as metadata() but it doesn't
|
// symlink_metadata() is the same as metadata() but it doesn't
|
||||||
// traverse symlinks, so that we can exclude them if necessary
|
// traverse symlinks, so that we can exclude them if necessary
|
||||||
|
// note: sizeof(Metadata) == 176
|
||||||
let meta = match path.symlink_metadata() {
|
let meta = match path.symlink_metadata() {
|
||||||
Ok(md) => md,
|
Ok(md) => md,
|
||||||
Err(_) if args.persistant() => return Ok(None),
|
Err(_) if args.persistant() => return Ok(None),
|
||||||
|
@ -66,7 +62,7 @@ impl Directory {
|
||||||
return Ok(Some(
|
return Ok(Some(
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
size: meta.len(),
|
size: args.len(&meta),
|
||||||
children: Vec::new()
|
children: Vec::new()
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
@ -85,7 +81,7 @@ impl Directory {
|
||||||
(Err(e), false) => return Err(e),
|
(Err(e), false) => return Err(e),
|
||||||
};
|
};
|
||||||
size += dir.size;
|
size += dir.size;
|
||||||
if args.tree() && args.should_print(dir.path()) {
|
if args.tree() && args.should_print(&dir.name) {
|
||||||
// since size was increased, this just prevents
|
// since size was increased, this just prevents
|
||||||
// the directory from appearing in printing
|
// the directory from appearing in printing
|
||||||
children.push(dir);
|
children.push(dir);
|
||||||
|
@ -144,7 +140,7 @@ impl Directory {
|
||||||
pub fn tree(self, unit: Unit) -> String {
|
pub fn tree(self, unit: Unit) -> String {
|
||||||
// since self.size is definitionally the greatest value, the tab length
|
// since self.size is definitionally the greatest value, the tab length
|
||||||
// is just the length of self.len, plus two for a tab width
|
// is just the length of self.len, plus two for a tab width
|
||||||
let tab_size = unit.convert(self.size).len() + 2;
|
let tab_size = unit.convert_with_units(self.size).len() + 2;
|
||||||
self.vectorise(unit)
|
self.vectorise(unit)
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| e.stringify_tabbed(tab_size))
|
.map(|e| e.stringify_tabbed(tab_size))
|
||||||
|
@ -209,7 +205,7 @@ impl TreeEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stringify_tabbed(&self, tab_size: usize) -> String {
|
fn stringify_tabbed(&self, tab_size: usize) -> String {
|
||||||
let mut result = format!("{:<tab_size$}", self.unit.convert(self.size));
|
let mut result = format!("{:<tab_size$}", self.unit.convert_with_units(self.size));
|
||||||
|
|
||||||
for part in self.parts.iter().rev() {
|
for part in self.parts.iter().rev() {
|
||||||
result += part.display();
|
result += part.display();
|
||||||
|
|
|
@ -42,17 +42,17 @@ fn main() -> ExitCode {
|
||||||
println!(
|
println!(
|
||||||
"{}: {}",
|
"{}: {}",
|
||||||
path,
|
path,
|
||||||
args.unit().convert(dir_structure.size())
|
args.unit().convert_with_units(dir_structure.size())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let total = args.unit().convert(total);
|
|
||||||
|
|
||||||
if args.total() {
|
if args.total() {
|
||||||
|
let total = args.unit().convert_with_units(total);
|
||||||
println!("total: {total}");
|
println!("total: {total}");
|
||||||
}
|
}
|
||||||
else if args.minimal() {
|
else if args.minimal() {
|
||||||
|
let total = args.unit().convert(total);
|
||||||
print!("{total}");
|
print!("{total}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
27
src/unit.rs
27
src/unit.rs
|
@ -34,19 +34,22 @@ impl Unit {
|
||||||
"blk" | "blks"
|
"blk" | "blks"
|
||||||
| "blck" |"blcks"
|
| "blck" |"blcks"
|
||||||
| "block" | "blocks" => Ok(Self::Blocks),
|
| "block" | "blocks" => Ok(Self::Blocks),
|
||||||
_ => Err(s),
|
_ => Err("use --help to get a list of units".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert(self, n: u64) -> String {
|
pub fn convert(self, n: u64) -> String {
|
||||||
let n = if self == Self::Blocks {
|
format!("{}", n/self.integer_value())
|
||||||
n.next_multiple_of(self.integer_value())
|
|
||||||
} else {
|
|
||||||
n
|
|
||||||
};
|
|
||||||
format!("{}{}", n/self.integer_value(), self.units_pretty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn convert_with_units(self, n: u64) -> String {
|
||||||
|
self.convert(n) + self.units_pretty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Units to print for each different unit.
|
||||||
|
/// They all have a space between at the front
|
||||||
|
/// for style reasons, except for bytes which are
|
||||||
|
/// basically unindicated
|
||||||
const fn units_pretty(self) -> &'static str {
|
const fn units_pretty(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Byte => "",
|
Self::Byte => "",
|
||||||
|
@ -62,9 +65,16 @@ impl Unit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The size is always held in bytes, so
|
||||||
|
/// this returns the scale factor.
|
||||||
|
/// A special case is made for
|
||||||
|
/// blocks, because the number of blocks
|
||||||
|
/// is repeatedly queried throughout
|
||||||
|
/// the search process, it needn't be
|
||||||
|
/// altered here
|
||||||
const fn integer_value(self) -> u64 {
|
const fn integer_value(self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
Self::Byte => 1,
|
Self::Byte | Self::Blocks => 1,
|
||||||
Self::Kilo => 1_000,
|
Self::Kilo => 1_000,
|
||||||
Self::Kibi => 1_024,
|
Self::Kibi => 1_024,
|
||||||
Self::Mega => 1_000_000,
|
Self::Mega => 1_000_000,
|
||||||
|
@ -73,7 +83,6 @@ impl Unit {
|
||||||
Self::Gibi => 1_073_741_824,
|
Self::Gibi => 1_073_741_824,
|
||||||
Self::Tera => 1_000_000_000_000,
|
Self::Tera => 1_000_000_000_000,
|
||||||
Self::Tibi => 1_099_511_627_776,
|
Self::Tibi => 1_099_511_627_776,
|
||||||
Self::Blocks => 512,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue