Skip to content

Commit 84130f0

Browse files
committed
Fix unwanted file modify event on MacOS on startup.
1 parent 8e5f6ce commit 84130f0

File tree

3 files changed

+26
-12
lines changed

3 files changed

+26
-12
lines changed

pkgs/watcher/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## 1.1.4-wip
22

3+
- Bug fix: with `FileWatcher` on MacOS, a modify event was sometimes reported if
4+
the file was created immediately before the watcher was created. Now, if the
5+
file exists when the watcher is created then this create event is ignored,
6+
which matches the Linux native and polling (Windows) watchers.
37
- Improve handling of subdirectories: ignore `PathNotFoundException` due to
48
subdirectory deletion racing with watcher internals, instead of raising
59
it on the event stream.

pkgs/watcher/lib/src/file_watcher/native.dart

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
3434
final _readyCompleter = Completer<void>();
3535

3636
StreamSubscription<List<FileSystemEvent>>? _subscription;
37+
Future<bool>? _existedAtStartupFuture;
38+
bool? _existedAtStartup;
3739

3840
_NativeFileWatcher(this.path) {
3941
_listen();
@@ -44,20 +46,37 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
4446
}
4547

4648
void _listen() {
49+
var file = File(path);
50+
4751
// Batch the events together so that we can dedup them.
48-
_subscription = File(path)
52+
_subscription = file
4953
.watch()
5054
.batchEvents()
5155
.listen(_onBatch, onError: _eventsController.addError, onDone: _onDone);
56+
57+
// On MacOS events can arrive from file changes before the `watch`. Check
58+
// existence on startup to differentiate creation before and after the
59+
// `watch`.
60+
if (Platform.isMacOS) _existedAtStartupFuture = file.exists();
5261
}
5362

54-
void _onBatch(List<FileSystemEvent> batch) {
63+
void _onBatch(List<FileSystemEvent> batch) async {
5564
if (batch.any((event) => event.type == FileSystemEvent.delete)) {
5665
// If the file is deleted, the underlying stream will close. We handle
5766
// emitting our own REMOVE event in [_onDone].
5867
return;
5968
}
6069

70+
if (Platform.isMacOS) {
71+
var existedAtStartup =
72+
_existedAtStartup ??= await _existedAtStartupFuture!;
73+
if (existedAtStartup &&
74+
batch.every((event) => event.type == FileSystemEvent.create)) {
75+
// It's a create event from before `watch` was called, ignore it.
76+
return;
77+
}
78+
}
79+
6180
_eventsController.add(WatchEvent(ChangeType.MODIFY, path));
6281
}
6382

pkgs/watcher/test/file_watcher/startup_race_tests.dart

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'dart:io';
6-
75
import 'package:test/test.dart';
86

97
import '../utils.dart';
@@ -27,13 +25,6 @@ void startupRaceTests({required bool isNative}) {
2725
);
2826
}
2927
await Future.wait(futures);
30-
31-
// TODO(davidmorgan): the MacOS watcher currently does get unwanted events,
32-
// fix it.
33-
if (isNative && Platform.isMacOS) {
34-
expect(events, greaterThan(50));
35-
} else {
36-
expect(events, 0);
37-
}
28+
expect(events, 0);
3829
});
3930
}

0 commit comments

Comments
 (0)