Skip to content

Commit b92d4ac

Browse files
committed
Fix unwanted file modify event on MacOS on startup.
1 parent f15eb9d commit b92d4ac

File tree

4 files changed

+39
-17
lines changed

4 files changed

+39
-17
lines changed

pkgs/watcher/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 1.1.5-wip
2+
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.
7+
18
## 1.1.4
29

310
- Improve handling of subdirectories: ignore `PathNotFoundException` due to

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

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
3535

3636
StreamSubscription<List<FileSystemEvent>>? _subscription;
3737

38+
/// On MacOS only, whether the file existed on startup.
39+
bool? _existedAtStartup;
40+
3841
_NativeFileWatcher(this.path) {
3942
_listen();
4043

@@ -43,21 +46,42 @@ class _NativeFileWatcher implements FileWatcher, ManuallyClosedWatcher {
4346
_readyCompleter.complete();
4447
}
4548

46-
void _listen() {
49+
void _listen() async {
50+
var file = File(path);
51+
4752
// 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);
5266
}
5367

54-
void _onBatch(List<FileSystemEvent> batch) {
68+
void _onBatch(List<FileSystemEvent> batch) async {
5569
if (batch.any((event) => event.type == FileSystemEvent.delete)) {
5670
// If the file is deleted, the underlying stream will close. We handle
5771
// emitting our own REMOVE event in [_onDone].
5872
return;
5973
}
6074

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+
6185
_eventsController.add(WatchEvent(ChangeType.MODIFY, path));
6286
}
6387

pkgs/watcher/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: watcher
2-
version: 1.1.4
2+
version: 1.1.5-wip
33
description: >-
44
A file system watcher. It monitors changes to contents of directories and
55
sends notifications when files have been added, removed, or modified.

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)