Unverified Commit a4e7b599 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Migrate flutter_command to null safety (#92871)

parent 19804929
......@@ -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 'package:args/command_runner.dart';
import 'package:file/file.dart';
......@@ -70,7 +68,7 @@ class FlutterCommandResult {
/// Optional data that can be appended to the timing event.
/// https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#timingLabel
/// Do not add PII.
final List<String> timingLabelParts;
final List<String>? timingLabelParts;
/// Optional epoch time when the command's non-interactive wait time is
/// complete during the command's execution. Use to measure user perceivable
......@@ -78,7 +76,7 @@ class FlutterCommandResult {
///
/// [FlutterCommand] will automatically measure and report the command's
/// complete time if not overridden.
final DateTime endTimeOverride;
final DateTime? endTimeOverride;
@override
String toString() {
......@@ -92,7 +90,6 @@ class FlutterCommandResult {
case ExitStatus.killed:
return 'killed';
}
return null; // dead code, remove with null safety migration
}
}
......@@ -131,7 +128,7 @@ abstract class FlutterCommand extends Command<void> {
/// The currently executing command (or sub-command).
///
/// Will be `null` until the top-most command has begun execution.
static FlutterCommand get current => context.get<FlutterCommand>();
static FlutterCommand? get current => context.get<FlutterCommand>();
/// The option name for a custom observatory port.
static const String observatoryPortOption = 'observatory-port';
......@@ -168,7 +165,7 @@ abstract class FlutterCommand extends Command<void> {
);
@override
FlutterCommandRunner get runner => super.runner as FlutterCommandRunner;
FlutterCommandRunner? get runner => super.runner as FlutterCommandRunner?;
bool _requiresPubspecYaml = false;
......@@ -197,7 +194,7 @@ abstract class FlutterCommand extends Command<void> {
_requiresPubspecYaml = true;
}
void usesWebOptions({ @required bool verboseHelp }) {
void usesWebOptions({ required bool verboseHelp }) {
argParser.addOption('web-hostname',
defaultsTo: 'localhost',
help:
......@@ -208,7 +205,6 @@ abstract class FlutterCommand extends Command<void> {
hide: !verboseHelp,
);
argParser.addOption('web-port',
defaultsTo: null,
help: 'The host port to serve the web application from. If not provided, the tool '
'will select a random open port on the host.',
hide: !verboseHelp,
......@@ -241,13 +237,11 @@ abstract class FlutterCommand extends Command<void> {
hide: !verboseHelp,
);
argParser.addFlag('web-allow-expose-url',
defaultsTo: false,
help: 'Enables daemon-to-editor requests (app.exposeUrl) for exposing URLs '
'when running on remote machines.',
hide: !verboseHelp,
);
argParser.addFlag('web-run-headless',
defaultsTo: false,
help: 'Launches the browser in headless mode. Currently only Chrome '
'supports this option.',
hide: !verboseHelp,
......@@ -278,11 +272,12 @@ abstract class FlutterCommand extends Command<void> {
}
String get targetFile {
if (argResults.wasParsed('target')) {
return stringArg('target');
if (argResults?.wasParsed('target') == true) {
return stringArg('target')!;
}
if (argResults.rest.isNotEmpty) {
return argResults.rest.first;
final List<String>? rest = argResults?.rest;
if (rest != null && rest.isNotEmpty) {
return rest.first;
}
return bundle.defaultMainPath;
}
......@@ -290,12 +285,12 @@ abstract class FlutterCommand extends Command<void> {
/// Path to the Dart's package config file.
///
/// This can be overridden by some of its subclasses.
String get packagesPath => globalResults['packages'] as String;
String? get packagesPath => globalResults?['packages'] as String?;
/// The value of the `--filesystem-scheme` argument.
///
/// This can be overridden by some of its subclasses.
String get fileSystemScheme =>
String? get fileSystemScheme =>
argParser.options.containsKey(FlutterOptions.kFileSystemScheme)
? stringArg(FlutterOptions.kFileSystemScheme)
: null;
......@@ -303,7 +298,7 @@ abstract class FlutterCommand extends Command<void> {
/// The values of the `--filesystem-root` argument.
///
/// This can be overridden by some of its subclasses.
List<String> get fileSystemRoots =>
List<String>? get fileSystemRoots =>
argParser.options.containsKey(FlutterOptions.kFileSystemRoot)
? stringsArg(FlutterOptions.kFileSystemRoot)
: null;
......@@ -320,7 +315,7 @@ abstract class FlutterCommand extends Command<void> {
///
/// The `hide` argument indicates whether or not to hide these options when
/// the user asks for help.
void usesFilesystemOptions({ @required bool hide }) {
void usesFilesystemOptions({ required bool hide }) {
argParser
..addOption('output-dill',
hide: hide,
......@@ -342,7 +337,7 @@ abstract class FlutterCommand extends Command<void> {
}
/// Adds options for connecting to the Dart VM observatory port.
void usesPortOptions({ @required bool verboseHelp }) {
void usesPortOptions({ required bool verboseHelp }) {
argParser.addOption(observatoryPortOption,
help: '(deprecated; use host-vmservice-port instead) '
'Listen to the given port for an observatory debugger connection.\n'
......@@ -364,7 +359,7 @@ abstract class FlutterCommand extends Command<void> {
_usesPortOption = true;
}
void addDevToolsOptions({@required bool verboseHelp}) {
void addDevToolsOptions({required bool verboseHelp}) {
argParser.addFlag(
kEnableDevTools,
hide: !verboseHelp,
......@@ -382,7 +377,7 @@ abstract class FlutterCommand extends Command<void> {
);
}
void addDdsOptions({@required bool verboseHelp}) {
void addDdsOptions({required bool verboseHelp}) {
argParser.addOption('dds-port',
help: 'When this value is provided, the Dart Development Service (DDS) will be '
'bound to the provided port.\n'
......@@ -407,55 +402,61 @@ abstract class FlutterCommand extends Command<void> {
);
}
bool _ddsEnabled;
bool get enableDds {
if (_ddsEnabled == null) {
if (argResults.wasParsed('disable-dds')) {
if (argResults.wasParsed('dds')) {
throwToolExit('The "--[no-]dds" and "--[no-]disable-dds" arguments are mutually exclusive. Only specify "--[no-]dds".');
}
_ddsEnabled = !boolArg('disable-dds');
// TODO(ianh): enable the following code once google3 is migrated away from --disable-dds (and add test to flutter_command_test.dart)
if (false) { // ignore: dead_code
if (_ddsEnabled) {
globals.printError('${globals.logger.terminal.warningMark} The "--no-disable-dds" argument is deprecated and redundant, and should be omitted.');
} else {
globals.printError('${globals.logger.terminal.warningMark} The "--disable-dds" argument is deprecated. Use "--no-dds" instead.');
}
late final bool enableDds = () {
bool ddsEnabled = false;
if (argResults?.wasParsed('disable-dds') == true) {
if (argResults?.wasParsed('dds') == true) {
throwToolExit(
'The "--[no-]dds" and "--[no-]disable-dds" arguments are mutually exclusive. Only specify "--[no-]dds".');
}
ddsEnabled = !boolArg('disable-dds');
// TODO(ianh): enable the following code once google3 is migrated away from --disable-dds (and add test to flutter_command_test.dart)
if (false) { // ignore: dead_code
if (ddsEnabled) {
globals.printError('${globals.logger.terminal
.warningMark} The "--no-disable-dds" argument is deprecated and redundant, and should be omitted.');
} else {
globals.printError('${globals.logger.terminal
.warningMark} The "--disable-dds" argument is deprecated. Use "--no-dds" instead.');
}
} else {
_ddsEnabled = boolArg('dds');
}
} else {
ddsEnabled = boolArg('dds');
}
return _ddsEnabled;
}
return ddsEnabled;
}();
bool get _hostVmServicePortProvided => argResults.wasParsed('observatory-port') ||
argResults.wasParsed('host-vmservice-port');
bool get _hostVmServicePortProvided => argResults?.wasParsed('observatory-port') == true ||
argResults?.wasParsed('host-vmservice-port') == true;
int _tryParseHostVmservicePort() {
final String? observatoryPort = stringArg('observatory-port');
final String? hostPort = stringArg('host-vmservice-port');
if (observatoryPort == null && hostPort == null) {
throwToolExit('Invalid port for `--observatory-port/--host-vmservice-port`');
}
try {
return int.parse(stringArg('observatory-port') ?? stringArg('host-vmservice-port'));
return int.parse((observatoryPort ?? hostPort)!);
} on FormatException catch (error) {
throwToolExit('Invalid port for `--observatory-port/--host-vmservice-port`: $error');
}
}
int get ddsPort {
if (!argResults.wasParsed('dds-port') && _hostVmServicePortProvided) {
if (argResults?.wasParsed('dds-port') != true && _hostVmServicePortProvided) {
// If an explicit DDS port is _not_ provided, use the host-vmservice-port for DDS.
return _tryParseHostVmservicePort();
} else if (argResults.wasParsed('dds-port')) {
} else if (argResults?.wasParsed('dds-port') == true) {
// If an explicit DDS port is provided, use dds-port for DDS.
return int.tryParse(stringArg('dds-port')) ?? 0;
return int.tryParse(stringArg('dds-port')!) ?? 0;
}
// Otherwise, DDS can bind to a random port.
return 0;
}
Uri get devToolsServerAddress {
if (argResults.wasParsed(kDevToolsServerAddress)) {
final Uri uri = Uri.tryParse(stringArg(kDevToolsServerAddress));
Uri? get devToolsServerAddress {
if (argResults?.wasParsed(kDevToolsServerAddress) == true) {
final Uri? uri = Uri.tryParse(stringArg(kDevToolsServerAddress)!);
if (uri != null && uri.host.isNotEmpty && uri.port != 0) {
return uri;
}
......@@ -470,19 +471,19 @@ abstract class FlutterCommand extends Command<void> {
/// specified.
///
/// If no port is set, returns null.
int get hostVmservicePort {
int? get hostVmservicePort {
if (!_usesPortOption || !_hostVmServicePortProvided) {
return null;
}
if (argResults.wasParsed('observatory-port') &&
argResults.wasParsed('host-vmservice-port')) {
if (argResults?.wasParsed('observatory-port') == true &&
argResults?.wasParsed('host-vmservice-port') == true) {
throwToolExit('Only one of "--observatory-port" and '
'"--host-vmservice-port" may be specified.');
}
// If DDS is enabled and no explicit DDS port is provided, use the
// host-vmservice-port for DDS instead and bind the VM service to a random
// port.
if (enableDds && !argResults.wasParsed('dds-port')) {
if (enableDds && argResults?.wasParsed('dds-port') != true) {
return null;
}
return _tryParseHostVmservicePort();
......@@ -491,12 +492,13 @@ abstract class FlutterCommand extends Command<void> {
/// Gets the vmservice port provided to in the 'device-vmservice-port' option.
///
/// If no port is set, returns null.
int get deviceVmservicePort {
if (!_usesPortOption || argResults['device-vmservice-port'] == null) {
int? get deviceVmservicePort {
final String? devicePort = stringArg('device-vmservice-port');
if (!_usesPortOption || devicePort == null) {
return null;
}
try {
return int.parse(stringArg('device-vmservice-port'));
return int.parse(devicePort);
} on FormatException catch (error) {
throwToolExit('Invalid port for `--device-vmservice-port`: $error');
}
......@@ -504,7 +506,6 @@ abstract class FlutterCommand extends Command<void> {
void addPublishPort({ bool enabledByDefault = true, bool verboseHelp = false }) {
argParser.addFlag('publish-port',
negatable: true,
hide: !verboseHelp,
help: 'Publish the VM service port over mDNS. Disable to prevent the '
'local network permission app dialog in debug and profile build modes (iOS devices only).',
......@@ -514,7 +515,7 @@ abstract class FlutterCommand extends Command<void> {
bool get disablePortPublication => !boolArg('publish-port');
void usesIpv6Flag({@required bool verboseHelp}) {
void usesIpv6Flag({required bool verboseHelp}) {
argParser.addFlag(ipv6Flag,
negatable: false,
help: 'Binds to IPv6 localhost instead of IPv4 when the flutter tool '
......@@ -525,7 +526,7 @@ abstract class FlutterCommand extends Command<void> {
_usesIpv6Flag = true;
}
bool get ipv6 => _usesIpv6Flag ? boolArg('ipv6') : null;
bool? get ipv6 => _usesIpv6Flag ? boolArg('ipv6') : null;
void usesBuildNumberOption() {
argParser.addOption('build-number',
......@@ -592,22 +593,20 @@ abstract class FlutterCommand extends Command<void> {
/// Whether this command should report null safety analytics.
bool get reportNullSafety => false;
Duration get deviceDiscoveryTimeout {
if (_deviceDiscoveryTimeout == null
&& argResults.options.contains(FlutterOptions.kDeviceTimeout)
&& argResults.wasParsed(FlutterOptions.kDeviceTimeout)) {
final int timeoutSeconds = int.tryParse(stringArg(FlutterOptions.kDeviceTimeout));
late final Duration? deviceDiscoveryTimeout = () {
if (argResults?.options.contains(FlutterOptions.kDeviceTimeout) == true
&& argResults?.wasParsed(FlutterOptions.kDeviceTimeout) == true) {
final int? timeoutSeconds = int.tryParse(stringArg(FlutterOptions.kDeviceTimeout)!);
if (timeoutSeconds == null) {
throwToolExit( 'Could not parse "--${FlutterOptions.kDeviceTimeout}" argument. It must be an integer.');
}
_deviceDiscoveryTimeout = Duration(seconds: timeoutSeconds);
return Duration(seconds: timeoutSeconds);
}
return _deviceDiscoveryTimeout;
}
Duration _deviceDiscoveryTimeout;
return null;
}();
void addBuildModeFlags({
@required bool verboseHelp,
required bool verboseHelp,
bool defaultToRelease = true,
bool excludeDebug = false,
bool excludeRelease = false,
......@@ -669,7 +668,7 @@ abstract class FlutterCommand extends Command<void> {
);
}
void addBundleSkSLPathOption({ @required bool hide }) {
void addBundleSkSLPathOption({ required bool hide }) {
argParser.addOption(FlutterOptions.kBundleSkSLPathOption,
help: 'A path to a file containing precompiled SkSL shaders generated '
'during "flutter run". These can be included in an application to '
......@@ -680,26 +679,24 @@ abstract class FlutterCommand extends Command<void> {
}
void addTreeShakeIconsFlag({
bool enabledByDefault
bool? enabledByDefault
}) {
argParser.addFlag('tree-shake-icons',
negatable: true,
defaultsTo: enabledByDefault
?? kIconTreeShakerEnabledDefault,
help: 'Tree shake icon fonts so that only glyphs used by the application remain.',
);
}
void addShrinkingFlag({ @required bool verboseHelp }) {
void addShrinkingFlag({ required bool verboseHelp }) {
argParser.addFlag('shrink',
negatable: true,
hide: !verboseHelp,
help: 'This flag has no effect. Code shrinking is always enabled in release builds. '
'To learn more, see: https://developer.android.com/studio/build/shrink-code'
);
}
void addNullSafetyModeOptions({ @required bool hide }) {
void addNullSafetyModeOptions({ required bool hide }) {
argParser.addFlag(FlutterOptions.kNullSafety,
help:
'Whether to override the inferred null safety mode. This allows null-safe '
......@@ -720,13 +717,12 @@ abstract class FlutterCommand extends Command<void> {
/// Enables support for the hidden options --extra-front-end-options and
/// --extra-gen-snapshot-options.
void usesExtraDartFlagOptions({ @required bool verboseHelp }) {
void usesExtraDartFlagOptions({ required bool verboseHelp }) {
argParser.addMultiOption(FlutterOptions.kExtraFrontEndOptions,
aliases: <String>[ kExtraFrontEndOptions ], // supported for historical reasons
help: 'A comma-separated list of additional command line arguments that will be passed directly to the Dart front end. '
'For example, "--${FlutterOptions.kExtraFrontEndOptions}=--enable-experiment=nonfunction-type-aliases".',
valueHelp: '--foo,--bar',
splitCommas: true,
hide: !verboseHelp,
);
argParser.addMultiOption(FlutterOptions.kExtraGenSnapshotOptions,
......@@ -735,7 +731,6 @@ abstract class FlutterCommand extends Command<void> {
'(Only used in "--profile" or "--release" builds.) '
'For example, "--${FlutterOptions.kExtraGenSnapshotOptions}=--no-strip".',
valueHelp: '--foo,--bar',
splitCommas: true,
hide: !verboseHelp,
);
}
......@@ -757,7 +752,7 @@ abstract class FlutterCommand extends Command<void> {
);
}
void addEnableExperimentation({ @required bool hide }) {
void addEnableExperimentation({ required bool hide }) {
argParser.addMultiOption(
FlutterOptions.kEnableExperiment,
help:
......@@ -810,7 +805,7 @@ abstract class FlutterCommand extends Command<void> {
);
}
void usesInitializeFromDillOption({ @required bool hide }) {
void usesInitializeFromDillOption({ required bool hide }) {
argParser.addOption(FlutterOptions.kInitializeFromDill,
help: 'Initializes the resident compiler with a specific kernel file instead of '
'the default cached location.',
......@@ -820,7 +815,6 @@ abstract class FlutterCommand extends Command<void> {
void addMultidexOption({ bool hide = false }) {
argParser.addFlag('multidex',
negatable: true,
defaultsTo: true,
help: 'When enabled, indicates that the app should be built with multidex support. This '
'flag adds the dependencies for multidex when the minimum android sdk is 20 or '
......@@ -829,7 +823,7 @@ abstract class FlutterCommand extends Command<void> {
}
/// Adds build options common to all of the desktop build commands.
void addCommonDesktopBuildOptions({ @required bool verboseHelp }) {
void addCommonDesktopBuildOptions({ required bool verboseHelp }) {
addBuildModeFlags(verboseHelp: verboseHelp);
addBuildPerformanceFile(hide: !verboseHelp);
addBundleSkSLPathOption(hide: !verboseHelp);
......@@ -850,7 +844,7 @@ abstract class FlutterCommand extends Command<void> {
/// explicitly specified.
///
/// Use [getBuildMode] to obtain the actual effective build mode.
BuildMode defaultBuildMode;
BuildMode defaultBuildMode = BuildMode.debug;
BuildMode getBuildMode() {
// No debug when _excludeDebug is true.
......@@ -866,7 +860,7 @@ abstract class FlutterCommand extends Command<void> {
];
if (modeFlags.where((bool flag) => flag).length > 1) {
throw UsageException('Only one of "--debug", "--profile", "--jit-release", '
'or "--release" can be specified.', null);
'or "--release" can be specified.', '');
}
if (debugResult) {
return BuildMode.debug;
......@@ -892,7 +886,7 @@ abstract class FlutterCommand extends Command<void> {
);
}
void usesTrackWidgetCreation({ bool hasEffect = true, @required bool verboseHelp }) {
void usesTrackWidgetCreation({ bool hasEffect = true, required bool verboseHelp }) {
argParser.addFlag(
'track-widget-creation',
hide: !hasEffect && !verboseHelp,
......@@ -905,7 +899,6 @@ abstract class FlutterCommand extends Command<void> {
void usesAnalyzeSizeFlag() {
argParser.addFlag(
FlutterOptions.kAnalyzeSize,
defaultsTo: false,
help: 'Whether to produce additional profile information for artifact output size. '
'This flag is only supported on "--release" builds. When building for Android, a single '
'ABI must be specified at a time with the "--target-platform" flag. When building for iOS, '
......@@ -928,11 +921,11 @@ abstract class FlutterCommand extends Command<void> {
///
/// Throws a [ToolExit] if the current set of options is not compatible with
/// each other.
Future<BuildInfo> getBuildInfo({ BuildMode forcedBuildMode, File forcedTargetFile }) async {
Future<BuildInfo> getBuildInfo({ BuildMode? forcedBuildMode, File? forcedTargetFile }) async {
final bool trackWidgetCreation = argParser.options.containsKey('track-widget-creation') &&
boolArg('track-widget-creation');
final String buildNumber = argParser.options.containsKey('build-number')
final String? buildNumber = argParser.options.containsKey('build-number')
? stringArg('build-number')
: null;
......@@ -962,7 +955,7 @@ abstract class FlutterCommand extends Command<void> {
}
}
String codeSizeDirectory;
String? codeSizeDirectory;
if (argParser.options.containsKey(FlutterOptions.kAnalyzeSize) && boolArg(FlutterOptions.kAnalyzeSize)) {
Directory directory = globals.fsUtils.getUniqueDirectory(
globals.fs.directory(getBuildDirectory()),
......@@ -980,13 +973,13 @@ abstract class FlutterCommand extends Command<void> {
// Explicitly check for `true` and `false` so that `null` results in not
// passing a flag. Examine the entrypoint file to determine if it
// is opted in or out.
final bool wasNullSafetyFlagParsed = argResults.wasParsed(FlutterOptions.kNullSafety);
final bool wasNullSafetyFlagParsed = argResults?.wasParsed(FlutterOptions.kNullSafety) == true;
if (!wasNullSafetyFlagParsed && (argParser.options.containsKey('target') || forcedTargetFile != null)) {
final File entrypointFile = forcedTargetFile ?? globals.fs.file(targetFile);
final LanguageVersion languageVersion = determineLanguageVersion(
entrypointFile,
packageConfig.packageOf(entrypointFile.absolute.uri),
Cache.flutterRoot,
Cache.flutterRoot!,
);
// Extra frontend options are only provided if explicitly
// requested.
......@@ -1011,7 +1004,7 @@ abstract class FlutterCommand extends Command<void> {
final bool dartObfuscation = argParser.options.containsKey(FlutterOptions.kDartObfuscationOption)
&& boolArg(FlutterOptions.kDartObfuscationOption);
final String splitDebugInfoPath = argParser.options.containsKey(FlutterOptions.kSplitDebugInfoOption)
final String? splitDebugInfoPath = argParser.options.containsKey(FlutterOptions.kSplitDebugInfoOption)
? stringArg(FlutterOptions.kSplitDebugInfoOption)
: null;
......@@ -1037,10 +1030,10 @@ abstract class FlutterCommand extends Command<void> {
}
final bool treeShakeIcons = argParser.options.containsKey('tree-shake-icons')
&& buildMode.isPrecompiled
&& buildMode.isPrecompiled == true
&& boolArg('tree-shake-icons');
final String bundleSkSLPath = argParser.options.containsKey(FlutterOptions.kBundleSkSLPathOption)
final String? bundleSkSLPath = argParser.options.containsKey(FlutterOptions.kBundleSkSLPathOption)
? stringArg(FlutterOptions.kBundleSkSLPathOption)
: null;
......@@ -1048,7 +1041,7 @@ abstract class FlutterCommand extends Command<void> {
throwToolExit('No SkSL shader bundle found at $bundleSkSLPath.');
}
final String performanceMeasurementFile = argParser.options.containsKey(FlutterOptions.kPerformanceMeasurementFile)
final String? performanceMeasurementFile = argParser.options.containsKey(FlutterOptions.kPerformanceMeasurementFile)
? stringArg(FlutterOptions.kPerformanceMeasurementFile)
: null;
......@@ -1057,7 +1050,7 @@ abstract class FlutterCommand extends Command<void> {
: <String>[];
if (argParser.options.containsKey('web-renderer')) {
dartDefines = updateDartDefines(dartDefines, stringArg('web-renderer'));
dartDefines = updateDartDefines(dartDefines, stringArg('web-renderer')!);
}
return BuildInfo(buildMode,
......@@ -1065,10 +1058,10 @@ abstract class FlutterCommand extends Command<void> {
? stringArg('flavor')
: null,
trackWidgetCreation: trackWidgetCreation,
extraFrontEndOptions: extraFrontEndOptions?.isNotEmpty ?? false
extraFrontEndOptions: extraFrontEndOptions.isNotEmpty
? extraFrontEndOptions
: null,
extraGenSnapshotOptions: extraGenSnapshotOptions?.isNotEmpty ?? false
extraGenSnapshotOptions: extraGenSnapshotOptions.isNotEmpty
? extraGenSnapshotOptions
: null,
fileSystemRoots: fileSystemRoots,
......@@ -1102,10 +1095,10 @@ abstract class FlutterCommand extends Command<void> {
/// The path to send to Google Analytics. Return null here to disable
/// tracking of the command.
Future<String> get usagePath async {
Future<String?> get usagePath async {
if (parent is FlutterCommand) {
final FlutterCommand commandParent = parent as FlutterCommand;
final String path = await commandParent.usagePath;
final FlutterCommand? commandParent = parent as FlutterCommand?;
final String? path = await commandParent?.usagePath;
// Don't report for parents that return null for usagePath.
return path == null ? null : '$path/$name';
} else {
......@@ -1133,15 +1126,19 @@ abstract class FlutterCommand extends Command<void> {
// Prints the welcome message if needed.
globals.flutterUsage.printWelcome();
_printDeprecationWarning();
final String commandPath = await usagePath;
_registerSignalHandlers(commandPath, startTime);
final String? commandPath = await usagePath;
if (commandPath != null) {
_registerSignalHandlers(commandPath, startTime);
}
FlutterCommandResult commandResult = FlutterCommandResult.fail();
try {
commandResult = await verifyThenRunCommand(commandPath);
} finally {
final DateTime endTime = globals.systemClock.now();
globals.printTrace(userMessages.flutterElapsedTime(name, getElapsedAsMilliseconds(endTime.difference(startTime))));
_sendPostUsage(commandPath, commandResult, startTime, endTime);
if (commandPath != null) {
_sendPostUsage(commandPath, commandResult, startTime, endTime);
}
}
},
);
......@@ -1167,7 +1164,10 @@ abstract class FlutterCommand extends Command<void> {
&& dartDefines.any((String d) => d.startsWith('FLUTTER_WEB_USE_SKIA='))) {
dartDefinesSet.removeWhere((String d) => d.startsWith('FLUTTER_WEB_USE_SKIA='));
}
dartDefinesSet.addAll(_webRendererDartDefines[webRenderer]);
final Iterable<String>? webRendererDefine = _webRendererDartDefines[webRenderer];
if (webRendererDefine != null) {
dartDefinesSet.addAll(webRendererDefine);
}
return dartDefinesSet.toList();
}
......@@ -1207,7 +1207,7 @@ abstract class FlutterCommand extends Command<void> {
if (commandResult.exitStatus != null)
getEnumName(commandResult.exitStatus),
if (commandResult.timingLabelParts?.isNotEmpty ?? false)
...commandResult.timingLabelParts,
...?commandResult.timingLabelParts,
];
final String label = labels
......@@ -1233,7 +1233,7 @@ abstract class FlutterCommand extends Command<void> {
/// then call this method to execute the command
/// rather than calling [runCommand] directly.
@mustCallSuper
Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) async {
Future<FlutterCommandResult> verifyThenRunCommand(String? commandPath) async {
// Populate the cache. We call this before pub get below so that the
// sky_engine package is available in the flutter cache for pub to find.
if (shouldUpdateCache) {
......@@ -1249,7 +1249,7 @@ abstract class FlutterCommand extends Command<void> {
if (shouldRunPub) {
final FlutterProject project = FlutterProject.current();
final Environment environment = Environment(
artifacts: globals.artifacts,
artifacts: globals.artifacts!,
logger: globals.logger,
cacheDir: globals.cache.getRoot(),
engineVersion: globals.flutterVersion.engineRevision,
......@@ -1264,7 +1264,7 @@ abstract class FlutterCommand extends Command<void> {
await generateLocalizationsSyntheticPackage(
environment: environment,
buildSystem: globals.buildSystem,
buildSystem: globals.buildSystem!,
);
await pub.get(
......@@ -1314,21 +1314,21 @@ abstract class FlutterCommand extends Command<void> {
/// devices and criteria entered by the user on the command line.
/// If no device can be found that meets specified criteria,
/// then print an error message and return null.
Future<List<Device>> findAllTargetDevices({
Future<List<Device>?> findAllTargetDevices({
bool includeUnsupportedDevices = false,
}) async {
if (!globals.doctor.canLaunchAnything) {
if (!globals.doctor!.canLaunchAnything) {
globals.printError(userMessages.flutterNoDevelopmentDevice);
return null;
}
final DeviceManager deviceManager = globals.deviceManager;
final DeviceManager deviceManager = globals.deviceManager!;
List<Device> devices = await deviceManager.findTargetDevices(
includeUnsupportedDevices ? null : FlutterProject.current(),
timeout: deviceDiscoveryTimeout,
);
if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) {
globals.printStatus(userMessages.flutterNoMatchingDevice(deviceManager.specifiedDeviceId));
globals.printStatus(userMessages.flutterNoMatchingDevice(deviceManager.specifiedDeviceId!));
return null;
} else if (devices.isEmpty) {
if (deviceManager.hasSpecifiedAllDevices) {
......@@ -1346,7 +1346,7 @@ abstract class FlutterCommand extends Command<void> {
.toList(),
'\n',
);
result.writeln('');
result.writeln();
result.writeln(userMessages.flutterMissPlatformProjects(
Device.devicesPlatformTypes(unsupportedDevices),
));
......@@ -1355,7 +1355,7 @@ abstract class FlutterCommand extends Command<void> {
return null;
} else if (devices.length > 1 && !deviceManager.hasSpecifiedAllDevices) {
if (deviceManager.hasSpecifiedDeviceId) {
globals.printStatus(userMessages.flutterFoundSpecifiedDevices(devices.length, deviceManager.specifiedDeviceId));
globals.printStatus(userMessages.flutterFoundSpecifiedDevices(devices.length, deviceManager.specifiedDeviceId!));
} else {
globals.printStatus(userMessages.flutterSpecifyDeviceWithAllOption);
devices = await deviceManager.getAllConnectedDevices();
......@@ -1374,16 +1374,16 @@ abstract class FlutterCommand extends Command<void> {
///
/// If [includeUnsupportedDevices] is true, the tool does not filter
/// the list by the current project support list.
Future<Device> findTargetDevice({
Future<Device?> findTargetDevice({
bool includeUnsupportedDevices = false,
}) async {
List<Device> deviceList = await findAllTargetDevices(includeUnsupportedDevices: includeUnsupportedDevices);
List<Device>? deviceList = await findAllTargetDevices(includeUnsupportedDevices: includeUnsupportedDevices);
if (deviceList == null) {
return null;
}
if (deviceList.length > 1) {
globals.printStatus(userMessages.flutterSpecifyDevice);
deviceList = await globals.deviceManager.getAllConnectedDevices();
deviceList = await globals.deviceManager!.getAllConnectedDevices();
globals.printStatus('');
await Device.printDevices(deviceList, globals.logger);
return null;
......@@ -1394,7 +1394,7 @@ abstract class FlutterCommand extends Command<void> {
@protected
@mustCallSuper
Future<void> validateCommand() async {
if (_requiresPubspecYaml && !globalResults.wasParsed('packages')) {
if (_requiresPubspecYaml && globalResults?.wasParsed('packages') != true) {
// Don't expect a pubspec.yaml file if the user passed in an explicit .packages file path.
// If there is no pubspec in the current directory, look in the parent
......@@ -1433,23 +1433,23 @@ abstract class FlutterCommand extends Command<void> {
description,
'',
'Global options:',
runner.argParser.usage,
'${runner?.argParser.usage}',
'',
usageWithoutDescription,
].join('\n');
return help;
}
ApplicationPackageFactory applicationPackages;
ApplicationPackageFactory? applicationPackages;
/// Gets the parsed command-line option named [name] as `bool`.
bool boolArg(String name) => argResults[name] as bool;
bool boolArg(String name) => argResults?[name] as bool? ?? false;
/// Gets the parsed command-line option named [name] as `String`.
String stringArg(String name) => argResults[name] as String;
String? stringArg(String name) => argResults?[name] as String?;
/// Gets the parsed command-line option named [name] as `List<String>`.
List<String> stringsArg(String name) => argResults[name] as List<String>;
List<String> stringsArg(String name) => argResults?[name] as List<String>? ?? <String>[];
}
/// A mixin which applies an implementation of [requiredArtifacts] that only
......@@ -1460,7 +1460,7 @@ mixin DeviceBasedDevelopmentArtifacts on FlutterCommand {
// If there are no attached devices, use the default configuration.
// Otherwise, only add development artifacts which correspond to a
// connected device.
final List<Device> devices = await globals.deviceManager.getDevices();
final List<Device> devices = await globals.deviceManager!.getDevices();
if (devices.isEmpty) {
return super.requiredArtifacts;
}
......@@ -1469,7 +1469,7 @@ mixin DeviceBasedDevelopmentArtifacts on FlutterCommand {
};
for (final Device device in devices) {
final TargetPlatform targetPlatform = await device.targetPlatform;
final DevelopmentArtifact developmentArtifact = artifactFromTargetPlatform(targetPlatform);
final DevelopmentArtifact? developmentArtifact = artifactFromTargetPlatform(targetPlatform);
if (developmentArtifact != null) {
artifacts.add(developmentArtifact);
}
......@@ -1481,7 +1481,7 @@ mixin DeviceBasedDevelopmentArtifacts on FlutterCommand {
// Returns the development artifact for the target platform, or null
// if none is supported
@protected
DevelopmentArtifact artifactFromTargetPlatform(TargetPlatform targetPlatform) {
DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) {
switch (targetPlatform) {
case TargetPlatform.android:
case TargetPlatform.android_arm:
......@@ -1518,7 +1518,6 @@ DevelopmentArtifact artifactFromTargetPlatform(TargetPlatform targetPlatform) {
}
return null;
}
return null;
}
/// Returns true if s is either null, empty or is solely made of whitespace characters (as defined by String.trim).
......
......@@ -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 'package:args/command_runner.dart';
import 'package:completion/completion.dart';
......@@ -45,14 +43,12 @@ class FlutterCommandRunner extends CommandRunner<void> {
argParser.addFlag('prefixed-errors',
negatable: false,
help: 'Causes lines sent to stderr to be prefixed with "ERROR:".',
hide: !verboseHelp,
defaultsTo: false);
hide: !verboseHelp);
argParser.addFlag('quiet',
negatable: false,
hide: !verboseHelp,
help: 'Reduce the amount of output from some commands.');
argParser.addFlag('wrap',
negatable: true,
hide: !verboseHelp,
help: 'Toggles output word wrapping, regardless of whether or not the output is a terminal.',
defaultsTo: true);
......@@ -60,8 +56,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
hide: !verboseHelp,
help: 'Sets the output wrap column. If not set, uses the width of the terminal. No '
'wrapping occurs if not writing to a terminal. Use "--no-wrap" to turn off wrapping '
'when connected to a terminal.',
defaultsTo: null);
'when connected to a terminal.');
argParser.addOption('device-id',
abbr: 'd',
help: 'Target device id or name (prefixes allowed).');
......@@ -73,12 +68,10 @@ class FlutterCommandRunner extends CommandRunner<void> {
hide: !verboseHelp,
help: 'When used with the "--version" flag, outputs the information using JSON.');
argParser.addFlag('color',
negatable: true,
hide: !verboseHelp,
help: 'Whether to use terminal colors (requires support for ANSI escape sequences).',
defaultsTo: true);
argParser.addFlag('version-check',
negatable: true,
defaultsTo: true,
hide: !verboseHelp,
help: 'Allow Flutter to check for updates when this command runs.');
......@@ -158,12 +151,12 @@ class FlutterCommandRunner extends CommandRunner<void> {
usageException(error.message);
}
Command<void> command = commands[error.commands.first];
Command<void>? command = commands[error.commands.first];
for (final String commandName in error.commands.skip(1)) {
command = command.subcommands[commandName];
command = command?.subcommands[commandName];
}
command.usageException(error.message);
command!.usageException(error.message);
}
}
......@@ -184,12 +177,12 @@ class FlutterCommandRunner extends CommandRunner<void> {
@override
Future<void> runCommand(ArgResults topLevelResults) async {
final Map<Type, dynamic> contextOverrides = <Type, dynamic>{};
final Map<Type, Object?> contextOverrides = <Type, Object?>{};
// Don't set wrapColumns unless the user said to: if it's set, then all
// wrapping will occur at this width explicitly, and won't adapt if the
// terminal size changes during a run.
int wrapColumn;
int? wrapColumn;
if (topLevelResults.wasParsed('wrap-column')) {
try {
wrapColumn = int.parse(topLevelResults['wrap-column'] as String);
......@@ -208,53 +201,53 @@ class FlutterCommandRunner extends CommandRunner<void> {
: globals.stdio.terminalColumns != null && topLevelResults['wrap'] as bool;
contextOverrides[OutputPreferences] = OutputPreferences(
wrapText: useWrapping,
showColor: topLevelResults['color'] as bool,
showColor: topLevelResults['color'] as bool?,
wrapColumn: wrapColumn,
);
if (topLevelResults['show-test-device'] as bool ||
if ((topLevelResults['show-test-device'] as bool?) == true ||
topLevelResults['device-id'] == FlutterTesterDevices.kTesterDeviceId) {
FlutterTesterDevices.showFlutterTesterDevice = true;
}
if (topLevelResults['show-web-server-device'] as bool ||
if ((topLevelResults['show-web-server-device'] as bool?) == true ||
topLevelResults['device-id'] == WebServerDevice.kWebServerDeviceId) {
WebServerDevice.showWebServerDevice = true;
}
// Set up the tooling configuration.
final EngineBuildPaths engineBuildPaths = await globals.localEngineLocator.findEnginePath(
topLevelResults['local-engine-src-path'] as String,
topLevelResults['local-engine'] as String,
topLevelResults['packages'] as String,
final EngineBuildPaths? engineBuildPaths = await globals.localEngineLocator?.findEnginePath(
topLevelResults['local-engine-src-path'] as String?,
topLevelResults['local-engine'] as String?,
topLevelResults['packages'] as String?,
);
if (engineBuildPaths != null) {
contextOverrides.addAll(<Type, dynamic>{
contextOverrides.addAll(<Type, Object?>{
Artifacts: Artifacts.getLocalEngine(engineBuildPaths),
});
}
await context.run<void>(
overrides: contextOverrides.map<Type, Generator>((Type type, dynamic value) {
overrides: contextOverrides.map<Type, Generator>((Type type, Object? value) {
return MapEntry<Type, Generator>(type, () => value);
}),
body: () async {
globals.logger.quiet = topLevelResults['quiet'] as bool;
globals.logger.quiet = (topLevelResults['quiet'] as bool?) == true;
if (globals.platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
await globals.cache.lock();
}
if (topLevelResults['suppress-analytics'] as bool) {
if ((topLevelResults['suppress-analytics'] as bool?) == true) {
globals.flutterUsage.suppressAnalytics = true;
}
globals.flutterVersion.ensureVersionFile();
final bool machineFlag = topLevelResults['machine'] as bool;
final bool machineFlag = topLevelResults['machine'] as bool? ?? false;
final bool ci = await globals.botDetector.isRunningOnBot;
final bool redirectedCompletion = !globals.stdio.hasTerminal &&
(topLevelResults.command?.name ?? '').endsWith('-completion');
final bool isMachine = machineFlag || ci || redirectedCompletion;
final bool versionCheckFlag = topLevelResults['version-check'] as bool;
final bool versionCheckFlag = topLevelResults['version-check'] as bool? ?? false;
final bool explicitVersionCheckPassed = topLevelResults.wasParsed('version-check') && versionCheckFlag;
if (topLevelResults.command?.name != 'upgrade' &&
......@@ -263,16 +256,16 @@ class FlutterCommandRunner extends CommandRunner<void> {
}
// See if the user specified a specific device.
globals.deviceManager.specifiedDeviceId = topLevelResults['device-id'] as String;
globals.deviceManager?.specifiedDeviceId = topLevelResults['device-id'] as String?;
if (topLevelResults['version'] as bool) {
if ((topLevelResults['version'] as bool?) == true) {
globals.flutterUsage.sendCommand('version');
globals.flutterVersion.fetchTagsAndUpdate();
String status;
if (machineFlag) {
final Map<String, Object> jsonOut = globals.flutterVersion.toJson();
if (jsonOut != null) {
jsonOut['flutterRoot'] = Cache.flutterRoot;
jsonOut['flutterRoot'] = Cache.flutterRoot!;
}
status = const JsonEncoder.withIndent(' ').convert(jsonOut);
} else {
......@@ -292,7 +285,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
/// Get the root directories of the repo - the directories containing Dart packages.
List<String> getRepoRoots() {
final String root = globals.fs.path.absolute(Cache.flutterRoot);
final String root = globals.fs.path.absolute(Cache.flutterRoot!);
// not bin, and not the root
return <String>['dev', 'examples', 'packages'].map<String>((String item) {
return globals.fs.path.join(root, item);
......
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