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

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: Respond to review. 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
« no previous file with comments | « utils/pub/io.dart ('k') | utils/pub/packages_dir.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, SourceRegistry sources) {
13 final pubspecPath = join(packageDir, 'pubspec'); 13 var pubspecPath = join(packageDir, 'pubspec');
14 14
15 return _parsePubspec(pubspecPath, sources).transform((dependencies) { 15 return fileExists(pubspecPath).chain((exists) {
16 return new Package._(packageDir, dependencies); 16 if (exists) {
17 return readTextFile(pubspecPath).transform((contents) {
18 return new Pubspec.parse(contents, sources);
19 });
20 } else {
21 // If there is no pubspec, we implicitly treat that as a package with
22 // no dependencies.
23 return new Future.immediate(new Pubspec.empty());
24 }
25 }).transform((pubspec) {
26 return new Package._(packageDir, pubspec);
17 }); 27 });
18 } 28 }
19 29
20 /** 30 /**
21 * The path to the directory containing the package. 31 * The path to the directory containing the package.
22 */ 32 */
23 final String dir; 33 final String dir;
24 34
25 /** 35 /**
26 * The name of the package. 36 * The name of the package.
27 */ 37 */
28 final String name; 38 final String name;
29 39
30 /** 40 /**
41 * The package's version.
42 */
43 Version get version() => pubspec.version;
44
45 /**
46 * The parsed pubspec associated with this package.
47 */
48 final Pubspec pubspec;
49
50 /**
31 * The ids of the packages that this package depends on. This is what is 51 * 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. 52 * specified in the pubspec when this package depends on another.
33 */ 53 */
34 final Collection<PackageId> dependencies; 54 Collection<PackageRef> get dependencies() => pubspec.dependencies;
35 55
36 /** 56 /**
37 * Constructs a package. This should not be called directly. Instead, acquire 57 * Constructs a package. This should not be called directly. Instead, acquire
38 * packages from [load()]. 58 * packages from [load()].
39 */ 59 */
40 Package._(String dir, this.dependencies) 60 Package._(String dir, this.pubspec)
41 : dir = dir, 61 : dir = dir,
42 name = basename(dir); 62 name = basename(dir);
43
44 /**
45 * Generates a hashcode for the package.
46 */
47 // TODO(rnystrom): Do something more sophisticated here once we care about
48 // versioning and different package sources.
49 int hashCode() => name.hashCode();
50 63
51 /** 64 /**
52 * Returns a debug string for the package. 65 * Returns a debug string for the package.
53 */ 66 */
54 String toString() => '$name ($dir)'; 67 String toString() => '$name ($dir)';
68 }
69
70 /**
71 * An unambiguous resolved reference to a package. A package ID contains enough
72 * information to correctly install the package.
73 *
74 * Note that it's possible for multiple distinct package IDs to point to
75 * different directories that happen to contain identical packages. For example,
76 * the same package may be available from multiple sources. As far as Pub is
77 * concerned, those packages are different.
78 */
79 class PackageId implements Comparable, Hashable {
80 /**
81 * The [Source] used to look up this package given its [description].
82 */
83 final Source source;
55 84
56 /** 85 /**
57 * Parses the pubspec at the given path and returns the list of package 86 * The package's version.
58 * dependencies it exposes.
59 */ 87 */
60 static Future<List<PackageId>> _parsePubspec(String path, 88 final Version version;
61 SourceRegistry sources) {
62 final completer = new Completer<List<PackageId>>();
63 89
64 // TODO(rnystrom): Handle the directory not existing. 90 /**
65 // TODO(rnystrom): Error-handling. 91 * The metadata used by the package's [source] to identify and locate it. It
66 final readFuture = readTextFile(path); 92 * contains whatever [Source]-specific data it needs to be able to install
67 readFuture.handleException((error) { 93 * 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 94 * by the URL "git://github.com/dart/uilib.git".
69 // dependencies. 95 */
70 // TODO(rnystrom): Distinguish file not found from other real errors. 96 final description;
71 completer.complete(<PackageId>[]);
72 return true;
73 });
74 97
75 readFuture.then((pubspec) { 98 PackageId(this.source, this.version, this.description);
76 if (pubspec.trim() == '') {
77 completer.complete(<String>[]);
78 return;
79 }
80 99
81 var parsedPubspec = loadYaml(pubspec); 100 /**
82 if (parsedPubspec is! Map) { 101 * The name of the package being identified. This will be the human-friendly
83 completer.completeException('The pubspec must be a YAML mapping.'); 102 * name like "uilib".
84 } 103 */
104 String get name() => source.packageName(this);
85 105
86 if (!parsedPubspec.containsKey('dependencies')) { 106 int hashCode() => name.hashCode() ^
87 completer.complete(<String>[]); 107 source.name.hashCode() ^
88 return; 108 version.hashCode();
89 }
90 109
91 var dependencies = parsedPubspec['dependencies']; 110 bool operator ==(other) {
92 if (dependencies is! Map || 111 if (other is! PackageId) return false;
93 dependencies.getKeys().some((e) => e is! String)) { 112 // TODO(rnystrom): We're assuming here the name/version/source tuple is
94 completer.completeException( 113 // 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.'); 114 // into the description.
96 } 115 return other.name == name &&
116 other.source.name == source.name &&
117 other.version == version;
118 }
97 119
98 var dependencyIds = <PackageId>[]; 120 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 121
108 var sourceNames = spec.getKeys(); 122 int compareTo(Comparable other) {
109 if (sourceNames.length > 1) { 123 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 124
116 var sourceName = only(sourceNames); 125 var sourceComp = source.name.compareTo(other.source.name);
117 if (sourceName is! String) { 126 if (sourceComp != 0) return sourceComp;
118 completer.completeException(
119 'Source name $sourceName must be a string.');
120 return;
121 }
122 source = sources[sourceName];
123 127
124 // TODO(nweiz): At some point we want fullName to be able to be an 128 var nameComp = name.compareTo(other.name);
125 // arbitrary object that's parsed by the source. 129 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 130
138 var id = new PackageId(fullName, source); 131 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 } 132 }
154 } 133 }
155 134
156 /** 135 /**
157 * A unique identifier for a package. A given package id specifies a single 136 * A reference to a package. Unlike a [PackageId], a PackageRef may not
158 * chunk of code and resources. 137 * unambiguously refer to a single package. It may describe a range of allowed
159 * 138 * 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 */ 139 */
164 // TODO(nweiz, rnystrom): this should include version eventually 140 class PackageRef {
165 class PackageId implements Hashable, Comparable {
166 /** 141 /**
167 * The name used by the [source] to look up the package. 142 * 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 */ 143 */
176 final String fullName; 144 final String name;
177 145
178 /** 146 /**
179 * The [Source] used to look up the package given the [fullName]. 147 * The [Source] used to look up the package.
180 */ 148 */
181 final Source source; 149 final Source source;
182 150
183 PackageId(String this.fullName, Source this.source); 151 /**
152 * The allowed package versions.
153 */
154 final VersionConstraint version;
184 155
185 /** 156 /**
186 * The name of the package being imported. Not necessarily the same as 157 * The metadata used to identify the package being referenced. The
187 * [fullName]. 158 * interpretation of this will vary based on the [source].
188 */ 159 */
189 String get name() => source.packageName(this); 160 final description;
190 161
191 int hashCode() => fullName.hashCode() ^ source.name.hashCode(); 162 PackageRef(this.name, this.source, this.version, this.description);
192 163
193 bool operator ==(other) { 164 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 } 165 }
OLDNEW
« no previous file with comments | « utils/pub/io.dart ('k') | utils/pub/packages_dir.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698