@@ -10,7 +10,7 @@ use rustc_codegen_spirv_types::CompileResult;
1010use crate :: { SpirvBuilder , SpirvBuilderError , leaf_deps} ;
1111
1212impl SpirvBuilder {
13- /// Watches the module for changes using [`notify`] , rebuilding it upon changes .
13+ /// Watches the module for changes, rebuilding it upon them .
1414 ///
1515 /// Calls `on_compilation_finishes` after each successful compilation.
1616 /// The second `Option<AcceptFirstCompile<T>>` param allows you to return some `T`
@@ -27,36 +27,18 @@ impl SpirvBuilder {
2727 . as_ref ( )
2828 . ok_or ( SpirvBuilderError :: MissingCratePath ) ?;
2929 if !matches ! ( self . print_metadata, crate :: MetadataPrintout :: None ) {
30- return Err ( SpirvBuilderError :: WatchWithPrintMetadata ) ;
30+ return Err ( SpirvBuilderWatchError :: WatchWithPrintMetadata . into ( ) ) ;
3131 }
3232
33- let metadata_result = crate :: invoke_rustc ( self ) ;
34- // Load the dependencies of the thing
35- let metadata_file = if let Ok ( path) = metadata_result {
36- path
37- } else {
38- // Fall back to watching from the crate root if the initial compilation fails
39- // This is likely to notice changes in the `target` dir, however, given that `cargo watch` doesn't seem to handle that,
40- let mut watcher = Watcher :: new ( ) ;
41- watcher
42- . watcher
43- . watch ( path_to_crate, RecursiveMode :: Recursive )
44- . expect ( "Could watch crate root" ) ;
45- loop {
46- watcher. recv ( ) ;
47- let metadata_file = crate :: invoke_rustc ( self ) ;
48- if let Ok ( f) = metadata_file {
49- break f;
50- }
51- }
52- } ;
33+ let metadata_file = metadata_file ( path_to_crate, self ) ?;
5334 let metadata = self . parse_metadata_file ( & metadata_file) ?;
35+
5436 let mut first_compile = None ;
5537 on_compilation_finishes ( metadata, Some ( AcceptFirstCompile ( & mut first_compile) ) ) ;
5638
5739 let builder = self . clone ( ) ;
40+ let mut watcher = Watcher :: new ( ) ?;
5841 let watch_thread = std:: thread:: spawn ( move || {
59- let mut watcher = Watcher :: new ( ) ;
6042 watcher. watch_leaf_deps ( & metadata_file) ;
6143
6244 loop {
@@ -65,7 +47,7 @@ impl SpirvBuilder {
6547 if let Ok ( file) = metadata_result {
6648 let metadata = builder
6749 . parse_metadata_file ( & file)
68- . expect ( "Metadata file is correct " ) ;
50+ . expect ( "metadata file should be valid " ) ;
6951 watcher. watch_leaf_deps ( & metadata_file) ;
7052 on_compilation_finishes ( metadata, None ) ;
7153 }
@@ -79,6 +61,52 @@ impl SpirvBuilder {
7961 }
8062}
8163
64+ fn notify_channel ( ) -> Result < ( RecommendedWatcher , Receiver < ( ) > ) , SpirvBuilderWatchError > {
65+ let ( tx, rx) = sync_channel ( 0 ) ;
66+ let event_handler = move |result : notify:: Result < Event > | match result {
67+ Ok ( event) => match event. kind {
68+ notify:: EventKind :: Any
69+ | notify:: EventKind :: Create ( _)
70+ | notify:: EventKind :: Modify ( _)
71+ | notify:: EventKind :: Remove ( _)
72+ | notify:: EventKind :: Other => {
73+ if let Err ( err) = tx. try_send ( ( ) ) {
74+ log:: error!( "send error: {err:?}" ) ;
75+ }
76+ }
77+ notify:: EventKind :: Access ( _) => { }
78+ } ,
79+ Err ( err) => log:: error!( "notify error: {err:?}" ) ,
80+ } ;
81+ let watcher = notify:: recommended_watcher ( event_handler) ?;
82+ Ok ( ( watcher, rx) )
83+ }
84+
85+ fn metadata_file < P > (
86+ crate_path : P ,
87+ builder : & SpirvBuilder ,
88+ ) -> Result < PathBuf , SpirvBuilderWatchError >
89+ where
90+ P : AsRef < Path > ,
91+ {
92+ match crate :: invoke_rustc ( builder) {
93+ Ok ( path) => return Ok ( path) ,
94+ Err ( err) => log:: error!( "{err}" ) ,
95+ }
96+
97+ // Fall back to watching from the crate root if the initial compilation fails
98+ // This is likely to notice changes in the `target` dir, however, given that `cargo watch` doesn't seem to handle that,
99+ let ( mut watcher, rx) = notify_channel ( ) ?;
100+ watcher. watch ( crate_path. as_ref ( ) , RecursiveMode :: Recursive ) ?;
101+ loop {
102+ rx. recv ( ) . expect ( "watcher should be alive" ) ;
103+ match crate :: invoke_rustc ( builder) {
104+ Ok ( path) => break Ok ( path) ,
105+ Err ( err) => log:: error!( "{err}" ) ,
106+ }
107+ }
108+ }
109+
82110pub struct AcceptFirstCompile < ' a , T > ( & ' a mut Option < T > ) ;
83111
84112impl < ' a , T > AcceptFirstCompile < ' a , T > {
@@ -111,28 +139,13 @@ struct Watcher {
111139}
112140
113141impl Watcher {
114- fn new ( ) -> Self {
115- let ( tx, rx) = sync_channel ( 0 ) ;
116- let watcher =
117- notify:: recommended_watcher ( move |event : notify:: Result < Event > | match event {
118- Ok ( e) => match e. kind {
119- notify:: EventKind :: Access ( _) => ( ) ,
120- notify:: EventKind :: Any
121- | notify:: EventKind :: Create ( _)
122- | notify:: EventKind :: Modify ( _)
123- | notify:: EventKind :: Remove ( _)
124- | notify:: EventKind :: Other => {
125- let _ = tx. try_send ( ( ) ) ;
126- }
127- } ,
128- Err ( e) => println ! ( "notify error: {e:?}" ) ,
129- } )
130- . expect ( "Could create watcher" ) ;
131- Self {
142+ fn new ( ) -> Result < Self , SpirvBuilderWatchError > {
143+ let ( watcher, rx) = notify_channel ( ) ?;
144+ Ok ( Self {
132145 watcher,
133146 rx,
134147 watched_paths : HashSet :: new ( ) ,
135- }
148+ } )
136149 }
137150
138151 fn watch_leaf_deps ( & mut self , metadata_file : & Path ) {
@@ -141,13 +154,21 @@ impl Watcher {
141154 if self . watched_paths . insert ( path. to_owned ( ) ) {
142155 self . watcher
143156 . watch ( it. to_path ( ) . unwrap ( ) , RecursiveMode :: NonRecursive )
144- . expect ( "Cargo dependencies are valid files " ) ;
157+ . expect ( "files of cargo dependencies should be valid " ) ;
145158 }
146159 } )
147- . expect ( "Could read dependencies file" ) ;
160+ . expect ( "should be able to read dependencies file" ) ;
148161 }
149162
150163 fn recv ( & self ) {
151- self . rx . recv ( ) . expect ( "Watcher still alive" ) ;
164+ self . rx . recv ( ) . expect ( "watcher should be alive" ) ;
152165 }
153166}
167+
168+ #[ derive( Debug , thiserror:: Error ) ]
169+ pub enum SpirvBuilderWatchError {
170+ #[ error( "watching within build scripts will prevent build completion" ) ]
171+ WatchWithPrintMetadata ,
172+ #[ error( "could not notify for changes: {0}" ) ]
173+ NotifyFailed ( #[ from] notify:: Error ) ,
174+ }
0 commit comments