blob: 30cbc6652f110043e1b5e0fc9e8abf723f08c510 [file] [log] [blame]
// Copyright (c) 2018, 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 'package:front_end/src/api_unstable/build_integration.dart';
/// A [FileSystem] that resolves custom URIs to entities under a specified root
/// folder on an underlying [FileSystem].
///
/// This abstraction lets packages like `package:front_end` use absolute URIs
/// freely, while hiding machine-specific or user-specific details. In
/// particular, this file-system is used to create a machine-independent .dill
/// files in distributed build systems.
///
/// The resolution rules are as follows: if a given URI uses a special
/// [markerScheme] it gets resolved under the given [root], while a given URI
/// with any other scheme will produce an error.
///
/// For example, if [markerScheme] is `single-root`, and [root] is
/// `file:///a/b/c/`, then, calling [entityForUri] will:
///
/// * resolve `single-root:///f1.dart` to `file:///a/b/c/f1.dart`.
/// * resolve `single-root:///d/f2.dart` to `file:///a/b/c/d/f2.dart`.
/// * throw on `other-custom-scheme:///d/f2.dart`.
/// * throw on `file:///d/f2.dart`.
class SingleRootFileSystem implements FileSystem {
final String markerScheme;
final Uri root;
final FileSystem original;
SingleRootFileSystem(this.markerScheme, Uri root, this.original)
: root = _normalize(root);
@override
FileSystemEntity entityForUri(Uri uri) {
if (uri.scheme != markerScheme) {
throw new FileSystemException(
uri,
"This SingleRootFileSystem only handles URIs with the '$markerScheme'"
" scheme and cannot handle URIs with scheme '${uri.scheme}': $uri");
}
if (!uri.path.startsWith('/')) {
throw new FileSystemException(
uri, "This SingleRootFileSystem only handles absolutes URIs: $uri");
}
var path = uri.path.substring(1);
return new SingleRootFileSystemEntity(
uri, original.entityForUri(root.resolve(path)));
}
}
/// [FileSystemEntity] with a URI of the `SingleRootFileSystem.markerScheme`,
/// that delegates all operations to an underlying entity in the original
/// `SingleRootFileSystem.filesystem`.
class SingleRootFileSystemEntity implements FileSystemEntity {
final Uri uri;
final FileSystemEntity delegate;
SingleRootFileSystemEntity(this.uri, this.delegate);
@override
Future<bool> exists() async => delegate.exists();
@override
Future<bool> existsAsyncIfPossible() async =>
delegate.existsAsyncIfPossible();
@override
Future<List<int>> readAsBytes() async => delegate.readAsBytes();
@override
Future<List<int>> readAsBytesAsyncIfPossible() async =>
delegate.readAsBytesAsyncIfPossible();
@override
Future<String> readAsString() async => delegate.readAsString();
}
_normalize(root) {
Uri uri = root;
return uri.path.endsWith('/') ? uri : uri.replace(path: '${uri.path}/');
}