vx_cli/commands/stats.rs
1// Stats and cleanup command implementation
2
3use crate::ui::UI;
4use anyhow::Result;
5use vx_plugin::PluginRegistry;
6
7pub async fn handle(registry: &PluginRegistry) -> Result<()> {
8 show_all_stats(registry).await
9}
10
11pub async fn handle_cleanup(cache: bool, orphaned: bool, dry_run: bool) -> Result<()> {
12 if dry_run {
13 UI::header("Cleanup Preview (Dry Run)");
14 } else {
15 UI::header("Cleaning up...");
16 }
17
18 // TODO: Replace with vx-core executor
19 // let mut executor = crate::executor::Executor::new()?;
20
21 if cache || !orphaned {
22 if dry_run {
23 UI::info("Would clean cache directories");
24 } else {
25 UI::step("Cleaning cache...");
26 UI::warning("Cache cleanup not yet implemented in new architecture");
27 // TODO: Implement cache cleanup
28 }
29 }
30
31 if orphaned || !cache {
32 if dry_run {
33 UI::info("Would clean orphaned packages");
34 } else {
35 UI::step("Cleaning orphaned packages...");
36 UI::warning("Orphaned package cleanup not yet implemented in new architecture");
37 // executor.cleanup()?;
38 }
39 }
40
41 if !dry_run {
42 UI::success("Cleanup completed");
43 }
44
45 Ok(())
46}
47
48#[allow(dead_code)]
49async fn show_tool_stats(tool_name: &str, _detailed: bool) -> Result<()> {
50 UI::header(&format!("Statistics for {tool_name}"));
51 UI::warning("Tool stats not yet implemented in new architecture");
52
53 // TODO: Replace with vx-core package manager
54 // let package_manager = crate::package_manager::PackageManager::new()?;
55 // let versions = package_manager.list_versions(tool_name);
56
57 // if versions.is_empty() {
58 // UI::warning(&format!("Tool '{tool_name}' is not installed"));
59 // return Ok(());
60 // }
61
62 // let mut total_size = 0u64;
63 // let version_count = versions.len();
64
65 // if detailed {
66 // println!("Installed versions:");
67 // for version in &versions {
68 // if let Ok(path) = package_manager.get_version_path(tool_name, version) {
69 // let size = calculate_directory_size(&path).unwrap_or(0);
70 // total_size += size;
71 // println!(" {} - {} ({})", version, format_size(size), path.display());
72 // }
73 // }
74 // println!();
75 // } else {
76 // for version in &versions {
77 // if let Ok(path) = package_manager.get_version_path(tool_name, version) {
78 // total_size += calculate_directory_size(&path).unwrap_or(0);
79 // }
80 // }
81 // }
82
83 // println!("Total versions: {version_count}");
84 // println!("Total size: {}", format_size(total_size));
85
86 Ok(())
87}
88
89async fn show_all_stats(_registry: &PluginRegistry) -> Result<()> {
90 let spinner = UI::new_spinner("Collecting package statistics...");
91 UI::warning("Package statistics not yet implemented in new architecture");
92
93 // TODO: Replace with vx-core executor
94 // let mut executor = crate::executor::Executor::new()?;
95 // let stats = executor.get_stats()?;
96 spinner.finish_and_clear();
97
98 // UI::show_stats(
99 // stats.total_packages,
100 // stats.total_versions,
101 // stats.total_size,
102 // &stats
103 // .last_updated
104 // .format("%Y-%m-%d %H:%M:%S UTC")
105 // .to_string(),
106 // );
107
108 // List installed packages
109 // if let Ok(packages) = executor.list_installed_packages() {
110 // if !packages.is_empty() {
111 // if detailed {
112 // println!();
113 // UI::header("Installed Packages");
114 // for package in &packages {
115 // println!(
116 // " {} {} - {}",
117 // package.name, package.version, &package.metadata.description
118 // );
119 // }
120 // } else {
121 // // Create a simple list without active status for now
122 // let package_list: Vec<(String, String, bool)> = packages
123 // .iter()
124 // .map(|package| {
125 // // For now, mark all as inactive to avoid borrowing issues
126 // // TODO: Improve this to show actual active status
127 // (package.name.clone(), package.version.clone(), false)
128 // })
129 // .collect();
130
131 // println!();
132 // UI::show_package_list(&package_list);
133 // }
134 // }
135 // }
136
137 Ok(())
138}
139
140#[allow(dead_code)]
141fn calculate_directory_size(path: &std::path::Path) -> Result<u64> {
142 if path.is_file() {
143 Ok(path.metadata()?.len())
144 } else if path.is_dir() {
145 let mut size = 0;
146 for entry in walkdir::WalkDir::new(path) {
147 let entry = entry?;
148 if entry.file_type().is_file() {
149 size += entry.metadata()?.len();
150 }
151 }
152 Ok(size)
153 } else {
154 Ok(0)
155 }
156}
157
158#[allow(dead_code)]
159fn format_size(bytes: u64) -> String {
160 const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB"];
161 let mut size = bytes as f64;
162 let mut unit_index = 0;
163
164 while size >= 1024.0 && unit_index < UNITS.len() - 1 {
165 size /= 1024.0;
166 unit_index += 1;
167 }
168
169 if unit_index == 0 {
170 format!("{} {}", bytes, UNITS[unit_index])
171 } else {
172 format!("{:.1} {}", size, UNITS[unit_index])
173 }
174}