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

Side by Side Diff: packages/watcher/lib/src/directory_watcher/windows.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 4 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 // TODO(rnystrom): Merge with mac_os version. 4 // TODO(rnystrom): Merge with mac_os version.
5 5
6 library watcher.directory_watcher.windows;
7
8 import 'dart:async'; 6 import 'dart:async';
9 import 'dart:collection'; 7 import 'dart:collection';
10 import 'dart:io'; 8 import 'dart:io';
11 9
12 import 'package:path/path.dart' as p; 10 import 'package:path/path.dart' as p;
13 11
14 import '../constructable_file_system_event.dart'; 12 import '../constructable_file_system_event.dart';
15 import '../directory_watcher.dart'; 13 import '../directory_watcher.dart';
16 import '../path_set.dart'; 14 import '../path_set.dart';
17 import '../resubscribable.dart'; 15 import '../resubscribable.dart';
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 if (p.basename(event.path) != p.basename(absoluteDir)) return; 127 if (p.basename(event.path) != p.basename(absoluteDir)) return;
130 // Test if the directory is removed. FileSystemEntity.typeSync will 128 // Test if the directory is removed. FileSystemEntity.typeSync will
131 // return NOT_FOUND if it's unable to decide upon the type, including 129 // return NOT_FOUND if it's unable to decide upon the type, including
132 // access denied issues, which may happen when the directory is deleted. 130 // access denied issues, which may happen when the directory is deleted.
133 // FileSystemMoveEvent and FileSystemDeleteEvent events will always mean 131 // FileSystemMoveEvent and FileSystemDeleteEvent events will always mean
134 // the directory is now gone. 132 // the directory is now gone.
135 if (event is FileSystemMoveEvent || 133 if (event is FileSystemMoveEvent ||
136 event is FileSystemDeleteEvent || 134 event is FileSystemDeleteEvent ||
137 (FileSystemEntity.typeSync(path) == 135 (FileSystemEntity.typeSync(path) ==
138 FileSystemEntityType.NOT_FOUND)) { 136 FileSystemEntityType.NOT_FOUND)) {
139 for (var path in _files.toSet()) { 137 for (var path in _files.paths) {
140 _emitEvent(ChangeType.REMOVE, path); 138 _emitEvent(ChangeType.REMOVE, path);
141 } 139 }
142 _files.clear(); 140 _files.clear();
143 close(); 141 close();
144 } 142 }
145 }, onError: (error) { 143 }, onError: (error) {
146 // Ignore errors, simply close the stream. The user listens on 144 // Ignore errors, simply close the stream. The user listens on
147 // [directory], and while it can fail to listen on the parent, we may 145 // [directory], and while it can fail to listen on the parent, we may
148 // still be able to listen on the path requested. 146 // still be able to listen on the path requested.
149 _parentWatchSubscription.cancel(); 147 _parentWatchSubscription.cancel();
150 _parentWatchSubscription = null; 148 _parentWatchSubscription = null;
151 }); 149 });
152 } 150 }
153 151
154 void _onEvent(FileSystemEvent event) { 152 void _onEvent(FileSystemEvent event) {
155 assert(isReady); 153 assert(isReady);
156 final batcher = _eventBatchers.putIfAbsent( 154 final batcher = _eventBatchers.putIfAbsent(
157 event.path, () => new _EventBatcher()); 155 event.path, () => new _EventBatcher());
158 batcher.addEvent(event, () { 156 batcher.addEvent(event, () {
159 _eventBatchers.remove(event.path); 157 _eventBatchers.remove(event.path);
160 _onBatch(batcher.events); 158 _onBatch(batcher.events);
161 }); 159 });
162 } 160 }
163 161
164 /// The callback that's run when [Directory.watch] emits a batch of events. 162 /// The callback that's run when [Directory.watch] emits a batch of events.
165 void _onBatch(List<FileSystemEvent> batch) { 163 void _onBatch(List<FileSystemEvent> batch) {
166 _sortEvents(batch).forEach((path, events) { 164 _sortEvents(batch).forEach((path, eventSet) {
167 165
168 var canonicalEvent = _canonicalEvent(events); 166 var canonicalEvent = _canonicalEvent(eventSet);
169 events = canonicalEvent == null ? 167 var events = canonicalEvent == null ?
170 _eventsBasedOnFileSystem(path) : [canonicalEvent]; 168 _eventsBasedOnFileSystem(path) : [canonicalEvent];
171 169
172 for (var event in events) { 170 for (var event in events) {
173 if (event is FileSystemCreateEvent) { 171 if (event is FileSystemCreateEvent) {
174 if (!event.isDirectory) { 172 if (!event.isDirectory) {
175 if (_files.contains(path)) continue; 173 if (_files.contains(path)) continue;
176 174
177 _emitEvent(ChangeType.ADD, path); 175 _emitEvent(ChangeType.ADD, path);
178 _files.add(path); 176 _files.add(path);
179 continue; 177 continue;
180 } 178 }
181 179
182 if (_files.containsDir(path)) continue; 180 if (_files.containsDir(path)) continue;
183 181
184 var stream = new Directory(path).list(recursive: true); 182 var stream = new Directory(path).list(recursive: true);
185 var sub; 183 StreamSubscription<FileSystemEntity> subscription;
186 sub = stream.listen((entity) { 184 subscription = stream.listen((entity) {
187 if (entity is Directory) return; 185 if (entity is Directory) return;
188 if (_files.contains(path)) return; 186 if (_files.contains(path)) return;
189 187
190 _emitEvent(ChangeType.ADD, entity.path); 188 _emitEvent(ChangeType.ADD, entity.path);
191 _files.add(entity.path); 189 _files.add(entity.path);
192 }, onDone: () { 190 }, onDone: () {
193 _listSubscriptions.remove(sub); 191 _listSubscriptions.remove(subscription);
194 }, onError: (e, stackTrace) { 192 }, onError: (e, stackTrace) {
195 _listSubscriptions.remove(sub); 193 _listSubscriptions.remove(subscription);
196 _emitError(e, stackTrace); 194 _emitError(e, stackTrace);
197 }, cancelOnError: true); 195 }, cancelOnError: true);
198 _listSubscriptions.add(sub); 196 _listSubscriptions.add(subscription);
199 } else if (event is FileSystemModifyEvent) { 197 } else if (event is FileSystemModifyEvent) {
200 if (!event.isDirectory) { 198 if (!event.isDirectory) {
201 _emitEvent(ChangeType.MODIFY, path); 199 _emitEvent(ChangeType.MODIFY, path);
202 } 200 }
203 } else { 201 } else {
204 assert(event is FileSystemDeleteEvent); 202 assert(event is FileSystemDeleteEvent);
205 for (var removedPath in _files.remove(path)) { 203 for (var removedPath in _files.remove(path)) {
206 _emitEvent(ChangeType.REMOVE, removedPath); 204 _emitEvent(ChangeType.REMOVE, removedPath);
207 } 205 }
208 } 206 }
209 } 207 }
210 }); 208 });
211 } 209 }
212 210
213 /// Sort all the events in a batch into sets based on their path. 211 /// Sort all the events in a batch into sets based on their path.
214 /// 212 ///
215 /// A single input event may result in multiple events in the returned map; 213 /// A single input event may result in multiple events in the returned map;
216 /// for example, a MOVE event becomes a DELETE event for the source and a 214 /// for example, a MOVE event becomes a DELETE event for the source and a
217 /// CREATE event for the destination. 215 /// CREATE event for the destination.
218 /// 216 ///
219 /// The returned events won't contain any [FileSystemMoveEvent]s, nor will it 217 /// The returned events won't contain any [FileSystemMoveEvent]s, nor will it
220 /// contain any events relating to [path]. 218 /// contain any events relating to [path].
221 Map<String, Set<FileSystemEvent>> _sortEvents(List<FileSystemEvent> batch) { 219 Map<String, Set<FileSystemEvent>> _sortEvents(List<FileSystemEvent> batch) {
222 var eventsForPaths = {}; 220 var eventsForPaths = <String, Set>{};
223 221
224 // Events within directories that already have events are superfluous; the 222 // Events within directories that already have events are superfluous; the
225 // directory's full contents will be examined anyway, so we ignore such 223 // directory's full contents will be examined anyway, so we ignore such
226 // events. Emitting them could cause useless or out-of-order events. 224 // events. Emitting them could cause useless or out-of-order events.
227 var directories = unionAll(batch.map((event) { 225 var directories = unionAll(batch.map((event) {
228 if (!event.isDirectory) return new Set(); 226 if (!event.isDirectory) return new Set();
229 if (event is! FileSystemMoveEvent) return new Set.from([event.path]); 227 if (event is FileSystemMoveEvent) {
230 return new Set.from([event.path, event.destination]); 228 return new Set.from([event.path, event.destination]);
229 }
230 return new Set.from([event.path]);
231 })); 231 }));
232 232
233 isInModifiedDirectory(path) => 233 isInModifiedDirectory(path) =>
234 directories.any((dir) => path != dir && path.startsWith(dir)); 234 directories.any((dir) => path != dir && path.startsWith(dir));
235 235
236 addEvent(path, event) { 236 addEvent(path, event) {
237 if (isInModifiedDirectory(path)) return; 237 if (isInModifiedDirectory(path)) return;
238 var set = eventsForPaths.putIfAbsent(path, () => new Set()); 238 var set = eventsForPaths.putIfAbsent(path, () => new Set());
239 set.add(event); 239 set.add(event);
240 } 240 }
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
315 /// This returns a list whose order should be reflected in the events emitted 315 /// This returns a list whose order should be reflected in the events emitted
316 /// to the user, unlike the batched events from [Directory.watch]. The 316 /// to the user, unlike the batched events from [Directory.watch]. The
317 /// returned list may be empty, indicating that no changes occurred to [path] 317 /// returned list may be empty, indicating that no changes occurred to [path]
318 /// (probably indicating that it was created and then immediately deleted). 318 /// (probably indicating that it was created and then immediately deleted).
319 List<FileSystemEvent> _eventsBasedOnFileSystem(String path) { 319 List<FileSystemEvent> _eventsBasedOnFileSystem(String path) {
320 var fileExisted = _files.contains(path); 320 var fileExisted = _files.contains(path);
321 var dirExisted = _files.containsDir(path); 321 var dirExisted = _files.containsDir(path);
322 var fileExists = new File(path).existsSync(); 322 var fileExists = new File(path).existsSync();
323 var dirExists = new Directory(path).existsSync(); 323 var dirExists = new Directory(path).existsSync();
324 324
325 var events = []; 325 var events = <FileSystemEvent>[];
326 if (fileExisted) { 326 if (fileExisted) {
327 if (fileExists) { 327 if (fileExists) {
328 events.add(new ConstructableFileSystemModifyEvent(path, false, false)); 328 events.add(new ConstructableFileSystemModifyEvent(path, false, false));
329 } else { 329 } else {
330 events.add(new ConstructableFileSystemDeleteEvent(path, false)); 330 events.add(new ConstructableFileSystemDeleteEvent(path, false));
331 } 331 }
332 } else if (dirExisted) { 332 } else if (dirExisted) {
333 if (dirExists) { 333 if (dirExists) {
334 // If we got contradictory events for a directory that used to exist and 334 // If we got contradictory events for a directory that used to exist and
335 // still exists, we need to rescan the whole thing in case it was 335 // still exists, we need to rescan the whole thing in case it was
(...skipping 14 matching lines...) Expand all
350 return events; 350 return events;
351 } 351 }
352 352
353 /// The callback that's run when the [Directory.watch] stream is closed. 353 /// The callback that's run when the [Directory.watch] stream is closed.
354 /// Note that this is unlikely to happen on Windows, unless the system itself 354 /// Note that this is unlikely to happen on Windows, unless the system itself
355 /// closes the handle. 355 /// closes the handle.
356 void _onDone() { 356 void _onDone() {
357 _watchSubscription = null; 357 _watchSubscription = null;
358 358
359 // Emit remove events for any remaining files. 359 // Emit remove events for any remaining files.
360 for (var file in _files.toSet()) { 360 for (var file in _files.paths) {
361 _emitEvent(ChangeType.REMOVE, file); 361 _emitEvent(ChangeType.REMOVE, file);
362 } 362 }
363 _files.clear(); 363 _files.clear();
364 close(); 364 close();
365 } 365 }
366 366
367 /// Start or restart the underlying [Directory.watch] stream. 367 /// Start or restart the underlying [Directory.watch] stream.
368 void _startWatch() { 368 void _startWatch() {
369 // Batch the events together so that we can dedup events. 369 // Batch the events together so that we can dedup events.
370 var innerStream = new Directory(path).watch(recursive: true); 370 var innerStream = new Directory(path).watch(recursive: true);
(...skipping 28 matching lines...) Expand all
399 399
400 _eventsController.add(new WatchEvent(type, path)); 400 _eventsController.add(new WatchEvent(type, path));
401 } 401 }
402 402
403 /// Emit an error, then close the watcher. 403 /// Emit an error, then close the watcher.
404 void _emitError(error, StackTrace stackTrace) { 404 void _emitError(error, StackTrace stackTrace) {
405 _eventsController.addError(error, stackTrace); 405 _eventsController.addError(error, stackTrace);
406 close(); 406 close();
407 } 407 }
408 } 408 }
OLDNEW
« no previous file with comments | « packages/watcher/lib/src/directory_watcher/polling.dart ('k') | packages/watcher/lib/src/file_watcher.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698