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")

-    ]);

-  });

 }