44
55use std:: {
66 collections:: HashMap ,
7+ ffi:: OsStr ,
78 fs:: { File , FileType } ,
8- io:: { Read , Write } ,
9+ io:: { BufRead , Read , Write } ,
910 path:: { Path , PathBuf } ,
1011 process:: { Command , ExitStatus } ,
1112 str:: FromStr ,
@@ -20,6 +21,7 @@ use std::{
2021use anyhow:: Context ;
2122#[ cfg( target_os = "linux" ) ]
2223use heck:: ToKebabCase ;
24+ use ignore:: gitignore:: { Gitignore , GitignoreBuilder } ;
2325use log:: { debug, info} ;
2426use notify:: RecursiveMode ;
2527use notify_debouncer_mini:: new_debouncer;
@@ -255,6 +257,59 @@ impl Interface for Rust {
255257 }
256258}
257259
260+ struct IgnoreMatcher ( Vec < Gitignore > ) ;
261+
262+ impl IgnoreMatcher {
263+ fn is_ignore ( & self , path : & Path , is_dir : bool ) -> bool {
264+ for gitignore in & self . 0 {
265+ if gitignore. matched ( path, is_dir) . is_ignore ( ) {
266+ return true ;
267+ }
268+ }
269+ false
270+ }
271+ }
272+
273+ fn build_ignore_matcher ( dir : & Path ) -> IgnoreMatcher {
274+ let mut matchers = Vec :: new ( ) ;
275+
276+ // ignore crate doesn't expose an API to build `ignore::gitignore::GitIgnore`
277+ // with custom ignore file names so we have to walk the directory and collect
278+ // our custom ignore files and add it using `ignore::gitignore::GitIgnoreBuilder::add`
279+ for entry in ignore:: WalkBuilder :: new ( dir)
280+ . require_git ( false )
281+ . ignore ( false )
282+ . overrides (
283+ ignore:: overrides:: OverrideBuilder :: new ( dir)
284+ . add ( ".taurignore" )
285+ . unwrap ( )
286+ . build ( )
287+ . unwrap ( ) ,
288+ )
289+ . build ( )
290+ . flatten ( )
291+ {
292+ let path = entry. path ( ) ;
293+ if path. file_name ( ) == Some ( OsStr :: new ( ".taurignore" ) ) {
294+ let mut ignore_builder = GitignoreBuilder :: new ( path. parent ( ) . unwrap ( ) ) ;
295+
296+ ignore_builder. add ( path) ;
297+
298+ if let Ok ( ignore_file) = std:: env:: var ( "TAURI_DEV_WATCHER_IGNORE_FILE" ) {
299+ ignore_builder. add ( dir. join ( ignore_file) ) ;
300+ }
301+
302+ for line in crate :: dev:: TAURI_DEV_WATCHER_GITIGNORE . lines ( ) . flatten ( ) {
303+ let _ = ignore_builder. add_line ( None , & line) ;
304+ }
305+
306+ matchers. push ( ignore_builder. build ( ) . unwrap ( ) ) ;
307+ }
308+ }
309+
310+ IgnoreMatcher ( matchers)
311+ }
312+
258313fn lookup < F : FnMut ( FileType , PathBuf ) > ( dir : & Path , mut f : F ) {
259314 let mut default_gitignore = std:: env:: temp_dir ( ) ;
260315 default_gitignore. push ( ".tauri-dev" ) ;
@@ -365,27 +420,33 @@ impl Rust {
365420 . unwrap_or_else ( || vec ! [ tauri_path] )
366421 } ;
367422
423+ let watch_folders = watch_folders. iter ( ) . map ( Path :: new) . collect :: < Vec < _ > > ( ) ;
424+ let common_ancestor = common_path:: common_path_all ( watch_folders. clone ( ) ) . unwrap ( ) ;
425+ let ignore_matcher = build_ignore_matcher ( & common_ancestor) ;
426+
368427 let mut watcher = new_debouncer ( Duration :: from_secs ( 1 ) , None , move |r| {
369428 if let Ok ( events) = r {
370429 tx. send ( events) . unwrap ( )
371430 }
372431 } )
373432 . unwrap ( ) ;
374433 for path in watch_folders {
375- info ! ( "Watching {} for changes..." , path. display( ) ) ;
376- lookup ( & path, |file_type, p| {
377- if p != path {
378- debug ! ( "Watching {} for changes..." , p. display( ) ) ;
379- let _ = watcher. watcher ( ) . watch (
380- & p,
381- if file_type. is_dir ( ) {
382- RecursiveMode :: Recursive
383- } else {
384- RecursiveMode :: NonRecursive
385- } ,
386- ) ;
387- }
388- } ) ;
434+ if !ignore_matcher. is_ignore ( path, true ) {
435+ info ! ( "Watching {} for changes..." , path. display( ) ) ;
436+ lookup ( path, |file_type, p| {
437+ if p != path {
438+ debug ! ( "Watching {} for changes..." , p. display( ) ) ;
439+ let _ = watcher. watcher ( ) . watch (
440+ & p,
441+ if file_type. is_dir ( ) {
442+ RecursiveMode :: Recursive
443+ } else {
444+ RecursiveMode :: NonRecursive
445+ } ,
446+ ) ;
447+ }
448+ } ) ;
449+ }
389450 }
390451
391452 loop {
@@ -394,33 +455,35 @@ impl Rust {
394455 let on_exit = on_exit. clone ( ) ;
395456 let event_path = event. path ;
396457
397- if is_configuration_file ( & event_path) {
398- info ! ( "Tauri configuration changed. Rewriting manifest..." ) ;
399- let config = reload_config ( options. config . as_deref ( ) ) ?;
400- self . app_settings . manifest =
401- rewrite_manifest ( config. lock ( ) . unwrap ( ) . as_ref ( ) . unwrap ( ) ) ?;
402- } else {
403- info ! (
404- "File {} changed. Rebuilding application..." ,
405- event_path
406- . strip_prefix( & app_path)
407- . unwrap_or( & event_path)
408- . display( )
409- ) ;
410- // When tauri.conf.json is changed, rewrite_manifest will be called
411- // which will trigger the watcher again
412- // So the app should only be started when a file other than tauri.conf.json is changed
413- let mut p = process. lock ( ) . unwrap ( ) ;
414- p. kill ( ) . with_context ( || "failed to kill app process" ) ?;
415- // wait for the process to exit
416- loop {
417- if let Ok ( Some ( _) ) = p. try_wait ( ) {
418- break ;
458+ if !ignore_matcher. is_ignore ( & event_path, event_path. is_dir ( ) ) {
459+ if is_configuration_file ( & event_path) {
460+ info ! ( "Tauri configuration changed. Rewriting manifest..." ) ;
461+ let config = reload_config ( options. config . as_deref ( ) ) ?;
462+ self . app_settings . manifest =
463+ rewrite_manifest ( config. lock ( ) . unwrap ( ) . as_ref ( ) . unwrap ( ) ) ?;
464+ } else {
465+ info ! (
466+ "File {} changed. Rebuilding application..." ,
467+ event_path
468+ . strip_prefix( & app_path)
469+ . unwrap_or( & event_path)
470+ . display( )
471+ ) ;
472+ // When tauri.conf.json is changed, rewrite_manifest will be called
473+ // which will trigger the watcher again
474+ // So the app should only be started when a file other than tauri.conf.json is changed
475+ let mut p = process. lock ( ) . unwrap ( ) ;
476+ p. kill ( ) . with_context ( || "failed to kill app process" ) ?;
477+ // wait for the process to exit
478+ loop {
479+ if let Ok ( Some ( _) ) = p. try_wait ( ) {
480+ break ;
481+ }
419482 }
483+ * p = self . run_dev ( options. clone ( ) , move |status, reason| {
484+ on_exit ( status, reason)
485+ } ) ?;
420486 }
421- * p = self . run_dev ( options. clone ( ) , move |status, reason| {
422- on_exit ( status, reason)
423- } ) ?;
424487 }
425488 }
426489 }
0 commit comments