Index: sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart |
diff --git a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart |
index 1944eb0135790b50a5754be5f1553031caaaeff5..d96f1574e834822047737209da20d3131a302552 100644 |
--- a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart |
+++ b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart |
@@ -2,11 +2,13 @@ |
// for details. All rights reserved. Use of this source code is governed by a |
// BSD-style license that can be found in the LICENSE file. |
-/// A back-tracking depth-first solver. Attempts to find the best solution for |
-/// a root package's transitive dependency graph, where a "solution" is a set |
-/// of concrete package versions. A valid solution will select concrete |
-/// versions for every package reached from the root package's dependency graph, |
-/// and each of those packages will fit the version constraints placed on it. |
+/// A back-tracking depth-first solver. |
+/// |
+/// Attempts to find the best solution for a root package's transitive |
+/// dependency graph, where a "solution" is a set of concrete package versions. |
+/// A valid solution will select concrete versions for every package reached |
+/// from the root package's dependency graph, and each of those packages will |
+/// fit the version constraints placed on it. |
/// |
/// The solver builds up a solution incrementally by traversing the dependency |
/// graph starting at the root package. When it reaches a new package, it gets |
@@ -50,9 +52,11 @@ import 'dependency_queue.dart'; |
import 'version_queue.dart'; |
import 'version_solver.dart'; |
-/// The top-level solver. Keeps track of the current potential solution, and |
-/// the other possible versions for speculative package selections. Backtracks |
-/// and advances to the next potential solution in the case of a failure. |
+/// The top-level solver. |
+/// |
+/// Keeps track of the current potential solution, and the other possible |
+/// versions for speculative package selections. Backtracks and advances to the |
+/// next potential solution in the case of a failure. |
class BacktrackingSolver { |
final SourceRegistry sources; |
final Package root; |
@@ -62,8 +66,10 @@ class BacktrackingSolver { |
final PubspecCache cache; |
- /// The set of packages that are being explicitly upgraded. The solver will |
- /// only allow the very latest version for each of these packages. |
+ /// The set of packages that are being explicitly upgraded. |
+ /// |
+ /// The solver will only allow the very latest version for each of these |
+ /// packages. |
final _forceLatest = new Set<String>(); |
/// If this is set, the contents of [lockFile] are ignored while solving. |
@@ -76,6 +82,9 @@ class BacktrackingSolver { |
/// to use the one here. |
final _overrides = new Map<String, PackageDep>(); |
+ /// The package versions currently selected by the solver, along with the |
+ /// versions which are remaining to be tried. |
+ /// |
/// Every time a package is encountered when traversing the dependency graph, |
/// the solver must select a version for it, sometimes when multiple versions |
/// are valid. This keeps track of which versions have been selected so far |
@@ -113,8 +122,10 @@ class BacktrackingSolver { |
} |
} |
- /// Run the solver. Completes with a list of specific package versions if |
- /// successful or an error if it failed to find a solution. |
+ /// Run the solver. |
+ /// |
+ /// Completes with a list of specific package versions if successful or an |
+ /// error if it failed to find a solution. |
Future<SolveResult> solve() { |
var stopwatch = new Stopwatch(); |
@@ -177,10 +188,11 @@ class BacktrackingSolver { |
} |
/// Adds [versions], which is the list of all allowed versions of a given |
- /// package, to the set of versions to consider for solutions. The first item |
- /// in the list will be the currently selected version of that package. |
- /// Subsequent items will be tried if it the current selection fails. Returns |
- /// the first selected version. |
+ /// package, to the set of versions to consider for solutions. |
+ /// |
+ /// The first item in the list will be the currently selected version of that |
+ /// package. Subsequent items will be tried if it the current selection fails. |
+ /// Returns the first selected version. |
PackageId select(VersionQueue versions) { |
_selected.add(versions); |
logSolve(); |
@@ -201,8 +213,9 @@ class BacktrackingSolver { |
return null; |
} |
- /// Gets the version of [package] currently locked in the lock file. Returns |
- /// `null` if it isn't in the lockfile (or has been unlocked). |
+ /// Gets the version of [package] currently locked in the lock file. |
+ /// |
+ /// Returns `null` if it isn't in the lockfile (or has been unlocked). |
PackageId getLocked(String package) { |
if (_upgradeAll) return null; |
if (_forceLatest.contains(package)) return null; |
@@ -211,10 +224,12 @@ class BacktrackingSolver { |
} |
/// Traverses the root package's dependency graph using the current potential |
- /// solution. If successful, completes to the solution. If not, backtracks |
- /// to the most recently selected version of a package and tries the next |
- /// version of it. If there are no more versions, continues to backtrack to |
- /// previous selections, and so on. If there is nothing left to backtrack to, |
+ /// solution. |
+ /// |
+ /// If successful, completes to the solution. If not, backtracks to the most |
+ /// recently selected version of a package and tries the next version of it. |
+ /// If there are no more versions, continues to backtrack to previous |
+ /// selections, and so on. If there is nothing left to backtrack to, |
/// completes to the last failure that occurred. |
Future<List<PackageId>> _traverseSolution() => resetStack(() { |
return new Traverser(this).traverse().catchError((error) { |
@@ -233,9 +248,11 @@ class BacktrackingSolver { |
}); |
/// Backtracks from the current failed solution and determines the next |
- /// solution to try. If possible, it will backjump based on the cause of the |
- /// [failure] to minize backtracking. Otherwise, it will simply backtrack to |
- /// the next possible solution. |
+ /// solution to try. |
+ /// |
+ /// If possible, it will backjump based on the cause of the [failure] to |
+ /// minize backtracking. Otherwise, it will simply backtrack to the next |
+ /// possible solution. |
/// |
/// Returns `true` if there is a new solution to try. |
Future<bool> _backtrack(SolveFailure failure) { |
@@ -278,9 +295,10 @@ class BacktrackingSolver { |
} |
/// Walks the selected packages from most to least recent to determine which |
- /// ones can be ignored and jumped over by the backtracker. The only packages |
- /// we need to backtrack to are ones that led (possibly indirectly) to the |
- /// failure. Everything else can be skipped. |
+ /// ones can be ignored and jumped over by the backtracker. |
+ /// |
+ /// The only packages we need to backtrack to are ones that led (possibly |
+ /// indirectly) to the failure. Everything else can be skipped. |
void _backjump(SolveFailure failure) { |
for (var i = _selected.length - 1; i >= 0; i--) { |
// Each queue will never be empty since it gets discarded by _backtrack() |
@@ -382,8 +400,9 @@ class BacktrackingSolver { |
log.solver(buffer.toString().trim()); |
} |
- /// Logs [message] in the context of the current selected packages. If |
- /// [message] is omitted, just logs a description of leaf-most selection. |
+ /// Logs [message] in the context of the current selected packages. |
+ /// |
+ /// If [message] is omitted, just logs a description of leaf-most selection. |
void logSolve([String message]) { |
if (message == null) { |
if (_selected.isEmpty) { |
@@ -404,26 +423,32 @@ class BacktrackingSolver { |
/// Given the solver's current set of selected package versions, this tries to |
/// traverse the dependency graph and see if a complete set of valid versions |
-/// has been chosen. If it reaches a conflict, it will fail and stop |
-/// traversing. If it reaches a package that isn't selected it will refine the |
-/// solution by adding that package's set of allowed versions to the solver and |
-/// then select the best one and continue. |
+/// has been chosen. |
+/// |
+/// If it reaches a conflict, it fails and stops traversing. If it reaches a |
+/// package that isn't selected, it refines the solution by adding that |
+/// package's set of allowed versions to the solver and then select the best |
+/// one and continuing. |
class Traverser { |
final BacktrackingSolver _solver; |
- /// The queue of packages left to traverse. We do a breadth-first traversal |
- /// using an explicit queue just to avoid the code complexity of a recursive |
- /// asynchronous traversal. |
+ /// The queue of packages left to traverse. |
+ /// |
+ /// We do a breadth-first traversal using an explicit queue just to avoid the |
+ /// code complexity of a recursive asynchronous traversal. |
final _packages = new Queue<PackageId>(); |
- /// The packages we have already traversed. Used to avoid traversing the same |
- /// package multiple times, and to build the complete solution results. |
+ /// The packages we have already traversed. |
+ /// |
+ /// Used to avoid traversing the same package multiple times, and to build |
+ /// the complete solution results. |
final _visited = new Set<PackageId>(); |
- /// The dependencies visited so far in the traversal. For each package name |
- /// (the map key) we track the list of dependencies that other packages have |
- /// placed on it so that we can calculate the complete constraint for shared |
- /// dependencies. |
+ /// The dependencies visited so far in the traversal. |
+ /// |
+ /// For each package name (the map key) we track the list of dependencies |
+ /// that other packages have placed on it so that we can calculate the |
+ /// complete constraint for shared dependencies. |
final _dependencies = <String, List<Dependency>>{}; |
Traverser(this._solver); |
@@ -436,10 +461,11 @@ class Traverser { |
return _traversePackage(); |
} |
- /// Traverses the next package in the queue. Completes to a list of package |
- /// IDs if the traversal completed successfully and found a solution. |
- /// Completes to an error if the traversal failed. Otherwise, recurses to the |
- /// next package in the queue, etc. |
+ /// Traverses the next package in the queue. |
+ /// |
+ /// Completes to a list of package IDs if the traversal completed |
+ /// successfully and found a solution. Completes to an error if the traversal |
+ /// failed. Otherwise, recurses to the next package in the queue, etc. |
Future<List<PackageId>> _traversePackage() { |
if (_packages.isEmpty) { |
// We traversed the whole graph. If we got here, we successfully found |
@@ -603,9 +629,10 @@ class Traverser { |
} |
/// Ensures that dependency [dep] from [depender] is consistent with the |
- /// other dependencies on the same package. Throws a [SolveFailure] |
- /// exception if not. Only validates sources and descriptions, not the |
- /// version. |
+ /// other dependencies on the same package. |
+ /// |
+ /// Throws a [SolveFailure] exception if not. Only validates sources and |
+ /// descriptions, not the version. |
void _validateDependency(PackageDep dep, PackageId depender) { |
// Make sure the dependencies agree on source and description. |
var required = _getRequired(dep.name); |
@@ -630,10 +657,11 @@ class Traverser { |
} |
/// Validates the currently selected package against the new dependency that |
- /// [dep] and [constraint] place on it. Returns `null` if there is no |
- /// currently selected package, throws a [SolveFailure] if the new reference |
- /// it not does not allow the previously selected version, or returns the |
- /// selected package if successful. |
+ /// [dep] and [constraint] place on it. |
+ /// |
+ /// Returns `null` if there is no currently selected package, throws a |
+ /// [SolveFailure] if the new reference it not does not allow the previously |
+ /// selected version, or returns the selected package if successful. |
PackageId _validateSelected(PackageDep dep, VersionConstraint constraint) { |
var selected = _solver.getSelected(dep.name); |
if (selected == null) return null; |
@@ -648,17 +676,19 @@ class Traverser { |
return selected; |
} |
- /// Gets the list of dependencies for package [name]. Will create an empty |
- /// list if needed. |
+ /// Gets the list of dependencies for package [name]. |
+ /// |
+ /// Creates an empty list if needed. |
List<Dependency> _getDependencies(String name) { |
return _dependencies.putIfAbsent(name, () => <Dependency>[]); |
} |
- /// Gets a "required" reference to the package [name]. This is the first |
- /// non-root dependency on that package. All dependencies on a package must |
- /// agree on source and description, except for references to the root |
- /// package. This will return a reference to that "canonical" source and |
- /// description, or `null` if there is no required reference yet. |
+ /// Gets a "required" reference to the package [name]. |
+ /// |
+ /// This is the first non-root dependency on that package. All dependencies |
+ /// on a package must agree on source and description, except for references |
+ /// to the root package. This will return a reference to that "canonical" |
+ /// source and description, or `null` if there is no required reference yet. |
/// |
/// This is required because you may have a circular dependency back onto the |
/// root package. That second dependency won't be a root dependency and it's |
@@ -682,7 +712,9 @@ class Traverser { |
/// Gets the package [name] that's currently contained in the lockfile if it |
/// meets [constraint] and has the same source and description as other |
- /// references to that package. Returns `null` otherwise. |
+ /// references to that package. |
+ /// |
+ /// Returns `null` otherwise. |
PackageId _getValidLocked(String name) { |
var package = _solver.getLocked(name); |
if (package == null) return null; |
@@ -709,7 +741,9 @@ class Traverser { |
} |
/// Ensures that if [pubspec] has an SDK constraint, then it is compatible |
-/// with the current SDK. Throws a [SolveFailure] if not. |
+/// with the current SDK. |
+/// |
+/// Throws a [SolveFailure] if not. |
void _validateSdkConstraint(Pubspec pubspec) { |
if (pubspec.environment.sdkVersion.allows(sdk.version)) return; |