use crate::{Action, Data, Flag, Predicate, Rule, Scalar, SerializableRegex, Token};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
pub fn run(working_dir: impl AsRef<Path>, data: &Data) -> io::Result<()> {
for dir_entry in fs::read_dir(working_dir)? {
let dir_entry = dbg!(dir_entry?);
if dir_entry.file_type()?.is_dir() {
continue;
}
for rule in &data.rules {
run_rule(dir_entry.path(), rule)?;
}
}
Ok(())
}
fn run_rule(path: impl AsRef<Path>, rule: &Rule) -> io::Result<()> {
if path_matches_patterns(&path, rule.flags.contains(&Flag::IgnoreCase), &rule.patterns) {
if let Some(predicate) = &rule.predicate {
if file_matches_predicates(&path, predicate)? {
return apply_action(&path, &rule.action);
}
} else {
return apply_action(&path, &rule.action);
}
}
Ok(())
}
fn apply_action(path: impl AsRef<Path>, action: &Action) -> io::Result<()> {
println!("apply_action({:?}, {:?})", path.as_ref(), action);
match action {
Action::Delete => fs::remove_file(path),
Action::Move { to } => {
fs::copy(&path, to.join(&path))?;
fs::remove_file(&path)
}
}
}
fn path_matches_patterns(
path: impl AsRef<Path>,
ignore_case: bool,
patterns: &[SerializableRegex],
) -> bool {
if patterns.is_empty() {
return true;
}
let path = if let Some(path) = path.as_ref().to_str() {
path
} else {
return false;
};
patterns.iter().map(|pat| pat.as_ref()).any(|pattern| {
if ignore_case {
pattern.is_match(&path.to_lowercase()) || pattern.is_match(&path.to_uppercase())
} else {
pattern.is_match(path)
}
})
}
fn file_matches_predicates(path: impl AsRef<Path>, predicate: &Predicate) -> io::Result<bool> {
match predicate {
Predicate::Comparison {
token,
operator,
value,
} => match (token, value) {
(Token::Size, Scalar::Size(size)) => {
let file_metadata = fs::metadata(path)?;
Ok(operator.compare(&file_metadata.len(), size))
}
(Token::Age, Scalar::Time(_)) => unimplemented!(),
_ => Ok(false),
},
}
}