Skip to content

Commit f3a13c2

Browse files
committed
fix: deprecate paths_mut, introduce WatchPathConfig and some renames
`WatchPathConfig` provides a way to configure single watch. Now it's just a wrapper around a `RecursiveMode` but it'll help us to add some functionality, like filter watched paths or specify a mask for events without breaking changes
1 parent 7530d19 commit f3a13c2

File tree

4 files changed

+159
-56
lines changed

4 files changed

+159
-56
lines changed

notify/src/config.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Configuration types
22
3-
use std::time::Duration;
3+
use std::{path::PathBuf, time::Duration};
44

55
/// Indicates whether only the provided directory or its sub-directories as well should be watched
66
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
@@ -123,3 +123,62 @@ impl Default for Config {
123123
}
124124
}
125125
}
126+
127+
/// Single watch backend configuration
128+
///
129+
/// This contains some settings that may relate to only one specific backend,
130+
/// such as to correctly configure each backend regardless of what is selected during runtime.
131+
#[derive(Debug)]
132+
pub struct WatchPathConfig {
133+
recursive_mode: RecursiveMode,
134+
}
135+
136+
impl WatchPathConfig {
137+
/// Creates new instance with provided [`RecursiveMode`]
138+
pub fn new(recursive_mode: RecursiveMode) -> Self {
139+
Self { recursive_mode }
140+
}
141+
142+
/// Set [`RecursiveMode`] for the watch
143+
pub fn with_recursive_mode(mut self, recursive_mode: RecursiveMode) -> Self {
144+
self.recursive_mode = recursive_mode;
145+
self
146+
}
147+
148+
/// Returns current setting
149+
pub fn recursive_mode(&self) -> RecursiveMode {
150+
self.recursive_mode
151+
}
152+
}
153+
154+
/// An operation to apply to a watcher
155+
///
156+
/// See [`Watcher::update_paths`] for more information
157+
#[derive(Debug)]
158+
pub enum PathOp {
159+
/// Path should be watcher
160+
Watch(PathBuf, WatchPathConfig),
161+
162+
/// Path should be unwatched
163+
Unwatch(PathBuf),
164+
}
165+
166+
impl PathOp {
167+
/// Watch the path with [`RecursiveMode::Recursive`]
168+
pub fn watch_recursive<P: Into<PathBuf>>(path: P) -> Self {
169+
Self::Watch(path.into(), WatchPathConfig::new(RecursiveMode::Recursive))
170+
}
171+
172+
/// Watch the path with [`RecursiveMode::NonRecursive`]
173+
pub fn watch_non_recursive<P: Into<PathBuf>>(path: P) -> Self {
174+
Self::Watch(
175+
path.into(),
176+
WatchPathConfig::new(RecursiveMode::NonRecursive),
177+
)
178+
}
179+
180+
/// Unwatch the path
181+
pub fn unwatch<P: Into<PathBuf>>(path: P) -> Self {
182+
Self::Unwatch(path.into())
183+
}
184+
}

notify/src/error.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Error types
22
3-
use crate::{Config, WatchOp};
3+
use crate::{Config, PathOp};
44
use std::error::Error as StdError;
55
use std::fmt::Debug;
66
use std::path::PathBuf;
@@ -159,23 +159,23 @@ impl<T> From<std::sync::PoisonError<T>> for Error {
159159
}
160160
}
161161

