Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * A named, versioned, unit of code and resource reuse. | 6 * A named, versioned, unit of code and resource reuse. |
| 7 */ | 7 */ |
| 8 class Package { | 8 class Package implements Hashable { |
| 9 /** | |
| 10 * Loads the package whose root directory is [packageDir]. | |
| 11 */ | |
| 12 static Future<Package> load(String packageDir) { | |
| 13 final pubspecPath = join(packageDir, 'pubspec'); | |
| 14 | |
| 15 return _parsePubspec(pubspecPath).transform((dependencies) { | |
| 16 return new Package._(packageDir, dependencies); | |
| 17 }); | |
| 18 } | |
| 19 | |
| 20 /** | |
| 21 * The path to the directory containing the package. | |
| 22 */ | |
| 23 final String dir; | |
| 24 | |
| 9 /** | 25 /** |
| 10 * The name of the package. | 26 * The name of the package. |
| 11 */ | 27 */ |
| 12 final String name; | 28 final String name; |
| 13 | 29 |
| 14 /** | 30 /** |
| 15 * The names of the packages that this package depends on. This is what is | 31 * The names of the packages that this package depends on. This is what is |
| 16 * specified in the pubspec when this package depends on another. | 32 * specified in the pubspec when this package depends on another. |
| 17 */ | 33 */ |
| 18 // TODO(rnystrom): When packages are versioned and sourced, this will likely | 34 // TODO(rnystrom): When packages are versioned and sourced, this will likely |
| 19 // be something more than just a string. | 35 // be something more than just a string. |
| 20 final Collection<String> dependencies; | 36 final Collection<String> dependencies; |
| 21 | 37 |
| 22 /** | 38 /** |
| 23 * The cache where this package is contained. | 39 * Constructs a package. This should not be called directly. Instead, acquire |
| 40 * packages from [load()]. | |
| 24 */ | 41 */ |
| 25 final PackageCache _cache; | 42 Package._(String dir, this.dependencies) |
| 43 : dir = dir, | |
| 44 name = basename(dir); | |
| 26 | 45 |
| 27 /** | 46 /** |
| 28 * Constructs a package. This should not be called directly. Instead, acquire | 47 * Reads and returns all of the packages this package immediately depends on. |
| 29 * packages from [PackageCache]. | |
| 30 */ | 48 */ |
| 31 Package._(this._cache, this.name, this.dependencies); | 49 Future<Collection<Package>> loadDependencies() { |
|
nweiz
2012/04/25 17:50:47
I don't think the distinction between loadDependen
Bob Nystrom
2012/04/25 22:20:29
"local" doesn't have the right connotation to me.
nweiz
2012/04/25 22:30:09
I like "loadImmediateDependencies". It is verbose,
| |
| 50 return Futures.wait(dependencies.map((name) => cache.find(name))); | |
| 51 } | |
| 32 | 52 |
| 33 /** | 53 /** |
| 34 * Reads and returns all of the packages this package depends on. | 54 * Walks the entire dependency graph starting at this package and returns a |
| 55 * [Set] of all of the packages dependend on by this one, directly or | |
| 56 * indirectly. This package is included in the result set. | |
| 35 */ | 57 */ |
| 36 Future<Collection<Package>> readDependencies() { | 58 Future<Set<Package>> traverseDependencies() { |
| 37 return Futures.wait(dependencies.map((name) => _cache.find(name))); | 59 final completer = new Completer<Set<Package>>(); |
| 60 final packages = new Set<Package>(); | |
| 61 | |
| 62 var pendingAsyncCalls = 0; | |
| 63 | |
| 64 walkPackage(Package package) { | |
| 65 // Skip packages we've already traversed. | |
| 66 if (packages.contains(package)) return; | |
| 67 | |
| 68 // Add the package. | |
| 69 packages.add(package); | |
| 70 | |
| 71 // Recurse into its dependencies. | |
| 72 pendingAsyncCalls++; | |
| 73 package.loadDependencies().then((dependencies) { | |
| 74 for (final dependency in dependencies) { | |
|
nweiz
2012/04/25 17:50:47
I would write dependencies.forEach(walkPackage), b
Bob Nystrom
2012/04/25 22:20:29
Done.
| |
| 75 walkPackage(dependency); | |
| 76 } | |
| 77 | |
| 78 pendingAsyncCalls--; | |
| 79 if (pendingAsyncCalls == 0) completer.complete(packages); | |
| 80 }); | |
| 81 } | |
| 82 | |
| 83 walkPackage(this); | |
| 84 | |
| 85 return completer.future; | |
| 86 } | |
| 87 | |
| 88 /** | |
| 89 * Generates a hashcode for the package. | |
| 90 */ | |
| 91 int hashCode() => name.hashCode(); | |
|
nweiz
2012/04/25 17:50:47
If you define hashCode, you should also define ==.
Bob Nystrom
2012/04/25 22:20:29
Leaving a TODO for now. I definitely want somethin
| |
| 92 | |
| 93 /** | |
| 94 * Returns a debug string for the package. | |
| 95 */ | |
| 96 String toString() => '$name ($dir)'; | |
| 97 | |
| 98 /** | |
| 99 * Parses the pubspec at the given path and returns the list of package | |
| 100 * dependencies it exposes. | |
| 101 */ | |
| 102 static Future<List<String>> _parsePubspec(String path) { | |
| 103 final completer = new Completer<List<String>>(); | |
| 104 | |
| 105 // TODO(rnystrom): Handle the directory not existing. | |
| 106 // TODO(rnystrom): Error-handling. | |
| 107 final readFuture = readTextFile(path); | |
| 108 readFuture.handleException((error) { | |
| 109 // If there is no pubspec, we implicitly treat that as a package with no | |
| 110 // dependencies. | |
| 111 // TODO(rnystrom): Distinguish file not found from other real errors. | |
| 112 completer.complete(<String>[]); | |
| 113 return true; | |
| 114 }); | |
| 115 | |
| 116 readFuture.then((pubspec) { | |
| 117 // TODO(rnystrom): Use YAML parser when ready. For now, it's just a flat | |
| 118 // list of newline-separated strings. | |
| 119 final dependencyNames = pubspec.split('\n'). | |
| 120 map((name) => name.trim()). | |
| 121 filter((name) => (name != null) && (name != '')); | |
| 122 | |
| 123 completer.complete(dependencyNames); | |
| 124 }); | |
| 125 | |
| 126 return completer.future; | |
| 38 } | 127 } |
| 39 } | 128 } |
| OLD | NEW |