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

Side by Side Diff: pkg/analysis_server/lib/src/resource.dart

Issue 372763003: Move file_system libraries into 'analyzer'. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 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
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 resource;
6
7 import 'dart:async';
8 import 'dart:collection';
9 import 'dart:io' as io;
10
11 import 'package:analyzer/src/generated/engine.dart' show TimestampedData;
12 import 'package:analyzer/src/generated/java_io.dart';
13 import 'package:analyzer/src/generated/source_io.dart';
14 import 'package:path/path.dart';
15 import 'package:watcher/watcher.dart';
16
17
18 /**
19 * [File]s are leaf [Resource]s which contain data.
20 */
21 abstract class File extends Resource {
22 /**
23 * Create a new [Source] instance that serves this file.
24 */
25 Source createSource(UriKind uriKind);
26 }
27
28
29 /**
30 * [Folder]s are [Resource]s which may contain files and/or other folders.
31 */
32 abstract class Folder extends Resource {
33 /**
34 * Return an existing child [Resource] with the given [relPath].
35 * Return a not existing [File] if no such child exist.
36 */
37 Resource getChild(String relPath);
38
39 /**
40 * Return a list of existing direct children [Resource]s (folders and files)
41 * in this folder, in no particular order.
42 */
43 List<Resource> getChildren();
44
45 /**
46 * Watch for changes to the files inside this folder (and in any nested
47 * folders, including folders reachable via links).
48 */
49 Stream<WatchEvent> get changes;
50
51 /**
52 * If the path [path] is a relative path, convert it to an absolute path
53 * by interpreting it relative to this folder. If it is already an aboslute
54 * path, then don't change it.
55 *
56 * However, regardless of whether [path] is relative or absolute, normalize
57 * it by removing path components of the form '.' or '..'.
58 */
59 String canonicalizePath(String path);
60 }
61
62
63 /**
64 * The abstract class [Resource] is an abstraction of file or folder.
65 */
66 abstract class Resource {
67 /**
68 * Return `true` if this resource exists.
69 */
70 bool get exists;
71
72 /**
73 * Return the full path to this resource.
74 */
75 String get path;
76
77 /**
78 * Return a short version of the name that can be displayed to the user to
79 * denote this resource.
80 */
81 String get shortName;
82
83 /**
84 * Return the [Folder] that contains this resource, or `null` if this resource
85 * is a root folder.
86 */
87 Folder get parent;
88 }
89
90
91 /**
92 * Instances of the class [ResourceProvider] convert [String] paths into
93 * [Resource]s.
94 */
95 abstract class ResourceProvider {
96 /**
97 * Return the [Resource] that corresponds to the given [path].
98 */
99 Resource getResource(String path);
100
101 /**
102 * Get the path context used by this resource provider.
103 */
104 Context get pathContext;
105 }
106
107
108 /**
109 * An in-memory implementation of [Resource].
110 */
111 abstract class _MemoryResource implements Resource {
112 final MemoryResourceProvider _provider;
113 final String path;
114
115 _MemoryResource(this._provider, this.path);
116
117 @override
118 bool operator ==(other) {
119 if (runtimeType != other.runtimeType) {
120 return false;
121 }
122 return path == other.path;
123 }
124
125 @override
126 bool get exists => _provider._pathToResource.containsKey(path);
127
128 @override
129 get hashCode => path.hashCode;
130
131 @override
132 String get shortName => posix.basename(path);
133
134 @override
135 String toString() => path;
136
137 @override
138 Folder get parent {
139 String parentPath = posix.dirname(path);
140 if (parentPath == path) {
141 return null;
142 }
143 return _provider.getResource(parentPath);
144 }
145 }
146
147
148 /**
149 * An in-memory implementation of [File].
150 */
151 class _MemoryFile extends _MemoryResource implements File {
152 _MemoryFile(MemoryResourceProvider provider, String path) :
153 super(provider, path);
154
155 @override
156 Source createSource(UriKind uriKind) {
157 return new _MemoryFileSource(this, uriKind);
158 }
159
160 String get _content {
161 String content = _provider._pathToContent[path];
162 if (content == null) {
163 throw new MemoryResourceException(path, "File '$path' does not exist");
164 }
165 return content;
166 }
167
168 int get _timestamp => _provider._pathToTimestamp[path];
169 }
170
171
172 /**
173 * Exception thrown when a memory [Resource] file operation fails.
174 */
175 class MemoryResourceException {
176 final path;
177 final message;
178
179 MemoryResourceException(this.path, this.message);
180
181 @override
182 String toString() {
183 return "MemoryResourceException(path=$path; message=$message)";
184 }
185 }
186
187
188 /**
189 * An in-memory implementation of [File] which acts like a symbolic link to a
190 * non-existent file.
191 */
192 class _MemoryDummyLink extends _MemoryResource implements File {
193 _MemoryDummyLink(MemoryResourceProvider provider, String path) :
194 super(provider, path);
195
196 @override
197 Source createSource(UriKind uriKind) {
198 throw new MemoryResourceException(path, "File '$path' could not be read");
199 }
200
201 String get _content {
202 throw new MemoryResourceException(path, "File '$path' could not be read");
203 }
204
205 int get _timestamp => _provider._pathToTimestamp[path];
206
207 @override
208 bool get exists => false;
209 }
210
211
212 /**
213 * An in-memory implementation of [Source].
214 */
215 class _MemoryFileSource implements Source {
216 final _MemoryFile _file;
217
218 final UriKind uriKind;
219
220 _MemoryFileSource(this._file, this.uriKind);
221
222 @override
223 bool operator ==(other) {
224 if (other is _MemoryFileSource) {
225 return other._file == _file;
226 }
227 return false;
228 }
229
230 @override
231 TimestampedData<String> get contents {
232 return new TimestampedData<String>(modificationStamp, _file._content);
233 }
234
235 @override
236 String get encoding {
237 return '${new String.fromCharCode(uriKind.encoding)}${_file.path}';
238 }
239
240 @override
241 bool exists() => _file.exists;
242
243 @override
244 String get fullName => _file.path;
245
246 @override
247 int get hashCode => _file.hashCode;
248
249 @override
250 bool get isInSystemLibrary => false;
251
252 @override
253 int get modificationStamp => _file._timestamp;
254
255 @override
256 Source resolveRelative(Uri relativeUri) {
257 String relativePath = posix.fromUri(relativeUri);
258 String folderPath = posix.dirname(_file.path);
259 String path = posix.join(folderPath, relativePath);
260 path = posix.normalize(path);
261 _MemoryFile file = new _MemoryFile(_file._provider, path);
262 return new _MemoryFileSource(file, uriKind);
263 }
264
265 @override
266 String get shortName => _file.shortName;
267 }
268
269
270 /**
271 * An in-memory implementation of [Folder].
272 */
273 class _MemoryFolder extends _MemoryResource implements Folder {
274 _MemoryFolder(MemoryResourceProvider provider, String path) :
275 super(provider, path);
276 @override
277 Resource getChild(String relPath) {
278 String childPath = canonicalizePath(relPath);
279 _MemoryResource resource = _provider._pathToResource[childPath];
280 if (resource == null) {
281 resource = new _MemoryFile(_provider, childPath);
282 }
283 return resource;
284 }
285
286 @override
287 List<Resource> getChildren() {
288 List<Resource> children = <Resource>[];
289 _provider._pathToResource.forEach((resourcePath, resource) {
290 if (posix.dirname(resourcePath) == path) {
291 children.add(resource);
292 }
293 });
294 return children;
295 }
296
297 @override
298 Stream<WatchEvent> get changes {
299 StreamController<WatchEvent> streamController = new StreamController<WatchEv ent>();
300 if (!_provider._pathToWatchers.containsKey(path)) {
301 _provider._pathToWatchers[path] = <StreamController<WatchEvent>>[];
302 }
303 _provider._pathToWatchers[path].add(streamController);
304 streamController.done.then((_) {
305 _provider._pathToWatchers[path].remove(streamController);
306 if (_provider._pathToWatchers[path].isEmpty) {
307 _provider._pathToWatchers.remove(path);
308 }
309 });
310 return streamController.stream;
311 }
312
313 @override
314 String canonicalizePath(String relPath) {
315 relPath = posix.normalize(relPath);
316 String childPath = posix.join(path, relPath);
317 childPath = posix.normalize(childPath);
318 return childPath;
319 }
320 }
321
322
323 /**
324 * An in-memory implementation of [ResourceProvider].
325 * Use `/` as a path separator.
326 */
327 class MemoryResourceProvider implements ResourceProvider {
328 final Map<String, _MemoryResource> _pathToResource =
329 new HashMap<String, _MemoryResource>();
330 final Map<String, String> _pathToContent = new HashMap<String, String>();
331 final Map<String, int> _pathToTimestamp = new HashMap<String, int>();
332 final Map<String, List<StreamController<WatchEvent>>> _pathToWatchers =
333 new HashMap<String, List<StreamController<WatchEvent>>>();
334 int nextStamp = 0;
335
336 @override
337 Resource getResource(String path) {
338 path = posix.normalize(path);
339 Resource resource = _pathToResource[path];
340 if (resource == null) {
341 resource = new _MemoryFile(this, path);
342 }
343 return resource;
344 }
345
346 Folder newFolder(String path) {
347 path = posix.normalize(path);
348 if (!path.startsWith('/')) {
349 throw new ArgumentError("Path must start with '/'");
350 }
351 _MemoryResource resource = _pathToResource[path];
352 if (resource == null) {
353 String parentPath = posix.dirname(path);
354 if (parentPath != path) {
355 newFolder(parentPath);
356 }
357 _MemoryFolder folder = new _MemoryFolder(this, path);
358 _pathToResource[path] = folder;
359 _pathToTimestamp[path] = nextStamp++;
360 return folder;
361 } else if (resource is _MemoryFolder) {
362 return resource;
363 } else {
364 String message = 'Folder expected at '
365 "'$path'"
366 'but ${resource.runtimeType} found';
367 throw new ArgumentError(message);
368 }
369 }
370
371 File newFile(String path, String content) {
372 path = posix.normalize(path);
373 newFolder(posix.dirname(path));
374 _MemoryFile file = new _MemoryFile(this, path);
375 _pathToResource[path] = file;
376 _pathToContent[path] = content;
377 _pathToTimestamp[path] = nextStamp++;
378 _notifyWatchers(path, ChangeType.ADD);
379 return file;
380 }
381
382 /**
383 * Create a resource representing a dummy link (that is, a File object which
384 * appears in its parent directory, but whose `exists` property is false)
385 */
386 File newDummyLink(String path) {
387 path = posix.normalize(path);
388 newFolder(posix.dirname(path));
389 _MemoryDummyLink link = new _MemoryDummyLink(this, path);
390 _pathToResource[path] = link;
391 _pathToTimestamp[path] = nextStamp++;
392 _notifyWatchers(path, ChangeType.ADD);
393 return link;
394 }
395
396 void _notifyWatchers(String path, ChangeType changeType) {
397 _pathToWatchers.forEach((String watcherPath, List<StreamController<WatchEven t>> streamControllers) {
398 if (posix.isWithin(watcherPath, path)) {
399 for (StreamController<WatchEvent> streamController in streamControllers) {
400 streamController.add(new WatchEvent(changeType, path));
401 }
402 }
403 });
404 }
405
406 void modifyFile(String path, String content) {
407 _checkFileAtPath(path);
408 _pathToContent[path] = content;
409 _pathToTimestamp[path] = nextStamp++;
410 _notifyWatchers(path, ChangeType.MODIFY);
411 }
412
413 void _checkFileAtPath(String path) {
414 _MemoryResource resource = _pathToResource[path];
415 if (resource is! _MemoryFile) {
416 throw new ArgumentError(
417 'File expected at "$path" but ${resource.runtimeType} found');
418 }
419 }
420
421 void deleteFile(String path) {
422 _checkFileAtPath(path);
423 _pathToResource.remove(path);
424 _pathToContent.remove(path);
425 _pathToTimestamp.remove(path);
426 _notifyWatchers(path, ChangeType.REMOVE);
427 }
428
429 @override
430 Context get pathContext => posix;
431 }
432
433
434 /**
435 * A `dart:io` based implementation of [File].
436 */
437 class _PhysicalFile extends _PhysicalResource implements File {
438 _PhysicalFile(io.File file) : super(file);
439
440 @override
441 Source createSource(UriKind uriKind) {
442 io.File file = _entry as io.File;
443 JavaFile javaFile = new JavaFile(file.absolute.path);
444 return new FileBasedSource.con2(javaFile, uriKind);
445 }
446 }
447
448
449 /**
450 * A `dart:io` based implementation of [Folder].
451 */
452 class _PhysicalFolder extends _PhysicalResource implements Folder {
453 _PhysicalFolder(io.Directory directory) : super(directory);
454
455 @override
456 Resource getChild(String relPath) {
457 return PhysicalResourceProvider.INSTANCE.getResource(canonicalizePath(relPat h));
458 }
459
460 @override
461 List<Resource> getChildren() {
462 List<Resource> children = <Resource>[];
463 io.Directory directory = _entry as io.Directory;
464 List<io.FileSystemEntity> entries = directory.listSync(recursive: false);
465 int numEntries = entries.length;
466 for (int i = 0; i < numEntries; i++) {
467 io.FileSystemEntity entity = entries[i];
468 if (entity is io.Directory) {
469 children.add(new _PhysicalFolder(entity));
470 } else if (entity is io.File) {
471 children.add(new _PhysicalFile(entity));
472 }
473 }
474 return children;
475 }
476
477 @override
478 Stream<WatchEvent> get changes => new DirectoryWatcher(_entry.path).events;
479
480 @override
481 String canonicalizePath(String relPath) {
482 return normalize(join(_entry.absolute.path, relPath));
483 }
484 }
485
486
487 /**
488 * A `dart:io` based implementation of [Resource].
489 */
490 abstract class _PhysicalResource implements Resource {
491 final io.FileSystemEntity _entry;
492
493 _PhysicalResource(this._entry);
494
495 @override
496 bool get exists => _entry.existsSync();
497
498 @override
499 String get path => _entry.absolute.path;
500
501 @override
502 get hashCode => path.hashCode;
503
504 @override
505 bool operator==(other) {
506 if (runtimeType != other.runtimeType) {
507 return false;
508 }
509 return path == other.path;
510 }
511
512 @override
513 String get shortName => basename(path);
514
515 @override
516 String toString() => path;
517
518 @override
519 Folder get parent {
520 String parentPath = dirname(path);
521 if (parentPath == path) {
522 return null;
523 }
524 return new _PhysicalFolder(new io.Directory(parentPath));
525 }
526 }
527
528
529 /**
530 * A `dart:io` based implementation of [ResourceProvider].
531 */
532 class PhysicalResourceProvider implements ResourceProvider {
533 static final PhysicalResourceProvider INSTANCE = new PhysicalResourceProvider. _();
534
535 PhysicalResourceProvider._();
536
537 @override
538 Resource getResource(String path) {
539 if (io.FileSystemEntity.isDirectorySync(path)) {
540 io.Directory directory = new io.Directory(path);
541 return new _PhysicalFolder(directory);
542 } else {
543 io.File file = new io.File(path);
544 return new _PhysicalFile(file);
545 }
546 }
547
548 @override
549 Context get pathContext => io.Platform.isWindows ? windows : posix;
550 }
551
552
553 /**
554 * A [UriResolver] for [Resource]s.
555 */
556 class ResourceUriResolver extends UriResolver {
557 /**
558 * The name of the `file` scheme.
559 */
560 static String _FILE_SCHEME = "file";
561
562 final ResourceProvider _provider;
563
564 ResourceUriResolver(this._provider);
565
566 @override
567 Source fromEncoding(UriKind kind, Uri uri) {
568 if (kind == UriKind.FILE_URI) {
569 Resource resource = _provider.getResource(uri.path);
570 if (resource is File) {
571 return resource.createSource(kind);
572 }
573 }
574 return null;
575 }
576
577 @override
578 Source resolveAbsolute(Uri uri) {
579 if (!_isFileUri(uri)) {
580 return null;
581 }
582 Resource resource = _provider.getResource(uri.path);
583 if (resource is File) {
584 return resource.createSource(UriKind.FILE_URI);
585 }
586 return null;
587 }
588
589 /**
590 * Return `true` if the given URI is a `file` URI.
591 *
592 * @param uri the URI being tested
593 * @return `true` if the given URI is a `file` URI
594 */
595 static bool _isFileUri(Uri uri) => uri.scheme == _FILE_SCHEME;
596 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/lib/src/package_uri_resolver.dart ('k') | pkg/analysis_server/lib/src/socket_server.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698