blob: 7c88666f29180765de45008656e7ef9b57ec5009 [file] [log] [blame]
// 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- ")}';
}