pub mod filter;
pub mod remover;
use crate::filter::{Filter, FilterEngine};
use crate::remover::MockRemover;
pub use crate::remover::RealRemover;
use clap::Parser;
use remover::Remover;
use std::error::Error;
use std::path::PathBuf;
use walkdir::DirEntry;
use walkdir::WalkDir;
#[derive(Parser)]
pub struct Cli {
#[arg(short = 'd')]
pub dir: String,
#[arg(long = "fd")]
pub filter_dir: Option<Vec<String>>,
#[arg(long = "ext")]
pub file_ext: Option<Vec<String>>,
#[arg(long = "day")]
pub day: Option<i32>,
#[arg(long = "size")]
pub size: Option<String>,
#[arg(long = "skip_dir")]
pub is_skip_dir: bool,
#[arg(long = "is_test")]
pub is_test: bool,
}
pub fn run(args: &Cli) -> Result<Vec<PathBuf>, Box<dyn Error>> {
if args.is_test{
let mut mock_remover = MockRemover::new();
remove_files(args, &mut mock_remover)?;
Ok(mock_remover.removed.borrow().to_vec())
}else{
let mut real_remover = RealRemover {
is_skip_dir: args.is_skip_dir.clone(),
};
remove_files(args, &mut real_remover)?;
Ok(Vec::new())
}
}
pub fn remove_files<T:Remover>(args: &Cli, remover: &mut T) -> Result<(), Box<dyn Error>> {
let filter_engine = FilterEngine::from(&args)?;
let skip_dirs = args.filter_dir.clone().unwrap_or_default();
for entry in WalkDir::new(&args.dir)
.into_iter()
.filter_entry(|e| is_not_target_dir(e, &skip_dirs))
.filter_map(Result::ok)
.skip(1) {
if let Ok(_) = filter_engine.filter(&entry) {
remover.remove(entry.path())?;
}
}
Ok(())
}
fn is_not_target_dir(entry: &DirEntry, skip_dirs: &Vec<String>) -> bool {
if skip_dirs.is_empty() {
return true;
}
if entry.file_type().is_dir() {
if let Some(name) = entry.file_name().to_str() {
return !skip_dirs.contains(&name.to_string());
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::{create_dir, File};
use tempfile::tempdir;
fn make_cli(dir: &str) -> Cli {
Cli {
dir: dir.to_string(),
filter_dir: None,
file_ext: None,
day: None,
size: None,
is_skip_dir: false,
is_test: true
}
}
#[test]
fn test_remove_all_files() {
let temp = tempdir().unwrap();
let file1 = temp.path().join("a.txt");
let file2 = temp.path().join("b.txt");
File::create(&file1).unwrap();
File::create(&file2).unwrap();
let cli = make_cli(temp.path().to_str().unwrap());
let ret = run(&cli).unwrap();
assert_eq!(ret.len(), 2);
}
#[test]
fn test_skip_specific_dir() {
let temp = tempdir().unwrap();
let skip_dir = temp.path().join("skip_me");
let normal_dir = temp.path().join("delete_me");
create_dir(&skip_dir).unwrap();
create_dir(&normal_dir).unwrap();
let file1 = skip_dir.join("a.txt");
let file2 = normal_dir.join("b.txt");
File::create(&file1).unwrap();
File::create(&file2).unwrap();
let cli = Cli {
dir: temp.path().to_str().unwrap().to_string(),
filter_dir: Some(vec!["skip_me".to_string()]),
file_ext: None,
day: None,
size: None,
is_skip_dir: false,
is_test: true
};
let ret = run(&cli).unwrap();
assert_eq!(ret.len(), 2);
}
}