diff options
author | Bernardo <[email protected]> | 2019-01-18 23:53:06 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-26 08:46:27 +0000 |
commit | f181e36a44d1998d3239f09365b16bfea50288a4 (patch) | |
tree | b93c2aca51c5498e9acab866d0fac04a4ef7c5d5 /crates | |
parent | e69b620f0d1e90afcc14dc7cf07ed0b828d8ec96 (diff) |
handle recursive watching ourselves
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_vfs/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_vfs/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_vfs/src/watcher.rs | 57 |
3 files changed, 46 insertions, 16 deletions
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" | |||
12 | log = "0.4.6" | 12 | log = "0.4.6" |
13 | # until https://github.com/passcod/notify/issues/169 is fixed | 13 | # until https://github.com/passcod/notify/issues/169 is fixed |
14 | notify = { git = "https://github.com/vemoo/notify/", branch = "v4-legacy" } | 14 | notify = { git = "https://github.com/vemoo/notify/", branch = "v4-legacy" } |
15 | ignore = "0.4" | ||
15 | drop_bomb = "0.1.0" | 16 | drop_bomb = "0.1.0" |
16 | 17 | ||
17 | thread_worker = { path = "../thread_worker" } | 18 | 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 { | |||
141 | }; | 141 | }; |
142 | res.worker.inp.send(task).unwrap(); | 142 | res.worker.inp.send(task).unwrap(); |
143 | if let Some(ref mut watcher) = res.watcher { | 143 | if let Some(ref mut watcher) = res.watcher { |
144 | if let Err(e) = watcher.watch(path) { | 144 | watcher.watch(path); |
145 | log::warn!("could not watch \"{}\": {}", path.display(), e); | ||
146 | } | ||
147 | } | 145 | } |
148 | } | 146 | } |
149 | let roots = res.roots.iter().map(|(id, _)| id).collect(); | 147 | 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 @@ | |||
1 | use crate::io; | ||
2 | use crossbeam_channel::Sender; | ||
3 | use drop_bomb::DropBomb; | ||
4 | use ignore; | ||
5 | use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; | ||
1 | use std::{ | 6 | use std::{ |
2 | path::{Path, PathBuf}, | 7 | path::{Path, PathBuf}, |
3 | sync::mpsc, | 8 | sync::{mpsc, Arc, Mutex}, |
4 | thread, | 9 | thread, |
5 | time::Duration, | 10 | time::Duration, |
6 | }; | 11 | }; |
7 | 12 | ||
8 | use crate::io; | ||
9 | use crossbeam_channel::Sender; | ||
10 | use drop_bomb::DropBomb; | ||
11 | use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher as NotifyWatcher}; | ||
12 | |||
13 | pub struct Watcher { | 13 | pub struct Watcher { |
14 | watcher: RecommendedWatcher, | 14 | watcher: Arc<Mutex<RecommendedWatcher>>, |
15 | thread: thread::JoinHandle<()>, | 15 | thread: thread::JoinHandle<()>, |
16 | bomb: DropBomb, | 16 | bomb: DropBomb, |
17 | } | 17 | } |
@@ -24,9 +24,10 @@ pub enum WatcherChange { | |||
24 | Rescan, | 24 | Rescan, |
25 | } | 25 | } |
26 | 26 | ||
27 | fn send_change_events( | 27 | fn handle_change_event( |
28 | ev: DebouncedEvent, | 28 | ev: DebouncedEvent, |
29 | sender: &Sender<io::Task>, | 29 | sender: &Sender<io::Task>, |
30 | watcher: &Arc<Mutex<RecommendedWatcher>>, | ||
30 | ) -> Result<(), Box<std::error::Error>> { | 31 | ) -> Result<(), Box<std::error::Error>> { |
31 | match ev { | 32 | match ev { |
32 | DebouncedEvent::NoticeWrite(_) | 33 | DebouncedEvent::NoticeWrite(_) |
@@ -38,6 +39,9 @@ fn send_change_events( | |||
38 | sender.send(io::Task::HandleChange(WatcherChange::Rescan))?; | 39 | sender.send(io::Task::HandleChange(WatcherChange::Rescan))?; |
39 | } | 40 | } |
40 | DebouncedEvent::Create(path) => { | 41 | DebouncedEvent::Create(path) => { |
42 | if path.is_dir() { | ||
43 | watch_recursive(watcher, &path); | ||
44 | } | ||
41 | sender.send(io::Task::HandleChange(WatcherChange::Create(path)))?; | 45 | sender.send(io::Task::HandleChange(WatcherChange::Create(path)))?; |
42 | } | 46 | } |
43 | DebouncedEvent::Write(path) => { | 47 | DebouncedEvent::Write(path) => { |
@@ -58,17 +62,45 @@ fn send_change_events( | |||
58 | Ok(()) | 62 | Ok(()) |
59 | } | 63 | } |
60 | 64 | ||
65 | fn watch_one(watcher: &mut RecommendedWatcher, path: &Path) { | ||
66 | match watcher.watch(path, RecursiveMode::NonRecursive) { | ||
67 | Ok(()) => log::debug!("watching \"{}\"", path.display()), | ||
68 | Err(e) => log::warn!("could not watch \"{}\": {}", path.display(), e), | ||
69 | } | ||
70 | } | ||
71 | |||
72 | fn watch_recursive(watcher: &Arc<Mutex<RecommendedWatcher>>, path: &Path) { | ||
73 | log::debug!("watch_recursive \"{}\"", path.display()); | ||
74 | let mut w = watcher.lock().unwrap(); | ||
75 | // TODO it seems path itself isn't checked against ignores | ||
76 | // check if path should be ignored before walking it | ||
77 | for res in ignore::Walk::new(path) { | ||
78 | match res { | ||
79 | Ok(entry) => { | ||
80 | if entry.path().is_dir() { | ||
81 | watch_one(&mut w, entry.path()); | ||
82 | } | ||
83 | } | ||
84 | Err(e) => log::warn!("watcher error: {}", e), | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
61 | impl Watcher { | 89 | impl Watcher { |
62 | pub(crate) fn start( | 90 | pub(crate) fn start( |
63 | output_sender: Sender<io::Task>, | 91 | output_sender: Sender<io::Task>, |
64 | ) -> Result<Watcher, Box<std::error::Error>> { | 92 | ) -> Result<Watcher, Box<std::error::Error>> { |
65 | let (input_sender, input_receiver) = mpsc::channel(); | 93 | let (input_sender, input_receiver) = mpsc::channel(); |
66 | let watcher = notify::watcher(input_sender, Duration::from_millis(250))?; | 94 | let watcher = Arc::new(Mutex::new(notify::watcher( |
95 | input_sender, | ||
96 | Duration::from_millis(250), | ||
97 | )?)); | ||
98 | let w = watcher.clone(); | ||
67 | let thread = thread::spawn(move || { | 99 | let thread = thread::spawn(move || { |
68 | input_receiver | 100 | input_receiver |
69 | .into_iter() | 101 | .into_iter() |
70 | // forward relevant events only | 102 | // forward relevant events only |
71 | .try_for_each(|change| send_change_events(change, &output_sender)) | 103 | .try_for_each(|change| handle_change_event(change, &output_sender, &w)) |
72 | .unwrap() | 104 | .unwrap() |
73 | }); | 105 | }); |
74 | Ok(Watcher { | 106 | Ok(Watcher { |
@@ -78,9 +110,8 @@ impl Watcher { | |||
78 | }) | 110 | }) |
79 | } | 111 | } |
80 | 112 | ||
81 | pub fn watch(&mut self, root: impl AsRef<Path>) -> Result<(), Box<std::error::Error>> { | 113 | pub fn watch(&mut self, root: impl AsRef<Path>) { |
82 | self.watcher.watch(root, RecursiveMode::Recursive)?; | 114 | watch_recursive(&self.watcher, root.as_ref()); |
83 | Ok(()) | ||
84 | } | 115 | } |
85 | 116 | ||
86 | pub fn shutdown(mut self) -> thread::Result<()> { | 117 | pub fn shutdown(mut self) -> thread::Result<()> { |