From 881729448c9abd0d0c7941a8a31c94119ce827af Mon Sep 17 00:00:00 2001 From: Fabian-Lars Date: Fri, 3 Jan 2025 15:00:31 +0100 Subject: [PATCH] fix(cli): Ignore file access events (#12164) --- .changes/ignore-notify-access-type.md | 6 ++ Cargo.lock | 20 ++++-- .../files_transfer/src-tauri/src/main.rs | 2 +- .../src/bundle/linux/appimage.rs | 6 +- .../src/bundle/linux/freedesktop/mod.rs | 2 +- crates/tauri-cli/Cargo.toml | 2 +- crates/tauri-cli/src/build.rs | 2 +- .../tauri-cli/src/dev/builtin_dev_server.rs | 3 +- crates/tauri-cli/src/interface/rust.rs | 71 +++++++++---------- crates/tauri-macros/src/command/wrapper.rs | 2 +- crates/tauri-runtime-wry/src/lib.rs | 6 +- crates/tauri-utils/src/platform.rs | 1 + crates/tauri/build.rs | 2 +- .../file-associations/src-tauri/src/main.rs | 4 +- 14 files changed, 72 insertions(+), 57 deletions(-) create mode 100644 .changes/ignore-notify-access-type.md diff --git a/.changes/ignore-notify-access-type.md b/.changes/ignore-notify-access-type.md new file mode 100644 index 000000000000..7b053f0c6109 --- /dev/null +++ b/.changes/ignore-notify-access-type.md @@ -0,0 +1,6 @@ +--- +tauri-cli: 'patch:bug' +'@tauri-apps/cli': 'patch:bug' +--- + +Fixed an issue that caused `tauri dev` to crash before showing the app on Linux. diff --git a/Cargo.lock b/Cargo.lock index 4ba3caeb6545..fe9b0041f0b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2954,6 +2954,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "file-id" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bc904b9bbefcadbd8e3a9fb0d464a9b979de6324c03b3c663e8994f46a5be36" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "filetime" version = "0.2.25" @@ -5384,15 +5393,16 @@ dependencies = [ ] [[package]] -name = "notify-debouncer-mini" -version = "0.5.0" +name = "notify-debouncer-full" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa5a66d07ed97dce782be94dcf5ab4d1b457f4243f7566c7557f15cabc8c799" +checksum = "9dcf855483228259b2353f89e99df35fc639b2b2510d1166e4858e3f67ec1afb" dependencies = [ + "file-id", "log", "notify", "notify-types", - "tempfile", + "walkdir", ] [[package]] @@ -9230,7 +9240,7 @@ dependencies = [ "memchr", "minisign", "notify", - "notify-debouncer-mini", + "notify-debouncer-full", "object 0.36.5", "os_info", "os_pipe", diff --git a/bench/tests/files_transfer/src-tauri/src/main.rs b/bench/tests/files_transfer/src-tauri/src/main.rs index 9ac64be2d4b7..3563d86850bf 100644 --- a/bench/tests/files_transfer/src-tauri/src/main.rs +++ b/bench/tests/files_transfer/src-tauri/src/main.rs @@ -18,7 +18,7 @@ async fn read_file(app: AppHandle) -> Result { .path() .resolve(".tauri_3mb.json", BaseDirectory::Home) .map_err(|e| e.to_string())?; - let contents = read(&path).map_err(|e| e.to_string())?; + let contents = read(path).map_err(|e| e.to_string())?; Ok(Response::new(contents)) } diff --git a/crates/tauri-bundler/src/bundle/linux/appimage.rs b/crates/tauri-bundler/src/bundle/linux/appimage.rs index 533f3fbe0a90..87aa238eb1f4 100644 --- a/crates/tauri-bundler/src/bundle/linux/appimage.rs +++ b/crates/tauri-bundler/src/bundle/linux/appimage.rs @@ -56,7 +56,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { let product_name = settings.product_name(); let mut settings = settings.clone(); - if main_binary.name().contains(" ") { + if main_binary.name().contains(' ') { let main_binary_path = settings.binary_path(main_binary); let project_out_directory = settings.project_out_directory(); @@ -108,7 +108,7 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { // Using create_dir_all for a single dir so we don't get errors if the path already exists fs::create_dir_all(&app_dir_usr_bin)?; - fs::create_dir_all(&app_dir_usr_lib)?; + fs::create_dir_all(app_dir_usr_lib)?; // Copy bins and libs that linuxdeploy doesn't know about @@ -258,7 +258,7 @@ fn prepare_tools(tools_path: &Path, arch: &str) -> crate::Result { fn write_and_make_executable(path: &Path, data: Vec) -> std::io::Result<()> { use std::os::unix::fs::PermissionsExt; - fs::write(path, &data)?; + fs::write(path, data)?; fs::set_permissions(path, fs::Permissions::from_mode(0o770))?; Ok(()) diff --git a/crates/tauri-bundler/src/bundle/linux/freedesktop/mod.rs b/crates/tauri-bundler/src/bundle/linux/freedesktop/mod.rs index 75d6d9bcdb5d..4a7c08917412 100644 --- a/crates/tauri-bundler/src/bundle/linux/freedesktop/mod.rs +++ b/crates/tauri-bundler/src/bundle/linux/freedesktop/mod.rs @@ -153,7 +153,7 @@ pub fn generate_desktop_file( let mime_type = (!mime_type.is_empty()).then_some(mime_type.join(";")); - let bin_name_exec = if bin_name.contains(" ") { + let bin_name_exec = if bin_name.contains(' ') { format!("\"{bin_name}\"") } else { bin_name.to_string() diff --git a/crates/tauri-cli/Cargo.toml b/crates/tauri-cli/Cargo.toml index ca62a001bf5d..92979dd76c12 100644 --- a/crates/tauri-cli/Cargo.toml +++ b/crates/tauri-cli/Cargo.toml @@ -52,7 +52,7 @@ colored = "2" serde = { version = "1", features = ["derive"] } serde_json = { version = "1", features = ["preserve_order"] } notify = "7" -notify-debouncer-mini = "0.5" +notify-debouncer-full = "0.4" shared_child = "1" duct = "0.13" toml_edit = { version = "0.22", features = ["serde"] } diff --git a/crates/tauri-cli/src/build.rs b/crates/tauri-cli/src/build.rs index 46ace0f95ec3..52d30262c113 100644 --- a/crates/tauri-cli/src/build.rs +++ b/crates/tauri-cli/src/build.rs @@ -87,7 +87,7 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> { let bin_path = interface.build(interface_options)?; - log::info!(action ="Built"; "application at: {}", tauri_utils::display_path(&bin_path)); + log::info!(action ="Built"; "application at: {}", tauri_utils::display_path(bin_path)); let app_settings = interface.app_settings(); diff --git a/crates/tauri-cli/src/dev/builtin_dev_server.rs b/crates/tauri-cli/src/dev/builtin_dev_server.rs index 1353cb440b1b..9f51f2d74ca7 100644 --- a/crates/tauri-cli/src/dev/builtin_dev_server.rs +++ b/crates/tauri-cli/src/dev/builtin_dev_server.rs @@ -162,11 +162,10 @@ fn watch(dir: PathBuf, handler: F) { thread::spawn(move || { let (tx, rx) = std::sync::mpsc::channel(); - let mut watcher = notify_debouncer_mini::new_debouncer(Duration::from_secs(1), tx) + let mut watcher = notify_debouncer_full::new_debouncer(Duration::from_secs(1), None, tx) .expect("failed to start builtin server fs watcher"); watcher - .watcher() .watch(&dir, notify::RecursiveMode::Recursive) .expect("builtin server failed to watch dir"); diff --git a/crates/tauri-cli/src/interface/rust.rs b/crates/tauri-cli/src/interface/rust.rs index b6542466da18..581a380720ec 100644 --- a/crates/tauri-cli/src/interface/rust.rs +++ b/crates/tauri-cli/src/interface/rust.rs @@ -18,7 +18,7 @@ use anyhow::Context; use glob::glob; use ignore::gitignore::{Gitignore, GitignoreBuilder}; use notify::RecursiveMode; -use notify_debouncer_mini::new_debouncer; +use notify_debouncer_full::new_debouncer; use serde::{Deserialize, Deserializer}; use tauri_bundler::{ AppCategory, AppImageSettings, BundleBinary, BundleSettings, DebianSettings, DmgSettings, @@ -124,15 +124,13 @@ impl Interface for Rust { fn new(config: &Config, target: Option) -> crate::Result { let manifest = { let (tx, rx) = sync_channel(1); - let mut watcher = new_debouncer(Duration::from_secs(1), move |r| { + let mut watcher = new_debouncer(Duration::from_secs(1), None, move |r| { if let Ok(events) = r { let _ = tx.send(events); } }) .unwrap(); - watcher - .watcher() - .watch(&tauri_dir().join("Cargo.toml"), RecursiveMode::Recursive)?; + watcher.watch(tauri_dir().join("Cargo.toml"), RecursiveMode::Recursive)?; let (manifest, _modified) = rewrite_manifest(config)?; let now = Instant::now(); let timeout = Duration::from_secs(2); @@ -527,7 +525,7 @@ impl Rust { .expect("watch_folders should not be empty"); let ignore_matcher = build_ignore_matcher(&common_ancestor); - let mut watcher = new_debouncer(Duration::from_secs(1), move |r| { + let mut watcher = new_debouncer(Duration::from_secs(1), None, move |r| { if let Ok(events) = r { tx.send(events).unwrap() } @@ -539,7 +537,7 @@ impl Rust { lookup(&path, |file_type, p| { if p != path { log::debug!("Watching {} for changes...", display_path(&p)); - let _ = watcher.watcher().watch( + let _ = watcher.watch( &p, if file_type.is_dir() { RecursiveMode::Recursive @@ -555,42 +553,43 @@ impl Rust { loop { if let Ok(events) = rx.recv() { for event in events { - let event_path = event.path; - - if !ignore_matcher.is_ignore(&event_path, event_path.is_dir()) { - if is_configuration_file(self.app_settings.target, &event_path) { - if let Ok(config) = reload_config(config.as_ref()) { - let (manifest, modified) = - rewrite_manifest(config.lock().unwrap().as_ref().unwrap())?; - if modified { - *self.app_settings.manifest.lock().unwrap() = manifest; - // no need to run the watcher logic, the manifest was modified - // and it will trigger the watcher again - continue; + #[cfg(target_os = "linux")] + if event.kind.is_access() { + continue; + } + + if let Some(event_path) = event.paths.first() { + if !ignore_matcher.is_ignore(event_path, event_path.is_dir()) { + if is_configuration_file(self.app_settings.target, event_path) { + if let Ok(config) = reload_config(config.as_ref()) { + let (manifest, modified) = + rewrite_manifest(config.lock().unwrap().as_ref().unwrap())?; + if modified { + *self.app_settings.manifest.lock().unwrap() = manifest; + // no need to run the watcher logic, the manifest was modified + // and it will trigger the watcher again + continue; + } } } - } - log::info!( - "File {} changed. Rebuilding application...", - display_path( - event_path - .strip_prefix(frontend_path) - .unwrap_or(&event_path) - ) - ); + log::info!( + "File {} changed. Rebuilding application...", + display_path(event_path.strip_prefix(frontend_path).unwrap_or(event_path)) + ); - let mut p = process.lock().unwrap(); - p.kill().with_context(|| "failed to kill app process")?; + let mut p = process.lock().unwrap(); + p.kill().with_context(|| "failed to kill app process")?; - // wait for the process to exit - // note that on mobile, kill() already waits for the process to exit (duct implementation) - loop { - if !matches!(p.try_wait(), Ok(None)) { - break; + // wait for the process to exit + // note that on mobile, kill() already waits for the process to exit (duct implementation) + loop { + if !matches!(p.try_wait(), Ok(None)) { + break; + } } + *p = run(self)?; } - *p = run(self)?; } } } diff --git a/crates/tauri-macros/src/command/wrapper.rs b/crates/tauri-macros/src/command/wrapper.rs index 4babd0dbb325..fc02b2537c3e 100644 --- a/crates/tauri-macros/src/command/wrapper.rs +++ b/crates/tauri-macros/src/command/wrapper.rs @@ -478,7 +478,7 @@ fn rustc_version() -> (u32, u32) { .split(' ') .nth(1) .unwrap_or_default() - .split(".") + .split('.') .take(2) .flat_map(|p| p.parse::().ok()) .collect::>(); diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 82d636dd2d37..beaa7f9cb4af 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -2682,7 +2682,7 @@ impl Runtime for Wry { pending, )?; - #[allow(clippy::manual_inspect)] + #[allow(unknown_lints, clippy::manual_inspect)] self .context .main_thread @@ -3311,7 +3311,7 @@ fn handle_user_message( let _ = webview.print(); } WebviewMessage::Close => { - #[allow(clippy::manual_inspect)] + #[allow(unknown_lints, clippy::manual_inspect)] windows.0.borrow_mut().get_mut(&window_id).map(|window| { if let Some(i) = window.webviews.iter().position(|w| w.id == webview.id) { window.webviews.remove(i); @@ -3535,7 +3535,7 @@ fn handle_user_message( if let Some(window) = window { match handler(&window) { Ok(webview) => { - #[allow(clippy::manual_inspect)] + #[allow(unknown_lints, clippy::manual_inspect)] windows.0.borrow_mut().get_mut(&window_id).map(|w| { w.webviews.push(webview); w.has_children.store(true, Ordering::Relaxed); diff --git a/crates/tauri-utils/src/platform.rs b/crates/tauri-utils/src/platform.rs index 7a9c99431ed5..f795820691dd 100644 --- a/crates/tauri-utils/src/platform.rs +++ b/crates/tauri-utils/src/platform.rs @@ -396,6 +396,7 @@ mod tests { assert_eq!(resource_dir, path.parent().unwrap()); let path = PathBuf::from("/path/to/target/unknown-profile/app"); + #[allow(clippy::needless_borrows_for_generic_args)] let resource_dir = super::resource_dir_from(&path, &package_info, &env); #[cfg(target_os = "macos")] assert!(resource_dir.is_err()); diff --git a/crates/tauri/build.rs b/crates/tauri/build.rs index 6d42d967b4ce..86eb0f55897d 100644 --- a/crates/tauri/build.rs +++ b/crates/tauri/build.rs @@ -428,7 +428,7 @@ permissions = [{}] .join(",") ); - write_if_changed(&default_toml, toml_content) + write_if_changed(default_toml, toml_content) .unwrap_or_else(|_| panic!("unable to autogenerate core:default set")); let _ = tauri_utils::acl::build::define_permissions( diff --git a/examples/file-associations/src-tauri/src/main.rs b/examples/file-associations/src-tauri/src/main.rs index 397e36eda085..ea2ec8f3b4d9 100644 --- a/examples/file-associations/src-tauri/src/main.rs +++ b/examples/file-associations/src-tauri/src/main.rs @@ -35,7 +35,7 @@ fn handle_file_associations(app: AppHandle, files: Vec) { let files = files .into_iter() .map(|f| { - let file = f.to_string_lossy().replace("\\", "\\\\"); // escape backslash + let file = f.to_string_lossy().replace('\\', "\\\\"); // escape backslash format!("\"{file}\"",) // wrap in quotes for JS array }) .collect::>() @@ -59,7 +59,7 @@ fn main() { // files may aslo be passed as `file://path/to/file` for maybe_file in std::env::args().skip(1) { // skip flags like -f or --flag - if maybe_file.starts_with("-") { + if maybe_file.starts_with('-') { continue; }