8a3d8eee67
R=brianwilkerson@google.com, jwren@google.com BUG= Review URL: https://codereview.chromium.org/2393813003 .
280 lines
7.5 KiB
Dart
280 lines
7.5 KiB
Dart
// 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 analyzer.file_system.file_system;
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:analyzer/src/generated/source.dart';
|
|
import 'package:analyzer/src/util/absolute_path.dart';
|
|
import 'package:path/path.dart';
|
|
import 'package:watcher/watcher.dart';
|
|
|
|
/**
|
|
* [File]s are leaf [Resource]s which contain data.
|
|
*/
|
|
abstract class File implements Resource {
|
|
/**
|
|
* Watch for changes to this file
|
|
*/
|
|
Stream<WatchEvent> get changes;
|
|
|
|
/**
|
|
* Return the last-modified stamp of the file.
|
|
* Throws [FileSystemException] if the file does not exist.
|
|
*/
|
|
int get modificationStamp;
|
|
|
|
/**
|
|
* Create a new [Source] instance that serves this file.
|
|
*/
|
|
Source createSource([Uri uri]);
|
|
|
|
/**
|
|
* Synchronously read the entire file contents as a list of bytes.
|
|
* Throws a [FileSystemException] if the operation fails.
|
|
*/
|
|
List<int> readAsBytesSync();
|
|
|
|
/**
|
|
* Synchronously read the entire file contents as a [String].
|
|
* Throws [FileSystemException] if the file does not exist.
|
|
*/
|
|
String readAsStringSync();
|
|
|
|
/**
|
|
* Synchronously rename this file.
|
|
* Return a [File] instance for the renamed file.
|
|
*
|
|
* If [newPath] identifies an existing file, that file is replaced.
|
|
* If [newPath] identifies an existing resource the operation might fail and
|
|
* an exception is thrown.
|
|
*/
|
|
File renameSync(String newPath);
|
|
|
|
/**
|
|
* Synchronously write the given [bytes] to the file. The new content will
|
|
* replace any existing content.
|
|
*
|
|
* Throws a [FileSystemException] if the operation fails.
|
|
*/
|
|
void writeAsBytesSync(List<int> bytes);
|
|
|
|
/**
|
|
* Synchronously write the given [content] to the file. The new content will
|
|
* replace any existing content.
|
|
*
|
|
* Throws a [FileSystemException] if the operation fails.
|
|
*/
|
|
void writeAsStringSync(String content);
|
|
}
|
|
|
|
/**
|
|
* Base class for all file system exceptions.
|
|
*/
|
|
class FileSystemException implements Exception {
|
|
final String path;
|
|
final String message;
|
|
|
|
FileSystemException(this.path, this.message);
|
|
|
|
@override
|
|
String toString() => 'FileSystemException(path=$path; message=$message)';
|
|
}
|
|
|
|
/**
|
|
* [Folder]s are [Resource]s which may contain files and/or other folders.
|
|
*/
|
|
abstract class Folder implements Resource {
|
|
/**
|
|
* Watch for changes to the files inside this folder (and in any nested
|
|
* folders, including folders reachable via links).
|
|
*/
|
|
Stream<WatchEvent> get changes;
|
|
|
|
/**
|
|
* If the path [path] is a relative path, convert it to an absolute path
|
|
* by interpreting it relative to this folder. If it is already an absolute
|
|
* path, then don't change it.
|
|
*
|
|
* However, regardless of whether [path] is relative or absolute, normalize
|
|
* it by removing path components of the form '.' or '..'.
|
|
*/
|
|
String canonicalizePath(String path);
|
|
|
|
/**
|
|
* Return `true` if absolute [path] references a resource in this folder.
|
|
*/
|
|
bool contains(String path);
|
|
|
|
/**
|
|
* 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 [File] representing a child [Resource] with the given
|
|
* [relPath]. This call does not check whether a file with the given name
|
|
* exists on the filesystem - client must call the [File]'s `exists` getter
|
|
* to determine whether the folder actually exists.
|
|
*/
|
|
File getChildAssumingFile(String relPath);
|
|
|
|
/**
|
|
* Return a [Folder] representing a child [Resource] with the given
|
|
* [relPath]. This call does not check whether a folder with the given name
|
|
* exists on the filesystem--client must call the [Folder]'s `exists` getter
|
|
* to determine whether the folder actually exists.
|
|
*/
|
|
Folder getChildAssumingFolder(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 [Folder] that contains this resource, or `null` if this resource
|
|
* is a root folder.
|
|
*/
|
|
Folder get parent;
|
|
|
|
/**
|
|
* Return the full path to this resource.
|
|
*/
|
|
String get path;
|
|
|
|
/**
|
|
* Return a short version of the name that can be displayed to the user to
|
|
* denote this resource.
|
|
*/
|
|
String get shortName;
|
|
|
|
/**
|
|
* Synchronously deletes this resource and its children.
|
|
*
|
|
* Throws an exception if the resource cannot be deleted.
|
|
*/
|
|
void delete();
|
|
|
|
/**
|
|
* Return `true` if absolute [path] references this resource or a resource in
|
|
* this folder.
|
|
*/
|
|
bool isOrContains(String path);
|
|
|
|
/**
|
|
* Return a resource that refers to the same resource as this resource, but
|
|
* whose path does not contain any symbolic links.
|
|
*/
|
|
Resource resolveSymbolicLinksSync();
|
|
|
|
/**
|
|
* Return a Uri representing this resource.
|
|
*/
|
|
Uri toUri();
|
|
}
|
|
|
|
/**
|
|
* Instances of the class [ResourceProvider] convert [String] paths into
|
|
* [Resource]s.
|
|
*/
|
|
abstract class ResourceProvider {
|
|
/**
|
|
* Get the absolute path context used by this resource provider.
|
|
*/
|
|
AbsolutePathContext get absolutePathContext;
|
|
|
|
/**
|
|
* Get the path context used by this resource provider.
|
|
*/
|
|
Context get pathContext;
|
|
|
|
/**
|
|
* Return a [File] that corresponds to the given [path].
|
|
*
|
|
* A file may or may not exist at this location.
|
|
*/
|
|
File getFile(String path);
|
|
|
|
/**
|
|
* Return a [Folder] that corresponds to the given [path].
|
|
*
|
|
* A folder may or may not exist at this location.
|
|
*/
|
|
Folder getFolder(String path);
|
|
|
|
/**
|
|
* Complete with a list of modification times for the given [sources].
|
|
*
|
|
* If the file of a source is not managed by this provider, return `null`.
|
|
* If the file a source does not exist, return `-1`.
|
|
*/
|
|
Future<List<int>> getModificationTimes(List<Source> sources);
|
|
|
|
/**
|
|
* Return the [Resource] that corresponds to the given [path].
|
|
*/
|
|
Resource getResource(String path);
|
|
|
|
/**
|
|
* Return the folder in which the plugin with the given [pluginId] can store
|
|
* state that will persist across sessions. The folder returned for a given id
|
|
* will not be returned for a different id, ensuring that plugins do not need
|
|
* to be concerned with file name collisions with other plugins, assuming that
|
|
* the plugin ids are unique. The plugin ids must be valid folder names.
|
|
*/
|
|
Folder getStateLocation(String pluginId);
|
|
}
|
|
|
|
/**
|
|
* A [UriResolver] for [Resource]s.
|
|
*/
|
|
class ResourceUriResolver extends UriResolver {
|
|
/**
|
|
* The name of the `file` scheme.
|
|
*/
|
|
static final String FILE_SCHEME = "file";
|
|
|
|
final ResourceProvider _provider;
|
|
|
|
ResourceUriResolver(this._provider);
|
|
|
|
ResourceProvider get provider => _provider;
|
|
|
|
@override
|
|
Source resolveAbsolute(Uri uri, [Uri actualUri]) {
|
|
if (!isFileUri(uri)) {
|
|
return null;
|
|
}
|
|
String path = _provider.pathContext.fromUri(uri);
|
|
Resource resource = _provider.getResource(path);
|
|
if (resource is File) {
|
|
return resource.createSource(actualUri ?? uri);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@override
|
|
Uri restoreAbsolute(Source source) =>
|
|
_provider.pathContext.toUri(source.fullName);
|
|
|
|
/**
|
|
* Return `true` if the given [uri] is a `file` URI.
|
|
*/
|
|
static bool isFileUri(Uri uri) => uri.scheme == FILE_SCHEME;
|
|
}
|