Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: utils/pub/package.dart

Issue 10399076: Get codebase ready for actually supporting versioning. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Tiny tweak. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 implements Hashable { 8 class Package {
9 /** 9 /**
10 * Loads the package whose root directory is [packageDir]. 10 * Loads the package whose root directory is [packageDir].
11 */ 11 */
12 static Future<Package> load(String packageDir, SourceRegistry sources) { 12 static Future<Package> load(String packageDir, SystemCache cache) {
13 final pubspecPath = join(packageDir, 'pubspec'); 13 var pubspecPath = join(packageDir, 'pubspec');
14 14
15 return _parsePubspec(pubspecPath, sources).transform((dependencies) { 15 return Pubspec.parse(pubspecPath, cache.sources).transform((pubspec) {
16 return new Package._(packageDir, dependencies); 16 return new Package._(packageDir, cache, pubspec);
17 }); 17 });
18 } 18 }
19 19
20 /** 20 /**
21 * The path to the directory containing the package. 21 * The path to the directory containing the package.
22 */ 22 */
23 final String dir; 23 final String dir;
24 24
25 /** 25 /**
26 * The name of the package. 26 * The name of the package.
27 */ 27 */
28 final String name; 28 final String name;
29 29
30 /** 30 /**
31 * The package's version.
32 */
33 Version get version() => pubspec.version;
34
35 /**
36 * The parsed pubspec associated with this package.
37 */
38 final Pubspec pubspec;
39
40 /**
41 * The "packages" directory that this package installs its dependencies into.
42 */
43 final PackagesDir packagesDir;
44
45 /**
31 * The ids of the packages that this package depends on. This is what is 46 * The ids of the packages that this package depends on. This is what is
32 * specified in the pubspec when this package depends on another. 47 * specified in the pubspec when this package depends on another.
33 */ 48 */
34 final Collection<PackageId> dependencies; 49 Collection<PackageRef> get dependencies() => pubspec.dependencies;
35 50
36 /** 51 /**
37 * Constructs a package. This should not be called directly. Instead, acquire 52 * Constructs a package. This should not be called directly. Instead, acquire
38 * packages from [load()]. 53 * packages from [load()].
39 */ 54 */
40 Package._(String dir, this.dependencies) 55 Package._(String dir, SystemCache cache, this.pubspec)
nweiz 2012/05/18 00:08:24 I'm not sure I like Package having a reference to
Bob Nystrom 2012/05/18 20:02:38 Done.
41 : dir = dir, 56 : dir = dir,
42 name = basename(dir); 57 name = basename(dir),
58 packagesDir = new PackagesDir(join(dir, 'packages'), cache);
43 59
44 /** 60 /**
45 * Generates a hashcode for the package. 61 * Installs all dependencies of this package to its "packages" directory.
62 * Returns a [Future] that completes when all dependencies are installed.
46 */ 63 */
47 // TODO(rnystrom): Do something more sophisticated here once we care about 64 Future installDependencies() {
48 // versioning and different package sources. 65 return packagesDir.installTransitively(this, this.dependencies);
49 int hashCode() => name.hashCode(); 66 }
67
68 /**
69 * Given [ref], which ambiguously identifies a dependent package, selects an
70 * appropriate precise package to use when this package is the entrypoint.
71 * In other words, given a loose refence like "foo >= 2.0", figures out what
72 * concrete package *this* app wants to use.
73 */
74 Future<PackageId> resolve(PackageRef ref) {
75 // TODO(rnystrom): This should use the lockfile to select the right version
76 // once that's implemented. If the lockfile doesn't exist, it should
77 // generate it. In the meantime, here's a dumb implementation:
78 return new Future.immediate(
79 new PackageId(ref.source, Version.none, ref.description));
80 }
50 81
51 /** 82 /**
52 * Returns a debug string for the package. 83 * Returns a debug string for the package.
53 */ 84 */
54 String toString() => '$name ($dir)'; 85 String toString() => '$name ($dir)';
86 }
87
88 /**
89 * An unambiguous resolved reference to a package. A package ID contains enough
90 * information to correctly install the package.
91 *
92 * Note that it's possible for multiple distinct package IDs to point to
93 * different directories that happen to contain identical packages. For example,
94 * the same package may be available from multiple sources. As far as Pub is
95 * concerned, those packages are different.
96 */
97 class PackageId implements Comparable, Hashable {
98 /**
99 * The [Source] used to look up this package given its [description].
100 */
101 final Source source;
55 102
56 /** 103 /**
57 * Parses the pubspec at the given path and returns the list of package 104 * The package's version.
58 * dependencies it exposes.
59 */ 105 */
60 static Future<List<PackageId>> _parsePubspec(String path, 106 final Version version;
61 SourceRegistry sources) {
62 final completer = new Completer<List<PackageId>>();
63 107
64 // TODO(rnystrom): Handle the directory not existing. 108 /**
65 // TODO(rnystrom): Error-handling. 109 * The metadata used by the package's [source] to identify and locate it. It
66 final readFuture = readTextFile(path); 110 * contains whatever [Source]-specific data it needs to be able to install
67 readFuture.handleException((error) { 111 * the package. For example, the description of a git sourced package might
68 // If there is no pubspec, we implicitly treat that as a package with no 112 * by the URL "git://github.com/dart/uilib.git".
69 // dependencies. 113 */
70 // TODO(rnystrom): Distinguish file not found from other real errors. 114 final description;
71 completer.complete(<PackageId>[]);
72 return true;
73 });
74 115
75 readFuture.then((pubspec) { 116 PackageId(this.source, this.version, this.description);
76 if (pubspec.trim() == '') {
77 completer.complete(<String>[]);
78 return;
79 }
80 117
81 var parsedPubspec = loadYaml(pubspec); 118 /**
82 if (parsedPubspec is! Map) { 119 * The name of the package being identified. This will be the human-friendly
83 completer.completeException('The pubspec must be a YAML mapping.'); 120 * name like "uilib".
84 } 121 */
122 String get name() => source.packageName(this);
85 123
86 if (!parsedPubspec.containsKey('dependencies')) { 124 int hashCode() => name.hashCode() ^
87 completer.complete(<String>[]); 125 source.name.hashCode() ^
88 return; 126 version.hashCode();
89 }
90 127
91 var dependencies = parsedPubspec['dependencies']; 128 bool operator ==(other) {
92 if (dependencies is! Map || 129 if (other is! PackageId) return false;
93 dependencies.getKeys().some((e) => e is! String)) { 130 // TODO(rnystrom): We're assuming here the name/version/source tuple is
94 completer.completeException( 131 // enough to uniquely identify the package and that we don't need to delve
95 'The pubspec dependencies must be a map of package names.'); 132 // into the description.
96 } 133 return other.name == name &&
134 other.source.name == source.name &&
135 other.version == version;
136 }
97 137
98 var dependencyIds = <PackageId>[]; 138 String toString() => "$name $version from ${source.name}";
99 dependencies.forEach((name, spec) {
100 var fullName, source;
101 // TODO(nweiz): parse the version once we have version handling
102 if (spec == null || spec is String) {
103 fullName = name;
104 source = sources.defaultSource;
105 } else if (spec is Map) {
106 spec.remove('version');
107 139
108 var sourceNames = spec.getKeys(); 140 int compareTo(Comparable other) {
109 if (sourceNames.length > 1) { 141 if (other is! PackageId) throw new IllegalArgumentException(other);
110 completer.completeException(
111 'Dependency $name may not have multiple sources: '
112 '$sourceNames.');
113 return;
114 }
115 142
116 var sourceName = only(sourceNames); 143 var sourceComp = source.name.compareTo(other.source.name);
117 if (sourceName is! String) { 144 if (sourceComp != 0) return sourceComp;
118 completer.completeException(
119 'Source name $sourceName must be a string.');
120 return;
121 }
122 source = sources[sourceName];
123 145
124 // TODO(nweiz): At some point we want fullName to be able to be an 146 var nameComp = name.compareTo(other.name);
125 // arbitrary object that's parsed by the source. 147 if (nameComp != 0) return nameComp;
126 fullName = spec[sourceName];
127 if (fullName is! String) {
128 completer.completeException(
129 'Source identifier $fullName must be a string.');
130 return;
131 }
132 } else {
133 completer.completeException(
134 'Dependency specification $spec must be a string or a mapping.');
135 return;
136 }
137 148
138 var id = new PackageId(fullName, source); 149 return version.compareTo(other.version);
139 var nameFromSource = source.packageName(id);
140 if (nameFromSource != name) {
141 completer.completeException(
142 'Dependency name "$name" doesn\'t match name "$nameFromSource" '
143 'from source "${source.name}".');
144 return;
145 }
146
147 dependencyIds.add(id);
148 });
149 completer.complete(dependencyIds);
150 });
151
152 return completer.future;
153 } 150 }
154 } 151 }
155 152
156 /** 153 /**
157 * A unique identifier for a package. A given package id specifies a single 154 * A reference to a package. Unlike a [PackageId], a PackageRef may not
158 * chunk of code and resources. 155 * unambiguously refer to a single package. It may describe a range of allowed
159 * 156 * packages.
160 * Note that it's possible for multiple package ids to point to identical
161 * packages. For example, the same package may be available from multiple
162 * sources. As far as Pub is concerned, those packages are different.
163 */ 157 */
164 // TODO(nweiz, rnystrom): this should include version eventually 158 class PackageRef {
nweiz 2012/05/18 00:08:24 What do you think about PackageRange or PackageCon
Bob Nystrom 2012/05/18 20:02:38 I <3 Ref as per our discussion.
165 class PackageId implements Hashable, Comparable {
166 /** 159 /**
167 * The name used by the [source] to look up the package. 160 * The name of the package being referenced.
168 *
169 * Note that this may be distinct from [name], which is the name of the
170 * package itself. The [source] uses this name to locate the package and
171 * returns the true package name. For example, for a Git source [fullName]
172 * might be the URL "git://github.com/dart/uilib.git", while [name] would just
173 * be "uilib". It would be up to the source to take the URL and extract the
174 * package name.
175 */ 161 */
176 final String fullName; 162 final String name;
177 163
178 /** 164 /**
179 * The [Source] used to look up the package given the [fullName]. 165 * The [Source] used to look up the package.
180 */ 166 */
181 final Source source; 167 final Source source;
182 168
183 PackageId(String this.fullName, Source this.source); 169 /**
170 * The allowed package versions.
171 */
172 final VersionConstraint version;
184 173
185 /** 174 /**
186 * The name of the package being imported. Not necessarily the same as 175 * The metadata used to identify the package being referenced. The
187 * [fullName]. 176 * interpretation of this will vary based on the [source].
188 */ 177 */
189 String get name() => source.packageName(this); 178 final description;
190 179
191 int hashCode() => fullName.hashCode() ^ source.name.hashCode(); 180 PackageRef(this.name, this.source, this.version, this.description);
192 181
193 bool operator ==(other) { 182 String toString() => "$name $version from $source ($description)";
194 if (other is! PackageId) return false;
195 return other.fullName == fullName && other.source.name == source.name;
196 }
197
198 String toString() => "$fullName from ${source.name}";
199
200 int compareTo(Comparable other) {
201 if (other is! PackageId) throw new IllegalArgumentException(other);
202 var sourceComp = this.source.name.compareTo(other.source.name);
203 if (sourceComp != 0) return sourceComp;
204 return this.fullName.compareTo(other.fullName);
205 }
206 } 183 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698