Skip to main content

tome/
directory.rs

1use super::script;
2use std::{fs, io, path::Path};
3
4pub struct TomeIgnorer {
5    gitignore: ignore::gitignore::Gitignore,
6}
7
8impl TomeIgnorer {
9    pub fn new(root: &Path) -> Self {
10        let mut builder = ignore::gitignore::GitignoreBuilder::new(root);
11        let tomeignore_path = root.join(".tomeignore");
12        if tomeignore_path.exists() {
13            if let Ok(metadata) = fs::metadata(&tomeignore_path) {
14                if metadata.len() > 0 {
15                    builder.add(tomeignore_path);
16                }
17            }
18        }
19        let gitignore = builder.build().unwrap_or(ignore::gitignore::Gitignore::empty());
20        Self { gitignore }
21    }
22
23    pub fn is_ignored(&self, path: &Path) -> bool {
24        // ignore dot directories and files
25        if path.file_name()
26            .unwrap_or_default()
27            .to_str()
28            .unwrap_or_default()
29            .starts_with('.') {
30            return true;
31        }
32
33        // old behavior fallback: if there's an empty .tomeignore in a directory, ignore that directory
34        if path.is_dir() {
35            let tomeignore_path = path.join(".tomeignore");
36            if tomeignore_path.exists() {
37                if let Ok(metadata) = fs::metadata(&tomeignore_path) {
38                    if metadata.len() == 0 {
39                        return true;
40                    }
41                }
42            }
43        }
44
45        self.gitignore.matched_path_or_any_parents(path, path.is_dir()).is_ignore()
46    }
47}
48
49/// scan a directory for all files,
50/// consuming each one as a script.
51pub fn scan_directory(
52    root: &str,
53    previous_commands: &mut Vec<String>,
54    ignorer: &TomeIgnorer,
55) -> io::Result<Vec<(String, script::Script)>> {
56    let mut result = vec![];
57    let paths_raw = fs::read_dir(root);
58    if paths_raw.is_err() {
59        return Ok(vec![]);
60    }
61    let paths: Vec<_> = paths_raw.unwrap().map(|r| r.unwrap()).collect();
62    for entry in paths {
63        let path = entry.path();
64        
65        if ignorer.is_ignored(&path) {
66            continue;
67        }
68
69        let file_name = path.file_name().unwrap_or_default().to_str().unwrap_or_default();
70        let command_name = script::strip_source_suffix(file_name).to_string();
71        previous_commands.push(command_name);
72        if path.is_dir() {
73            result.extend(scan_directory(
74                path.as_path().to_str().unwrap_or_default(),
75                previous_commands,
76                ignorer,
77            )?);
78        } else if script::is_tome_script(&path) {
79            result.push((
80                previous_commands.join(" "),
81                script::Script::load(path.as_path().to_str().unwrap_or_default())?,
82            ));
83        }
84        previous_commands.pop();
85    }
86    Ok(result)
87}
88