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 pub.solver.version_solver; | 5 library pub.solver.version_solver; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import "dart:convert"; | 8 import "dart:convert"; |
9 | 9 |
10 import 'package:pub_semver/pub_semver.dart'; | 10 import 'package:pub_semver/pub_semver.dart'; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 if (!succeeded) { | 126 if (!succeeded) { |
127 return 'Failed to solve after $attemptedSolutions attempts:\n' | 127 return 'Failed to solve after $attemptedSolutions attempts:\n' |
128 '$error'; | 128 '$error'; |
129 } | 129 } |
130 | 130 |
131 return 'Took $attemptedSolutions tries to resolve to\n' | 131 return 'Took $attemptedSolutions tries to resolve to\n' |
132 '- ${packages.join("\n- ")}'; | 132 '- ${packages.join("\n- ")}'; |
133 } | 133 } |
134 } | 134 } |
135 | 135 |
136 /// Maintains a cache of previously-requested data: pubspecs and version lists. | 136 /// Maintains a cache of previously-requested version lists. |
137 /// | 137 class SolverCache { |
138 /// Used to avoid requesting the same pubspec from the server repeatedly. | |
139 class PubspecCache { | |
140 final SourceRegistry _sources; | 138 final SourceRegistry _sources; |
141 | 139 |
142 /// The already-requested cached pubspec lists. | 140 /// The already-requested cached version lists. |
143 final _versions = new Map<PackageRef, List<PackageId>>(); | 141 final _versions = new Map<PackageRef, List<PackageId>>(); |
144 | 142 |
145 /// The errors from failed version list requests. | 143 /// The errors from failed version list requests. |
146 final _versionErrors = new Map<PackageRef, Pair<Object, Chain>>(); | 144 final _versionErrors = new Map<PackageRef, Pair<Object, Chain>>(); |
147 | 145 |
148 /// The already-requested cached pubspecs. | |
149 final _pubspecs = new Map<PackageId, Pubspec>(); | |
150 | |
151 // TODO(nweiz): Currently, if [getCachedPubspec] returns pubspecs cached via | |
152 // [getVersions], the "complex backtrack" test case in version_solver_test | |
153 // fails. Fix that. See also [BacktrackingSolver._getTransitiveDependers]. | |
154 /// The set of package ids for which [getPubspec] has been explicitly called. | |
155 final _explicitlyCached = new Set<PackageId>(); | |
156 | |
157 /// The type of version resolution that was run. | 146 /// The type of version resolution that was run. |
158 final SolveType _type; | 147 final SolveType _type; |
159 | 148 |
160 /// The number of times a version list was requested and it wasn't cached and | 149 /// The number of times a version list was requested and it wasn't cached and |
161 /// had to be requested from the source. | 150 /// had to be requested from the source. |
162 int _versionCacheMisses = 0; | 151 int _versionCacheMisses = 0; |
163 | 152 |
164 /// The number of times a version list was requested and the cached version | 153 /// The number of times a version list was requested and the cached version |
165 /// was returned. | 154 /// was returned. |
166 int _versionCacheHits = 0; | 155 int _versionCacheHits = 0; |
167 | 156 |
168 /// The number of times a pubspec was requested and it wasn't cached and had | 157 SolverCache(this._type, this._sources); |
169 /// to be requested from the source. | |
170 int _pubspecCacheMisses = 0; | |
171 | |
172 /// The number of times a pubspec was requested and the cached version was | |
173 /// returned. | |
174 int _pubspecCacheHits = 0; | |
175 | |
176 PubspecCache(this._type, this._sources); | |
177 | |
178 /// Caches [pubspec] as the [Pubspec] for the package identified by [id]. | |
179 void cache(PackageId id, Pubspec pubspec) { | |
180 _pubspecs[id] = pubspec; | |
181 } | |
182 | |
183 /// Loads the pubspec for the package identified by [id]. | |
184 Future<Pubspec> getPubspec(PackageId id) async { | |
185 _explicitlyCached.add(id); | |
186 | |
187 // Complete immediately if it's already cached. | |
188 if (_pubspecs.containsKey(id)) { | |
189 _pubspecCacheHits++; | |
190 return _pubspecs[id]; | |
191 } | |
192 | |
193 _pubspecCacheMisses++; | |
194 | |
195 var source = _sources[id.source]; | |
196 var pubspec = await source.describe(id); | |
197 _pubspecs[id] = pubspec; | |
198 return pubspec; | |
199 } | |
200 | |
201 /// Returns the previously cached pubspec for the package identified by [id] | |
202 /// or returns `null` if not in the cache. | |
203 Pubspec getCachedPubspec(PackageId id) => | |
204 _explicitlyCached.contains(id) ? _pubspecs[id] : null; | |
205 | 158 |
206 /// Gets the list of versions for [package]. | 159 /// Gets the list of versions for [package]. |
207 /// | 160 /// |
208 /// Packages are sorted in descending version order with all "stable" | 161 /// Packages are sorted in descending version order with all "stable" |
209 /// versions (i.e. ones without a prerelease suffix) before pre-release | 162 /// versions (i.e. ones without a prerelease suffix) before pre-release |
210 /// versions. This ensures that the solver prefers stable packages over | 163 /// versions. This ensures that the solver prefers stable packages over |
211 /// unstable ones. | 164 /// unstable ones. |
212 Future<List<PackageId>> getVersions(PackageRef package) async { | 165 Future<List<PackageId>> getVersions(PackageRef package) async { |
213 if (package.isRoot) { | 166 if (package.isRoot) { |
214 throw new StateError("Cannot get versions for root package $package."); | 167 throw new StateError("Cannot get versions for root package $package."); |
(...skipping 11 matching lines...) Expand all Loading... |
226 // See if we cached a failure. | 179 // See if we cached a failure. |
227 var error = _versionErrors[package]; | 180 var error = _versionErrors[package]; |
228 if (error != null) { | 181 if (error != null) { |
229 _versionCacheHits++; | 182 _versionCacheHits++; |
230 await new Future.error(error.first, error.last); | 183 await new Future.error(error.first, error.last); |
231 } | 184 } |
232 | 185 |
233 _versionCacheMisses++; | 186 _versionCacheMisses++; |
234 | 187 |
235 var source = _sources[package.source]; | 188 var source = _sources[package.source]; |
236 var pubspecs; | 189 var ids; |
237 try { | 190 try { |
238 pubspecs = await source.getVersions(package.name, package.description); | 191 ids = await source.getVersions(package); |
239 } catch (error, stackTrace) { | 192 } catch (error, stackTrace) { |
240 // If an error occurs, cache that too. We only want to do one request | 193 // If an error occurs, cache that too. We only want to do one request |
241 // for any given package, successful or not. | 194 // for any given package, successful or not. |
242 var chain = new Chain.forTrace(stackTrace); | 195 var chain = new Chain.forTrace(stackTrace); |
243 log.solver("Could not get versions for $package:\n$error\n\n" + | 196 log.solver("Could not get versions for $package:\n$error\n\n" + |
244 chain.terse.toString()); | 197 chain.terse.toString()); |
245 _versionErrors[package] = new Pair(error, chain); | 198 _versionErrors[package] = new Pair(error, chain); |
246 throw error; | 199 throw error; |
247 } | 200 } |
248 | 201 |
249 // Sort by priority so we try preferred versions first. | 202 // Sort by priority so we try preferred versions first. |
250 pubspecs.sort((pubspec1, pubspec2) { | 203 ids.sort((id1, id2) { |
| 204 // Reverse the IDs because we want the newest version at the front of the |
| 205 // list. |
251 return _type == SolveType.DOWNGRADE | 206 return _type == SolveType.DOWNGRADE |
252 ? Version.antiprioritize(pubspec1.version, pubspec2.version) | 207 ? Version.antiprioritize(id2.version, id1.version) |
253 : Version.prioritize(pubspec1.version, pubspec2.version); | 208 : Version.prioritize(id2.version, id1.version); |
254 }); | 209 }); |
255 | 210 |
256 var ids = pubspecs.reversed.map((pubspec) { | 211 ids = ids.toList(); |
257 var id = package.atVersion(pubspec.version); | |
258 // Eagerly cache the pubspec now since we have it. | |
259 _pubspecs[id] = pubspec; | |
260 return id; | |
261 }).toList(); | |
262 _versions[package] = ids; | 212 _versions[package] = ids; |
263 return ids; | 213 return ids; |
264 } | 214 } |
265 | 215 |
266 /// Returns the previously cached list of versions for the package identified | 216 /// Returns the previously cached list of versions for the package identified |
267 /// by [package] or returns `null` if not in the cache. | 217 /// by [package] or returns `null` if not in the cache. |
268 List<PackageId> getCachedVersions(PackageRef package) => _versions[package]; | 218 List<PackageId> getCachedVersions(PackageRef package) => _versions[package]; |
269 | 219 |
270 /// Returns a user-friendly output string describing metrics of the solve. | 220 /// Returns a user-friendly output string describing metrics of the solve. |
271 String describeResults() { | 221 String describeResults() { |
272 var results = '''- Requested $_versionCacheMisses version lists | 222 var results = '''- Requested $_versionCacheMisses version lists |
273 - Looked up $_versionCacheHits cached version lists | 223 - Looked up $_versionCacheHits cached version lists |
274 - Requested $_pubspecCacheMisses pubspecs | |
275 - Looked up $_pubspecCacheHits cached pubspecs | |
276 '''; | 224 '''; |
277 | 225 |
278 // Uncomment this to dump the visited package graph to JSON. | 226 // Uncomment this to dump the visited package graph to JSON. |
279 //results += _debugWritePackageGraph(); | 227 //results += _debugWritePackageGraph(); |
280 | 228 |
281 return results; | 229 return results; |
282 } | 230 } |
283 } | 231 } |
284 | 232 |
285 /// A reference from a depending package to a package that it depends on. | 233 /// A reference from a depending package to a package that it depends on. |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 | 426 |
479 DependencyNotFoundException(String package, this._innerException, | 427 DependencyNotFoundException(String package, this._innerException, |
480 Iterable<Dependency> dependencies) | 428 Iterable<Dependency> dependencies) |
481 : super(package, dependencies); | 429 : super(package, dependencies); |
482 | 430 |
483 /// The failure isn't because of the version of description of the package, | 431 /// The failure isn't because of the version of description of the package, |
484 /// it's the package itself that can't be found, so just show the name and no | 432 /// it's the package itself that can't be found, so just show the name and no |
485 /// descriptive details. | 433 /// descriptive details. |
486 String _describeDependency(PackageDep dep) => ""; | 434 String _describeDependency(PackageDep dep) => ""; |
487 } | 435 } |
OLD | NEW |