use figment::Provider; use ignore::{Walk, WalkBuilder}; use std::{path::PathBuf, vec::IntoIter}; use tracing::warn; pub use config::{Config, PathEntry}; pub use error::{Error, Result}; mod config; mod error; pub struct Paths { paths_iter: IntoIter, iter: Option, } impl Paths { pub fn new() -> Result { Self::from_provider(Config::figment()) } /// Extract `Config` from `provider` to construct new `Paths` pub fn from_provider(provider: T) -> Result { Config::extract(&provider) .map_err(Into::into) .map(Into::into) } } impl From> for Paths { fn from(value: Vec) -> Self { Self { paths_iter: value.into_iter(), iter: None, } } } impl From for Paths { fn from(value: Config) -> Self { value.paths.into() } } impl Iterator for Paths { type Item = PathBuf; #[tracing::instrument(skip(self))] fn next(&mut self) -> Option { loop { match self.iter.as_mut().and_then(|iter| iter.next()) { Some(Ok(d)) => return Some(d.into_path()), Some(Err(err)) => warn!("{:?}", err), None => { let next = self.paths_iter.next()?; self.iter = Some( WalkBuilder::new(next.path) .standard_filters(true) .max_depth(next.recurse) .hidden(next.hidden) .build(), ); } }; } } } #[cfg(test)] mod tests { use super::*; use std::fs; #[test] fn test_iteration() { let temp_dir = tempfile::Builder::new() .tempdir() .unwrap() .path() .to_owned(); let project_dir = temp_dir.join("project_dir"); let project1 = temp_dir.join("project_dir/project1"); let project2 = temp_dir.join("project_dir/project2"); let project3 = temp_dir.join("project3"); let project4 = temp_dir.join("subdir/project4"); let paths = Paths::from(Vec::from([ PathEntry { path: project_dir.to_owned(), hidden: false, recurse: Some(1), }, PathEntry { path: project3.to_owned(), hidden: false, recurse: Some(0), }, PathEntry { path: project4.to_owned(), hidden: false, recurse: Some(0), }, ])); let mut path_bufs = Vec::from([project_dir, project1, project2, project3, project4]); path_bufs.iter().try_for_each(fs::create_dir_all).unwrap(); path_bufs.sort(); let mut results = paths.into_iter().collect::>(); results.sort(); assert_eq!(path_bufs, results); } }