diff options
-rw-r--r-- | Cargo.lock | 72 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/cli.rs | 4 | ||||
-rw-r--r-- | src/config.rs | 56 | ||||
-rw-r--r-- | src/search.rs | 28 | ||||
-rw-r--r-- | src/search/entry.rs | 17 | ||||
-rw-r--r-- | src/search/entry/config.rs | 84 |
7 files changed, 143 insertions, 119 deletions
@@ -324,6 +324,7 @@ dependencies = [ "iana-time-zone", "num-integer", "num-traits", + "serde", "winapi", ] @@ -599,6 +600,41 @@ dependencies = [ ] [[package]] +name = "darling" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] name = "dashmap" version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1583,6 +1619,12 @@ dependencies = [ ] [[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] name = "idna" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1647,6 +1689,7 @@ checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", "hashbrown", + "serde", ] [[package]] @@ -2398,6 +2441,7 @@ dependencies = [ "onefetch", "pretty_assertions", "serde", + "serde_with", "sled", "ssh_cfg", "tempfile", @@ -2651,6 +2695,34 @@ dependencies = [ ] [[package]] +name = "serde_with" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bf4a5a814902cd1014dbccfa4d4560fb8432c779471e96e035602519f82eef" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3452b4c0f6c1e357f73fdb87cd1efabaa12acf328c7a528e252893baeb3f4aa" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "serde_yaml" version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -19,6 +19,7 @@ ignore = "0.4.18" onefetch = { version = "2.14.2", optional = true } pretty_assertions = "1.3.0" serde = { version = "1.0.147", features = ["derive"] } +serde_with = "2.1.0" sled = "0.34.7" ssh_cfg = { version = "0.3.0", optional = true } thiserror = "1.0.37" @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; use tracing::{metadata::LevelFilter, Level}; -use crate::{search, Config}; +use crate::{config::Entry, Config}; /// Tool for listing project directories. #[derive(Debug, Clone, Default, Parser, Serialize, Deserialize)] @@ -64,7 +64,7 @@ impl From<Projects> for Config { .paths .iter() .cloned() - .map(|path_buf| search::entry::Config { + .map(|path_buf| Entry { path_buf, hidden: value.hidden, max_depth: value.max_depth, diff --git a/src/config.rs b/src/config.rs index 126b939..e73b7e1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,11 +1,12 @@ use figment::{providers::Serialized, value, Figment, Metadata, Profile, Provider}; use serde::{Deserialize, Serialize}; +use std::{convert::Infallible, path::PathBuf, str::FromStr}; -use crate::search; - +#[serde_with::serde_as] #[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] pub struct Config { - pub(crate) paths: Vec<search::entry::Config>, + #[serde_as(as = "Vec<serde_with::PickFirst<(_, serde_with::DisplayFromStr)>>")] + pub(crate) paths: Vec<Entry>, } impl Config { @@ -30,6 +31,43 @@ impl Provider for Config { } } +#[derive(Debug, PartialEq, Eq, Clone, Default, Serialize, Deserialize)] +#[serde(default)] +pub struct Entry { + pub path_buf: PathBuf, + pub hidden: bool, + pub max_depth: Option<usize>, + pub pattern: Option<String>, + #[cfg(feature = "git")] + pub git: bool, +} + +impl Entry { + pub fn new(path_buf: PathBuf) -> Self { + Self { + path_buf, + ..Default::default() + } + } +} + +impl From<PathBuf> for Entry { + fn from(path_buf: PathBuf) -> Self { + Self::new(path_buf) + } +} + +impl FromStr for Entry { + type Err = Infallible; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + s.parse().map(|path_buf| Self { + path_buf, + ..Default::default() + }) + } +} + #[cfg(test)] mod tests { use super::*; @@ -37,15 +75,15 @@ mod tests { use pretty_assertions::assert_eq; #[test] - fn test_extract() { + fn test_extract_config() { figment::Jail::expect_with(|jail| { jail.create_file( "file.toml", r#" paths = [ "/path/to/projects", - { path = "/path/to/other_projects", recurse = 1, hidden = true }, - { path = "/path/to/another_project", recurse = 0 }, + { path_buf = "/path/to/other_projects", hidden = true, max_depth = 1 }, + { path_buf = "/path/to/another_project", max_depth = 0 } ] "#, )?; @@ -58,19 +96,19 @@ mod tests { config, Config { paths: Vec::from([ - search::entry::Config { + Entry { path_buf: "/path/to/projects".into(), hidden: false, max_depth: None, ..Default::default() }, - search::entry::Config { + Entry { path_buf: "/path/to/other_projects".into(), hidden: true, max_depth: Some(1), ..Default::default() }, - search::entry::Config { + Entry { path_buf: "/path/to/another_project".into(), hidden: false, max_depth: Some(0), diff --git a/src/search.rs b/src/search.rs index b2db0e3..6249da4 100644 --- a/src/search.rs +++ b/src/search.rs @@ -1,14 +1,14 @@ use figment::Provider; use std::vec::IntoIter; -use self::entry::Entry; -use crate::{project::ProjectItem, Config, Result}; +use self::entry::EntryIter; +use crate::{config::Entry, project::ProjectItem, Config, Result}; pub mod entry; pub struct Search { - iter: IntoIter<entry::Config>, - curr: Option<Entry>, + iter: IntoIter<Entry>, + curr: Option<EntryIter>, } impl std::fmt::Debug for Search { @@ -32,9 +32,15 @@ impl Search { } } +impl From<Config> for Search { + fn from(config: Config) -> Self { + config.paths.into() + } +} + impl<T> From<T> for Search where - T: IntoIterator<IntoIter = IntoIter<entry::Config>>, + T: IntoIterator<IntoIter = IntoIter<Entry>>, { fn from(value: T) -> Self { Self { @@ -44,12 +50,6 @@ where } } -impl From<Config> for Search { - fn from(value: Config) -> Self { - value.paths.into() - } -} - impl Iterator for Search { type Item = ProjectItem; @@ -86,17 +86,17 @@ mod tests { let project4 = temp_dir.join("subdir/project4"); let paths = Search::from(Vec::from([ - entry::Config { + Entry { path_buf: project_dir.to_owned(), max_depth: Some(1), ..Default::default() }, - entry::Config { + Entry { path_buf: project3.to_owned(), max_depth: Some(0), ..Default::default() }, - entry::Config { + Entry { path_buf: project4.to_owned(), max_depth: Some(0), ..Default::default() diff --git a/src/search/entry.rs b/src/search/entry.rs index 6cd601c..9e58962 100644 --- a/src/search/entry.rs +++ b/src/search/entry.rs @@ -2,21 +2,18 @@ use ignore::{Walk, WalkBuilder}; use tracing::error; use crate::{ + config::Entry, project::{path::PathMatcher, ProjectParser, ProjectParserGroup}, search::ProjectItem, }; -pub use config::Config; - -mod config; - -pub struct Entry { +pub struct EntryIter { parsers: ProjectParserGroup, iter: Walk, } -impl Entry { - fn new(config: &Config) -> Self { +impl EntryIter { + fn new(config: &Entry) -> Self { let iter = WalkBuilder::new(&config.path_buf) .standard_filters(true) .max_depth(config.max_depth) @@ -38,13 +35,13 @@ impl Entry { } } -impl From<Config> for Entry { - fn from(config: Config) -> Self { +impl From<Entry> for EntryIter { + fn from(config: Entry) -> Self { Self::new(&config) } } -impl Iterator for Entry { +impl Iterator for EntryIter { type Item = ProjectItem; fn next(&mut self) -> Option<Self::Item> { diff --git a/src/search/entry/config.rs b/src/search/entry/config.rs deleted file mode 100644 index 4372356..0000000 --- a/src/search/entry/config.rs +++ /dev/null @@ -1,84 +0,0 @@ -use serde::{Deserialize, Deserializer, Serialize}; -use std::{convert::Infallible, path::PathBuf, str::FromStr}; - -#[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 pattern: Option<String>, - - #[cfg(feature = "git")] - pub git: bool, -} - -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>, - pattern: Option<String>, - - #[cfg(feature = "git")] - git: bool, - }, - } - - match Variants::deserialize(deserializer)? { - Variants::String(s) => s.parse().map_err(serde::de::Error::custom), - Variants::Struct { - path_buf, - hidden, - max_depth, - pattern, - - #[cfg(feature = "git")] - git, - } => Ok(Self { - path_buf, - hidden, - max_depth, - pattern, - - #[cfg(feature = "git")] - git, - }), - } - } -} |