Skip to content

Commit d20c578

Browse files
committed
Normalize macOS notify paths for watch matching
1 parent e139ec0 commit d20c578

2 files changed

Lines changed: 33 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ All notable changes to `devloop` will be recorded in this file.
55
## [Unreleased]
66

77
### Fixed
8+
- Accepted macOS `notify` event paths reported under `/private/...`
9+
for watched roots configured under `/var/...`, so file changes in
10+
temp directories are no longer dropped by the watch classifier.
811
- Made the CI smoke test wait for file watching to start before editing
912
the watched fixture file, and retry the watched write until the state
1013
change is observed, avoiding startup races on macOS runners.

src/engine.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ fn classify_events(
409409
continue;
410410
}
411411
for path in &event.paths {
412-
let Ok(relative) = path.strip_prefix(root) else {
412+
let Some(relative) = relativize_event_path(root, path) else {
413413
continue;
414414
};
415415
for group in watch_groups {
@@ -428,6 +428,17 @@ fn classify_events(
428428
.collect()
429429
}
430430

431+
fn relativize_event_path<'a>(root: &'a Path, path: &'a Path) -> Option<&'a Path> {
432+
path.strip_prefix(root)
433+
.ok()
434+
.or_else(|| strip_private_prefix_variant(root, path))
435+
}
436+
437+
fn strip_private_prefix_variant<'a>(root: &'a Path, path: &'a Path) -> Option<&'a Path> {
438+
let private_root = Path::new("/private").join(root.strip_prefix("/").ok()?);
439+
path.strip_prefix(&private_root).ok()
440+
}
441+
431442
fn normalize_path(path: &Path) -> String {
432443
path.components()
433444
.map(|component| component.as_os_str().to_string_lossy())
@@ -484,6 +495,24 @@ mod tests {
484495
assert_eq!(grouped["content"], vec!["content/posts/example.md"]);
485496
}
486497

498+
#[test]
499+
fn classify_changes_by_workflow_accepts_private_var_event_paths() {
500+
let root = PathBuf::from("/var/folders/example/tmp");
501+
let groups =
502+
vec![CompiledWatchGroup::for_test(&["watched.txt"], "content").expect("watch group")];
503+
let events = vec![Event {
504+
kind: EventKind::Modify(ModifyKind::Any),
505+
paths: vec![PathBuf::from(
506+
"/private/var/folders/example/tmp/watched.txt",
507+
)],
508+
attrs: Default::default(),
509+
}];
510+
511+
let grouped = classify_events(&root, &groups, &events);
512+
513+
assert_eq!(grouped["content"], vec!["watched.txt"]);
514+
}
515+
487516
#[tokio::test]
488517
async fn write_state_step_renders_session_template() {
489518
let state_path = unique_state_path();

0 commit comments

Comments
 (0)