use std::path::PathBuf; use ignore::{Walk, WalkBuilder}; use tracing::{debug, error}; use crate::{ config::Filters, project::{path::PathMatcher, Project, ProjectParserGroup}, }; pub struct SearchPath { path_buf: PathBuf, parsers: ProjectParserGroup, iter: Walk, } impl std::fmt::Debug for SearchPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("SearchPath") .field("path_buf", &self.path_buf) .finish() } } impl SearchPath { pub fn new(path_buf: PathBuf, config: &Filters) -> Self { let mut parsers = ProjectParserGroup::new(); if config.all { parsers.push(Box::new(PathMatcher::All)) } if let Some(s) = config.pattern.as_ref() { parsers.push(Box::new(PathMatcher::Pattern(s.to_owned()))); }; #[cfg(feature = "git")] if config.git { parsers.push(Box::new(crate::project::git::GitMatcher)); }; let iter = WalkBuilder::new(&path_buf) .standard_filters(true) .max_depth(config.max_depth) .hidden(!config.hidden) .build(); Self { path_buf, parsers, iter, } } } impl Iterator for SearchPath { type Item = Project; fn next(&mut self) -> Option { match self.iter.next()? { Ok(dir_entry) if dir_entry.path() == self.path_buf => { debug!("Ignoring parent directory"); None } Ok(dir_entry) => self.parsers.parse(dir_entry.into_path()), Err(err) => { error!(%err, "Ignoring errored path"); None } } .or_else(|| self.next()) } }