#[derive(Debug, Clone)]
pub struct Glob {
pattern: String,
}
impl Glob {
pub fn new(pattern: &str) -> Result<Self, String> {
Ok(Self { pattern: pattern.to_string() })
}
pub fn is_match(&self, path: &std::path::Path) -> bool {
let path_str = path.to_string_lossy();
self.match_pattern(&self.pattern, &path_str)
}
fn match_pattern(&self, pattern: &str, path: &str) -> bool {
let mut pattern_iter = pattern.chars();
let mut path_iter = path.chars();
loop {
match (pattern_iter.next(), path_iter.next()) {
(None, None) => return true,
(None, Some(_)) => return false,
(Some('*'), None) => return true,
(Some('*'), Some(c)) => {
let remaining_pattern: String = pattern_iter.collect();
let remaining_path: String = path_iter.collect();
return self.match_pattern(&remaining_pattern, &remaining_path)
|| self.match_pattern(pattern, &format!("{}{}", c, remaining_path));
}
(Some('?'), Some(_)) => continue,
(Some(pc1), Some(pc2)) if pc1 == pc2 => continue,
_ => return false,
}
}
}
}
#[derive(Debug, Clone)]
pub struct GlobSet {
globs: Vec<Glob>,
}
impl GlobSet {
pub fn is_match(&self, path: &std::path::Path) -> bool {
self.globs.iter().any(|glob| glob.is_match(path))
}
}
pub struct GlobSetBuilder {
globs: Vec<Glob>,
}
impl GlobSetBuilder {
pub fn new() -> Self {
Self { globs: Vec::new() }
}
pub fn add(&mut self, glob: Result<Glob, String>) -> &mut Self {
if let Ok(glob) = glob {
self.globs.push(glob);
}
self
}
pub fn build(&self) -> Result<GlobSet, String> {
Ok(GlobSet { globs: self.globs.clone() })
}
}
pub fn build_glob_set(include_patterns: &[String], exclude_patterns: &[String]) -> Result<GlobSet, crate::errors::WalkError> {
let mut builder = GlobSetBuilder::new();
for pattern in exclude_patterns {
builder.add(Glob::new(pattern));
}
for pattern in include_patterns {
builder.add(Glob::new(pattern));
}
match builder.build() {
Ok(glob_set) => Ok(glob_set),
Err(err) => Err(crate::errors::WalkError::GlobParse(err)),
}
}
pub fn should_include(path: &std::path::Path, glob_set: &Option<GlobSet>) -> bool {
if let Some(glob_set) = glob_set {
!glob_set.is_match(path)
}
else {
true
}
}