ipfrs_cli/commands/
repo.rs1use anyhow::Result;
10
11use crate::output::{self, error, format_bytes, print_header, print_kv, success};
12use crate::progress;
13
14use super::stats::stats_repo;
15
16pub async fn repo_gc(dry_run: bool, format: &str) -> Result<()> {
18 use ipfrs::{Node, NodeConfig};
19
20 let action = if dry_run { "Analyzing" } else { "Running" };
21 let pb = progress::spinner(&format!("{} garbage collection", action));
22 let mut node = Node::new(NodeConfig::default())?;
23 node.start().await?;
24
25 let result = node.repo_gc(dry_run).await?;
26 progress::finish_spinner_success(&pb, "GC complete");
27
28 match format {
29 "json" => {
30 println!("{{");
31 println!(" \"blocks_collected\": {},", result.blocks_collected);
32 println!(" \"bytes_freed\": {},", result.bytes_freed);
33 println!(" \"blocks_marked\": {},", result.blocks_marked);
34 println!(" \"blocks_scanned\": {},", result.blocks_scanned);
35 println!(" \"duration_ms\": {}", result.duration.as_millis());
36 println!("}}");
37 }
38 _ => {
39 print_header("Garbage Collection Results");
40 print_kv("Blocks scanned", &result.blocks_scanned.to_string());
41 print_kv("Blocks marked", &result.blocks_marked.to_string());
42 print_kv("Blocks collected", &result.blocks_collected.to_string());
43 print_kv("Bytes freed", &format_bytes(result.bytes_freed));
44 print_kv(
45 "Duration",
46 &format!("{:.2}s", result.duration.as_secs_f64()),
47 );
48
49 if dry_run {
50 output::warning("Dry run - no blocks were actually deleted");
51 } else if result.blocks_collected > 0 {
52 success(&format!(
53 "Freed {} from {} blocks",
54 format_bytes(result.bytes_freed),
55 result.blocks_collected
56 ));
57 } else {
58 output::info("No unreferenced blocks found");
59 }
60 }
61 }
62
63 node.stop().await?;
64 Ok(())
65}
66
67pub async fn repo_stat(format: &str) -> Result<()> {
69 stats_repo(format).await
71}
72
73pub async fn repo_fsck(format: &str) -> Result<()> {
75 use ipfrs::{Node, NodeConfig};
76
77 let pb = progress::spinner("Checking repository integrity");
78 let mut node = Node::new(NodeConfig::default())?;
79 node.start().await?;
80
81 let result = node.repo_fsck().await?;
82 progress::finish_spinner_success(&pb, "Integrity check complete");
83
84 match format {
85 "json" => {
86 println!("{{");
87 println!(" \"blocks_checked\": {},", result.blocks_checked);
88 println!(" \"blocks_valid\": {},", result.blocks_valid);
89 println!(" \"blocks_corrupt\": {},", result.blocks_corrupt.len());
90 println!(" \"blocks_missing\": {}", result.blocks_missing.len());
91 println!("}}");
92 }
93 _ => {
94 print_header("Repository Integrity Check");
95 print_kv("Blocks checked", &result.blocks_checked.to_string());
96 print_kv("Valid blocks", &result.blocks_valid.to_string());
97 print_kv("Corrupt blocks", &result.blocks_corrupt.len().to_string());
98 print_kv("Missing blocks", &result.blocks_missing.len().to_string());
99
100 if result.blocks_corrupt.is_empty() && result.blocks_missing.is_empty() {
101 success("Repository integrity verified - no issues found");
102 } else {
103 if !result.blocks_corrupt.is_empty() {
104 println!("\nCorrupt blocks:");
105 for cid in &result.blocks_corrupt {
106 error(&format!(" {}", cid));
107 }
108 }
109 if !result.blocks_missing.is_empty() {
110 println!("\nMissing blocks:");
111 for cid in &result.blocks_missing {
112 error(&format!(" {}", cid));
113 }
114 }
115 }
116 }
117 }
118
119 node.stop().await?;
120 Ok(())
121}
122
123pub async fn repo_version(_format: &str) -> Result<()> {
125 print_header("Repository Version");
126 print_kv("Format version", "1");
127 print_kv("IPFRS version", env!("CARGO_PKG_VERSION"));
128 Ok(())
129}