use crate::utils::security::validate_delete_path;
use anyhow::Result;
use std::fs;
use std::path::Path;
pub fn cleanup_test_artifacts(base_path: &Path, preserve_specs: bool) -> Result<()> {
validate_delete_path(base_path)?;
let test_patterns = ["test-", "tmp-", "temp-", ".test-", "test_output"];
let generated_patterns = ["generated-", "output-", "build-test-"];
if base_path.exists() && base_path.is_dir() {
for entry in fs::read_dir(base_path)? {
let entry = entry?;
let path = entry.path();
let file_name = entry.file_name();
let name = file_name.to_string_lossy();
let is_test_dir = test_patterns
.iter()
.any(|pattern| name.starts_with(pattern));
let is_generated = generated_patterns
.iter()
.any(|pattern| name.starts_with(pattern));
if is_test_dir || is_generated {
if path.is_dir() {
if preserve_specs && contains_spec_files(&path) {
println!(" ⚠️ Preserving {} (contains spec files)", name);
continue;
}
validate_delete_path(&path)?;
println!(" 🗑️ Removing test directory: {}", name);
fs::remove_dir_all(&path)?;
} else if path.is_file() {
if is_test_file(&name) {
validate_delete_path(&path)?;
println!(" 🗑️ Removing test file: {}", name);
fs::remove_file(&path)?;
}
}
}
}
}
Ok(())
}
fn contains_spec_files(dir: &Path) -> bool {
if let Ok(entries) = fs::read_dir(dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.is_file() {
if let Some(ext) = path.extension() {
if ext == "yaml" || ext == "json" || ext == "yml" {
if let Some(name) = path.file_name() {
let name_str = name.to_string_lossy();
if name_str.contains("spec")
|| name_str.contains("api")
|| name_str.contains("swagger")
|| name_str.contains("openapi")
{
return true;
}
}
}
}
} else if path.is_dir() && path.file_name().map_or(false, |n| n == "specs") {
return true;
}
}
}
false
}
fn is_test_file(name: &str) -> bool {
name.ends_with("-test.sh")
|| name.ends_with(".test.js")
|| name.ends_with(".test.ts")
|| name.starts_with("test-") && name.ends_with(".json")
|| name.starts_with("test-") && name.ends_with(".mk")
|| name == "test.mk"
}
pub fn cleanup_analyze_artifacts(output_dir: &Path, keep_latest: bool) -> Result<()> {
validate_delete_path(output_dir)?;
if !keep_latest {
let backup_patterns = [".backup", ".old", ".prev"];
if output_dir.exists() {
for entry in fs::read_dir(output_dir)? {
let entry = entry?;
let path = entry.path();
let name = entry.file_name().to_string_lossy().to_string();
if backup_patterns.iter().any(|p| name.contains(p)) {
if path.is_dir() {
println!(" 🗑️ Removing backup: {}", name);
fs::remove_dir_all(&path)?;
}
}
}
}
}
Ok(())
}
pub fn cleanup_empty_dirs(base_path: &Path) -> Result<()> {
if base_path.is_dir() {
let mut is_empty = true;
for entry in fs::read_dir(base_path)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
cleanup_empty_dirs(&path)?;
if fs::read_dir(&path)?.next().is_none() {
println!(" 🗑️ Removing empty directory: {}", path.display());
fs::remove_dir(&path)?;
} else {
is_empty = false;
}
} else {
is_empty = false;
}
}
let _ = is_empty;
}
Ok(())
}