|
1 |
| -use std::{collections::HashSet, sync::mpsc::sync_channel}; |
2 |
| - |
3 |
| -use notify::{Event, RecursiveMode, Watcher}; |
4 |
| -use rustc_codegen_spirv_types::CompileResult; |
5 |
| - |
6 | 1 | use crate::{SpirvBuilder, SpirvBuilderError, leaf_deps};
|
| 2 | +use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher as _}; |
| 3 | +use rustc_codegen_spirv_types::CompileResult; |
| 4 | +use std::path::{Path, PathBuf}; |
| 5 | +use std::sync::mpsc::Receiver; |
| 6 | +use std::{collections::HashSet, sync::mpsc::sync_channel}; |
7 | 7 |
|
8 | 8 | impl SpirvBuilder {
|
9 | 9 | /// Watches the module for changes using [`notify`](https://crates.io/crates/notify),
|
10 |
| - /// and rebuild it upon changes |
11 |
| - /// |
12 |
| - /// Returns the result of the first successful compilation, then calls |
13 |
| - /// `on_compilation_finishes` for each subsequent compilation. |
| 10 | + /// and rebuild it upon changes. Calls `on_compilation_finishes` after each |
| 11 | + /// successful compilation. |
14 | 12 | pub fn watch(
|
15 |
| - self, |
| 13 | + &self, |
16 | 14 | mut on_compilation_finishes: impl FnMut(CompileResult) + Send + 'static,
|
17 |
| - ) -> Result<CompileResult, SpirvBuilderError> { |
| 15 | + ) -> Result<(), SpirvBuilderError> { |
18 | 16 | let path_to_crate = self
|
19 | 17 | .path_to_crate
|
20 | 18 | .as_ref()
|
21 | 19 | .ok_or(SpirvBuilderError::MissingCratePath)?;
|
22 | 20 | if !matches!(self.print_metadata, crate::MetadataPrintout::None) {
|
23 | 21 | return Err(SpirvBuilderError::WatchWithPrintMetadata);
|
24 | 22 | }
|
25 |
| - let metadata_result = crate::invoke_rustc(&self); |
| 23 | + |
| 24 | + let metadata_result = crate::invoke_rustc(self); |
26 | 25 | // Load the dependencies of the thing
|
27 | 26 | let metadata_file = if let Ok(path) = metadata_result {
|
28 | 27 | path
|
29 | 28 | } else {
|
30 |
| - let (tx, rx) = sync_channel(0); |
31 | 29 | // Fall back to watching from the crate root if the initial compilation fails
|
32 |
| - let mut watcher = |
33 |
| - notify::recommended_watcher(move |event: notify::Result<Event>| match event { |
34 |
| - Ok(e) => match e.kind { |
35 |
| - notify::EventKind::Access(_) => (), |
36 |
| - notify::EventKind::Any |
37 |
| - | notify::EventKind::Create(_) |
38 |
| - | notify::EventKind::Modify(_) |
39 |
| - | notify::EventKind::Remove(_) |
40 |
| - | notify::EventKind::Other => { |
41 |
| - let _ = tx.try_send(()); |
42 |
| - } |
43 |
| - }, |
44 |
| - Err(e) => println!("notify error: {e:?}"), |
45 |
| - }) |
46 |
| - .expect("Could create watcher"); |
47 | 30 | // This is likely to notice changes in the `target` dir, however, given that `cargo watch` doesn't seem to handle that,
|
| 31 | + let mut watcher = Watcher::new(); |
48 | 32 | watcher
|
| 33 | + .watcher |
49 | 34 | .watch(path_to_crate, RecursiveMode::Recursive)
|
50 | 35 | .expect("Could watch crate root");
|
51 | 36 | loop {
|
52 |
| - rx.recv().expect("Watcher still alive"); |
53 |
| - let metadata_file = crate::invoke_rustc(&self); |
| 37 | + watcher.recv(); |
| 38 | + let metadata_file = crate::invoke_rustc(self); |
54 | 39 | if let Ok(f) = metadata_file {
|
55 | 40 | break f;
|
56 | 41 | }
|
57 | 42 | }
|
58 | 43 | };
|
59 | 44 | let metadata = self.parse_metadata_file(&metadata_file)?;
|
60 |
| - let first_result = metadata; |
| 45 | + on_compilation_finishes(metadata); |
61 | 46 |
|
| 47 | + let builder = self.clone(); |
62 | 48 | let thread = std::thread::spawn(move || {
|
63 |
| - let mut watched_paths = HashSet::new(); |
64 |
| - let (tx, rx) = sync_channel(0); |
65 |
| - let mut watcher = |
66 |
| - notify::recommended_watcher(move |event: notify::Result<Event>| match event { |
67 |
| - Ok(e) => match e.kind { |
68 |
| - notify::EventKind::Access(_) => (), |
69 |
| - notify::EventKind::Any |
70 |
| - | notify::EventKind::Create(_) |
71 |
| - | notify::EventKind::Modify(_) |
72 |
| - | notify::EventKind::Remove(_) |
73 |
| - | notify::EventKind::Other => { |
74 |
| - let _ = tx.try_send(()); |
75 |
| - } |
76 |
| - }, |
77 |
| - Err(e) => println!("notify error: {e:?}"), |
78 |
| - }) |
79 |
| - .expect("Could create watcher"); |
80 |
| - leaf_deps(&metadata_file, |it| { |
81 |
| - let path = it.to_path().unwrap(); |
82 |
| - if watched_paths.insert(path.to_owned()) { |
83 |
| - watcher |
84 |
| - .watch(it.to_path().unwrap(), RecursiveMode::NonRecursive) |
85 |
| - .expect("Cargo dependencies are valid files"); |
86 |
| - } |
87 |
| - }) |
88 |
| - .expect("Could read dependencies file"); |
| 49 | + let mut watcher = Watcher::new(); |
| 50 | + watcher.watch_leaf_deps(&metadata_file); |
| 51 | + |
89 | 52 | loop {
|
90 |
| - rx.recv().expect("Watcher still alive"); |
91 |
| - let metadata_result = crate::invoke_rustc(&self); |
| 53 | + watcher.recv(); |
| 54 | + let metadata_result = crate::invoke_rustc(&builder); |
92 | 55 | if let Ok(file) = metadata_result {
|
93 |
| - let metadata = self |
| 56 | + let metadata = builder |
94 | 57 | .parse_metadata_file(&file)
|
95 | 58 | .expect("Metadata file is correct");
|
96 |
| - |
97 |
| - leaf_deps(&file, |it| { |
98 |
| - let path = it.to_path().unwrap(); |
99 |
| - if watched_paths.insert(path.to_owned()) { |
100 |
| - watcher |
101 |
| - .watch(it.to_path().unwrap(), RecursiveMode::NonRecursive) |
102 |
| - .expect("Cargo dependencies are valid files"); |
103 |
| - } |
104 |
| - }) |
105 |
| - .expect("Could read dependencies file"); |
106 |
| - |
| 59 | + watcher.watch_leaf_deps(&metadata_file); |
107 | 60 | on_compilation_finishes(metadata);
|
108 | 61 | }
|
109 | 62 | }
|
110 | 63 | });
|
111 |
| - std::mem::drop(thread); |
112 |
| - Ok(first_result) |
| 64 | + drop(thread); |
| 65 | + Ok(()) |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +struct Watcher { |
| 70 | + watcher: RecommendedWatcher, |
| 71 | + rx: Receiver<()>, |
| 72 | + watched_paths: HashSet<PathBuf>, |
| 73 | +} |
| 74 | + |
| 75 | +impl Watcher { |
| 76 | + fn new() -> Self { |
| 77 | + let (tx, rx) = sync_channel(0); |
| 78 | + let watcher = |
| 79 | + notify::recommended_watcher(move |event: notify::Result<Event>| match event { |
| 80 | + Ok(e) => match e.kind { |
| 81 | + notify::EventKind::Access(_) => (), |
| 82 | + notify::EventKind::Any |
| 83 | + | notify::EventKind::Create(_) |
| 84 | + | notify::EventKind::Modify(_) |
| 85 | + | notify::EventKind::Remove(_) |
| 86 | + | notify::EventKind::Other => { |
| 87 | + let _ = tx.try_send(()); |
| 88 | + } |
| 89 | + }, |
| 90 | + Err(e) => println!("notify error: {e:?}"), |
| 91 | + }) |
| 92 | + .expect("Could create watcher"); |
| 93 | + Self { |
| 94 | + watcher, |
| 95 | + rx, |
| 96 | + watched_paths: HashSet::new(), |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + fn watch_leaf_deps(&mut self, metadata_file: &Path) { |
| 101 | + leaf_deps(metadata_file, |it| { |
| 102 | + let path = it.to_path().unwrap(); |
| 103 | + if self.watched_paths.insert(path.to_owned()) { |
| 104 | + self.watcher |
| 105 | + .watch(it.to_path().unwrap(), RecursiveMode::NonRecursive) |
| 106 | + .expect("Cargo dependencies are valid files"); |
| 107 | + } |
| 108 | + }) |
| 109 | + .expect("Could read dependencies file"); |
| 110 | + } |
| 111 | + |
| 112 | + fn recv(&self) { |
| 113 | + self.rx.recv().expect("Watcher still alive"); |
113 | 114 | }
|
114 | 115 | }
|
0 commit comments