diff --git a/Cargo.toml b/Cargo.toml index 7c56716..7d394e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simpath" -version = "1.3.1" +version = "1.4.1" authors = ["Andrew Mackenzie "] description = "Search for files on a path defined in an environment variable" license = "MIT" diff --git a/src/lib.rs b/src/lib.rs index 6898bc0..cdf7396 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,10 @@ +#![deny(missing_docs)] +//! Simpath - or Simple Path is a small library for creating, manipulating and using Unix style +//! `Path`s. +//! +//! A `Path` is an environment variable (a String) with one or more colon-separated directories +//! specified. They are usually used to find a file that resides in one of the directories. +//! use std::path::PathBuf; use std::fmt; use std::env; @@ -5,18 +12,33 @@ use std::fs; use std::io::{Error, ErrorKind}; #[derive(Clone, Debug)] +/// `Simpath` is the struct returned when you create a new on using a named environment variable +/// which you then use to interact with the `Path` pub struct Simpath { name: String, - dirs: Vec + entries: Vec } #[derive(Debug)] +/// `FileType` can be used to find an entry in a path of a specific type (`Directory`, `File`) or +/// of `Any` type pub enum FileType { + /// An entry in the `Path` of type `File` File, + /// An entry in the `Path` of type `Directory` Directory, + /// An entry in the `Path` of `Any` types Any } +/// When validating a `Path` there can be the following types of `PathError`s returned +pub enum PathError { + /// The `Path` entry does not exist on the file system + DoesNotExist(String), + /// The `Path` entry cannot be reads + CannotRead(String) +} + impl Simpath { /// Create a new simpath, providing the name of the environment variable to initialize the /// search path with. If an environment variable of that name exists and it will be parsed @@ -44,7 +66,7 @@ impl Simpath { pub fn new(var_name: &str) -> Self { let mut search_path = Simpath { name: var_name.to_string(), - dirs: vec!() + entries: vec!() }; search_path.add_from_env_var(var_name); @@ -53,6 +75,15 @@ impl Simpath { } /// Get the name associated with the simpath. Note that this could be an empty String + /// ``` + /// extern crate simpath; + /// use simpath::Simpath; + /// + /// fn main() { + /// let search_path = Simpath::new("PATH"); + /// println!("Directories in Search Path: {:?}", search_path.name()); + /// } + /// ``` pub fn name(&self) -> &str { &self.name } @@ -70,7 +101,7 @@ impl Simpath { /// ``` /// pub fn directories(&self) -> &Vec { - &self.dirs + &self.entries } /// Try to find a file by filename (not full path) on a search path. @@ -95,8 +126,23 @@ impl Simpath { self.find_type(file_name, FileType::Any) } + /// find an entry of a specific `FileType` in a `Path` + /// + /// ``` + /// extern crate simpath; + /// use simpath::Simpath; + /// + /// fn main() { + /// use simpath::FileType; + /// let search_path = Simpath::new("PATH"); + /// match search_path.find_type("my-file", FileType::Directory) { + /// Ok(_found_dir) => println!("Didn't expect that!!"), + /// Err(e) => println!("{}", e.to_string()) + /// } + /// } + /// ``` pub fn find_type(&self, file_name: &str, file_type: FileType) -> Result { - for search_dir in &self.dirs { + for search_dir in &self.entries { for entry in fs::read_dir(search_dir)? { let file = entry?; if let Some(filename) = file.file_name().to_str() { @@ -136,13 +182,11 @@ impl Simpath { pub fn add_directory(&mut self, dir: &str) { let path = PathBuf::from(dir); if path.exists() && path.is_dir() && path.read_dir().is_ok() { - self.dirs.push(path); + self.entries.push(path); } } - /// Check if a search path contains a directory - /// - /// + /// Check if a search path contains an entry /// ``` /// extern crate simpath; /// use simpath::Simpath; @@ -154,9 +198,9 @@ impl Simpath { /// } /// } /// ``` - pub fn contains(&self, dir: &str) -> bool { - for search_dir in &self.dirs { - if search_dir.to_str().unwrap() == dir { + pub fn contains(&self, entry: &str) -> bool { + for search_dir in &self.entries { + if search_dir.to_str().unwrap() == entry { return true; } } @@ -188,12 +232,30 @@ impl Simpath { } } } + + /// `validate` checks that all the entries in the `Path` are of a valid syntax, exist on + /// the file system and can be read + pub fn validate(&self) -> Vec { + let mut errors = vec!(); + + for entry in &self.entries { + if !entry.exists() { + errors.push(PathError::DoesNotExist(entry.to_str().unwrap().into())); + } + + if fs::metadata(entry).is_err() { + errors.push(PathError::CannotRead(entry.to_str().unwrap().into())); + } + } + + errors + } } impl fmt::Display for Simpath { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Search Path: '{}', Directories: {{", self.name).unwrap(); - for dir in &self.dirs { + for dir in &self.entries { write!(f, "'{}', ", dir.display()).unwrap(); } @@ -354,4 +416,25 @@ mod test { println!("Simpath can be printed: {}", path); } + + #[test] + fn entry_does_not_exist() { + let var_name = "MyPathEnv"; + env::set_var(var_name, "/foo"); + let mut path = Simpath::new("MyName"); + path.add_from_env_var(var_name); + + assert_eq!(path.directories().len(), 0); + } + + #[test] + fn one_entry_does_not_exist() { + let var_name = "MyPathEnv"; + env::set_var(var_name, ".:/foo"); + let mut path = Simpath::new("MyName"); + path.add_from_env_var(var_name); + + assert_eq!(path.directories().len(), 1); + assert_eq!(path.validate().len(), 0); + } } \ No newline at end of file