Skip to content

Commit f0374d1

Browse files
committed
Fix MacOS watch issue with same name directory deletes.
1 parent 9480d20 commit f0374d1

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

pkgs/watcher/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
various situations involving subdirectory moves.
4040
- Bug fix: with `DirectoryWatcher` on MacOS, fix events for changes in new
4141
directories: don't emit duplicate ADD, don't emit MODIFY without ADD.
42+
- Bug fix: with `DirectoryWatcher` on MacOS, fix handling of repeated deletes
43+
of a directory with the same name in a short space of time.
4244
- Bug fix: with `FileWatcher` on MacOS, a modify event was sometimes reported if
4345
the file was created immediately before the watcher was created. Now, if the
4446
file exists when the watcher is created then this modify event is not sent.

pkgs/watcher/lib/src/directory_watcher/mac_os.dart

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,18 +195,23 @@ class _MacOSDirectoryWatcher
195195
batch = batch.where((event) => event.path != path).toList();
196196

197197
// Events within directories that already have create events are not needed
198-
// as the directory's full content will be listed.
199-
var createdDirectories = unionAll(batch.map((event) {
200-
return event.type == EventType.createDirectory
198+
// as the directory's full content will be listed. And, events that are
199+
// under direcory deletes are not needed as all files are removed.
200+
var ignoredPaths = unionAll(batch.map((event) {
201+
return event.type == EventType.createDirectory ||
202+
// Events don't distinguish file deletes from directory deletes,
203+
// but that doesn't matter here as deleted files will not match
204+
// as the parent directory of any file.
205+
event.type == EventType.delete
201206
? {event.path}
202207
: const <String>{};
203208
}));
204209

205-
bool isInCreatedDirectory(String path) =>
206-
createdDirectories.any((dir) => path != dir && p.isWithin(dir, path));
210+
bool isUnderDeleteOrDirectoryCreate(String path) =>
211+
ignoredPaths.any((dir) => path != dir && p.isWithin(dir, path));
207212

208213
void addEvent(String path, Event event) {
209-
if (isInCreatedDirectory(path)) return;
214+
if (isUnderDeleteOrDirectoryCreate(path)) return;
210215
eventsForPaths.putIfAbsent(path, () => <Event>{}).add(event);
211216
}
212217

pkgs/watcher/test/directory_watcher/file_tests.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,25 @@ void _fileTests({required bool isNative}) {
471471
await expectNoEvents();
472472
});
473473

474+
test('multiple deletes order is respected', () async {
475+
createDir('watched');
476+
writeFile('a/1');
477+
writeFile('b/1');
478+
479+
await startWatcher(path: 'watched');
480+
481+
renameDir('a', 'watched/x');
482+
renameDir('watched/x', 'a');
483+
renameDir('b', 'watched/x');
484+
writeFile('watched/x/1', contents: 'updated');
485+
// This is a "duplicate" delete of x, but it's not the same delete and the
486+
// watcher needs to notice that it happens after the update to x/1 so
487+
// there is no file left behind.
488+
renameDir('watched/x', 'b');
489+
490+
await expectNoEvents();
491+
});
492+
474493
test('subdirectory watching is robust against races', () async {
475494
// Make sandboxPath accessible to child isolates created by Isolate.run.
476495
final sandboxPath = d.sandbox;

0 commit comments

Comments
 (0)