diff --git a/notify/src/poll.rs b/notify/src/poll.rs index b2833171..3ea3790c 100644 --- a/notify/src/poll.rs +++ b/notify/src/poll.rs @@ -18,7 +18,7 @@ use std::{ use data::{DataBuilder, WatchData}; mod data { use crate::{ - event::{CreateKind, DataChange, Event, EventKind, MetadataKind, ModifyKind, RemoveKind}, + event::{CreateKind, DataChange, Event, EventKind, MetadataKind, ModifyKind, RemoveKind, EventAttributes}, EventHandler, }; use filetime::FileTime; @@ -37,6 +37,7 @@ mod data { /// Builder for [`WatchData`] & [`PathData`]. pub(super) struct DataBuilder { emitter: EventEmitter, + scan_emitter: Option, // TODO: May allow user setup their custom BuildHasher / BuildHasherDefault // in future. @@ -47,12 +48,13 @@ mod data { } impl DataBuilder { - pub(super) fn new(event_handler: F, compare_content: bool) -> Self + pub(super) fn new(event_handler: F, compare_content: bool, scan_emitter: Option) -> Self where F: EventHandler, { Self { emitter: EventEmitter::new(event_handler), + scan_emitter: scan_emitter.map(EventEmitter::new), build_hasher: compare_content.then(RandomState::default), now: Instant::now(), } @@ -192,6 +194,7 @@ mod data { root: PathBuf, is_recursive: bool, ) -> impl Iterator + '_ { + log::trace!("rescanning {root:?}"); // WalkDir return only one entry if root is a file (not a folder), // so we can use single logic to do the both file & dir's jobs. // @@ -212,11 +215,26 @@ mod data { // propagate to event handler. It may not consistent. // // FIXME: Should we emit all IO error events? Or ignore them all? - .filter_map(|entry| entry.ok()) + .filter_map(|entry_res| { + match entry_res { + Ok(entry) => { + Some(entry) + }, + Err(err) => { + log::warn!("walkdir error scanning {err:?}"); + let crate_err = crate::Error::new(crate::ErrorKind::Generic(err.to_string())); + data_builder.emitter.emit(Err(crate_err)); + None + } + } + }) .filter_map(|entry| match entry.metadata() { Ok(metadata) => { let path = entry.into_path(); - + // emit initial scans + if let Some(emitter) = &data_builder.scan_emitter { + emitter.emit(Ok(Event { kind: EventKind::Create(CreateKind::File), paths: vec![path.clone()], attrs: EventAttributes::new() })); + } let meta_path = MetaPath::from_parts_unchecked(path, metadata); let data_path = data_builder.build_path_data(&meta_path); @@ -409,7 +427,14 @@ pub struct PollWatcher { impl PollWatcher { /// Create a new [PollWatcher], configured as needed. pub fn new(event_handler: F, config: Config) -> crate::Result { - let data_builder = DataBuilder::new(event_handler, config.compare_contents()); + Self::with_initial_scan::<_,>(event_handler, config, None) + } + + /// Crate a new [PollWatcher] with an event handler called on the initial scan with all files seen by the pollwatcher. + /// + /// `scan_fallback` is called on the initial scan and rescans + pub fn with_initial_scan(event_handler: F, config: Config, scan_callback: Option) -> crate::Result { + let data_builder = DataBuilder::new(event_handler, config.compare_contents(), scan_callback); let poll_watcher = PollWatcher { watches: Default::default(),