| 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 /// A back-tracking depth-first solver. Attempts to find the best solution for | 5 /// A back-tracking depth-first solver. Attempts to find the best solution for |
| 6 /// a root package's transitive dependency graph, where a "solution" is a set | 6 /// a root package's transitive dependency graph, where a "solution" is a set |
| 7 /// of concrete package versions. A valid solution will select concrete | 7 /// of concrete package versions. A valid solution will select concrete |
| 8 /// versions for every package reached from the root package's dependency graph, | 8 /// versions for every package reached from the root package's dependency graph, |
| 9 /// and each of those packages will fit the version constraints placed on it. | 9 /// and each of those packages will fit the version constraints placed on it. |
| 10 /// | 10 /// |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 /// a valid solution has been found or until all possible options for all | 32 /// a valid solution has been found or until all possible options for all |
| 33 /// speculative choices have been exhausted. | 33 /// speculative choices have been exhausted. |
| 34 library version_solver2; | 34 library version_solver2; |
| 35 | 35 |
| 36 import 'dart:async'; | 36 import 'dart:async'; |
| 37 import 'dart:collection' show Queue; | 37 import 'dart:collection' show Queue; |
| 38 | 38 |
| 39 import '../lock_file.dart'; | 39 import '../lock_file.dart'; |
| 40 import '../log.dart' as log; | 40 import '../log.dart' as log; |
| 41 import '../package.dart'; | 41 import '../package.dart'; |
| 42 import '../pubspec.dart'; |
| 43 import '../sdk.dart' as sdk; |
| 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 import 'version_solver.dart'; | 48 import 'version_solver.dart'; |
| 47 | 49 |
| 48 /// The top-level solver. Keeps track of the current potential solution, and | 50 /// The top-level solver. Keeps track of the current potential solution, and |
| 49 /// the other possible versions for speculative package selections. Backtracks | 51 /// the other possible versions for speculative package selections. Backtracks |
| 50 /// and advances to the next potential solution in the case of a failure. | 52 /// and advances to the next potential solution in the case of a failure. |
| 51 class BacktrackingVersionSolver extends VersionSolver { | 53 class BacktrackingVersionSolver extends VersionSolver { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 67 /// | 69 /// |
| 68 /// The solver tries versions in depth-first order, so only the last queue in | 70 /// The solver tries versions in depth-first order, so only the last queue in |
| 69 /// the list will have items removed from it. When a new constraint is placed | 71 /// the list will have items removed from it. When a new constraint is placed |
| 70 /// on an already-selected package, and that constraint doesn't match the | 72 /// on an already-selected package, and that constraint doesn't match the |
| 71 /// selected version, that will cause the current solution to fail and | 73 /// selected version, that will cause the current solution to fail and |
| 72 /// trigger backtracking. | 74 /// trigger backtracking. |
| 73 final _selected = <Queue<PackageId>>[]; | 75 final _selected = <Queue<PackageId>>[]; |
| 74 | 76 |
| 75 /// The number of possible solutions that have been attempted. | 77 /// The number of possible solutions that have been attempted. |
| 76 int get attemptedSolutions => _attemptedSolutions; | 78 int get attemptedSolutions => _attemptedSolutions; |
| 77 var _attemptedSolutions = 0; | 79 var _attemptedSolutions = 1; |
| 78 | 80 |
| 79 BacktrackingVersionSolver(SourceRegistry sources, Package root, | 81 BacktrackingVersionSolver(SourceRegistry sources, Package root, |
| 80 LockFile lockFile, List<String> useLatest) | 82 LockFile lockFile, List<String> useLatest) |
| 81 : super(sources, root, lockFile, useLatest); | 83 : super(sources, root, lockFile, useLatest); |
| 82 | 84 |
| 83 void forceLatestVersion(String package) { | 85 void forceLatestVersion(String package) { |
| 84 _forceLatest.add(package); | 86 _forceLatest.add(package); |
| 85 } | 87 } |
| 86 | 88 |
| 87 Future<List<PackageId>> runSolver() => _traverseSolution(); | 89 Future<List<PackageId>> runSolver() { |
| 90 return new Future.sync(() { |
| 91 _validateSdkConstraint(root.pubspec); |
| 92 return _traverseSolution(); |
| 93 }); |
| 94 } |
| 88 | 95 |
| 89 /// Adds [versions], which is the list of all allowed versions of a given | 96 /// Adds [versions], which is the list of all allowed versions of a given |
| 90 /// package, to the set of versions to consider for solutions. The first item | 97 /// package, to the set of versions to consider for solutions. The first item |
| 91 /// in the list will be the currently selected version of that package. | 98 /// in the list will be the currently selected version of that package. |
| 92 /// Subsequent items will be tried if it the current selection fails. Returns | 99 /// Subsequent items will be tried if it the current selection fails. Returns |
| 93 /// the first selected version. | 100 /// the first selected version. |
| 94 PackageId select(Iterable<PackageId> versions) { | 101 PackageId select(Iterable<PackageId> versions) { |
| 95 _selected.add(new Queue<PackageId>.from(versions)); | 102 _selected.add(new Queue<PackageId>.from(versions)); |
| 96 logSolve(); | 103 logSolve(); |
| 97 return versions.first; | 104 return versions.first; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 115 /// `null` if it isn't in the lockfile (or has been unlocked). | 122 /// `null` if it isn't in the lockfile (or has been unlocked). |
| 116 PackageId getLocked(String package) => lockFile.packages[package]; | 123 PackageId getLocked(String package) => lockFile.packages[package]; |
| 117 | 124 |
| 118 /// Traverses the root package's dependency graph using the current potential | 125 /// Traverses the root package's dependency graph using the current potential |
| 119 /// solution. If successful, completes to the solution. If not, backtracks | 126 /// solution. If successful, completes to the solution. If not, backtracks |
| 120 /// to the most recently selected version of a package and tries the next | 127 /// to the most recently selected version of a package and tries the next |
| 121 /// version of it. If there are no more versions, continues to backtrack to | 128 /// version of it. If there are no more versions, continues to backtrack to |
| 122 /// previous selections, and so on. If there is nothing left to backtrack to, | 129 /// previous selections, and so on. If there is nothing left to backtrack to, |
| 123 /// completes to the last failure that occurred. | 130 /// completes to the last failure that occurred. |
| 124 Future<List<PackageId>> _traverseSolution() { | 131 Future<List<PackageId>> _traverseSolution() { |
| 125 _attemptedSolutions++; | |
| 126 | |
| 127 return new Traverser(this).traverse().catchError((error) { | 132 return new Traverser(this).traverse().catchError((error) { |
| 128 if (error is! SolveFailure) throw error; | 133 if (error is! SolveFailure) throw error; |
| 129 | 134 |
| 130 if (_backtrack(error)) return _traverseSolution(); | 135 if (_backtrack(error)) { |
| 136 _attemptedSolutions++; |
| 137 return _traverseSolution(); |
| 138 } |
| 131 | 139 |
| 132 // All out of solutions, so fail. | 140 // All out of solutions, so fail. |
| 133 throw error; | 141 throw error; |
| 134 }); | 142 }); |
| 135 } | 143 } |
| 136 | 144 |
| 137 /// Backtracks from the current failed solution and determines the next | 145 /// Backtracks from the current failed solution and determines the next |
| 138 /// solution to try. If possible, it will backjump based on the cause of the | 146 /// solution to try. If possible, it will backjump based on the cause of the |
| 139 /// [failure] to minize backtracking. Otherwise, it will simply backtrack to | 147 /// [failure] to minize backtracking. Otherwise, it will simply backtrack to |
| 140 /// the next possible solution. | 148 /// the next possible solution. |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 | 298 |
| 291 var id = _packages.removeFirst(); | 299 var id = _packages.removeFirst(); |
| 292 | 300 |
| 293 // Don't visit the same package twice. | 301 // Don't visit the same package twice. |
| 294 if (_visited.contains(id)) { | 302 if (_visited.contains(id)) { |
| 295 return _traversePackage(); | 303 return _traversePackage(); |
| 296 } | 304 } |
| 297 _visited.add(id); | 305 _visited.add(id); |
| 298 | 306 |
| 299 return _solver.cache.getPubspec(id).then((pubspec) { | 307 return _solver.cache.getPubspec(id).then((pubspec) { |
| 308 _validateSdkConstraint(pubspec); |
| 309 |
| 300 var refs = pubspec.dependencies.toList(); | 310 var refs = pubspec.dependencies.toList(); |
| 301 | 311 |
| 302 // Include dev dependencies of the root package. | 312 // Include dev dependencies of the root package. |
| 303 if (id.isRoot) refs.addAll(pubspec.devDependencies); | 313 if (id.isRoot) refs.addAll(pubspec.devDependencies); |
| 304 | 314 |
| 305 // Given a package ref, returns a future that completes to a pair of the | 315 // Given a package ref, returns a future that completes to a pair of the |
| 306 // ref and the number of versions available for it. | 316 // ref and the number of versions available for it. |
| 307 getNumVersions(PackageRef ref) { | 317 getNumVersions(PackageRef ref) { |
| 308 // There is only ever one version of the root package. | 318 // There is only ever one version of the root package. |
| 309 if (ref.isRoot) { | 319 if (ref.isRoot) { |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 | 537 |
| 528 var required = _getRequired(name); | 538 var required = _getRequired(name); |
| 529 if (required != null) { | 539 if (required != null) { |
| 530 if (package.source.name != required.ref.source.name) return null; | 540 if (package.source.name != required.ref.source.name) return null; |
| 531 if (!package.descriptionEquals(required.ref)) return null; | 541 if (!package.descriptionEquals(required.ref)) return null; |
| 532 } | 542 } |
| 533 | 543 |
| 534 return package; | 544 return package; |
| 535 } | 545 } |
| 536 } | 546 } |
| 547 |
| 548 /// Ensures that if [pubspec] has an SDK constraint, then it is compatible |
| 549 /// with the current SDK. Throws a [SolverFailure] if not. |
| 550 void _validateSdkConstraint(Pubspec pubspec) { |
| 551 if (pubspec.environment.sdkVersion.allows(sdk.version)) return; |
| 552 |
| 553 throw new CouldNotSolveException( |
| 554 'Package ${pubspec.name} requires SDK version ' |
| 555 '${pubspec.environment.sdkVersion} but the current SDK is ' |
| 556 '${sdk.version}.'); |
| 557 } |
| OLD | NEW |