aboutsummaryrefslogtreecommitdiff
path: root/mingling/src/parser/picker/path.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mingling/src/parser/picker/path.rs')
-rw-r--r--mingling/src/parser/picker/path.rs145
1 files changed, 145 insertions, 0 deletions
diff --git a/mingling/src/parser/picker/path.rs b/mingling/src/parser/picker/path.rs
new file mode 100644
index 0000000..589531f
--- /dev/null
+++ b/mingling/src/parser/picker/path.rs
@@ -0,0 +1,145 @@
+use std::path::PathBuf;
+
+use crate::parser::Pickable;
+
+mod rule;
+pub use rule::*;
+
+impl Pickable for Vec<PathBuf> {
+ type Output = Vec<PathBuf>;
+
+ fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> {
+ let raw: Vec<String> = args.pick_arguments(flag);
+ let paths: Vec<PathBuf> = raw.into_iter().map(|s| PathBuf::from(s)).collect();
+ Some(paths)
+ }
+}
+
+impl Pickable for PathBuf {
+ type Output = PathBuf;
+
+ fn pick(args: &mut crate::parser::Argument, flag: mingling_core::Flag) -> Option<Self::Output> {
+ let raw: String = args.pick_argument(flag)?;
+ let path: PathBuf = PathBuf::from(raw);
+ Some(path)
+ }
+}
+
+/// Provides path checking methods for [`Vec<PathBuf>`]
+///
+/// This trait automatically provides implementations for `Into<Vec<PathBuf>>`
+pub trait PathsChecker {
+ /// Check if all paths in the list satisfy the rule
+ fn is_all_passed(&self, rule: &PathCheckRule) -> bool
+ where
+ Self: Into<Vec<PathBuf>> + Clone,
+ {
+ check_paths(self.clone(), rule).is_ok()
+ }
+
+ /// Classify paths into (Passed, Stripped)
+ ///
+ /// Passed means paths that satisfy the rule, Stripped means paths that do not.
+ fn classify(self, rule: &PathCheckRule) -> (Vec<PathBuf>, Vec<PathBuf>)
+ where
+ Self: Into<Vec<PathBuf>>,
+ {
+ let paths = self.into();
+ let mut passed = Vec::new();
+ let mut stripped = Vec::new();
+ for path in paths {
+ if check_path(&path, rule).is_ok() {
+ passed.push(path);
+ } else {
+ stripped.push(path);
+ }
+ }
+ (passed, stripped)
+ }
+
+ /// Return paths that satisfy the rule
+ fn passed(self, rule: &PathCheckRule) -> Vec<PathBuf>
+ where
+ Self: Into<Vec<PathBuf>>,
+ {
+ self.classify(rule).0
+ }
+
+ /// Return paths that do not satisfy the rule
+ fn stripped(self, rule: &PathCheckRule) -> Vec<PathBuf>
+ where
+ Self: Into<Vec<PathBuf>>,
+ {
+ self.classify(rule).1
+ }
+}
+
+/// Provides path checking methods for [`PathBuf`]
+///
+/// This trait automatically provides implementations for `Into<PathBuf>`
+pub trait PathChecker {
+ fn is_passed(&self, rule: &PathCheckRule) -> bool
+ where
+ Self: Into<PathBuf> + Clone,
+ {
+ check_path(self.clone(), rule).is_ok()
+ }
+}
+
+impl<T: Into<Vec<PathBuf>>> PathsChecker for T where T: Into<Vec<PathBuf>> {}
+impl<T: Into<PathBuf>> PathChecker for T where T: Into<PathBuf> {}
+
+fn check_paths(path: impl Into<Vec<PathBuf>>, rule: &PathCheckRule) -> Result<(), ()> {
+ let paths = path.into();
+ for p in paths.iter() {
+ check_exist(p, rule)?;
+ check_type(p, rule)?;
+ }
+
+ Ok(())
+}
+
+fn check_path(path: impl Into<PathBuf>, rule: &PathCheckRule) -> Result<(), ()> {
+ let p = path.into();
+ check_exist(&p, rule)?;
+ check_type(&p, rule)?;
+
+ Ok(())
+}
+
+fn check_exist(path: &PathBuf, rule: &PathCheckRule) -> Result<(), ()> {
+ let Some(exist_check) = &rule.exist_check else {
+ return Ok(());
+ };
+
+ match exist_check {
+ PathExistCheck::Exists => bool_to_result(path.exists()),
+ PathExistCheck::NotExists => bool_to_result(!path.exists()),
+ }
+}
+
+fn check_type(path: &PathBuf, rule: &PathCheckRule) -> Result<(), ()> {
+ let Some(type_check) = &rule.type_check else {
+ return Ok(());
+ };
+
+ let is_dir = path.is_dir();
+ let is_file = path.is_file();
+ let is_symlink = path.is_symlink();
+
+ if type_check.allow_dir && is_dir {
+ return Ok(());
+ }
+ if type_check.allow_file && is_file {
+ return Ok(());
+ }
+ if type_check.allow_symlink && is_symlink {
+ return Ok(());
+ }
+
+ Err(())
+}
+
+fn bool_to_result(b: bool) -> Result<(), ()> {
+ if b { Ok(()) } else { Err(()) }
+}