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 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 157 for (var version in versions) { | 157 for (var version in versions) { |
| 158 if (dependency.useLatestVersion || | 158 if (dependency.useLatestVersion || |
| 159 dependency.constraint.allows(version)) { | 159 dependency.constraint.allows(version)) { |
| 160 if (best == null || version > best) best = version; | 160 if (best == null || version > best) best = version; |
| 161 } | 161 } |
| 162 } | 162 } |
| 163 | 163 |
| 164 // TODO(rnystrom): Better exception. | 164 // TODO(rnystrom): Better exception. |
| 165 if (best == null) { | 165 if (best == null) { |
| 166 if (tryUnlockDepender(dependency)) return null; | 166 if (tryUnlockDepender(dependency)) return null; |
| 167 throw new NoVersionException(dependency.name, dependency.constraint); | 167 throw new NoVersionException(dependency.name, dependency.constraint, |
| 168 dependency._refs); | |
| 168 } else if (!dependency.constraint.allows(best)) { | 169 } else if (!dependency.constraint.allows(best)) { |
| 169 if (tryUnlockDepender(dependency)) return null; | 170 if (tryUnlockDepender(dependency)) return null; |
| 170 throw new CouldNotUpdateException( | 171 throw new CouldNotUpdateException( |
| 171 dependency.name, dependency.constraint, best); | 172 dependency.name, dependency.constraint, best); |
| 172 } | 173 } |
| 173 | 174 |
| 174 return best; | 175 return best; |
| 175 }); | 176 }); |
| 176 } | 177 } |
| 177 | 178 |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 | 347 |
| 347 // If the package is over-constrained, i.e. the packages depending have | 348 // If the package is over-constrained, i.e. the packages depending have |
| 348 // disjoint constraints, then try unlocking a depender that's locked by the | 349 // disjoint constraints, then try unlocking a depender that's locked by the |
| 349 // lockfile. If there are no remaining locked dependencies, throw an error. | 350 // lockfile. If there are no remaining locked dependencies, throw an error. |
| 350 if (newConstraint != null && newConstraint.isEmpty) { | 351 if (newConstraint != null && newConstraint.isEmpty) { |
| 351 if (solver.tryUnlockDepender(newDependency)) { | 352 if (solver.tryUnlockDepender(newDependency)) { |
| 352 undo(solver); | 353 undo(solver); |
| 353 return null; | 354 return null; |
| 354 } | 355 } |
| 355 | 356 |
| 356 throw new DisjointConstraintException(name); | 357 throw new DisjointConstraintException(name, newDependency._refs); |
| 357 } | 358 } |
| 358 | 359 |
| 359 // If this constraint change didn't cause the overall constraint on the | 360 // If this constraint change didn't cause the overall constraint on the |
| 360 // package to change, then we don't need to do any further work. | 361 // package to change, then we don't need to do any further work. |
| 361 if (oldConstraint == newConstraint) return null; | 362 if (oldConstraint == newConstraint) return null; |
| 362 | 363 |
| 363 // If the dependency has been cut free from the graph, just remove it. | 364 // If the dependency has been cut free from the graph, just remove it. |
| 364 if (!newDependency.isDependedOn) { | 365 if (!newDependency.isDependedOn) { |
| 365 solver.enqueue(new ChangeVersion(name, source, description, null)); | 366 solver.enqueue(new ChangeVersion(name, source, description, null)); |
| 366 return null; | 367 return null; |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 599 /** Creates a copy of this dependency. */ | 600 /** Creates a copy of this dependency. */ |
| 600 Dependency clone() => new Dependency._clone(this); | 601 Dependency clone() => new Dependency._clone(this); |
| 601 | 602 |
| 602 /// Return a list of available versions for this dependency. | 603 /// Return a list of available versions for this dependency. |
| 603 Future<List<Version>> getVersions() => source.getVersions(name, description); | 604 Future<List<Version>> getVersions() => source.getVersions(name, description); |
| 604 | 605 |
| 605 /** | 606 /** |
| 606 * Places [ref] as a constraint from [package] onto this. | 607 * Places [ref] as a constraint from [package] onto this. |
| 607 */ | 608 */ |
| 608 void placeConstraint(String package, PackageRef ref) { | 609 void placeConstraint(String package, PackageRef ref) { |
| 609 var required = _requiredRef(); | 610 var requiredDepender = _requiredDepender(); |
| 610 if (required != null) { | 611 if (requiredDepender != null) { |
| 612 var required = _refs[requiredDepender]; | |
| 611 if (required.source.name != ref.source.name) { | 613 if (required.source.name != ref.source.name) { |
| 612 throw new SourceMismatchException(name, required.source, ref.source); | 614 throw new SourceMismatchException(name, |
| 615 requiredDepender, required.source, package, ref.source); | |
| 613 } else if (!required.source.descriptionsEqual( | 616 } else if (!required.source.descriptionsEqual( |
| 614 required.description, ref.description)) { | 617 required.description, ref.description)) { |
| 615 throw new DescriptionMismatchException( | 618 throw new DescriptionMismatchException(name, |
| 616 name, required.description, ref.description); | 619 requiredDepender, required.description, package, ref.description); |
| 617 } | 620 } |
| 618 } | 621 } |
| 619 | 622 |
| 620 _refs[package] = ref; | 623 _refs[package] = ref; |
| 621 } | 624 } |
| 622 | 625 |
| 623 /// Returns a PackageRef whose source and description any new constraints are | 626 /// Returns the name of a package whose constraint source and description |
|
nweiz
2012/12/06 00:58:55
"constraint" -> ""?
Bob Nystrom
2012/12/06 17:44:41
It returns the name of the depender, and it's not
nweiz
2012/12/06 19:43:10
Then maybe "constraint's"?
| |
| 624 /// required to match. Returns null if there are no requirements on new | 627 /// all other constraints must match. Returns null if there are no |
| 625 /// constraints. | 628 /// requirements on new constraints. |
| 626 PackageRef _requiredRef() { | 629 String _requiredDepender() { |
| 627 if (_refs.isEmpty) return null; | 630 if (_refs.isEmpty) return null; |
| 628 var refs = _refs.values; | 631 |
| 629 var first = refs[0]; | 632 var dependers = _refs.keys; |
| 630 if (refs.length == 1) { | 633 if (dependers.length == 1) { |
| 631 if (first.source is RootSource) return null; | 634 var depender = dependers[0]; |
| 632 return first; | 635 if (_refs[depender].source is RootSource) return null; |
| 636 return depender; | |
| 633 } | 637 } |
| 634 return refs[1]; | 638 |
| 639 return dependers[1]; | |
| 635 } | 640 } |
| 636 | 641 |
| 637 /** | 642 /** |
| 638 * Removes the constraint from [package] onto this. | 643 * Removes the constraint from [package] onto this. |
| 639 */ | 644 */ |
| 640 PackageRef removeConstraint(String package) => _refs.remove(package); | 645 PackageRef removeConstraint(String package) => _refs.remove(package); |
| 641 } | 646 } |
| 642 | 647 |
| 643 // TODO(rnystrom): Report the last of depending packages and their constraints. | |
| 644 /** | 648 /** |
| 645 * Exception thrown when the [VersionConstraint] used to match a package is | 649 * Exception thrown when the [VersionConstraint] used to match a package is |
| 646 * valid (i.e. non-empty), but there are no released versions of the package | 650 * valid (i.e. non-empty), but there are no released versions of the package |
| 647 * that fit that constraint. | 651 * that fit that constraint. |
| 648 */ | 652 */ |
| 649 class NoVersionException implements Exception { | 653 class NoVersionException implements Exception { |
| 650 final String package; | 654 final String package; |
| 651 final VersionConstraint constraint; | 655 final VersionConstraint constraint; |
| 656 final Map<String, PackageRef> _dependencies; | |
| 652 | 657 |
| 653 NoVersionException(this.package, this.constraint); | 658 NoVersionException(this.package, this.constraint, this._dependencies); |
| 654 | 659 |
| 655 String toString() => | 660 String toString() { |
| 656 "Package '$package' has no versions that match $constraint."; | 661 var buffer = new StringBuffer(); |
| 662 buffer.add("Package '$package' has no versions that match $constraint derive d from:\n"); | |
|
nweiz
2012/12/06 00:58:55
Long line
Bob Nystrom
2012/12/06 17:44:41
Done.
| |
| 663 | |
| 664 var keys = new List.from(_dependencies.keys); | |
| 665 keys.sort(); | |
| 666 | |
| 667 for (var key in keys) { | |
| 668 buffer.add("- '$key' depends on version " | |
| 669 "${_dependencies[key].constraint}\n"); | |
| 670 } | |
| 671 | |
| 672 return buffer.toString(); | |
| 673 } | |
| 657 } | 674 } |
| 658 | 675 |
| 659 // TODO(rnystrom): Report the list of depending packages and their constraints. | 676 // TODO(rnystrom): Report the list of depending packages and their constraints. |
| 660 /** | 677 /** |
| 661 * Exception thrown when the most recent version of [package] must be selected, | 678 * Exception thrown when the most recent version of [package] must be selected, |
| 662 * but doesn't match the [VersionConstraint] imposed on the package. | 679 * but doesn't match the [VersionConstraint] imposed on the package. |
| 663 */ | 680 */ |
| 664 class CouldNotUpdateException implements Exception { | 681 class CouldNotUpdateException implements Exception { |
| 665 final String package; | 682 final String package; |
| 666 final VersionConstraint constraint; | 683 final VersionConstraint constraint; |
| 667 final Version best; | 684 final Version best; |
| 668 | 685 |
| 669 CouldNotUpdateException(this.package, this.constraint, this.best); | 686 CouldNotUpdateException(this.package, this.constraint, this.best); |
| 670 | 687 |
| 671 String toString() => | 688 String toString() => |
| 672 "The latest version of '$package', $best, does not match $constraint."; | 689 "The latest version of '$package', $best, does not match $constraint."; |
| 673 } | 690 } |
| 674 | 691 |
| 675 // TODO(rnystrom): Report the last of depending packages and their constraints. | |
| 676 /** | 692 /** |
| 677 * Exception thrown when the [VersionConstraint] used to match a package is | 693 * Exception thrown when the [VersionConstraint] used to match a package is |
| 678 * the empty set: in other words, multiple packages depend on it and have | 694 * the empty set: in other words, multiple packages depend on it and have |
| 679 * conflicting constraints that have no overlap. | 695 * conflicting constraints that have no overlap. |
| 680 */ | 696 */ |
| 681 class DisjointConstraintException implements Exception { | 697 class DisjointConstraintException implements Exception { |
| 682 final String package; | 698 final String package; |
| 699 final Map<String, PackageRef> _dependencies; | |
| 683 | 700 |
| 684 DisjointConstraintException(this.package); | 701 DisjointConstraintException(this.package, this._dependencies); |
| 685 | 702 |
| 686 String toString() => | 703 String toString() { |
| 687 "Package '$package' has disjoint constraints."; | 704 var buffer = new StringBuffer(); |
| 705 buffer.add("Shared dependency version conflict on '$package':\n"); | |
|
nweiz
2012/12/06 00:58:55
I don't think "shared dependency version conflict"
Bob Nystrom
2012/12/06 17:44:41
Done.
| |
| 706 | |
| 707 var keys = new List.from(_dependencies.keys); | |
| 708 keys.sort(); | |
| 709 | |
| 710 for (var key in keys) { | |
| 711 buffer.add("- '$key' depends on version " | |
| 712 "${_dependencies[key].constraint}\n"); | |
| 713 } | |
| 714 | |
| 715 return buffer.toString(); | |
| 716 } | |
| 688 } | 717 } |
| 689 | 718 |
| 690 /** | 719 /** |
| 691 * Exception thrown when the [VersionSolver] fails to find a solution after a | 720 * Exception thrown when the [VersionSolver] fails to find a solution after a |
| 692 * certain number of iterations. | 721 * certain number of iterations. |
| 693 */ | 722 */ |
| 694 class CouldNotSolveException implements Exception { | 723 class CouldNotSolveException implements Exception { |
| 695 CouldNotSolveException(); | 724 CouldNotSolveException(); |
| 696 | 725 |
| 697 String toString() => | 726 String toString() => |
| 698 "Could not find a solution that met all version constraints."; | 727 "Could not find a solution that met all version constraints."; |
| 699 } | 728 } |
| 700 | 729 |
| 701 /** | 730 /** |
| 702 * Exception thrown when two packages with the same name but different sources | 731 * Exception thrown when two packages with the same name but different sources |
| 703 * are depended upon. | 732 * are depended upon. |
| 704 */ | 733 */ |
| 705 class SourceMismatchException implements Exception { | 734 class SourceMismatchException implements Exception { |
| 706 final String package; | 735 final String package; |
| 736 final String depender1; | |
| 707 final Source source1; | 737 final Source source1; |
| 738 final String depender2; | |
| 708 final Source source2; | 739 final Source source2; |
| 709 | 740 |
| 710 SourceMismatchException(this.package, this.source1, this.source2); | 741 SourceMismatchException(this.package, this.depender1, this.source1, |
| 742 this.depender2, this.source2); | |
| 711 | 743 |
| 712 String toString() { | 744 String toString() { |
| 713 return "Package '$package' is depended on from both sources " | 745 return "Shared dependency conflict on '$package':\n" |
| 714 "'${source1.name}' and '${source2.name}'."; | 746 "- '$depender1' depends on it from source '$source1'\n" |
| 747 "- '$depender2' depends on it from source '$source2'"; | |
| 715 } | 748 } |
| 716 } | 749 } |
| 717 | 750 |
| 718 /** | 751 /** |
| 719 * Exception thrown when two packages with the same name and source but | 752 * Exception thrown when two packages with the same name and source but |
| 720 * different descriptions are depended upon. | 753 * different descriptions are depended upon. |
| 721 */ | 754 */ |
| 722 class DescriptionMismatchException implements Exception { | 755 class DescriptionMismatchException implements Exception { |
| 723 final String package; | 756 final String package; |
| 757 final String depender1; | |
| 724 final description1; | 758 final description1; |
| 759 final String depender2; | |
| 725 final description2; | 760 final description2; |
| 726 | 761 |
| 727 DescriptionMismatchException(this.package, this.description1, | 762 DescriptionMismatchException(this.package, this.depender1, this.description1, |
| 728 this.description2); | 763 this.depender2, this.description2); |
| 729 | 764 |
| 730 // TODO(nweiz): Dump to YAML when that's supported | 765 String toString() { |
| 731 String toString() => "Package '$package' has conflicting descriptions " | 766 // TODO(nweiz): Dump descriptions to YAML when that's supported. |
| 732 "'${JSON.stringify(description1)}' and '${JSON.stringify(description2)}'"; | 767 return "Shared dependency conflict on '$package':\n" |
| 768 "- '$depender1' depends on it with description " | |
| 769 "${JSON.stringify(description1)}\n" | |
| 770 "- '$depender2' depends on it with description " | |
| 771 "${JSON.stringify(description2)}"; | |
| 772 } | |
| 733 } | 773 } |
| OLD | NEW |