this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at tangled-ci 80 lines 2.8 kB view raw
1//! Shared helpers for container formats (tar, zip, 7z). 2//! 3//! Single-stream codecs know the total input size up front from file 4//! metadata. Container formats take N paths and recurse into directories, so 5//! they have to pre-walk the input to get a meaningful progress total. 6 7use std::path::Path; 8 9/// Sum sizes of all regular files reachable from the given paths, recursing 10/// into directories. Uses `fs::metadata` (follows symlinks) so that the 11/// file-vs-directory judgment matches `Path::is_file` / `Path::is_dir` 12/// semantics used by each backend's walker — otherwise a symlink to a file 13/// would contribute 0 to the total while the walker reads (and bar-ticks) 14/// the full target. Best-effort: anything we can't stat (permission denied, 15/// racy deletion, broken symlink) is counted as zero; the bar may finish 16/// short rather than fail the run. 17pub fn total_input_bytes<P: AsRef<Path>>(paths: &[P]) -> u64 { 18 paths.iter().map(|p| sum_path(p.as_ref())).sum() 19} 20 21fn sum_path(path: &Path) -> u64 { 22 let Ok(meta) = std::fs::metadata(path) else { 23 return 0; 24 }; 25 if meta.is_file() { 26 return meta.len(); 27 } 28 if meta.is_dir() { 29 let Ok(entries) = std::fs::read_dir(path) else { 30 return 0; 31 }; 32 return entries.flatten().map(|e| sum_path(&e.path())).sum(); 33 } 34 0 35} 36 37#[cfg(test)] 38mod tests { 39 use super::*; 40 use assert_fs::prelude::*; 41 42 #[test] 43 fn sums_single_file() { 44 let dir = assert_fs::TempDir::new().unwrap(); 45 let f = dir.child("a.txt"); 46 f.write_str("hello").unwrap(); 47 assert_eq!(total_input_bytes(&[f.path().to_path_buf()]), 5); 48 } 49 50 #[test] 51 fn sums_directory_recursively() { 52 let dir = assert_fs::TempDir::new().unwrap(); 53 dir.child("a.txt").write_str("abc").unwrap(); 54 dir.child("sub/b.txt").write_str("defgh").unwrap(); 55 assert_eq!(total_input_bytes(&[dir.path().to_path_buf()]), 8); 56 } 57 58 #[test] 59 fn missing_path_counts_zero() { 60 assert_eq!( 61 total_input_bytes(&[std::path::PathBuf::from("/nope/xx")]), 62 0 63 ); 64 } 65 66 /// Symlinks to regular files must contribute their target's size so the 67 /// bar total matches what the walkers actually read. Regression for 68 /// tar/zip/7z bars overshooting past 100% on directories containing 69 /// symlinks. 70 #[cfg(unix)] 71 #[test] 72 fn follows_symlink_to_file() { 73 let dir = assert_fs::TempDir::new().unwrap(); 74 dir.child("target.txt").write_str("abcdefghij").unwrap(); 75 std::os::unix::fs::symlink(dir.path().join("target.txt"), dir.path().join("link.txt")) 76 .unwrap(); 77 // target.txt (10) + link.txt following to target (10) = 20 78 assert_eq!(total_input_bytes(&[dir.path().to_path_buf()]), 20); 79 } 80}