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 22 matching lines...) Expand all Loading... | |
| 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 'dart:json'; |
| 41 import 'dart:math'; | 41 import 'dart:math'; |
| 42 import 'lock_file.dart'; | 42 import 'lock_file.dart'; |
| 43 import 'log.dart' as log; | |
| 43 import 'package.dart'; | 44 import 'package.dart'; |
| 44 import 'pubspec.dart'; | 45 import 'pubspec.dart'; |
| 45 import 'root_source.dart'; | 46 import 'root_source.dart'; |
| 46 import 'source.dart'; | 47 import 'source.dart'; |
| 47 import 'source_registry.dart'; | 48 import 'source_registry.dart'; |
| 48 import 'utils.dart'; | 49 import 'utils.dart'; |
| 49 import 'version.dart'; | 50 import 'version.dart'; |
| 50 | 51 |
| 51 /** | 52 /** |
| 52 * Attempts to select the best concrete versions for all of the transitive | 53 * Attempts to select the best concrete versions for all of the transitive |
| 53 * dependencies of [root] taking into account all of the [VersionConstraint]s | 54 * dependencies of [root] taking into account all of the [VersionConstraint]s |
| 54 * that those dependencies place on each other and the requirements imposed by | 55 * that those dependencies place on each other and the requirements imposed by |
| 55 * [lockFile]. If successful, completes to a [Map] that maps package names to | 56 * [lockFile]. If successful, completes to a [Map] that maps package names to |
| 56 * the selected version for that package. If it fails, the future will complete | 57 * the selected version for that package. If it fails, the future will complete |
| 57 * with a [NoVersionException], [DisjointConstraintException], or | 58 * with a [NoVersionException], [DisjointConstraintException], or |
| 58 * [CouldNotSolveException]. | 59 * [CouldNotSolveException]. |
| 59 */ | 60 */ |
| 60 Future<List<PackageId>> resolveVersions(SourceRegistry sources, Package root, | 61 Future<List<PackageId>> resolveVersions(SourceRegistry sources, Package root, |
| 61 LockFile lockFile) { | 62 LockFile lockFile) { |
| 62 print('Resolving dependencies...'); | 63 log.message('Resolving dependencies...'); |
| 63 return new VersionSolver(sources, root, lockFile).solve(); | 64 return new VersionSolver(sources, root, lockFile).solve(); |
| 64 } | 65 } |
| 65 | 66 |
| 66 class VersionSolver { | 67 class VersionSolver { |
| 67 final SourceRegistry _sources; | 68 final SourceRegistry _sources; |
| 68 final Package _root; | 69 final Package _root; |
| 69 final LockFile lockFile; | 70 final LockFile lockFile; |
| 70 final PubspecCache _pubspecs; | 71 final PubspecCache _pubspecs; |
| 71 final Map<String, Dependency> _packages; | 72 final Map<String, Dependency> _packages; |
| 72 final Queue<WorkItem> _work; | 73 final Queue<WorkItem> _work; |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 259 /** | 260 /** |
| 260 * The new selected version. | 261 * The new selected version. |
| 261 */ | 262 */ |
| 262 final Version version; | 263 final Version version; |
| 263 | 264 |
| 264 ChangeVersion(this.package, this.source, this.description, this.version) { | 265 ChangeVersion(this.package, this.source, this.description, this.version) { |
| 265 if (source == null) throw "null source"; | 266 if (source == null) throw "null source"; |
| 266 } | 267 } |
| 267 | 268 |
| 268 Future process(VersionSolver solver) { | 269 Future process(VersionSolver solver) { |
| 270 log.fine("Changing $package to version $version."); | |
| 271 | |
| 269 var dependency = solver.getDependency(package); | 272 var dependency = solver.getDependency(package); |
| 270 var oldVersion = dependency.version; | 273 var oldVersion = dependency.version; |
| 271 solver.setVersion(package, version); | 274 solver.setVersion(package, version); |
| 272 | 275 |
| 273 // The dependencies between the old and new version may be different. Walk | 276 // The dependencies between the old and new version may be different. Walk |
| 274 // them both and update any constraints that differ between the two. | 277 // them both and update any constraints that differ between the two. |
| 275 return Futures.wait([ | 278 return Futures.wait([ |
| 276 getDependencyRefs(solver, oldVersion), | 279 getDependencyRefs(solver, oldVersion), |
| 277 getDependencyRefs(solver, version)]).transform((list) { | 280 getDependencyRefs(solver, version)]).transform((list) { |
| 278 var oldDependencyRefs = list[0]; | 281 var oldDependencyRefs = list[0]; |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 410 /** | 413 /** |
| 411 * The package being depended on and the constraints being placed on it. The | 414 * The package being depended on and the constraints being placed on it. The |
| 412 * source, version, and description in this ref are all considered constraints | 415 * source, version, and description in this ref are all considered constraints |
| 413 * on the dependent package. | 416 * on the dependent package. |
| 414 */ | 417 */ |
| 415 final PackageRef ref; | 418 final PackageRef ref; |
| 416 | 419 |
| 417 AddConstraint(this.depender, this.ref); | 420 AddConstraint(this.depender, this.ref); |
| 418 | 421 |
| 419 Future process(VersionSolver solver) { | 422 Future process(VersionSolver solver) { |
| 423 log.fine("Adding $depender's constraint $ref."); | |
| 424 | |
| 420 var dependency = solver.getDependency(ref.name); | 425 var dependency = solver.getDependency(ref.name); |
| 421 var oldDependency = dependency.clone(); | 426 var oldDependency = dependency.clone(); |
| 422 dependency.placeConstraint(depender, ref); | 427 dependency.placeConstraint(depender, ref); |
| 423 return _processChange(solver, oldDependency, dependency); | 428 return _processChange(solver, oldDependency, dependency); |
| 424 } | 429 } |
| 425 | 430 |
| 426 void undo(VersionSolver solver) { | 431 void undo(VersionSolver solver) { |
| 427 solver.getDependency(ref.name).removeConstraint(depender); | 432 solver.getDependency(ref.name).removeConstraint(depender); |
| 428 } | 433 } |
| 429 } | 434 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 441 * The package that was being depended on. | 446 * The package that was being depended on. |
| 442 */ | 447 */ |
| 443 String dependent; | 448 String dependent; |
| 444 | 449 |
| 445 /** The constraint that was removed. */ | 450 /** The constraint that was removed. */ |
| 446 PackageRef _removed; | 451 PackageRef _removed; |
| 447 | 452 |
| 448 RemoveConstraint(this.depender, this.dependent); | 453 RemoveConstraint(this.depender, this.dependent); |
| 449 | 454 |
| 450 Future process(VersionSolver solver) { | 455 Future process(VersionSolver solver) { |
| 456 log.fine("Removing $depender's constraint on $dependent."); | |
|
nweiz
2012/12/05 23:56:54
Log what the removed constraint was.
Bob Nystrom
2012/12/06 01:33:26
Done.
| |
| 457 | |
| 451 var dependency = solver.getDependency(dependent); | 458 var dependency = solver.getDependency(dependent); |
| 452 var oldDependency = dependency.clone(); | 459 var oldDependency = dependency.clone(); |
| 453 _removed = dependency.removeConstraint(depender); | 460 _removed = dependency.removeConstraint(depender); |
| 454 return _processChange(solver, oldDependency, dependency); | 461 return _processChange(solver, oldDependency, dependency); |
| 455 } | 462 } |
| 456 | 463 |
| 457 void undo(VersionSolver solver) { | 464 void undo(VersionSolver solver) { |
| 458 solver.getDependency(dependent).placeConstraint(depender, _removed); | 465 solver.getDependency(dependent).placeConstraint(depender, _removed); |
| 459 } | 466 } |
| 460 } | 467 } |
| 461 | 468 |
| 462 /** [package]'s version is no longer constrained by the lockfile. */ | 469 /** [package]'s version is no longer constrained by the lockfile. */ |
| 463 class UnlockPackage implements WorkItem { | 470 class UnlockPackage implements WorkItem { |
| 464 /** The package being unlocked. */ | 471 /** The package being unlocked. */ |
| 465 Dependency package; | 472 Dependency package; |
| 466 | 473 |
| 467 UnlockPackage(this.package); | 474 UnlockPackage(this.package); |
| 468 | 475 |
| 469 Future process(VersionSolver solver) { | 476 Future process(VersionSolver solver) { |
| 477 log.fine("Unlocking ${package.name}."); | |
| 478 | |
| 470 solver.lockFile.packages.remove(package.name); | 479 solver.lockFile.packages.remove(package.name); |
| 471 return solver.getBestVersion(package).transform((best) { | 480 return solver.getBestVersion(package).transform((best) { |
| 472 if (best == null) return null; | 481 if (best == null) return null; |
| 473 solver.enqueue(new ChangeVersion( | 482 solver.enqueue(new ChangeVersion( |
| 474 package.name, package.source, package.description, best)); | 483 package.name, package.source, package.description, best)); |
| 475 }); | 484 }); |
| 476 } | 485 } |
| 477 } | 486 } |
| 478 | 487 |
| 479 // TODO(rnystrom): Instead of always pulling from the source (which will mean | 488 // TODO(rnystrom): Instead of always pulling from the source (which will mean |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 724 final description1; | 733 final description1; |
| 725 final description2; | 734 final description2; |
| 726 | 735 |
| 727 DescriptionMismatchException(this.package, this.description1, | 736 DescriptionMismatchException(this.package, this.description1, |
| 728 this.description2); | 737 this.description2); |
| 729 | 738 |
| 730 // TODO(nweiz): Dump to YAML when that's supported | 739 // TODO(nweiz): Dump to YAML when that's supported |
| 731 String toString() => "Package '$package' has conflicting descriptions " | 740 String toString() => "Package '$package' has conflicting descriptions " |
| 732 "'${JSON.stringify(description1)}' and '${JSON.stringify(description2)}'"; | 741 "'${JSON.stringify(description1)}' and '${JSON.stringify(description2)}'"; |
| 733 } | 742 } |
| OLD | NEW |