cersei_tools/
file_watcher.rs1#[cfg(feature = "file-watch")]
4use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher};
5use parking_lot::Mutex;
6use std::path::{Path, PathBuf};
7use std::sync::Arc;
8
9#[derive(Debug, Clone, Default)]
11pub struct FileChangeTracker {
12 changed_files: Vec<PathBuf>,
13 max_tracked: usize,
14}
15
16impl FileChangeTracker {
17 pub fn new(max: usize) -> Self {
18 Self {
19 changed_files: Vec::new(),
20 max_tracked: max,
21 }
22 }
23
24 pub fn record_change(&mut self, path: PathBuf) {
25 if !self.changed_files.contains(&path) {
26 self.changed_files.push(path);
27 if self.changed_files.len() > self.max_tracked {
28 self.changed_files.remove(0);
29 }
30 }
31 }
32
33 pub fn drain(&mut self) -> Vec<PathBuf> {
34 std::mem::take(&mut self.changed_files)
35 }
36
37 pub fn recent(&self) -> &[PathBuf] {
38 &self.changed_files
39 }
40}
41
42#[cfg(feature = "file-watch")]
44pub fn watch_directory(
45 root: &Path,
46 tracker: Arc<Mutex<FileChangeTracker>>,
47) -> Option<RecommendedWatcher> {
48 let root = root.to_path_buf();
49 let mut watcher = notify::recommended_watcher(move |res: Result<Event, _>| {
50 if let Ok(event) = res {
51 for path in event.paths {
52 let path_str = path.display().to_string();
54 if path_str.contains("/.git/")
55 || path_str.contains("/target/")
56 || path_str.contains("/node_modules/")
57 || path_str.contains("/__pycache__/")
58 {
59 continue;
60 }
61 tracker.lock().record_change(path);
62 }
63 }
64 })
65 .ok()?;
66
67 watcher.watch(&root, RecursiveMode::Recursive).ok()?;
68 Some(watcher)
69}
70
71#[cfg(not(feature = "file-watch"))]
72pub fn watch_directory(_root: &Path, _tracker: Arc<Mutex<FileChangeTracker>>) -> Option<()> {
73 None
74}