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 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 /// | 207 /// |
208 /// Packages are sorted in descending version order with all "stable" | 208 /// Packages are sorted in descending version order with all "stable" |
209 /// versions (i.e. ones without a prerelease suffix) before pre-release | 209 /// versions (i.e. ones without a prerelease suffix) before pre-release |
210 /// versions. This ensures that the solver prefers stable packages over | 210 /// versions. This ensures that the solver prefers stable packages over |
211 /// unstable ones. | 211 /// unstable ones. |
212 Future<List<PackageId>> getVersions(PackageRef package) async { | 212 Future<List<PackageId>> getVersions(PackageRef package) async { |
213 if (package.isRoot) { | 213 if (package.isRoot) { |
214 throw new StateError("Cannot get versions for root package $package."); | 214 throw new StateError("Cannot get versions for root package $package."); |
215 } | 215 } |
216 | 216 |
| 217 if (package.isMagic) return [new PackageId.magic(package.name)]; |
| 218 |
217 // See if we have it cached. | 219 // See if we have it cached. |
218 var versions = _versions[package]; | 220 var versions = _versions[package]; |
219 if (versions != null) { | 221 if (versions != null) { |
220 _versionCacheHits++; | 222 _versionCacheHits++; |
221 return versions; | 223 return versions; |
222 } | 224 } |
223 | 225 |
224 // See if we cached a failure. | 226 // See if we cached a failure. |
225 var error = _versionErrors[package]; | 227 var error = _versionErrors[package]; |
226 if (error != null) { | 228 if (error != null) { |
227 _versionCacheHits++; | 229 _versionCacheHits++; |
228 await new Future.error(error.first, error.last); | 230 await new Future.error(error.first, error.last); |
229 } | 231 } |
230 | 232 |
231 _versionCacheMisses++; | 233 _versionCacheMisses++; |
232 | 234 |
233 var source = _sources[package.source]; | 235 var source = _sources[package.source]; |
234 var pubspecs; | 236 var pubspecs; |
235 try { | 237 try { |
236 pubspecs = await source.getVersions(package.name, package.description); | 238 pubspecs = await source.getVersions(package.name, package.description); |
237 } catch (error, stackTrace) { | 239 } catch (error, stackTrace) { |
238 // If an error occurs, cache that too. We only want to do one request | 240 // If an error occurs, cache that too. We only want to do one request |
239 // for any given package, successful or not. | 241 // for any given package, successful or not. |
240 log.solver("Could not get versions for $package:\n$error\n\n$stackTrace"); | 242 var chain = new Chain.forTrace(stackTrace); |
241 _versionErrors[package] = new Pair(error, new Chain.forTrace(stackTrace)); | 243 log.solver("Could not get versions for $package:\n$error\n\n" + |
| 244 chain.terse.toString()); |
| 245 _versionErrors[package] = new Pair(error, chain); |
242 throw error; | 246 throw error; |
243 } | 247 } |
244 | 248 |
245 // Sort by priority so we try preferred versions first. | 249 // Sort by priority so we try preferred versions first. |
246 pubspecs.sort((pubspec1, pubspec2) { | 250 pubspecs.sort((pubspec1, pubspec2) { |
247 return _type == SolveType.DOWNGRADE | 251 return _type == SolveType.DOWNGRADE |
248 ? Version.antiprioritize(pubspec1.version, pubspec2.version) | 252 ? Version.antiprioritize(pubspec1.version, pubspec2.version) |
249 : Version.prioritize(pubspec1.version, pubspec2.version); | 253 : Version.prioritize(pubspec1.version, pubspec2.version); |
250 }); | 254 }); |
251 | 255 |
(...skipping 21 matching lines...) Expand all Loading... |
273 | 277 |
274 // Uncomment this to dump the visited package graph to JSON. | 278 // Uncomment this to dump the visited package graph to JSON. |
275 //results += _debugWritePackageGraph(); | 279 //results += _debugWritePackageGraph(); |
276 | 280 |
277 return results; | 281 return results; |
278 } | 282 } |
279 } | 283 } |
280 | 284 |
281 /// A reference from a depending package to a package that it depends on. | 285 /// A reference from a depending package to a package that it depends on. |
282 class Dependency { | 286 class Dependency { |
283 /// The name of the package that has this dependency. | 287 /// The package that has this dependency. |
284 final String depender; | 288 final PackageId depender; |
285 | |
286 /// The version of the depender that has this dependency. | |
287 final Version dependerVersion; | |
288 | 289 |
289 /// The package being depended on. | 290 /// The package being depended on. |
290 final PackageDep dep; | 291 final PackageDep dep; |
291 | 292 |
292 /// Whether [depender] is a magic dependency (e.g. "pub itself" or "pub global | 293 Dependency(this.depender, this.dep); |
293 /// activate"). | |
294 bool get isMagic => depender.contains(" "); | |
295 | 294 |
296 | 295 String toString() => '$depender -> $dep'; |
297 Dependency(this.depender, this.dependerVersion, this.dep); | |
298 | |
299 String toString() => '$depender $dependerVersion -> $dep'; | |
300 } | 296 } |
301 | 297 |
302 /// An enum for types of version resolution. | 298 /// An enum for types of version resolution. |
303 class SolveType { | 299 class SolveType { |
304 /// As few changes to the lockfile as possible to be consistent with the | 300 /// As few changes to the lockfile as possible to be consistent with the |
305 /// pubspec. | 301 /// pubspec. |
306 static const GET = const SolveType._("get"); | 302 static const GET = const SolveType._("get"); |
307 | 303 |
308 /// Upgrade all packages or specific packages to the highest versions | 304 /// Upgrade all packages or specific packages to the highest versions |
309 /// possible, regardless of the lockfile. | 305 /// possible, regardless of the lockfile. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
342 SolveFailure(this.package, Iterable<Dependency> dependencies) | 338 SolveFailure(this.package, Iterable<Dependency> dependencies) |
343 : dependencies = dependencies != null ? dependencies : <Dependency>[]; | 339 : dependencies = dependencies != null ? dependencies : <Dependency>[]; |
344 | 340 |
345 String toString() { | 341 String toString() { |
346 if (dependencies.isEmpty) return _message; | 342 if (dependencies.isEmpty) return _message; |
347 | 343 |
348 var buffer = new StringBuffer(); | 344 var buffer = new StringBuffer(); |
349 buffer.write("$_message:"); | 345 buffer.write("$_message:"); |
350 | 346 |
351 var sorted = dependencies.toList(); | 347 var sorted = dependencies.toList(); |
352 sorted.sort((a, b) => a.depender.compareTo(b.depender)); | 348 sorted.sort((a, b) => a.depender.name.compareTo(b.depender.name)); |
353 | 349 |
354 for (var dep in sorted) { | 350 for (var dep in sorted) { |
355 buffer.writeln(); | 351 buffer.writeln(); |
356 buffer.write("- ${log.bold(dep.depender)}"); | 352 buffer.write("- ${log.bold(dep.depender.name)}"); |
357 if (!dep.isMagic) buffer.write(" ${dep.dependerVersion}"); | 353 if (!dep.depender.isMagic && !dep.depender.isRoot) { |
| 354 buffer.write(" ${dep.depender.version}"); |
| 355 } |
358 buffer.write(" ${_describeDependency(dep.dep)}"); | 356 buffer.write(" ${_describeDependency(dep.dep)}"); |
359 } | 357 } |
360 | 358 |
361 return buffer.toString(); | 359 return buffer.toString(); |
362 } | 360 } |
363 | 361 |
364 /// Describes a dependency's reference in the output message. | 362 /// Describes a dependency's reference in the output message. |
365 /// | 363 /// |
366 /// Override this to highlight which aspect of [dep] led to the failure. | 364 /// Override this to highlight which aspect of [dep] led to the failure. |
367 String _describeDependency(PackageDep dep) => | 365 String _describeDependency(PackageDep dep) => |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 "depends on it from source ${dep.source}"; | 441 "depends on it from source ${dep.source}"; |
444 } | 442 } |
445 | 443 |
446 /// Exception thrown when a dependency on an unknown source name is found. | 444 /// Exception thrown when a dependency on an unknown source name is found. |
447 class UnknownSourceException extends SolveFailure { | 445 class UnknownSourceException extends SolveFailure { |
448 UnknownSourceException(String package, Iterable<Dependency> dependencies) | 446 UnknownSourceException(String package, Iterable<Dependency> dependencies) |
449 : super(package, dependencies); | 447 : super(package, dependencies); |
450 | 448 |
451 String toString() { | 449 String toString() { |
452 var dep = dependencies.single; | 450 var dep = dependencies.single; |
453 return 'Package ${dep.depender} depends on ${dep.dep.name} from unknown ' | 451 return 'Package ${dep.depender.name} depends on ${dep.dep.name} from ' |
454 'source "${dep.dep.source}".'; | 452 'unknown source "${dep.dep.source}".'; |
455 } | 453 } |
456 } | 454 } |
457 | 455 |
458 /// Exception thrown when two packages with the same name and source but | 456 /// Exception thrown when two packages with the same name and source but |
459 /// different descriptions are depended upon. | 457 /// different descriptions are depended upon. |
460 class DescriptionMismatchException extends SolveFailure { | 458 class DescriptionMismatchException extends SolveFailure { |
461 String get _message => "Incompatible dependencies on $package"; | 459 String get _message => "Incompatible dependencies on $package"; |
462 | 460 |
463 DescriptionMismatchException(String package, | 461 DescriptionMismatchException(String package, |
464 Iterable<Dependency> dependencies) | 462 Iterable<Dependency> dependencies) |
(...skipping 15 matching lines...) Expand all Loading... |
480 | 478 |
481 DependencyNotFoundException(String package, this._innerException, | 479 DependencyNotFoundException(String package, this._innerException, |
482 Iterable<Dependency> dependencies) | 480 Iterable<Dependency> dependencies) |
483 : super(package, dependencies); | 481 : super(package, dependencies); |
484 | 482 |
485 /// The failure isn't because of the version of description of the package, | 483 /// The failure isn't because of the version of description of the package, |
486 /// it's the package itself that can't be found, so just show the name and no | 484 /// it's the package itself that can't be found, so just show the name and no |
487 /// descriptive details. | 485 /// descriptive details. |
488 String _describeDependency(PackageDep dep) => ""; | 486 String _describeDependency(PackageDep dep) => ""; |
489 } | 487 } |
OLD | NEW |