| OLD | NEW |
| 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.linux; | 5 library watcher.directory_watcher.linux; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'package:stack_trace/stack_trace.dart'; |
| 11 |
| 10 import '../utils.dart'; | 12 import '../utils.dart'; |
| 11 import '../watch_event.dart'; | 13 import '../watch_event.dart'; |
| 12 import 'resubscribable.dart'; | 14 import 'resubscribable.dart'; |
| 13 | 15 |
| 14 /// Uses the inotify subsystem to watch for filesystem events. | 16 /// Uses the inotify subsystem to watch for filesystem events. |
| 15 /// | 17 /// |
| 16 /// Inotify doesn't suport recursively watching subdirectories, nor does | 18 /// Inotify doesn't suport recursively watching subdirectories, nor does |
| 17 /// [Directory.watch] polyfill that functionality. This class polyfills it | 19 /// [Directory.watch] polyfill that functionality. This class polyfills it |
| 18 /// instead. | 20 /// instead. |
| 19 /// | 21 /// |
| (...skipping 29 matching lines...) Expand all Loading... |
| 49 | 51 |
| 50 /// A set of all subscriptions that this watcher subscribes to. | 52 /// A set of all subscriptions that this watcher subscribes to. |
| 51 /// | 53 /// |
| 52 /// These are gathered together so that they may all be canceled when the | 54 /// These are gathered together so that they may all be canceled when the |
| 53 /// watcher is closed. | 55 /// watcher is closed. |
| 54 final _subscriptions = new Set<StreamSubscription>(); | 56 final _subscriptions = new Set<StreamSubscription>(); |
| 55 | 57 |
| 56 _LinuxDirectoryWatcher(String directory) | 58 _LinuxDirectoryWatcher(String directory) |
| 57 : directory = directory { | 59 : directory = directory { |
| 58 // Batch the inotify changes together so that we can dedup events. | 60 // Batch the inotify changes together so that we can dedup events. |
| 59 var innerStream = new Directory(directory).watch().transform( | 61 var innerStream = Chain.track(new Directory(directory).watch()) |
| 60 new BatchedStreamTransformer<FileSystemEvent>()); | 62 .transform(new BatchedStreamTransformer<FileSystemEvent>()); |
| 61 _listen(innerStream, _onBatch, | 63 _listen(innerStream, _onBatch, |
| 62 onError: _eventsController.addError, | 64 onError: _eventsController.addError, |
| 63 onDone: _onDone); | 65 onDone: _onDone); |
| 64 | 66 |
| 65 _listen(new Directory(directory).list(), (entity) { | 67 _listen(Chain.track(new Directory(directory).list()), (entity) { |
| 66 _entries[entity.path] = new _EntryState(entity is Directory); | 68 _entries[entity.path] = new _EntryState(entity is Directory); |
| 67 if (entity is! Directory) return; | 69 if (entity is! Directory) return; |
| 68 _watchSubdir(entity.path); | 70 _watchSubdir(entity.path); |
| 69 }, onError: (error, stackTrace) { | 71 }, onError: (error, stackTrace) { |
| 70 _eventsController.addError(error, stackTrace); | 72 _eventsController.addError(error, stackTrace); |
| 71 close(); | 73 close(); |
| 72 }, onDone: () { | 74 }, onDone: () { |
| 73 _waitUntilReady().then((_) => _readyCompleter.complete()); | 75 _waitUntilReady().then((_) => _readyCompleter.complete()); |
| 74 }, cancelOnError: true); | 76 }, cancelOnError: true); |
| 75 } | 77 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 // `DirectoryWatcher.eventsAndExistingFiles`) to tell a watcher to emit | 152 // `DirectoryWatcher.eventsAndExistingFiles`) to tell a watcher to emit |
| 151 // events for all the files that already exist. This would be useful for | 153 // events for all the files that already exist. This would be useful for |
| 152 // top-level clients such as barback as well, and could be implemented with | 154 // top-level clients such as barback as well, and could be implemented with |
| 153 // a wrapper similar to how listening/canceling works now. | 155 // a wrapper similar to how listening/canceling works now. |
| 154 | 156 |
| 155 // If a directory is added after we're finished with the initial scan, emit | 157 // If a directory is added after we're finished with the initial scan, emit |
| 156 // an event for each entry in it. This gives the user consistently gets an | 158 // an event for each entry in it. This gives the user consistently gets an |
| 157 // event for every new file. | 159 // event for every new file. |
| 158 watcher.ready.then((_) { | 160 watcher.ready.then((_) { |
| 159 if (!isReady || _eventsController.isClosed) return; | 161 if (!isReady || _eventsController.isClosed) return; |
| 160 _listen(new Directory(path).list(recursive: true), (entry) { | 162 _listen(Chain.track(new Directory(path).list(recursive: true)), (entry) { |
| 161 if (entry is Directory) return; | 163 if (entry is Directory) return; |
| 162 _eventsController.add(new WatchEvent(ChangeType.ADD, entry.path)); | 164 _eventsController.add(new WatchEvent(ChangeType.ADD, entry.path)); |
| 163 }, onError: (error, stackTrace) { | 165 }, onError: (error, stackTrace) { |
| 164 // Ignore an exception caused by the dir not existing. It's fine if it | 166 // Ignore an exception caused by the dir not existing. It's fine if it |
| 165 // was added and then quickly removed. | 167 // was added and then quickly removed. |
| 166 if (error is FileSystemException) return; | 168 if (error is FileSystemException) return; |
| 167 | 169 |
| 168 _eventsController.addError(error, stackTrace); | 170 _eventsController.addError(error, stackTrace); |
| 169 close(); | 171 close(); |
| 170 }, cancelOnError: true); | 172 }, cancelOnError: true); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 static const DIRECTORY = const _EntryState._("directory"); | 299 static const DIRECTORY = const _EntryState._("directory"); |
| 298 | 300 |
| 299 const _EntryState._(this._name); | 301 const _EntryState._(this._name); |
| 300 | 302 |
| 301 /// Returns [DIRECTORY] if [isDir] is true, and [FILE] otherwise. | 303 /// Returns [DIRECTORY] if [isDir] is true, and [FILE] otherwise. |
| 302 factory _EntryState(bool isDir) => | 304 factory _EntryState(bool isDir) => |
| 303 isDir ? _EntryState.DIRECTORY : _EntryState.FILE; | 305 isDir ? _EntryState.DIRECTORY : _EntryState.FILE; |
| 304 | 306 |
| 305 String toString() => _name; | 307 String toString() => _name; |
| 306 } | 308 } |
| OLD | NEW |