handle recursive watching ourselves

This commit is contained in:
Bernardo 2019-01-19 00:53:06 +01:00 committed by Aleksey Kladov
parent e69b620f0d
commit f181e36a44
4 changed files with 78 additions and 16 deletions

32
Cargo.lock generated
View file

@ -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"

View file

@ -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" }

View file

@ -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();

View file

@ -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<Mutex<RecommendedWatcher>>,
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<io::Task>,
watcher: &Arc<Mutex<RecommendedWatcher>>,
) -> Result<(), Box<std::error::Error>> {
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<Mutex<RecommendedWatcher>>, 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<io::Task>,
) -> Result<Watcher, Box<std::error::Error>> {
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<Path>) -> Result<(), Box<std::error::Error>> {
self.watcher.watch(root, RecursiveMode::Recursive)?;
Ok(())
pub fn watch(&mut self, root: impl AsRef<Path>) {
watch_recursive(&self.watcher, root.as_ref());
}
pub fn shutdown(mut self) -> thread::Result<()> {