diff options
Diffstat (limited to 'src/projects.rs')
-rw-r--r-- | src/projects.rs | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/projects.rs b/src/projects.rs new file mode 100644 index 0000000..70ea891 --- /dev/null +++ b/src/projects.rs @@ -0,0 +1,115 @@ +use crate::{Config, Result}; +use figment::Provider; +use ignore::{Walk, WalkBuilder}; +use std::{path::PathBuf, vec::IntoIter}; +use tracing::warn; + +pub use entry::SearchPath; + +mod entry; + +pub struct Projects { + paths_iter: IntoIter<SearchPath>, + iter: Option<Walk>, +} + +impl Projects { + pub fn new() -> Result<Self> { + Self::from_provider(Config::figment()) + } + + /// Extract `Config` from `provider` to construct new `Paths` + pub fn from_provider<T: Provider>(provider: T) -> Result<Self> { + Config::extract(&provider) + .map_err(Into::into) + .map(Into::into) + } +} + +impl From<Vec<SearchPath>> for Projects { + fn from(value: Vec<SearchPath>) -> Self { + Self { + paths_iter: value.into_iter(), + iter: None, + } + } +} + +impl From<Config> for Projects { + fn from(value: Config) -> Self { + value.paths.into() + } +} + +impl Iterator for Projects { + type Item = PathBuf; + + #[tracing::instrument(skip(self))] + fn next(&mut self) -> Option<Self::Item> { + 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 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, + recurse: Some(1), + }, + SearchPath { + path: project3.to_owned(), + hidden: false, + recurse: Some(0), + }, + SearchPath { + 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::<Vec<PathBuf>>(); + results.sort(); + + assert_eq!(path_bufs, results); + } +} |