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 |