in lib/src/command/upgrade.dart [277:396]
Future<void> _runUpgradeNullSafety() async {
final toUpgrade = _directDependenciesToUpgrade();
final nullsafetyPubspec = await _upgradeToNullSafetyConstraints(
entrypoint.root.pubspec,
toUpgrade,
);
/// Solve [nullsafetyPubspec] in-memory and consolidate the resolved
/// versions of the packages into a map for quick searching.
final resolvedPackages = <String, PackageId>{};
final solveResult = await log.spinner('Resolving dependencies', () async {
return await resolveVersions(
SolveType.upgrade,
cache,
Package.inMemory(nullsafetyPubspec),
);
}, condition: _shouldShowSpinner);
for (final resolvedPackage in solveResult.packages) {
resolvedPackages[resolvedPackage.name] = resolvedPackage;
}
/// Changes to be made to `pubspec.yaml`.
/// Mapping from original to changed value.
final changes = <PackageRange, PackageRange>{};
final declaredHostedDependencies = [
...entrypoint.root.pubspec.dependencies.values,
...entrypoint.root.pubspec.devDependencies.values,
].where((dep) => dep.source is HostedSource);
for (final dep in declaredHostedDependencies) {
final resolvedPackage = resolvedPackages[dep.name]!;
if (!toUpgrade.contains(dep.name)) {
// If we're not to upgrade this package, or it wasn't in the
// resolution somehow, then we ignore it.
continue;
}
final constraint = VersionConstraint.compatibleWith(
resolvedPackage.version,
);
if (dep.constraint.allowsAll(constraint) &&
constraint.allowsAll(dep.constraint)) {
// If constraint allows the same as the existing constraint then
// there is no need to make changes.
continue;
}
changes[dep] = dep.withConstraint(constraint);
}
final newPubspecText = _updatePubspec(changes);
if (_dryRun) {
// Even if it is a dry run, run `acquireDependencies` so that the user
// gets a report on changes.
// TODO(jonasfj): Stop abusing Entrypoint.global for dry-run output
await Entrypoint.inMemory(
Package.inMemory(Pubspec.parse(newPubspecText, cache.sources)),
cache,
lockFile: entrypoint.lockFile,
solveResult: solveResult,
).acquireDependencies(
SolveType.upgrade,
dryRun: true,
precompile: _precompile,
analytics: null,
generateDotPackages: false,
);
} else {
if (changes.isNotEmpty) {
writeTextFile(entrypoint.pubspecPath, newPubspecText);
}
// TODO: Allow Entrypoint to be created with in-memory pubspec, so that
// we can show the changes in --dry-run mode. For now we only show
// the changes made to pubspec.yaml in dry-run mode.
await Entrypoint(directory, cache).acquireDependencies(
SolveType.upgrade,
precompile: _precompile,
analytics: analytics,
generateDotPackages: argResults['legacy-packages-file'],
);
}
_outputChangeSummary(changes);
// Warn if not all dependencies were migrated to a null-safety compatible
// version. This can happen because:
// - `upgradeOnly` was given,
// - root has SDK dependencies,
// - root has git or path dependencies,
// - root has dependency_overrides
final nonMigratedDirectDeps = <String>[];
final directDeps = [
...entrypoint.root.pubspec.dependencies.keys,
...entrypoint.root.pubspec.devDependencies.keys
];
await Future.wait(directDeps.map((name) async {
final resolvedPackage = resolvedPackages[name]!;
final boundSource = resolvedPackage.source!.bind(cache);
final pubspec = await boundSource.describe(resolvedPackage);
if (!pubspec.languageVersion.supportsNullSafety) {
nonMigratedDirectDeps.add(name);
}
}));
if (nonMigratedDirectDeps.isNotEmpty) {
log.warning('''
\nFollowing direct 'dependencies' and 'dev_dependencies' are not migrated to
null-safety yet:
- ${nonMigratedDirectDeps.join('\n - ')}
You may have to:
* Upgrade git and path dependencies manually,
* Upgrade to a newer SDK for newer SDK dependencies,
* Remove dependency_overrides, and/or,
* Find other packages to use.
''');
}
_showOfflineWarning();
}