Index: utils/pub/version_solver.dart |
diff --git a/utils/pub/version_solver.dart b/utils/pub/version_solver.dart |
index 1a84aa255bd0ba2a14adf6323e2c84823df893d5..a4b70f89a0c4c208d1d5cc888ca3814cc4b2899b 100644 |
--- a/utils/pub/version_solver.dart |
+++ b/utils/pub/version_solver.dart |
@@ -2,39 +2,37 @@ |
// 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. |
-/** |
- * Attempts to resolve a set of version constraints for a package dependency |
- * graph and select an appropriate set of best specific versions for all |
- * dependent packages. It works iteratively and tries to reach a stable |
- * solution where the constraints of all dependencies are met. If it fails to |
- * reach a solution after a certain number of iterations, it assumes the |
- * dependency graph is unstable and reports and error. |
- * |
- * There are two fundamental operations in the process of iterating over the |
- * graph: |
- * |
- * 1. Changing the selected concrete version of some package. (This includes |
- * adding and removing a package too, which is considering changing the |
- * version to or from "none".) In other words, a node has changed. |
- * 2. Changing the version constraint that one package places on another. In |
- * other words, and edge has changed. |
- * |
- * Both of these events have a corresponding (potentional) async operation and |
- * roughly cycle back and forth between each other. When we change the version |
- * of package changes, we asynchronously load the pubspec for the new version. |
- * When that's done, we compare the dependencies of the new version versus the |
- * old one. For everything that differs, we change those constraints between |
- * this package and that dependency. |
- * |
- * When a constraint on a package changes, we re-calculate the overall |
- * constraint on that package. I.e. with a shared dependency, we intersect all |
- * of the constraints that its depending packages place on it. If that overall |
- * constraint changes (say from "<3.0.0" to "<2.5.0"), then the currently |
- * picked version for that package may fall outside of the new constraint. If |
- * that happens, we find the new best version that meets the updated constraint |
- * and then the change the package to use that version. That cycles back up to |
- * the beginning again. |
- */ |
+/// Attempts to resolve a set of version constraints for a package dependency |
+/// graph and select an appropriate set of best specific versions for all |
+/// dependent packages. It works iteratively and tries to reach a stable |
+/// solution where the constraints of all dependencies are met. If it fails to |
+/// reach a solution after a certain number of iterations, it assumes the |
+/// dependency graph is unstable and reports and error. |
+/// |
+/// There are two fundamental operations in the process of iterating over the |
+/// graph: |
+/// |
+/// 1. Changing the selected concrete version of some package. (This includes |
+/// adding and removing a package too, which is considering changing the |
+/// version to or from "none".) In other words, a node has changed. |
+/// 2. Changing the version constraint that one package places on another. In |
+/// other words, and edge has changed. |
+/// |
+/// Both of these events have a corresponding (potentional) async operation and |
+/// roughly cycle back and forth between each other. When we change the version |
+/// of package changes, we asynchronously load the pubspec for the new version. |
+/// When that's done, we compare the dependencies of the new version versus the |
+/// old one. For everything that differs, we change those constraints between |
+/// this package and that dependency. |
+/// |
+/// When a constraint on a package changes, we re-calculate the overall |
+/// constraint on that package. I.e. with a shared dependency, we intersect all |
+/// of the constraints that its depending packages place on it. If that overall |
+/// constraint changes (say from "<3.0.0" to "<2.5.0"), then the currently |
+/// picked version for that package may fall outside of the new constraint. If |
+/// that happens, we find the new best version that meets the updated constraint |
+/// and then the change the package to use that version. That cycles back up to |
+/// the beginning again. |
library version_solver; |
import 'dart:json'; |
@@ -49,15 +47,13 @@ import 'source_registry.dart'; |
import 'utils.dart'; |
import 'version.dart'; |
-/** |
- * Attempts to select the best concrete versions for all of the transitive |
- * dependencies of [root] taking into account all of the [VersionConstraint]s |
- * that those dependencies place on each other and the requirements imposed by |
- * [lockFile]. If successful, completes to a [Map] that maps package names to |
- * the selected version for that package. If it fails, the future will complete |
- * with a [NoVersionException], [DisjointConstraintException], or |
- * [CouldNotSolveException]. |
- */ |
+/// Attempts to select the best concrete versions for all of the transitive |
+/// dependencies of [root] taking into account all of the [VersionConstraint]s |
+/// that those dependencies place on each other and the requirements imposed by |
+/// [lockFile]. If successful, completes to a [Map] that maps package names to |
+/// the selected version for that package. If it fails, the future will complete |
+/// with a [NoVersionException], [DisjointConstraintException], or |
+/// [CouldNotSolveException]. |
Future<List<PackageId>> resolveVersions(SourceRegistry sources, Package root, |
LockFile lockFile) { |
log.message('Resolving dependencies...'); |
@@ -79,12 +75,10 @@ class VersionSolver { |
_packages = <String, Dependency>{}, |
_work = new Queue<WorkItem>(); |
- /** |
- * Tell the version solver to use the most recent version of [package] that |
- * exists in whatever source it's installed from. If that version violates |
- * constraints imposed by other dependencies, an error will be raised when |
- * solving the versions, even if an earlier compatible version exists. |
- */ |
+ /// Tell the version solver to use the most recent version of [package] that |
+ /// exists in whatever source it's installed from. If that version violates |
+ /// constraints imposed by other dependencies, an error will be raised when |
+ /// solving the versions, even if an earlier compatible version exists. |
void useLatestVersion(String package) { |
// TODO(nweiz): How do we want to detect and handle unknown dependencies |
// here? |
@@ -141,17 +135,13 @@ class VersionSolver { |
return _packages[package]; |
} |
- /** |
- * Sets the best selected version of [package] to [version]. |
- */ |
+ /// Sets the best selected version of [package] to [version]. |
void setVersion(String package, Version version) { |
_packages[package].version = version; |
} |
- /** |
- * Returns the most recent version of [dependency] that satisfies all of its |
- * version constraints. |
- */ |
+ /// Returns the most recent version of [dependency] that satisfies all of its |
+ /// version constraints. |
Future<Version> getBestVersion(Dependency dependency) { |
return dependency.getVersions().transform((versions) { |
var best = null; |
@@ -177,15 +167,13 @@ class VersionSolver { |
}); |
} |
- /** |
- * Looks for a package that depends (transitively) on [dependency] and has its |
- * version locked in the lockfile. If one is found, enqueues an |
- * [UnlockPackage] work item for it and returns true. Otherwise, returns |
- * false. |
- * |
- * This does a breadth-first search; immediate dependers will be unlocked |
- * first, followed by transitive dependers. |
- */ |
+ /// Looks for a package that depends (transitively) on [dependency] and has |
+ /// its version locked in the lockfile. If one is found, enqueues an |
+ /// [UnlockPackage] work item for it and returns true. Otherwise, returns |
+ /// false. |
+ /// |
+ /// This does a breadth-first search; immediate dependers will be unlocked |
+ /// first, followed by transitive dependers. |
bool tryUnlockDepender(Dependency dependency, [Set<String> seen]) { |
if (seen == null) seen = new Set(); |
// Avoid an infinite loop if there are circular dependencies. |
@@ -224,43 +212,31 @@ class VersionSolver { |
} |
} |
-/** |
- * The constraint solver works by iteratively processing a queue of work items. |
- * Each item is a single atomic change to the dependency graph. Handling them |
- * in a queue lets us handle asynchrony (resolving versions requires information |
- * from servers) as well as avoid deeply nested recursion. |
-*/ |
+/// The constraint solver works by iteratively processing a queue of work items. |
+/// Each item is a single atomic change to the dependency graph. Handling them |
+/// in a queue lets us handle asynchrony (resolving versions requires |
+/// information from servers) as well as avoid deeply nested recursion. |
abstract class WorkItem { |
- /** |
- * Processes this work item. Returns a future that completes when the work is |
- * done. If `null` is returned, that means the work has completed |
- * synchronously and the next item can be started immediately. |
- */ |
+ /// Processes this work item. Returns a future that completes when the work is |
+ /// done. If `null` is returned, that means the work has completed |
+ /// synchronously and the next item can be started immediately. |
Future process(VersionSolver solver); |
} |
-/** |
- * The best selected version for a package has changed to [version]. If the |
- * previous version of the package is `null`, that means the package is being |
- * added to the graph. If [version] is `null`, it is being removed. |
- */ |
+/// The best selected version for a package has changed to [version]. If the |
+/// previous version of the package is `null`, that means the package is being |
+/// added to the graph. If [version] is `null`, it is being removed. |
class ChangeVersion implements WorkItem { |
/// The name of the package whose version is being changed. |
final String package; |
- /** |
- * The source of the package whose version is changing. |
- */ |
+ /// The source of the package whose version is changing. |
final Source source; |
- /** |
- * The description identifying the package whose version is changing. |
- */ |
+ /// The description identifying the package whose version is changing. |
final description; |
- /** |
- * The new selected version. |
- */ |
+ /// The new selected version. |
final Version version; |
ChangeVersion(this.package, this.source, this.description, this.version) { |
@@ -303,9 +279,7 @@ class ChangeVersion implements WorkItem { |
}); |
} |
- /** |
- * Get the dependencies at [version] of the package being changed. |
- */ |
+ /// Get the dependencies at [version] of the package being changed. |
Future<Map<String, PackageRef>> getDependencyRefs(VersionSolver solver, |
Version version) { |
// If there is no version, it means no package, so no dependencies. |
@@ -325,14 +299,12 @@ class ChangeVersion implements WorkItem { |
} |
} |
-/** |
- * A constraint that a depending package places on a dependent package has |
- * changed. |
- * |
- * This is an abstract class that contains logic for updating the dependency |
- * graph once a dependency has changed. Changing the dependency is the |
- * responsibility of subclasses. |
- */ |
+/// A constraint that a depending package places on a dependent package has |
+/// changed. |
+/// |
+/// This is an abstract class that contains logic for updating the dependency |
+/// graph once a dependency has changed. Changing the dependency is the |
+/// responsibility of subclasses. |
abstract class ChangeConstraint implements WorkItem { |
Future process(VersionSolver solver); |
@@ -402,20 +374,14 @@ abstract class ChangeConstraint implements WorkItem { |
} |
} |
-/** |
- * The constraint given by [ref] is being placed by [depender]. |
- */ |
+/// The constraint given by [ref] is being placed by [depender]. |
class AddConstraint extends ChangeConstraint { |
- /** |
- * The package that has the dependency. |
- */ |
+ /// The package that has the dependency. |
final String depender; |
- /** |
- * The package being depended on and the constraints being placed on it. The |
- * source, version, and description in this ref are all considered constraints |
- * on the dependent package. |
- */ |
+ /// The package being depended on and the constraints being placed on it. The |
+ /// source, version, and description in this ref are all considered |
+ /// constraints on the dependent package. |
final PackageRef ref; |
AddConstraint(this.depender, this.ref); |
@@ -434,21 +400,15 @@ class AddConstraint extends ChangeConstraint { |
} |
} |
-/** |
- * [depender] is no longer placing a constraint on [dependent]. |
- */ |
+/// [depender] is no longer placing a constraint on [dependent]. |
class RemoveConstraint extends ChangeConstraint { |
- /** |
- * The package that was placing a constraint on [dependent]. |
- */ |
+ /// The package that was placing a constraint on [dependent]. |
String depender; |
- /** |
- * The package that was being depended on. |
- */ |
+ /// The package that was being depended on. |
String dependent; |
- /** The constraint that was removed. */ |
+ /// The constraint that was removed. |
PackageRef _removed; |
RemoveConstraint(this.depender, this.dependent); |
@@ -467,9 +427,9 @@ class RemoveConstraint extends ChangeConstraint { |
} |
} |
-/** [package]'s version is no longer constrained by the lockfile. */ |
+/// [package]'s version is no longer constrained by the lockfile. |
class UnlockPackage implements WorkItem { |
- /** The package being unlocked. */ |
+ /// The package being unlocked. |
Dependency package; |
UnlockPackage(this.package); |
@@ -489,10 +449,8 @@ class UnlockPackage implements WorkItem { |
// TODO(rnystrom): Instead of always pulling from the source (which will mean |
// hitting a server), we should consider caching pubspecs of uninstalled |
// packages in the system cache. |
-/** |
- * Maintains a cache of previously-loaded pubspecs. Used to avoid requesting |
- * the same pubspec from the server repeatedly. |
- */ |
+/// Maintains a cache of previously-loaded pubspecs. Used to avoid requesting |
+/// the same pubspec from the server repeatedly. |
class PubspecCache { |
final SourceRegistry _sources; |
final Map<PackageId, Pubspec> _pubspecs; |
@@ -500,16 +458,12 @@ class PubspecCache { |
PubspecCache(this._sources) |
: _pubspecs = new Map<PackageId, Pubspec>(); |
- /** |
- * Caches [pubspec] as the [Pubspec] for the package identified by [id]. |
- */ |
+ /// Caches [pubspec] as the [Pubspec] for the package identified by [id]. |
void cache(PackageId id, Pubspec pubspec) { |
_pubspecs[id] = pubspec; |
} |
- /** |
- * Loads the pubspec for the package identified by [id]. |
- */ |
+ /// Loads the pubspec for the package identified by [id]. |
Future<Pubspec> load(PackageId id) { |
// Complete immediately if it's already cached. |
if (_pubspecs.containsKey(id)) { |
@@ -524,47 +478,33 @@ class PubspecCache { |
} |
} |
-/** |
- * Describes one [Package] in the [DependencyGraph] and keeps track of which |
- * packages depend on it and what constraints they place on it. |
- */ |
+/// Describes one [Package] in the [DependencyGraph] and keeps track of which |
+/// packages depend on it and what constraints they place on it. |
class Dependency { |
- /** |
- * The name of the this dependency's package. |
- */ |
+ /// The name of the this dependency's package. |
final String name; |
- /** |
- * The [PackageRefs] that represent constraints that depending packages have |
- * placed on this one. |
- */ |
+ /// The [PackageRefs] that represent constraints that depending packages have |
+ /// placed on this one. |
final Map<String, PackageRef> _refs; |
- /** |
- * The currently-selected best version for this dependency. |
- */ |
+ /// The currently-selected best version for this dependency. |
Version version; |
- /** |
- * Whether this dependency should always select the latest version. |
- */ |
+ /// Whether this dependency should always select the latest version. |
bool useLatestVersion = false; |
- /** |
- * Gets whether or not any other packages are currently depending on this |
- * one. If `false`, then it means this package is not part of the dependency |
- * graph and should be omitted. |
- */ |
+ /// Gets whether or not any other packages are currently depending on this |
+ /// one. If `false`, then it means this package is not part of the dependency |
+ /// graph and should be omitted. |
bool get isDependedOn => !_refs.isEmpty; |
- /** The names of all the packages that depend on this dependency. */ |
+ /// The names of all the packages that depend on this dependency. |
Collection<String> get dependers => _refs.keys; |
- /** |
- * Gets the overall constraint that all packages are placing on this one. |
- * If no packages have a constraint on this one (which can happen when this |
- * package is in the process of being added to the graph), returns `null`. |
- */ |
+ /// Gets the overall constraint that all packages are placing on this one. |
+ /// If no packages have a constraint on this one (which can happen when this |
+ /// package is in the process of being added to the graph), returns `null`. |
VersionConstraint get constraint { |
if (_refs.isEmpty) return null; |
return new VersionConstraint.intersection( |
@@ -606,15 +546,13 @@ class Dependency { |
version = other.version, |
_refs = new Map<String, PackageRef>.from(other._refs); |
- /** Creates a copy of this dependency. */ |
+ /// Creates a copy of this dependency. |
Dependency clone() => new Dependency._clone(this); |
/// Return a list of available versions for this dependency. |
Future<List<Version>> getVersions() => source.getVersions(name, description); |
- /** |
- * Places [ref] as a constraint from [package] onto this. |
- */ |
+ /// Places [ref] as a constraint from [package] onto this. |
void placeConstraint(String package, PackageRef ref) { |
var requiredDepender = _requiredDepender(); |
if (requiredDepender != null) { |
@@ -648,17 +586,13 @@ class Dependency { |
return dependers[1]; |
} |
- /** |
- * Removes the constraint from [package] onto this. |
- */ |
+ /// Removes the constraint from [package] onto this. |
PackageRef removeConstraint(String package) => _refs.remove(package); |
} |
-/** |
- * Exception thrown when the [VersionConstraint] used to match a package is |
- * valid (i.e. non-empty), but there are no released versions of the package |
- * that fit that constraint. |
- */ |
+/// Exception thrown when the [VersionConstraint] used to match a package is |
+/// valid (i.e. non-empty), but there are no released versions of the package |
+/// that fit that constraint. |
class NoVersionException implements Exception { |
final String package; |
final VersionConstraint constraint; |
@@ -684,10 +618,8 @@ class NoVersionException implements Exception { |
} |
// TODO(rnystrom): Report the list of depending packages and their constraints. |
-/** |
- * Exception thrown when the most recent version of [package] must be selected, |
- * but doesn't match the [VersionConstraint] imposed on the package. |
- */ |
+/// Exception thrown when the most recent version of [package] must be selected, |
+/// but doesn't match the [VersionConstraint] imposed on the package. |
class CouldNotUpdateException implements Exception { |
final String package; |
final VersionConstraint constraint; |
@@ -699,11 +631,9 @@ class CouldNotUpdateException implements Exception { |
"The latest version of '$package', $best, does not match $constraint."; |
} |
-/** |
- * Exception thrown when the [VersionConstraint] used to match a package is |
- * the empty set: in other words, multiple packages depend on it and have |
- * conflicting constraints that have no overlap. |
- */ |
+/// Exception thrown when the [VersionConstraint] used to match a package is |
+/// the empty set: in other words, multiple packages depend on it and have |
+/// conflicting constraints that have no overlap. |
class DisjointConstraintException implements Exception { |
final String package; |
final Map<String, PackageRef> _dependencies; |
@@ -726,10 +656,8 @@ class DisjointConstraintException implements Exception { |
} |
} |
-/** |
- * Exception thrown when the [VersionSolver] fails to find a solution after a |
- * certain number of iterations. |
- */ |
+/// Exception thrown when the [VersionSolver] fails to find a solution after a |
+/// certain number of iterations. |
class CouldNotSolveException implements Exception { |
CouldNotSolveException(); |
@@ -737,10 +665,8 @@ class CouldNotSolveException implements Exception { |
"Could not find a solution that met all version constraints."; |
} |
-/** |
- * Exception thrown when two packages with the same name but different sources |
- * are depended upon. |
- */ |
+/// Exception thrown when two packages with the same name but different sources |
+/// are depended upon. |
class SourceMismatchException implements Exception { |
final String package; |
final String depender1; |
@@ -758,10 +684,8 @@ class SourceMismatchException implements Exception { |
} |
} |
-/** |
- * Exception thrown when two packages with the same name and source but |
- * different descriptions are depended upon. |
- */ |
+/// Exception thrown when two packages with the same name and source but |
+/// different descriptions are depended upon. |
class DescriptionMismatchException implements Exception { |
final String package; |
final String depender1; |