| Index: mojo/public/dart/third_party/package_config/lib/discovery_analysis.dart
|
| diff --git a/mojo/public/dart/third_party/package_config/lib/discovery_analysis.dart b/mojo/public/dart/third_party/package_config/lib/discovery_analysis.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..af4df070a4ac7b471caf26b8023fb527afeedf02
|
| --- /dev/null
|
| +++ b/mojo/public/dart/third_party/package_config/lib/discovery_analysis.dart
|
| @@ -0,0 +1,166 @@
|
| +// Copyright (c) 2015, 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.
|
| +
|
| +/// Analyse a directory structure and find packages resolvers for each
|
| +/// sub-directory.
|
| +///
|
| +/// The resolvers are generally the same that would be found by using
|
| +/// the `discovery.dart` library on each sub-directory in turn,
|
| +/// but more efficiently and with some heuristics for directories that
|
| +/// wouldn't otherwise have a package resolution strategy, or that are
|
| +/// determined to be "package directories" themselves.
|
| +library package_config.discovery_analysis;
|
| +
|
| +import "dart:io" show File, Directory;
|
| +import "dart:collection" show HashMap;
|
| +
|
| +import "package:path/path.dart" as path;
|
| +
|
| +import "packages.dart";
|
| +import "packages_file.dart" as pkgfile;
|
| +import "src/packages_impl.dart";
|
| +import "src/packages_io_impl.dart";
|
| +
|
| +/// Associates a [Packages] package resolution strategy with a directory.
|
| +///
|
| +/// The package resolution applies to the directory and any sub-directory
|
| +/// that doesn't have its own overriding child [PackageContext].
|
| +abstract class PackageContext {
|
| + /// The directory that introduced the [packages] resolver.
|
| + Directory get directory;
|
| +
|
| + /// A [Packages] resolver that applies to the directory.
|
| + ///
|
| + /// Introduced either by a `.packages` file or a `packages/` directory.
|
| + Packages get packages;
|
| +
|
| + /// Child contexts that apply to sub-directories of [directory].
|
| + List<PackageContext> get children;
|
| +
|
| + /// Look up the [PackageContext] that applies to a specific directory.
|
| + ///
|
| + /// The directory must be inside [directory].
|
| + PackageContext operator[](Directory directory);
|
| +
|
| + /// A map from directory to package resolver.
|
| + ///
|
| + /// Has an entry for this package context and for each child context
|
| + /// contained in this one.
|
| + Map<Directory, Packages> asMap();
|
| +
|
| + /// Analyze [directory] and sub-directories for package resolution strategies.
|
| + ///
|
| + /// Returns a mapping from sub-directories to [Packages] objects.
|
| + ///
|
| + /// The analysis assumes that there are no `.packages` files in a parent
|
| + /// directory of `directory`. If there is, its corresponding `Packages` object
|
| + /// should be provided as `root`.
|
| + static PackageContext findAll(Directory directory,
|
| + {Packages root: Packages.noPackages}) {
|
| + if (!directory.existsSync()) {
|
| + throw new ArgumentError("Directory not found: $directory");
|
| + }
|
| + List contexts = [];
|
| + void findRoots(Directory directory) {
|
| + Packages packages;
|
| + List oldContexts;
|
| + File packagesFile = new File(path.join(directory.path, ".packages"));
|
| + if (packagesFile.existsSync()) {
|
| + packages = _loadPackagesFile(packagesFile);
|
| + oldContexts = contexts;
|
| + contexts = [];
|
| + } else {
|
| + Directory packagesDir =
|
| + new Directory(path.join(directory.path, "packages"));
|
| + if (packagesDir.existsSync()) {
|
| + packages = new FilePackagesDirectoryPackages(packagesDir);
|
| + oldContexts = contexts;
|
| + contexts = [];
|
| + }
|
| + }
|
| + for (var entry in directory.listSync()) {
|
| + if (entry is Directory) {
|
| + if (packages == null || !entry.path.endsWith("/packages")) {
|
| + findRoots(entry);
|
| + }
|
| + }
|
| + }
|
| + if (packages != null) {
|
| + oldContexts.add(new _PackageContext(directory, packages, contexts));
|
| + contexts = oldContexts;
|
| + }
|
| + }
|
| + findRoots(directory);
|
| + // If the root is not itself context root, add a the wrapper context.
|
| + if (contexts.length == 1 &&
|
| + contexts[0].directory == directory) {
|
| + return contexts[0];
|
| + }
|
| + return new _PackageContext(directory, root, contexts);
|
| + }
|
| +}
|
| +
|
| +class _PackageContext implements PackageContext {
|
| + final Directory directory;
|
| + final Packages packages;
|
| + final List<PackageContext> children;
|
| + _PackageContext(this.directory, this.packages, List<PackageContext> children)
|
| + : children = new List<PackageContext>.unmodifiable(children);
|
| +
|
| + Map<Directory, Packages> asMap() {
|
| + var result = new HashMap<Directory, Packages>();
|
| + recurse(_PackageContext current) {
|
| + result[current.directory] = current.packages;
|
| + for (var child in current.children) {
|
| + recurse(child);
|
| + }
|
| + }
|
| + recurse(this);
|
| + return result;
|
| + }
|
| +
|
| + PackageContext operator[](Directory directory) {
|
| + String path = directory.path;
|
| + if (!path.startsWith(this.directory.path)) {
|
| + throw new ArgumentError("Not inside $path: $directory");
|
| + }
|
| + _PackageContext current = this;
|
| + // The current path is know to agree with directory until deltaIndex.
|
| + int deltaIndex = current.directory.path.length;
|
| + List children = current.children;
|
| + int i = 0;
|
| + while (i < children.length) {
|
| + // TODO(lrn): Sort children and use binary search.
|
| + _PackageContext child = children[i];
|
| + String childPath = child.directory.path;
|
| + if (_stringsAgree(path, childPath, deltaIndex, childPath.length)) {
|
| + deltaIndex = childPath.length;
|
| + if (deltaIndex == path.length) {
|
| + return child;
|
| + }
|
| + current = child;
|
| + children = current.children;
|
| + i = 0;
|
| + continue;
|
| + }
|
| + i++;
|
| + }
|
| + return current;
|
| + }
|
| +
|
| + static bool _stringsAgree(String a, String b, int start, int end) {
|
| + if (a.length < end || b.length < end) return false;
|
| + for (int i = start; i < end; i++) {
|
| + if (a.codeUnitAt(i) != b.codeUnitAt(i)) return false;
|
| + }
|
| + return true;
|
| + }
|
| +}
|
| +
|
| +Packages _loadPackagesFile(File file) {
|
| + var uri = new Uri.file(file.path);
|
| + var bytes = file.readAsBytesSync();
|
| + var map = pkgfile.parse(bytes, uri);
|
| + return new MapPackages(map);
|
| +}
|
|
|