use crate::{Config, Result}; use figment::Provider; use ignore::Walk; use std::{path::PathBuf, vec::IntoIter}; use tracing::warn; pub use entry::SearchPath; mod entry; pub struct Projects { search_path_iter: IntoIter, walk: Option, } impl std::fmt::Debug for Projects { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Projects") .field("paths_iter", &self.search_path_iter) .finish_non_exhaustive() } } impl Projects { 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 Projects { fn from(value: Vec) -> Self { Self { search_path_iter: value.into_iter(), walk: None, } } } impl From for Projects { fn from(value: Config) -> Self { value.paths.into() } } impl Iterator for Projects { type Item = PathBuf; #[tracing::instrument] fn next(&mut self) -> Option { if self.walk.is_none() { self.walk = Some(self.search_path_iter.next()?.into()); }; match self.walk.as_mut()?.next()? { Ok(d) => Some(d.into_path()), Err(err) => { warn!("{:?}", err); None } } } } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; 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 = Projects::from(Vec::from([ SearchPath { path: project_dir.to_owned(), hidden: false, max_depth: Some(1), }, SearchPath { path: project3.to_owned(), hidden: false, max_depth: Some(0), }, SearchPath { path: project4.to_owned(), hidden: false, max_depth: 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); } }