Index: pkg/watcher/lib/src/directory_watcher/mac_os.dart |
diff --git a/pkg/watcher/lib/src/directory_watcher/mac_os.dart b/pkg/watcher/lib/src/directory_watcher/mac_os.dart |
index 5b1feb342f2a220316c339af1e01dd8a3f6eba23..7055c400b285c8071a59c4bc027864228cfe9e2c 100644 |
--- a/pkg/watcher/lib/src/directory_watcher/mac_os.dart |
+++ b/pkg/watcher/lib/src/directory_watcher/mac_os.dart |
@@ -21,8 +21,8 @@ import 'resubscribable.dart'; |
/// succession, it won't report them in the order they occurred. See issue |
/// 14373. |
/// |
-/// This also works around issues 14793, 14806, and 14849 in the implementation |
-/// of [Directory.watch]. |
+/// This also works around issues 15458 and 14849 in the implementation of |
+/// [Directory.watch]. |
class MacOSDirectoryWatcher extends ResubscribableDirectoryWatcher { |
MacOSDirectoryWatcher(String directory) |
: super(directory, () => new _MacOSDirectoryWatcher(directory)); |
@@ -104,11 +104,18 @@ class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher { |
for (var event in events) { |
if (event is FileSystemCreateEvent) { |
if (!event.isDirectory) { |
+ // Don't emit ADD events for files or directories that we already |
+ // know about. Such an event comes from FSEvents reporting an add |
+ // that happened prior to the watch beginning. |
+ if (_files.contains(path)) continue; |
+ |
_emitEvent(ChangeType.ADD, path); |
_files.add(path); |
continue; |
} |
+ if (_files.containsDir(path)) continue; |
+ |
_listen(new Directory(path).list(recursive: true), (entity) { |
if (entity is Directory) return; |
_emitEvent(ChangeType.ADD, entity.path); |
@@ -161,34 +168,12 @@ class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher { |
set.add(event); |
} |
- for (var event in batch.where((event) => event is! FileSystemMoveEvent)) { |
+ for (var event in batch) { |
+ // The Mac OS watcher doesn't emit move events. See issue 14806. |
+ assert(event is! FileSystemMoveEvent); |
addEvent(event.path, event); |
} |
- // Issue 14806 means that move events can be misleading if they're in the |
- // same batch as another modification of a related file. If they are, we |
- // make the event set empty to ensure we check the state of the filesystem. |
- // Otherwise, treat them as a DELETE followed by an ADD. |
- for (var event in batch.where((event) => event is FileSystemMoveEvent)) { |
- if (eventsForPaths.containsKey(event.path) || |
- eventsForPaths.containsKey(event.destination)) { |
- |
- if (!isInModifiedDirectory(event.path)) { |
- eventsForPaths[event.path] = new Set(); |
- } |
- if (!isInModifiedDirectory(event.destination)) { |
- eventsForPaths[event.destination] = new Set(); |
- } |
- |
- continue; |
- } |
- |
- addEvent(event.path, new ConstructableFileSystemDeleteEvent( |
- event.path, event.isDirectory)); |
- addEvent(event.destination, new ConstructableFileSystemCreateEvent( |
- event.path, event.isDirectory)); |
- } |
- |
return eventsForPaths; |
} |
@@ -209,6 +194,7 @@ class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher { |
var type = batch.first.type; |
var isDir = batch.first.isDirectory; |
+ var hadModifyEvent = false; |
for (var event in batch.skip(1)) { |
// If one event reports that the file is a directory and another event |
@@ -219,7 +205,10 @@ class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher { |
// safely assume the file was modified after a CREATE or before the |
// REMOVE; otherwise there will also be a REMOVE or CREATE event |
// (respectively) that will be contradictory. |
- if (event is FileSystemModifyEvent) continue; |
+ if (event is FileSystemModifyEvent) { |
+ hadModifyEvent = true; |
+ continue; |
+ } |
assert(event is FileSystemCreateEvent || event is FileSystemDeleteEvent); |
// If we previously thought this was a MODIFY, we now consider it to be a |
@@ -234,13 +223,23 @@ class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher { |
if (type != event.type) return null; |
} |
+ // If we got a CREATE event for a file we already knew about, that comes |
+ // from FSEvents reporting an add that happened prior to the watch |
+ // beginning. If we also received a MODIFY event, we want to report that, |
+ // but not the CREATE. |
+ if (type == FileSystemEvent.CREATE && hadModifyEvent && |
+ _files.contains(batch.first.path)) { |
+ type = FileSystemEvent.MODIFY; |
+ } |
+ |
switch (type) { |
case FileSystemEvent.CREATE: |
- // Issue 14793 means that CREATE events can actually mean DELETE, so we |
- // should always check the filesystem for them. |
- return null; |
+ return new ConstructableFileSystemCreateEvent(batch.first.path, isDir); |
case FileSystemEvent.DELETE: |
- return new ConstructableFileSystemDeleteEvent(batch.first.path, isDir); |
+ // Issue 15458 means that DELETE events for directories can actually |
+ // mean CREATE, so we always check the filesystem for them. |
+ if (isDir) return null; |
+ return new ConstructableFileSystemCreateEvent(batch.first.path, false); |
case FileSystemEvent.MODIFY: |
return new ConstructableFileSystemModifyEvent( |
batch.first.path, isDir, false); |
@@ -325,11 +324,6 @@ class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher { |
void _emitEvent(ChangeType type, String path) { |
if (!isReady) return; |
- // Don't emit ADD events for files that we already know about. Such an event |
- // probably comes from FSEvents reporting an add that happened prior to the |
- // watch beginning. |
- if (type == ChangeType.ADD && _files.contains(path)) return; |
- |
_eventsController.add(new WatchEvent(type, path)); |
} |