blob: 5b1022b158065cbe05075c0a33a3a5357bd29032 [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 '../lock_file.dart';
import '../package.dart';
import '../package_name.dart';
import '../pubspec.dart';
import '../source_registry.dart';
import '../system_cache.dart';
import 'report.dart';
import 'type.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;
/// 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.
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 [LockFile] representing the packages selected by this version
/// resolution.
LockFile get lockFile {
// Don't factor in overridden dependencies' SDK constraints, because we'll
// accept those packages even if their constraints don't match.
var nonOverrides = pubspecs.values
(pubspec) => !_root.dependencyOverrides.containsKey(
var sdkConstraints = <String, VersionConstraint>{};
for (var pubspec in nonOverrides) {
pubspec.sdkConstraints.forEach((identifier, constraint) {
sdkConstraints[identifier] = constraint
.intersect(sdkConstraints[identifier] ?? VersionConstraint.any);
return LockFile(packages,
sdkConstraints: sdkConstraints,
mainDependencies: MapKeySet(_root.dependencies),
devDependencies: MapKeySet(_root.devDependencies),
overriddenDependencies: MapKeySet(_root.dependencyOverrides));
final SourceRegistry _sources;
final LockFile _previousLockFile;
/// Returns the names of all packages that were changed.
/// This includes packages that were added or removed.
Set<String> get changedPackages {
if (packages == null) return null;
var changed = packages
.where((id) => _previousLockFile.packages[] != id)
.map((id) =>
return changed.union(_previousLockFile.packages.keys
.where((package) => !availableVersions.containsKey(package))
SolveResult(this._sources, this._root, this._previousLockFile, this.packages,
this.pubspecs, this.availableVersions, this.attemptedSolutions);
/// Displays a report of what changes were made to the lockfile.
/// [type] is the type of version resolution that was run.
Future<void> showReport(SolveType type, SystemCache cache) async {
await SolveReport(type, _sources, _root, _previousLockFile, this, cache)
/// Displays a one-line message summarizing what changes were made (or would
/// be made) to the lockfile.
/// If [type] is `SolveType.UPGRADE` it also shows the number of packages
/// that are not at the latest available version.
/// [type] is the type of version resolution that was run.
Future<void> summarizeChanges(SolveType type, SystemCache cache,
{bool dryRun = false}) async {
final report =
SolveReport(type, _sources, _root, _previousLockFile, this, cache);
report.summarize(dryRun: dryRun);
if (type == SolveType.UPGRADE) {
String toString() => 'Took $attemptedSolutions tries to resolve to\n'
'- ${packages.join("\n- ")}';