#![cfg_attr(coverage_nightly, coverage(off))]
use anyhow::Result;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
use crate::cli::OutputFormat;
#[derive(Debug, Clone, PartialEq)]
pub enum CleanupTarget {
Rust,
Docker,
Node,
Git,
Logs,
Caches,
All,
}
impl CleanupTarget {
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn parse(s: &str) -> Option<Self> {
match s.to_lowercase().as_str() {
"rust" => Some(Self::Rust),
"docker" => Some(Self::Docker),
"node" => Some(Self::Node),
"git" => Some(Self::Git),
"logs" => Some(Self::Logs),
"caches" => Some(Self::Caches),
"all" => Some(Self::All),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct CleanupCandidate {
pub path: PathBuf,
pub size_bytes: u64,
pub category: String,
pub description: String,
pub age_days: u32,
}
#[derive(Debug, Default)]
pub struct CleanupResult {
pub candidates: Vec<CleanupCandidate>,
pub total_size_bytes: u64,
pub items_found: usize,
pub items_cleaned: usize,
pub space_freed_bytes: u64,
pub errors: Vec<String>,
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub async fn handle_cleanup_resources(
project_dir: &Path,
targets: &[String],
execute: bool,
exclude: &[String],
min_age_days: u32,
format: OutputFormat,
) -> Result<()> {
let parsed_targets: Vec<CleanupTarget> = targets
.iter()
.filter_map(|t| CleanupTarget::parse(t))
.collect();
if parsed_targets.is_empty() {
println!("โ ๏ธ No valid cleanup targets specified");
println!(" Valid targets: rust, docker, node, git, logs, caches, all");
return Ok(());
}
let has_all = parsed_targets.contains(&CleanupTarget::All);
println!("๐งน PMAT Resource Cleanup");
println!("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
println!("๐ Scanning: {}", project_dir.display());
println!("๐ฏ Targets: {:?}", targets);
println!("โก Mode: {}", if execute { "EXECUTE" } else { "DRY-RUN" });
println!();
let mut result = CleanupResult::default();
scan_targets(
project_dir,
&parsed_targets,
has_all,
exclude,
min_age_days,
&mut result,
)?;
print_results(&result, format)?;
finalize_cleanup(execute, &mut result)
}
fn scan_targets(
project_dir: &Path,
targets: &[CleanupTarget],
has_all: bool,
exclude: &[String],
min_age_days: u32,
result: &mut CleanupResult,
) -> Result<()> {
if has_all || targets.contains(&CleanupTarget::Rust) {
scan_rust_targets(project_dir, exclude, min_age_days, result)?;
}
if has_all || targets.contains(&CleanupTarget::Node) {
scan_node_targets(project_dir, exclude, min_age_days, result)?;
}
if has_all || targets.contains(&CleanupTarget::Git) {
scan_git_targets(project_dir, result)?;
}
if has_all || targets.contains(&CleanupTarget::Logs) {
scan_log_targets(project_dir, exclude, min_age_days, result)?;
}
Ok(())
}
fn finalize_cleanup(execute: bool, result: &mut CleanupResult) -> Result<()> {
if execute && !result.candidates.is_empty() {
println!();
println!("๐ฅ Executing cleanup...");
execute_cleanup(result)?;
println!();
println!(
"โ
Cleaned {} items, freed {} MB",
result.items_cleaned,
result.space_freed_bytes / (1024 * 1024)
);
} else if !execute && !result.candidates.is_empty() {
println!();
println!("๐ก Run with --execute to perform cleanup");
}
Ok(())
}
include!("cleanup_scanners.rs");
include!("cleanup_execution.rs");
include!("cleanup_tests.rs");