Skip to content

Commit 28e44e5

Browse files
committed
use Roots in watcher
1 parent b770221 commit 28e44e5

File tree

4 files changed

+274
-330
lines changed

4 files changed

+274
-330
lines changed

crates/ra_vfs/src/io.rs

Lines changed: 51 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,72 @@
1-
use std::{
2-
fmt, fs,
3-
path::{Path, PathBuf},
4-
sync::Arc,
5-
thread,
6-
};
1+
use std::{fs, sync::Arc, thread};
72

83
use crossbeam_channel::{Receiver, Sender};
9-
use parking_lot::Mutex;
104
use relative_path::RelativePathBuf;
115
use thread_worker::WorkerHandle;
126
use walkdir::WalkDir;
137

148
mod watcher;
159
use watcher::Watcher;
16-
pub use watcher::WatcherChange;
1710

18-
use crate::{RootFilter, VfsRoot};
11+
use crate::{RootFilter, Roots, VfsRoot};
1912

2013
pub(crate) enum Task {
2114
AddRoot {
2215
root: VfsRoot,
23-
path: PathBuf,
24-
root_filter: Arc<RootFilter>,
25-
nested_roots: Vec<PathBuf>,
26-
},
27-
/// this variant should only be created by the watcher
28-
HandleChange(WatcherChange),
29-
LoadChange(WatcherChange),
30-
Watch {
31-
dir: PathBuf,
32-
root_filter: Arc<RootFilter>,
16+
filter: Arc<RootFilter>,
3317
},
3418
}
3519

3620
#[derive(Debug)]
37-
pub struct AddRootResult {
38-
pub(crate) root: VfsRoot,
39-
pub(crate) files: Vec<(RelativePathBuf, String)>,
40-
}
41-
42-
#[derive(Debug)]
43-
pub enum WatcherChangeData {
44-
Create { path: PathBuf, text: String },
45-
Write { path: PathBuf, text: String },
46-
Remove { path: PathBuf },
47-
}
48-
4921
pub enum TaskResult {
50-
AddRoot(AddRootResult),
51-
HandleChange(WatcherChange),
52-
LoadChange(WatcherChangeData),
53-
}
54-
55-
impl fmt::Debug for TaskResult {
56-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57-
match self {
58-
TaskResult::AddRoot(..) => f.write_str("TaskResult::AddRoot(..)"),
59-
TaskResult::HandleChange(c) => write!(f, "TaskResult::HandleChange({:?})", c),
60-
TaskResult::LoadChange(c) => write!(f, "TaskResult::LoadChange({:?})", c),
61-
}
62-
}
22+
BulkLoadRoot {
23+
root: VfsRoot,
24+
files: Vec<(RelativePathBuf, String)>,
25+
},
26+
AddSingleFile {
27+
root: VfsRoot,
28+
path: RelativePathBuf,
29+
text: String,
30+
},
31+
ChangeSingleFile {
32+
root: VfsRoot,
33+
path: RelativePathBuf,
34+
text: String,
35+
},
36+
RemoveSingleFile {
37+
root: VfsRoot,
38+
path: RelativePathBuf,
39+
},
6340
}
6441

6542
pub(crate) struct Worker {
6643
worker: thread_worker::Worker<Task, TaskResult>,
6744
worker_handle: WorkerHandle,
68-
watcher: Arc<Mutex<Option<Watcher>>>,
6945
}
7046

