Skip to content

Commit 252b4da

Browse files
committed
Add paths_mut to KqueueWatcher
1 parent 772dce8 commit 252b4da

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

notify/src/kqueue.rs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
use super::event::*;
88
use super::{Config, Error, EventHandler, RecursiveMode, Result, Watcher};
9-
use crate::{unbounded, Receiver, Sender};
9+
use crate::{unbounded, PathsMut, Receiver, Sender};
1010
use kqueue::{EventData, EventFilter, FilterFlag, Ident};
1111
use std::collections::HashMap;
1212
use std::env;
@@ -46,6 +46,7 @@ pub struct KqueueWatcher {
4646

4747
enum EventLoopMsg {
4848
AddWatch(PathBuf, RecursiveMode, Sender<Result<()>>),
49+
AddWatchMultiple(Vec<(PathBuf, RecursiveMode)>, Sender<Result<()>>),
4950
RemoveWatch(PathBuf, Sender<Result<()>>),
5051
Shutdown,
5152
}
@@ -133,6 +134,9 @@ impl EventLoop {
133134
EventLoopMsg::AddWatch(path, recursive_mode, tx) => {
134135
let _ = tx.send(self.add_watch(path, recursive_mode.is_recursive()));
135136
}
137+
EventLoopMsg::AddWatchMultiple(paths, tx) => {
138+
let _ = tx.send(self.add_watch_multiple(paths));
139+
}
136140
EventLoopMsg::RemoveWatch(path, tx) => {
137141
let _ = tx.send(self.remove_watch(path, false));
138142
}
@@ -313,6 +317,30 @@ impl EventLoop {
313317
Ok(())
314318
}
315319

320+
fn add_watch_multiple(&mut self, paths: Vec<(PathBuf, RecursiveMode)>) -> Result<()> {
321+
for (path, recursive_mode) in paths {
322+
let is_recursive = recursive_mode.is_recursive();
323+
// If the watch is not recursive, or if we determine (by stat'ing the path to get its
324+
// metadata) that the watched path is not a directory, add a single path watch.
325+
if !is_recursive || !metadata(&path).map_err(Error::io)?.is_dir() {
326+
self.add_single_watch(path, false)?;
327+
} else {
328+
for entry in WalkDir::new(path)
329+
.follow_links(self.follow_symlinks)
330+
.into_iter()
331+
{
332+
let entry = entry.map_err(map_walkdir_error)?;
333+
self.add_single_watch(entry.into_path(), is_recursive)?;
334+
}
335+
}
336+
}
337+
338+
// Only make a single `kevent` syscall to add all the watches.
339+
self.kqueue.watch()?;
340+
341+
Ok(())
342+
}
343+
316344
/// Adds a single watch to the kqueue.
317345
///
318346
/// The caller of this function must call `self.kqueue.watch()` afterwards to register the new watch.
@@ -374,6 +402,34 @@ fn map_walkdir_error(e: walkdir::Error) -> Error {
374402
}
375403
}
376404

405+
struct KqueuePathsMut<'a> {
406+
inner: &'a mut KqueueWatcher,
407+
add_paths: Vec<(PathBuf, RecursiveMode)>,
408+
}
409+
impl<'a> KqueuePathsMut<'a> {
410+
fn new(watcher: &'a mut KqueueWatcher) -> Self {
411+
Self {
412+
inner: watcher,
413+
add_paths: Vec::new(),
414+
}
415+
}
416+
}
417+
impl PathsMut for KqueuePathsMut<'_> {
418+
fn add(&mut self, path: &Path, recursive_mode: RecursiveMode) -> Result<()> {
419+
self.add_paths.push((path.to_owned(), recursive_mode));
420+
Ok(())
421+
}
422+
423+
fn remove(&mut self, path: &Path) -> Result<()> {
424+
self.inner.unwatch_inner(path)
425+
}
426+
427+
fn commit(self: Box<Self>) -> Result<()> {
428+
let paths = self.add_paths;
429+
self.inner.watch_multiple_inner(paths)
430+
}
431+
}
432+
377433
impl KqueueWatcher {
378434
fn from_event_handler(
379435
event_handler: Box<dyn EventHandler>,
@@ -408,6 +464,32 @@ impl KqueueWatcher {
408464
.map_err(|e| Error::generic(&e.to_string()))
409465
}
410466

467+
fn watch_multiple_inner(&mut self, paths: Vec<(PathBuf, RecursiveMode)>) -> Result<()> {
468+
let pbs = paths
469+
.into_iter()
470+
.map(|(path, recursive_mode)| {
471+
if path.is_absolute() {
472+
Ok((path, recursive_mode))
473+
} else {
474+
let p = env::current_dir().map_err(Error::io)?;
475+
Ok((p.join(path), recursive_mode))
476+
}
477+
})
478+
.collect::<Result<Vec<(PathBuf, RecursiveMode)>>>()?;
479+
let (tx, rx) = unbounded();
480+
let msg = EventLoopMsg::AddWatchMultiple(pbs, tx);
481+
482+
self.channel
483+
.send(msg)
484+
.map_err(|e| Error::generic(&e.to_string()))?;
485+
self.waker
486+
.wake()
487+
.map_err(|e| Error::generic(&e.to_string()))?;
488+
rx.recv()
489+
.unwrap()
490+
.map_err(|e| Error::generic(&e.to_string()))
491+
}
492+
411493
fn unwatch_inner(&mut self, path: &Path) -> Result<()> {
412494
let pb = if path.is_absolute() {
413495
path.to_owned()
@@ -440,6 +522,10 @@ impl Watcher for KqueueWatcher {
440522
self.watch_inner(path, recursive_mode)
441523
}
442524

525+
fn paths_mut<'me>(&'me mut self) -> Box<dyn PathsMut + 'me> {
526+
Box::new(KqueuePathsMut::new(self))
527+
}
528+
443529
fn unwatch(&mut self, path: &Path) -> Result<()> {
444530
self.unwatch_inner(path)
445531
}

0 commit comments

Comments
 (0)