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 |