| // 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 '../http.dart'; |
| import '../lock_file.dart'; |
| import '../log.dart'; |
| 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) async { |
| final resolvedPackageIds = await progress('Downloading packages', () async { |
| return await Future.wait( |
| packages.map((id) async { |
| if (id.source is CachedSource) { |
| return await withDependencyType( |
| _root.pubspec.dependencyType(id.name), |
| () async { |
| return (await cache.downloadPackage(id)).packageId; |
| }, |
| ); |
| } |
| return id; |
| }), |
| ); |
| }); |
| // 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- ")}'; |
| } |