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

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

Issue 10690032: Make VersionSolver source- and description-aware. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 5 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 * Attempts to resolve a set of version constraints for a package dependency 6 * Attempts to resolve a set of version constraints for a package dependency
7 * graph and select an appropriate set of best specific versions for all 7 * graph and select an appropriate set of best specific versions for all
8 * dependent packages. It works iteratively and tries to reach a stable 8 * dependent packages. It works iteratively and tries to reach a stable
9 * solution where the constraints of all dependencies are met. If it fails to 9 * solution where the constraints of all dependencies are met. If it fails to
10 * reach a solution after a certain number of iterations, it assumes the 10 * reach a solution after a certain number of iterations, it assumes the
(...skipping 19 matching lines...) Expand all
30 * constraint on that package. I.e. with a shared dependency, we intersect all 30 * constraint on that package. I.e. with a shared dependency, we intersect all
31 * of the constraints that its depending packages place on it. If that overall 31 * of the constraints that its depending packages place on it. If that overall
32 * constraint changes (say from "<3.0.0" to "<2.5.0"), then the currently 32 * constraint changes (say from "<3.0.0" to "<2.5.0"), then the currently
33 * picked version for that package may fall outside of the new constraint. If 33 * picked version for that package may fall outside of the new constraint. If
34 * that happens, we find the new best version that meets the updated constraint 34 * that happens, we find the new best version that meets the updated constraint
35 * and then the change the package to use that version. That cycles back up to 35 * and then the change the package to use that version. That cycles back up to
36 * the beginning again. 36 * the beginning again.
37 */ 37 */
38 #library('version_solver'); 38 #library('version_solver');
39 39
40 #import('dart:json');
40 #import('package.dart'); 41 #import('package.dart');
41 #import('pubspec.dart'); 42 #import('pubspec.dart');
43 #import('root_source.dart');
42 #import('source.dart'); 44 #import('source.dart');
43 #import('source_registry.dart'); 45 #import('source_registry.dart');
44 #import('utils.dart'); 46 #import('utils.dart');
45 #import('version.dart'); 47 #import('version.dart');
46 48
47 /** 49 /**
48 * Attempts to select the best concrete versions for all of the transitive 50 * Attempts to select the best concrete versions for all of the transitive
49 * dependencies of [root] taking into account all of the [VersionConstraint]s 51 * dependencies of [root] taking into account all of the [VersionConstraint]s
50 * that those dependencies place on each other. If successful, completes to a 52 * that those dependencies place on each other. If successful, completes to a
51 * [Map] that maps package names to the selected version for that package. If 53 * [Map] that maps package names to the selected version for that package. If
(...skipping 13 matching lines...) Expand all
65 final Queue<WorkItem> _work; 67 final Queue<WorkItem> _work;
66 int _numIterations = 0; 68 int _numIterations = 0;
67 69
68 VersionSolver(SourceRegistry sources, Package root) 70 VersionSolver(SourceRegistry sources, Package root)
69 : _sources = sources, 71 : _sources = sources,
70 _root = root, 72 _root = root,
71 _pubspecs = new PubspecCache(sources), 73 _pubspecs = new PubspecCache(sources),
72 _packages = <Dependency>{}, 74 _packages = <Dependency>{},
73 _work = new Queue<WorkItem>(); 75 _work = new Queue<WorkItem>();
74 76
75 Future<Map<String, Version>> solve() { 77 Future<List<PackageId>> solve() {
76 // Kick off the work by adding the root package at its concrete version to 78 // Kick off the work by adding the root package at its concrete version to
77 // the dependency graph. 79 // the dependency graph.
78 _pubspecs.cache(_root); 80 var ref = new PackageRef(new RootSource(_root), _root.version, _root.name);
79 enqueue(new ChangeConstraint('(entrypoint)', _root.name, _root.version)); 81 enqueue(new AddConstraint('(entrypoint)', ref));
82 _pubspecs.cache(ref.withVersion(_root.version), _root.pubspec);
80 83
81 Future processNextWorkItem(_) { 84 Future processNextWorkItem(_) {
82 while (true) { 85 while (true) {
83 // Stop if we are done. 86 // Stop if we are done.
84 if (_work.isEmpty()) return new Future.immediate(buildResults()); 87 if (_work.isEmpty()) return new Future.immediate(buildResults());
85 88
86 // If we appear to be stuck in a loop, then we probably have an unstable 89 // If we appear to be stuck in a loop, then we probably have an unstable
87 // graph, bail. We guess this based on a rough heuristic that it should 90 // graph, bail. We guess this based on a rough heuristic that it should
88 // only take a certain number of steps to solve a graph with a given 91 // only take a certain number of steps to solve a graph with a given
89 // number of connections. 92 // number of connections.
(...skipping 18 matching lines...) Expand all
108 return processNextWorkItem(null); 111 return processNextWorkItem(null);
109 } 112 }
110 113
111 void enqueue(WorkItem work) { 114 void enqueue(WorkItem work) {
112 _work.add(work); 115 _work.add(work);
113 } 116 }
114 117
115 Dependency getDependency(String package) { 118 Dependency getDependency(String package) {
116 // There can be unused dependencies in the graph, so just create an empty 119 // There can be unused dependencies in the graph, so just create an empty
117 // one if needed. 120 // one if needed.
118 _packages.putIfAbsent(package, () => new Dependency()); 121 _packages.putIfAbsent(package, () => new Dependency(package));
119 return _packages[package]; 122 return _packages[package];
120 } 123 }
121 124
122 /** 125 /**
123 * Sets the best selected version of [package] to [version]. 126 * Sets the best selected version of [package] to [version].
124 */ 127 */
125 void setVersion(String package, Version version) { 128 void setVersion(String package, Version version) {
126 _packages[package].version = version; 129 _packages[package].version = version;
127 } 130 }
128 131
(...skipping 18 matching lines...) Expand all
147 interface WorkItem { 150 interface WorkItem {
148 /** 151 /**
149 * Processes this work item. Returns a future that completes when the work is 152 * Processes this work item. Returns a future that completes when the work is
150 * done. If `null` is returned, that means the work has completed 153 * done. If `null` is returned, that means the work has completed
151 * synchronously and the next item can be started immediately. 154 * synchronously and the next item can be started immediately.
152 */ 155 */
153 Future process(VersionSolver solver); 156 Future process(VersionSolver solver);
154 } 157 }
155 158
156 /** 159 /**
157 * The best selected version for [package] has changed to [version]. 160 * The best selected version for a package has changed to [version]. If the
158 * If the previous version of the package is `null`, that means the package is 161 * previous version of the package is `null`, that means the package is being
159 * being added to the graph. If [version] is `null`, it is being removed. 162 * added to the graph. If [version] is `null`, it is being removed.
160 */ 163 */
161 class ChangeVersion implements WorkItem { 164 class ChangeVersion implements WorkItem {
162 /** 165 /**
163 * The package whose version is changing. 166 * The source of the package whose version is changing.
164 */ 167 */
165 final String package; 168 final Source source;
Bob Nystrom 2012/06/29 17:24:40 Can we replace these three fields with just a Pack
nweiz 2012/06/29 18:45:08 It's invalid for a PackageId to have a null versio
169
170 /**
171 * The description identifying the package whose version is changing.
172 */
173 final description;
166 174
167 /** 175 /**
168 * The new selected version. 176 * The new selected version.
169 */ 177 */
170 final Version version; 178 final Version version;
171 179
172 ChangeVersion(this.package, this.version); 180 /**
181 * The name of the package whose version is changing.
182 */
183 String get package() => source.packageName(description);
184
185 ChangeVersion(this.source, this.description, this.version) {
186 if (source == null) throw "null source";
187 }
173 188
174 Future process(VersionSolver solver) { 189 Future process(VersionSolver solver) {
175 var oldVersion = solver.getDependency(package).version; 190 var dependency = solver.getDependency(package);
191 var oldVersion = dependency.version;
176 solver.setVersion(package, version); 192 solver.setVersion(package, version);
177 193
178 // The dependencies between the old and new version may be different. Walk 194 // The dependencies between the old and new version may be different. Walk
179 // them both and update any constraints that differ between the two. 195 // them both and update any constraints that differ between the two.
180 return Futures.wait([ 196 return Futures.wait([
181 getDependencyRefs(solver, oldVersion), 197 getDependencyRefs(solver, oldVersion),
182 getDependencyRefs(solver, version)]).transform((list) { 198 getDependencyRefs(solver, version)]).transform((list) {
183 var oldDependencies = list[0]; 199 var oldDependencyRefs = list[0];
184 var newDependencies = list[1]; 200 var newDependencyRefs = list[1];
185 201
186 for (var dependency in oldDependencies.getValues()) { 202 for (var oldRef in oldDependencyRefs.getValues()) {
187 var constraint; 203 if (newDependencyRefs.containsKey(oldRef.name)) {
188 if (newDependencies.containsKey(dependency.name)) {
189 // The dependency is in both versions of this package, but its 204 // The dependency is in both versions of this package, but its
190 // constraint may have changed. 205 // constraint may have changed.
191 constraint = newDependencies.remove(dependency.name).constraint; 206 var newRef = newDependencyRefs.remove(oldRef.name);
207 solver.enqueue(new AddConstraint(package, newRef));
192 } else { 208 } else {
193 // The dependency is not in the new version of the package, so just 209 // The dependency is not in the new version of the package, so just
194 // remove its constraint. 210 // remove its constraint.
195 constraint = null; 211 solver.enqueue(new RemoveConstraint(package, oldRef.name));
196 } 212 }
197
198 solver.enqueue(new ChangeConstraint(
199 package, dependency.name, constraint));
200 } 213 }
201 214
202 // Everything that's left is a depdendency that's only in the new 215 // Everything that's left is a depdendency that's only in the new
203 // version of the package. 216 // version of the package.
204 for (var dependency in newDependencies.getValues()) { 217 for (var newRef in newDependencyRefs.getValues()) {
205 solver.enqueue(new ChangeConstraint( 218 solver.enqueue(new AddConstraint(package, newRef));
206 package, dependency.name, dependency.constraint));
207 } 219 }
208 }); 220 });
209 } 221 }
210 222
211 /** 223 /**
212 * Get the dependencies that [package] has at [version]. 224 * Get the dependencies of [id].
Bob Nystrom 2012/06/29 17:24:40 Comment doesn't line up with parameters.
nweiz 2012/06/29 18:45:08 Done.
213 */ 225 */
214 Future<Map<String, PackageRef>> getDependencyRefs(VersionSolver solver, 226 Future<Map<String, PackageRef>> getDependencyRefs(VersionSolver solver,
215 Version version) { 227 Version version) {
216 // If there is no version, it means no package, so no dependencies. 228 // If there is no version, it means no package, so no dependencies.
217 if (version == null) { 229 if (version == null) {
218 return new Future<Map<String, PackageRef>>.immediate(<PackageRef>{}); 230 return new Future<Map<String, PackageRef>>.immediate(<PackageRef>{});
219 } 231 }
220 232
221 return solver._pubspecs.load(package, version).transform((pubspec) { 233 var id = new PackageId(source, version, description);
234 return solver._pubspecs.load(id).transform((pubspec) {
222 var dependencies = <PackageRef>{}; 235 var dependencies = <PackageRef>{};
223 for (var dependency in pubspec.dependencies) { 236 for (var dependency in pubspec.dependencies) {
224 dependencies[dependency.name] = dependency; 237 dependencies[dependency.name] = dependency;
225 } 238 }
226 return dependencies; 239 return dependencies;
227 }); 240 });
228 } 241 }
229 } 242 }
230 243
231 /** 244 /**
232 * The [VersionConstraint] that [depender] places on [dependent] has changed. 245 * A constraint that a depending package places on a dependent package has
246 * changed.
247 *
248 * This is an abstract class that contains logic for updating the dependency
249 * graph once a dependency has changed. Changing the dependency is the
250 * responsibility of subclasses.
233 */ 251 */
234 class ChangeConstraint implements WorkItem { 252 class ChangeConstraint implements WorkItem {
235 /** 253 abstract Future process(VersionSolver solver);
236 * The package that has the dependency.
237 */
238 final String depender;
239 254
240 /** 255 Future _processChange(VersionSolver solver, Source source, description,
241 * The package being depended on. 256 Dependency dependency, VersionConstraint oldConstraint,
242 */ 257 VersionConstraint newConstraint) {
243 final String dependent; 258 var name = dependency.name;
244
245 /**
246 * The constraint that [depender] places on [dependent]'s version.
247 */
248 final VersionConstraint constraint;
249
250 ChangeConstraint(this.depender, this.dependent, this.constraint);
251
252 Future process(VersionSolver solver) {
253 var dependency = solver.getDependency(dependent);
254 var oldConstraint = dependency.constraint;
255 dependency.placeConstraint(depender, constraint);
256 var newConstraint = dependency.constraint;
257 259
258 // If the package is over-constrained, i.e. the packages depending have 260 // If the package is over-constrained, i.e. the packages depending have
259 // disjoint constraints, then stop. 261 // disjoint constraints, then stop.
260 if (newConstraint != null && newConstraint.isEmpty) { 262 if (newConstraint != null && newConstraint.isEmpty) {
261 throw new DisjointConstraintException(dependent); 263 throw new DisjointConstraintException(name);
262 } 264 }
263 265
264 // If this constraint change didn't cause the overall constraint on the 266 // If this constraint change didn't cause the overall constraint on the
265 // package to change, then we don't need to do any further work. 267 // package to change, then we don't need to do any further work.
266 if (oldConstraint == newConstraint) return null; 268 if (oldConstraint == newConstraint) return null;
267 269
268 // If the dependency has been cut free from the graph, just remove it. 270 // If the dependency has been cut free from the graph, just remove it.
269 if (!dependency.isDependedOn) { 271 if (!dependency.isDependedOn) {
270 solver.enqueue(new ChangeVersion(dependent, null)); 272 solver.enqueue(new ChangeVersion(source, description, null));
271 return null; 273 return null;
272 } 274 }
273 275
274 // If the dependency is on the root package, then we don't need to do 276 // If the dependency is on the root package, then we don't need to do
275 // anything since it's already at the best version. 277 // anything since it's already at the best version.
276 if (dependent == solver._root.name) { 278 if (name == solver._root.name) {
277 solver.enqueue(new ChangeVersion(dependent, solver._root.version)); 279 solver.enqueue(new ChangeVersion(
280 source, description, solver._root.version));
278 return null; 281 return null;
279 } 282 }
280 283
281 // The constraint has changed, so see what the best version of the package 284 // The constraint has changed, so see what the best version of the package
282 // that meets the new constraint is. 285 // that meets the new constraint is.
283 // TODO(rnystrom): Should this always be the default source? 286 return source.getVersions(description).transform((versions) {
284 var source = solver._sources.defaultSource;
285 return source.getVersions(dependent).transform((versions) {
286 var best = null; 287 var best = null;
287 for (var version in versions) { 288 for (var version in versions) {
288 if (newConstraint.allows(version)) { 289 if (newConstraint.allows(version)) {
289 if (best == null || version > best) best = version; 290 if (best == null || version > best) best = version;
290 } 291 }
291 } 292 }
292 293
293 // TODO(rnystrom): Better exception. 294 // TODO(rnystrom): Better exception.
294 if (best == null) throw new NoVersionException(dependent, newConstraint); 295 if (best == null) throw new NoVersionException(name, newConstraint);
295 296
296 if (dependency.version != best) { 297 if (dependency.version != best) {
297 solver.enqueue(new ChangeVersion(dependent, best)); 298 solver.enqueue(new ChangeVersion(source, description, best));
298 } 299 }
299 }); 300 });
300 } 301 }
301 } 302 }
302 303
304 /**
305 * The constraint given by [ref] is being placed by [depender].
306 */
307 class AddConstraint extends ChangeConstraint {
308 /**
309 * The package that has the dependency.
310 */
311 final String depender;
312
313 /**
314 * The package being depended on and the constraints being placed on it. The
315 * source, version, and description in this ref are all considered constraints
316 * on the dependent package.
317 */
318 final PackageRef ref;
319
320 AddConstraint(this.depender, this.ref);
321
322 Future process(VersionSolver solver) {
323 var dependency = solver.getDependency(ref.name);
324 var oldConstraint = dependency.constraint;
325 dependency.placeConstraint(depender, ref);
326 var newConstraint = dependency.constraint;
327 return _processChange(solver, ref.source, ref.description, dependency,
328 oldConstraint, newConstraint);
329 }
330 }
331
332 /**
333 * [depender] is no longer placing a constraint on [dependent].
334 */
335 class RemoveConstraint extends ChangeConstraint {
336 /**
337 * The package that was placing a constraint on [dependent].
338 */
339 String depender;
340
341 /**
342 * The package that was being depended on.
343 */
344 String dependent;
345
346 RemoveConstraint(this.depender, this.dependent);
347
348 Future process(VersionSolver solver) {
349 var dependency = solver.getDependency(dependent);
350 var oldConstraint = dependency.constraint;
351 var source = dependency.source;
352 var description = dependency.description;
353 dependency.removeConstraint(depender);
354 var newConstraint = dependency.constraint;
355 return _processChange(solver, source, description, dependency,
356 oldConstraint, newConstraint);
357 }
358 }
359
303 // TODO(rnystrom): Instead of always pulling from the source (which will mean 360 // TODO(rnystrom): Instead of always pulling from the source (which will mean
304 // hitting a server), we should consider caching pubspecs of uninstalled 361 // hitting a server), we should consider caching pubspecs of uninstalled
305 // packages in the system cache. 362 // packages in the system cache.
306 /** 363 /**
307 * Maintains a cache of previously-loaded pubspecs. Used to avoid requesting 364 * Maintains a cache of previously-loaded pubspecs. Used to avoid requesting
308 * the same pubspec from the server repeatedly. 365 * the same pubspec from the server repeatedly.
309 */ 366 */
310 class PubspecCache { 367 class PubspecCache {
311 final SourceRegistry _sources; 368 final SourceRegistry _sources;
312 final Map<String, Map<Version, Pubspec>> _pubspecs; 369 final Map<PackageId, Pubspec> _pubspecs;
313 370
314 PubspecCache(this._sources) 371 PubspecCache(this._sources)
315 : _pubspecs = <Map<Version, Pubspec>>{}; 372 : _pubspecs = new Map<PackageId, Pubspec>();
316 373
317 /** 374 /**
318 * Adds the already loaded [package] to the cache. 375 * Caches [pubspec] as the [Pubspec] for the package identified by [id].
319 */ 376 */
320 void cache(Package package) { 377 void cache(PackageId id, Pubspec pubspec) {
321 _pubspecs.putIfAbsent(package.name, () => new Map<Version, Pubspec>()); 378 _pubspecs[id] = pubspec;
322 _pubspecs[package.name][package.version] = package.pubspec;
323 } 379 }
324 380
325 /** 381 /**
326 * Loads the pubspec for [package] at [version]. 382 * Loads the pubspec for the package identified by [id].
327 */ 383 */
328 Future<Pubspec> load(String package, Version version) { 384 Future<Pubspec> load(PackageId id) {
329 // Complete immediately if it's already cached. 385 // Complete immediately if it's already cached.
330 if (_pubspecs.containsKey(package) && 386 if (_pubspecs.containsKey(id)) {
331 _pubspecs[package].containsKey(version)) { 387 return new Future<Pubspec>.immediate(_pubspecs[id]);
332 return new Future<Pubspec>.immediate(_pubspecs[package][version]);
333 } 388 }
334 389
335 // TODO(rnystrom): Should this always be the default source? 390 return id.describe().transform((pubspec) {
336 var source = _sources.defaultSource;
337 return source.describe(package, version).transform((pubspec) {
338 // Cache it. 391 // Cache it.
339 _pubspecs.putIfAbsent(package, () => new Map<Version, Pubspec>()); 392 _pubspecs[id] = pubspec;
340 _pubspecs[package][version] = pubspec;
341
342 return pubspec; 393 return pubspec;
343 }); 394 });
344 } 395 }
345 } 396 }
346 397
347 /** 398 /**
348 * Describes one [Package] in the [DependencyGraph] and keeps track of which 399 * Describes one [Package] in the [DependencyGraph] and keeps track of which
349 * packages depend on it and what [VersionConstraint]s they place on it. 400 * packages depend on it and what constraints they place on it.
350 */ 401 */
351 class Dependency { 402 class Dependency {
352 /** 403 /**
353 * The currently selected best version for this dependency. 404 * The name of the this dependency's package.
405 */
406 final String name;
407
408 /**
409 * The [PackageRefs] that represent constraints that depending packages have
410 * placed on this one.
411 */
412 final Map<String, PackageRef> _refs;
413
414 /**
415 * The source of this dependency's package.
416 *
417 * All constraints in [_refs] must have this as their source.
418 */
419 Source source;
420
421 /**
422 * The description of this dependency's package.
423 *
424 * All constraints in [_refs] must have a description equivalent to this one
425 * according to [source].
426 */
427 var description;
428
429 /**
430 * The currently-selected best version for this dependency.
354 */ 431 */
355 Version version; 432 Version version;
356 433
357 /** 434 /**
358 * The constraints that depending packages have placed on this one.
359 */
360 final Map<String, VersionConstraint> _constraints;
361
362 /**
363 * Gets whether or not any other packages are currently depending on this 435 * Gets whether or not any other packages are currently depending on this
364 * one. If `false`, then it means this package is not part of the dependency 436 * one. If `false`, then it means this package is not part of the dependency
365 * graph and should be omitted. 437 * graph and should be omitted.
366 */ 438 */
367 bool get isDependedOn() => !_constraints.isEmpty(); 439 bool get isDependedOn() => !_refs.isEmpty();
368 440
369 /** 441 /**
370 * Gets the overall constraint that all packages are placing on this one. 442 * Gets the overall constraint that all packages are placing on this one.
371 * If no packages have a constraint on this one (which can happen when this 443 * If no packages have a constraint on this one (which can happen when this
372 * package is in the process of being added to the graph), returns `null`. 444 * package is in the process of being added to the graph), returns `null`.
373 */ 445 */
374 VersionConstraint get constraint() { 446 VersionConstraint get constraint() {
375 if (_constraints.isEmpty()) return null; 447 if (_refs.isEmpty()) return null;
376 return new VersionConstraint.intersect(_constraints.getValues()); 448 return new VersionConstraint.intersect(
449 _refs.getValues().map((ref) => ref.constraint));
377 } 450 }
378 451
379 Dependency() 452 Dependency(this.name)
380 : _constraints = <VersionConstraint>{}; 453 : _refs = <PackageRef>{};
381 454
382 /** 455 /**
383 * Places [constraint] from [package] onto this. 456 * Places [ref] as a constraint from [package] onto this.
384 */ 457 */
385 void placeConstraint(String package, VersionConstraint constraint) { 458 void placeConstraint(String package, PackageRef ref) {
386 if (constraint == null) { 459 // If this isn't the first constraint placed on this package, make sure it
387 _constraints.remove(package); 460 // matches the source and description of past constraints.
388 } else { 461 if (_refs.isEmpty()) {
389 _constraints[package] = constraint; 462 source = ref.source;
463 description = ref.description;
464 } else if (source.name != ref.source.name) {
465 throw new SourceMismatchException(name, source, ref.source);
466 } else if (!source.descriptionsEqual(description, ref.description)) {
467 throw new DescriptionMismatchException(
468 name, description, ref.description);
469 }
470
471 _refs[package] = ref;
472 }
473
474 /**
475 * Removes the constraint from [package] onto this.
476 */
477 void removeConstraint(String package) {
478 _refs.remove(package);
479
480 if (_refs.isEmpty()) {
481 source = null;
482 description = null;
390 } 483 }
391 } 484 }
392 } 485 }
393 486
394 // TODO(rnystrom): Report the last of depending packages and their constraints. 487 // TODO(rnystrom): Report the last of depending packages and their constraints.
395 /** 488 /**
396 * Exception thrown when the [VersionConstraint] used to match a package is 489 * Exception thrown when the [VersionConstraint] used to match a package is
397 * valid (i.e. non-empty), but there are no released versions of the package 490 * valid (i.e. non-empty), but there are no released versions of the package
398 * that fit that constraint. 491 * that fit that constraint.
399 */ 492 */
(...skipping 25 matching lines...) Expand all
425 /** 518 /**
426 * Exception thrown when the [VersionSolver] fails to find a solution after a 519 * Exception thrown when the [VersionSolver] fails to find a solution after a
427 * certain number of iterations. 520 * certain number of iterations.
428 */ 521 */
429 class CouldNotSolveException implements Exception { 522 class CouldNotSolveException implements Exception {
430 CouldNotSolveException(); 523 CouldNotSolveException();
431 524
432 String toString() => 525 String toString() =>
433 "Could not find a solution that met all version constraints."; 526 "Could not find a solution that met all version constraints.";
434 } 527 }
528
529 /**
530 * Exception thrown when two packages with the same name but different sources
531 * are depended upon.
532 */
533 class SourceMismatchException implements Exception {
534 final String package;
535 final Source source1;
536 final Source source2;
537
538 SourceMismatchException(this.package, this.source1, this.source2);
539
540 String toString() {
541 return "Package '$package' is depended on from both sources "
542 "'${source1.name}' and '${source2.name}'.";
543 }
544 }
545
546 /**
547 * Exception thrown when two packages with the same name and source but
548 * different descriptions are depended upon.
549 */
550 class DescriptionMismatchException implements Exception {
551 final String package;
552 final description1;
553 final description2;
554
555 DescriptionMismatchException(this.package, this.description1,
556 this.description2);
557
558 // TODO(nweiz): Dump to YAML when that's supported
559 String toString() => "Package '$package' has conflicting descriptions "
560 "'${JSON.stringify(description1)}' and '${JSON.stringify(description2)}'";
561 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698