git_closure/snapshot/
summary.rs1use 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
10pub 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}