162-
/// The error provided by [`crate::Watcher::update_watches`] method
162+
/// The error provided by [`crate::Watcher::update_paths`] method
163163
#[derive(Debug)]
164-
pub struct UpdateWatchesError {
164+
pub struct UpdatePathsError {
165165
/// The original error
166166
pub source: Error,
167167

168168
/// The remaining operations that haven't been applied
169-
pub remaining: Vec<WatchOp>,
169+
pub remaining: Vec<PathOp>,
170170
}
171171

172-
impl fmt::Display for UpdateWatchesError {
172+
impl fmt::Display for UpdatePathsError {
173173
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174174
write!(f, "unable to apply the batch operation: {}", self.source)
175175
}
176176
}
177177

178-
impl StdError for UpdateWatchesError {
178+
impl StdError for UpdatePathsError {
179179
fn source(&self) -> Option<&(dyn StdError + 'static)> {
180180
Some(&self.source)
181181
}
@@ -198,8 +198,8 @@ mod tests {
198198
}
199199

200200
#[test]
201-
fn display_update_watches() {
202-
let actual = UpdateWatchesError {
201+
fn display_update_paths() {
202+
let actual = UpdatePathsError {
203203
source: Error::generic("Some error"),
204204
remaining: Default::default(),
205205
}

notify/src/fsevent.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
1515
#![allow(non_upper_case_globals, dead_code)]
1616

17-
use crate::{event::*, WatchOp};
17+
use crate::{event::*, PathOp};
1818
use crate::{unbounded, Config, Error, EventHandler, RecursiveMode, Result, Sender, Watcher};
1919
use fsevent_sys as fs;
2020
use fsevent_sys::core_foundation as cf;
@@ -296,15 +296,15 @@ impl FsEventWatcher {
296296
result
297297
}
298298

299-
fn update_watches_inner(
299+
fn update_paths_inner(
300300
&mut self,
301-
ops: Vec<crate::WatchOp>,
302-
) -> crate::StdResult<(), crate::UpdateWatchesError> {
301+
ops: Vec<crate::PathOp>,
302+
) -> crate::StdResult<(), crate::UpdatePathsError> {
303303
self.stop();
304304

305-
let result = crate::update_watches(ops, |op| match op {
306-
crate::WatchOp::Watch(path, recursive_mode) => self.append_path(&path, recursive_mode),
307-
crate::WatchOp::Unwatch(path) => self.remove_path(&path),
305+
let result = crate::update_paths(ops, |op| match op {
306+
crate::PathOp::Watch(path, config) => self.append_path(&path, config.recursive_mode()),
307+
crate::PathOp::Unwatch(path) => self.remove_path(&path),
308308
});
309309

310310
// ignore return error: may be empty path list
@@ -582,11 +582,8 @@ impl Watcher for FsEventWatcher {
582582
self.unwatch_inner(path)
583583
}
584584

585-
fn update_watches(
586-
&mut self,
587-
ops: Vec<WatchOp>,
588-
) -> crate::StdResult<(), crate::UpdateWatchesError> {
589-
self.update_watches_inner(ops)
585+
fn update_paths(&mut self, ops: Vec<PathOp>) -> crate::StdResult<(), crate::UpdatePathsError> {
586+
self.update_paths_inner(ops)
590587
}
591588

592589
fn configure(&mut self, config: Config) -> Result<bool> {

notify/src/lib.rs

Lines changed: 82 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,10 @@
162162
163163
#![deny(missing_docs)]
164164

165-
pub use config::{Config, RecursiveMode};
166-
pub use error::{Error, ErrorKind, Result, UpdateWatchesError};
165+
pub use config::{Config, PathOp, RecursiveMode, WatchPathConfig};
166+
pub use error::{Error, ErrorKind, Result, UpdatePathsError};
167167
pub use notify_types::event::{self, Event, EventKind};
168-
use std::path::{Path, PathBuf};
168+
use std::path::Path;
169169

170170
pub(crate) type StdResult<T, E> = std::result::Result<T, E>;
171171
pub(crate) type Receiver<T> = std::sync::mpsc::Receiver<T>;
@@ -294,16 +294,47 @@ pub enum WatcherKind {
294294
NullWatcher,
295295
}
296296

297-
/// An operation to apply to a watcher
297+
/// Providing methods for adding and removing paths to watch.
298298
///
299-
/// See [`Watcher::update_watches`] for more information
300-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
301-
pub enum WatchOp {
302-
/// Path should be watcher
303-
Watch(PathBuf, RecursiveMode),
304-
305-
/// Path should be unwatched
306-
Unwatch(PathBuf),
299+
/// `Box<dyn PathsMut>` is created by [`Watcher::paths_mut`]. See its documentation for more.
300+
#[deprecated(
301+
since = "9.0.0",
302+
note = "paths_mut has been replaced with update_paths"
303+
)]
304+
pub trait PathsMut {
305+
/// Add a new path to watch. See [`Watcher::watch`] for more.
306+
fn add(&mut self, path: &Path, recursive_mode: RecursiveMode) -> Result<()>;
307+
308+
/// Remove a path from watching. See [`Watcher::unwatch`] for more.
309+
fn remove(&mut self, path: &Path) -> Result<()>;
310+
311+
/// Ensure added/removed paths are applied.
312+
fn commit(self: Box<Self>) -> Result<()>;
313+
}
314+
315+
struct PathsMutInternal<'a, T: ?Sized> {
316+
ops: Vec<PathOp>,
317+
watcher: &'a mut T,
318+
}
319+
320+
#[allow(deprecated)]
321+
impl<'a, T: Watcher + ?Sized> PathsMut for PathsMutInternal<'a, T> {
322+
fn add(&mut self, path: &Path, recursive_mode: RecursiveMode) -> Result<()> {
323+
self.ops.push(PathOp::Watch(
324+
path.to_path_buf(),
325+
WatchPathConfig::new(recursive_mode),
326+
));
327+
Ok(())
328+
}
329+
330+
fn remove(&mut self, path: &Path) -> Result<()> {
331+
self.ops.push(PathOp::Unwatch(path.to_path_buf()));
332+
Ok(())
333+
}
334+
335+
fn commit(self: Box<Self>) -> Result<()> {
336+
self.watcher.update_paths(self.ops).map_err(|v| v.source)
337+
}
307338
}
308339

309340
/// Type that can deliver file activity notifications
@@ -341,6 +372,19 @@ pub trait Watcher {
341372
/// fails.
342373
fn unwatch(&mut self, path: &Path) -> Result<()>;
343374

375+
/// deprecated
376+
#[deprecated(
377+
since = "9.0.0",
378+
note = "paths_mut has been replaced with update_paths"
379+
)]
380+
#[allow(deprecated)]
381+
fn paths_mut<'me>(&'me mut self) -> Box<dyn PathsMut + 'me> {
382+
Box::new(PathsMutInternal {
383+
watcher: self,
384+
ops: Default::default(),
385+
})
386+
}
387+
344388
/// Add/remove paths to watch in batch.
345389
///
346390
/// For some [`Watcher`] implementations this method provides better performance than multiple
@@ -349,31 +393,31 @@ pub trait Watcher {
349393
/// # Examples
350394
///
351395
/// ```
352-
/// # use notify::{Watcher, RecursiveMode, WatchOp};
353-
/// # use std::path::Path;
396+
/// # use notify::{Watcher, RecursiveMode, PathOp};
397+
/// # use std::path::{Path, PathBuf};
354398
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
355-
/// # let many_paths_to_add = vec![];
356-
/// # let many_paths_to_remove = vec![];
399+
/// # let many_paths_to_add: Vec<PathBuf> = vec![];
400+
/// # let many_paths_to_remove: Vec<PathBuf> = vec![];
357401
/// let mut watcher = notify::NullWatcher;
358402
/// let mut batch = Vec::new();
359403
///
360-
/// for (path, recursive_mode) in many_paths_to_add {
361-
/// batch.push(WatchOp::Watch(path, recursive_mode));
404+
/// for path in many_paths_to_add {
405+
/// batch.push(PathOp::watch_recursive(path));
362406
/// }
363407
///
364408
/// for path in many_paths_to_remove {
365-
/// batch.push(WatchOp::Unwatch(path));
409+
/// batch.push(PathOp::unwatch(path));
366410
/// }
367411
///
368412
/// // real work is done there
369-
/// watcher.update_watches(batch)?;
413+
/// watcher.update_paths(batch)?;
370414
/// # Ok(())
371415
/// # }
372416
/// ```
373-
fn update_watches(&mut self, ops: Vec<WatchOp>) -> StdResult<(), UpdateWatchesError> {
374-
update_watches(ops, |op| match op {
375-
WatchOp::Watch(path, recursive_mode) => self.watch(&path, recursive_mode),
376-
WatchOp::Unwatch(path) => self.unwatch(&path),
417+
fn update_paths(&mut self, ops: Vec<PathOp>) -> StdResult<(), UpdatePathsError> {
418+
update_paths(ops, |op| match op {
419+
PathOp::Watch(path, config) => self.watch(&path, config.recursive_mode()),
420+
PathOp::Unwatch(path) => self.unwatch(&path),
377421
})
378422
}
379423

@@ -438,17 +482,14 @@ where
438482
RecommendedWatcher::new(event_handler, Config::default())
439483
}
440484

441-
pub(crate) fn update_watches<F>(
442-
ops: Vec<WatchOp>,
443-
mut apply: F,
444-
) -> StdResult<(), UpdateWatchesError>
485+
pub(crate) fn update_paths<F>(ops: Vec<PathOp>, mut apply: F) -> StdResult<(), UpdatePathsError>
445486
where
446-
F: FnMut(WatchOp) -> Result<()>,
487+
F: FnMut(PathOp) -> Result<()>,
447488
{
448489
let mut iter = ops.into_iter();
449490
while let Some(op) = iter.next() {
450491
if let Err(source) = apply(op) {
451-
return Err(UpdateWatchesError {
492+
return Err(UpdatePathsError {
452493
source,
453494
remaining: iter.collect(),
454495
});
@@ -557,7 +598,7 @@ mod tests {
557598
}
558599

559600
#[test]
560-
fn test_update_watches() -> std::result::Result<(), Box<dyn std::error::Error>> {
601+
fn test_update_paths() -> std::result::Result<(), Box<dyn std::error::Error>> {
561602
let dir = tempdir()?;
562603

563604
let dir_a = dir.path().join("a");
@@ -570,9 +611,15 @@ mod tests {
570611
let mut watcher = RecommendedWatcher::new(tx, Config::default())?;
571612

572613
// start watching a and b
573-
watcher.update_watches(vec![
574-
WatchOp::Watch(dir_a.clone(), RecursiveMode::Recursive),
575-
WatchOp::Watch(dir_b.clone(), RecursiveMode::Recursive),
614+
watcher.update_paths(vec![
615+
PathOp::Watch(
616+
dir_a.clone(),
617+
WatchPathConfig::new(RecursiveMode::Recursive),
618+
),
619+
PathOp::Watch(
620+
dir_b.clone(),
621+
WatchPathConfig::new(RecursiveMode::Recursive),
622+
),
576623
])?;
577624

578625
// create file1 in both a and b
@@ -599,7 +646,7 @@ mod tests {
599646
assert!(b_file1_encountered, "Did not receive event of {b_file1:?}");
600647

601648
// stop watching a
602-
watcher.update_watches(vec![WatchOp::Unwatch(dir_a.clone())])?;
649+
watcher.update_paths(vec![PathOp::unwatch(&dir_a)])?;
603650

604651
// create file2 in both a and b
605652
let a_file2 = dir_a.join("file2");

0 commit comments

Comments
 (0)