use normalize_rules_config::{PathFilter, WalkConfig};
use std::path::Path;
fn configure_walk_builder(
builder: &mut ignore::WalkBuilder,
walk_config: &WalkConfig,
root: &Path,
) {
let ignore_files = walk_config.ignore_files();
let has_gitignore = ignore_files.contains(&".gitignore");
builder.hidden(false);
builder.git_ignore(has_gitignore);
builder.git_global(has_gitignore);
builder.git_exclude(has_gitignore);
for file in &ignore_files {
if *file != ".gitignore" {
let ignore_path = root.join(file);
if ignore_path.exists() {
builder.add_ignore(ignore_path);
}
}
}
}
pub fn gitignore_walk(
root: &Path,
walk_config: &WalkConfig,
) -> impl Iterator<Item = ignore::DirEntry> {
let mut builder = ignore::WalkBuilder::new(root);
configure_walk_builder(&mut builder, walk_config, root);
let excludes = walk_config.compiled_excludes(root);
let root_owned = root.to_path_buf();
builder.filter_entry(move |e| {
let path = e.path();
let rel = path.strip_prefix(&root_owned).unwrap_or(path);
if rel.as_os_str().is_empty() {
return true;
}
let is_dir = e.file_type().is_some_and(|ft| ft.is_dir());
!excludes
.matched_path_or_any_parents(rel, is_dir)
.is_ignore()
});
builder.build().filter_map(|e| e.ok())
}
#[allow(dead_code)]
pub fn filtered_gitignore_walk<'a>(
root: &'a Path,
filter: &'a PathFilter,
walk_config: &'a WalkConfig,
) -> Box<dyn Iterator<Item = ignore::DirEntry> + 'a> {
if filter.is_empty() {
return Box::new(gitignore_walk(root, walk_config));
}
Box::new(gitignore_walk(root, walk_config).filter(move |entry| {
if entry.file_type().is_some_and(|ft| ft.is_dir()) {
return true;
}
let rel = entry.path().strip_prefix(root).unwrap_or(entry.path());
filter.matches_path(rel)
}))
}