use std::ffi::OsStr;
use std::path::Path;
use ignore::{self, DirEntry, WalkBuilder, WalkState};
use crate::hooks;
pub fn find_files_recursively(root: impl AsRef<Path>, f: impl Fn(&Path) + Sync) {
let root = root.as_ref();
let does_dir_entry_match = move |path: &Path| {
if [".git"].map(Path::new).contains(&path) {
return false;
}
true
};
let does_file_entry_match = move |path: &Path| {
let is_at_root = path.components().count() == 1;
if is_at_root && hooks::is_hook(path) {
return false;
}
let file_name = path.file_name().expect("we don't have `..` here");
if [".deez", ".ignore", ".gitignore"]
.map(OsStr::new)
.contains(&file_name)
{
return false;
}
true
};
assert!(root.is_dir());
WalkBuilder::new(root)
.follow_links(false)
.hidden(false)
.max_depth(None)
.build_parallel()
.run(|| {
Box::new(|entry| {
if let Ok(entry) = entry {
let path = strip_root(root, entry.path());
if is_dir(&entry) {
return if does_dir_entry_match(path) {
WalkState::Continue
} else {
WalkState::Skip
};
}
if does_file_entry_match(path) {
f(path);
return WalkState::Continue;
}
}
WalkState::Skip
})
});
}
#[inline]
fn strip_root<'a>(root: &Path, path: &'a Path) -> &'a Path {
path.strip_prefix(root)
.expect("`path` always contains `root`")
}
fn is_dir(entry: &DirEntry) -> bool {
entry.file_type().is_some_and(|entry| entry.is_dir())
}