1use crate::git::git_interop::is_shallow_repository;
2use crate::git::size_ops::{get_notes_size, get_repo_stats, NotesSizeInfo, RepoStats};
3use anyhow::Result;
4use git_perf_cli_types::SizeFormat;
5use human_repr::HumanCount;
6
7pub fn calculate_measurement_size(
9 detailed: bool,
10 format: SizeFormat,
11 disk_size: bool,
12 include_objects: bool,
13) -> Result<()> {
14 let is_shallow = is_shallow_repository().unwrap_or(false);
16
17 let notes_info = get_notes_size(detailed, disk_size)?;
19
20 let repo_stats = if include_objects {
22 Some(get_repo_stats()?)
23 } else {
24 None
25 };
26
27 display_size_report(
29 ¬es_info,
30 repo_stats.as_ref(),
31 format,
32 disk_size,
33 is_shallow,
34 )?;
35
36 Ok(())
37}
38
39fn display_size_report(
41 info: &NotesSizeInfo,
42 repo_stats: Option<&RepoStats>,
43 format: SizeFormat,
44 disk_size: bool,
45 is_shallow: bool,
46) -> Result<()> {
47 let size_type = if disk_size {
48 "on-disk (compressed)"
49 } else {
50 "logical (uncompressed)"
51 };
52
53 println!("Live Measurement Size Report");
54 println!("============================");
55 println!();
56
57 if is_shallow {
59 println!("⚠️ Shallow clone detected - measurement counts may be incomplete (see FAQ)");
60 println!();
61 }
62
63 println!("Number of commits with measurements: {}", info.note_count);
64 println!(
65 "Total measurement data size ({}): {}",
66 size_type,
67 format_size(info.total_bytes, format)
68 );
69
70 if let Some(stats) = repo_stats {
72 println!();
73 println!("Repository Statistics (for context):");
74 println!("-------------------------------------");
75 println!(
76 " Loose objects: {} ({})",
77 stats.loose_objects,
78 format_size(stats.loose_size, format)
79 );
80 println!(
81 " Packed objects: {} ({})",
82 stats.packed_objects,
83 format_size(stats.pack_size, format)
84 );
85 println!(
86 " Total repository size: {}",
87 format_size(stats.loose_size + stats.pack_size, format)
88 );
89 }
90
91 if let Some(by_name) = &info.by_measurement {
93 println!();
94 println!("Breakdown by Measurement Name ({}):", size_type);
95 println!("------------------------------");
96
97 let mut sorted: Vec<_> = by_name.iter().collect();
99 sorted.sort_by(|a, b| b.1.total_bytes.cmp(&a.1.total_bytes));
100
101 for (name, size_info) in sorted {
102 println!(
103 " {} ({} occurrences): {}",
104 name,
105 size_info.count,
106 format_size(size_info.total_bytes, format)
107 );
108 }
109 }
110
111 Ok(())
112}
113
114fn format_size(bytes: u64, format: SizeFormat) -> String {
116 match format {
117 SizeFormat::Bytes => bytes.to_string(),
118 SizeFormat::Human => bytes.human_count_bytes().to_string(),
119 }
120}