diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bade001..c557d93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -241,17 +241,12 @@ jobs: - name: Build run: cmake --build build/release --parallel - # patch-efsw.cmake patch 2 fixed the FSEvents teardown abort (exit 134), - # so the whole FileWatcherTest suite no longer needs excluding — 8/9 pass - # on macOS (start/stop/create/modify/recursive/double-stop). - # One narrow exclusion remains: - # * DetectsFileDelete — efsw's FSEvents backend delivers an event on - # unlink but does not classify it as Action::Delete (its handleAddModDel - # gates Delete on flags&ItemRemoved && !exists; the real flag bits need - # observing on-device via efDEBUG). Create/Modify detection works. - # Tracked follow-up; not the teardown crash. + # Full unit suite, no exclusions. The FSEvents teardown abort is fixed + # (patch-efsw.cmake patch 2) and the macOS delete-detection gap is fixed + # in watcher.cpp: on_efsw_event now treats a vanished path as Remove + # regardless of the coalesced FSEvents label, so DetectsFileDelete passes. - name: Test (unit suite) - run: ./build/release/tests/lci_tests "--gtest_filter=-FileWatcherTest.DetectsFileDelete" + run: ./build/release/tests/lci_tests # --------------------------------------------------------------------------- # Benchmarks — self-hosted Linux, main only. Numbers go to the job log; no diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 639ae5d..388f480 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -179,12 +179,11 @@ jobs: - name: Build run: cmake --build build/release --parallel - # FSEvents teardown abort fixed by patch-efsw.cmake (drains+releases the - # dispatch queue on teardown). Only DetectsFileDelete stays excluded on - # macOS — efsw doesn't classify an FSEvents unlink as Action::Delete - # (tracked follow-up; see ci.yml macOS leg). + # Full unit suite, no exclusions — FSEvents teardown abort fixed in + # patch-efsw.cmake, and the delete-detection gap fixed in watcher.cpp + # (vanished path -> Remove regardless of the coalesced FSEvents label). - name: Test (unit suite) - run: ./build/release/tests/lci_tests "--gtest_filter=-FileWatcherTest.DetectsFileDelete" + run: ./build/release/tests/lci_tests - name: Package run: | diff --git a/src/indexing/watcher.cpp b/src/indexing/watcher.cpp index 3d28e08..567503f 100644 --- a/src/indexing/watcher.cpp +++ b/src/indexing/watcher.cpp @@ -202,12 +202,27 @@ void FileWatcher::on_efsw_event(const std::string& dir, if (!should_process_path(full_path)) return; + // Trust the filesystem over the backend's event label: a path that no + // longer exists is a removal. macOS FSEvents coalesces events and can hand + // us a Write/Create-labelled event for a file that was ultimately deleted, + // so the Remove would never surface otherwise. No-op on Linux/Windows, + // whose backends already label deletes (gone file -> Remove stays Remove). + if (type != FileEventType::Remove) { + std::error_code exist_ec; + if (!fs::exists(full_path, exist_ec)) { + type = FileEventType::Remove; + } + } + // Size cap: skip files exceeding max_file_size to match the prior - // behaviour (avoids re-indexing huge generated artefacts). - auto file_size = fs::file_size(full_path, ec); - if (!ec && file_size > - static_cast(config_.index.max_file_size)) { - return; + // behaviour (avoids re-indexing huge generated artefacts). A removed file + // has no size (file_size sets ec), so removals are never skipped here. + if (type != FileEventType::Remove) { + auto file_size = fs::file_size(full_path, ec); + if (!ec && file_size > + static_cast(config_.index.max_file_size)) { + return; + } } dispatch_event(full_path, type);