diff --git a/Cargo.lock b/Cargo.lock index 18d185f..15a480b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1727,11 +1727,11 @@ dependencies = [ [[package]] name = "inotify" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.9.1", "inotify-sys", "libc", ] @@ -1745,15 +1745,6 @@ dependencies = [ "libc", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - [[package]] name = "iq" version = "0.4.0" @@ -2139,9 +2130,9 @@ dependencies = [ [[package]] name = "notify" -version = "7.0.0" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533b4c39709f9ba5005d8002048266593c1cfaf3c5f0739d5b8ab0c6c504009" +checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" dependencies = [ "bitflags 2.9.1", "filetime", @@ -2153,17 +2144,14 @@ dependencies = [ "mio", "notify-types", "walkdir", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "notify-types" -version = "1.0.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585d3cb5e12e01aed9e8a1f70d5c6b5e86fe2a6e48fc8cd0b3e0b8df6f6eb174" -dependencies = [ - "instant", -] +checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" [[package]] name = "num-derive" @@ -3222,15 +3210,6 @@ dependencies = [ "windows-targets 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index da4fa7d..c6d7e65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ gix = { version = "0.72", default-features = false, features = ["index", "exclud glob = "0.3" iq = { version = "0.4", features = ["template"] } lazy-regex = "3.4.1" -notify = "7.0" +notify = "8.0" rodio = { version = "0.20", optional = true, default-features = false, features = ["mp3"] } rustc-hash = "2" serde = { version = "1.0", features = ["derive"] } diff --git a/src/cli/args.rs b/src/cli/args.rs index f6608d1..01faaa0 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -156,6 +156,10 @@ pub struct Args { #[clap(last = true)] /// Arguments given to the job pub additional_job_args: Vec, + + /// Change the recommended file watcher into a polling watcher by setting its polling interval (in seconds) + #[clap(long, value_name = "seconds")] + pub poll: Option, } impl Args { diff --git a/src/tui/app.rs b/src/tui/app.rs index 3a3f53e..c9c1a5e 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -85,6 +85,7 @@ pub fn run( action_rx.clone(), message.take(), headless, + args, )?; match do_after { DoAfterMission::NextJob(job_ref) => { @@ -115,6 +116,7 @@ fn run_mission( action_rx: Receiver, message: Option, headless: bool, + args: &Args ) -> Result { let keybindings = mission.settings.keybindings.clone(); let grace_period = mission.job.grace_period(); @@ -123,10 +125,10 @@ fn run_mission( // build the watcher detecting and transmitting mission file changes let ignorer = time!(Info, mission.ignorer()); - let mission_watcher = Watcher::new(&mission.paths_to_watch, ignorer)?; + let mission_watcher = Watcher::new(&mission.paths_to_watch, ignorer, args.poll)?; // create the watcher for config file changes - let config_watcher = Watcher::new(&mission.settings.config_files, IgnorerSet::default())?; + let config_watcher = Watcher::new(&mission.settings.config_files, IgnorerSet::default(), args.poll)?; // create the executor, mission, and state let mut executor = MissionExecutor::new(&mission)?; diff --git a/src/watcher.rs b/src/watcher.rs index c016fcf..1e99567 100644 --- a/src/watcher.rs +++ b/src/watcher.rs @@ -2,44 +2,40 @@ use { crate::*, anyhow::Result, notify::{ - RecommendedWatcher, - RecursiveMode, - Watcher as NotifyWatcher, event::{ - AccessKind, - AccessMode, - DataChange, - EventKind, - ModifyKind, - }, + AccessKind, AccessMode, DataChange, EventKind, MetadataKind, ModifyKind + }, RecursiveMode, Watcher as NotifyWatcher }, - std::path::PathBuf, + std::{path::PathBuf, time::Duration}, termimad::crossbeam::channel::{ - Receiver, - bounded, + bounded, Receiver }, }; /// A file watcher, providing a channel to receive notifications pub struct Watcher { pub receiver: Receiver<()>, - _notify_watcher: RecommendedWatcher, + _notify_watcher: Box, } impl Watcher { pub fn new( paths_to_watch: &[PathBuf], mut ignorer: IgnorerSet, + polling: Option, ) -> Result { info!("watcher on {:#?}", paths_to_watch); let (sender, receiver) = bounded(0); - let mut notify_watcher = - notify::recommended_watcher(move |res: notify::Result| match res { + let event_handler = move |res: notify::Result| match res { Ok(we) => { match we.kind { - EventKind::Modify(ModifyKind::Metadata(_)) => { - debug!("ignoring metadata change"); - return; // useless event + EventKind::Modify(ModifyKind::Metadata(kind)) => { + if kind == MetadataKind::WriteTime && polling.is_some() { + // the only event triggered usable when polling on WSL2 + } else { + debug!("ignoring metadata change: {:?}", kind); + return; // useless event + } } EventKind::Modify(ModifyKind::Data(DataChange::Any)) => { debug!("ignoring 'any' data change"); @@ -73,7 +69,20 @@ impl Watcher { } } Err(e) => warn!("watch error: {:?}", e), - })?; + }; + let use_polling = polling.is_some(); + let notify_watcher: Result, notify::Error> = if use_polling { + let config = notify::Config::default() + .with_poll_interval(Duration::from_secs(polling.unwrap_or_default())) + .with_compare_contents(true); + notify::PollWatcher::new(event_handler, config) + .map(|w| Box::new(w) as Box) + } else { + notify::recommended_watcher(event_handler) + .map(|w| Box::new(w) as Box) + }; + let mut notify_watcher = notify_watcher?; + for path in paths_to_watch { if !path.exists() { warn!("watch path doesn't exist: {:?}", path);