diff --git a/src/predicate/path/ft.rs b/src/predicate/path/ft.rs new file mode 100644 index 0000000..e863726 --- /dev/null +++ b/src/predicate/path/ft.rs @@ -0,0 +1,125 @@ +// Copyright (c) 2018 The predicates-rs Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::path; +use std::fs; + +use Predicate; + +#[derive(Clone, Copy, Debug)] +enum FileType { + File, + Dir, + Symlink, +} + +impl FileType { + fn eval(self, ft: &fs::FileType) -> bool { + match self { + FileType::File => ft.is_file(), + FileType::Dir => ft.is_dir(), + FileType::Symlink => ft.is_symlink(), + } + } +} + +/// Predicate that checks the `std::fs::FileType`. +/// +/// This is created by the `predicate::path::is_file`, `predicate::path::is_dir`, and `predicate::path::is_symlink`. +#[derive(Debug)] +pub struct FileTypePredicate { + ft: FileType, + follow: bool, +} + +impl FileTypePredicate { + /// Follow symbolic links. + /// + /// When yes is true, symbolic links are followed as if they were normal directories and files. + /// + /// Default: disabled. + pub fn follow_links(mut self, yes: bool) -> Self { + self.follow = yes; + self + } +} + +impl Predicate for FileTypePredicate { + type Item = path::Path; + + fn eval(&self, path: &path::Path) -> bool { + let metadata = if self.follow { + path.metadata() + } else { + path.symlink_metadata() + }; + metadata + .map(|m| self.ft.eval(&m.file_type())) + .unwrap_or(false) + } +} + +/// Creates a new `Predicate` that ensures the path points to a file. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// use predicates::predicate::*; +/// +/// let predicate_fn = path::is_file(); +/// assert_eq!(true, predicate_fn.eval(Path::new("Cargo.toml"))); +/// assert_eq!(false, predicate_fn.eval(Path::new("src"))); +/// assert_eq!(false, predicate_fn.eval(Path::new("non-existent-file.foo"))); +/// ``` +pub fn is_file() -> FileTypePredicate { + FileTypePredicate { + ft: FileType::File, + follow: false, + } +} + +/// Creates a new `Predicate` that ensures the path points to a directory. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// use predicates::predicate::*; +/// +/// let predicate_fn = path::is_dir(); +/// assert_eq!(false, predicate_fn.eval(Path::new("Cargo.toml"))); +/// assert_eq!(true, predicate_fn.eval(Path::new("src"))); +/// assert_eq!(false, predicate_fn.eval(Path::new("non-existent-file.foo"))); +/// ``` +pub fn is_dir() -> FileTypePredicate { + FileTypePredicate { + ft: FileType::Dir, + follow: false, + } +} + +/// Creates a new `Predicate` that ensures the path points to a symlink. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// use predicates::predicate::*; +/// +/// let predicate_fn = path::is_symlink(); +/// assert_eq!(false, predicate_fn.eval(Path::new("Cargo.toml"))); +/// assert_eq!(false, predicate_fn.eval(Path::new("src"))); +/// assert_eq!(false, predicate_fn.eval(Path::new("non-existent-file.foo"))); +/// ``` +pub fn is_symlink() -> FileTypePredicate { + FileTypePredicate { + ft: FileType::Symlink, + follow: false, + } +} diff --git a/src/predicate/path/mod.rs b/src/predicate/path/mod.rs index 0da02ce..c00d85e 100644 --- a/src/predicate/path/mod.rs +++ b/src/predicate/path/mod.rs @@ -12,3 +12,5 @@ mod existence; pub use self::existence::{exists, missing, ExistencePredicate}; +mod ft; +pub use self::ft::{is_dir, is_file, is_symlink, FileTypePredicate};