Skip to main content

git_closure/snapshot/
summary.rs

1/// Snapshot summary extraction for compact metadata reporting.
2use std::fs;
3use std::path::Path;
4
5use crate::utils::io_error_with_path;
6
7use super::serial::parse_snapshot;
8use super::{Result, SnapshotSummary};
9
10/// Computes aggregate snapshot metadata for human or machine-readable output.
11pub fn summarize_snapshot(path: &Path) -> Result<SnapshotSummary> {
12    let text = fs::read_to_string(path).map_err(|err| io_error_with_path(err, path))?;
13    let (header, files) = parse_snapshot(&text)?;
14
15    let symlink_count = files.iter().filter(|f| f.symlink_target.is_some()).count();
16    let regular_count = files.len().saturating_sub(symlink_count);
17    let total_bytes = files.iter().map(|f| f.size).sum::<u64>();
18
19    let mut largest_files: Vec<(String, u64)> = files
20        .iter()
21        .filter(|f| f.symlink_target.is_none())
22        .map(|f| (f.path.clone(), f.size))
23        .collect();
24    largest_files.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0)));
25    largest_files.truncate(5);
26
27    Ok(SnapshotSummary {
28        snapshot_hash: header.snapshot_hash,
29        file_count: header.file_count,
30        regular_count,
31        symlink_count,
32        total_bytes,
33        git_rev: header.git_rev,
34        git_branch: header.git_branch,
35        largest_files,
36    })
37}
38
39#[cfg(test)]
40mod tests {
41    use super::summarize_snapshot;
42    use crate::snapshot::build::build_snapshot;
43    use tempfile::TempDir;
44
45    #[test]
46    fn summarize_snapshot_largest_files_is_top_five_descending() {
47        let source = TempDir::new().expect("create source tempdir");
48        for i in 0..7u8 {
49            let size = (i + 1) as usize;
50            let name = format!("f{i}.txt");
51            std::fs::write(source.path().join(name), vec![b'x'; size]).expect("write source file");
52        }
53
54        let snapshot = source.path().join("snapshot.gcl");
55        build_snapshot(source.path(), &snapshot).expect("build snapshot");
56
57        let summary = summarize_snapshot(&snapshot).expect("summarize snapshot");
58        assert_eq!(summary.largest_files.len(), 5);
59        assert_eq!(summary.largest_files[0], ("f6.txt".to_string(), 7));
60        assert_eq!(summary.largest_files[4], ("f2.txt".to_string(), 3));
61    }
62}