Unverified Commit 410d9921 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Migrate emulators, packages, upgrade, and downgrade to null safety (#95712)

parent 18c59cdb
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:process/process.dart';
import '../base/common.dart';
......@@ -31,13 +29,13 @@ import '../version.dart';
class DowngradeCommand extends FlutterCommand {
DowngradeCommand({
bool verboseHelp = false,
PersistentToolState persistentToolState,
Logger logger,
ProcessManager processManager,
FlutterVersion flutterVersion,
Terminal terminal,
Stdio stdio,
FileSystem fileSystem,
PersistentToolState? persistentToolState,
Logger? logger,
ProcessManager? processManager,
FlutterVersion? flutterVersion,
Terminal? terminal,
Stdio? stdio,
FileSystem? fileSystem,
}) : _terminal = terminal,
_flutterVersion = flutterVersion,
_persistentToolState = persistentToolState,
......@@ -61,14 +59,14 @@ class DowngradeCommand extends FlutterCommand {
);
}
Terminal _terminal;
FlutterVersion _flutterVersion;
PersistentToolState _persistentToolState;
ProcessUtils _processUtils;
ProcessManager _processManager;
Logger _logger;
Stdio _stdio;
FileSystem _fileSystem;
Terminal? _terminal;
FlutterVersion? _flutterVersion;
PersistentToolState? _persistentToolState;
ProcessUtils? _processUtils;
ProcessManager? _processManager;
Logger? _logger;
Stdio? _stdio;
FileSystem? _fileSystem;
@override
String get description => 'Downgrade Flutter to the last active version for the current channel.';
......@@ -89,25 +87,26 @@ class DowngradeCommand extends FlutterCommand {
_flutterVersion ??= globals.flutterVersion;
_persistentToolState ??= globals.persistentToolState;
_processManager ??= globals.processManager;
_processUtils ??= ProcessUtils(processManager: _processManager, logger: _logger);
_processUtils ??= ProcessUtils(processManager: _processManager!, logger: _logger!);
_stdio ??= globals.stdio;
_fileSystem ??= globals.fs;
String workingDirectory = Cache.flutterRoot;
if (argResults.wasParsed('working-directory')) {
workingDirectory = stringArg('working-directory');
String workingDirectory = Cache.flutterRoot!;
if (argResults!.wasParsed('working-directory')) {
workingDirectory = stringArg('working-directory')!;
_flutterVersion = FlutterVersion(workingDirectory: workingDirectory);
}
final String currentChannel = _flutterVersion.channel;
final Channel channel = getChannelForName(currentChannel);
final String currentChannel = _flutterVersion!.channel;
final Channel? channel = getChannelForName(currentChannel);
if (channel == null) {
throwToolExit(
'Flutter is not currently on a known channel. Use "flutter channel <name>" '
'to switch to an official channel.',
);
}
final String lastFlutterVersion = _persistentToolState.lastActiveVersion(channel);
final String currentFlutterVersion = _flutterVersion.frameworkRevision;
final PersistentToolState persistentToolState = _persistentToolState!;
final String? lastFlutterVersion = persistentToolState.lastActiveVersion(channel);
final String? currentFlutterVersion = _flutterVersion?.frameworkRevision;
if (lastFlutterVersion == null || currentFlutterVersion == lastFlutterVersion) {
final String trailing = await _createErrorMessage(workingDirectory, channel);
throwToolExit(
......@@ -117,7 +116,8 @@ class DowngradeCommand extends FlutterCommand {
}
// Detect unknown versions.
final RunResult parseResult = await _processUtils.run(<String>[
final ProcessUtils processUtils = _processUtils!;
final RunResult parseResult = await processUtils.run(<String>[
'git', 'describe', '--tags', lastFlutterVersion,
], workingDirectory: workingDirectory);
if (parseResult.exitCode != 0) {
......@@ -126,25 +126,28 @@ class DowngradeCommand extends FlutterCommand {
final String humanReadableVersion = parseResult.stdout;
// If there is a terminal attached, prompt the user to confirm the downgrade.
if (_stdio.hasTerminal && boolArg('prompt')) {
_terminal.usesTerminalUi = true;
final String result = await _terminal.promptForCharInput(
final Stdio stdio = _stdio!;
final Terminal terminal = _terminal!;
final Logger logger = _logger!;
if (stdio.hasTerminal && boolArg('prompt')) {
terminal.usesTerminalUi = true;
final String result = await terminal.promptForCharInput(
const <String>['y', 'n'],
prompt: 'Downgrade flutter to version $humanReadableVersion?',
logger: _logger,
logger: logger,
);
if (result == 'n') {
return FlutterCommandResult.success();
}
} else {
_logger.printStatus('Downgrading Flutter to version $humanReadableVersion');
logger.printStatus('Downgrading Flutter to version $humanReadableVersion');
}
// To downgrade the tool, we perform a git checkout --hard, and then
// switch channels. The version recorded must have existed on that branch
// so this operation is safe.
try {
await _processUtils.run(
await processUtils.run(
<String>['git', 'reset', '--hard', lastFlutterVersion],
throwOnError: true,
workingDirectory: workingDirectory,
......@@ -158,7 +161,7 @@ class DowngradeCommand extends FlutterCommand {
);
}
try {
await _processUtils.run(
await processUtils.run(
<String>['git', 'checkout', currentChannel, '--'],
throwOnError: true,
workingDirectory: workingDirectory,
......@@ -172,7 +175,7 @@ class DowngradeCommand extends FlutterCommand {
);
}
await FlutterVersion.resetFlutterVersionFreshnessCheck();
_logger.printStatus('Success');
logger.printStatus('Success');
return FlutterCommandResult.success();
}
......@@ -183,11 +186,11 @@ class DowngradeCommand extends FlutterCommand {
if (channel == currentChannel) {
continue;
}
final String sha = _persistentToolState.lastActiveVersion(channel);
final String? sha = _persistentToolState?.lastActiveVersion(channel);
if (sha == null) {
continue;
}
final RunResult parseResult = await _processUtils.run(<String>[
final RunResult parseResult = await _processUtils!.run(<String>[
'git', 'describe', '--tags', sha,
], workingDirectory: workingDirectory);
if (parseResult.exitCode == 0) {
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:args/args.dart';
import '../base/common.dart';
import '../base/utils.dart';
......@@ -39,22 +39,22 @@ class EmulatorsCommand extends FlutterCommand {
@override
Future<FlutterCommandResult> runCommand() async {
if (globals.doctor.workflows.every((Workflow w) => !w.canListEmulators)) {
if (globals.doctor!.workflows.every((Workflow w) => !w.canListEmulators)) {
throwToolExit(
'Unable to find any emulator sources. Please ensure you have some\n'
'Android AVD images ${globals.platform.isMacOS ? 'or an iOS Simulator ' : ''}available.',
exitCode: 1);
}
if (argResults.wasParsed('launch')) {
final bool coldBoot = argResults.wasParsed('cold');
await _launchEmulator(stringArg('launch'), coldBoot: coldBoot);
} else if (argResults.wasParsed('create')) {
final ArgResults argumentResults = argResults!;
if (argumentResults.wasParsed('launch')) {
final bool coldBoot = argumentResults.wasParsed('cold');
await _launchEmulator(stringArg('launch')!, coldBoot: coldBoot);
} else if (argumentResults.wasParsed('create')) {
await _createEmulator(name: stringArg('name'));
} else {
final String searchText =
argResults.rest != null && argResults.rest.isNotEmpty
? argResults.rest.first
final String? searchText =
argumentResults.rest != null && argumentResults.rest.isNotEmpty
? argumentResults.rest.first
: null;
await _listEmulators(searchText);
}
......@@ -62,9 +62,9 @@ class EmulatorsCommand extends FlutterCommand {
return FlutterCommandResult.success();
}
Future<void> _launchEmulator(String id, {bool coldBoot}) async {
Future<void> _launchEmulator(String id, { required bool coldBoot }) async {
final List<Emulator> emulators =
await emulatorManager.getEmulatorsMatching(id);
await emulatorManager!.getEmulatorsMatching(id);
if (emulators.isEmpty) {
globals.printStatus("No emulator found that matches '$id'.");
......@@ -78,23 +78,26 @@ class EmulatorsCommand extends FlutterCommand {
}
}
Future<void> _createEmulator({ String name }) async {
Future<void> _createEmulator({ String? name }) async {
final CreateEmulatorResult createResult =
await emulatorManager.createEmulator(name: name);
await emulatorManager!.createEmulator(name: name);
if (createResult.success) {
globals.printStatus("Emulator '${createResult.emulatorName}' created successfully.");
} else {
globals.printStatus("Failed to create emulator '${createResult.emulatorName}'.\n");
globals.printStatus(createResult.error.trim());
final String? error = createResult.error;
if (error != null) {
globals.printStatus(error.trim());
}
_printAdditionalInfo();
}
}
Future<void> _listEmulators(String searchText) async {
Future<void> _listEmulators(String? searchText) async {
final List<Emulator> emulators = searchText == null
? await emulatorManager.getAllAvailableEmulators()
: await emulatorManager.getEmulatorsMatching(searchText);
? await emulatorManager!.getAllAvailableEmulators()
: await emulatorManager!.getEmulatorsMatching(searchText);
if (emulators.isEmpty) {
globals.printStatus('No emulators available.');
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:args/args.dart';
import '../base/common.dart';
......@@ -55,7 +53,7 @@ class PackagesCommand extends FlutterCommand {
String get category => FlutterCommandCategory.project;
@override
Future<FlutterCommandResult> runCommand() async => null;
Future<FlutterCommandResult> runCommand() async => FlutterCommandResult.fail();
}
class PackagesGetCommand extends FlutterCommand {
......@@ -79,15 +77,16 @@ class PackagesGetCommand extends FlutterCommand {
@override
String get invocation {
return '${runner.executableName} pub $name [<target directory>]';
return '${runner!.executableName} pub $name [<target directory>]';
}
/// The pub packages usage values are incorrect since these are calculated/sent
/// before pub get completes. This needs to be performed after dependency resolution.
@override
Future<CustomDimensions> get usageValues async {
final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null;
final String target = findProjectRoot(globals.fs, workingDirectory);
final ArgResults argumentResults = argResults!;
final String? workingDirectory = argumentResults.rest.length == 1 ? argumentResults.rest[0] : null;
final String? target = findProjectRoot(globals.fs, workingDirectory);
if (target == null) {
return const CustomDimensions();
}
......@@ -118,7 +117,7 @@ class PackagesGetCommand extends FlutterCommand {
Future<void> _runPubGet(String directory, FlutterProject flutterProject) async {
if (flutterProject.manifest.generateSyntheticPackage) {
final Environment environment = Environment(
artifacts: globals.artifacts,
artifacts: globals.artifacts!,
logger: globals.logger,
cacheDir: globals.cache.getRoot(),
engineVersion: globals.flutterVersion.engineRevision,
......@@ -159,12 +158,13 @@ class PackagesGetCommand extends FlutterCommand {
@override
Future<FlutterCommandResult> runCommand() async {
if (argResults.rest.length > 1) {
final ArgResults argumentResults = argResults!;
if (argumentResults.rest.length > 1) {
throwToolExit('Too many arguments.\n$usage');
}
final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null;
final String target = findProjectRoot(globals.fs, workingDirectory);
final String? workingDirectory = argumentResults.rest.length == 1 ? argumentResults.rest[0] : null;
final String? target = findProjectRoot(globals.fs, workingDirectory);
if (target == null) {
throwToolExit(
'Expected to find project root in '
......@@ -207,12 +207,12 @@ class PackagesTestCommand extends FlutterCommand {
@override
String get invocation {
return '${runner.executableName} pub test [<tests...>]';
return '${runner!.executableName} pub test [<tests...>]';
}
@override
Future<FlutterCommandResult> runCommand() async {
await pub.batch(<String>['run', 'test', ...argResults.rest], context: PubContext.runTest, retry: false);
await pub.batch(<String>['run', 'test', ...argResults!.rest], context: PubContext.runTest, retry: false);
return FlutterCommandResult.success();
}
}
......@@ -241,12 +241,12 @@ class PackagesForwardCommand extends FlutterCommand {
@override
String get invocation {
return '${runner.executableName} pub $_commandName [<arguments...>]';
return '${runner!.executableName} pub $_commandName [<arguments...>]';
}
@override
Future<FlutterCommandResult> runCommand() async {
final List<String> subArgs = argResults.rest.toList()
final List<String> subArgs = argResults!.rest.toList()
..removeWhere((String arg) => arg == '--');
await pub.interactively(<String>[_commandName, ...subArgs], stdio: globals.stdio);
return FlutterCommandResult.success();
......@@ -268,12 +268,12 @@ class PackagesPassthroughCommand extends FlutterCommand {
@override
String get invocation {
return '${runner.executableName} packages pub [<arguments...>]';
return '${runner!.executableName} packages pub [<arguments...>]';
}
@override
Future<FlutterCommandResult> runCommand() async {
await pub.interactively(argResults.rest, stdio: globals.stdio);
await pub.interactively(argResults!.rest, stdio: globals.stdio);
return FlutterCommandResult.success();
}
}
......@@ -298,14 +298,14 @@ class PackagesInteractiveGetCommand extends FlutterCommand {
@override
String get invocation {
return '${runner.executableName} pub $_commandName [<arguments...>]';
return '${runner!.executableName} pub $_commandName [<arguments...>]';
}
@override
Future<FlutterCommandResult> runCommand() async {
List<String> rest = argResults.rest;
List<String> rest = argResults!.rest;
final bool isHelp = rest.contains('-h') || rest.contains('--help');
String target;
String? target;
if (rest.length == 1 && (rest.single.contains('/') || rest.single.contains(r'\'))) {
// For historical reasons, if there is one argument to the command and it contains
// a multiple-component path (i.e. contains a slash) then we use that to determine
......@@ -316,7 +316,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand {
target = findProjectRoot(globals.fs);
}
FlutterProject flutterProject;
FlutterProject? flutterProject;
if (!isHelp) {
if (target == null) {
throwToolExit('Expected to find project root in current working directory.');
......@@ -325,7 +325,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand {
if (flutterProject.manifest.generateSyntheticPackage) {
final Environment environment = Environment(
artifacts: globals.artifacts,
artifacts: globals.artifacts!,
logger: globals.logger,
cacheDir: globals.cache.getRoot(),
engineVersion: globals.flutterVersion.engineRevision,
......@@ -351,7 +351,7 @@ class PackagesInteractiveGetCommand extends FlutterCommand {
directory: target,
stdio: globals.stdio,
touchesPackageConfig: !isHelp,
generateSyntheticPackage: flutterProject?.manifest?.generateSyntheticPackage ?? false,
generateSyntheticPackage: flutterProject?.manifest.generateSyntheticPackage ?? false,
);
await flutterProject?.regeneratePlatformSpecificTooling();
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:meta/meta.dart';
import '../base/common.dart';
......@@ -13,6 +11,7 @@ import '../base/process.dart';
import '../cache.dart';
import '../dart/pub.dart';
import '../globals.dart' as globals;
import '../persistent_tool_state.dart';
import '../runner/flutter_command.dart';
import '../version.dart';
......@@ -21,8 +20,8 @@ const String _flutterInstallDocs = 'https://flutter.dev/docs/get-started/install
class UpgradeCommand extends FlutterCommand {
UpgradeCommand({
@required bool verboseHelp,
UpgradeCommandRunner commandRunner,
required bool verboseHelp,
UpgradeCommandRunner? commandRunner,
})
: _commandRunner = commandRunner ?? UpgradeCommandRunner() {
argParser
......@@ -70,7 +69,7 @@ class UpgradeCommand extends FlutterCommand {
@override
Future<FlutterCommandResult> runCommand() {
_commandRunner.workingDirectory = stringArg('working-directory') ?? Cache.flutterRoot;
_commandRunner.workingDirectory = stringArg('working-directory') ?? Cache.flutterRoot!;
return _commandRunner.runCommand(
force: boolArg('force'),
continueFlow: boolArg('continue'),
......@@ -87,15 +86,15 @@ class UpgradeCommand extends FlutterCommand {
@visibleForTesting
class UpgradeCommandRunner {
String workingDirectory;
String? workingDirectory;
Future<FlutterCommandResult> runCommand({
@required bool force,
@required bool continueFlow,
@required bool testFlow,
@required GitTagVersion gitTagVersion,
@required FlutterVersion flutterVersion,
@required bool verifyOnly,
required bool force,
required bool continueFlow,
required bool testFlow,
required GitTagVersion gitTagVersion,
required FlutterVersion flutterVersion,
required bool verifyOnly,
}) async {
if (!continueFlow) {
await runCommandFirstHalf(
......@@ -112,11 +111,11 @@ class UpgradeCommandRunner {
}
Future<void> runCommandFirstHalf({
@required bool force,
@required GitTagVersion gitTagVersion,
@required FlutterVersion flutterVersion,
@required bool testFlow,
@required bool verifyOnly,
required bool force,
required GitTagVersion gitTagVersion,
required FlutterVersion flutterVersion,
required bool testFlow,
required bool verifyOnly,
}) async {
final FlutterVersion upstreamVersion = await fetchLatestVersion(localVersion: flutterVersion);
if (flutterVersion.frameworkRevision == upstreamVersion.frameworkRevision) {
......@@ -172,11 +171,11 @@ class UpgradeCommandRunner {
}
void recordState(FlutterVersion flutterVersion) {
final Channel channel = getChannelForName(flutterVersion.channel);
final Channel? channel = getChannelForName(flutterVersion.channel);
if (channel == null) {
return;
}
globals.persistentToolState.updateLastActiveVersion(flutterVersion.frameworkRevision, channel);
globals.persistentToolState!.updateLastActiveVersion(flutterVersion.frameworkRevision, channel);
}
Future<void> flutterUpgradeContinue() async {
......@@ -200,12 +199,13 @@ class UpgradeCommandRunner {
// re-entrantly with the `--continue` flag
Future<void> runCommandSecondHalf(FlutterVersion flutterVersion) async {
// Make sure the welcome message re-display is delayed until the end.
globals.persistentToolState.setShouldRedisplayWelcomeMessage(false);
final PersistentToolState persistentToolState = globals.persistentToolState!;
persistentToolState.setShouldRedisplayWelcomeMessage(false);
await precacheArtifacts();
await updatePackages(flutterVersion);
await runDoctor();
// Force the welcome message to re-display following the upgrade.
globals.persistentToolState.setShouldRedisplayWelcomeMessage(true);
persistentToolState.setShouldRedisplayWelcomeMessage(true);
}
Future<bool> hasUncommittedChanges() async {
......@@ -235,7 +235,8 @@ class UpgradeCommandRunner {
/// Exits tool if the tracking remote is not standard.
void verifyStandardRemote(FlutterVersion localVersion) {
// If repositoryUrl of the local version is null, exit
if (localVersion.repositoryUrl == null) {
final String? repositoryUrl = localVersion.repositoryUrl;
if (repositoryUrl == null) {
throwToolExit(
'Unable to upgrade Flutter: The tool could not determine the remote '
'upstream which is being tracked by the SDK.\n'
......@@ -244,7 +245,7 @@ class UpgradeCommandRunner {
}
// Strip `.git` suffix before comparing the remotes
final String trackingUrl = stripDotGit(localVersion.repositoryUrl);
final String trackingUrl = stripDotGit(repositoryUrl);
final String flutterGitUrl = stripDotGit(globals.flutterGit);
// Exempt the official flutter git SSH remote from this check
......@@ -287,18 +288,18 @@ class UpgradeCommandRunner {
// URLs without ".git" suffix will remain unaffected.
String stripDotGit(String url) {
final RegExp pattern = RegExp(r'(.*)(\.git)$');
final RegExpMatch match = pattern.firstMatch(url);
final RegExpMatch? match = pattern.firstMatch(url);
if (match == null) {
return url;
}
return match.group(1);
return match.group(1)!;
}
/// Returns the remote HEAD flutter version.
///
/// Exits tool if HEAD isn't pointing to a branch, or there is no upstream.
Future<FlutterVersion> fetchLatestVersion({
@required FlutterVersion localVersion,
required FlutterVersion localVersion,
}) async {
String revision;
try {
......@@ -380,14 +381,13 @@ class UpgradeCommandRunner {
Future<void> updatePackages(FlutterVersion flutterVersion) async {
globals.printStatus('');
globals.printStatus(flutterVersion.toString());
final String projectRoot = findProjectRoot(globals.fs);
final String? projectRoot = findProjectRoot(globals.fs);
if (projectRoot != null) {
globals.printStatus('');
await pub.get(
context: PubContext.pubUpgrade,
directory: projectRoot,
upgrade: true,
generateSyntheticPackage: false,
);
}
}
......
......@@ -101,7 +101,7 @@ abstract class Pub {
bool upgrade = false,
bool offline = false,
bool generateSyntheticPackage = false,
String flutterRootOverride,
String? flutterRootOverride,
bool checkUpToDate = false,
bool shouldSkipThirdPartyGenerator = true,
bool printProgress = true,
......@@ -135,7 +135,7 @@ abstract class Pub {
/// stdout/stderr stream of pub to the corresponding streams of this process.
Future<void> interactively(
List<String> arguments, {
String directory,
String? directory,
required io.Stdio stdio,
bool touchesPackageConfig = false,
bool generateSyntheticPackage = false,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment