1use crate::{Action, Data, Flag, Predicate, Rule, Scalar, SerializableRegex, Token};
2use std::fs;
3use std::io;
4use std::path::{Path, PathBuf};
5
6pub fn run(working_dir: impl AsRef<Path>, data: &Data) -> io::Result<()> {
7 for dir_entry in fs::read_dir(working_dir)? {
8 let dir_entry = dbg!(dir_entry?);
9 if dir_entry.file_type()?.is_dir() {
10 continue;
11 }
12 for rule in &data.rules {
13 run_rule(dir_entry.path(), rule)?;
14 }
15 }
16
17 Ok(())
18}
19
20fn run_rule(path: impl AsRef<Path>, rule: &Rule) -> io::Result<()> {
21 if path_matches_patterns(&path, rule.flags.contains(&Flag::IgnoreCase), &rule.patterns) {
22 if let Some(predicate) = &rule.predicate {
23 if file_matches_predicates(&path, predicate)? {
24 return apply_action(&path, &rule.action);
25 }
26 } else {
27 return apply_action(&path, &rule.action);
28 }
29 }
30
31 Ok(())
32}
33
34fn apply_action(path: impl AsRef<Path>, action: &Action) -> io::Result<()> {
35 println!("apply_action({:?}, {:?})", path.as_ref(), action);
36 match action {
37 Action::Delete => fs::remove_file(path),
38 Action::Move { to } => {
39 fs::copy(&path, to.join(&path))?;
40 fs::remove_file(&path)
41 }
42 }
43}
44
45fn path_matches_patterns(
46 path: impl AsRef<Path>,
47 ignore_case: bool,
48 patterns: &[SerializableRegex],
49) -> bool {
50 if patterns.is_empty() {
51 return true;
52 }
53
54 let path = if let Some(path) = path.as_ref().to_str() {
55 path
56 } else {
57 return false;
58 };
59
60 patterns.iter().map(|pat| pat.as_ref()).any(|pattern| {
61 if ignore_case {
62 pattern.is_match(&path.to_lowercase()) || pattern.is_match(&path.to_uppercase())
63 } else {
64 pattern.is_match(path)
65 }
66 })
67}
68
69fn file_matches_predicates(path: impl AsRef<Path>, predicate: &Predicate) -> io::Result<bool> {
70 match predicate {
71 Predicate::Comparison {
72 token,
73 operator,
74 value,
75 } => match (token, value) {
76 (Token::Size, Scalar::Size(size)) => {
77 let file_metadata = fs::metadata(path)?;
78
79 Ok(operator.compare(&file_metadata.len(), size))
80 }
81 (Token::Age, Scalar::Time(_)) => unimplemented!(),
82 _ => Ok(false),
83 },
84 }
85}