| 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 library version_solver; | 5 library version_solver; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:json' as json; | 8 import 'dart:json' as json; |
| 9 | 9 |
| 10 import '../lock_file.dart'; | 10 import '../lock_file.dart'; |
| 11 import '../log.dart' as log; | 11 import '../log.dart' as log; |
| 12 import '../package.dart'; | 12 import '../package.dart'; |
| 13 import '../pubspec.dart'; | 13 import '../pubspec.dart'; |
| 14 import '../source.dart'; | 14 import '../source.dart'; |
| 15 import '../source_registry.dart'; | 15 import '../source_registry.dart'; |
| 16 import '../version.dart'; | 16 import '../version.dart'; |
| 17 import 'backtracking_solver.dart'; | 17 import 'backtracking_solver.dart'; |
| 18 import 'greedy_solver.dart'; | |
| 19 | 18 |
| 20 /// Attempts to select the best concrete versions for all of the transitive | 19 /// Attempts to select the best concrete versions for all of the transitive |
| 21 /// dependencies of [root] taking into account all of the [VersionConstraint]s | 20 /// dependencies of [root] taking into account all of the [VersionConstraint]s |
| 22 /// that those dependencies place on each other and the requirements imposed by | 21 /// that those dependencies place on each other and the requirements imposed by |
| 23 /// [lockFile]. | 22 /// [lockFile]. |
| 24 /// | 23 /// |
| 25 /// If [useLatest] is given, then only the latest versions of the referenced | 24 /// If [useLatest] is given, then only the latest versions of the referenced |
| 26 /// packages will be used. This is for forcing an update to one or more | 25 /// packages will be used. This is for forcing an update to one or more |
| 27 /// packages. | 26 /// packages. |
| 28 /// | |
| 29 /// If [allowBacktracking] is `true` the backtracking version solver will | |
| 30 /// be used. Otherwise, the non-backtracking one will be. | |
| 31 Future<SolveResult> resolveVersions(SourceRegistry sources, Package root, | 27 Future<SolveResult> resolveVersions(SourceRegistry sources, Package root, |
| 32 {LockFile lockFile, bool allowBacktracking, List<PackageRef> useLatest}) { | 28 {LockFile lockFile, List<PackageRef> useLatest}) { |
| 33 log.message('Resolving dependencies...'); | 29 log.message('Resolving dependencies...'); |
| 34 | 30 |
| 35 if (allowBacktracking == null) allowBacktracking = false; | |
| 36 if (lockFile == null) lockFile = new LockFile.empty(); | 31 if (lockFile == null) lockFile = new LockFile.empty(); |
| 37 if (useLatest == null) useLatest = []; | 32 if (useLatest == null) useLatest = []; |
| 38 | 33 |
| 39 var solver; | 34 return new BacktrackingSolver(sources, root, lockFile, useLatest).solve(); |
| 40 if (allowBacktracking) { | |
| 41 solver = new BacktrackingVersionSolver(sources, root, lockFile, useLatest); | |
| 42 } else { | |
| 43 solver = new GreedyVersionSolver(sources, root, lockFile, useLatest); | |
| 44 } | |
| 45 | |
| 46 return solver.solve(); | |
| 47 } | |
| 48 | |
| 49 /// Base class for an implementation of the version constraint solver. | |
| 50 class VersionSolver { | |
| 51 final SourceRegistry sources; | |
| 52 final Package root; | |
| 53 final LockFile lockFile; | |
| 54 final PubspecCache cache; | |
| 55 | |
| 56 VersionSolver(SourceRegistry sources, this.root, this.lockFile, | |
| 57 List<String> useLatest) | |
| 58 : sources = sources, | |
| 59 cache = new PubspecCache(sources) { | |
| 60 for (var package in useLatest) { | |
| 61 forceLatestVersion(package); | |
| 62 lockFile.packages.remove(package); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 /// The number of solutions the solver has tried so far. | |
| 67 int get attemptedSolutions; | |
| 68 | |
| 69 /// Force the solver to upgrade [package] to the latest available version. | |
| 70 void forceLatestVersion(String package); | |
| 71 | |
| 72 /// Run the solver. Completes with a list of specific package versions if | |
| 73 /// successful or an error if it failed to find a solution. | |
| 74 Future<SolveResult> solve() { | |
| 75 var stopwatch = new Stopwatch(); | |
| 76 | |
| 77 return new Future(() { | |
| 78 stopwatch.start(); | |
| 79 | |
| 80 // Pre-cache the root package's known pubspec. | |
| 81 cache.cache(new PackageId.root(root), root.pubspec); | |
| 82 return runSolver(); | |
| 83 }).then((packages) { | |
| 84 return new SolveResult(packages, null, attemptedSolutions); | |
| 85 }).catchError((error) { | |
| 86 if (error is! SolveFailure) throw error; | |
| 87 | |
| 88 // Wrap a failure in a result so we can attach some other data. | |
| 89 return new SolveResult(null, error, attemptedSolutions); | |
| 90 }).whenComplete(() { | |
| 91 // Gather some solving metrics. | |
| 92 var buffer = new StringBuffer(); | |
| 93 buffer.writeln('${runtimeType} took ${stopwatch.elapsed} seconds.'); | |
| 94 buffer.writeln( | |
| 95 '- Requested ${cache.versionCacheMisses} version lists'); | |
| 96 buffer.writeln( | |
| 97 '- Looked up ${cache.versionCacheHits} cached version lists'); | |
| 98 buffer.writeln( | |
| 99 '- Requested ${cache.pubspecCacheMisses} pubspecs'); | |
| 100 buffer.writeln( | |
| 101 '- Looked up ${cache.pubspecCacheHits} cached pubspecs'); | |
| 102 log.solver(buffer); | |
| 103 }); | |
| 104 } | |
| 105 | |
| 106 /// Entrypoint for subclasses to actually begin solving. External code should | |
| 107 /// call [solve()]. | |
| 108 Future<List<PackageId>> runSolver(); | |
| 109 } | 35 } |
| 110 | 36 |
| 111 /// The result of a version resolution. | 37 /// The result of a version resolution. |
| 112 class SolveResult { | 38 class SolveResult { |
| 113 /// Whether the solver found a complete solution or failed. | 39 /// Whether the solver found a complete solution or failed. |
| 114 bool get succeeded => error == null; | 40 bool get succeeded => error == null; |
| 115 | 41 |
| 116 /// The list of concrete package versions that were selected for each package | 42 /// The list of concrete package versions that were selected for each package |
| 117 /// reachable from the root, or `null` if the solver failed. | 43 /// reachable from the root, or `null` if the solver failed. |
| 118 final List<PackageId> packages; | 44 final List<PackageId> packages; |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 Iterable<Dependency> dependencies) | 299 Iterable<Dependency> dependencies) |
| 374 : super(package, dependencies); | 300 : super(package, dependencies); |
| 375 | 301 |
| 376 String get _message => "Incompatible dependencies on '$package'"; | 302 String get _message => "Incompatible dependencies on '$package'"; |
| 377 | 303 |
| 378 String _describeDependency(PackageRef ref) { | 304 String _describeDependency(PackageRef ref) { |
| 379 // TODO(nweiz): Dump descriptions to YAML when that's supported. | 305 // TODO(nweiz): Dump descriptions to YAML when that's supported. |
| 380 return "depends on it with description ${json.stringify(ref.description)}"; | 306 return "depends on it with description ${json.stringify(ref.description)}"; |
| 381 } | 307 } |
| 382 } | 308 } |
| OLD | NEW |