Clean up the Windows watcher. BUG= R=rnystrom@google.com Review URL: https://codereview.chromium.org//313353003 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/watcher@37159 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkgs/watcher/lib/src/directory_watcher/windows.dart b/pkgs/watcher/lib/src/directory_watcher/windows.dart index ddcf897..4f41d33 100644 --- a/pkgs/watcher/lib/src/directory_watcher/windows.dart +++ b/pkgs/watcher/lib/src/directory_watcher/windows.dart
@@ -28,11 +28,8 @@ final List<FileSystemEvent> events = []; Timer timer; - void addEvent(FileSystemEvent event) { + void addEvent(FileSystemEvent event, void callback()) { events.add(event); - } - - void startTimer(void callback()) { if (timer != null) { timer.cancel(); } @@ -78,18 +75,19 @@ /// the directory to determine its initial state. StreamSubscription<FileSystemEntity> _initialListSubscription; - /// The subscriptions to the [Directory.list] call for listing the contents of - /// subdirectories that was moved into the watched directory. + /// The subscriptions to the [Directory.list] calls for listing the contents + /// of subdirectories that were moved into the watched directory. final Set<StreamSubscription<FileSystemEntity>> _listSubscriptions = new HashSet<StreamSubscription<FileSystemEntity>>(); _WindowsDirectoryWatcher(String directory) : directory = directory, _files = new PathSet(directory) { - _startWatch(); - _startParentWatcher(); - // Before we're ready to emit events, wait for [_listDir] to complete. - _listDir().then(_readyCompleter.complete); + _listDir().then((_) { + _startWatch(); + _startParentWatcher(); + _readyCompleter.complete(); + }); } void close() { @@ -111,13 +109,13 @@ } /// On Windows, if [directory] is deleted, we will not receive any event. + /// /// Instead, we add a watcher on the parent folder (if any), that can notify - /// us about [directory]. - /// This also includes events such as moves. + /// us about [directory]. This also includes events such as moves. void _startParentWatcher() { var absoluteDir = p.absolute(directory); var parent = p.dirname(absoluteDir); - // Check if we [directory] is already the root directory. + // Check if [directory] is already the root directory. if (FileSystemEntity.identicalSync(parent, directory)) return; var parentStream = Chain.track( new Directory(parent).watch(recursive: false)); @@ -140,26 +138,19 @@ close(); } }, onError: (error) { - // Ignore errors, simply close the stream. + // Ignore errors, simply close the stream. The user listens on + // [directory], and while it can fail to listen on the parent, we may + // still be able to listen on the path requested. _parentWatchSubscription.cancel(); _parentWatchSubscription = null; }); } void _onEvent(FileSystemEvent event) { - // If we get a event before we're ready to begin emitting events, - // ignore those events and re-list the directory. - if (!isReady) { - _listDir().then((_) { - _readyCompleter.complete(); - }); - return; - } - - _EventBatcher batcher = _eventBatchers.putIfAbsent( + assert(isReady); + final batcher = _eventBatchers.putIfAbsent( event.path, () => new _EventBatcher()); - batcher.addEvent(event); - batcher.startTimer(() { + batcher.addEvent(event, () { _eventBatchers.remove(event.path); _onBatch(batcher.events); }); @@ -246,8 +237,7 @@ for (var event in batch) { if (event is FileSystemMoveEvent) { - FileSystemMoveEvent moveEvent = event; - addEvent(moveEvent.destination, event); + addEvent(event.destination, event); } addEvent(event.path, event); } @@ -366,7 +356,7 @@ void _onDone() { _watchSubscription = null; - // Emit remove-events for any remaining files. + // Emit remove events for any remaining files. for (var file in _files.toSet()) { _emitEvent(ChangeType.REMOVE, file); } @@ -376,7 +366,7 @@ /// Start or restart the underlying [Directory.watch] stream. void _startWatch() { - // Batch the events changes together so that we can dedup events. + // Batch the events together so that we can dedup events. var innerStream = Chain.track(new Directory(directory).watch(recursive: true)); _watchSubscription = innerStream.listen(_onEvent,
diff --git a/pkgs/watcher/test/directory_watcher/shared.dart b/pkgs/watcher/test/directory_watcher/shared.dart index 849cea0..d3575ea 100644 --- a/pkgs/watcher/test/directory_watcher/shared.dart +++ b/pkgs/watcher/test/directory_watcher/shared.dart
@@ -78,6 +78,20 @@ ]); }); + test('when the watched directory is moved, removes all files', () { + writeFile("dir/a.txt"); + writeFile("dir/b.txt"); + + startWatcher(dir: "dir"); + + renameDir("dir", "moved_dir"); + createDir("dir"); + inAnyOrder([ + isRemoveEvent("dir/a.txt"), + isRemoveEvent("dir/b.txt") + ]); + }); + group("moves", () { test('notifies when a file is moved within the watched directory', () { writeFile("old.txt");
diff --git a/pkgs/watcher/test/directory_watcher/windows_test.dart b/pkgs/watcher/test/directory_watcher/windows_test.dart index 3e9a854..6bfb88b 100644 --- a/pkgs/watcher/test/directory_watcher/windows_test.dart +++ b/pkgs/watcher/test/directory_watcher/windows_test.dart
@@ -23,19 +23,5 @@ expect(new DirectoryWatcher('.'), new isInstanceOf<WindowsDirectoryWatcher>()); }); - - test('when the watched directory is moved, removes all files', () { - writeFile("dir/a.txt"); - writeFile("dir/b.txt"); - - startWatcher(dir: "dir"); - - renameDir("dir", "moved_dir"); - createDir("dir"); - inAnyOrder([ - isRemoveEvent("dir/a.txt"), - isRemoveEvent("dir/b.txt") - ]); - }); }