| Index: pkg/front_end/lib/src/base/processed_options.dart
|
| diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
|
| index 189cc2aefbc6013a9bbfb49fcebe9ee7c4d81eba..e2cf32a4974c2941b2a07232370cbc4f45a67546 100644
|
| --- a/pkg/front_end/lib/src/base/processed_options.dart
|
| +++ b/pkg/front_end/lib/src/base/processed_options.dart
|
| @@ -19,6 +19,9 @@ import 'package:kernel/kernel.dart'
|
| show Program, loadProgramFromBytes, CanonicalName;
|
| import 'package:kernel/target/targets.dart';
|
| import 'package:kernel/target/vm_fasta.dart';
|
| +import 'package:package_config/packages.dart' show Packages;
|
| +import 'package:package_config/src/packages_impl.dart'
|
| + show NonFilePackagesDirectoryPackages, MapPackages;
|
| import 'package:package_config/packages_file.dart' as package_config;
|
| import 'package:source_span/source_span.dart' show SourceSpan, SourceLocation;
|
|
|
| @@ -41,7 +44,7 @@ class ProcessedOptions {
|
|
|
| /// The package map derived from the options, or `null` if the package map has
|
| /// not been computed yet.
|
| - Map<String, Uri> _packages;
|
| + Packages _packages;
|
|
|
| /// The object that knows how to resolve "package:" and "dart:" URIs,
|
| /// or `null` if it has not been computed yet.
|
| @@ -123,11 +126,22 @@ class ProcessedOptions {
|
| /// Runs various validations checks on the input options. For instance,
|
| /// if an option is a path to a file, it checks that the file exists.
|
| Future<bool> validateOptions() async {
|
| + if (inputs.isEmpty) {
|
| + reportMessageWithoutLocation(messageMissingInput);
|
| + return false;
|
| + }
|
| +
|
| for (var source in inputs) {
|
| - if (source.scheme == 'file' &&
|
| + // Note: we don't translate Uris at this point because some of the
|
| + // validation further below must be done before we even construct an
|
| + // UriTranslator
|
| + // TODO(sigmund): consider validating dart/packages uri right after we
|
| + // build the uri translator.
|
| + if (source.scheme != 'dart' &&
|
| + source.scheme != 'packages' &&
|
| !await fileSystem.entityForUri(source).exists()) {
|
| reportMessageWithoutLocation(
|
| - templateMissingInputFile.withArguments('$source'));
|
| + templateInputFileNotFound.withArguments('$source'));
|
| return false;
|
| }
|
| }
|
| @@ -135,14 +149,14 @@ class ProcessedOptions {
|
| if (_raw.sdkRoot != null &&
|
| !await fileSystem.entityForUri(sdkRoot).exists()) {
|
| reportMessageWithoutLocation(
|
| - templateMissingSdkRoot.withArguments('$sdkRoot'));
|
| + templateSdkRootNotFound.withArguments('$sdkRoot'));
|
| return false;
|
| }
|
|
|
| var summary = sdkSummary;
|
| if (summary != null && !await fileSystem.entityForUri(summary).exists()) {
|
| reportMessageWithoutLocation(
|
| - templateMissingSdkSummary.withArguments('$summary'));
|
| + templateSdkSummaryNotFound.withArguments('$summary'));
|
| return false;
|
| }
|
|
|
| @@ -248,22 +262,96 @@ class ProcessedOptions {
|
| ///
|
| /// This is an asynchronous getter since file system operations may be
|
| /// required to locate/read the packages file.
|
| - Future<Map<String, Uri>> _getPackages() async {
|
| + Future<Packages> _getPackages() async {
|
| if (_packages == null) {
|
| if (_raw.packagesFileUri == null) {
|
| - // TODO(sigmund,paulberry): implement
|
| - return unimplemented('search for .packages');
|
| - } else if (_raw.packagesFileUri.path.isEmpty) {
|
| - _packages = {};
|
| + if (inputs.length > 1) {
|
| + // TODO(sigmund): consider not reporting an error if we would infer
|
| + // the same .packages file from all of the inputs.
|
| + reportMessageWithoutLocation(messageCantInferPackagesFromManyInputs);
|
| + _packages = Packages.noPackages;
|
| + } else {
|
| + _packages = await _findPackages(inputs.first);
|
| + }
|
| } else {
|
| - var contents =
|
| - await fileSystem.entityForUri(_raw.packagesFileUri).readAsBytes();
|
| - _packages = package_config.parse(contents, _raw.packagesFileUri);
|
| + _packages = await createPackagesFromFile(_raw.packagesFileUri);
|
| }
|
| }
|
| return _packages;
|
| }
|
|
|
| + /// Create a [Packages] given the Uri to a `.packages` file.
|
| + Future<Packages> createPackagesFromFile(Uri file) async {
|
| + try {
|
| + List<int> contents = await fileSystem.entityForUri(file).readAsBytes();
|
| + Map<String, Uri> map = package_config.parse(contents, file);
|
| + return new MapPackages(map);
|
| + } catch (e) {
|
| + reportMessage(templateCannotReadPackagesFile
|
| + .withArguments("$e")
|
| + .withLocation(file, -1));
|
| + return Packages.noPackages;
|
| + }
|
| + }
|
| +
|
| + /// Finds a package resolution strategy using a [FileSystem].
|
| + ///
|
| + /// The [scriptUri] points to a Dart script with a valid scheme accepted by
|
| + /// the [FileSystem].
|
| + ///
|
| + /// This function first tries to locate a `.packages` file in the `scriptUri`
|
| + /// directory. If that is not found, it instead checks for the presence of a
|
| + /// `packages/` directory in the same place. If that also fails, it starts
|
| + /// checking parent directories for a `.packages` file, and stops if it finds
|
| + /// it. Otherwise it gives up and returns [Packages.noPackages].
|
| + ///
|
| + /// Note: this is a fork from `package:package_config/discovery.dart` to adapt
|
| + /// it to use [FileSystem]. The logic here is a mix of the logic in the
|
| + /// `findPackagesFromFile` and `findPackagesFromNonFile`:
|
| + ///
|
| + /// * Like `findPackagesFromFile` resolution searches for parent
|
| + /// directories
|
| + ///
|
| + /// * Like `findPackagesFromNonFile` if we resolve packages as the
|
| + /// `packages/` directory, we can't provide a list of packages that are
|
| + /// visible.
|
| + Future<Packages> _findPackages(Uri scriptUri) async {
|
| + var dir = scriptUri.resolve('.');
|
| + if (!dir.isAbsolute) {
|
| + reportMessageWithoutLocation(templateInternalProblemUnsupported
|
| + .withArguments("Expected input Uri to be absolute: $scriptUri."));
|
| + return Packages.noPackages;
|
| + }
|
| +
|
| + Future<Uri> checkInDir(Uri dir) async {
|
| + Uri candidate = dir.resolve('.packages');
|
| + if (await fileSystem.entityForUri(candidate).exists()) return candidate;
|
| + return null;
|
| + }
|
| +
|
| + // Check for $cwd/.packages
|
| + var candidate = await checkInDir(dir);
|
| + if (candidate != null) return createPackagesFromFile(candidate);
|
| +
|
| + // Check for $cwd/packages/
|
| + var packagesDir = dir.resolve("packages/");
|
| + if (await fileSystem.entityForUri(packagesDir).exists()) {
|
| + return new NonFilePackagesDirectoryPackages(packagesDir);
|
| + }
|
| +
|
| + // Check for cwd(/..)+/.packages
|
| + var parentDir = dir.resolve('..');
|
| + while (parentDir.path != dir.path) {
|
| + candidate = await checkInDir(parentDir);
|
| + if (candidate != null) break;
|
| + dir = parentDir;
|
| + parentDir = dir.resolve('..');
|
| + }
|
| +
|
| + if (candidate != null) return createPackagesFromFile(candidate);
|
| + return Packages.noPackages;
|
| + }
|
| +
|
| /// Get the location of the SDK.
|
| Uri _normalizeSdkRoot() {
|
| // If an SDK summary location was provided, the SDK itself should not be
|
|
|