@@ -35,6 +35,9 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
35
35
36
36
StreamSubscription <List <FileSystemEvent >>? _subscription;
37
37
38
+ /// On MacOS only, whether the file existed on startup.
39
+ bool ? _existedAtStartup;
40
+
38
41
_NativeFileWatcher (this .path) {
39
42
_listen ();
40
43
@@ -43,21 +46,42 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
43
46
_readyCompleter.complete ();
44
47
}
45
48
46
- void _listen () {
49
+ void _listen () async {
50
+ var file = File (path);
51
+
47
52
// Batch the events together so that we can dedup them.
48
- _subscription = File (path)
49
- .watch ()
50
- .batchEvents ()
51
- .listen (_onBatch, onError: _eventsController.addError, onDone: _onDone);
53
+ var stream = file.watch ().batchEvents ();
54
+
55
+ if (Platform .isMacOS) {
56
+ var existedAtStartupFuture = file.exists ();
57
+ // Delay processing watch events until the existence check finishes.
58
+ stream = stream.asyncMap ((event) async {
59
+ _existedAtStartup ?? = await existedAtStartupFuture;
60
+ return event;
61
+ });
62
+ }
63
+
64
+ _subscription = stream.listen (_onBatch,
65
+ onError: _eventsController.addError, onDone: _onDone);
52
66
}
53
67
54
- void _onBatch (List <FileSystemEvent > batch) {
68
+ void _onBatch (List <FileSystemEvent > batch) async {
55
69
if (batch.any ((event) => event.type == FileSystemEvent .delete)) {
56
70
// If the file is deleted, the underlying stream will close. We handle
57
71
// emitting our own REMOVE event in [_onDone].
58
72
return ;
59
73
}
60
74
75
+ if (Platform .isMacOS) {
76
+ // On MacOS, a spurious `create` event can be received for a file that is
77
+ // created just before the `watch`. If the file existed at startup then it
78
+ // should be ignored.
79
+ if (_existedAtStartup! &&
80
+ batch.every ((event) => event.type == FileSystemEvent .create)) {
81
+ return ;
82
+ }
83
+ }
84
+
61
85
_eventsController.add (WatchEvent (ChangeType .MODIFY , path));
62
86
}
63
87
0 commit comments