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 |