Skip to main content

jeeves/
run.rs

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}