| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'package:collection/collection.dart'; | |
| import 'package:pub_semver/pub_semver.dart'; | |
| import '../lock_file.dart'; | |
| import '../log.dart' as log; | |
| import '../package.dart'; | |
| import '../package_name.dart'; | |
| import '../pubspec.dart'; | |
| import '../source/cached.dart'; | |
| import '../system_cache.dart'; | |
| /// The result of a successful version resolution. | |
| class SolveResult { | |
| /// The list of concrete package versions that were selected for each package | |
| /// reachable from the root. | |
| final List<PackageId> packages; | |
| /// Names of all dependency overrides in the workspace. | |
| final Set<String> _overriddenPackages; | |
| /// The root package of this resolution. | |
| final Package _root; | |
| /// A map from package names to the pubspecs for the versions of those | |
| /// packages that were installed. | |
| final Map<String, Pubspec> pubspecs; | |
| /// The available versions of all selected packages from their source. | |
| /// | |
| /// An entry here may not include the full list of versions available if the | |
| /// given package was locked and did not need to be unlocked during the solve. | |
| /// | |
| /// No version list will not contain any retracted package versions. | |
| final Map<String, List<Version>> availableVersions; | |
| /// The number of solutions that were attempted before either finding a | |
| /// successful solution or exhausting all options. | |
| /// | |
| /// In other words, one more than the number of times it had to backtrack | |
| /// because it found an invalid solution. | |
| final int attemptedSolutions; | |
| /// The wall clock time the resolution took. | |
| final Duration resolutionTime; | |
| /// Downloads all the cached packages selected by this version resolution. | |
| /// | |
| /// If some already cached package differs from what is provided by the server | |
| /// (according to the content-hash) a warning is printed and the package is | |
| /// redownloaded. | |
| /// | |
| /// Returns the [LockFile] representing the packages selected by this version | |
| /// resolution. Any resolved [PackageId]s will correspond to those in the | |
| /// cache (and thus to the one provided by the server). | |
| /// | |
| /// If there is a mismatch between the previous content-hash from pubspec.lock | |
| /// and the new one a warning will be printed but the new one will be | |
| /// returned. | |
| Future<LockFile> downloadCachedPackages( | |
| SystemCache cache, { | |
| bool transient = false, | |
| }) async { | |
| final resolvedPackageIds = await log.progress<List<PackageId>>( | |
| 'Downloading packages', | |
| () => Future.wait( | |
| packages.map((id) async { | |
| if (id.source is CachedSource) { | |
| return (await cache.downloadPackage(id)).packageId; | |
| } | |
| return id; | |
| }), | |
| ), | |
| transient: transient, | |
| ); | |
| // Invariant: the content-hashes in PUB_CACHE matches those provided by the | |
| // server. | |
| // Don't factor in overridden dependencies' SDK constraints, because we'll | |
| // accept those packages even if their constraints don't match. | |
| final nonOverrides = | |
| pubspecs.values | |
| .where((pubspec) => !_overriddenPackages.contains(pubspec.name)) | |
| .toList(); | |
| final sdkConstraints = <String, VersionConstraint>{}; | |
| for (var pubspec in nonOverrides) { | |
| pubspec.sdkConstraints.forEach((identifier, constraint) { | |
| sdkConstraints[identifier] = constraint.effectiveConstraint.intersect( | |
| sdkConstraints[identifier] ?? VersionConstraint.any, | |
| ); | |
| }); | |
| } | |
| return LockFile( | |
| resolvedPackageIds, | |
| sdkConstraints: { | |
| for (final MapEntry(:key, :value) in sdkConstraints.entries) | |
| key: SdkConstraint(value), | |
| }, | |
| mainDependencies: MapKeySet(_root.dependencies), | |
| devDependencies: MapKeySet(_root.devDependencies), | |
| overriddenDependencies: _overriddenPackages, | |
| ); | |
| } | |
| final LockFile _previousLockFile; | |
| /// Returns the names of all packages that were changed. | |
| /// | |
| /// This includes packages that were added or removed. | |
| Set<String> get changedPackages { | |
| final changed = | |
| packages | |
| .where((id) => _previousLockFile.packages[id.name] != id) | |
| .map((id) => id.name) | |
| .toSet(); | |
| return changed.union( | |
| _previousLockFile.packages.keys | |
| .where((package) => !availableVersions.containsKey(package)) | |
| .toSet(), | |
| ); | |
| } | |
| SolveResult( | |
| this._root, | |
| this._overriddenPackages, | |
| this._previousLockFile, | |
| this.packages, | |
| this.pubspecs, | |
| this.availableVersions, | |
| this.attemptedSolutions, | |
| this.resolutionTime, | |
| ); | |
| @override | |
| String toString() => | |
| 'Took $attemptedSolutions tries to resolve to\n' | |
| '- ${packages.join("\n- ")}'; | |
| } |