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

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

Issue 64383004: Re-mark directory_watcher/mac_os_test as passing. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 1 month 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/pkg.status ('k') | pkg/watcher/test/utils.dart » ('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;
11 11
12 import '../constructable_file_system_event.dart'; 12 import '../constructable_file_system_event.dart';
13 import '../path_set.dart'; 13 import '../path_set.dart';
14 import '../utils.dart'; 14 import '../utils.dart';
15 import '../watch_event.dart'; 15 import '../watch_event.dart';
16 import 'resubscribable.dart'; 16 import 'resubscribable.dart';
17 17
18 /// Uses the FSEvents subsystem to watch for filesystem events. 18 /// Uses the FSEvents subsystem to watch for filesystem events.
19 /// 19 ///
20 /// FSEvents has two main idiosyncrasies that this class works around. First, it 20 /// FSEvents has two main idiosyncrasies that this class works around. First, it
21 /// will occasionally report events that occurred before the filesystem watch 21 /// will occasionally report events that occurred before the filesystem watch
22 /// was initiated. Second, if multiple events happen to the same file in close 22 /// was initiated. Second, if multiple events happen to the same file in close
23 /// succession, it won't report them in the order they occurred. See issue 23 /// succession, it won't report them in the order they occurred. See issue
24 /// 14373. 24 /// 14373.
25 /// 25 ///
26 /// This also works around issues 14793, 14806, and 14849 in the implementation 26 /// This also works around issues 14793, 14806, and 14849 in the implementation
27 /// of [Directory.watch]. 27 /// of [Directory.watch].
28 class MacOSDirectoryWatcher extends ResubscribableDirectoryWatcher { 28 class MacOSDirectoryWatcher extends ResubscribableDirectoryWatcher {
29 // TODO(nweiz): remove this when issue 15042 is fixed. 29 // TODO(nweiz): remove these when issue 15042 is fixed.
30 static bool logDebugInfo = false; 30 static var logDebugInfo = false;
31 static var _count = 0;
32 final int _id;
31 33
32 MacOSDirectoryWatcher(String directory) 34 MacOSDirectoryWatcher(String directory)
33 : super(directory, () => new _MacOSDirectoryWatcher(directory)); 35 : _id = _count++,
36 super(directory, () => new _MacOSDirectoryWatcher(directory, _count));
34 } 37 }
35 38
36 class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher { 39 class _MacOSDirectoryWatcher implements ManuallyClosedDirectoryWatcher {
40 // TODO(nweiz): remove these when issue 15042 is fixed.
41 static var _count = 0;
42 final String _id;
43
37 final String directory; 44 final String directory;
38 45
39 Stream<WatchEvent> get events => _eventsController.stream; 46 Stream<WatchEvent> get events => _eventsController.stream;
40 final _eventsController = new StreamController<WatchEvent>.broadcast(); 47 final _eventsController = new StreamController<WatchEvent>.broadcast();
41 48
42 bool get isReady => _readyCompleter.isCompleted; 49 bool get isReady => _readyCompleter.isCompleted;
43 50
44 Future get ready => _readyCompleter.future; 51 Future get ready => _readyCompleter.future;
45 final _readyCompleter = new Completer(); 52 final _readyCompleter = new Completer();
46 53
(...skipping 19 matching lines...) Expand all
66 /// This is separate from [_subscriptions] because this stream occasionally 73 /// This is separate from [_subscriptions] because this stream occasionally
67 /// needs to be resubscribed in order to work around issue 14849. 74 /// needs to be resubscribed in order to work around issue 14849.
68 StreamSubscription<FileSystemEvent> _watchSubscription; 75 StreamSubscription<FileSystemEvent> _watchSubscription;
69 76
70 /// A set of subscriptions that this watcher subscribes to. 77 /// A set of subscriptions that this watcher subscribes to.
71 /// 78 ///
72 /// These are gathered together so that they may all be canceled when the 79 /// These are gathered together so that they may all be canceled when the
73 /// watcher is closed. This does not include [_watchSubscription]. 80 /// watcher is closed. This does not include [_watchSubscription].
74 final _subscriptions = new Set<StreamSubscription>(); 81 final _subscriptions = new Set<StreamSubscription>();
75 82
76 _MacOSDirectoryWatcher(String directory) 83 _MacOSDirectoryWatcher(String directory, int parentId)
77 : directory = directory, 84 : directory = directory,
78 _files = new PathSet(directory) { 85 _files = new PathSet(directory),
86 _id = "$parentId/${_count++}" {
79 _startWatch(); 87 _startWatch();
80 88
81 _listen(new Directory(directory).list(recursive: true), 89 _listen(new Directory(directory).list(recursive: true),
82 (entity) { 90 (entity) {
83 if (entity is! Directory) _files.add(entity.path); 91 if (entity is! Directory) _files.add(entity.path);
84 }, 92 },
85 onError: _emitError, 93 onError: _emitError,
86 onDone: () { 94 onDone: () {
87 if (MacOSDirectoryWatcher.logDebugInfo) { 95 if (MacOSDirectoryWatcher.logDebugInfo) {
88 print("watcher is ready"); 96 print("[$_id] watcher is ready, known files:");
97 for (var file in _files.toSet()) {
98 print("[$_id] ${p.relative(file, from: directory)}");
99 }
89 } 100 }
90 _readyCompleter.complete(); 101 _readyCompleter.complete();
91 }, 102 },
92 cancelOnError: true); 103 cancelOnError: true);
93 } 104 }
94 105
95 void close() { 106 void close() {
107 if (MacOSDirectoryWatcher.logDebugInfo) {
108 print("[$_id] watcher is closed");
109 }
96 for (var subscription in _subscriptions) { 110 for (var subscription in _subscriptions) {
97 subscription.cancel(); 111 subscription.cancel();
98 } 112 }
99 _subscriptions.clear(); 113 _subscriptions.clear();
100 if (_watchSubscription != null) _watchSubscription.cancel(); 114 if (_watchSubscription != null) _watchSubscription.cancel();
101 _watchSubscription = null; 115 _watchSubscription = null;
102 _eventsController.close(); 116 _eventsController.close();
103 } 117 }
104 118
105 /// The callback that's run when [Directory.watch] emits a batch of events. 119 /// The callback that's run when [Directory.watch] emits a batch of events.
106 void _onBatch(List<FileSystemEvent> batch) { 120 void _onBatch(List<FileSystemEvent> batch) {
107 if (MacOSDirectoryWatcher.logDebugInfo) { 121 if (MacOSDirectoryWatcher.logDebugInfo) {
108 print("======== batch:"); 122 print("[$_id] ======== batch:");
109 for (var event in batch) { 123 for (var event in batch) {
110 print(" ${_formatEvent(event)}"); 124 print("[$_id] ${_formatEvent(event)}");
111 } 125 }
112 126
113 print("known files:"); 127 print("[$_id] known files:");
114 for (var foo in _files.toSet()) { 128 for (var file in _files.toSet()) {
115 print(" ${p.relative(foo, from: directory)}"); 129 print("[$_id] ${p.relative(file, from: directory)}");
116 } 130 }
117 } 131 }
118 132
119 batches++; 133 batches++;
120 134
121 _sortEvents(batch).forEach((path, events) { 135 _sortEvents(batch).forEach((path, events) {
122 var relativePath = p.relative(path, from: directory); 136 var relativePath = p.relative(path, from: directory);
123 if (MacOSDirectoryWatcher.logDebugInfo) { 137 if (MacOSDirectoryWatcher.logDebugInfo) {
124 print("events for $relativePath:\n"); 138 print("[$_id] events for $relativePath:\n");
125 for (var event in events) { 139 for (var event in events) {
126 print(" ${_formatEvent(event)}"); 140 print("[$_id] ${_formatEvent(event)}");
127 } 141 }
128 } 142 }
129 143
130 var canonicalEvent = _canonicalEvent(events); 144 var canonicalEvent = _canonicalEvent(events);
131 events = canonicalEvent == null ? 145 events = canonicalEvent == null ?
132 _eventsBasedOnFileSystem(path) : [canonicalEvent]; 146 _eventsBasedOnFileSystem(path) : [canonicalEvent];
133 if (MacOSDirectoryWatcher.logDebugInfo) { 147 if (MacOSDirectoryWatcher.logDebugInfo) {
134 print("canonical event for $relativePath: " 148 print("[$_id] canonical event for $relativePath: "
135 "${_formatEvent(canonicalEvent)}"); 149 "${_formatEvent(canonicalEvent)}");
136 print("actionable events for $relativePath: " 150 print("[$_id] actionable events for $relativePath: "
137 "${events.map(_formatEvent)}"); 151 "${events.map(_formatEvent)}");
138 } 152 }
139 153
140 for (var event in events) { 154 for (var event in events) {
141 if (event is FileSystemCreateEvent) { 155 if (event is FileSystemCreateEvent) {
142 if (!event.isDirectory) { 156 if (!event.isDirectory) {
143 _emitEvent(ChangeType.ADD, path); 157 _emitEvent(ChangeType.ADD, path);
144 _files.add(path); 158 _files.add(path);
145 continue; 159 continue;
146 } 160 }
147 161
148 _listen(new Directory(path).list(recursive: true), (entity) { 162 _listen(new Directory(path).list(recursive: true), (entity) {
149 if (entity is Directory) return; 163 if (entity is Directory) return;
150 _emitEvent(ChangeType.ADD, entity.path); 164 _emitEvent(ChangeType.ADD, entity.path);
151 _files.add(entity.path); 165 _files.add(entity.path);
152 }, onError: (e, stackTrace) { 166 }, onError: (e, stackTrace) {
153 if (MacOSDirectoryWatcher.logDebugInfo) { 167 if (MacOSDirectoryWatcher.logDebugInfo) {
154 print("got error listing $relativePath: $e"); 168 print("[$_id] got error listing $relativePath: $e");
155 } 169 }
156 _emitError(e, stackTrace); 170 _emitError(e, stackTrace);
157 }, cancelOnError: true); 171 }, cancelOnError: true);
158 } else if (event is FileSystemModifyEvent) { 172 } else if (event is FileSystemModifyEvent) {
159 assert(!event.isDirectory); 173 assert(!event.isDirectory);
160 _emitEvent(ChangeType.MODIFY, path); 174 _emitEvent(ChangeType.MODIFY, path);
161 } else { 175 } else {
162 assert(event is FileSystemDeleteEvent); 176 assert(event is FileSystemDeleteEvent);
163 for (var removedPath in _files.remove(path)) { 177 for (var removedPath in _files.remove(path)) {
164 _emitEvent(ChangeType.REMOVE, removedPath); 178 _emitEvent(ChangeType.REMOVE, removedPath);
165 } 179 }
166 } 180 }
167 } 181 }
168 }); 182 });
169 183
170 if (MacOSDirectoryWatcher.logDebugInfo) { 184 if (MacOSDirectoryWatcher.logDebugInfo) {
171 print("========"); 185 print("[$_id] ======== batch complete");
172 } 186 }
173 } 187 }
174 188
175 /// Sort all the events in a batch into sets based on their path. 189 /// Sort all the events in a batch into sets based on their path.
176 /// 190 ///
177 /// A single input event may result in multiple events in the returned map; 191 /// A single input event may result in multiple events in the returned map;
178 /// for example, a MOVE event becomes a DELETE event for the source and a 192 /// for example, a MOVE event becomes a DELETE event for the source and a
179 /// CREATE event for the destination. 193 /// CREATE event for the destination.
180 /// 194 ///
181 /// The returned events won't contain any [FileSystemMoveEvent]s, nor will it 195 /// The returned events won't contain any [FileSystemMoveEvent]s, nor will it
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 /// to the user, unlike the batched events from [Directory.watch]. The 314 /// to the user, unlike the batched events from [Directory.watch]. The
301 /// returned list may be empty, indicating that no changes occurred to [path] 315 /// returned list may be empty, indicating that no changes occurred to [path]
302 /// (probably indicating that it was created and then immediately deleted). 316 /// (probably indicating that it was created and then immediately deleted).
303 List<FileSystemEvent> _eventsBasedOnFileSystem(String path) { 317 List<FileSystemEvent> _eventsBasedOnFileSystem(String path) {
304 var fileExisted = _files.contains(path); 318 var fileExisted = _files.contains(path);
305 var dirExisted = _files.containsDir(path); 319 var dirExisted = _files.containsDir(path);
306 var fileExists = new File(path).existsSync(); 320 var fileExists = new File(path).existsSync();
307 var dirExists = new Directory(path).existsSync(); 321 var dirExists = new Directory(path).existsSync();
308 322
309 if (MacOSDirectoryWatcher.logDebugInfo) { 323 if (MacOSDirectoryWatcher.logDebugInfo) {
310 print("file existed: $fileExisted"); 324 print("[$_id] file existed: $fileExisted");
311 print("dir existed: $dirExisted"); 325 print("[$_id] dir existed: $dirExisted");
312 print("file exists: $fileExists"); 326 print("[$_id] file exists: $fileExists");
313 print("dir exists: $dirExists"); 327 print("[$_id] dir exists: $dirExists");
314 } 328 }
315 329
316 var events = []; 330 var events = [];
317 if (fileExisted) { 331 if (fileExisted) {
318 if (fileExists) { 332 if (fileExists) {
319 events.add(new ConstructableFileSystemModifyEvent(path, false, false)); 333 events.add(new ConstructableFileSystemModifyEvent(path, false, false));
320 } else { 334 } else {
321 events.add(new ConstructableFileSystemDeleteEvent(path, false)); 335 events.add(new ConstructableFileSystemDeleteEvent(path, false));
322 } 336 }
323 } else if (dirExisted) { 337 } else if (dirExisted) {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 /// Emit an event with the given [type] and [path]. 390 /// Emit an event with the given [type] and [path].
377 void _emitEvent(ChangeType type, String path) { 391 void _emitEvent(ChangeType type, String path) {
378 if (!isReady) return; 392 if (!isReady) return;
379 393
380 // Don't emit ADD events for files that we already know about. Such an event 394 // Don't emit ADD events for files that we already know about. Such an event
381 // probably comes from FSEvents reporting an add that happened prior to the 395 // probably comes from FSEvents reporting an add that happened prior to the
382 // watch beginning. 396 // watch beginning.
383 if (type == ChangeType.ADD && _files.contains(path)) return; 397 if (type == ChangeType.ADD && _files.contains(path)) return;
384 398
385 if (MacOSDirectoryWatcher.logDebugInfo) { 399 if (MacOSDirectoryWatcher.logDebugInfo) {
386 print("emitting $type ${p.relative(path, from: directory)}"); 400 print("[$_id] emitting $type ${p.relative(path, from: directory)}");
387 } 401 }
388 402
389 _eventsController.add(new WatchEvent(type, path)); 403 _eventsController.add(new WatchEvent(type, path));
390 } 404 }
391 405
392 /// Emit an error, then close the watcher. 406 /// Emit an error, then close the watcher.
393 void _emitError(error, StackTrace stackTrace) { 407 void _emitError(error, StackTrace stackTrace) {
394 _eventsController.addError(error, stackTrace); 408 _eventsController.addError(error, stackTrace);
395 close(); 409 close();
396 } 410 }
(...skipping 22 matching lines...) Expand all
419 } else if (event is FileSystemDeleteEvent) { 433 } else if (event is FileSystemDeleteEvent) {
420 return "delete $type $path"; 434 return "delete $type $path";
421 } else if (event is FileSystemModifyEvent) { 435 } else if (event is FileSystemModifyEvent) {
422 return "modify $type $path"; 436 return "modify $type $path";
423 } else if (event is FileSystemMoveEvent) { 437 } else if (event is FileSystemMoveEvent) {
424 return "move $type $path to " 438 return "move $type $path to "
425 "${p.relative(event.destination, from: directory)}"; 439 "${p.relative(event.destination, from: directory)}";
426 } 440 }
427 } 441 }
428 } 442 }
OLDNEW
« no previous file with comments | « pkg/pkg.status ('k') | pkg/watcher/test/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698