From dbc52e012e9178486b13649f192a7e2b819ac5c9 Mon Sep 17 00:00:00 2001 From: SpiralP Date: Sun, 3 Mar 2019 14:40:35 -0800 Subject: [PATCH] [run] Always canonicalize input paths (#113) A client may pass non-canonicalized paths into `watch`, and these are therefore not matched against the filters correctly. Thus, some events could call a Handler's `on_update` method even when an ignored file was changed. See repro: https://github.com/SpiralP/rust-cargo-watch-test This bug was introduced in aae5a216b0b7d381b7c8af2d032f0b959757efbf. --- src/cli.rs | 11 +++++------ src/run.rs | 17 +++++++++++++---- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index c6a3f7f..756bf82 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -2,7 +2,6 @@ use clap::{App, Arg, Error}; use error; use std::{ ffi::OsString, - fs::canonicalize, path::{PathBuf, MAIN_SEPARATOR}, process::Command, }; @@ -146,11 +145,11 @@ where }; let cmd: Vec = values_t!(args.values_of("command"), String)?; - let str_paths = values_t!(args.values_of("path"), String).unwrap_or(vec![".".into()]); - let mut paths = vec![]; - for path in str_paths { - paths.push(canonicalize(&path).map_err(|e| error::Error::Canonicalization(path, e))?); - } + let paths = values_t!(args.values_of("path"), String) + .unwrap_or(vec![".".into()]) + .iter() + .map(|string_path| string_path.into()) + .collect(); // Treat --kill as --signal SIGKILL (for compatibility with older syntax) let signal = if args.is_present("kill") { diff --git a/src/run.rs b/src/run.rs index 650f3c4..8324fb7 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,6 +1,6 @@ use cli::{clear_screen, Args}; use env_logger; -use error::Result; +use error::{Error, Result}; use gitignore; use log; use notification_filter::NotificationFilter; @@ -11,6 +11,7 @@ use process::{self, Process}; use signal::{self, Signal}; use std::{ collections::HashMap, + fs::canonicalize, io::Write, sync::{ mpsc::{channel, Receiver}, @@ -78,14 +79,22 @@ where init_logger(args.debug); let mut handler = H::new(args.clone())?; - let gitignore = gitignore::load(if args.no_vcs_ignore { &[] } else { &args.paths }); + let mut paths = vec![]; + for path in args.paths { + paths.push( + canonicalize(&path) + .map_err(|e| Error::Canonicalization(path.to_string_lossy().into_owned(), e))?, + ); + } + + let gitignore = gitignore::load(if args.no_vcs_ignore { &[] } else { &paths }); let filter = NotificationFilter::new(&args.filters, &args.ignores, gitignore)?; let (tx, rx) = channel(); let poll = args.poll.clone(); #[cfg(target_os = "linux")] let poll_interval = args.poll_interval.clone(); - let watcher = Watcher::new(tx.clone(), &args.paths, args.poll, args.poll_interval).or_else(|err| { + let watcher = Watcher::new(tx.clone(), &paths, args.poll, args.poll_interval).or_else(|err| { if poll { return Err(err); } @@ -102,7 +111,7 @@ where } if fallback { - return Watcher::new(tx, &args.paths, true, poll_interval); + return Watcher::new(tx, &paths, true, poll_interval); } }