diff --git a/Cargo.lock b/Cargo.lock index d012c1a..55d2bdd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "watchexec" -version = "1.6.2" +version = "1.7.0" dependencies = [ "clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/cli.rs b/src/cli.rs index 45e0d3b..353d28b 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -6,6 +6,7 @@ use clap::{App, Arg}; #[derive(Debug)] pub struct Args { pub cmd: String, + pub paths: Vec, pub filters: Vec, pub ignores: Vec, pub clear_screen: bool, @@ -44,6 +45,13 @@ pub fn get_args() -> Args { .short("e") .long("exts") .takes_value(true)) + .arg(Arg::with_name("path") + .help("Watch a specific directory") + .short("w") + .long("watch") + .number_of_values(1) + .multiple(true) + .takes_value(true)) .arg(Arg::with_name("clear") .help("Clear screen before executing command") .short("c") @@ -93,6 +101,8 @@ pub fn get_args() -> Args { .get_matches(); let cmd = values_t!(args.values_of("command"), String).unwrap().join(" "); + let paths = values_t!(args.values_of("path"), String).unwrap_or(vec![String::from(".")]); + let mut filters = values_t!(args.values_of("filter"), String).unwrap_or(vec![]); if let Some(extensions) = args.values_of("extensions") { @@ -121,6 +131,7 @@ pub fn get_args() -> Args { Args { cmd: cmd, + paths: paths, filters: filters, ignores: ignores, clear_screen: args.is_present("clear"), diff --git a/src/gitignore.rs b/src/gitignore.rs index 6691d08..61536ec 100644 --- a/src/gitignore.rs +++ b/src/gitignore.rs @@ -41,7 +41,7 @@ enum MatchResult { None, } -pub fn load(paths: Vec<&Path>) -> Gitignore { +pub fn load(paths: &Vec) -> Gitignore { let mut files = vec![]; let mut checked_dirs = HashSet::new(); diff --git a/src/main.rs b/src/main.rs index fb598bb..2262860 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,8 +27,7 @@ mod signal; mod watcher; use std::collections::HashMap; -use std::env; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::{Arc, RwLock}; use std::sync::mpsc::{channel, Receiver}; use std::time::Duration; @@ -79,34 +78,31 @@ fn main() { init_logger(args.debug); - let cwd = env::current_dir() - .expect("unable to get cwd") - .canonicalize() - .expect("unable to canonicalize cwd"); + let paths: Vec = args.paths + .iter() + .map(|p| Path::new(&p) + .canonicalize() + .expect(&format!("unable to canonicalize \"{}\"", &p)) + .to_owned()) + .collect(); let gitignore = if !args.no_vcs_ignore { - gitignore::load(vec![&cwd]) + gitignore::load(&paths) } else { - gitignore::load(vec![]) + gitignore::load(&vec![]) }; let filter = NotificationFilter::new(args.filters, args.ignores, gitignore) .expect("unable to create notification filter"); let (tx, rx) = channel(); - let mut watcher = Watcher::new(tx, args.poll, args.poll_interval) + let watcher = Watcher::new(tx, &paths, args.poll, args.poll_interval) .expect("unable to create watcher"); if watcher.is_polling() { warn!("Polling for changes every {} ms", args.poll_interval); } - let result = watcher.watch(cwd); - if let Err(e) = result { - error!("Unable to watch directory/subdirectory: {}", e); - return; - } - // Start child process initially, if necessary if args.run_initially && !args.once { if args.clear_screen { diff --git a/src/notification_filter.rs b/src/notification_filter.rs index 7762081..f0a0302 100644 --- a/src/notification_filter.rs +++ b/src/notification_filter.rs @@ -94,7 +94,7 @@ mod tests { #[test] fn test_allows_everything_by_default() { - let filter = NotificationFilter::new(vec![], vec![], gitignore::load(vec![])).unwrap(); + let filter = NotificationFilter::new(vec![], vec![], gitignore::load(&vec![])).unwrap(); assert!(!filter.is_excluded(&Path::new("foo"))); } @@ -102,7 +102,7 @@ mod tests { #[test] fn test_multiple_filters() { let filters = vec![String::from("*.rs"), String::from("*.toml")]; - let filter = NotificationFilter::new(filters, vec![], gitignore::load(vec![])).unwrap(); + let filter = NotificationFilter::new(filters, vec![], gitignore::load(&vec![])).unwrap(); assert!(!filter.is_excluded(&Path::new("hello.rs"))); assert!(!filter.is_excluded(&Path::new("Cargo.toml"))); @@ -112,7 +112,7 @@ mod tests { #[test] fn test_multiple_ignores() { let ignores = vec![String::from("*.rs"), String::from("*.toml")]; - let filter = NotificationFilter::new(vec![], ignores, gitignore::load(vec![])).unwrap(); + let filter = NotificationFilter::new(vec![], ignores, gitignore::load(&vec![])).unwrap(); assert!(filter.is_excluded(&Path::new("hello.rs"))); assert!(filter.is_excluded(&Path::new("Cargo.toml"))); @@ -122,7 +122,7 @@ mod tests { #[test] fn test_ignores_take_precedence() { let ignores = vec![String::from("*.rs"), String::from("*.toml")]; - let filter = NotificationFilter::new(ignores.clone(), ignores, gitignore::load(vec![])) + let filter = NotificationFilter::new(ignores.clone(), ignores, gitignore::load(&vec![])) .unwrap(); assert!(filter.is_excluded(&Path::new("hello.rs"))); diff --git a/src/watcher.rs b/src/watcher.rs index 1c5a926..c39b8f6 100644 --- a/src/watcher.rs +++ b/src/watcher.rs @@ -1,4 +1,4 @@ -use std::path::Path; +use std::path::PathBuf; use std::sync::mpsc::Sender; use notify::{PollWatcher, RecommendedWatcher, RecursiveMode, raw_watcher}; @@ -22,14 +22,28 @@ enum WatcherImpl { } impl Watcher { - pub fn new(tx: Sender, poll: bool, interval_ms: u32) -> Result { + pub fn new(tx: Sender, paths: &Vec, poll: bool, interval_ms: u32) -> Result { + use notify::Watcher; + let imp = if poll { - WatcherImpl::Poll(try!(PollWatcher::with_delay_ms(tx, interval_ms))) + let mut watcher = try!(PollWatcher::with_delay_ms(tx, interval_ms)); + for ref path in paths { + try!(watcher.watch(path, RecursiveMode::Recursive)); + debug!("Watching {:?}", path); + } + + WatcherImpl::Poll(watcher) } else { - WatcherImpl::Recommended(try!(raw_watcher(tx))) + let mut watcher = try!(raw_watcher(tx)); + for ref path in paths { + try!(watcher.watch(path, RecursiveMode::Recursive)); + debug!("Watching {:?}", path); + } + + WatcherImpl::Recommended(watcher) }; - Ok(Watcher { watcher_impl: imp }) + Ok(self::Watcher { watcher_impl: imp }) } pub fn is_polling(&self) -> bool { @@ -39,13 +53,4 @@ impl Watcher { false } } - - pub fn watch>(&mut self, path: P) -> Result<(), Error> { - use notify::Watcher; - - match self.watcher_impl { - WatcherImpl::Recommended(ref mut w) => w.watch(path, RecursiveMode::Recursive), - WatcherImpl::Poll(ref mut w) => w.watch(path, RecursiveMode::Recursive), - } - } }