From 2a035c86c5f12aeee635a827c1f458211ca923ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Sat, 20 Apr 2019 22:56:41 +1200 Subject: [PATCH] [dual] Explicitely support more than one watcher on a channel --- src/event.rs | 2 +- src/lib.rs | 39 +++++++++++++--- tests/debounce.rs | 33 +++++++++++++ tests/watcher.rs | 115 +++++++++++++++++++++++++--------------------- 4 files changed, 130 insertions(+), 59 deletions(-) diff --git a/src/event.rs b/src/event.rs index 7d433de1..c0ea07ce 100644 --- a/src/event.rs +++ b/src/event.rs @@ -284,7 +284,7 @@ impl EventKind { pub fn is_other(&self) -> bool { match *self { EventKind::Other => true, - _ => false + _ => false, } } } diff --git a/src/lib.rs b/src/lib.rs index 45fc80ec..eede8648 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,15 +91,9 @@ //! # use notify::{Watcher, RecommendedWatcher, RecursiveMode, Result}; //! # //! # fn main() -> Result<()> { -//! # // Create a channel to receive the events. //! # let (tx, rx) = unbounded(); //! # -//! # // Create a watcher object, delivering raw events. -//! # // The notification back-end is selected based on the platform. //! let mut watcher: RecommendedWatcher = Watcher::new_immediate(tx)?; -//! # -//! # // Add a path to be watched. All files and directories at that path and -//! # // below will be monitored for changes. //! # watcher.watch(".", RecursiveMode::Recursive)?; //! # //! # loop { @@ -113,6 +107,39 @@ //! # Ok(()) //! # } //! ``` +//! +//! ## With different configurations +//! +//! It is possible to create several watchers with different configurations or implementations that +//! all send to the same channel. This can accomodate advanced behaviour or work around limits. +//! +//! ``` +//! # extern crate crossbeam_channel; +//! # extern crate notify; +//! # +//! # use crossbeam_channel::unbounded; +//! # use notify::{Watcher, RecommendedWatcher, RecursiveMode, Result}; +//! # +//! # fn main() -> Result<()> { +//! # let (tx, rx) = unbounded(); +//! # +//! let mut watcher1: RecommendedWatcher = Watcher::new_immediate(tx.clone())?; +//! let mut watcher2: RecommendedWatcher = Watcher::new_immediate(tx)?; +//! # +//! # watcher1.watch(".", RecursiveMode::Recursive)?; +//! # watcher2.watch(".", RecursiveMode::Recursive)?; +//! # +//! loop { +//! # break; +//! match rx.recv() { +//! Ok(event) => println!("event: {:?}", event), +//! Err(e) => println!("watch error: {:?}", e), +//! } +//! } +//! # +//! # Ok(()) +//! # } +//! ``` #![deny(missing_docs)] diff --git a/tests/debounce.rs b/tests/debounce.rs index 9f1b52ec..c4eee337 100644 --- a/tests/debounce.rs +++ b/tests/debounce.rs @@ -1476,3 +1476,36 @@ fn one_file_many_events() { ); io_thread.join().unwrap(); } + +#[test] +fn dual_create_file() { + let tdir1 = TempDir::new("temp_dir1").expect("failed to create temporary directory"); + let tdir2 = TempDir::new("temp_dir2").expect("failed to create temporary directory"); + + sleep_macos(10); + + let (tx, rx) = unbounded(); + let mut watcher1: RecommendedWatcher = + Watcher::new(tx.clone(), Duration::from_millis(DELAY_MS)) + .expect("failed to create debounced watcher"); + let mut watcher2: RecommendedWatcher = Watcher::new(tx, Duration::from_millis(DELAY_MS)) + .expect("failed to create debounced watcher"); + + watcher1 + .watch(tdir1.mkpath("."), RecursiveMode::Recursive) + .expect("failed to watch directory"); + watcher2 + .watch(tdir2.mkpath("."), RecursiveMode::Recursive) + .expect("failed to watch directory"); + + tdir1.create("file1"); + tdir2.create("file2"); + + assert_eq!( + recv_events_debounced(&rx), + vec![ + (Kind::Create, vec![tdir1.mkpath("file1")], false), + (Kind::Create, vec![tdir2.mkpath("file2")], false), + ] + ); +} diff --git a/tests/watcher.rs b/tests/watcher.rs index 36af8394..44d37deb 100644 --- a/tests/watcher.rs +++ b/tests/watcher.rs @@ -59,6 +59,15 @@ fn new_recommended() { assert!(w.is_ok()); } +#[test] +fn new_dual() { + let (tx, _) = unbounded(); + let w1: Result = Watcher::new_immediate(tx.clone()); + let w2: Result = Watcher::new_immediate(tx); + assert!(w1.is_ok()); + assert!(w2.is_ok()); +} + // if this test builds, it means RecommendedWatcher is Send. #[test] fn test_watcher_send() { @@ -144,67 +153,68 @@ fn watch_relative() { } } } - if cfg!(target_os = "windows") && !NETWORK_PATH.is_empty() { - // watch_relative_network_directory - let tdir = TempDir::new_in(NETWORK_PATH, "temp_dir") - .expect("failed to create temporary directory"); - tdir.create("dir1"); - - env::set_current_dir(tdir.path()).expect("failed to change working directory"); - let (tx, _) = unbounded(); - let mut watcher: RecommendedWatcher = - Watcher::new_immediate(tx).expect("failed to create recommended watcher"); - watcher - .watch("dir1", RecursiveMode::Recursive) - .expect("failed to watch directory"); - - watcher - .unwatch("dir1") - .expect("failed to unwatch directory"); - - if cfg!(not(target_os = "windows")) { - match watcher.unwatch("dir1") { - Err(Error::WatchNotFound) => (), - Err(e) => panic!("{:?}", e), - Ok(o) => panic!("{:?}", o), + // To run: set a valid NETWORK_PATH. + if cfg!(target_os = "windows") && cfg!(feature = "manual_tests") { + { + // watch_relative_network_directory + let tdir = TempDir::new_in(NETWORK_PATH, "temp_dir") + .expect("failed to create temporary directory"); + tdir.create("dir1"); + + env::set_current_dir(tdir.path()).expect("failed to change working directory"); + + let (tx, _) = unbounded(); + let mut watcher: RecommendedWatcher = + Watcher::new_immediate(tx).expect("failed to create recommended watcher"); + watcher + .watch("dir1", RecursiveMode::Recursive) + .expect("failed to watch directory"); + + watcher + .unwatch("dir1") + .expect("failed to unwatch directory"); + + if cfg!(not(target_os = "windows")) { + match watcher.unwatch("dir1") { + Err(Error::WatchNotFound) => (), + Err(e) => panic!("{:?}", e), + Ok(o) => panic!("{:?}", o), + } } } - } - if cfg!(target_os = "windows") && !NETWORK_PATH.is_empty() { - // watch_relative_network_file - let tdir = TempDir::new_in(NETWORK_PATH, "temp_dir") - .expect("failed to create temporary directory"); - tdir.create("file1"); - - env::set_current_dir(tdir.path()).expect("failed to change working directory"); - - let (tx, _) = unbounded(); - let mut watcher: RecommendedWatcher = - Watcher::new_immediate(tx).expect("failed to create recommended watcher"); - watcher - .watch("file1", RecursiveMode::Recursive) - .expect("failed to watch file"); - - watcher.unwatch("file1").expect("failed to unwatch file"); - - if cfg!(not(target_os = "windows")) { - match watcher.unwatch("file1") { - Err(Error::WatchNotFound) => (), - Err(e) => panic!("{:?}", e), - Ok(o) => panic!("{:?}", o), + { + // watch_relative_network_file + let tdir = TempDir::new_in(NETWORK_PATH, "temp_dir") + .expect("failed to create temporary directory"); + tdir.create("file1"); + + env::set_current_dir(tdir.path()).expect("failed to change working directory"); + + let (tx, _) = unbounded(); + let mut watcher: RecommendedWatcher = + Watcher::new_immediate(tx).expect("failed to create recommended watcher"); + watcher + .watch("file1", RecursiveMode::Recursive) + .expect("failed to watch file"); + + watcher.unwatch("file1").expect("failed to unwatch file"); + + if cfg!(not(target_os = "windows")) { + match watcher.unwatch("file1") { + Err(Error::WatchNotFound) => (), + Err(e) => panic!("{:?}", e), + Ok(o) => panic!("{:?}", o), + } } } } } #[test] -#[cfg(target_os = "windows")] +#[cfg(all(feature = "manual_tests", target_os = "windows"))] +// To run: set a valid NETWORK_PATH. fn watch_absolute_network_directory() { - if NETWORK_PATH.is_empty() { - return; - } - let tdir = TempDir::new_in(NETWORK_PATH, "temp_dir").expect("failed to create temporary directory"); tdir.create("dir1"); @@ -230,7 +240,8 @@ fn watch_absolute_network_directory() { } #[test] -#[cfg(target_os = "windows")] +#[cfg(all(feature = "manual_tests", target_os = "windows"))] +// To run: set a valid NETWORK_PATH. fn watch_absolute_network_file() { if NETWORK_PATH.is_empty() { return;