Skip to content

Commit 7cc73b0

Browse files
committed
du: put excludes in traveraloptions and make size_format enum
1 parent d6b10d4 commit 7cc73b0

File tree

1 file changed

+68
-108
lines changed

1 file changed

+68
-108
lines changed

src/uu/du/src/du.rs

Lines changed: 68 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ struct TraversalOptions {
8383
dereference: Deref,
8484
count_links: bool,
8585
verbose: bool,
86+
excludes: Vec<Pattern>,
8687
}
8788

8889
#[derive(Clone)]
@@ -92,13 +93,7 @@ struct PrintingOptions {
9293
max_depth: Option<usize>,
9394
threshold: Option<Threshold>,
9495
apparent_size: bool,
95-
// TODO: the size conversion fields should be unified
96-
si: bool,
97-
bytes: bool,
98-
human_readable: bool,
99-
block_size_1k: bool,
100-
block_size_1m: bool,
101-
block_size: u64,
96+
size_format: SizeFormat,
10297
time: Option<Time>,
10398
time_format: String,
10499
line_ending: LineEnding,
@@ -118,6 +113,12 @@ enum Time {
118113
Created,
119114
}
120115

116+
#[derive(Clone)]
117+
enum SizeFormat {
118+
Human(u64),
119+
BlockSize(u64),
120+
}
121+
121122
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
122123
struct FileInfo {
123124
file_id: u128,
@@ -298,7 +299,7 @@ fn read_block_size(s: Option<&str>) -> UResult<u64> {
298299
fn choose_size(options: &PrintingOptions, stat: &Stat) -> u64 {
299300
if options.inodes {
300301
stat.inodes
301-
} else if options.apparent_size || options.bytes {
302+
} else if options.apparent_size {
302303
stat.size
303304
} else {
304305
// The st_blocks field indicates the number of blocks allocated to the file, 512-byte units.
@@ -314,7 +315,6 @@ fn du(
314315
options: &TraversalOptions,
315316
depth: usize,
316317
seen_inodes: &mut HashSet<FileInfo>,
317-
exclude: &[Pattern],
318318
print_tx: &mpsc::Sender<UResult<StatPrintInfo>>,
319319
) -> Result<Stat, Box<mpsc::SendError<UResult<StatPrintInfo>>>> {
320320
if my_stat.is_dir {
@@ -334,7 +334,7 @@ fn du(
334334
match Stat::new(&entry.path(), options) {
335335
Ok(this_stat) => {
336336
// We have an exclude list
337-
for pattern in exclude {
337+
for pattern in &options.excludes {
338338
// Look at all patterns with both short and long paths
339339
// if we have 'du foo' but search to exclude 'foo/bar'
340340
// we need the full path
@@ -370,14 +370,8 @@ fn du(
370370
}
371371
}
372372

373-
let this_stat = du(
374-
this_stat,
375-
options,
376-
depth + 1,
377-
seen_inodes,
378-
exclude,
379-
print_tx,
380-
)?;
373+
let this_stat =
374+
du(this_stat, options, depth + 1, seen_inodes, print_tx)?;
381375

382376
if !options.separate_dirs {
383377
my_stat.size += this_stat.size;
@@ -413,52 +407,6 @@ fn du(
413407
Ok(my_stat)
414408
}
415409

416-
fn convert_size_human(size: u64, multiplier: u64, _block_size: u64) -> String {
417-
for &(unit, power) in &UNITS {
418-
let limit = multiplier.pow(power);
419-
if size >= limit {
420-
return format!("{:.1}{}", (size as f64) / (limit as f64), unit);
421-
}
422-
}
423-
if size == 0 {
424-
return "0".to_string();
425-
}
426-
format!("{size}B")
427-
}
428-
429-
fn convert_size_b(size: u64, _multiplier: u64, _block_size: u64) -> String {
430-
format!("{}", ((size as f64) / (1_f64)).ceil())
431-
}
432-
433-
fn convert_size_k(size: u64, multiplier: u64, _block_size: u64) -> String {
434-
format!("{}", ((size as f64) / (multiplier as f64)).ceil())
435-
}
436-
437-
fn convert_size_m(size: u64, multiplier: u64, _block_size: u64) -> String {
438-
format!(
439-
"{}",
440-
((size as f64) / ((multiplier * multiplier) as f64)).ceil()
441-
)
442-
}
443-
444-
fn convert_size_other(size: u64, _multiplier: u64, block_size: u64) -> String {
445-
format!("{}", ((size as f64) / (block_size as f64)).ceil())
446-
}
447-
448-
fn get_convert_size_fn(options: &PrintingOptions) -> Box<dyn Fn(u64, u64, u64) -> String + Send> {
449-
if options.human_readable || options.si {
450-
Box::new(convert_size_human)
451-
} else if options.bytes {
452-
Box::new(convert_size_b)
453-
} else if options.block_size_1k {
454-
Box::new(convert_size_k)
455-
} else if options.block_size_1m {
456-
Box::new(convert_size_m)
457-
} else {
458-
Box::new(convert_size_other)
459-
}
460-
}
461-
462410
#[derive(Debug)]
463411
enum DuError {
464412
InvalidMaxDepthArg(String),
@@ -557,26 +505,11 @@ struct StatPrintInfo {
557505
struct StatPrinter {
558506
summarize: bool,
559507
options: PrintingOptions,
560-
convert_size: Box<dyn Fn(u64) -> String + Send>,
561508
}
562509

563510
impl StatPrinter {
564511
fn new(options: PrintingOptions, summarize: bool) -> UResult<Self> {
565-
let multiplier: u64 = if options.si { 1000 } else { 1024 };
566-
567-
let convert_size_fn = get_convert_size_fn(&options);
568-
569-
let convert_size: Box<dyn Fn(u64) -> String + Send> = if options.inodes {
570-
Box::new(|size: u64| size.to_string())
571-
} else {
572-
Box::new(move |size: u64| convert_size_fn(size, multiplier, options.block_size))
573-
};
574-
575-
Ok(Self {
576-
summarize,
577-
options,
578-
convert_size,
579-
})
512+
Ok(Self { summarize, options })
580513
}
581514

582515
fn print_stats(&self, rx: &mpsc::Receiver<UResult<StatPrintInfo>>) -> UResult<()> {
@@ -613,21 +546,42 @@ impl StatPrinter {
613546
}
614547

615548
if self.options.total {
616-
print!("{}\ttotal", (self.convert_size)(grand_total));
549+
print!("{}\ttotal", self.convert_size(grand_total));
617550
print!("{}", self.options.line_ending);
618551
}
619552

620553
Ok(())
621554
}
622555

556+
fn convert_size(&self, size: u64) -> String {
557+
if self.options.inodes {
558+
return size.to_string();
559+
}
560+
match self.options.size_format {
561+
SizeFormat::Human(multiplier) => {
562+
for &(unit, power) in &UNITS {
563+
let limit = multiplier.pow(power);
564+
if size >= limit {
565+
return format!("{:.1}{}", (size as f64) / (limit as f64), unit);
566+
}
567+
}
568+
if size == 0 {
569+
return "0".to_string();
570+
}
571+
format!("{size}B")
572+
}
573+
SizeFormat::BlockSize(block_size) => div_ceil(size, block_size).to_string(),
574+
}
575+
}
576+
623577
fn print_stat(&self, stat: &Stat, size: u64) -> UResult<()> {
624578
if let Some(time) = self.options.time {
625579
let secs = get_time_secs(time, stat)?;
626580
let tm = DateTime::<Local>::from(UNIX_EPOCH + Duration::from_secs(secs));
627581
let time_str = tm.format(&self.options.time_format).to_string();
628-
print!("{}\t{}\t", (self.convert_size)(size), time_str);
582+
print!("{}\t{}\t", self.convert_size(size), time_str);
629583
} else {
630-
print!("{}\t", (self.convert_size)(size));
584+
print!("{}\t", self.convert_size(size));
631585
}
632586

633587
print_verbatim(&stat.path).unwrap();
@@ -637,6 +591,13 @@ impl StatPrinter {
637591
}
638592
}
639593

594+
// This can be replaced with u64::div_ceil once it is stabilized.
595+
// This implementation approach is optimized for when `b` is a constant,
596+
// particularly a power of two.
597+
pub fn div_ceil(a: u64, b: u64) -> u64 {
598+
(a + b - 1) / b
599+
}
600+
640601
#[uucore::main]
641602
#[allow(clippy::cognitive_complexity)]
642603
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
@@ -671,11 +632,23 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
671632
}
672633
});
673634

674-
let block_size = read_block_size(
675-
matches
676-
.get_one::<String>(options::BLOCK_SIZE)
677-
.map(|s| s.as_str()),
678-
)?;
635+
let size_format = if matches.get_flag(options::HUMAN_READABLE) {
636+
SizeFormat::Human(1024)
637+
} else if matches.get_flag(options::SI) {
638+
SizeFormat::Human(1000)
639+
} else if matches.get_flag(options::BYTES) {
640+
SizeFormat::BlockSize(1)
641+
} else if matches.get_flag(options::BLOCK_SIZE_1K) {
642+
SizeFormat::BlockSize(1024)
643+
} else if matches.get_flag(options::BLOCK_SIZE_1M) {
644+
SizeFormat::BlockSize(1024 * 1024)
645+
} else {
646+
SizeFormat::BlockSize(read_block_size(
647+
matches
648+
.get_one::<String>(options::BLOCK_SIZE)
649+
.map(AsRef::as_ref),
650+
)?)
651+
};
679652

680653
let traversal_options = TraversalOptions {
681654
all: matches.get_flag(options::ALL),
@@ -691,13 +664,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
691664
},
692665
count_links: matches.get_flag(options::COUNT_LINKS),
693666
verbose: matches.get_flag(options::VERBOSE),
667+
excludes: build_exclude_patterns(&matches)?,
694668
};
695669

696670
let printing_options = PrintingOptions {
697671
max_depth,
672+
size_format,
698673
total: matches.get_flag(options::TOTAL),
699674
inodes: matches.get_flag(options::INODES),
700-
si: matches.get_flag(options::SI),
701675
threshold: matches
702676
.get_one::<String>(options::THRESHOLD)
703677
.map(|s| {
@@ -706,13 +680,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
706680
})
707681
})
708682
.transpose()?,
709-
apparent_size: matches.get_flag(options::APPARENT_SIZE),
710-
bytes: matches.get_flag(options::BYTES),
683+
apparent_size: matches.get_flag(options::APPARENT_SIZE) || matches.get_flag(options::BYTES),
711684
time,
712-
block_size,
713-
human_readable: matches.get_flag(options::HUMAN_READABLE),
714-
block_size_1k: matches.get_flag(options::BLOCK_SIZE_1K),
715-
block_size_1m: matches.get_flag(options::BLOCK_SIZE_1M),
716685
time_format: parse_time_style(matches.get_one::<String>("time-style").map(|s| s.as_str()))?
717686
.to_string(),
718687
line_ending: LineEnding::from_zero_flag(matches.get_flag(options::NULL)),
@@ -729,13 +698,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
729698
let (print_tx, rx) = mpsc::channel::<UResult<StatPrintInfo>>();
730699
let printing_thread = thread::spawn(move || stat_printer.print_stats(&rx));
731700

732-
let excludes = build_exclude_patterns(&matches)?;
733-
734701
'loop_file: for path in files {
735702
// Skip if we don't want to ignore anything
736-
if !&excludes.is_empty() {
703+
if !&traversal_options.excludes.is_empty() {
737704
let path_string = path.to_string_lossy();
738-
for pattern in &excludes {
705+
for pattern in &traversal_options.excludes {
739706
if pattern.matches(&path_string) {
740707
// if the directory is ignored, leave early
741708
if traversal_options.verbose {
@@ -753,15 +720,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
753720
if let Some(inode) = stat.inode {
754721
seen_inodes.insert(inode);
755722
}
756-
let stat = du(
757-
stat,
758-
&traversal_options,
759-
0,
760-
&mut seen_inodes,
761-
&excludes,
762-
&print_tx,
763-
)
764-
.map_err(|e| USimpleError::new(1, e.to_string()))?;
723+
let stat = du(stat, &traversal_options, 0, &mut seen_inodes, &print_tx)
724+
.map_err(|e| USimpleError::new(1, e.to_string()))?;
765725

766726
print_tx
767727
.send(Ok(StatPrintInfo { stat, depth: 0 }))

0 commit comments

Comments
 (0)