summaryrefslogtreecommitdiffstats
path: root/src/projects.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/projects.rs')
-rw-r--r--src/projects.rs115
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);
+ }
+}