Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Side by Side Diff: pkg/watcher/lib/src/directory_watcher/mac_os.dart

Issue 670653003: Revert "Mac no longer fire bogus events. Fix Mac watcher." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/watcher/CHANGELOG.md ('k') | pkg/watcher/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library watcher.directory_watcher.mac_os; 5 library watcher.directory_watcher.mac_os;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:io'; 8 import 'dart:io';
9 9
10 import 'package:path/path.dart' as p; 10 import 'package:path/path.dart' as p;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 StreamSubscription<FileSystemEvent> _watchSubscription; 66 StreamSubscription<FileSystemEvent> _watchSubscription;
67 67
68 /// The subscription to the [Directory.list] call for the initial listing of 68 /// The subscription to the [Directory.list] call for the initial listing of
69 /// the directory to determine its initial state. 69 /// the directory to determine its initial state.
70 StreamSubscription<FileSystemEntity> _initialListSubscription; 70 StreamSubscription<FileSystemEntity> _initialListSubscription;
71 71
72 /// The subscription to the [Directory.list] call for listing the contents of 72 /// The subscription to the [Directory.list] call for listing the contents of
73 /// a subdirectory that was moved into the watched directory. 73 /// a subdirectory that was moved into the watched directory.
74 StreamSubscription<FileSystemEntity> _listSubscription; 74 StreamSubscription<FileSystemEntity> _listSubscription;
75 75
76 /// The timer for tracking how long we wait for an initial batch of bogus
77 /// events (see issue 14373).
78 Timer _bogusEventTimer;
79
76 _MacOSDirectoryWatcher(String directory, int parentId) 80 _MacOSDirectoryWatcher(String directory, int parentId)
77 : directory = directory, 81 : directory = directory,
78 _files = new PathSet(directory), 82 _files = new PathSet(directory),
79 _id = "$parentId/${_count++}" { 83 _id = "$parentId/${_count++}" {
80 _listDir().then((_) { 84 _startWatch();
81 if (MacOSDirectoryWatcher.logDebugInfo) { 85
82 print("[$_id] finished initial directory list"); 86 // Before we're ready to emit events, wait for [_listDir] to complete and
83 } 87 // for enough time to elapse that if bogus events (issue 14373) would be
84 _startWatch(); 88 // emitted, they will be.
89 //
90 // If we do receive a batch of events, [_onBatch] will ensure that these
91 // futures don't fire and that the directory is re-listed.
92 Future.wait([
93 _listDir().then((_) {
94 if (MacOSDirectoryWatcher.logDebugInfo) {
95 print("[$_id] finished initial directory list");
96 }
97 }),
98 _waitForBogusEvents()
99 ]).then((_) {
85 if (MacOSDirectoryWatcher.logDebugInfo) { 100 if (MacOSDirectoryWatcher.logDebugInfo) {
86 print("[$_id] watcher is ready, known files:"); 101 print("[$_id] watcher is ready, known files:");
87 for (var file in _files.toSet()) { 102 for (var file in _files.toSet()) {
88 print("[$_id] ${p.relative(file, from: directory)}"); 103 print("[$_id] ${p.relative(file, from: directory)}");
89 } 104 }
90 } 105 }
91 _readyCompleter.complete(); 106 _readyCompleter.complete();
92 }); 107 });
93 } 108 }
94 109
(...skipping 17 matching lines...) Expand all
112 for (var event in batch) { 127 for (var event in batch) {
113 print("[$_id] ${_formatEvent(event)}"); 128 print("[$_id] ${_formatEvent(event)}");
114 } 129 }
115 130
116 print("[$_id] known files:"); 131 print("[$_id] known files:");
117 for (var file in _files.toSet()) { 132 for (var file in _files.toSet()) {
118 print("[$_id] ${p.relative(file, from: directory)}"); 133 print("[$_id] ${p.relative(file, from: directory)}");
119 } 134 }
120 } 135 }
121 136
137 // If we get a batch of events before we're ready to begin emitting events,
138 // it's probable that it's a batch of pre-watcher events (see issue 14373).
139 // Ignore those events and re-list the directory.
140 if (!isReady) {
141 if (MacOSDirectoryWatcher.logDebugInfo) {
142 print("[$_id] not ready to emit events, re-listing directory");
143 }
144
145 // Cancel the timer because bogus events only occur in the first batch, so
146 // we can fire [ready] as soon as we're done listing the directory.
147 _bogusEventTimer.cancel();
148 _listDir().then((_) {
149 if (MacOSDirectoryWatcher.logDebugInfo) {
150 print("[$_id] watcher is ready, known files:");
151 for (var file in _files.toSet()) {
152 print("[$_id] ${p.relative(file, from: directory)}");
153 }
154 }
155 _readyCompleter.complete();
156 });
157 return;
158 }
159
122 _sortEvents(batch).forEach((path, events) { 160 _sortEvents(batch).forEach((path, events) {
123 var relativePath = p.relative(path, from: directory); 161 var relativePath = p.relative(path, from: directory);
124 if (MacOSDirectoryWatcher.logDebugInfo) { 162 if (MacOSDirectoryWatcher.logDebugInfo) {
125 print("[$_id] events for $relativePath:"); 163 print("[$_id] events for $relativePath:");
126 for (var event in events) { 164 for (var event in events) {
127 print("[$_id] ${_formatEvent(event)}"); 165 print("[$_id] ${_formatEvent(event)}");
128 } 166 }
129 } 167 }
130 168
131 var canonicalEvent = _canonicalEvent(events); 169 var canonicalEvent = _canonicalEvent(events);
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 385
348 return events; 386 return events;
349 } 387 }
350 388
351 /// The callback that's run when the [Directory.watch] stream is closed. 389 /// The callback that's run when the [Directory.watch] stream is closed.
352 void _onDone() { 390 void _onDone() {
353 if (MacOSDirectoryWatcher.logDebugInfo) print("[$_id] stream closed"); 391 if (MacOSDirectoryWatcher.logDebugInfo) print("[$_id] stream closed");
354 392
355 _watchSubscription = null; 393 _watchSubscription = null;
356 394
395 // If the directory still exists and we're still expecting bogus events,
396 // this is probably issue 14849 rather than a real close event. We should
397 // just restart the watcher.
398 if (!isReady && new Directory(directory).existsSync()) {
399 if (MacOSDirectoryWatcher.logDebugInfo) {
400 print("[$_id] fake closure (issue 14849), re-opening stream");
401 }
402 _startWatch();
403 return;
404 }
405
357 // FSEvents can fail to report the contents of the directory being removed 406 // FSEvents can fail to report the contents of the directory being removed
358 // when the directory itself is removed, so we need to manually mark the 407 // when the directory itself is removed, so we need to manually mark the
359 // files as removed. 408 // files as removed.
360 for (var file in _files.toSet()) { 409 for (var file in _files.toSet()) {
361 _emitEvent(ChangeType.REMOVE, file); 410 _emitEvent(ChangeType.REMOVE, file);
362 } 411 }
363 _files.clear(); 412 _files.clear();
364 close(); 413 close();
365 } 414 }
366 415
(...skipping 19 matching lines...) Expand all
386 var stream = Chain.track(new Directory(directory).list(recursive: true)); 435 var stream = Chain.track(new Directory(directory).list(recursive: true));
387 _initialListSubscription = stream.listen((entity) { 436 _initialListSubscription = stream.listen((entity) {
388 if (entity is! Directory) _files.add(entity.path); 437 if (entity is! Directory) _files.add(entity.path);
389 }, 438 },
390 onError: _emitError, 439 onError: _emitError,
391 onDone: completer.complete, 440 onDone: completer.complete,
392 cancelOnError: true); 441 cancelOnError: true);
393 return completer.future; 442 return completer.future;
394 } 443 }
395 444
445 /// Wait 200ms for a batch of bogus events (issue 14373) to come in.
446 ///
447 /// 200ms is short in terms of human interaction, but longer than any Mac OS
448 /// watcher tests take on the bots, so it should be safe to assume that any
449 /// bogus events will be signaled in that time frame.
450 Future _waitForBogusEvents() {
451 var completer = new Completer();
452 _bogusEventTimer = new Timer(
453 new Duration(milliseconds: 200),
454 completer.complete);
455 return completer.future;
456 }
457
396 /// Emit an event with the given [type] and [path]. 458 /// Emit an event with the given [type] and [path].
397 void _emitEvent(ChangeType type, String path) { 459 void _emitEvent(ChangeType type, String path) {
398 if (!isReady) return; 460 if (!isReady) return;
399 461
400 if (MacOSDirectoryWatcher.logDebugInfo) { 462 if (MacOSDirectoryWatcher.logDebugInfo) {
401 print("[$_id] emitting $type ${p.relative(path, from: directory)}"); 463 print("[$_id] emitting $type ${p.relative(path, from: directory)}");
402 } 464 }
403 465
404 _eventsController.add(new WatchEvent(type, path)); 466 _eventsController.add(new WatchEvent(type, path));
405 } 467 }
(...skipping 20 matching lines...) Expand all
426 } else if (event is FileSystemDeleteEvent) { 488 } else if (event is FileSystemDeleteEvent) {
427 return "delete $type $path"; 489 return "delete $type $path";
428 } else if (event is FileSystemModifyEvent) { 490 } else if (event is FileSystemModifyEvent) {
429 return "modify $type $path"; 491 return "modify $type $path";
430 } else if (event is FileSystemMoveEvent) { 492 } else if (event is FileSystemMoveEvent) {
431 return "move $type $path to " 493 return "move $type $path to "
432 "${p.relative(event.destination, from: directory)}"; 494 "${p.relative(event.destination, from: directory)}";
433 } 495 }
434 } 496 }
435 } 497 }
OLDNEW
« no previous file with comments | « pkg/watcher/CHANGELOG.md ('k') | pkg/watcher/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698