provenant/scanner/
count.rs1use crate::utils::file::is_path_excluded;
2use glob::Pattern;
3use std::fs;
4use std::path::Path;
5
6pub fn count_with_size<P: AsRef<Path>>(
7 path: P,
8 max_depth: usize,
9 exclude_patterns: &[Pattern],
10) -> std::io::Result<(usize, usize, usize, u64)> {
11 let depth_limit = depth_limit_from_cli(max_depth);
12 count_internal(path.as_ref(), depth_limit, exclude_patterns)
13}
14
15fn depth_limit_from_cli(max_depth: usize) -> Option<usize> {
16 if max_depth == 0 {
17 None
18 } else {
19 Some(max_depth)
20 }
21}
22
23fn count_internal(
24 path: &Path,
25 depth_limit: Option<usize>,
26 exclude_patterns: &[Pattern],
27) -> std::io::Result<(usize, usize, usize, u64)> {
28 if is_path_excluded(path, exclude_patterns) {
29 return Ok((0, 0, 1, 0));
30 }
31
32 let mut files_count = 0;
33 let mut dirs_count = 1; let mut excluded_count = 0;
35 let mut total_file_bytes = 0_u64;
36
37 for entry in fs::read_dir(path)? {
39 let entry = entry?;
40 let entry_path = entry.path();
41
42 if is_path_excluded(&entry_path, exclude_patterns) {
43 excluded_count += 1;
44 continue;
45 }
46
47 let metadata = entry.metadata()?;
48 if metadata.is_file() {
49 files_count += 1;
50 total_file_bytes += metadata.len();
51 } else if metadata.is_dir() {
52 dirs_count += 1;
53
54 let should_recurse = match depth_limit {
55 None => true,
56 Some(remaining_depth) => remaining_depth > 0,
57 };
58
59 if should_recurse {
60 let next_depth_limit = depth_limit.map(|remaining_depth| remaining_depth - 1);
61 let (sub_files, sub_dirs, sub_excluded, sub_bytes) =
62 count_internal(&entry_path, next_depth_limit, exclude_patterns)?;
63
64 files_count += sub_files;
65 dirs_count += sub_dirs - 1; excluded_count += sub_excluded;
67 total_file_bytes += sub_bytes;
68 }
69 }
70 }
71
72 Ok((files_count, dirs_count, excluded_count, total_file_bytes))
73}