| Index: pkg/analysis_server/lib/src/resource.dart
|
| diff --git a/pkg/analysis_server/lib/src/resource.dart b/pkg/analysis_server/lib/src/resource.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2db8d615b1152d1cafda3c36bed5ea685c1d84f2
|
| --- /dev/null
|
| +++ b/pkg/analysis_server/lib/src/resource.dart
|
| @@ -0,0 +1,381 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library resource;
|
| +
|
| +import 'dart:io' as io;
|
| +
|
| +import 'package:analyzer/src/generated/engine.dart' show TimestampedData;
|
| +import 'package:analyzer/src/generated/java_io.dart';
|
| +import 'package:analyzer/src/generated/source_io.dart';
|
| +import 'package:path/path.dart';
|
| +
|
| +
|
| +/**
|
| + * [File]s are leaf [Resource]s which contain data.
|
| + */
|
| +abstract class File extends Resource {
|
| + /**
|
| + * Create a new [Source] instance that serves this file.
|
| + */
|
| + Source createSource(UriKind uriKind);
|
| +}
|
| +
|
| +
|
| +/**
|
| + * [Folder]s are [Resource]s which may contain files and/or other folders.
|
| + */
|
| +abstract class Folder extends Resource {
|
| + /**
|
| + * Return an existing child [Resource] with the given [relPath].
|
| + * Return a not existing [File] if no such child exist.
|
| + */
|
| + Resource getChild(String relPath);
|
| +
|
| + /**
|
| + * Return a list of existing direct children [Resource]s (folders and files)
|
| + * in this folder, in no particular order.
|
| + */
|
| + List<Resource> getChildren();
|
| +}
|
| +
|
| +
|
| +/**
|
| + * The abstract class [Resource] is an abstraction of file or folder.
|
| + */
|
| +abstract class Resource {
|
| + /**
|
| + * Return `true` if this resource exists.
|
| + */
|
| + bool get exists;
|
| +
|
| + /**
|
| + * Return the full (long) version of the name that can be displayed to the
|
| + * user to denote this resource.
|
| + */
|
| + String get fullName;
|
| +
|
| + /**
|
| + * Return a short version of the name that can be displayed to the user to
|
| + * denote this resource.
|
| + */
|
| + String get shortName;
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Instances of the class [ResourceProvider] convert [String] paths into
|
| + * [Resource]s.
|
| + */
|
| +abstract class ResourceProvider {
|
| + /**
|
| + * Return the [Resource] that corresponds to the given [path].
|
| + */
|
| + Resource getResource(String path);
|
| +}
|
| +
|
| +
|
| +/**
|
| + * An in-memory implementation of [Resource].
|
| + */
|
| +abstract class _MemoryResource implements Resource {
|
| + final MemoryResourceProvider _provider;
|
| + final String _path;
|
| +
|
| + _MemoryResource(this._provider, this._path);
|
| +
|
| + @override
|
| + bool operator ==(other) {
|
| + return identical(this, other);
|
| + }
|
| +
|
| + @override
|
| + bool get exists => _provider._pathToResource.containsKey(_path);
|
| +
|
| + @override
|
| + String get fullName => _path;
|
| +
|
| + @override
|
| + get hashCode => _path.hashCode;
|
| +
|
| + @override
|
| + String get shortName => basename(_path);
|
| +
|
| + @override
|
| + String toString() => fullName;
|
| +}
|
| +
|
| +
|
| +/**
|
| + * An in-memory implementation of [File].
|
| + */
|
| +class _MemoryFile extends _MemoryResource implements File {
|
| + _MemoryFile(MemoryResourceProvider provider, String path) :
|
| + super(provider, path);
|
| +
|
| + @override
|
| + Source createSource(UriKind uriKind) {
|
| + return new _MemoryFileSource(this, uriKind);
|
| + }
|
| +
|
| + String get _content {
|
| + String content = _provider._pathToContent[_path];
|
| + if (content == null) {
|
| + throw new MemoryResourceException(_path, "File '$_path' does not exist");
|
| + }
|
| + return content;
|
| + }
|
| +
|
| + int get _timestamp => _provider._pathToTimestamp[_path];
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Exception thrown when a memory [Resource] file operation fails.
|
| + */
|
| +class MemoryResourceException {
|
| + final path;
|
| + final message;
|
| +
|
| + MemoryResourceException(this.path, this.message);
|
| +
|
| + @override
|
| + String toString() {
|
| + return "MemoryResourceException(path=$path; message=$message)";
|
| + }
|
| +}
|
| +
|
| +
|
| +/**
|
| + * An in-memory implementation of [Source].
|
| + */
|
| +class _MemoryFileSource implements Source {
|
| + final _MemoryFile _file;
|
| +
|
| + final UriKind uriKind;
|
| +
|
| + _MemoryFileSource(this._file, this.uriKind);
|
| +
|
| + @override
|
| + TimestampedData<String> get contents {
|
| + return new TimestampedData<String>(modificationStamp, _file._content);
|
| + }
|
| +
|
| + @override
|
| + String get encoding {
|
| + return '${new String.fromCharCode(uriKind.encoding)}${_file.fullName}';
|
| + }
|
| +
|
| + @override
|
| + bool exists() => _file.exists;
|
| +
|
| + @override
|
| + String get fullName => _file.fullName;
|
| +
|
| + @override
|
| + bool get isInSystemLibrary => false;
|
| +
|
| + @override
|
| + int get modificationStamp => _file._timestamp;
|
| +
|
| + @override
|
| + Source resolveRelative(Uri relativeUri) {
|
| + String relativePath = fromUri(relativeUri);
|
| + String folderPath = dirname(_file._path);
|
| + String path = join(folderPath, relativePath);
|
| + path = normalize(path);
|
| + _MemoryFile file = new _MemoryFile(_file._provider, path);
|
| + return new _MemoryFileSource(file, uriKind);
|
| + }
|
| +
|
| + @override
|
| + String get shortName => _file.shortName;
|
| +}
|
| +
|
| +
|
| +/**
|
| + * An in-memory implementation of [Folder].
|
| + */
|
| +class _MemoryFolder extends _MemoryResource implements Folder {
|
| + _MemoryFolder(MemoryResourceProvider provider, String path) :
|
| + super(provider, path);
|
| + @override
|
| + Resource getChild(String relPath) {
|
| + relPath = normalize(relPath);
|
| + String childPath = join(_path, relPath);
|
| + childPath = normalize(childPath);
|
| + _MemoryResource resource = _provider._pathToResource[childPath];
|
| + if (resource == null) {
|
| + resource = new _MemoryFile(_provider, childPath);
|
| + }
|
| + return resource;
|
| + }
|
| +
|
| + @override
|
| + List<Resource> getChildren() {
|
| + List<Resource> children = <Resource>[];
|
| + _provider._pathToResource.forEach((path, resource) {
|
| + if (dirname(path) == _path) {
|
| + children.add(resource);
|
| + }
|
| + });
|
| + return children;
|
| + }
|
| +}
|
| +
|
| +
|
| +/**
|
| + * An in-memory implementation of [ResourceProvider].
|
| + * Use `/` as a path separator.
|
| + */
|
| +class MemoryResourceProvider implements ResourceProvider {
|
| + final Map<String, _MemoryResource> _pathToResource = <String, _MemoryResource>{};
|
| + final Map<String, String> _pathToContent = <String, String>{};
|
| + final Map<String, int> _pathToTimestamp = <String, int>{};
|
| + int nextStamp = 0;
|
| +
|
| + @override
|
| + Resource getResource(String path) {
|
| + path = normalize(path);
|
| + Resource resource = _pathToResource[path];
|
| + if (resource == null) {
|
| + resource = new _MemoryFile(this, path);
|
| + }
|
| + return resource;
|
| + }
|
| +
|
| + Folder newFolder(String path) {
|
| + path = normalize(path);
|
| + if (path.isEmpty) {
|
| + throw new ArgumentError('Empty paths are not supported');
|
| + }
|
| + if (!path.startsWith('/')) {
|
| + throw new ArgumentError("Path must start with '/'");
|
| + }
|
| + _MemoryFolder folder = null;
|
| + String partialPath = "";
|
| + for (String pathPart in path.split('/')) {
|
| + if (pathPart.isEmpty) {
|
| + continue;
|
| + }
|
| + partialPath += '/' + pathPart;
|
| + _MemoryResource resource = _pathToResource[partialPath];
|
| + if (resource == null) {
|
| + folder = new _MemoryFolder(this, partialPath);
|
| + _pathToResource[partialPath] = folder;
|
| + _pathToTimestamp[partialPath] = nextStamp++;
|
| + } else if (resource is _MemoryFolder) {
|
| + folder = resource;
|
| + } else {
|
| + String message = 'Folder expected at '
|
| + "'$partialPath'"
|
| + 'but ${resource.runtimeType} found';
|
| + throw new ArgumentError(message);
|
| + }
|
| + }
|
| + return folder;
|
| + }
|
| +
|
| + File newFile(String path, String content) {
|
| + path = normalize(path);
|
| + newFolder(dirname(path));
|
| + _MemoryFile file = new _MemoryFile(this, path);
|
| + _pathToResource[path] = file;
|
| + _pathToContent[path] = content;
|
| + _pathToTimestamp[path] = nextStamp++;
|
| + return file;
|
| + }
|
| +}
|
| +
|
| +
|
| +/**
|
| + * A `dart:io` based implementation of [File].
|
| + */
|
| +class _PhysicalFile extends _PhysicalResource implements File {
|
| + _PhysicalFile(io.File file) : super(file);
|
| +
|
| + @override
|
| + Source createSource(UriKind uriKind) {
|
| + io.File file = _entry as io.File;
|
| + JavaFile javaFile = new JavaFile(file.absolute.path);
|
| + return new FileBasedSource.con2(javaFile, uriKind);
|
| + }
|
| +}
|
| +
|
| +
|
| +/**
|
| + * A `dart:io` based implementation of [Folder].
|
| + */
|
| +class _PhysicalFolder extends _PhysicalResource implements Folder {
|
| + _PhysicalFolder(io.Directory directory) : super(directory);
|
| +
|
| + @override
|
| + Resource getChild(String relPath) {
|
| + String childPath = join(_entry.absolute.path, relPath);
|
| + return PhysicalResourceProvider.INSTANCE.getResource(childPath);
|
| + }
|
| +
|
| + @override
|
| + List<Resource> getChildren() {
|
| + List<Resource> children = <Resource>[];
|
| + io.Directory directory = _entry as io.Directory;
|
| + List<io.FileSystemEntity> entries = directory.listSync(recursive: false);
|
| + int numEntries = entries.length;
|
| + for (int i = 0; i < numEntries; i++) {
|
| + io.FileSystemEntity entity = entries[i];
|
| + if (entity is io.Directory) {
|
| + children.add(new _PhysicalFolder(entity));
|
| + } else if (entity is io.File) {
|
| + children.add(new _PhysicalFile(entity));
|
| + }
|
| + }
|
| + return children;
|
| + }
|
| +}
|
| +
|
| +
|
| +/**
|
| + * A `dart:io` based implementation of [Resource].
|
| + */
|
| +abstract class _PhysicalResource implements Resource {
|
| + final io.FileSystemEntity _entry;
|
| +
|
| + _PhysicalResource(this._entry);
|
| +
|
| + @override
|
| + bool get exists => _entry.existsSync();
|
| +
|
| + @override
|
| + String get fullName => _entry.absolute.path;
|
| +
|
| + @override
|
| + get hashCode => _entry.hashCode;
|
| +
|
| + @override
|
| + String get shortName => basename(fullName);
|
| +
|
| + @override
|
| + String toString() => fullName;
|
| +}
|
| +
|
| +
|
| +/**
|
| + * A `dart:io` based implementation of [ResourceProvider].
|
| + */
|
| +class PhysicalResourceProvider implements ResourceProvider {
|
| + static final PhysicalResourceProvider INSTANCE = new PhysicalResourceProvider._();
|
| +
|
| + PhysicalResourceProvider._();
|
| +
|
| + @override
|
| + Resource getResource(String path) {
|
| + if (io.FileSystemEntity.isDirectorySync(path)) {
|
| + io.Directory directory = new io.Directory(path);
|
| + return new _PhysicalFolder(directory);
|
| + } else {
|
| + io.File file = new io.File(path);
|
| + return new _PhysicalFile(file);
|
| + }
|
| + }
|
| +}
|
|
|