objdiff_core/build/
watcher.rs1use std::{
2 fs,
3 path::{Path, PathBuf},
4 sync::{
5 Arc,
6 atomic::{AtomicBool, Ordering},
7 },
8 task::Waker,
9 time::Duration,
10};
11
12use globset::GlobSet;
13use notify::RecursiveMode;
14use notify_debouncer_full::{DebounceEventResult, new_debouncer_opt};
15
16pub type Watcher = notify_debouncer_full::Debouncer<
17 notify::RecommendedWatcher,
18 notify_debouncer_full::RecommendedCache,
19>;
20
21pub struct WatcherState {
22 pub config_path: Option<PathBuf>,
23 pub left_obj_path: Option<PathBuf>,
24 pub right_obj_path: Option<PathBuf>,
25 pub patterns: GlobSet,
26}
27
28pub fn create_watcher(
29 modified: Arc<AtomicBool>,
30 project_dir: &Path,
31 patterns: GlobSet,
32 ignore_patterns: GlobSet,
33 waker: Waker,
34) -> notify::Result<Watcher> {
35 let base_dir = fs::canonicalize(project_dir)?;
36 let base_dir_clone = base_dir.clone();
37 let timeout = Duration::from_millis(200);
38 let config = notify::Config::default().with_poll_interval(Duration::from_secs(2));
39 let mut debouncer = new_debouncer_opt(
40 timeout,
41 None,
42 move |result: DebounceEventResult| match result {
43 Ok(events) => {
44 let mut any_match = false;
45 for event in events.iter() {
46 if !matches!(
47 event.kind,
48 notify::EventKind::Modify(..)
49 | notify::EventKind::Create(..)
50 | notify::EventKind::Remove(..)
51 ) {
52 continue;
53 }
54 for path in &event.paths {
55 let Ok(path) = path.strip_prefix(&base_dir_clone) else {
56 continue;
57 };
58 if patterns.is_match(path) && !ignore_patterns.is_match(path) {
59 log::debug!("File modified: {}", path.display());
60 any_match = true;
61 }
62 }
63 }
64 if any_match {
65 modified.store(true, Ordering::Relaxed);
66 waker.wake_by_ref();
67 }
68 }
69 Err(errors) => errors.iter().for_each(|e| log::error!("Watch error: {e:?}")),
70 },
71 notify_debouncer_full::RecommendedCache::new(),
72 config,
73 )?;
74 debouncer.watch(base_dir, RecursiveMode::Recursive)?;
75 Ok(debouncer)
76}