use std::path::{Path, PathBuf};
use ignore::WalkBuilder;
use crate::extract::resolve_format;
#[derive(Debug, Clone, Copy)]
pub(crate) struct WalkOptions {
pub(crate) hidden: bool,
pub(crate) respect_ignore: bool,
}
impl Default for WalkOptions {
fn default() -> Self {
Self {
hidden: false,
respect_ignore: true,
}
}
}
pub(crate) fn collect(roots: &[PathBuf], options: WalkOptions) -> Vec<PathBuf> {
let mut files = Vec::new();
for root in roots {
if root.is_file() {
files.push(root.clone());
continue;
}
let mut builder = WalkBuilder::new(root);
builder
.hidden(!options.hidden)
.git_ignore(options.respect_ignore)
.git_global(options.respect_ignore)
.git_exclude(options.respect_ignore)
.parents(options.respect_ignore);
for entry in builder.build().filter_map(Result::ok) {
let path = entry.path();
if !entry.file_type().is_some_and(|kind| kind.is_file()) {
continue;
}
if has_a_format(path) {
files.push(path.to_path_buf());
}
}
}
files.sort();
files.dedup();
files
}
fn has_a_format(path: &Path) -> bool {
path.file_name()
.and_then(|name| name.to_str())
.and_then(|name| resolve_format(None, Some(name)))
.is_some()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_name_with_no_format_is_not_walked() {
assert!(has_a_format(Path::new("a/b/app.log")));
assert!(has_a_format(Path::new("events.json")));
assert!(!has_a_format(Path::new("main.rs")));
assert!(!has_a_format(Path::new("Makefile")));
}
#[test]
fn the_default_is_the_walk_a_reader_expects() {
let options = WalkOptions::default();
assert!(!options.hidden, "hidden files are skipped");
assert!(options.respect_ignore, "gitignore is honoured");
}
}