1use std::fs;
2use std::path::Path;
3
4use anyhow::{Context, Result};
5
6use crate::scanner::ScannedProject;
7
8#[derive(Debug)]
10pub struct CleanResult {
11 pub project_name: String,
12 pub targets_cleaned: usize,
13 pub bytes_freed: u64,
14 pub errors: Vec<String>,
15}
16
17pub fn clean_project(project: &ScannedProject, dry_run: bool) -> Result<CleanResult> {
21 let mut result = CleanResult {
22 project_name: project.name.clone(),
23 targets_cleaned: 0,
24 bytes_freed: 0,
25 errors: Vec::new(),
26 };
27
28 for target in &project.clean_targets {
29 if dry_run {
30 result.targets_cleaned += 1;
31 result.bytes_freed += target.size_bytes;
32 continue;
33 }
34
35 match remove_dir_all(&target.path) {
36 Ok(()) => {
37 result.targets_cleaned += 1;
38 result.bytes_freed += target.size_bytes;
39 }
40 Err(e) => {
41 result.errors.push(format!(
42 "Failed to remove {}: {}",
43 target.path.display(),
44 e
45 ));
46 }
47 }
48 }
49
50 Ok(result)
51}
52
53fn remove_dir_all(path: &Path) -> Result<()> {
57 fs::remove_dir_all(path)
58 .with_context(|| format!("Failed to remove directory: {}", path.display()))?;
59 Ok(())
60}
61
62pub fn clean_projects(
64 projects: &[&ScannedProject],
65 dry_run: bool,
66) -> Vec<CleanResult> {
67 projects
68 .iter()
69 .map(|p| {
70 clean_project(p, dry_run).unwrap_or_else(|e| CleanResult {
71 project_name: p.name.clone(),
72 targets_cleaned: 0,
73 bytes_freed: 0,
74 errors: vec![e.to_string()],
75 })
76 })
77 .collect()
78}