diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 4b3c8bea51..2bed8a461b 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -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 timingLabelParts; + final List? 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 { /// The currently executing command (or sub-command). /// /// Will be `null` until the top-most command has begun execution. - static FlutterCommand get current => context.get(); + static FlutterCommand? get current => context.get(); /// The option name for a custom observatory port. static const String observatoryPortOption = 'observatory-port'; @@ -168,7 +165,7 @@ abstract class FlutterCommand extends Command { ); @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 { _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 { 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 { 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 { } 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? rest = argResults?.rest; + if (rest != null && rest.isNotEmpty) { + return rest.first; } return bundle.defaultMainPath; } @@ -290,12 +285,12 @@ abstract class FlutterCommand extends Command { /// 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 { /// The values of the `--filesystem-root` argument. /// /// This can be overridden by some of its subclasses. - List get fileSystemRoots => + List? get fileSystemRoots => argParser.options.containsKey(FlutterOptions.kFileSystemRoot) ? stringsArg(FlutterOptions.kFileSystemRoot) : null; @@ -320,7 +315,7 @@ abstract class FlutterCommand extends Command { /// /// 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 { } /// 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 { _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 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 { ); } - 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.'); - } - } - } else { - _ddsEnabled = boolArg('dds'); + 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'); } - 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 { /// 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 { /// 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 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 { 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 { _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 { /// 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 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 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 { /// 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: [ 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 { '(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 addEnableExperimentation({ @required bool hide }) { + void addEnableExperimentation({ required bool hide }) { argParser.addMultiOption( FlutterOptions.kEnableExperiment, help: @@ -810,7 +805,7 @@ abstract class FlutterCommand extends Command { ); } - 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 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 { } /// 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 { /// 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 { ]; 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 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 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 { /// /// Throws a [ToolExit] if the current set of options is not compatible with /// each other. - Future getBuildInfo({ BuildMode forcedBuildMode, File forcedTargetFile }) async { + Future 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 { } } - 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 { // 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 { 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 { } 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 { 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 { : []; 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 { ? 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 { /// The path to send to Google Analytics. Return null here to disable /// tracking of the command. - Future get usagePath async { + Future 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 { // 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 { && 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? webRendererDefine = _webRendererDartDefines[webRenderer]; + if (webRendererDefine != null) { + dartDefinesSet.addAll(webRendererDefine); + } return dartDefinesSet.toList(); } @@ -1207,7 +1207,7 @@ abstract class FlutterCommand extends Command { 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 { /// then call this method to execute the command /// rather than calling [runCommand] directly. @mustCallSuper - Future verifyThenRunCommand(String commandPath) async { + Future 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 { 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 { await generateLocalizationsSyntheticPackage( environment: environment, - buildSystem: globals.buildSystem, + buildSystem: globals.buildSystem!, ); await pub.get( @@ -1314,21 +1314,21 @@ abstract class FlutterCommand extends Command { /// 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> findAllTargetDevices({ + Future?> 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 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 { .toList(), '\n', ); - result.writeln(''); + result.writeln(); result.writeln(userMessages.flutterMissPlatformProjects( Device.devicesPlatformTypes(unsupportedDevices), )); @@ -1355,7 +1355,7 @@ abstract class FlutterCommand extends Command { 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 { /// /// If [includeUnsupportedDevices] is true, the tool does not filter /// the list by the current project support list. - Future findTargetDevice({ + Future findTargetDevice({ bool includeUnsupportedDevices = false, }) async { - List deviceList = await findAllTargetDevices(includeUnsupportedDevices: includeUnsupportedDevices); + List? 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 { @protected @mustCallSuper Future 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 { 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`. - List stringsArg(String name) => argResults[name] as List; + List stringsArg(String name) => argResults?[name] as List? ?? []; } /// 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 devices = await globals.deviceManager.getDevices(); + final List 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). diff --git a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart index 4030bbe757..396756808e 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command_runner.dart @@ -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 { 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 { 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 { 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 { usageException(error.message); } - Command command = commands[error.commands.first]; + Command? 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 { @override Future runCommand(ArgResults topLevelResults) async { - final Map contextOverrides = {}; + final Map contextOverrides = {}; // 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 { : 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({ + contextOverrides.addAll({ Artifacts: Artifacts.getLocalEngine(engineBuildPaths), }); } await context.run( - overrides: contextOverrides.map((Type type, dynamic value) { + overrides: contextOverrides.map((Type type, Object? value) { return MapEntry(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 { } // 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 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 { /// Get the root directories of the repo - the directories containing Dart packages. List 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 ['dev', 'examples', 'packages'].map((String item) { return globals.fs.path.join(root, item);