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 /// 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 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 /// Backtracks from the current failed solution and determines the next | 185 /// Backtracks from the current failed solution and determines the next |
| 186 /// solution to try. If possible, it will backjump based on the cause of the | 186 /// solution to try. If possible, it will backjump based on the cause of the |
| 187 /// [failure] to minize backtracking. Otherwise, it will simply backtrack to | 187 /// [failure] to minize backtracking. Otherwise, it will simply backtrack to |
| 188 /// the next possible solution. | 188 /// the next possible solution. |
| 189 /// | 189 /// |
| 190 /// Returns `true` if there is a new solution to try. | 190 /// Returns `true` if there is a new solution to try. |
| 191 bool _backtrack(SolveFailure failure) { | 191 bool _backtrack(SolveFailure failure) { |
| 192 var dependers = failure.dependencies.map((dep) => dep.depender).toSet(); | 192 var dependers = failure.dependencies.map((dep) => dep.depender).toSet(); |
| 193 | 193 |
| 194 while (!_selected.isEmpty) { | 194 while (!_selected.isEmpty) { |
| 195 // Look for a relevant selection to jump back to. | 195 _backjump(failure); |
| 196 for (var i = _selected.length - 1; i >= 0; i--) { | |
| 197 // Can't jump to a package that has no more alternatives. | |
| 198 if (_selected[i].length == 1) continue; | |
| 199 | |
| 200 var selected = _selected[i].first; | |
| 201 | |
| 202 // If we find the package itself that failed, jump to it. | |
| 203 if (selected.name == failure.package) { | |
| 204 logSolve('jump to selected package ${failure.package}'); | |
| 205 _selected.removeRange(i + 1, _selected.length); | |
| 206 break; | |
| 207 } | |
| 208 | |
| 209 // See if this package directly or indirectly depends on [package]. | |
| 210 var path = _getDependencyPath(selected, failure.package); | |
| 211 if (path != null) { | |
| 212 logSolve('backjump to ${selected.name} because it depends on ' | |
| 213 '${failure.package} by $path'); | |
| 214 _selected.removeRange(i + 1, _selected.length); | |
| 215 break; | |
| 216 } | |
| 217 } | |
| 218 | 196 |
| 219 // Advance past the current version of the leaf-most package. | 197 // Advance past the current version of the leaf-most package. |
| 220 var previous = _selected.last.removeFirst(); | 198 var previous = _selected.last.removeFirst(); |
| 221 if (!_selected.last.isEmpty) { | 199 if (!_selected.last.isEmpty) { |
| 222 logSolve(); | 200 logSolve(); |
| 223 return true; | 201 return true; |
| 224 } | 202 } |
| 225 | 203 |
| 226 logSolve('$previous is last version, backtracking'); | 204 logSolve('$previous is last version, backtracking'); |
| 227 | 205 |
| 228 // That package has no more versions, so pop it and try the next one. | 206 // That package has no more versions, so pop it and try the next one. |
| 229 _selected.removeLast(); | 207 _selected.removeLast(); |
| 230 } | 208 } |
| 231 | 209 |
| 232 return false; | 210 return false; |
| 233 } | 211 } |
| 234 | 212 |
| 213 /// Walks the selected packages from most to least recent to determine which | |
| 214 /// ones can be ignored and jumped over by the backtracker. The only packages | |
| 215 /// we need to backtrack to are ones that have other versions to try and that | |
| 216 /// led (possibly indirectly) to the failure. Everything else can be skipped. | |
| 217 void _backjump(SolveFailure failure) { | |
| 218 for (var i = _selected.length - 1; i >= 0; i--) { | |
| 219 var selected = _selected[i].first; | |
|
nweiz
2013/05/01 01:17:52
Might be nice to add a comment or assertion here e
Bob Nystrom
2013/05/01 01:38:57
Done.
| |
| 220 | |
| 221 // If the package has no more versions, we can jump over it. | |
| 222 if (_selected[i].length == 1) continue; | |
| 223 | |
| 224 // If we get to the package that failed, stop there. | |
| 225 if (selected.name == failure.package) { | |
| 226 logSolve('backjump to failed package ${selected.name}'); | |
| 227 _selected.removeRange(i + 1, _selected.length); | |
| 228 return; | |
| 229 } | |
| 230 | |
| 231 // If we get to a package that depends on the failing package, try stop | |
| 232 // there. | |
| 233 var path = _getDependencyPath(selected, failure.package); | |
| 234 if (path != null) { | |
| 235 logSolve('backjump to ${selected.name} because it depends on ' | |
| 236 '${failure.package} along $path'); | |
| 237 _selected.removeRange(i + 1, _selected.length); | |
| 238 return; | |
| 239 } | |
| 240 } | |
| 241 | |
| 242 // If we got here, every selection can be jumped over (except for the first | |
| 243 // root package one). | |
| 244 _selected.removeRange(1, _selected.length); | |
|
nweiz
2013/05/01 01:17:52
I'm not 100% clear what's going on here. How did w
Bob Nystrom
2013/05/01 01:38:57
Added some comments.
| |
| 245 } | |
| 246 | |
| 235 /// Determines if [depender] has a direct or indirect dependency on | 247 /// Determines if [depender] has a direct or indirect dependency on |
| 236 /// [dependent] based on the currently selected versions of all packages. | 248 /// [dependent] based on the currently selected versions of all packages. |
| 237 /// Returns a string describing the dependency chain if it does, or `null` if | 249 /// Returns a string describing the dependency chain if it does, or `null` if |
| 238 /// there is no dependency. | 250 /// there is no dependency. |
| 239 String _getDependencyPath(PackageId depender, String dependent) { | 251 String _getDependencyPath(PackageId depender, String dependent) { |
| 240 // TODO(rnystrom): This is O(n^2) where n is the number of selected | 252 // TODO(rnystrom): This is O(n^2) where n is the number of selected |
| 241 // packages. Could store the reverse dependency graph to address that. If | 253 // packages. Could store the reverse dependency graph to address that. If |
| 242 // we do that, we need to make sure it gets correctly rolled back when | 254 // we do that, we need to make sure it gets correctly rolled back when |
| 243 // backtracking occurs. | 255 // backtracking occurs. |
| 244 var visited = new Set<String>(); | 256 var visited = new Set<String>(); |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 587 /// with the current SDK. Throws a [SolverFailure] if not. | 599 /// with the current SDK. Throws a [SolverFailure] if not. |
| 588 void _validateSdkConstraint(Pubspec pubspec) { | 600 void _validateSdkConstraint(Pubspec pubspec) { |
| 589 // If the user is running a continouous build of the SDK, just disable SDK | 601 // If the user is running a continouous build of the SDK, just disable SDK |
| 590 // constraint checking entirely. The actual version number you get is | 602 // constraint checking entirely. The actual version number you get is |
| 591 // impossibly old and not correct. We'll just assume users on continuous | 603 // impossibly old and not correct. We'll just assume users on continuous |
| 592 // know what they're doing. | 604 // know what they're doing. |
| 593 if (sdk.isBleedingEdge) return; | 605 if (sdk.isBleedingEdge) return; |
| 594 | 606 |
| 595 if (pubspec.environment.sdkVersion.allows(sdk.version)) return; | 607 if (pubspec.environment.sdkVersion.allows(sdk.version)) return; |
| 596 | 608 |
| 597 throw new CouldNotSolveException( | 609 throw new BadSdkVersionException(pubspec.name, |
| 598 'Package ${pubspec.name} requires SDK version ' | 610 'Package ${pubspec.name} requires SDK version ' |
| 599 '${pubspec.environment.sdkVersion} but the current SDK is ' | 611 '${pubspec.environment.sdkVersion} but the current SDK is ' |
| 600 '${sdk.version}.'); | 612 '${sdk.version}.'); |
| 601 } | 613 } |
| OLD | NEW |