From f181e36a44d1998d3239f09365b16bfea50288a4 Mon Sep 17 00:00:00 2001 From: Bernardo Date: Sat, 19 Jan 2019 00:53:06 +0100 Subject: handle recursive watching ourselves --- Cargo.lock | 32 +++++++++++++++++++++++++ crates/ra_vfs/Cargo.toml | 1 + crates/ra_vfs/src/lib.rs | 4 +--- crates/ra_vfs/src/watcher.rs | 57 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d51146956..2d18122d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,6 +446,18 @@ name = "glob" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "globset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "heck" version = "0.3.1" @@ -469,6 +481,23 @@ dependencies = [ "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ignore" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "im" version = "12.3.0" @@ -1010,6 +1039,7 @@ dependencies = [ "crossbeam-channel 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "flexi_logger 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.6 (git+https://github.com/vemoo/notify/?branch=v4-legacy)", "ra_arena 0.1.0", @@ -1868,9 +1898,11 @@ dependencies = [ "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" +"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum humansize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ad03ca67dc12474ecd91fdb94d758cbd20cb4e7a78ebe831df26a9b7511e1162" "checksum im 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0627d417829c1d763d602687634869f254fc79f7e22dea6c824dab993db857e4" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" diff --git a/crates/ra_vfs/Cargo.toml b/crates/ra_vfs/Cargo.toml index 1a21557bf..58196555c 100644 --- a/crates/ra_vfs/Cargo.toml +++ b/crates/ra_vfs/Cargo.toml @@ -12,6 +12,7 @@ crossbeam-channel = "0.3.5" log = "0.4.6" # until https://github.com/passcod/notify/issues/169 is fixed notify = { git = "https://github.com/vemoo/notify/", branch = "v4-legacy" } +ignore = "0.4" drop_bomb = "0.1.0" thread_worker = { path = "../thread_worker" } diff --git a/crates/ra_vfs/src/lib.rs b/crates/ra_vfs/src/lib.rs index 48a46d210..ad40db340 100644 --- a/crates/ra_vfs/src/lib.rs +++ b/crates/ra_vfs/src/lib.rs @@ -141,9 +141,7 @@ impl Vfs { }; res.worker.inp.send(task).unwrap(); if let Some(ref mut watcher) = res.watcher { - if let Err(e) = watcher.watch(path) { - log::warn!("could not watch \"{}\": {}", path.display(), e); - } + watcher.watch(path); } } let roots = res.roots.iter().map(|(id, _)| id).collect(); diff --git a/crates/ra_vfs/src/watcher.rs b/crates/ra_vfs/src/watcher.rs index dfbbcbfe6..013611e1a 100644 --- a/crates/ra_vfs/src/watcher.rs +++ b/crates/ra_vfs/src/watcher.rs @@ -1,17 +1,17 @@ +use crate::io; +use crossbeam_channel::Sender; +use drop_bomb::DropBomb; +use ignore; +use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; use std::{ path::{Path, PathBuf}, - sync::mpsc, + sync::{mpsc, Arc, Mutex}, thread, time::Duration, }; -use crate::io; -use crossbeam_channel::Sender; -use drop_bomb::DropBomb; -use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; - pub struct Watcher { - watcher: RecommendedWatcher, + watcher: Arc>, thread: thread::JoinHandle<()>, bomb: DropBomb, } @@ -24,9 +24,10 @@ pub enum WatcherChange { Rescan, } -fn send_change_events( +fn handle_change_event( ev: DebouncedEvent, sender: &Sender, + watcher: &Arc>, ) -> Result<(), Box> { match ev { DebouncedEvent::NoticeWrite(_) @@ -38,6 +39,9 @@ fn send_change_events( sender.send(io::Task::HandleChange(WatcherChange::Rescan))?; } DebouncedEvent::Create(path) => { + if path.is_dir() { + watch_recursive(watcher, &path); + } sender.send(io::Task::HandleChange(WatcherChange::Create(path)))?; } DebouncedEvent::Write(path) => { @@ -58,17 +62,45 @@ fn send_change_events( Ok(()) } +fn watch_one(watcher: &mut RecommendedWatcher, path: &Path) { + match watcher.watch(path, RecursiveMode::NonRecursive) { + Ok(()) => log::debug!("watching \"{}\"", path.display()), + Err(e) => log::warn!("could not watch \"{}\": {}", path.display(), e), + } +} + +fn watch_recursive(watcher: &Arc>, path: &Path) { + log::debug!("watch_recursive \"{}\"", path.display()); + let mut w = watcher.lock().unwrap(); + // TODO it seems path itself isn't checked against ignores + // check if path should be ignored before walking it + for res in ignore::Walk::new(path) { + match res { + Ok(entry) => { + if entry.path().is_dir() { + watch_one(&mut w, entry.path()); + } + } + Err(e) => log::warn!("watcher error: {}", e), + } + } +} + impl Watcher { pub(crate) fn start( output_sender: Sender, ) -> Result> { let (input_sender, input_receiver) = mpsc::channel(); - let watcher = notify::watcher(input_sender, Duration::from_millis(250))?; + let watcher = Arc::new(Mutex::new(notify::watcher( + input_sender, + Duration::from_millis(250), + )?)); + let w = watcher.clone(); let thread = thread::spawn(move || { input_receiver .into_iter() // forward relevant events only - .try_for_each(|change| send_change_events(change, &output_sender)) + .try_for_each(|change| handle_change_event(change, &output_sender, &w)) .unwrap() }); Ok(Watcher { @@ -78,9 +110,8 @@ impl Watcher { }) } - pub fn watch(&mut self, root: impl AsRef) -> Result<(), Box> { - self.watcher.watch(root, RecursiveMode::Recursive)?; - Ok(()) + pub fn watch(&mut self, root: impl AsRef) { + watch_recursive(&self.watcher, root.as_ref()); } pub fn shutdown(mut self) -> thread::Result<()> { -- cgit v1.2.3