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

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

Issue 69863003: "Reverting 30205" (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') | no next file » | 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;
11
12 import '../constructable_file_system_event.dart'; 10 import '../constructable_file_system_event.dart';
13 import '../path_set.dart'; 11 import '../path_set.dart';
14 import '../utils.dart'; 12 import '../utils.dart';
15 import '../watch_event.dart'; 13 import '../watch_event.dart';
16 import 'resubscribable.dart'; 14 import 'resubscribable.dart';
17 15
18 /// Uses the FSEvents subsystem to watch for filesystem events. 16 /// Uses the FSEvents subsystem to watch for filesystem events.
19 /// 17 ///
20 /// FSEvents has two main idiosyncrasies that this class works around. First, it 18 /// FSEvents has two main idiosyncrasies that this class works around. First, it
21 /// will occasionally report events that occurred before the filesystem watch 19 /// will occasionally report events that occurred before the filesystem watch
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 _MacOSDirectoryWatcher(String directory) 71 _MacOSDirectoryWatcher(String directory)
74 : directory = directory, 72 : directory = directory,
75 _files = new PathSet(directory) { 73 _files = new PathSet(directory) {
76 _startWatch(); 74 _startWatch();
77 75
78 _listen(new Directory(directory).list(recursive: true), 76 _listen(new Directory(directory).list(recursive: true),
79 (entity) { 77 (entity) {
80 if (entity is! Directory) _files.add(entity.path); 78 if (entity is! Directory) _files.add(entity.path);
81 }, 79 },
82 onError: _emitError, 80 onError: _emitError,
83 onDone: () { 81 onDone: _readyCompleter.complete,
84 if (_runningOnBuildbot) {
85 print("watcher is ready");
86 }
87 _readyCompleter.complete();
88 },
89 cancelOnError: true); 82 cancelOnError: true);
90 } 83 }
91 84
92 void close() { 85 void close() {
93 for (var subscription in _subscriptions) { 86 for (var subscription in _subscriptions) {
94 subscription.cancel(); 87 subscription.cancel();
95 } 88 }
96 _subscriptions.clear(); 89 _subscriptions.clear();
97 if (_watchSubscription != null) _watchSubscription.cancel(); 90 if (_watchSubscription != null) _watchSubscription.cancel();
98 _watchSubscription = null; 91 _watchSubscription = null;
99 _eventsController.close(); 92 _eventsController.close();
100 } 93 }
101 94
102 /// The callback that's run when [Directory.watch] emits a batch of events. 95 /// The callback that's run when [Directory.watch] emits a batch of events.
103 void _onBatch(List<FileSystemEvent> batch) { 96 void _onBatch(List<FileSystemEvent> batch) {
104 if (_runningOnBuildbot) {
105 print("======== batch:");
106 for (var event in batch) {
107 print(" ${_formatEvent(event)}");
108 }
109
110 print("known files:");
111 for (var foo in _files.toSet()) {
112 print(" ${p.relative(foo, from: directory)}");
113 }
114 }
115
116 batches++; 97 batches++;
117 98
118 _sortEvents(batch).forEach((path, events) { 99 _sortEvents(batch).forEach((path, events) {
119 var relativePath = p.relative(path, from: directory);
120 if (_runningOnBuildbot) {
121 print("events for $relativePath:\n");
122 for (var event in events) {
123 print(" ${_formatEvent(event)}");
124 }
125 }
126
127 var canonicalEvent = _canonicalEvent(events); 100 var canonicalEvent = _canonicalEvent(events);
128 events = canonicalEvent == null ? 101 events = canonicalEvent == null ?
129 _eventsBasedOnFileSystem(path) : [canonicalEvent]; 102 _eventsBasedOnFileSystem(path) : [canonicalEvent];
130 if (_runningOnBuildbot) {
131 print("canonical event for $relativePath: "
132 "${_formatEvent(canonicalEvent)}");
133 print("actionable events for $relativePath: "
134 "${events.map(_formatEvent)}");
135 }
136 103
137 for (var event in events) { 104 for (var event in events) {
138 if (event is FileSystemCreateEvent) { 105 if (event is FileSystemCreateEvent) {
139 if (!event.isDirectory) { 106 if (!event.isDirectory) {
140 _emitEvent(ChangeType.ADD, path); 107 _emitEvent(ChangeType.ADD, path);
141 _files.add(path); 108 _files.add(path);
142 continue; 109 continue;
143 } 110 }
144 111
145 _listen(new Directory(path).list(recursive: true), (entity) { 112 _listen(new Directory(path).list(recursive: true), (entity) {
146 if (entity is Directory) return; 113 if (entity is Directory) return;
147 _emitEvent(ChangeType.ADD, entity.path); 114 _emitEvent(ChangeType.ADD, entity.path);
148 _files.add(entity.path); 115 _files.add(entity.path);
149 }, onError: (e, stackTrace) { 116 }, onError: _emitError, cancelOnError: true);
150 if (_runningOnBuildbot) {
151 print("got error listing $relativePath: $e");
152 }
153 _emitError(e, stackTrace);
154 }, cancelOnError: true);
155 } else if (event is FileSystemModifyEvent) { 117 } else if (event is FileSystemModifyEvent) {
156 assert(!event.isDirectory); 118 assert(!event.isDirectory);
157 _emitEvent(ChangeType.MODIFY, path); 119 _emitEvent(ChangeType.MODIFY, path);
158 } else { 120 } else {
159 assert(event is FileSystemDeleteEvent); 121 assert(event is FileSystemDeleteEvent);
160 for (var removedPath in _files.remove(path)) { 122 for (var removedPath in _files.remove(path)) {
161 _emitEvent(ChangeType.REMOVE, removedPath); 123 _emitEvent(ChangeType.REMOVE, removedPath);
162 } 124 }
163 } 125 }
164 } 126 }
165 }); 127 });
166
167 if (_runningOnBuildbot) {
168 print("========");
169 }
170 } 128 }
171 129
172 /// Sort all the events in a batch into sets based on their path. 130 /// Sort all the events in a batch into sets based on their path.
173 /// 131 ///
174 /// A single input event may result in multiple events in the returned map; 132 /// A single input event may result in multiple events in the returned map;
175 /// for example, a MOVE event becomes a DELETE event for the source and a 133 /// for example, a MOVE event becomes a DELETE event for the source and a
176 /// CREATE event for the destination. 134 /// CREATE event for the destination.
177 /// 135 ///
178 /// The returned events won't contain any [FileSystemMoveEvent]s, nor will it 136 /// The returned events won't contain any [FileSystemMoveEvent]s, nor will it
179 /// contain any events relating to [directory]. 137 /// contain any events relating to [directory].
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 /// This returns a list whose order should be reflected in the events emitted 254 /// This returns a list whose order should be reflected in the events emitted
297 /// to the user, unlike the batched events from [Directory.watch]. The 255 /// to the user, unlike the batched events from [Directory.watch]. The
298 /// returned list may be empty, indicating that no changes occurred to [path] 256 /// returned list may be empty, indicating that no changes occurred to [path]
299 /// (probably indicating that it was created and then immediately deleted). 257 /// (probably indicating that it was created and then immediately deleted).
300 List<FileSystemEvent> _eventsBasedOnFileSystem(String path) { 258 List<FileSystemEvent> _eventsBasedOnFileSystem(String path) {
301 var fileExisted = _files.contains(path); 259 var fileExisted = _files.contains(path);
302 var dirExisted = _files.containsDir(path); 260 var dirExisted = _files.containsDir(path);
303 var fileExists = new File(path).existsSync(); 261 var fileExists = new File(path).existsSync();
304 var dirExists = new Directory(path).existsSync(); 262 var dirExists = new Directory(path).existsSync();
305 263
306 if (_runningOnBuildbot) {
307 print("file existed: $fileExisted");
308 print("dir existed: $dirExisted");
309 print("file exists: $fileExists");
310 print("dir exists: $dirExists");
311 }
312
313 var events = []; 264 var events = [];
314 if (fileExisted) { 265 if (fileExisted) {
315 if (fileExists) { 266 if (fileExists) {
316 events.add(new ConstructableFileSystemModifyEvent(path, false, false)); 267 events.add(new ConstructableFileSystemModifyEvent(path, false, false));
317 } else { 268 } else {
318 events.add(new ConstructableFileSystemDeleteEvent(path, false)); 269 events.add(new ConstructableFileSystemDeleteEvent(path, false));
319 } 270 }
320 } else if (dirExisted) { 271 } else if (dirExisted) {
321 if (dirExists) { 272 if (dirExists) {
322 // If we got contradictory events for a directory that used to exist and 273 // If we got contradictory events for a directory that used to exist and
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 323
373 /// Emit an event with the given [type] and [path]. 324 /// Emit an event with the given [type] and [path].
374 void _emitEvent(ChangeType type, String path) { 325 void _emitEvent(ChangeType type, String path) {
375 if (!isReady) return; 326 if (!isReady) return;
376 327
377 // Don't emit ADD events for files that we already know about. Such an event 328 // Don't emit ADD events for files that we already know about. Such an event
378 // probably comes from FSEvents reporting an add that happened prior to the 329 // probably comes from FSEvents reporting an add that happened prior to the
379 // watch beginning. 330 // watch beginning.
380 if (type == ChangeType.ADD && _files.contains(path)) return; 331 if (type == ChangeType.ADD && _files.contains(path)) return;
381 332
382 if (_runningOnBuildbot) {
383 print("emitting $type ${p.relative(path, from: directory)}");
384 }
385
386 _eventsController.add(new WatchEvent(type, path)); 333 _eventsController.add(new WatchEvent(type, path));
387 } 334 }
388 335
389 /// Emit an error, then close the watcher. 336 /// Emit an error, then close the watcher.
390 void _emitError(error, StackTrace stackTrace) { 337 void _emitError(error, StackTrace stackTrace) {
391 _eventsController.addError(error, stackTrace); 338 _eventsController.addError(error, stackTrace);
392 close(); 339 close();
393 } 340 }
394 341
395 /// Like [Stream.listen], but automatically adds the subscription to 342 /// Like [Stream.listen], but automatically adds the subscription to
396 /// [_subscriptions] so that it can be canceled when [close] is called. 343 /// [_subscriptions] so that it can be canceled when [close] is called.
397 void _listen(Stream stream, void onData(event), {Function onError, 344 void _listen(Stream stream, void onData(event), {Function onError,
398 void onDone(), bool cancelOnError}) { 345 void onDone(), bool cancelOnError}) {
399 var subscription; 346 var subscription;
400 subscription = stream.listen(onData, onError: onError, onDone: () { 347 subscription = stream.listen(onData, onError: onError, onDone: () {
401 _subscriptions.remove(subscription); 348 _subscriptions.remove(subscription);
402 if (onDone != null) onDone(); 349 if (onDone != null) onDone();
403 }, cancelOnError: cancelOnError); 350 }, cancelOnError: cancelOnError);
404 _subscriptions.add(subscription); 351 _subscriptions.add(subscription);
405 } 352 }
406
407 /// Return a human-friendly string representation of [event].
408 String _formatEvent(FileSystemEvent event) {
409 if (event == null) return 'null';
410
411 var path = p.relative(event.path, from: directory);
412 var type = event.isDirectory ? 'directory' : 'file';
413 if (event is FileSystemCreateEvent) {
414 return "create $type $path";
415 } else if (event is FileSystemDeleteEvent) {
416 return "delete $type $path";
417 } else if (event is FileSystemModifyEvent) {
418 return "modify $type $path";
419 } else if (event is FileSystemMoveEvent) {
420 return "move $type $path to "
421 "${p.relative(event.destination, from: directory)}";
422 }
423 }
424
425 // TODO(nweiz): remove this when the buildbots calm down.
426 /// Whether this code is running on a buildbot.
427 bool get _runningOnBuildbot =>
428 Platform.environment['LOGNAME'] == 'chrome-bot';
429 } 353 }
OLDNEW
« no previous file with comments | « pkg/pkg.status ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698