List directory failure (#2151)
diff --git a/pkgs/watcher/CHANGELOG.md b/pkgs/watcher/CHANGELOG.md index b4727e5..30a1975 100644 --- a/pkgs/watcher/CHANGELOG.md +++ b/pkgs/watcher/CHANGELOG.md
@@ -1,10 +1,12 @@ -## 1.1.3-wip +## 1.1.3 - Improve handling of `FileSystemException: Directory watcher closed unexpectedly` on Windows. The watcher was already attempting to restart after this error and resume sending events. But, the restart would sometimes silently fail. Now, it is more reliable. +- Improving handling of directories that are created then immediately deleted on + Windows. Previously, that could cause a `PathNotfoundException` to be thrown. ## 1.1.2
diff --git a/pkgs/watcher/lib/src/directory_watcher/windows.dart b/pkgs/watcher/lib/src/directory_watcher/windows.dart index 6d88e65..8f21268 100644 --- a/pkgs/watcher/lib/src/directory_watcher/windows.dart +++ b/pkgs/watcher/lib/src/directory_watcher/windows.dart
@@ -198,7 +198,14 @@ }); subscription.onError((Object e, StackTrace stackTrace) { _listSubscriptions.remove(subscription); - _emitError(e, stackTrace); + // "Path not found" can be caused by creating then quickly removing + // a directory: continue without reporting an error. Nested files + // that get removed during the `list` are already ignored by `list` + // itself, so there are no other types of "path not found" that + // might need different handling here. + if (e is! PathNotFoundException) { + _emitError(e, stackTrace); + } }); _listSubscriptions.add(subscription); } else if (event is FileSystemModifyEvent) {
diff --git a/pkgs/watcher/pubspec.yaml b/pkgs/watcher/pubspec.yaml index bccdfac..16af27b 100644 --- a/pkgs/watcher/pubspec.yaml +++ b/pkgs/watcher/pubspec.yaml
@@ -1,5 +1,5 @@ name: watcher -version: 1.1.3-wip +version: 1.1.3 description: >- A file system watcher. It monitors changes to contents of directories and sends notifications when files have been added, removed, or modified.
diff --git a/pkgs/watcher/test/directory_watcher/windows_test.dart b/pkgs/watcher/test/directory_watcher/windows_test.dart index a6bc14d..6489771 100644 --- a/pkgs/watcher/test/directory_watcher/windows_test.dart +++ b/pkgs/watcher/test/directory_watcher/windows_test.dart
@@ -66,6 +66,52 @@ }, ); + // Regression test for https://github.com/dart-lang/tools/issues/2152: + // watcher can throws if a directory is created then quickly deleted. + group('Transient directory', () { + late StreamSubscription<Object> subscription; + late Directory temp; + late Watcher watcher; + late int errorsSeen; + + setUp(() async { + temp = Directory.systemTemp.createTempSync(); + watcher = DirectoryWatcher(temp.path); + errorsSeen = 0; + subscription = watcher.events.listen( + (e) {}, + onError: (Object e, _) { + print('Event stream error: $e'); + ++errorsSeen; + }, + ); + await watcher.ready; + }); + + tearDown(() { + subscription.cancel(); + }); + + test('does not break watching', () async { + // Iterate creating 10 directories and deleting 1-10 of them. This means + // the directories will exist for different lengths of times, exploring + // possible race conditions in directory handling. + for (var i = 0; i != 50; ++i) { + for (var j = 0; j != 10; ++j) { + File('${temp.path}\\$j\\file').createSync(recursive: true); + } + await Future<void>.delayed(const Duration(milliseconds: 1)); + for (var j = 0; j != i % 10 + 1; ++j) { + final d = Directory('${temp.path}\\$j'); + d.deleteSync(recursive: true); + } + await Future<void>.delayed(const Duration(milliseconds: 1)); + } + + expect(errorsSeen, 0); + }); + }); + // The Windows native watcher has a buffer that gets exhausted if events are // not handled quickly enough. Then, it throws an error and stops watching. // The exhaustion is reliably triggered if enough events arrive during a sync