Skip to content

Commit

Permalink
Merge pull request #6 from andrewdavidmackenzie/simpath-5
Browse files Browse the repository at this point in the history
simpath-5 Fixes #5
  • Loading branch information
andrewdavidmackenzie authored Mar 21, 2020
2 parents b7d8c90 + da347ea commit 1fb0ce1
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "simpath"
version = "1.3.1"
version = "1.4.1"
authors = ["Andrew Mackenzie <[email protected]>"]
description = "Search for files on a path defined in an environment variable"
license = "MIT"
Expand Down
107 changes: 95 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,44 @@
#![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;
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<PathBuf>
entries: Vec<PathBuf>
}

#[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
Expand Down Expand Up @@ -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);
Expand All @@ -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
}
Expand All @@ -70,7 +101,7 @@ impl Simpath {
/// ```
///
pub fn directories(&self) -> &Vec<PathBuf> {
&self.dirs
&self.entries
}

/// Try to find a file by filename (not full path) on a search path.
Expand All @@ -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<PathBuf, Error> {
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() {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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<PathError> {
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();

}
Expand Down Expand Up @@ -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);
}
}

0 comments on commit 1fb0ce1

Please sign in to comment.