| Index: utils/pub/package.dart
|
| diff --git a/utils/pub/package.dart b/utils/pub/package.dart
|
| index 2942a92c67c1c4ec2af1a8a65d3b9b276d722f72..7a6a71b39797d709b757ac2a54da003fc6d1d360 100644
|
| --- a/utils/pub/package.dart
|
| +++ b/utils/pub/package.dart
|
| @@ -5,7 +5,23 @@
|
| /**
|
| * A named, versioned, unit of code and resource reuse.
|
| */
|
| -class Package {
|
| +class Package implements Hashable {
|
| + /**
|
| + * Loads the package whose root directory is [packageDir].
|
| + */
|
| + static Future<Package> load(String packageDir) {
|
| + final pubspecPath = join(packageDir, 'pubspec');
|
| +
|
| + return _parsePubspec(pubspecPath).transform((dependencies) {
|
| + return new Package._(packageDir, dependencies);
|
| + });
|
| + }
|
| +
|
| + /**
|
| + * The path to the directory containing the package.
|
| + */
|
| + final String dir;
|
| +
|
| /**
|
| * The name of the package.
|
| */
|
| @@ -20,20 +36,93 @@ class Package {
|
| final Collection<String> dependencies;
|
|
|
| /**
|
| - * The cache where this package is contained.
|
| + * Constructs a package. This should not be called directly. Instead, acquire
|
| + * packages from [load()].
|
| */
|
| - final PackageCache _cache;
|
| + Package._(String dir, this.dependencies)
|
| + : dir = dir,
|
| + name = basename(dir);
|
|
|
| /**
|
| - * Constructs a package. This should not be called directly. Instead, acquire
|
| - * packages from [PackageCache].
|
| + * Reads and returns all of the packages this package immediately depends on.
|
| + */
|
| + Future<Collection<Package>> loadDependencies(PackageCache cache) {
|
| + return Futures.wait(dependencies.map((name) => cache.find(name)));
|
| + }
|
| +
|
| + /**
|
| + * Walks the entire dependency graph starting at this package and returns a
|
| + * [Set] of all of the packages dependend on by this one, directly or
|
| + * indirectly. This package is included in the result set.
|
| + */
|
| + Future<Set<Package>> traverseDependencies(PackageCache cache) {
|
| + final completer = new Completer<Set<Package>>();
|
| + final packages = new Set<Package>();
|
| +
|
| + var pendingAsyncCalls = 0;
|
| +
|
| + walkPackage(Package package) {
|
| + // Skip packages we've already traversed.
|
| + if (packages.contains(package)) return;
|
| +
|
| + // Add the package.
|
| + packages.add(package);
|
| +
|
| + // Recurse into its dependencies.
|
| + pendingAsyncCalls++;
|
| + package.loadDependencies(cache).then((dependencies) {
|
| + for (final dependency in dependencies) {
|
| + walkPackage(dependency);
|
| + }
|
| +
|
| + pendingAsyncCalls--;
|
| + if (pendingAsyncCalls == 0) completer.complete(packages);
|
| + });
|
| + }
|
| +
|
| + walkPackage(this);
|
| +
|
| + return completer.future;
|
| + }
|
| +
|
| + /**
|
| + * Generates a hashcode for the package.
|
| + */
|
| + int hashCode() => name.hashCode();
|
| +
|
| + /**
|
| + * Returns a debug string for the package.
|
| */
|
| - Package._(this._cache, this.name, this.dependencies);
|
| + String toString() => '$name ($dir)';
|
|
|
| /**
|
| - * Reads and returns all of the packages this package depends on.
|
| + * Parses the pubspec at the given path and returns the list of package
|
| + * dependencies it exposes.
|
| */
|
| - Future<Collection<Package>> readDependencies() {
|
| - return Futures.wait(dependencies.map((name) => _cache.find(name)));
|
| + static Future<List<String>> _parsePubspec(String path) {
|
| + final completer = new Completer<List<String>>();
|
| +
|
| + // TODO(rnystrom): Handle the directory not existing.
|
| + // TODO(rnystrom): Error-handling.
|
| + final readFuture = readTextFile(path);
|
| + readFuture.handleException((error) {
|
| + // If there is no pubspec, we implicitly treat that as a package with no
|
| + // dependencies.
|
| + // TODO(rnystrom): Distinguish file not found from other real errors.
|
| + completer.complete(<String>[]);
|
| + return true;
|
| + });
|
| +
|
| + readFuture.then((pubspec) {
|
| + // TODO(rnystrom): Use YAML parser when ready. For now, it's just a flat
|
| + // list of newline-separated strings.
|
| + final dependencyNames = pubspec.split('\n').
|
| + map((name) => name.trim()).
|
| + filter((name) => (name != null) && (name != ''));
|
| +
|
| + completer.complete(dependencyNames);
|
| + });
|
| +
|
| + return completer.future;
|
| }
|
| }
|
|
|