Skip to content

Commit 5266e7b

Browse files
committed
Treat write-close watcher events as changes
1 parent dbcd781 commit 5266e7b

1 file changed

Lines changed: 54 additions & 1 deletion

File tree

src/engine.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::time::Duration;
88
use anyhow::{Result, anyhow};
99
use notify::{
1010
Config as NotifyConfig, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher,
11+
event::{AccessKind, AccessMode},
1112
};
1213
use serde_json::{Map, Value};
1314
use tokio::signal;
@@ -527,7 +528,15 @@ fn normalize_path(path: &Path) -> String {
527528
fn is_relevant_event(kind: &EventKind) -> bool {
528529
matches!(
529530
kind,
530-
EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) | EventKind::Any
531+
EventKind::Create(_)
532+
| EventKind::Modify(_)
533+
| EventKind::Remove(_)
534+
| EventKind::Any
535+
// Some backends collapse close-after-write saves into an imprecise close event,
536+
// so keep unknown close modes to avoid missing real file writes.
537+
| EventKind::Access(AccessKind::Close(
538+
AccessMode::Write | AccessMode::Any | AccessMode::Other
539+
))
531540
)
532541
}
533542

@@ -607,6 +616,50 @@ mod tests {
607616
assert_eq!(grouped["content"], vec!["watched.txt"]);
608617
}
609618

619+
#[test]
620+
fn classify_changes_by_workflow_accepts_write_close_access_events() {
621+
let root = PathBuf::from("/tmp/example");
622+
let groups =
623+
vec![CompiledWatchGroup::for_test(&["tailwind.css"], "css").expect("watch group")];
624+
let events = vec![
625+
Event {
626+
kind: EventKind::Access(AccessKind::Close(AccessMode::Write)),
627+
paths: vec![root.join("tailwind.css")],
628+
attrs: Default::default(),
629+
},
630+
Event {
631+
kind: EventKind::Access(AccessKind::Close(AccessMode::Any)),
632+
paths: vec![root.join("tailwind.css")],
633+
attrs: Default::default(),
634+
},
635+
Event {
636+
kind: EventKind::Access(AccessKind::Close(AccessMode::Other)),
637+
paths: vec![root.join("tailwind.css")],
638+
attrs: Default::default(),
639+
},
640+
];
641+
642+
let grouped = classify_events(&root, &groups, &events);
643+
644+
assert_eq!(grouped["css"], vec!["tailwind.css"]);
645+
}
646+
647+
#[test]
648+
fn classify_changes_by_workflow_rejects_read_close_access_events() {
649+
let root = PathBuf::from("/tmp/example");
650+
let groups =
651+
vec![CompiledWatchGroup::for_test(&["tailwind.css"], "css").expect("watch group")];
652+
let events = vec![Event {
653+
kind: EventKind::Access(AccessKind::Close(AccessMode::Read)),
654+
paths: vec![root.join("tailwind.css")],
655+
attrs: Default::default(),
656+
}];
657+
658+
let grouped = classify_events(&root, &groups, &events);
659+
660+
assert!(grouped.is_empty());
661+
}
662+
610663
#[tokio::test]
611664
async fn write_state_step_renders_session_template() {
612665
let state_path = unique_state_path();

0 commit comments

Comments
 (0)