Skip to content

Commit 9417ce4

Browse files
fix(cli): apply .taurignore rules to workspace members, closes #5355 (#5460)
Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
1 parent 7a231cd commit 9417ce4

4 files changed

Lines changed: 116 additions & 40 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"cli.rs": patch
3+
---
4+
5+
Ignore workspace members in dev watcher if they are ignored by `.taurignore`

tooling/cli/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tooling/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ html5ever = "0.25"
8383
infer = "0.9"
8484
kuchiki = "0.8"
8585
tokio = { version = "1", features = ["macros", "sync"] }
86+
common-path = "1"
8687

8788
[target."cfg(windows)".dependencies]
8889
winapi = { version = "0.3", features = [ "handleapi", "processenv", "winbase", "wincon", "winnt" ] }

tooling/cli/src/interface/rust.rs

Lines changed: 103 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44

55
use 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::{
2021
use anyhow::Context;
2122
#[cfg(target_os = "linux")]
2223
use heck::ToKebabCase;
24+
use ignore::gitignore::{Gitignore, GitignoreBuilder};
2325
use log::{debug, info};
2426
use notify::RecursiveMode;
2527
use 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+
258313
fn 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

Comments
 (0)