| 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 |