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

Side by Side Diff: analyzer/lib/file_system/memory_file_system.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library memory_file_system;
6
7 import 'dart:async';
8 import 'dart:collection';
9 import 'dart:core' hide Resource;
10
11 import 'package:analyzer/src/generated/engine.dart' show TimestampedData;
12 import 'package:analyzer/src/generated/source_io.dart';
13 import 'package:path/path.dart';
14 import 'package:watcher/watcher.dart';
15
16 import 'file_system.dart';
17
18 /**
19 * An in-memory implementation of [ResourceProvider].
20 * Use `/` as a path separator.
21 */
22 class MemoryResourceProvider implements ResourceProvider {
23 final Map<String, _MemoryResource> _pathToResource =
24 new HashMap<String, _MemoryResource>();
25 final Map<String, String> _pathToContent = new HashMap<String, String>();
26 final Map<String, int> _pathToTimestamp = new HashMap<String, int>();
27 final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers =
28 new HashMap<String, List<StreamController<WatchEvent>>>();
29 int nextStamp = 0;
30
31 @override
32 Context get pathContext => posix;
33
34 /**
35 * Delete the file with the given path.
36 */
37 void deleteFile(String path) {
38 _checkFileAtPath(path);
39 _pathToResource.remove(path);
40 _pathToContent.remove(path);
41 _pathToTimestamp.remove(path);
42 _notifyWatchers(path, ChangeType.REMOVE);
43 }
44
45 /**
46 * Delete the folder with the given path
47 * and recurively delete nested files and folders.
48 */
49 void deleteFolder(String path) {
50 _checkFolderAtPath(path);
51 _MemoryFolder folder = _pathToResource[path];
52 for (Resource child in folder.getChildren()) {
53 if (child is File) {
54 deleteFile(child.path);
55 } else if (child is Folder) {
56 deleteFolder(child.path);
57 } else {
58 throw 'failed to delete resource: $child';
59 }
60 }
61 _pathToResource.remove(path);
62 _pathToContent.remove(path);
63 _pathToTimestamp.remove(path);
64 _notifyWatchers(path, ChangeType.REMOVE);
65 }
66
67 @override
68 File getFile(String path) => new _MemoryFile(this, path);
69
70 @override
71 Folder getFolder(String path) => newFolder(path);
72
73 @override
74 Resource getResource(String path) {
75 path = posix.normalize(path);
76 Resource resource = _pathToResource[path];
77 if (resource == null) {
78 resource = new _MemoryFile(this, path);
79 }
80 return resource;
81 }
82
83 @override
84 Folder getStateLocation(String pluginId) {
85 return newFolder('/user/home/$pluginId');
86 }
87
88 void modifyFile(String path, String content) {
89 _checkFileAtPath(path);
90 _pathToContent[path] = content;
91 _pathToTimestamp[path] = nextStamp++;
92 _notifyWatchers(path, ChangeType.MODIFY);
93 }
94
95 /**
96 * Create a resource representing a dummy link (that is, a File object which
97 * appears in its parent directory, but whose `exists` property is false)
98 */
99 File newDummyLink(String path) {
100 path = posix.normalize(path);
101 newFolder(posix.dirname(path));
102 _MemoryDummyLink link = new _MemoryDummyLink(this, path);
103 _pathToResource[path] = link;
104 _pathToTimestamp[path] = nextStamp++;
105 _notifyWatchers(path, ChangeType.ADD);
106 return link;
107 }
108
109 File newFile(String path, String content, [int stamp]) {
110 path = posix.normalize(path);
111 newFolder(posix.dirname(path));
112 _MemoryFile file = new _MemoryFile(this, path);
113 _pathToResource[path] = file;
114 _pathToContent[path] = content;
115 _pathToTimestamp[path] = stamp != null ? stamp : nextStamp++;
116 _notifyWatchers(path, ChangeType.ADD);
117 return file;
118 }
119
120 Folder newFolder(String path) {
121 path = posix.normalize(path);
122 if (!path.startsWith('/')) {
123 throw new ArgumentError("Path must start with '/'");
124 }
125 _MemoryResource resource = _pathToResource[path];
126 if (resource == null) {
127 String parentPath = posix.dirname(path);
128 if (parentPath != path) {
129 newFolder(parentPath);
130 }
131 _MemoryFolder folder = new _MemoryFolder(this, path);
132 _pathToResource[path] = folder;
133 _pathToTimestamp[path] = nextStamp++;
134 return folder;
135 } else if (resource is _MemoryFolder) {
136 return resource;
137 } else {
138 String message =
139 'Folder expected at ' "'$path'" 'but ${resource.runtimeType} found';
140 throw new ArgumentError(message);
141 }
142 }
143
144 File updateFile(String path, String content, [int stamp]) {
145 path = posix.normalize(path);
146 newFolder(posix.dirname(path));
147 _MemoryFile file = new _MemoryFile(this, path);
148 _pathToResource[path] = file;
149 _pathToContent[path] = content;
150 _pathToTimestamp[path] = stamp != null ? stamp : nextStamp++;
151 _notifyWatchers(path, ChangeType.MODIFY);
152 return file;
153 }
154
155 void _checkFileAtPath(String path) {
156 _MemoryResource resource = _pathToResource[path];
157 if (resource is! _MemoryFile) {
158 throw new ArgumentError(
159 'File expected at "$path" but ${resource.runtimeType} found');
160 }
161 }
162
163 void _checkFolderAtPath(String path) {
164 _MemoryResource resource = _pathToResource[path];
165 if (resource is! _MemoryFolder) {
166 throw new ArgumentError(
167 'Folder expected at "$path" but ${resource.runtimeType} found');
168 }
169 }
170
171 void _notifyWatchers(String path, ChangeType changeType) {
172 _pathToWatchers.forEach((String watcherPath,
173 List<StreamController<WatchEvent>> streamControllers) {
174 if (watcherPath == path || posix.isWithin(watcherPath, path)) {
175 for (StreamController<WatchEvent> streamController
176 in streamControllers) {
177 streamController.add(new WatchEvent(changeType, path));
178 }
179 }
180 });
181 }
182 }
183
184 /**
185 * An in-memory implementation of [File] which acts like a symbolic link to a
186 * non-existent file.
187 */
188 class _MemoryDummyLink extends _MemoryResource implements File {
189 _MemoryDummyLink(MemoryResourceProvider provider, String path)
190 : super(provider, path);
191
192 @override
193 Stream<WatchEvent> get changes {
194 throw new FileSystemException(path, "File does not exist");
195 }
196
197 @override
198 bool get exists => false;
199
200 int get modificationStamp {
201 int stamp = _provider._pathToTimestamp[path];
202 if (stamp == null) {
203 throw new FileSystemException(path, "File does not exist");
204 }
205 return stamp;
206 }
207
208 String get _content {
209 throw new FileSystemException(path, 'File could not be read');
210 }
211
212 @override
213 Source createSource([Uri uri]) {
214 throw new FileSystemException(path, 'File could not be read');
215 }
216
217 @override
218 bool isOrContains(String path) {
219 return path == this.path;
220 }
221
222 @override
223 String readAsStringSync() {
224 throw new FileSystemException(path, 'File could not be read');
225 }
226 }
227
228 /**
229 * An in-memory implementation of [File].
230 */
231 class _MemoryFile extends _MemoryResource implements File {
232 _MemoryFile(MemoryResourceProvider provider, String path)
233 : super(provider, path);
234
235 @override
236 bool get exists => _provider._pathToResource[path] is _MemoryFile;
237
238 int get modificationStamp {
239 int stamp = _provider._pathToTimestamp[path];
240 if (stamp == null) {
241 throw new FileSystemException(path, 'File "$path" does not exist.');
242 }
243 return stamp;
244 }
245
246 String get _content {
247 String content = _provider._pathToContent[path];
248 if (content == null) {
249 throw new FileSystemException(path, 'File "$path" does not exist.');
250 }
251 return content;
252 }
253
254 @override
255 Source createSource([Uri uri]) {
256 if (uri == null) {
257 uri = posix.toUri(path);
258 }
259 return new _MemoryFileSource(this, uri);
260 }
261
262 @override
263 bool isOrContains(String path) {
264 return path == this.path;
265 }
266
267 @override
268 String readAsStringSync() {
269 String content = _provider._pathToContent[path];
270 if (content == null) {
271 throw new FileSystemException(path, 'File "$path" does not exist.');
272 }
273 return content;
274 }
275 }
276
277 /**
278 * An in-memory implementation of [Source].
279 */
280 class _MemoryFileSource extends Source {
281 /**
282 * Map from encoded URI/filepath pair to a unique integer identifier. This
283 * identifier is used for equality tests and hash codes.
284 *
285 * The URI and filepath are joined into a pair by separating them with an '@'
286 * character.
287 */
288 static final Map<String, int> _idTable = new HashMap<String, int>();
289
290 final _MemoryFile file;
291
292 final Uri uri;
293
294 /**
295 * The unique ID associated with this [_MemoryFileSource].
296 */
297 final int id;
298
299 _MemoryFileSource(_MemoryFile file, Uri uri)
300 : uri = uri,
301 file = file,
302 id = _idTable.putIfAbsent('$uri@${file.path}', () => _idTable.length);
303
304 @override
305 TimestampedData<String> get contents {
306 return new TimestampedData<String>(modificationStamp, file._content);
307 }
308
309 @override
310 String get encoding {
311 return uri.toString();
312 }
313
314 @override
315 String get fullName => file.path;
316
317 @override
318 int get hashCode => id;
319
320 @override
321 bool get isInSystemLibrary => uriKind == UriKind.DART_URI;
322
323 @override
324 int get modificationStamp {
325 try {
326 return file.modificationStamp;
327 } on FileSystemException {
328 return -1;
329 }
330 }
331
332 @override
333 String get shortName => file.shortName;
334
335 @override
336 UriKind get uriKind {
337 String scheme = uri.scheme;
338 if (scheme == PackageUriResolver.PACKAGE_SCHEME) {
339 return UriKind.PACKAGE_URI;
340 } else if (scheme == DartUriResolver.DART_SCHEME) {
341 return UriKind.DART_URI;
342 } else if (scheme == FileUriResolver.FILE_SCHEME) {
343 return UriKind.FILE_URI;
344 }
345 return UriKind.FILE_URI;
346 }
347
348 @override
349 bool operator ==(other) {
350 return other is _MemoryFileSource && other.id == id;
351 }
352
353 @override
354 bool exists() => file.exists;
355
356 @override
357 Uri resolveRelativeUri(Uri relativeUri) {
358 return uri.resolveUri(relativeUri);
359 }
360
361 @override
362 String toString() => file.toString();
363 }
364
365 /**
366 * An in-memory implementation of [Folder].
367 */
368 class _MemoryFolder extends _MemoryResource implements Folder {
369 _MemoryFolder(MemoryResourceProvider provider, String path)
370 : super(provider, path);
371
372 @override
373 bool get exists => _provider._pathToResource[path] is _MemoryFolder;
374
375 @override
376 String canonicalizePath(String relPath) {
377 relPath = posix.normalize(relPath);
378 String childPath = posix.join(path, relPath);
379 childPath = posix.normalize(childPath);
380 return childPath;
381 }
382
383 @override
384 bool contains(String path) {
385 return posix.isWithin(this.path, path);
386 }
387
388 @override
389 Resource getChild(String relPath) {
390 String childPath = canonicalizePath(relPath);
391 _MemoryResource resource = _provider._pathToResource[childPath];
392 if (resource == null) {
393 resource = new _MemoryFile(_provider, childPath);
394 }
395 return resource;
396 }
397
398 @override
399 _MemoryFolder getChildAssumingFolder(String relPath) {
400 String childPath = canonicalizePath(relPath);
401 _MemoryResource resource = _provider._pathToResource[childPath];
402 if (resource is _MemoryFolder) {
403 return resource;
404 }
405 return new _MemoryFolder(_provider, childPath);
406 }
407
408 @override
409 List<Resource> getChildren() {
410 if (!exists) {
411 throw new FileSystemException(path, 'Folder does not exist.');
412 }
413 List<Resource> children = <Resource>[];
414 _provider._pathToResource.forEach((resourcePath, resource) {
415 if (posix.dirname(resourcePath) == path) {
416 children.add(resource);
417 }
418 });
419 return children;
420 }
421
422 @override
423 bool isOrContains(String path) {
424 if (path == this.path) {
425 return true;
426 }
427 return contains(path);
428 }
429 }
430
431 /**
432 * An in-memory implementation of [Resource].
433 */
434 abstract class _MemoryResource implements Resource {
435 final MemoryResourceProvider _provider;
436 final String path;
437
438 _MemoryResource(this._provider, this.path);
439
440 Stream<WatchEvent> get changes {
441 StreamController<WatchEvent> streamController =
442 new StreamController<WatchEvent>();
443 if (!_provider._pathToWatchers.containsKey(path)) {
444 _provider._pathToWatchers[path] = <StreamController<WatchEvent>>[];
445 }
446 _provider._pathToWatchers[path].add(streamController);
447 streamController.done.then((_) {
448 _provider._pathToWatchers[path].remove(streamController);
449 if (_provider._pathToWatchers[path].isEmpty) {
450 _provider._pathToWatchers.remove(path);
451 }
452 });
453 return streamController.stream;
454 }
455
456 @override
457 get hashCode => path.hashCode;
458
459 @override
460 Folder get parent {
461 String parentPath = posix.dirname(path);
462 if (parentPath == path) {
463 return null;
464 }
465 return _provider.getResource(parentPath);
466 }
467
468 @override
469 String get shortName => posix.basename(path);
470
471 @override
472 bool operator ==(other) {
473 if (runtimeType != other.runtimeType) {
474 return false;
475 }
476 return path == other.path;
477 }
478
479 @override
480 String toString() => path;
481 }
OLDNEW
« no previous file with comments | « analyzer/lib/file_system/file_system.dart ('k') | analyzer/lib/file_system/physical_file_system.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698