extern crate glob; use gitignore; use std::io; use std::path::{Path,PathBuf}; use self::glob::{Pattern,PatternError}; pub struct NotificationFilter { cwd: PathBuf, filters: Vec, ignores: Vec, ignore_file: Option } #[derive(Debug)] pub enum NotificationError { BadPattern(PatternError), Io(io::Error) } impl NotificationFilter { pub fn new(current_dir: &Path, ignore_file: Option) -> Result { let canonicalized = try!(current_dir.canonicalize()); Ok(NotificationFilter { cwd: canonicalized, filters: vec![], ignores: vec![], ignore_file: ignore_file }) } pub fn add_extension(&mut self, extensions: &str) -> Result<(), NotificationError> { let patterns: Vec = extensions .split(",") .filter(|ext| !ext.is_empty()) .map(|ext| format!("*.{}", ext.replace(".", ""))) .collect(); for pattern in patterns { try!(self.add_filter(&pattern)); } Ok(()) } pub fn add_filter(&mut self, pattern: &str) -> Result<(), NotificationError> { let compiled = try!(self.pattern_for(pattern)); self.filters.push(compiled); debug!("Adding filter: {}", pattern); Ok(()) } pub fn add_ignore(&mut self, pattern: &str) -> Result<(), NotificationError> { let compiled = try!(self.pattern_for(pattern)); self.ignores.push(compiled); debug!("Adding ignore: {}", pattern); Ok(()) } fn pattern_for(&self, p: &str) -> Result { let mut path = PathBuf::from(p); if path.is_relative() { path = self.cwd.join(path.as_path()); } if let Ok(metadata) = path.metadata() { if metadata.is_dir() { path = path.join("*"); } } Pattern::new(path.to_str().unwrap()) } pub fn is_excluded(&self, path: &Path) -> bool { let path_as_str = path.to_str().unwrap(); for pattern in &self.ignores { if pattern.matches(path_as_str) { return true; } } for pattern in &self.filters { if pattern.matches(path_as_str) { return false; } } if let Some(ref ignore_file) = self.ignore_file { if ignore_file.is_excluded(path) { return true; } } self.filters.len() > 0 } } impl From for NotificationError { fn from(err: io::Error) -> NotificationError { NotificationError::Io(err) } } impl From for NotificationError { fn from(err: PatternError) -> NotificationError { NotificationError::BadPattern(err) } }