From 0504c6c24f5f8e2d264d1d8391b07235ac246ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fe=CC=81lix=20Saparelli?= Date: Sat, 27 Apr 2024 22:10:16 +1200 Subject: [PATCH] feat(lib): make it possible to watch non-recursively --- crates/lib/src/sources/fs.rs | 65 +++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/crates/lib/src/sources/fs.rs b/crates/lib/src/sources/fs.rs index 3239d438..17278c24 100644 --- a/crates/lib/src/sources/fs.rs +++ b/crates/lib/src/sources/fs.rs @@ -76,35 +76,71 @@ impl Watcher { /// /// This is currently only a wrapper around a [`PathBuf`], but may be augmented in the future. #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct WatchedPath(PathBuf); +pub struct WatchedPath { + path: PathBuf, + recursive: bool, +} impl From for WatchedPath { fn from(path: PathBuf) -> Self { - Self(path) + Self { + path, + recursive: true, + } } } impl From<&str> for WatchedPath { fn from(path: &str) -> Self { - Self(path.into()) + Self { + path: path.into(), + recursive: true, + } } } impl From<&Path> for WatchedPath { fn from(path: &Path) -> Self { - Self(path.into()) + Self { + path: path.into(), + recursive: true, + } } } impl From for PathBuf { fn from(path: WatchedPath) -> Self { - path.0 + path.path + } +} + +impl From<&WatchedPath> for PathBuf { + fn from(path: &WatchedPath) -> Self { + path.path.clone() } } impl AsRef for WatchedPath { fn as_ref(&self) -> &Path { - self.0.as_ref() + self.path.as_ref() + } +} + +impl WatchedPath { + /// Create a new watched path, recursively descending into subdirectories. + pub fn recursive(path: impl Into) -> Self { + Self { + path: path.into(), + recursive: true, + } + } + + /// Create a new watched path, not descending into subdirectories. + pub fn non_recursive(path: impl Into) -> Self { + Self { + path: path.into(), + recursive: false, + } } } @@ -222,7 +258,7 @@ pub async fn worker( for path in to_drop { trace!(?path, "removing path from the watcher"); - if let Err(err) = watcher.unwatch(path.as_ref()) { + if let Err(err) = watcher.unwatch(path.path.as_ref()) { error!(?err, "notify unwatch() error"); for e in notify_multi_path_errors(watcher_type, path, err, true) { errors.send(e).await?; @@ -234,13 +270,18 @@ pub async fn worker( for path in to_watch { trace!(?path, "adding path to the watcher"); - if let Err(err) = watcher.watch(path.as_ref(), notify::RecursiveMode::Recursive) { + if let Err(err) = watcher.watch( + path.path.as_ref(), + if path.recursive { + notify::RecursiveMode::Recursive + } else { + notify::RecursiveMode::NonRecursive + }, + ) { error!(?err, "notify watch() error"); for e in notify_multi_path_errors(watcher_type, path, err, false) { errors.send(e).await?; } - // TODO: unwatch and re-watch manually while ignoring all the erroring paths - // See https://github.com/watchexec/watchexec/issues/218 } else { pathset.insert(path); } @@ -250,13 +291,13 @@ pub async fn worker( fn notify_multi_path_errors( kind: Watcher, - path: WatchedPath, + watched_path: WatchedPath, mut err: notify::Error, rm: bool, ) -> Vec { let mut paths = take(&mut err.paths); if paths.is_empty() { - paths.push(path.into()); + paths.push(watched_path.into()); } let generic = err.to_string();