Start watching a directory
(&self, path: &Path)
| 107 | |
| 108 | /// Start watching a directory |
| 109 | pub fn watch(&self, path: &Path) -> Result<(), WatcherError> { |
| 110 | if !path.exists() { |
| 111 | return Err(WatcherError::PathNotFound(path.to_path_buf())); |
| 112 | } |
| 113 | |
| 114 | if self.watched_paths.contains(path) { |
| 115 | return Err(WatcherError::AlreadyWatching(path.to_path_buf())); |
| 116 | } |
| 117 | |
| 118 | let event_tx = self.event_tx.clone(); |
| 119 | let ignore_patterns = self.ignore_patterns.clone(); |
| 120 | |
| 121 | let mut watcher = |
| 122 | notify::recommended_watcher(move |res: Result<Event, notify::Error>| match res { |
| 123 | Ok(event) => { |
| 124 | let file_event = match event.kind { |
| 125 | EventKind::Create(_) => FileEvent::Add, |
| 126 | EventKind::Modify(_) => FileEvent::Change, |
| 127 | EventKind::Remove(_) => FileEvent::Unlink, |
| 128 | _ => return, |
| 129 | }; |
| 130 | |
| 131 | for path in &event.paths { |
| 132 | let path_str = path.to_string_lossy(); |
| 133 | let should_ignore = ignore_patterns.iter().any(|p| p.matches(&path_str)); |
| 134 | |
| 135 | if should_ignore { |
| 136 | debug!(path = ?path, "Ignoring file event"); |
| 137 | continue; |
| 138 | } |
| 139 | |
| 140 | let watcher_event = WatcherEvent { |
| 141 | file: path.clone(), |
| 142 | event: file_event, |
| 143 | }; |
| 144 | |
| 145 | if let Err(e) = event_tx.send(watcher_event) { |
| 146 | warn!(error = %e, "Failed to send watcher event"); |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | Err(e) => { |
| 151 | error!(error = %e, "Watcher error"); |
| 152 | } |
| 153 | })?; |
| 154 | |
| 155 | watcher.configure( |
| 156 | Config::default().with_poll_interval(Duration::from_millis(self.debounce_ms)), |
| 157 | )?; |
| 158 | |
| 159 | let mode = if self.watched_paths.is_empty() { |
| 160 | RecursiveMode::Recursive |
| 161 | } else { |
| 162 | RecursiveMode::NonRecursive |
| 163 | }; |
| 164 | |
| 165 | watcher.watch(path, mode)?; |
| 166 |