diff options
Diffstat (limited to 'src/search')
-rw-r--r-- | src/search/entry.rs | 57 | ||||
-rw-r--r-- | src/search/entry/config.rs | 90 |
2 files changed, 147 insertions, 0 deletions
diff --git a/src/search/entry.rs b/src/search/entry.rs new file mode 100644 index 0000000..6e94b35 --- /dev/null +++ b/src/search/entry.rs @@ -0,0 +1,57 @@ +use ignore::{DirEntry, Walk}; +use tracing::error; + +use crate::{ + project::{GitProject, PathProject}, + Project, +}; + +pub use config::Config; + +mod config; + +pub struct Entry { + config: Config, + iter: Walk, +} + +impl std::fmt::Debug for Entry { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SearchPath") + .field("config", &self.config) + .finish() + } +} + +impl Entry { + pub fn match_project(&self, dir_entry: DirEntry) -> Option<Box<dyn Project>> { + if self.config.git { + if let Ok(git) = GitProject::try_from(dir_entry.to_owned()) { + return Some(Box::new(git)); + }; + }; + + if let Some(pattern) = &self.config.pattern { + if let Ok(proj) = PathProject::try_from((pattern, dir_entry)) { + return Some(Box::new(proj)); + }; + }; + + None + } +} + +impl Iterator for Entry { + type Item = Box<dyn Project>; + + #[tracing::instrument] + fn next(&mut self) -> Option<Self::Item> { + match self.iter.next()? { + Ok(dir_entry) => self.match_project(dir_entry), + Err(err) => { + error!(%err, "Ignoring errored path"); + self.next() + } + } + } +} diff --git a/src/search/entry/config.rs b/src/search/entry/config.rs new file mode 100644 index 0000000..d325b58 --- /dev/null +++ b/src/search/entry/config.rs @@ -0,0 +1,90 @@ +use ignore::WalkBuilder; +use serde::{Deserialize, Deserializer, Serialize}; +use std::{convert::Infallible, path::PathBuf, str::FromStr}; + +use super::Entry; + +#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize)] +#[serde(default)] +pub struct Config { + pub path_buf: PathBuf, + pub hidden: bool, + pub max_depth: Option<usize>, + pub git: bool, + pub pattern: Option<String>, +} + +impl From<Config> for Entry { + fn from(config: Config) -> Self { + let iter = WalkBuilder::new(&config.path_buf) + .standard_filters(true) + .max_depth(config.max_depth) + .hidden(!config.hidden) + .build(); + Self { iter, config } + } +} + +impl From<PathBuf> for Config { + fn from(path_buf: PathBuf) -> Self { + Self { + path_buf, + ..Default::default() + } + } +} + +impl Config { + pub fn new(path_buf: PathBuf) -> Self { + Self { + path_buf, + ..Default::default() + } + } +} + +impl FromStr for Config { + type Err = Infallible; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + s.parse().map(PathBuf::into) + } +} + +// Custom deserialize impl to accept either string or struct +impl<'de> Deserialize<'de> for Config { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(untagged)] + enum Variants { + String(String), + Struct { + path_buf: PathBuf, + hidden: bool, + max_depth: Option<usize>, + git: bool, + pattern: Option<String>, + }, + } + + match Variants::deserialize(deserializer)? { + Variants::String(s) => s.parse().map_err(serde::de::Error::custom), + Variants::Struct { + path_buf, + hidden, + max_depth, + git, + pattern, + } => Ok(Self { + path_buf, + hidden, + max_depth, + git, + pattern, + }), + } + } +} |