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

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

Issue 122573003: Don't test for file differences in the polling watcher. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Revise shared test. Created 6 years, 11 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/watcher/pubspec.yaml » ('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.polling; 5 library watcher.directory_watcher.polling;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:io'; 8 import 'dart:io';
9 9
10 import 'package:crypto/crypto.dart';
11 import 'package:stack_trace/stack_trace.dart'; 10 import 'package:stack_trace/stack_trace.dart';
12 11
13 import '../async_queue.dart'; 12 import '../async_queue.dart';
14 import '../stat.dart'; 13 import '../stat.dart';
15 import '../utils.dart'; 14 import '../utils.dart';
16 import '../watch_event.dart'; 15 import '../watch_event.dart';
17 import 'resubscribable.dart'; 16 import 'resubscribable.dart';
18 17
19 /// Periodically polls a directory for changes. 18 /// Periodically polls a directory for changes.
20 class PollingDirectoryWatcher extends ResubscribableDirectoryWatcher { 19 class PollingDirectoryWatcher extends ResubscribableDirectoryWatcher {
(...skipping 18 matching lines...) Expand all
39 38
40 bool get isReady => _ready.isCompleted; 39 bool get isReady => _ready.isCompleted;
41 40
42 Future get ready => _ready.future; 41 Future get ready => _ready.future;
43 final _ready = new Completer(); 42 final _ready = new Completer();
44 43
45 /// The amount of time the watcher pauses between successive polls of the 44 /// The amount of time the watcher pauses between successive polls of the
46 /// directory contents. 45 /// directory contents.
47 final Duration _pollingDelay; 46 final Duration _pollingDelay;
48 47
49 /// The previous status of the files in the directory. 48 /// The previous modification times of the files in the directory.
50 /// 49 ///
51 /// Used to tell which files have been modified. 50 /// Used to tell which files have been modified.
52 final _statuses = new Map<String, _FileStatus>(); 51 final _lastModifieds = new Map<String, DateTime>();
53 52
54 /// The subscription used while [directory] is being listed. 53 /// The subscription used while [directory] is being listed.
55 /// 54 ///
56 /// Will be `null` if a list is not currently happening. 55 /// Will be `null` if a list is not currently happening.
57 StreamSubscription<FileSystemEntity> _listSubscription; 56 StreamSubscription<FileSystemEntity> _listSubscription;
58 57
59 /// The queue of files waiting to be processed to see if they have been 58 /// The queue of files waiting to be processed to see if they have been
60 /// modified. 59 /// modified.
61 /// 60 ///
62 /// Processing a file is asynchronous, as is listing the directory, so the 61 /// Processing a file is asynchronous, as is listing the directory, so the
(...skipping 19 matching lines...) Expand all
82 81
83 void close() { 82 void close() {
84 _events.close(); 83 _events.close();
85 84
86 // If we're in the middle of listing the directory, stop. 85 // If we're in the middle of listing the directory, stop.
87 if (_listSubscription != null) _listSubscription.cancel(); 86 if (_listSubscription != null) _listSubscription.cancel();
88 87
89 // Don't process any remaining files. 88 // Don't process any remaining files.
90 _filesToProcess.clear(); 89 _filesToProcess.clear();
91 _polledFiles.clear(); 90 _polledFiles.clear();
92 _statuses.clear(); 91 _lastModifieds.clear();
93 } 92 }
94 93
95 /// Scans the contents of the directory once to see which files have been 94 /// Scans the contents of the directory once to see which files have been
96 /// added, removed, and modified. 95 /// added, removed, and modified.
97 void _poll() { 96 void _poll() {
98 _filesToProcess.clear(); 97 _filesToProcess.clear();
99 _polledFiles.clear(); 98 _polledFiles.clear();
100 99
101 endListing() { 100 endListing() {
102 assert(!_events.isClosed); 101 assert(!_events.isClosed);
(...skipping 25 matching lines...) Expand all
128 127
129 /// Processes [file] to determine if it has been modified since the last 128 /// Processes [file] to determine if it has been modified since the last
130 /// time it was scanned. 129 /// time it was scanned.
131 Future _processFile(String file) { 130 Future _processFile(String file) {
132 // `null` is the sentinel which means the directory listing is complete. 131 // `null` is the sentinel which means the directory listing is complete.
133 if (file == null) return _completePoll(); 132 if (file == null) return _completePoll();
134 133
135 return getModificationTime(file).then((modified) { 134 return getModificationTime(file).then((modified) {
136 if (_events.isClosed) return null; 135 if (_events.isClosed) return null;
137 136
138 var lastStatus = _statuses[file]; 137 var lastModified = _lastModifieds[file];
139 138
140 // If its modification time hasn't changed, assume the file is unchanged. 139 // If its modification time hasn't changed, assume the file is unchanged.
141 if (lastStatus != null && lastStatus.modified == modified) { 140 if (lastModified != null && lastModified == modified) {
142 // The file is still here. 141 // The file is still here.
143 _polledFiles.add(file); 142 _polledFiles.add(file);
144 return null; 143 return null;
145 } 144 }
146 145
147 return _hashFile(file).then((hash) { 146 if (_events.isClosed) return null;
148 if (_events.isClosed) return;
149 147
150 var status = new _FileStatus(modified, hash); 148 _lastModifieds[file] = modified;
151 _statuses[file] = status; 149 _polledFiles.add(file);
152 _polledFiles.add(file);
153 150
154 // Only notify if we're ready to emit events. 151 // Only notify if we're ready to emit events.
155 if (!isReady) return; 152 if (!isReady) return null;
156 153
157 // And the file is different. 154 var type = lastModified == null ? ChangeType.ADD : ChangeType.MODIFY;
158 var changed = lastStatus == null || !_sameHash(lastStatus.hash, hash); 155 _events.add(new WatchEvent(type, file));
159 if (!changed) return;
160
161 var type = lastStatus == null ? ChangeType.ADD : ChangeType.MODIFY;
162 _events.add(new WatchEvent(type, file));
163 });
164 }); 156 });
165 } 157 }
166 158
167 /// After the directory listing is complete, this determines which files were 159 /// After the directory listing is complete, this determines which files were
168 /// removed and then restarts the next poll. 160 /// removed and then restarts the next poll.
169 Future _completePoll() { 161 Future _completePoll() {
170 // Any files that were not seen in the last poll but that we have a 162 // Any files that were not seen in the last poll but that we have a
171 // status for must have been removed. 163 // status for must have been removed.
172 var removedFiles = _statuses.keys.toSet().difference(_polledFiles); 164 var removedFiles = _lastModifieds.keys.toSet().difference(_polledFiles);
173 for (var removed in removedFiles) { 165 for (var removed in removedFiles) {
174 if (isReady) _events.add(new WatchEvent(ChangeType.REMOVE, removed)); 166 if (isReady) _events.add(new WatchEvent(ChangeType.REMOVE, removed));
175 _statuses.remove(removed); 167 _lastModifieds.remove(removed);
176 } 168 }
177 169
178 if (!isReady) _ready.complete(); 170 if (!isReady) _ready.complete();
179 171
180 // Wait and then poll again. 172 // Wait and then poll again.
181 return new Future.delayed(_pollingDelay).then((_) { 173 return new Future.delayed(_pollingDelay).then((_) {
182 if (_events.isClosed) return; 174 if (_events.isClosed) return;
183 _poll(); 175 _poll();
184 }); 176 });
185 } 177 }
186
187 /// Calculates the SHA-1 hash of the file at [path].
188 Future<List<int>> _hashFile(String path) {
189 return Chain.track(new File(path).readAsBytes()).then((bytes) {
190 var sha1 = new SHA1();
191 sha1.add(bytes);
192 return sha1.close();
193 });
194 }
195
196 /// Returns `true` if [a] and [b] are the same hash value, i.e. the same
197 /// series of byte values.
198 bool _sameHash(List<int> a, List<int> b) {
199 // Hashes should always be the same size.
200 assert(a.length == b.length);
201
202 for (var i = 0; i < a.length; i++) {
203 if (a[i] != b[i]) return false;
204 }
205
206 return true;
207 }
208 } 178 }
209
210 class _FileStatus {
211 /// The last time the file was modified.
212 DateTime modified;
213
214 /// The SHA-1 hash of the contents of the file.
215 List<int> hash;
216
217 _FileStatus(this.modified, this.hash);
218 }
219
OLDNEW
« no previous file with comments | « no previous file | pkg/watcher/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698