1use std::path::Path;
2
3use crate::error::{Error, Result};
4use crate::finding::Finding;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum DeleteMode {
9 Trash,
11 Permanent,
13 DryRun,
15}
16
17pub struct CleanResult {
19 pub deleted_count: usize,
20 pub freed_bytes: u64,
21 pub errors: Vec<(String, String)>,
22}
23
24pub fn clean(findings: &[Finding], mode: DeleteMode) -> Result<CleanResult> {
26 let mut deleted_count = 0;
27 let mut freed_bytes = 0;
28 let mut errors: Vec<(String, String)> = Vec::new();
29
30 for finding in findings {
31 if mode == DeleteMode::DryRun {
32 deleted_count += 1;
33 freed_bytes += finding.size_bytes;
34 continue;
35 }
36
37 match delete_path(&finding.path, mode) {
38 Ok(()) => {
39 deleted_count += 1;
40 freed_bytes += finding.size_bytes;
41 }
42 Err(e) => {
43 errors.push((finding.path.display().to_string(), e.to_string()));
44 }
45 }
46 }
47
48 Ok(CleanResult {
49 deleted_count,
50 freed_bytes,
51 errors,
52 })
53}
54
55fn delete_path(path: &Path, mode: DeleteMode) -> Result<()> {
56 if !path.exists() {
57 return Ok(());
58 }
59
60 match mode {
61 DeleteMode::Trash => {
62 trash::delete(path).map_err(|e| Error::Trash(e.to_string()))?;
63 }
64 DeleteMode::Permanent => {
65 if path.is_dir() {
66 std::fs::remove_dir_all(path).map_err(|e| Error::io(path, e))?;
67 } else {
68 std::fs::remove_file(path).map_err(|e| Error::io(path, e))?;
69 }
70 }
71 DeleteMode::DryRun => {
72 }
74 }
75
76 Ok(())
77}