7147
impl Worker {
72-
pub(crate) fn start() -> Worker {
73-
let watcher = Arc::new(Mutex::new(None));
74-
let watcher_clone = watcher.clone();
48+
pub(crate) fn start(roots: Arc<Roots>) -> Worker {
7549
let (worker, worker_handle) =
7650
thread_worker::spawn("vfs", 128, move |input_receiver, output_sender| {
77-
input_receiver
51+
let mut watcher = match Watcher::start(roots, output_sender.clone()) {
52+
Ok(w) => Some(w),
53+
Err(e) => {
54+
log::error!("could not start watcher: {}", e);
55+
None
56+
}
57+
};
58+
let res = input_receiver
7859
.into_iter()
79-
.filter_map(|t| handle_task(t, &watcher_clone))
80-
.try_for_each(|it| output_sender.send(it))
81-
.unwrap()
60+
.filter_map(|t| handle_task(t, &mut watcher))
61+
.try_for_each(|it| output_sender.send(it));
62+
if let Some(watcher) = watcher {
63+
let _ = watcher.shutdown();
64+
}
65+
res.unwrap()
8266
});
83-
match Watcher::start(worker.inp.clone()) {
84-
Ok(w) => {
85-
watcher.lock().replace(w);
86-
}
87-
Err(e) => log::error!("could not start watcher: {}", e),
88-
};
8967
Worker {
9068
worker,
9169
worker_handle,
92-
watcher,
9370
}
9471
}
9572

@@ -102,72 +79,31 @@ impl Worker {
10279
}
10380

10481
pub(crate) fn shutdown(self) -> thread::Result<()> {
105-
if let Some(watcher) = self.watcher.lock().take() {
106-
let _ = watcher.shutdown();
107-
}
10882
let _ = self.worker.shutdown();
10983
self.worker_handle.shutdown()
11084
}
11185
}
11286

113-
fn watch(
114-
watcher: &Arc<Mutex<Option<Watcher>>>,
115-
dir: &Path,
116-
filter_entry: &RootFilter,
117-
emit_for_existing: bool,
118-
) {
119-
if let Some(watcher) = watcher.lock().as_mut() {
120-
watcher.watch_recursive(dir, filter_entry, emit_for_existing)
121-
}
122-
}
123-
124-
fn handle_task(task: Task, watcher: &Arc<Mutex<Option<Watcher>>>) -> Option<TaskResult> {
87+
fn handle_task(task: Task, watcher: &mut Option<Watcher>) -> Option<TaskResult> {
12588
match task {
126-
Task::AddRoot {
127-
root,
128-
path,
129-
root_filter,
130-
nested_roots,
131-
} => {
132-
watch(watcher, &path, root_filter.as_ref(), false);
133-
log::debug!("loading {} ...", path.as_path().display());
134-
let files = load_root(
135-
path.as_path(),
136-
root_filter.as_ref(),
137-
nested_roots.as_slice(),
138-
);
139-
log::debug!("... loaded {}", path.as_path().display());
140-
Some(TaskResult::AddRoot(AddRootResult { root, files }))
141-
}
142-
Task::HandleChange(change) => {
143-
// forward as is because Vfs has to decide if we should load it
144-
Some(TaskResult::HandleChange(change))
145-
}
146-
Task::LoadChange(change) => {
147-
log::debug!("loading {:?} ...", change);
148-
load_change(change).map(TaskResult::LoadChange)
149-
}
150-
Task::Watch { dir, root_filter } => {
151-
watch(watcher, &dir, root_filter.as_ref(), true);
152-
None
89+
Task::AddRoot { root, filter } => {
90+
if let Some(watcher) = watcher {
91+
watcher.watch_root(&filter)
92+
}
93+
log::debug!("loading {} ...", filter.root.as_path().display());
94+
let files = load_root(filter.as_ref());
95+
log::debug!("... loaded {}", filter.root.as_path().display());
96+
Some(TaskResult::BulkLoadRoot { root, files })
15397
}
15498
}
15599
}
156100

157-
fn load_root(
158-
root: &Path,
159-
root_filter: &RootFilter,
160-
nested_roots: &[PathBuf],
161-
) -> Vec<(RelativePathBuf, String)> {
101+
fn load_root(filter: &RootFilter) -> Vec<(RelativePathBuf, String)> {
162102
let mut res = Vec::new();
163-
for entry in WalkDir::new(root).into_iter().filter_entry(|entry| {
164-
if entry.file_type().is_dir() && nested_roots.iter().any(|it| it == entry.path()) {
165-
// do not load files of a nested root
166-
false
167-
} else {
168-
root_filter.can_contain(entry.path()).is_some()
169-
}
170-
}) {
103+
for entry in WalkDir::new(&filter.root)
104+
.into_iter()
105+
.filter_entry(filter.entry_filter())
106+
{
171107
let entry = match entry {
172108
Ok(entry) => entry,
173109
Err(e) => {
@@ -186,42 +122,8 @@ fn load_root(
186122
continue;
187123
}
188124
};
189-
let path = RelativePathBuf::from_path(path.strip_prefix(root).unwrap()).unwrap();
125+
let path = RelativePathBuf::from_path(path.strip_prefix(&filter.root).unwrap()).unwrap();
190126
res.push((path.to_owned(), text))
191127
}
192128
res
193129
}
194-
195-
fn load_change(change: WatcherChange) -> Option<WatcherChangeData> {
196-
let data = match change {
197-
WatcherChange::Create(path) => {
198-
if path.is_dir() {
199-
return None;
200-
}
201-
let text = match fs::read_to_string(&path) {
202-
Ok(text) => text,
203-
Err(e) => {
204-
log::warn!("watcher error \"{}\": {}", path.display(), e);
205-
return None;
206-
}
207-
};
208-
WatcherChangeData::Create { path, text }
209-
}
210-
WatcherChange::Write(path) => {
211-
let text = match fs::read_to_string(&path) {
212-
Ok(text) => text,
213-
Err(e) => {
214-
log::warn!("watcher error \"{}\": {}", path.display(), e);
215-
return None;
216-
}
217-
};
218-
WatcherChangeData::Write { path, text }
219-
}
220-
WatcherChange::Remove(path) => WatcherChangeData::Remove { path },
221-
WatcherChange::Rescan => {
222-
// this should be handled by Vfs::handle_task
223-
return None;
224-
}
225-
};
226-
Some(data)
227-
}

0 commit comments

Comments
 (0)