// 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. import 'dart:async'; import 'package:analyzer/src/generated/source.dart'; import 'package:path/path.dart'; import 'package:watcher/watcher.dart'; export 'package:analyzer/src/file_system/file_system.dart'; /** * [File]s are leaf [Resource]s which contain data. */ abstract class File implements Resource { /** * Watch for changes to this file */ Stream get changes; /** * Synchronously get the length of the file. * Throws a [FileSystemException] if the operation fails. */ int get lengthSync; /** * Return the last-modified stamp of the file. * Throws a [FileSystemException] if the file does not exist. */ int get modificationStamp; @override File copyTo(Folder parentFolder); /** * 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 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. * * The [newPath] must be absolute and normalized. * * 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 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 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 the [path] references a resource in this folder. * * The [path] must be absolute and normalized. */ bool contains(String path); @override Folder copyTo(Folder parentFolder); /** * If this folder does not already exist, create it. */ void create(); /** * 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. * * On I/O errors, this will throw [FileSystemException]. */ List 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; /** * Copy this resource to a child of the [parentFolder] with the same kind and * [shortName] as this resource. If this resource is a folder, then all of the * contents of the folder will be recursively copied. * * The parent folder is created if it does not already exist. * * Existing files and folders will be overwritten. * * Return the resource corresponding to this resource in the parent folder. */ Resource copyTo(Folder parentFolder); /** * 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. * * The [path] must be absolute and normalized. */ 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 path context used by this resource provider. */ Context get pathContext; /** * Return a [File] that corresponds to the given [path]. * * The [path] must be absolute and normalized. * * A file may or may not exist at this location. */ File getFile(String path); /** * Return a [Folder] that corresponds to the given [path]. * * The [path] must be absolute and normalized. * * 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> getModificationTimes(List sources); /** * Return the [Resource] that corresponds to the given [path]. * * The [path] must be absolute and normalized. */ 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); }