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 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 // Look for a relevant selection to jump back to. |
196 for (var i = _selected.length - 1; i >= 0; i--) { | 196 if (failure.mayHaveTransitiveCause) { |
nweiz
2013/04/30 22:00:29
I don't understand this distinction. Why can't sou
Bob Nystrom
2013/05/01 01:06:15
After putting on my thinking cap, I've got a clean
| |
197 // Can't jump to a package that has no more alternatives. | 197 _backjumpToDependency(failure.package); |
198 if (_selected[i].length == 1) continue; | 198 } else { |
199 | 199 _backjumpToPackage(failure.dependencies); |
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 } | 200 } |
218 | 201 |
219 // Advance past the current version of the leaf-most package. | 202 // Advance past the current version of the leaf-most package. |
220 var previous = _selected.last.removeFirst(); | 203 var previous = _selected.last.removeFirst(); |
221 if (!_selected.last.isEmpty) { | 204 if (!_selected.last.isEmpty) { |
222 logSolve(); | 205 logSolve(); |
223 return true; | 206 return true; |
224 } | 207 } |
225 | 208 |
226 logSolve('$previous is last version, backtracking'); | 209 logSolve('$previous is last version, backtracking'); |
227 | 210 |
228 // That package has no more versions, so pop it and try the next one. | 211 // That package has no more versions, so pop it and try the next one. |
229 _selected.removeLast(); | 212 _selected.removeLast(); |
230 } | 213 } |
231 | 214 |
232 return false; | 215 return false; |
233 } | 216 } |
234 | 217 |
218 /// Backjumps to the most recently selected package in [dependencies]. Does | |
219 /// not consider dependent or related packages. This is used for failures | |
220 /// like [SourceMismatchException] where one of the packages explicitly in | |
221 /// that list is known to be a direct cause of the failure. | |
222 void _backjumpToPackage(Iterable<Dependency> dependencies) { | |
223 for (var i = _selected.length - 1; i >= 0; i--) { | |
224 var selected = _selected[i].first; | |
225 | |
226 for (var dep in dependencies) { | |
227 if (selected.name == dep.dep.name) { | |
228 logSolve('backjump to ${selected.name} because it caused conflict'); | |
229 _selected.removeRange(i + 1, _selected.length); | |
230 return; | |
231 } | |
232 } | |
233 } | |
234 } | |
235 | |
236 /// Backjumps to the most recently selected package that directly or | |
237 /// indirectly depends on [package]. This is used for failures like | |
238 /// [NoVersionException] where we failed to find a version for [package] and | |
239 /// any package along the dependency graph leading to it could have caused | |
240 /// that failure. | |
241 void _backjumpToDependency(String package) { | |
242 for (var i = _selected.length - 1; i >= 0; i--) { | |
243 // Can't jump to a package that has no more alternatives. | |
244 if (_selected[i].length == 1) continue; | |
245 | |
246 var selected = _selected[i].first; | |
247 | |
248 // See if this package directly or indirectly depends on [package]. | |
249 var path = _getDependencyPath(selected, package); | |
250 if (path != null) { | |
251 logSolve('backjump to ${selected.name} because it depends on ' | |
252 '${package} by $path'); | |
nweiz
2013/04/30 22:00:29
indentation
Bob Nystrom
2013/05/01 01:06:15
Done.
| |
253 _selected.removeRange(i + 1, _selected.length); | |
254 return; | |
255 } | |
256 } | |
257 } | |
258 | |
235 /// Determines if [depender] has a direct or indirect dependency on | 259 /// Determines if [depender] has a direct or indirect dependency on |
236 /// [dependent] based on the currently selected versions of all packages. | 260 /// [dependent] based on the currently selected versions of all packages. |
237 /// Returns a string describing the dependency chain if it does, or `null` if | 261 /// Returns a string describing the dependency chain if it does, or `null` if |
238 /// there is no dependency. | 262 /// there is no dependency. |
239 String _getDependencyPath(PackageId depender, String dependent) { | 263 String _getDependencyPath(PackageId depender, String dependent) { |
240 // TODO(rnystrom): This is O(n^2) where n is the number of selected | 264 // 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 | 265 // 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 | 266 // we do that, we need to make sure it gets correctly rolled back when |
243 // backtracking occurs. | 267 // backtracking occurs. |
244 var visited = new Set<String>(); | 268 var visited = new Set<String>(); |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
592 // know what they're doing. | 616 // know what they're doing. |
593 if (sdk.isBleedingEdge) return; | 617 if (sdk.isBleedingEdge) return; |
594 | 618 |
595 if (pubspec.environment.sdkVersion.allows(sdk.version)) return; | 619 if (pubspec.environment.sdkVersion.allows(sdk.version)) return; |
596 | 620 |
597 throw new CouldNotSolveException( | 621 throw new CouldNotSolveException( |
598 'Package ${pubspec.name} requires SDK version ' | 622 'Package ${pubspec.name} requires SDK version ' |
599 '${pubspec.environment.sdkVersion} but the current SDK is ' | 623 '${pubspec.environment.sdkVersion} but the current SDK is ' |
600 '${sdk.version}.'); | 624 '${sdk.version}.'); |
601 } | 625 } |
OLD | NEW |