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 * 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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 69 final Map<String, Dependency> _packages; | 69 final Map<String, Dependency> _packages; |
| 70 final Queue<WorkItem> _work; | 70 final Queue<WorkItem> _work; |
| 71 int _numIterations = 0; | 71 int _numIterations = 0; |
| 72 | 72 |
| 73 VersionSolver(SourceRegistry sources, this._root, this.lockFile) | 73 VersionSolver(SourceRegistry sources, this._root, this.lockFile) |
| 74 : _sources = sources, | 74 : _sources = sources, |
| 75 _pubspecs = new PubspecCache(sources), | 75 _pubspecs = new PubspecCache(sources), |
| 76 _packages = <String, Dependency>{}, | 76 _packages = <String, Dependency>{}, |
| 77 _work = new Queue<WorkItem>(); | 77 _work = new Queue<WorkItem>(); |
| 78 | 78 |
| 79 /** | |
| 80 * Tell the version solver to use the most recent version of [package] that | |
| 81 * exists in whatever source it's installed from. If that version violates | |
| 82 * constraints imposed by other dependencies, an error will be raised when | |
| 83 * solving the versions, even if an earlier compatible version exists. | |
| 84 */ | |
| 85 void useLatestVersion(String package) { | |
| 86 // TODO(nweiz): How do we want to detect and handle unknown dependencies | |
| 87 // here? | |
| 88 getDependency(package).useLatestVersion = true; | |
| 89 lockFile.packages.remove(package); | |
| 90 } | |
| 91 | |
| 79 Future<List<PackageId>> solve() { | 92 Future<List<PackageId>> solve() { |
| 80 // Kick off the work by adding the root package at its concrete version to | 93 // Kick off the work by adding the root package at its concrete version to |
| 81 // the dependency graph. | 94 // the dependency graph. |
| 82 var ref = new PackageRef(new RootSource(_root), _root.version, _root.name); | 95 var ref = new PackageRef(new RootSource(_root), _root.version, _root.name); |
| 83 enqueue(new AddConstraint('(entrypoint)', ref)); | 96 enqueue(new AddConstraint('(entrypoint)', ref)); |
| 84 _pubspecs.cache(ref.atVersion(_root.version), _root.pubspec); | 97 _pubspecs.cache(ref.atVersion(_root.version), _root.pubspec); |
| 85 | 98 |
| 86 Future processNextWorkItem(_) { | 99 Future processNextWorkItem(_) { |
| 87 while (true) { | 100 while (true) { |
| 88 // Stop if we are done. | 101 // Stop if we are done. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 124 return _packages[package]; | 137 return _packages[package]; |
| 125 } | 138 } |
| 126 | 139 |
| 127 /** | 140 /** |
| 128 * Sets the best selected version of [package] to [version]. | 141 * Sets the best selected version of [package] to [version]. |
| 129 */ | 142 */ |
| 130 void setVersion(String package, Version version) { | 143 void setVersion(String package, Version version) { |
| 131 _packages[package].version = version; | 144 _packages[package].version = version; |
| 132 } | 145 } |
| 133 | 146 |
| 147 /** | |
| 148 * Returns the most recent version of [dependency] that satisfies all of its | |
| 149 * version constraints. | |
| 150 */ | |
| 151 Future<Version> getBestVersion(Dependency dependency) { | |
| 152 return dependency.source.getVersions(dependency.description) | |
| 153 .transform((versions) { | |
| 154 var best = null; | |
| 155 for (var version in versions) { | |
| 156 if (dependency.useLatestVersion || | |
| 157 dependency.constraint.allows(version)) { | |
| 158 if (best == null || version > best) best = version; | |
| 159 } | |
| 160 } | |
| 161 | |
| 162 // TODO(rnystrom): Better exception. | |
| 163 if (best == null) { | |
| 164 if (tryUnlockDepender(dependency)) return null; | |
| 165 throw new NoVersionException(dependency.name, dependency.constraint); | |
| 166 } else if (!dependency.constraint.allows(best)) { | |
| 167 if (tryUnlockDepender(dependency)) return null; | |
| 168 throw new CouldNotUpdateException( | |
| 169 dependency.name, dependency.constraint, best); | |
| 170 } | |
| 171 | |
| 172 return best; | |
| 173 }); | |
| 174 } | |
| 175 | |
| 176 /** | |
| 177 * Looks for a package that depends (transitively) on [dependency] and has its | |
| 178 * version locked in the lockfile. If one is found, enqueues an | |
| 179 * [UnlockPackage] work item for it and returns true. Otherwise, returns | |
| 180 * false. | |
| 181 * | |
| 182 * This does a breadth-first search; immediate dependers will be unlocked | |
| 183 * first, followed by transitive dependers. | |
| 184 */ | |
| 185 bool tryUnlockDepender(Dependency dependency) { | |
| 186 for (var dependerName in dependency.dependers) { | |
| 187 var depender = getDependency(dependerName); | |
| 188 var locked = lockFile.packages[dependerName]; | |
| 189 if (locked != null && depender.version == locked.version) { | |
| 190 enqueue(new UnlockPackage(depender)); | |
| 191 return true; | |
| 192 } | |
| 193 } | |
| 194 return dependency.dependers.map(getDependency).some(tryUnlockDepender); | |
| 195 } | |
| 196 | |
| 134 List<PackageId> buildResults() { | 197 List<PackageId> buildResults() { |
| 135 return _packages.getValues().filter((dep) => dep.isDependedOn).map((dep) { | 198 return _packages.getValues().filter((dep) => dep.isDependedOn).map((dep) { |
| 136 var description = dep.description; | 199 var description = dep.description; |
| 137 | 200 |
| 138 // If the lockfile contains a fully-resolved description for the package, | 201 // If the lockfile contains a fully-resolved description for the package, |
| 139 // use that. This allows e.g. Git to ensure that the same commit is used. | 202 // use that. This allows e.g. Git to ensure that the same commit is used. |
| 140 var lockedPackage = lockFile.packages[dep.name]; | 203 var lockedPackage = lockFile.packages[dep.name]; |
| 141 if (lockedPackage != null && lockedPackage.version == dep.version && | 204 if (lockedPackage != null && lockedPackage.version == dep.version && |
| 142 lockedPackage.source.name == dep.source.name && | 205 lockedPackage.source.name == dep.source.name && |
| 143 dep.source.descriptionsEqual( | 206 dep.source.descriptionsEqual( |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 255 * A constraint that a depending package places on a dependent package has | 318 * A constraint that a depending package places on a dependent package has |
| 256 * changed. | 319 * changed. |
| 257 * | 320 * |
| 258 * This is an abstract class that contains logic for updating the dependency | 321 * This is an abstract class that contains logic for updating the dependency |
| 259 * graph once a dependency has changed. Changing the dependency is the | 322 * graph once a dependency has changed. Changing the dependency is the |
| 260 * responsibility of subclasses. | 323 * responsibility of subclasses. |
| 261 */ | 324 */ |
| 262 class ChangeConstraint implements WorkItem { | 325 class ChangeConstraint implements WorkItem { |
| 263 abstract Future process(VersionSolver solver); | 326 abstract Future process(VersionSolver solver); |
| 264 | 327 |
| 328 abstract void undo(VersionSolver solver); | |
| 329 | |
| 265 Future _processChange(VersionSolver solver, Source source, description, | 330 Future _processChange(VersionSolver solver, Source source, description, |
| 266 Dependency dependency, VersionConstraint oldConstraint, | 331 Dependency dependency, VersionConstraint oldConstraint) { |
|
Bob Nystrom
2012/08/21 18:29:57
(source, dep, constraint) is a PackageRef. Can we
nweiz
2012/08/21 19:57:23
Calling these values a PackageRef isn't really an
| |
| 267 VersionConstraint newConstraint) { | |
| 268 var name = dependency.name; | 332 var name = dependency.name; |
| 333 var newConstraint = dependency.constraint; | |
| 269 | 334 |
| 270 // If the package is over-constrained, i.e. the packages depending have | 335 // If the package is over-constrained, i.e. the packages depending have |
| 271 // disjoint constraints, then stop. | 336 // disjoint constraints, then try unlocking a depender that's locked by the |
| 337 // lockfile. If there are no remaining locked dependencies, throw an error. | |
| 272 if (newConstraint != null && newConstraint.isEmpty) { | 338 if (newConstraint != null && newConstraint.isEmpty) { |
| 339 if (solver.tryUnlockDepender(dependency)) { | |
| 340 undo(solver); | |
| 341 return null; | |
| 342 } | |
| 343 | |
| 273 throw new DisjointConstraintException(name); | 344 throw new DisjointConstraintException(name); |
| 274 } | 345 } |
| 275 | 346 |
| 276 // If this constraint change didn't cause the overall constraint on the | 347 // If this constraint change didn't cause the overall constraint on the |
| 277 // package to change, then we don't need to do any further work. | 348 // package to change, then we don't need to do any further work. |
| 278 if (oldConstraint == newConstraint) return null; | 349 if (oldConstraint == newConstraint) return null; |
| 279 | 350 |
| 280 // If the dependency has been cut free from the graph, just remove it. | 351 // If the dependency has been cut free from the graph, just remove it. |
| 281 if (!dependency.isDependedOn) { | 352 if (!dependency.isDependedOn) { |
| 353 if (source == null) print("dependency for null source: ${dependency.name}" ); | |
|
Bob Nystrom
2012/08/21 18:29:57
Debug code. Nix.
nweiz
2012/08/21 19:57:23
Done.
| |
| 282 solver.enqueue(new ChangeVersion(source, description, null)); | 354 solver.enqueue(new ChangeVersion(source, description, null)); |
| 283 return null; | 355 return null; |
| 284 } | 356 } |
| 285 | 357 |
| 286 // If the dependency is on the root package, then we don't need to do | 358 // If the dependency is on the root package, then we don't need to do |
| 287 // anything since it's already at the best version. | 359 // anything since it's already at the best version. |
| 288 if (name == solver._root.name) { | 360 if (name == solver._root.name) { |
| 289 solver.enqueue(new ChangeVersion( | 361 solver.enqueue(new ChangeVersion( |
| 290 source, description, solver._root.version)); | 362 source, description, solver._root.version)); |
| 291 return null; | 363 return null; |
| 292 } | 364 } |
| 293 | 365 |
| 294 // If the dependency is on a package in the lockfile, use the lockfile's | 366 // If the dependency is on a package in the lockfile, use the lockfile's |
| 295 // version for that package if it's valid given the other constraints. | 367 // version for that package if it's valid given the other constraints. |
| 296 var lockedPackage = solver.lockFile.packages[name]; | 368 var lockedPackage = solver.lockFile.packages[name]; |
| 297 if (lockedPackage != null) { | 369 if (lockedPackage != null) { |
| 298 var lockedVersion = lockedPackage.version; | 370 var lockedVersion = lockedPackage.version; |
| 299 if (newConstraint.allows(lockedVersion)) { | 371 if (newConstraint.allows(lockedVersion)) { |
| 300 solver.enqueue(new ChangeVersion(source, description, lockedVersion)); | 372 solver.enqueue(new ChangeVersion(source, description, lockedVersion)); |
| 301 return null; | 373 return null; |
| 302 } | 374 } |
| 303 } | 375 } |
| 304 | 376 |
| 305 // The constraint has changed, so see what the best version of the package | 377 // The constraint has changed, so see what the best version of the package |
| 306 // that meets the new constraint is. | 378 // that meets the new constraint is. |
| 307 return source.getVersions(description).transform((versions) { | 379 return solver.getBestVersion(dependency).transform((best) { |
| 308 var best = null; | 380 if (best == null) { |
| 309 for (var version in versions) { | 381 undo(solver); |
| 310 if (newConstraint.allows(version)) { | 382 } else if (dependency.version != best) { |
| 311 if (best == null || version > best) best = version; | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 // TODO(rnystrom): Better exception. | |
| 316 if (best == null) throw new NoVersionException(name, newConstraint); | |
| 317 | |
| 318 if (dependency.version != best) { | |
| 319 solver.enqueue(new ChangeVersion(source, description, best)); | 383 solver.enqueue(new ChangeVersion(source, description, best)); |
| 320 } | 384 } |
| 321 }); | 385 }); |
| 322 } | 386 } |
| 323 } | 387 } |
| 324 | 388 |
| 325 /** | 389 /** |
| 326 * The constraint given by [ref] is being placed by [depender]. | 390 * The constraint given by [ref] is being placed by [depender]. |
| 327 */ | 391 */ |
| 328 class AddConstraint extends ChangeConstraint { | 392 class AddConstraint extends ChangeConstraint { |
| 329 /** | 393 /** |
| 330 * The package that has the dependency. | 394 * The package that has the dependency. |
| 331 */ | 395 */ |
| 332 final String depender; | 396 final String depender; |
| 333 | 397 |
| 334 /** | 398 /** |
| 335 * The package being depended on and the constraints being placed on it. The | 399 * The package being depended on and the constraints being placed on it. The |
| 336 * source, version, and description in this ref are all considered constraints | 400 * source, version, and description in this ref are all considered constraints |
| 337 * on the dependent package. | 401 * on the dependent package. |
| 338 */ | 402 */ |
| 339 final PackageRef ref; | 403 final PackageRef ref; |
| 340 | 404 |
| 341 AddConstraint(this.depender, this.ref); | 405 AddConstraint(this.depender, this.ref); |
| 342 | 406 |
| 343 Future process(VersionSolver solver) { | 407 Future process(VersionSolver solver) { |
| 344 var dependency = solver.getDependency(ref.name); | 408 var dependency = solver.getDependency(ref.name); |
| 345 var oldConstraint = dependency.constraint; | 409 var oldConstraint = dependency.constraint; |
| 346 dependency.placeConstraint(depender, ref); | 410 dependency.placeConstraint(depender, ref); |
| 347 var newConstraint = dependency.constraint; | |
| 348 return _processChange(solver, ref.source, ref.description, dependency, | 411 return _processChange(solver, ref.source, ref.description, dependency, |
| 349 oldConstraint, newConstraint); | 412 oldConstraint); |
| 413 } | |
| 414 | |
| 415 void undo(VersionSolver solver) { | |
| 416 solver.getDependency(ref.name).removeConstraint(depender); | |
| 350 } | 417 } |
| 351 } | 418 } |
| 352 | 419 |
| 353 /** | 420 /** |
| 354 * [depender] is no longer placing a constraint on [dependent]. | 421 * [depender] is no longer placing a constraint on [dependent]. |
| 355 */ | 422 */ |
| 356 class RemoveConstraint extends ChangeConstraint { | 423 class RemoveConstraint extends ChangeConstraint { |
| 357 /** | 424 /** |
| 358 * The package that was placing a constraint on [dependent]. | 425 * The package that was placing a constraint on [dependent]. |
| 359 */ | 426 */ |
| 360 String depender; | 427 String depender; |
| 361 | 428 |
| 362 /** | 429 /** |
| 363 * The package that was being depended on. | 430 * The package that was being depended on. |
| 364 */ | 431 */ |
| 365 String dependent; | 432 String dependent; |
| 366 | 433 |
| 434 /** The constraint that was removed. */ | |
| 435 PackageRef _removed; | |
| 436 | |
| 367 RemoveConstraint(this.depender, this.dependent); | 437 RemoveConstraint(this.depender, this.dependent); |
| 368 | 438 |
| 369 Future process(VersionSolver solver) { | 439 Future process(VersionSolver solver) { |
| 370 var dependency = solver.getDependency(dependent); | 440 var dependency = solver.getDependency(dependent); |
| 371 var oldConstraint = dependency.constraint; | 441 var oldConstraint = dependency.constraint; |
| 372 var source = dependency.source; | 442 var source = dependency.source; |
| 373 var description = dependency.description; | 443 var description = dependency.description; |
| 374 dependency.removeConstraint(depender); | 444 _removed = dependency.removeConstraint(depender); |
| 375 var newConstraint = dependency.constraint; | |
| 376 return _processChange(solver, source, description, dependency, | 445 return _processChange(solver, source, description, dependency, |
| 377 oldConstraint, newConstraint); | 446 oldConstraint); |
| 447 } | |
| 448 | |
| 449 void undo() { | |
| 450 solver.getDependency(dependent).placeConstraint(depender, _removed); | |
| 378 } | 451 } |
| 379 } | 452 } |
| 380 | 453 |
| 454 /** [package]'s version is no longer constrained by the lockfile. */ | |
| 455 class UnlockPackage implements WorkItem { | |
| 456 /** The package being unlocked. */ | |
| 457 Dependency package; | |
| 458 | |
| 459 UnlockPackage(this.package); | |
| 460 | |
| 461 Future process(VersionSolver solver) { | |
| 462 solver.lockFile.packages.remove(package.name); | |
| 463 return solver.getBestVersion(package).transform((best) { | |
| 464 if (best == null) return null; | |
| 465 solver.enqueue(new ChangeVersion( | |
| 466 package.source, package.description, best)); | |
| 467 }); | |
| 468 } | |
| 469 } | |
| 470 | |
| 381 // TODO(rnystrom): Instead of always pulling from the source (which will mean | 471 // TODO(rnystrom): Instead of always pulling from the source (which will mean |
| 382 // hitting a server), we should consider caching pubspecs of uninstalled | 472 // hitting a server), we should consider caching pubspecs of uninstalled |
| 383 // packages in the system cache. | 473 // packages in the system cache. |
| 384 /** | 474 /** |
| 385 * Maintains a cache of previously-loaded pubspecs. Used to avoid requesting | 475 * Maintains a cache of previously-loaded pubspecs. Used to avoid requesting |
| 386 * the same pubspec from the server repeatedly. | 476 * the same pubspec from the server repeatedly. |
| 387 */ | 477 */ |
| 388 class PubspecCache { | 478 class PubspecCache { |
| 389 final SourceRegistry _sources; | 479 final SourceRegistry _sources; |
| 390 final Map<PackageId, Pubspec> _pubspecs; | 480 final Map<PackageId, Pubspec> _pubspecs; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 446 * according to [source]. | 536 * according to [source]. |
| 447 */ | 537 */ |
| 448 var description; | 538 var description; |
| 449 | 539 |
| 450 /** | 540 /** |
| 451 * The currently-selected best version for this dependency. | 541 * The currently-selected best version for this dependency. |
| 452 */ | 542 */ |
| 453 Version version; | 543 Version version; |
| 454 | 544 |
| 455 /** | 545 /** |
| 546 * Whether this dependency should always select the latest version. | |
| 547 */ | |
| 548 bool useLatestVersion = false; | |
| 549 | |
| 550 /** | |
| 456 * Gets whether or not any other packages are currently depending on this | 551 * Gets whether or not any other packages are currently depending on this |
| 457 * one. If `false`, then it means this package is not part of the dependency | 552 * one. If `false`, then it means this package is not part of the dependency |
| 458 * graph and should be omitted. | 553 * graph and should be omitted. |
| 459 */ | 554 */ |
| 460 bool get isDependedOn() => !_refs.isEmpty(); | 555 bool get isDependedOn() => !_refs.isEmpty(); |
| 461 | 556 |
| 557 /** The names of all the packages that depend on this dependency. */ | |
| 558 Collection<String> get dependers() => _refs.getKeys(); | |
| 559 | |
| 462 /** | 560 /** |
| 463 * Gets the overall constraint that all packages are placing on this one. | 561 * Gets the overall constraint that all packages are placing on this one. |
| 464 * If no packages have a constraint on this one (which can happen when this | 562 * If no packages have a constraint on this one (which can happen when this |
| 465 * package is in the process of being added to the graph), returns `null`. | 563 * package is in the process of being added to the graph), returns `null`. |
| 466 */ | 564 */ |
| 467 VersionConstraint get constraint() { | 565 VersionConstraint get constraint() { |
| 468 if (_refs.isEmpty()) return null; | 566 if (_refs.isEmpty()) return null; |
| 469 return new VersionConstraint.intersect( | 567 return new VersionConstraint.intersect( |
| 470 _refs.getValues().map((ref) => ref.constraint)); | 568 _refs.getValues().map((ref) => ref.constraint)); |
| 471 } | 569 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 488 throw new DescriptionMismatchException( | 586 throw new DescriptionMismatchException( |
| 489 name, description, ref.description); | 587 name, description, ref.description); |
| 490 } | 588 } |
| 491 | 589 |
| 492 _refs[package] = ref; | 590 _refs[package] = ref; |
| 493 } | 591 } |
| 494 | 592 |
| 495 /** | 593 /** |
| 496 * Removes the constraint from [package] onto this. | 594 * Removes the constraint from [package] onto this. |
| 497 */ | 595 */ |
| 498 void removeConstraint(String package) { | 596 PackageRef removeConstraint(String package) { |
| 499 _refs.remove(package); | 597 var removed = _refs.remove(package); |
| 500 | 598 |
| 501 if (_refs.isEmpty()) { | 599 if (_refs.isEmpty()) { |
| 502 source = null; | 600 source = null; |
| 503 description = null; | 601 description = null; |
| 504 } | 602 } |
| 603 | |
| 604 return removed; | |
| 505 } | 605 } |
| 506 } | 606 } |
| 507 | 607 |
| 508 // TODO(rnystrom): Report the last of depending packages and their constraints. | 608 // TODO(rnystrom): Report the last of depending packages and their constraints. |
| 509 /** | 609 /** |
| 510 * Exception thrown when the [VersionConstraint] used to match a package is | 610 * Exception thrown when the [VersionConstraint] used to match a package is |
| 511 * valid (i.e. non-empty), but there are no released versions of the package | 611 * valid (i.e. non-empty), but there are no released versions of the package |
| 512 * that fit that constraint. | 612 * that fit that constraint. |
| 513 */ | 613 */ |
| 514 class NoVersionException implements Exception { | 614 class NoVersionException implements Exception { |
| 515 final String package; | 615 final String package; |
| 516 final VersionConstraint constraint; | 616 final VersionConstraint constraint; |
| 517 | 617 |
| 518 NoVersionException(this.package, this.constraint); | 618 NoVersionException(this.package, this.constraint); |
| 519 | 619 |
| 520 String toString() => | 620 String toString() => |
| 521 "Package '$package' has no versions that match $constraint."; | 621 "Package '$package' has no versions that match $constraint."; |
| 522 } | 622 } |
| 523 | 623 |
| 624 // TODO(rnystrom): Report the list of depending packages and their constraints. | |
| 625 /** | |
| 626 * Exception thrown when the most recent version of [package] must be selected, | |
| 627 * but doesn't match the [VersionConstraint] imposed on the package. | |
| 628 */ | |
| 629 class CouldNotUpdateException implements Exception { | |
| 630 final String package; | |
| 631 final VersionConstraint constraint; | |
| 632 final Version best; | |
| 633 | |
| 634 CouldNotUpdateException(this.package, this.constraint, this.best); | |
| 635 | |
| 636 String toString() => | |
| 637 "The latest version of '$package', $best, does not match $constraint."; | |
| 638 } | |
| 639 | |
| 524 // TODO(rnystrom): Report the last of depending packages and their constraints. | 640 // TODO(rnystrom): Report the last of depending packages and their constraints. |
| 525 /** | 641 /** |
| 526 * Exception thrown when the [VersionConstraint] used to match a package is | 642 * Exception thrown when the [VersionConstraint] used to match a package is |
| 527 * the empty set: in other words, multiple packages depend on it and have | 643 * the empty set: in other words, multiple packages depend on it and have |
| 528 * conflicting constraints that have no overlap. | 644 * conflicting constraints that have no overlap. |
| 529 */ | 645 */ |
| 530 class DisjointConstraintException implements Exception { | 646 class DisjointConstraintException implements Exception { |
| 531 final String package; | 647 final String package; |
| 532 | 648 |
| 533 DisjointConstraintException(this.package); | 649 DisjointConstraintException(this.package); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 573 final description1; | 689 final description1; |
| 574 final description2; | 690 final description2; |
| 575 | 691 |
| 576 DescriptionMismatchException(this.package, this.description1, | 692 DescriptionMismatchException(this.package, this.description1, |
| 577 this.description2); | 693 this.description2); |
| 578 | 694 |
| 579 // TODO(nweiz): Dump to YAML when that's supported | 695 // TODO(nweiz): Dump to YAML when that's supported |
| 580 String toString() => "Package '$package' has conflicting descriptions " | 696 String toString() => "Package '$package' has conflicting descriptions " |
| 581 "'${JSON.stringify(description1)}' and '${JSON.stringify(description2)}'"; | 697 "'${JSON.stringify(description1)}' and '${JSON.stringify(description2)}'"; |
| 582 } | 698 } |
| OLD | NEW |