diff options
Diffstat (limited to 'crates/server/src/vfs.rs')
-rw-r--r-- | crates/server/src/vfs.rs | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/crates/server/src/vfs.rs b/crates/server/src/vfs.rs new file mode 100644 index 000000000..a5c367494 --- /dev/null +++ b/crates/server/src/vfs.rs | |||
@@ -0,0 +1,79 @@ | |||
1 | use std::{ | ||
2 | path::PathBuf, | ||
3 | thread, | ||
4 | fs, | ||
5 | }; | ||
6 | |||
7 | use crossbeam_channel::{Sender, Receiver, bounded}; | ||
8 | use drop_bomb::DropBomb; | ||
9 | use walkdir::WalkDir; | ||
10 | |||
11 | use Result; | ||
12 | |||
13 | |||
14 | pub struct FileEvent { | ||
15 | pub path: PathBuf, | ||
16 | pub kind: FileEventKind, | ||
17 | } | ||
18 | |||
19 | pub enum FileEventKind { | ||
20 | Add(String), | ||
21 | #[allow(unused)] | ||
22 | Remove, | ||
23 | } | ||
24 | |||
25 | pub struct Watcher { | ||
26 | thread: thread::JoinHandle<()>, | ||
27 | bomb: DropBomb, | ||
28 | } | ||
29 | |||
30 | impl Watcher { | ||
31 | pub fn stop(mut self) -> Result<()> { | ||
32 | self.bomb.defuse(); | ||
33 | self.thread.join() | ||
34 | .map_err(|_| format_err!("file watcher died")) | ||
35 | } | ||
36 | } | ||
37 | |||
38 | pub fn watch(roots: Vec<PathBuf>) -> (Receiver<Vec<FileEvent>>, Watcher) { | ||
39 | let (sender, receiver) = bounded(16); | ||
40 | let thread = thread::spawn(move || run(roots, sender)); | ||
41 | (receiver, Watcher { | ||
42 | thread, | ||
43 | bomb: DropBomb::new("Watcher should be stopped explicitly"), | ||
44 | }) | ||
45 | } | ||
46 | |||
47 | fn run(roots: Vec<PathBuf>, sender: Sender<Vec<FileEvent>>) { | ||
48 | for root in roots { | ||
49 | let mut events = Vec::new(); | ||
50 | for entry in WalkDir::new(root.as_path()) { | ||
51 | let entry = match entry { | ||
52 | Ok(entry) => entry, | ||
53 | Err(e) => { | ||
54 | warn!("watcher error: {}", e); | ||
55 | continue; | ||
56 | } | ||
57 | }; | ||
58 | if !entry.file_type().is_file() { | ||
59 | continue; | ||
60 | } | ||
61 | let path = entry.path(); | ||
62 | if path.extension().and_then(|os| os.to_str()) != Some("rs") { | ||
63 | continue; | ||
64 | } | ||
65 | let text = match fs::read_to_string(path) { | ||
66 | Ok(text) => text, | ||
67 | Err(e) => { | ||
68 | warn!("watcher error: {}", e); | ||
69 | continue; | ||
70 | } | ||
71 | }; | ||
72 | events.push(FileEvent { | ||
73 | path: path.to_owned(), | ||
74 | kind: FileEventKind::Add(text), | ||
75 | }) | ||
76 | } | ||
77 | sender.send(events) | ||
78 | } | ||
79 | } | ||