[flutter_tool] partial null safety migration of tool source code (#105798)

This commit is contained in:
Jonah Williams 2022-06-15 13:02:07 -07:00 committed by GitHub
parent a7ddb9b64e
commit 92034482f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 1932 additions and 2025 deletions

View File

@ -339,6 +339,7 @@ Future<void> _runGeneralToolTests() async {
_toolsPath, _toolsPath,
testPaths: <String>[path.join('test', 'general.shard')], testPaths: <String>[path.join('test', 'general.shard')],
enableFlutterToolAsserts: false, enableFlutterToolAsserts: false,
// Detect unit test time regressions (poor time delay handling, etc). // Detect unit test time regressions (poor time delay handling, etc).
// This overrides the 15 minute default for tools tests. // This overrides the 15 minute default for tools tests.
// See the README.md and dart_test.yaml files in the flutter_tools package. // See the README.md and dart_test.yaml files in the flutter_tools package.

View File

@ -2,10 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:meta/meta.dart';
import 'runner.dart' as runner; import 'runner.dart' as runner;
import 'src/artifacts.dart'; import 'src/artifacts.dart';
import 'src/base/context.dart'; import 'src/base/context.dart';
@ -110,7 +106,7 @@ Future<void> main(List<String> args) async {
// devtools source code. // devtools source code.
DevtoolsLauncher: () => DevtoolsServerLauncher( DevtoolsLauncher: () => DevtoolsServerLauncher(
processManager: globals.processManager, processManager: globals.processManager,
dartExecutable: globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, dartExecutable: globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path,
logger: globals.logger, logger: globals.logger,
botDetector: globals.botDetector, botDetector: globals.botDetector,
), ),
@ -134,8 +130,8 @@ Future<void> main(List<String> args) async {
} }
List<FlutterCommand> generateCommands({ List<FlutterCommand> generateCommands({
@required bool verboseHelp, required bool verboseHelp,
@required bool verbose, required bool verbose,
}) => <FlutterCommand>[ }) => <FlutterCommand>[
AnalyzeCommand( AnalyzeCommand(
verboseHelp: verboseHelp, verboseHelp: verboseHelp,
@ -144,7 +140,7 @@ List<FlutterCommand> generateCommands({
processManager: globals.processManager, processManager: globals.processManager,
logger: globals.logger, logger: globals.logger,
terminal: globals.terminal, terminal: globals.terminal,
artifacts: globals.artifacts, artifacts: globals.artifacts!,
), ),
AssembleCommand(verboseHelp: verboseHelp, buildSystem: globals.buildSystem), AssembleCommand(verboseHelp: verboseHelp, buildSystem: globals.buildSystem),
AttachCommand(verboseHelp: verboseHelp), AttachCommand(verboseHelp: verboseHelp),
@ -210,9 +206,9 @@ List<FlutterCommand> generateCommands({
/// Our logger class hierarchy and runtime requirements are overly complicated. /// Our logger class hierarchy and runtime requirements are overly complicated.
class LoggerFactory { class LoggerFactory {
LoggerFactory({ LoggerFactory({
@required Terminal terminal, required Terminal terminal,
@required Stdio stdio, required Stdio stdio,
@required OutputPreferences outputPreferences, required OutputPreferences outputPreferences,
StopwatchFactory stopwatchFactory = const StopwatchFactory(), StopwatchFactory stopwatchFactory = const StopwatchFactory(),
}) : _terminal = terminal, }) : _terminal = terminal,
_stdio = stdio, _stdio = stdio,
@ -226,11 +222,11 @@ class LoggerFactory {
/// Create the appropriate logger for the current platform and configuration. /// Create the appropriate logger for the current platform and configuration.
Logger createLogger({ Logger createLogger({
@required bool verbose, required bool verbose,
@required bool prefixedErrors, required bool prefixedErrors,
@required bool machine, required bool machine,
@required bool daemon, required bool daemon,
@required bool windows, required bool windows,
}) { }) {
Logger logger; Logger logger;
if (windows) { if (windows) {

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
@ -31,9 +31,9 @@ Future<int> run(
bool muteCommandLogging = false, bool muteCommandLogging = false,
bool verbose = false, bool verbose = false,
bool verboseHelp = false, bool verboseHelp = false,
bool reportCrashes, bool? reportCrashes,
String flutterVersion, String? flutterVersion,
Map<Type, Generator> overrides, Map<Type, Generator>? overrides,
}) async { }) async {
if (muteCommandLogging) { if (muteCommandLogging) {
// Remove the verbose option; for help and doctor, users don't need to see // Remove the verbose option; for help and doctor, users don't need to see
@ -55,8 +55,8 @@ Future<int> run(
); );
String getVersion() => flutterVersion ?? globals.flutterVersion.getVersionString(redactUnknownBranches: true); String getVersion() => flutterVersion ?? globals.flutterVersion.getVersionString(redactUnknownBranches: true);
Object firstError; Object? firstError;
StackTrace firstStackTrace; StackTrace? firstStackTrace;
return runZoned<Future<int>>(() async { return runZoned<Future<int>>(() async {
try { try {
await runner.run(args); await runner.run(args);
@ -74,7 +74,7 @@ Future<int> run(
// This catches all exceptions to send to crash logging, etc. // This catches all exceptions to send to crash logging, etc.
firstError = error; firstError = error;
firstStackTrace = stackTrace; firstStackTrace = stackTrace;
return _handleToolError(error, stackTrace, verbose, args, reportCrashes, getVersion); return _handleToolError(error, stackTrace, verbose, args, reportCrashes!, getVersion);
} }
}, onError: (Object error, StackTrace stackTrace) async { // ignore: deprecated_member_use }, onError: (Object error, StackTrace stackTrace) async { // ignore: deprecated_member_use
// If sending a crash report throws an error into the zone, we don't want // If sending a crash report throws an error into the zone, we don't want
@ -82,14 +82,14 @@ Future<int> run(
// to send the original error that triggered the crash report. // to send the original error that triggered the crash report.
firstError ??= error; firstError ??= error;
firstStackTrace ??= stackTrace; firstStackTrace ??= stackTrace;
await _handleToolError(firstError, firstStackTrace, verbose, args, reportCrashes, getVersion); await _handleToolError(firstError!, firstStackTrace, verbose, args, reportCrashes!, getVersion);
}); });
}, overrides: overrides); }, overrides: overrides);
} }
Future<int> _handleToolError( Future<int> _handleToolError(
dynamic error, Object error,
StackTrace stackTrace, StackTrace? stackTrace,
bool verbose, bool verbose,
List<String> args, List<String> args,
bool reportCrashes, bool reportCrashes,
@ -102,7 +102,7 @@ Future<int> _handleToolError(
return _exit(64); return _exit(64);
} else if (error is ToolExit) { } else if (error is ToolExit) {
if (error.message != null) { if (error.message != null) {
globals.printError(error.message); globals.printError(error.message!);
} }
if (verbose) { if (verbose) {
globals.printError('\n$stackTrace\n'); globals.printError('\n$stackTrace\n');
@ -138,7 +138,7 @@ Future<int> _handleToolError(
); );
await crashReportSender.sendReport( await crashReportSender.sendReport(
error: error, error: error,
stackTrace: stackTrace, stackTrace: stackTrace!,
getFlutterVersion: getFlutterVersion, getFlutterVersion: getFlutterVersion,
command: args.join(' '), command: args.join(' '),
); );
@ -159,17 +159,17 @@ Future<int> _handleToolError(
final CrashDetails details = CrashDetails( final CrashDetails details = CrashDetails(
command: _crashCommand(args), command: _crashCommand(args),
error: error, error: error,
stackTrace: stackTrace, stackTrace: stackTrace!,
doctorText: doctorText, doctorText: doctorText,
); );
final File file = await _createLocalCrashReport(details); final File file = await _createLocalCrashReport(details);
await globals.crashReporter.informUser(details, file); await globals.crashReporter!.informUser(details, file);
return _exit(1); return _exit(1);
// This catch catches all exceptions to ensure the message below is printed. // This catch catches all exceptions to ensure the message below is printed.
} catch (error) { // ignore: avoid_catches_without_on_clauses } catch (error, st) { // ignore: avoid_catches_without_on_clauses
globals.stdio.stderrWrite( globals.stdio.stderrWrite(
'Unable to generate crash report due to secondary error: $error\n' 'Unable to generate crash report due to secondary error: $error\n$st\n'
'${globals.userMessages.flutterToolBugInstructions}\n', '${globals.userMessages.flutterToolBugInstructions}\n',
); );
// Any exception thrown here (including one thrown by `_exit()`) will // Any exception thrown here (including one thrown by `_exit()`) will
@ -241,7 +241,7 @@ Future<int> _exit(int code) async {
} }
// Run shutdown hooks before flushing logs // Run shutdown hooks before flushing logs
await globals.shutdownHooks.runShutdownHooks(); await globals.shutdownHooks!.runShutdownHooks();
final Completer<void> completer = Completer<void>(); final Completer<void> completer = Completer<void>();

View File

@ -271,7 +271,7 @@ class AndroidValidator extends DoctorValidator {
/// SDK have been accepted. /// SDK have been accepted.
class AndroidLicenseValidator extends DoctorValidator { class AndroidLicenseValidator extends DoctorValidator {
AndroidLicenseValidator({ AndroidLicenseValidator({
required AndroidSdk androidSdk, required AndroidSdk? androidSdk,
required Platform platform, required Platform platform,
required OperatingSystemUtils operatingSystemUtils, required OperatingSystemUtils operatingSystemUtils,
required FileSystem fileSystem, required FileSystem fileSystem,
@ -291,7 +291,7 @@ class AndroidLicenseValidator extends DoctorValidator {
_userMessages = userMessages, _userMessages = userMessages,
super('Android license subvalidator'); super('Android license subvalidator');
final AndroidSdk _androidSdk; final AndroidSdk? _androidSdk;
final AndroidStudio? _androidStudio; final AndroidStudio? _androidStudio;
final Stdio _stdio; final Stdio _stdio;
final OperatingSystemUtils _operatingSystemUtils; final OperatingSystemUtils _operatingSystemUtils;
@ -309,13 +309,13 @@ class AndroidLicenseValidator extends DoctorValidator {
final List<ValidationMessage> messages = <ValidationMessage>[]; final List<ValidationMessage> messages = <ValidationMessage>[];
// Match pre-existing early termination behavior // Match pre-existing early termination behavior
if (_androidSdk == null || _androidSdk.latestVersion == null || if (_androidSdk == null || _androidSdk?.latestVersion == null ||
_androidSdk.validateSdkWellFormed().isNotEmpty || _androidSdk!.validateSdkWellFormed().isNotEmpty ||
! await _checkJavaVersionNoOutput()) { ! await _checkJavaVersionNoOutput()) {
return ValidationResult(ValidationType.missing, messages); return ValidationResult(ValidationType.missing, messages);
} }
final String sdkVersionText = _userMessages.androidStatusInfo(_androidSdk.latestVersion!.buildToolsVersionName); final String sdkVersionText = _userMessages.androidStatusInfo(_androidSdk!.latestVersion!.buildToolsVersionName);
// Check for licenses. // Check for licenses.
switch (await licensesAccepted) { switch (await licensesAccepted) {
@ -392,8 +392,8 @@ class AndroidLicenseValidator extends DoctorValidator {
try { try {
final Process process = await _processManager.start( final Process process = await _processManager.start(
<String>[_androidSdk.sdkManagerPath!, '--licenses'], <String>[_androidSdk!.sdkManagerPath!, '--licenses'],
environment: _androidSdk.sdkManagerEnv, environment: _androidSdk!.sdkManagerEnv,
); );
process.stdin.write('n\n'); process.stdin.write('n\n');
// We expect logcat streams to occasionally contain invalid utf-8, // We expect logcat streams to occasionally contain invalid utf-8,
@ -432,8 +432,8 @@ class AndroidLicenseValidator extends DoctorValidator {
try { try {
final Process process = await _processManager.start( final Process process = await _processManager.start(
<String>[_androidSdk.sdkManagerPath!, '--licenses'], <String>[_androidSdk!.sdkManagerPath!, '--licenses'],
environment: _androidSdk.sdkManagerEnv, environment: _androidSdk!.sdkManagerEnv,
); );
// The real stdin will never finish streaming. Pipe until the child process // The real stdin will never finish streaming. Pipe until the child process
@ -463,7 +463,7 @@ class AndroidLicenseValidator extends DoctorValidator {
return exitCode == 0; return exitCode == 0;
} on ProcessException catch (e) { } on ProcessException catch (e) {
throwToolExit(_userMessages.androidCannotRunSdkManager( throwToolExit(_userMessages.androidCannotRunSdkManager(
_androidSdk.sdkManagerPath ?? '', _androidSdk?.sdkManagerPath ?? '',
e.toString(), e.toString(),
_platform, _platform,
)); ));
@ -471,7 +471,7 @@ class AndroidLicenseValidator extends DoctorValidator {
} }
bool _canRunSdkManager() { bool _canRunSdkManager() {
final String? sdkManagerPath = _androidSdk.sdkManagerPath; final String? sdkManagerPath = _androidSdk?.sdkManagerPath;
if (sdkManagerPath == null) { if (sdkManagerPath == null) {
return false; return false;
} }

View File

@ -97,7 +97,7 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag
/// Creates a new AndroidApk based on the information in the Android manifest. /// Creates a new AndroidApk based on the information in the Android manifest.
static Future<AndroidApk?> fromAndroidProject( static Future<AndroidApk?> fromAndroidProject(
AndroidProject androidProject, { AndroidProject androidProject, {
required AndroidSdk androidSdk, required AndroidSdk? androidSdk,
required ProcessManager processManager, required ProcessManager processManager,
required UserMessages userMessages, required UserMessages userMessages,
required ProcessUtils processUtils, required ProcessUtils processUtils,
@ -113,7 +113,7 @@ class AndroidApk extends ApplicationPackage implements PrebuiltApplicationPackag
// the application Id, so we need to look at what was actually built. // the application Id, so we need to look at what was actually built.
return AndroidApk.fromApk( return AndroidApk.fromApk(
apkFile, apkFile,
androidSdk: androidSdk, androidSdk: androidSdk!,
processManager: processManager, processManager: processManager,
logger: logger, logger: logger,
userMessages: userMessages, userMessages: userMessages,

View File

@ -157,9 +157,9 @@ class SettingsFile {
/// Given a data structure which is a Map of String to dynamic values, return /// Given a data structure which is a Map of String to dynamic values, return
/// the same structure (`Map<String, dynamic>`) with the correct runtime types. /// the same structure (`Map<String, dynamic>`) with the correct runtime types.
Map<String, dynamic>? castStringKeyedMap(dynamic untyped) { Map<String, Object?>? castStringKeyedMap(Object? untyped) {
final Map<dynamic, dynamic>? map = untyped as Map<dynamic, dynamic>?; final Map<dynamic, dynamic>? map = untyped as Map<dynamic, dynamic>?;
return map?.cast<String, dynamic>(); return map?.cast<String, Object?>();
} }
/// Smallest column that will be used for text wrapping. If the requested column /// Smallest column that will be used for text wrapping. If the requested column

View File

@ -2,11 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart';
import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service.dart';
import '../android/android_device.dart'; import '../android/android_device.dart';
@ -123,7 +120,7 @@ class AttachCommand extends FlutterCommand {
hotRunnerFactory ??= HotRunnerFactory(); hotRunnerFactory ??= HotRunnerFactory();
} }
HotRunnerFactory hotRunnerFactory; HotRunnerFactory? hotRunnerFactory;
@override @override
final String name = 'attach'; final String name = 'attach';
@ -148,22 +145,22 @@ known, it can be explicitly provided to attach via the command-line, e.g.
@override @override
final String category = FlutterCommandCategory.tools; final String category = FlutterCommandCategory.tools;
int get debugPort { int? get debugPort {
if (argResults['debug-port'] == null) { if (argResults!['debug-port'] == null) {
return null; return null;
} }
try { try {
return int.parse(stringArgDeprecated('debug-port')); return int.parse(stringArgDeprecated('debug-port')!);
} on Exception catch (error) { } on Exception catch (error) {
throwToolExit('Invalid port for `--debug-port`: $error'); throwToolExit('Invalid port for `--debug-port`: $error');
} }
} }
Uri get debugUri { Uri? get debugUri {
if (argResults['debug-url'] == null) { if (argResults!['debug-url'] == null) {
return null; return null;
} }
final Uri uri = Uri.tryParse(stringArgDeprecated('debug-url')); final Uri? uri = Uri.tryParse(stringArgDeprecated('debug-url')!);
if (uri == null) { if (uri == null) {
throwToolExit('Invalid `--debug-url`: ${stringArgDeprecated('debug-url')}'); throwToolExit('Invalid `--debug-url`: ${stringArgDeprecated('debug-url')}');
} }
@ -173,11 +170,11 @@ known, it can be explicitly provided to attach via the command-line, e.g.
return uri; return uri;
} }
String get appId { String? get appId {
return stringArgDeprecated('app-id'); return stringArgDeprecated('app-id');
} }
String get userIdentifier => stringArgDeprecated(FlutterOptions.kDeviceUser); String? get userIdentifier => stringArgDeprecated(FlutterOptions.kDeviceUser);
@override @override
Future<void> validateCommand() async { Future<void> validateCommand() async {
@ -189,13 +186,13 @@ known, it can be explicitly provided to attach via the command-line, e.g.
throwToolExit(null); throwToolExit(null);
} }
debugPort; debugPort;
if (debugPort == null && debugUri == null && argResults.wasParsed(FlutterCommand.ipv6Flag)) { if (debugPort == null && debugUri == null && argResults!.wasParsed(FlutterCommand.ipv6Flag)) {
throwToolExit( throwToolExit(
'When the --debug-port or --debug-url is unknown, this command determines ' 'When the --debug-port or --debug-url is unknown, this command determines '
'the value of --ipv6 on its own.', 'the value of --ipv6 on its own.',
); );
} }
if (debugPort == null && debugUri == null && argResults.wasParsed(FlutterCommand.observatoryPortOption)) { if (debugPort == null && debugUri == null && argResults!.wasParsed(FlutterCommand.observatoryPortOption)) {
throwToolExit( throwToolExit(
'When the --debug-port or --debug-url is unknown, this command does not use ' 'When the --debug-port or --debug-url is unknown, this command does not use '
'the value of --observatory-port.', 'the value of --observatory-port.',
@ -207,7 +204,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
} }
if (userIdentifier != null) { if (userIdentifier != null) {
final Device device = await findTargetDevice(); final Device? device = await findTargetDevice();
if (device is! AndroidDevice) { if (device is! AndroidDevice) {
throwToolExit('--${FlutterOptions.kDeviceUser} is only supported for Android'); throwToolExit('--${FlutterOptions.kDeviceUser} is only supported for Android');
} }
@ -218,9 +215,9 @@ known, it can be explicitly provided to attach via the command-line, e.g.
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
await _validateArguments(); await _validateArguments();
final Device device = await findTargetDevice(); final Device device = await (findTargetDevice() as FutureOr<Device>);
final Artifacts overrideArtifacts = device.artifactOverrides ?? globals.artifacts; final Artifacts? overrideArtifacts = device.artifactOverrides ?? globals.artifacts;
await context.run<void>( await context.run<void>(
body: () => _attachToDevice(device), body: () => _attachToDevice(device),
overrides: <Type, Generator>{ overrides: <Type, Generator>{
@ -234,7 +231,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
Future<void> _attachToDevice(Device device) async { Future<void> _attachToDevice(Device device) async {
final FlutterProject flutterProject = FlutterProject.current(); final FlutterProject flutterProject = FlutterProject.current();
final Daemon daemon = boolArgDeprecated('machine') final Daemon? daemon = boolArgDeprecated('machine')
? Daemon( ? Daemon(
DaemonConnection( DaemonConnection(
daemonStreams: DaemonStreams.fromStdio(globals.stdio, logger: globals.logger), daemonStreams: DaemonStreams.fromStdio(globals.stdio, logger: globals.logger),
@ -247,20 +244,20 @@ known, it can be explicitly provided to attach via the command-line, e.g.
) )
: null; : null;
Stream<Uri> observatoryUri; Stream<Uri>? observatoryUri;
bool usesIpv6 = ipv6; bool usesIpv6 = ipv6!;
final String ipv6Loopback = InternetAddress.loopbackIPv6.address; final String ipv6Loopback = InternetAddress.loopbackIPv6.address;
final String ipv4Loopback = InternetAddress.loopbackIPv4.address; final String ipv4Loopback = InternetAddress.loopbackIPv4.address;
final String hostname = usesIpv6 ? ipv6Loopback : ipv4Loopback; final String hostname = usesIpv6 ? ipv6Loopback : ipv4Loopback;
if (debugPort == null && debugUri == null) { if (debugPort == null && debugUri == null) {
if (device is FuchsiaDevice) { if (device is FuchsiaDevice) {
final String module = stringArgDeprecated('module'); final String module = stringArgDeprecated('module')!;
if (module == null) { if (module == null) {
throwToolExit("'--module' is required for attaching to a Fuchsia device"); throwToolExit("'--module' is required for attaching to a Fuchsia device");
} }
usesIpv6 = device.ipv6; usesIpv6 = device.ipv6;
FuchsiaIsolateDiscoveryProtocol isolateDiscoveryProtocol; FuchsiaIsolateDiscoveryProtocol? isolateDiscoveryProtocol;
try { try {
isolateDiscoveryProtocol = device.getIsolateDiscoveryProtocol(module); isolateDiscoveryProtocol = device.getIsolateDiscoveryProtocol(module);
observatoryUri = Stream<Uri>.value(await isolateDiscoveryProtocol.uri).asBroadcastStream(); observatoryUri = Stream<Uri>.value(await isolateDiscoveryProtocol.uri).asBroadcastStream();
@ -273,9 +270,9 @@ known, it can be explicitly provided to attach via the command-line, e.g.
rethrow; rethrow;
} }
} else if ((device is IOSDevice) || (device is IOSSimulator) || (device is MacOSDesignedForIPadDevice)) { } else if ((device is IOSDevice) || (device is IOSSimulator) || (device is MacOSDesignedForIPadDevice)) {
final Uri uriFromMdns = final Uri? uriFromMdns =
await MDnsObservatoryDiscovery.instance.getObservatoryUri( await MDnsObservatoryDiscovery.instance!.getObservatoryUri(
appId, appId!,
device, device,
usesIpv6: usesIpv6, usesIpv6: usesIpv6,
deviceVmservicePort: deviceVmservicePort, deviceVmservicePort: deviceVmservicePort,
@ -292,7 +289,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
// to find the service protocol. // to find the service protocol.
await device.getLogReader(includePastLogs: device is AndroidDevice), await device.getLogReader(includePastLogs: device is AndroidDevice),
portForwarder: device.portForwarder, portForwarder: device.portForwarder,
ipv6: ipv6, ipv6: ipv6!,
devicePort: deviceVmservicePort, devicePort: deviceVmservicePort,
hostPort: hostVmservicePort, hostPort: hostVmservicePort,
logger: globals.logger, logger: globals.logger,
@ -308,7 +305,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
buildObservatoryUri( buildObservatoryUri(
device, device,
debugUri?.host ?? hostname, debugUri?.host ?? hostname,
debugPort ?? debugUri.port, debugPort ?? debugUri!.port,
hostVmservicePort, hostVmservicePort,
debugUri?.path, debugUri?.path,
) )
@ -318,20 +315,20 @@ known, it can be explicitly provided to attach via the command-line, e.g.
globals.terminal.usesTerminalUi = daemon == null; globals.terminal.usesTerminalUi = daemon == null;
try { try {
int result; int? result;
if (daemon != null) { if (daemon != null) {
final ResidentRunner runner = await createResidentRunner( final ResidentRunner runner = await (createResidentRunner(
observatoryUris: observatoryUri, observatoryUris: observatoryUri,
device: device, device: device,
flutterProject: flutterProject, flutterProject: flutterProject,
usesIpv6: usesIpv6, usesIpv6: usesIpv6,
); ) as FutureOr<ResidentRunner>);
AppInstance app; late AppInstance app;
try { try {
app = await daemon.appDomain.launch( app = await daemon.appDomain.launch(
runner, runner,
({Completer<DebugConnectionInfo> connectionInfoCompleter, ({Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void> appStartedCompleter}) { Completer<void>? appStartedCompleter}) {
return runner.attach( return runner.attach(
connectionInfoCompleter: connectionInfoCompleter, connectionInfoCompleter: connectionInfoCompleter,
appStartedCompleter: appStartedCompleter, appStartedCompleter: appStartedCompleter,
@ -349,19 +346,19 @@ known, it can be explicitly provided to attach via the command-line, e.g.
} on Exception catch (error) { } on Exception catch (error) {
throwToolExit(error.toString()); throwToolExit(error.toString());
} }
result = await app.runner.waitForAppToFinish(); result = await app.runner!.waitForAppToFinish();
assert(result != null); assert(result != null);
return; return;
} }
while (true) { while (true) {
final ResidentRunner runner = await createResidentRunner( final ResidentRunner runner = await (createResidentRunner(
observatoryUris: observatoryUri, observatoryUris: observatoryUri,
device: device, device: device,
flutterProject: flutterProject, flutterProject: flutterProject,
usesIpv6: usesIpv6, usesIpv6: usesIpv6,
); ) as FutureOr<ResidentRunner>);
final Completer<void> onAppStart = Completer<void>.sync(); final Completer<void> onAppStart = Completer<void>.sync();
TerminalHandler terminalHandler; TerminalHandler? terminalHandler;
unawaited(onAppStart.future.whenComplete(() { unawaited(onAppStart.future.whenComplete(() {
terminalHandler = TerminalHandler( terminalHandler = TerminalHandler(
runner, runner,
@ -396,18 +393,18 @@ known, it can be explicitly provided to attach via the command-line, e.g.
} }
rethrow; rethrow;
} finally { } finally {
final List<ForwardedPort> ports = device.portForwarder.forwardedPorts.toList(); final List<ForwardedPort> ports = device.portForwarder!.forwardedPorts.toList();
for (final ForwardedPort port in ports) { for (final ForwardedPort port in ports) {
await device.portForwarder.unforward(port); await device.portForwarder!.unforward(port);
} }
} }
} }
Future<ResidentRunner> createResidentRunner({ Future<ResidentRunner?> createResidentRunner({
@required Stream<Uri> observatoryUris, required Stream<Uri> observatoryUris,
@required Device device, required Device device,
@required FlutterProject flutterProject, required FlutterProject flutterProject,
@required bool usesIpv6, required bool usesIpv6,
}) async { }) async {
assert(observatoryUris != null); assert(observatoryUris != null);
assert(device != null); assert(device != null);
@ -418,7 +415,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
final FlutterDevice flutterDevice = await FlutterDevice.create( final FlutterDevice flutterDevice = await FlutterDevice.create(
device, device,
target: targetFile, target: targetFile,
targetModel: TargetModel(stringArgDeprecated('target-model')), targetModel: TargetModel(stringArgDeprecated('target-model')!),
buildInfo: buildInfo, buildInfo: buildInfo,
userIdentifier: userIdentifier, userIdentifier: userIdentifier,
platform: globals.platform, platform: globals.platform,
@ -433,11 +430,11 @@ known, it can be explicitly provided to attach via the command-line, e.g.
); );
return buildInfo.isDebug return buildInfo.isDebug
? hotRunnerFactory.build( ? hotRunnerFactory!.build(
flutterDevices, flutterDevices,
target: targetFile, target: targetFile,
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,
packagesFilePath: globalResults['packages'] as String, packagesFilePath: globalResults!['packages'] as String?,
projectRootPath: stringArgDeprecated('project-root'), projectRootPath: stringArgDeprecated('project-root'),
dillOutputPath: stringArgDeprecated('output-dill'), dillOutputPath: stringArgDeprecated('output-dill'),
ipv6: usesIpv6, ipv6: usesIpv6,
@ -455,19 +452,19 @@ known, it can be explicitly provided to attach via the command-line, e.g.
} }
class HotRunnerFactory { class HotRunnerFactory {
HotRunner build( HotRunner? build(
List<FlutterDevice> devices, { List<FlutterDevice> devices, {
String target, required String target,
DebuggingOptions debuggingOptions, required DebuggingOptions debuggingOptions,
bool benchmarkMode = false, bool benchmarkMode = false,
File applicationBinary, File? applicationBinary,
bool hostIsIde = false, bool hostIsIde = false,
String projectRootPath, String? projectRootPath,
String packagesFilePath, String? packagesFilePath,
String dillOutputPath, String? dillOutputPath,
bool stayResident = true, bool stayResident = true,
bool ipv6 = false, bool ipv6 = false,
FlutterProject flutterProject, FlutterProject? flutterProject,
}) => HotRunner( }) => HotRunner(
devices, devices,
target: target, target: target,

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
@ -32,14 +32,14 @@ typedef PrintFn = void Function(Object);
class CustomDevicesCommand extends FlutterCommand { class CustomDevicesCommand extends FlutterCommand {
factory CustomDevicesCommand({ factory CustomDevicesCommand({
@required CustomDevicesConfig customDevicesConfig, required CustomDevicesConfig customDevicesConfig,
@required OperatingSystemUtils operatingSystemUtils, required OperatingSystemUtils operatingSystemUtils,
@required Terminal terminal, required Terminal terminal,
@required Platform platform, required Platform platform,
@required ProcessManager processManager, required ProcessManager processManager,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required Logger logger, required Logger logger,
@required FeatureFlags featureFlags, required FeatureFlags featureFlags,
}) { }) {
return CustomDevicesCommand._common( return CustomDevicesCommand._common(
customDevicesConfig: customDevicesConfig, customDevicesConfig: customDevicesConfig,
@ -55,14 +55,14 @@ class CustomDevicesCommand extends FlutterCommand {
@visibleForTesting @visibleForTesting
factory CustomDevicesCommand.test({ factory CustomDevicesCommand.test({
@required CustomDevicesConfig customDevicesConfig, required CustomDevicesConfig customDevicesConfig,
@required OperatingSystemUtils operatingSystemUtils, required OperatingSystemUtils operatingSystemUtils,
@required Terminal terminal, required Terminal terminal,
@required Platform platform, required Platform platform,
@required ProcessManager processManager, required ProcessManager processManager,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required Logger logger, required Logger logger,
@required FeatureFlags featureFlags, required FeatureFlags featureFlags,
PrintFn usagePrintFn = print PrintFn usagePrintFn = print
}) { }) {
return CustomDevicesCommand._common( return CustomDevicesCommand._common(
@ -79,14 +79,14 @@ class CustomDevicesCommand extends FlutterCommand {
} }
CustomDevicesCommand._common({ CustomDevicesCommand._common({
@required CustomDevicesConfig customDevicesConfig, required CustomDevicesConfig customDevicesConfig,
@required OperatingSystemUtils operatingSystemUtils, required OperatingSystemUtils operatingSystemUtils,
@required Terminal terminal, required Terminal terminal,
@required Platform platform, required Platform platform,
@required ProcessManager processManager, required ProcessManager processManager,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required Logger logger, required Logger logger,
@required FeatureFlags featureFlags, required FeatureFlags featureFlags,
PrintFn usagePrintFn = print, PrintFn usagePrintFn = print,
}) : assert(customDevicesConfig != null), }) : assert(customDevicesConfig != null),
assert(operatingSystemUtils != null), assert(operatingSystemUtils != null),
@ -162,7 +162,9 @@ Requires the custom devices feature to be enabled. You can enable it using "flut
String get category => FlutterCommandCategory.tools; String get category => FlutterCommandCategory.tools;
@override @override
Future<FlutterCommandResult> runCommand() async => null; Future<FlutterCommandResult> runCommand() async {
return FlutterCommandResult.success();
}
@override @override
void printUsage() { void printUsage() {
@ -175,15 +177,15 @@ Requires the custom devices feature to be enabled. You can enable it using "flut
/// feature is enabled. /// feature is enabled.
abstract class CustomDevicesCommandBase extends FlutterCommand { abstract class CustomDevicesCommandBase extends FlutterCommand {
CustomDevicesCommandBase({ CustomDevicesCommandBase({
@required this.customDevicesConfig, required this.customDevicesConfig,
@required this.featureFlags, required this.featureFlags,
@required this.fileSystem, required this.fileSystem,
@required this.logger, required this.logger,
}); });
@protected final CustomDevicesConfig customDevicesConfig; @protected final CustomDevicesConfig customDevicesConfig;
@protected final FeatureFlags featureFlags; @protected final FeatureFlags featureFlags;
@protected final FileSystem fileSystem; @protected final FileSystem? fileSystem;
@protected final Logger logger; @protected final Logger logger;
/// The path to the (potentially non-existing) backup of the config file. /// The path to the (potentially non-existing) backup of the config file.
@ -195,7 +197,7 @@ abstract class CustomDevicesCommandBase extends FlutterCommand {
/// doesn't exist. (True otherwise) /// doesn't exist. (True otherwise)
@protected @protected
bool backup() { bool backup() {
final File configFile = fileSystem.file(customDevicesConfig.configPath); final File configFile = fileSystem!.file(customDevicesConfig.configPath);
if (configFile.existsSync()) { if (configFile.existsSync()) {
configFile.copySync(configBackupPath); configFile.copySync(configBackupPath);
return true; return true;
@ -219,14 +221,11 @@ abstract class CustomDevicesCommandBase extends FlutterCommand {
class CustomDevicesListCommand extends CustomDevicesCommandBase { class CustomDevicesListCommand extends CustomDevicesCommandBase {
CustomDevicesListCommand({ CustomDevicesListCommand({
@required CustomDevicesConfig customDevicesConfig, required super.customDevicesConfig,
@required FeatureFlags featureFlags, required super.featureFlags,
@required Logger logger, required super.logger,
}) : super( }) : super(
customDevicesConfig: customDevicesConfig, fileSystem: null
featureFlags: featureFlags,
fileSystem: null,
logger: logger
); );
@override @override
@ -241,7 +240,7 @@ List the currently configured custom devices, both enabled and disabled, reachab
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
checkFeatureEnabled(); checkFeatureEnabled();
List<CustomDeviceConfig> devices; late List<CustomDeviceConfig> devices;
try { try {
devices = customDevicesConfig.devices; devices = customDevicesConfig.devices;
} on Exception { } on Exception {
@ -263,16 +262,11 @@ List the currently configured custom devices, both enabled and disabled, reachab
class CustomDevicesResetCommand extends CustomDevicesCommandBase { class CustomDevicesResetCommand extends CustomDevicesCommandBase {
CustomDevicesResetCommand({ CustomDevicesResetCommand({
@required CustomDevicesConfig customDevicesConfig, required super.customDevicesConfig,
@required FeatureFlags featureFlags, required super.featureFlags,
@required FileSystem fileSystem, required FileSystem super.fileSystem,
@required Logger logger, required super.logger,
}) : super( });
customDevicesConfig: customDevicesConfig,
featureFlags: featureFlags,
fileSystem: fileSystem,
logger: logger
);
@override @override
String get description => ''' String get description => '''
@ -291,7 +285,7 @@ If a file already exists at the backup location, it will be overwritten.
final bool wasBackedUp = backup(); final bool wasBackedUp = backup();
ErrorHandlingFileSystem.deleteIfExists(fileSystem.file(customDevicesConfig.configPath)); ErrorHandlingFileSystem.deleteIfExists(fileSystem!.file(customDevicesConfig.configPath));
customDevicesConfig.ensureFileExists(); customDevicesConfig.ensureFileExists();
logger.printStatus( logger.printStatus(
@ -306,24 +300,18 @@ If a file already exists at the backup location, it will be overwritten.
class CustomDevicesAddCommand extends CustomDevicesCommandBase { class CustomDevicesAddCommand extends CustomDevicesCommandBase {
CustomDevicesAddCommand({ CustomDevicesAddCommand({
@required CustomDevicesConfig customDevicesConfig, required super.customDevicesConfig,
@required OperatingSystemUtils operatingSystemUtils, required OperatingSystemUtils operatingSystemUtils,
@required Terminal terminal, required Terminal terminal,
@required Platform platform, required Platform platform,
@required FeatureFlags featureFlags, required super.featureFlags,
@required ProcessManager processManager, required ProcessManager processManager,
@required FileSystem fileSystem, required FileSystem super.fileSystem,
@required Logger logger, required super.logger,
}) : _operatingSystemUtils = operatingSystemUtils, }) : _operatingSystemUtils = operatingSystemUtils,
_terminal = terminal, _terminal = terminal,
_platform = platform, _platform = platform,
_processManager = processManager, _processManager = processManager
super(
customDevicesConfig: customDevicesConfig,
featureFlags: featureFlags,
fileSystem: fileSystem,
logger: logger
)
{ {
argParser.addFlag( argParser.addFlag(
_kCheck, _kCheck,
@ -379,7 +367,7 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
final Terminal _terminal; final Terminal _terminal;
final Platform _platform; final Platform _platform;
final ProcessManager _processManager; final ProcessManager _processManager;
StreamQueue<String> inputs; late StreamQueue<String> inputs;
@override @override
String get description => 'Add a new device the custom devices config file.'; String get description => 'Add a new device the custom devices config file.';
@ -413,7 +401,7 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
result = false; result = false;
} }
final Directory temp = await fileSystem.systemTempDirectory.createTemp(); final Directory temp = await fileSystem!.systemTempDirectory.createTemp();
try { try {
final bool ok = await device.tryInstall( final bool ok = await device.tryInstall(
@ -445,8 +433,8 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
if (config.usesPortForwarding) { if (config.usesPortForwarding) {
final CustomDevicePortForwarder portForwarder = CustomDevicePortForwarder( final CustomDevicePortForwarder portForwarder = CustomDevicePortForwarder(
deviceName: device.name, deviceName: device.name,
forwardPortCommand: config.forwardPortCommand, forwardPortCommand: config.forwardPortCommand!,
forwardPortSuccessRegex: config.forwardPortSuccessRegex, forwardPortSuccessRegex: config.forwardPortSuccessRegex!,
processManager: _processManager, processManager: _processManager,
logger: logger, logger: logger,
); );
@ -455,7 +443,7 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
// find a random port we can forward // find a random port we can forward
final int port = await _operatingSystemUtils.findFreePort(); final int port = await _operatingSystemUtils.findFreePort();
final ForwardedPort forwardedPort = await portForwarder.tryForward(port, port); final ForwardedPort forwardedPort = await (portForwarder.tryForward(port, port) as FutureOr<ForwardedPort>);
if (forwardedPort == null) { if (forwardedPort == null) {
_printConfigCheckingError("Couldn't forward test port $port from device.",); _printConfigCheckingError("Couldn't forward test port $port from device.",);
result = false; result = false;
@ -482,8 +470,8 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
/// ///
/// Only check if `--check` is explicitly specified. (Don't check by default) /// Only check if `--check` is explicitly specified. (Don't check by default)
Future<FlutterCommandResult> runNonInteractively() async { Future<FlutterCommandResult> runNonInteractively() async {
final String jsonStr = stringArgDeprecated(_kJson); final String jsonStr = stringArgDeprecated(_kJson)!;
final bool shouldCheck = boolArgDeprecated(_kCheck) ?? false; final bool shouldCheck = boolArgDeprecated(_kCheck);
dynamic json; dynamic json;
try { try {
@ -492,7 +480,7 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
throwToolExit('Could not decode json: $e'); throwToolExit('Could not decode json: $e');
} }
CustomDeviceConfig config; late CustomDeviceConfig config;
try { try {
config = CustomDeviceConfig.fromJson(json); config = CustomDeviceConfig.fromJson(json);
} on CustomDeviceRevivalException catch (e) { } on CustomDeviceRevivalException catch (e) {
@ -518,12 +506,12 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
bool _isValidIpAddr(String s) => InternetAddress.tryParse(s) != null; bool _isValidIpAddr(String s) => InternetAddress.tryParse(s) != null;
/// Ask the user to input a string. /// Ask the user to input a string.
Future<String> askForString( Future<String?> askForString(
String name, { String name, {
String description, String? description,
String example, String? example,
String defaultsTo, String? defaultsTo,
Future<bool> Function(String) validator, Future<bool> Function(String)? validator,
}) async { }) async {
String msg = description ?? name; String msg = description ?? name;
@ -555,7 +543,7 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
/// Ask the user for a y(es) / n(o) or empty input. /// Ask the user for a y(es) / n(o) or empty input.
Future<bool> askForBool( Future<bool> askForBool(
String name, { String name, {
String description, String? description,
bool defaultsTo = true, bool defaultsTo = true,
}) async { }) async {
final String defaultsToStr = defaultsTo == true ? '[Y/n]' : '[y/N]'; final String defaultsToStr = defaultsTo == true ? '[Y/n]' : '[y/N]';
@ -591,7 +579,7 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
/// Run interactively (with user prompts), the target device should be /// Run interactively (with user prompts), the target device should be
/// connected to via ssh. /// connected to via ssh.
Future<FlutterCommandResult> runInteractivelySsh() async { Future<FlutterCommandResult> runInteractivelySsh() async {
final bool shouldCheck = boolArgDeprecated(_kCheck) ?? true; final bool shouldCheck = boolArgDeprecated(_kCheck);
// Listen to the keystrokes stream as late as possible, since it's a // Listen to the keystrokes stream as late as possible, since it's a
// single-subscription stream apparently. // single-subscription stream apparently.
@ -610,61 +598,61 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
inputs = StreamQueue<String>(nonClosingKeystrokes.stream); inputs = StreamQueue<String>(nonClosingKeystrokes.stream);
final String id = await askForString( final String id = await (askForString(
'id', 'id',
description: description:
'Please enter the id you want to device to have. Must contain only ' 'Please enter the id you want to device to have. Must contain only '
'alphanumeric or underscore characters.', 'alphanumeric or underscore characters.',
example: 'pi', example: 'pi',
validator: (String s) async => RegExp(r'^\w+$').hasMatch(s), validator: (String s) async => RegExp(r'^\w+$').hasMatch(s),
); ) as FutureOr<String>);
final String label = await askForString( final String label = await (askForString(
'label', 'label',
description: description:
'Please enter the label of the device, which is a slightly more verbose ' 'Please enter the label of the device, which is a slightly more verbose '
'name for the device.', 'name for the device.',
example: 'Raspberry Pi', example: 'Raspberry Pi',
); ) as FutureOr<String>);
final String sdkNameAndVersion = await askForString( final String sdkNameAndVersion = await (askForString(
'SDK name and version', 'SDK name and version',
example: 'Raspberry Pi 4 Model B+', example: 'Raspberry Pi 4 Model B+',
); ) as FutureOr<String>);
final bool enabled = await askForBool( final bool enabled = await askForBool(
'enabled', 'enabled',
description: 'Should the device be enabled?', description: 'Should the device be enabled?',
); );
final String targetStr = await askForString( final String targetStr = await (askForString(
'target', 'target',
description: 'Please enter the hostname or IPv4/v6 address of the device.', description: 'Please enter the hostname or IPv4/v6 address of the device.',
example: 'raspberrypi', example: 'raspberrypi',
validator: (String s) async => _isValidHostname(s) || _isValidIpAddr(s) validator: (String s) async => _isValidHostname(s) || _isValidIpAddr(s)
); ) as FutureOr<String>);
final InternetAddress targetIp = InternetAddress.tryParse(targetStr); final InternetAddress? targetIp = InternetAddress.tryParse(targetStr);
final bool useIp = targetIp != null; final bool useIp = targetIp != null;
final bool ipv6 = useIp && targetIp.type == InternetAddressType.IPv6; final bool ipv6 = useIp && targetIp.type == InternetAddressType.IPv6;
final InternetAddress loopbackIp = ipv6 final InternetAddress loopbackIp = ipv6
? InternetAddress.loopbackIPv6 ? InternetAddress.loopbackIPv6
: InternetAddress.loopbackIPv4; : InternetAddress.loopbackIPv4;
final String username = await askForString( final String username = await (askForString(
'username', 'username',
description: 'Please enter the username used for ssh-ing into the remote device.', description: 'Please enter the username used for ssh-ing into the remote device.',
example: 'pi', example: 'pi',
defaultsTo: 'no username', defaultsTo: 'no username',
); ) as FutureOr<String>);
final String remoteRunDebugCommand = await askForString( final String remoteRunDebugCommand = await (askForString(
'run command', 'run command',
description: description:
'Please enter the command executed on the remote device for starting ' 'Please enter the command executed on the remote device for starting '
r'the app. "/tmp/${appName}" is the path to the asset bundle.', r'the app. "/tmp/${appName}" is the path to the asset bundle.',
example: r'flutter-pi /tmp/${appName}' example: r'flutter-pi /tmp/${appName}'
); ) as FutureOr<String>);
final bool usePortForwarding = await askForBool( final bool usePortForwarding = await askForBool(
'use port forwarding', 'use port forwarding',
@ -675,12 +663,12 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
'not using port forwarding.', 'not using port forwarding.',
); );
final String screenshotCommand = await askForString( final String screenshotCommand = await (askForString(
'screenshot command', 'screenshot command',
description: 'Enter the command executed on the remote device for taking a screenshot.', description: 'Enter the command executed on the remote device for taking a screenshot.',
example: r"fbgrab /tmp/screenshot.png && cat /tmp/screenshot.png | base64 | tr -d ' \n\t'", example: r"fbgrab /tmp/screenshot.png && cat /tmp/screenshot.png | base64 | tr -d ' \n\t'",
defaultsTo: 'no screenshotting support', defaultsTo: 'no screenshotting support',
); ) as FutureOr<String>);
// SSH expects IPv6 addresses to use the bracket syntax like URIs do too, // SSH expects IPv6 addresses to use the bracket syntax like URIs do too,
// but the IPv6 the user enters is a raw IPv6 address, so we need to wrap it. // but the IPv6 the user enters is a raw IPv6 address, so we need to wrap it.
@ -777,7 +765,6 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
targetStr, targetStr,
], ],
explicitPingSuccessRegex: true, explicitPingSuccessRegex: true,
pingSuccessRegex: null
); );
} else { } else {
throw UnsupportedError('Unsupported operating system'); throw UnsupportedError('Unsupported operating system');
@ -815,16 +802,11 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase {
class CustomDevicesDeleteCommand extends CustomDevicesCommandBase { class CustomDevicesDeleteCommand extends CustomDevicesCommandBase {
CustomDevicesDeleteCommand({ CustomDevicesDeleteCommand({
@required CustomDevicesConfig customDevicesConfig, required super.customDevicesConfig,
@required FeatureFlags featureFlags, required super.featureFlags,
@required FileSystem fileSystem, required FileSystem super.fileSystem,
@required Logger logger, required super.logger,
}) : super( });
customDevicesConfig: customDevicesConfig,
featureFlags: featureFlags,
fileSystem: fileSystem,
logger: logger
);
@override @override
String get description => ''' String get description => '''
@ -838,7 +820,7 @@ Delete a device from the config file.
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
checkFeatureEnabled(); checkFeatureEnabled();
final String id = globalResults['device-id'] as String; final String id = globalResults!['device-id'] as String;
if (!customDevicesConfig.contains(id)) { if (!customDevicesConfig.contains(id)) {
throwToolExit('Couldn\'t find device with id "$id" in config at "${customDevicesConfig.configPath}"'); throwToolExit('Couldn\'t find device with id "$id" in config at "${customDevicesConfig.configPath}"');
} }

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'package:async/async.dart'; import 'package:async/async.dart';
@ -66,10 +64,10 @@ class DaemonCommand extends FlutterCommand {
@override @override
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
if (argResults['listen-on-tcp-port'] != null) { if (argResults!['listen-on-tcp-port'] != null) {
int port; int? port;
try { try {
port = int.parse(stringArgDeprecated('listen-on-tcp-port')); port = int.parse(stringArgDeprecated('listen-on-tcp-port')!);
} on FormatException catch (error) { } on FormatException catch (error) {
throwToolExit('Invalid port for `--listen-on-tcp-port`: $error'); throwToolExit('Invalid port for `--listen-on-tcp-port`: $error');
} }
@ -108,17 +106,17 @@ class _DaemonServer {
this.notifyingLogger, this.notifyingLogger,
}); });
final int port; final int? port;
/// Stdout logger used to print general server-related errors. /// Stdout logger used to print general server-related errors.
final Logger logger; final Logger? logger;
// Logger that sends the message to the other end of daemon connection. // Logger that sends the message to the other end of daemon connection.
final NotifyingLogger notifyingLogger; final NotifyingLogger? notifyingLogger;
Future<void> run() async { Future<void> run() async {
final ServerSocket serverSocket = await ServerSocket.bind(InternetAddress.loopbackIPv4, port); final ServerSocket serverSocket = await ServerSocket.bind(InternetAddress.loopbackIPv4, port!);
logger.printStatus('Daemon server listening on ${serverSocket.port}'); logger!.printStatus('Daemon server listening on ${serverSocket.port}');
final StreamSubscription<Socket> subscription = serverSocket.listen( final StreamSubscription<Socket> subscription = serverSocket.listen(
(Socket socket) async { (Socket socket) async {
@ -126,13 +124,13 @@ class _DaemonServer {
// reset, we will receive an uncatchable exception. // reset, we will receive an uncatchable exception.
// https://github.com/dart-lang/sdk/issues/25518 // https://github.com/dart-lang/sdk/issues/25518
final Future<void> socketDone = socket.done.catchError((dynamic error, StackTrace stackTrace) { final Future<void> socketDone = socket.done.catchError((dynamic error, StackTrace stackTrace) {
logger.printError('Socket error: $error'); logger!.printError('Socket error: $error');
logger.printTrace('$stackTrace'); logger!.printTrace('$stackTrace');
}); });
final Daemon daemon = Daemon( final Daemon daemon = Daemon(
DaemonConnection( DaemonConnection(
daemonStreams: DaemonStreams.fromSocket(socket, logger: logger), daemonStreams: DaemonStreams.fromSocket(socket, logger: logger!),
logger: logger, logger: logger!,
), ),
notifyingLogger: notifyingLogger, notifyingLogger: notifyingLogger,
); );
@ -147,8 +145,8 @@ class _DaemonServer {
} }
} }
typedef CommandHandler = Future<dynamic> Function(Map<String, dynamic> args); typedef CommandHandler = Future<dynamic>? Function(Map<String, dynamic> args);
typedef CommandHandlerWithBinary = Future<dynamic> Function(Map<String, dynamic> args, Stream<List<int>> binary); typedef CommandHandlerWithBinary = Future<dynamic> Function(Map<String, dynamic> args, Stream<List<int>>? binary);
class Daemon { class Daemon {
Daemon( Daemon(
@ -178,15 +176,15 @@ class Daemon {
final DaemonConnection connection; final DaemonConnection connection;
DaemonDomain daemonDomain; late DaemonDomain daemonDomain;
AppDomain appDomain; late AppDomain appDomain;
DeviceDomain deviceDomain; late DeviceDomain deviceDomain;
EmulatorDomain emulatorDomain; EmulatorDomain? emulatorDomain;
DevToolsDomain devToolsDomain; DevToolsDomain? devToolsDomain;
ProxyDomain proxyDomain; late ProxyDomain proxyDomain;
StreamSubscription<DaemonMessage> _commandSubscription; StreamSubscription<DaemonMessage>? _commandSubscription;
final NotifyingLogger notifyingLogger; final NotifyingLogger? notifyingLogger;
final bool logToStdout; final bool logToStdout;
final Completer<int> _onExitCompleter = Completer<int>(); final Completer<int> _onExitCompleter = Completer<int>();
@ -203,7 +201,7 @@ class Daemon {
// {id, method, params} // {id, method, params}
// [id] is an opaque type to us. // [id] is an opaque type to us.
final dynamic id = request.data['id']; final Object? id = request.data['id'];
if (id == null) { if (id == null) {
globals.stdio.stderrWrite('no id for request: $request\n'); globals.stdio.stderrWrite('no id for request: $request\n');
@ -211,7 +209,7 @@ class Daemon {
} }
try { try {
final String method = request.data['method'] as String; final String method = request.data['method']! as String;
assert(method != null); assert(method != null);
if (!method.contains('.')) { if (!method.contains('.')) {
throw DaemonException('method not understood: $method'); throw DaemonException('method not understood: $method');
@ -223,13 +221,13 @@ class Daemon {
throw DaemonException('no domain for method: $method'); throw DaemonException('no domain for method: $method');
} }
_domainMap[prefix].handleCommand(name, id, castStringKeyedMap(request.data['params']) ?? const <String, dynamic>{}, request.binary); _domainMap[prefix]!.handleCommand(name, id, castStringKeyedMap(request.data['params']) ?? const <String, dynamic>{}, request.binary);
} on Exception catch (error, trace) { } on Exception catch (error, trace) {
connection.sendErrorResponse(id, _toJsonable(error), trace); connection.sendErrorResponse(id, _toJsonable(error), trace);
} }
} }
Future<void> shutdown({ dynamic error }) async { Future<void> shutdown({ Object? error }) async {
await devToolsDomain?.dispose(); await devToolsDomain?.dispose();
await _commandSubscription?.cancel(); await _commandSubscription?.cancel();
await connection.dispose(); await connection.dispose();
@ -270,12 +268,12 @@ abstract class Domain {
@override @override
String toString() => name; String toString() => name;
void handleCommand(String command, dynamic id, Map<String, dynamic> args, Stream<List<int>> binary) { void handleCommand(String command, Object id, Map<String, dynamic> args, Stream<List<int>>? binary) {
Future<dynamic>.sync(() { Future<dynamic>.sync(() {
if (_handlers.containsKey(command)) { if (_handlers.containsKey(command)) {
return _handlers[command](args); return _handlers[command]!(args);
} else if (_handlersWithBinary.containsKey(command)) { } else if (_handlersWithBinary.containsKey(command)) {
return _handlersWithBinary[command](args, binary); return _handlersWithBinary[command]!(args, binary);
} }
throw DaemonException('command not understood: $name.$command'); throw DaemonException('command not understood: $name.$command');
}).then<dynamic>((dynamic result) { }).then<dynamic>((dynamic result) {
@ -285,11 +283,11 @@ abstract class Domain {
}); });
} }
void sendEvent(String name, [ dynamic args, List<int> binary ]) { void sendEvent(String name, [ dynamic args, List<int>? binary ]) {
daemon.connection.sendEvent(name, _toJsonable(args), binary); daemon.connection.sendEvent(name, _toJsonable(args), binary);
} }
String _getStringArg(Map<String, dynamic> args, String name, { bool required = false }) { String? _getStringArg(Map<String, dynamic> args, String name, { bool required = false }) {
if (required && !args.containsKey(name)) { if (required && !args.containsKey(name)) {
throw DaemonException('$name is required'); throw DaemonException('$name is required');
} }
@ -297,10 +295,10 @@ abstract class Domain {
if (val != null && val is! String) { if (val != null && val is! String) {
throw DaemonException('$name is not a String'); throw DaemonException('$name is not a String');
} }
return val as String; return val as String?;
} }
bool _getBoolArg(Map<String, dynamic> args, String name, { bool required = false }) { bool? _getBoolArg(Map<String, dynamic> args, String name, { bool required = false }) {
if (required && !args.containsKey(name)) { if (required && !args.containsKey(name)) {
throw DaemonException('$name is required'); throw DaemonException('$name is required');
} }
@ -308,10 +306,10 @@ abstract class Domain {
if (val != null && val is! bool) { if (val != null && val is! bool) {
throw DaemonException('$name is not a bool'); throw DaemonException('$name is not a bool');
} }
return val as bool; return val as bool?;
} }
int _getIntArg(Map<String, dynamic> args, String name, { bool required = false }) { int? _getIntArg(Map<String, dynamic> args, String name, { bool required = false }) {
if (required && !args.containsKey(name)) { if (required && !args.containsKey(name)) {
throw DaemonException('$name is required'); throw DaemonException('$name is required');
} }
@ -319,7 +317,7 @@ abstract class Domain {
if (val != null && val is! int) { if (val != null && val is! int) {
throw DaemonException('$name is not an int'); throw DaemonException('$name is not an int');
} }
return val as int; return val as int?;
} }
Future<void> dispose() async { } Future<void> dispose() async { }
@ -342,7 +340,7 @@ class DaemonDomain extends Domain {
}, },
); );
_subscription = daemon.notifyingLogger.onMessage.listen((LogMessage message) { _subscription = daemon.notifyingLogger!.onMessage.listen((LogMessage message) {
if (daemon.logToStdout) { if (daemon.logToStdout) {
if (message.level == 'status') { if (message.level == 'status') {
// We use `print()` here instead of `stdout.writeln()` in order to // We use `print()` here instead of `stdout.writeln()` in order to
@ -374,7 +372,7 @@ class DaemonDomain extends Domain {
}); });
} }
StreamSubscription<LogMessage> _subscription; StreamSubscription<LogMessage>? _subscription;
Future<String> version(Map<String, dynamic> args) { Future<String> version(Map<String, dynamic> args) {
return Future<String>.value(protocolVersion); return Future<String>.value(protocolVersion);
@ -411,7 +409,7 @@ class DaemonDomain extends Domain {
/// as whether command line tools are installed or whether the host platform /// as whether command line tools are installed or whether the host platform
/// is correct. /// is correct.
Future<Map<String, Object>> getSupportedPlatforms(Map<String, dynamic> args) async { Future<Map<String, Object>> getSupportedPlatforms(Map<String, dynamic> args) async {
final String projectRoot = _getStringArg(args, 'projectRoot', required: true); final String? projectRoot = _getStringArg(args, 'projectRoot', required: true);
final List<String> result = <String>[]; final List<String> result = <String>[];
try { try {
final FlutterProject flutterProject = FlutterProject.fromDirectory(globals.fs.directory(projectRoot)); final FlutterProject flutterProject = FlutterProject.fromDirectory(globals.fs.directory(projectRoot));
@ -461,8 +459,8 @@ class DaemonDomain extends Domain {
} }
typedef RunOrAttach = Future<void> Function({ typedef RunOrAttach = Future<void> Function({
Completer<DebugConnectionInfo> connectionInfoCompleter, Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void> appStartedCompleter, Completer<void>? appStartedCompleter,
}); });
/// This domain responds to methods like [start] and [stop]. /// This domain responds to methods like [start] and [stop].
@ -488,17 +486,17 @@ class AppDomain extends Domain {
Device device, Device device,
String projectDirectory, String projectDirectory,
String target, String target,
String route, String? route,
DebuggingOptions options, DebuggingOptions options,
bool enableHotReload, { bool enableHotReload, {
File applicationBinary, File? applicationBinary,
@required bool trackWidgetCreation, required bool trackWidgetCreation,
String projectRootPath, String? projectRootPath,
String packagesFilePath, String? packagesFilePath,
String dillOutputPath, String? dillOutputPath,
bool ipv6 = false, bool ipv6 = false,
bool multidexEnabled = false, bool multidexEnabled = false,
String isolateFilter, String? isolateFilter,
bool machine = true, bool machine = true,
}) async { }) async {
if (!await device.supportsRuntimeMode(options.buildInfo.mode)) { if (!await device.supportsRuntimeMode(options.buildInfo.mode)) {
@ -523,14 +521,14 @@ class AppDomain extends Domain {
ResidentRunner runner; ResidentRunner runner;
if (await device.targetPlatform == TargetPlatform.web_javascript) { if (await device.targetPlatform == TargetPlatform.web_javascript) {
runner = webRunnerFactory.createWebRunner( runner = webRunnerFactory!.createWebRunner(
flutterDevice, flutterDevice,
flutterProject: flutterProject, flutterProject: flutterProject,
target: target, target: target,
debuggingOptions: options, debuggingOptions: options,
ipv6: ipv6, ipv6: ipv6,
stayResident: true, stayResident: true,
urlTunneller: options.webEnableExposeUrl ? daemon.daemonDomain.exposeUrl : null, urlTunneller: options.webEnableExposeUrl! ? daemon.daemonDomain.exposeUrl : null,
machine: machine, machine: machine,
usage: globals.flutterUsage, usage: globals.flutterUsage,
systemClock: globals.systemClock, systemClock: globals.systemClock,
@ -565,8 +563,8 @@ class AppDomain extends Domain {
return launch( return launch(
runner, runner,
({ ({
Completer<DebugConnectionInfo> connectionInfoCompleter, Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void> appStartedCompleter, Completer<void>? appStartedCompleter,
}) { }) {
return runner.run( return runner.run(
connectionInfoCompleter: connectionInfoCompleter, connectionInfoCompleter: connectionInfoCompleter,
@ -588,7 +586,7 @@ class AppDomain extends Domain {
ResidentRunner runner, ResidentRunner runner,
RunOrAttach runOrAttach, RunOrAttach runOrAttach,
Device device, Device device,
String projectDirectory, String? projectDirectory,
bool enableHotReload, bool enableHotReload,
Directory cwd, Directory cwd,
LaunchMode launchMode, LaunchMode launchMode,
@ -610,7 +608,7 @@ class AppDomain extends Domain {
'launchMode': launchMode.toString(), 'launchMode': launchMode.toString(),
}); });
Completer<DebugConnectionInfo> connectionInfoCompleter; Completer<DebugConnectionInfo>? connectionInfoCompleter;
if (runner.debuggingEnabled) { if (runner.debuggingEnabled) {
connectionInfoCompleter = Completer<DebugConnectionInfo>(); connectionInfoCompleter = Completer<DebugConnectionInfo>();
@ -620,7 +618,7 @@ class AppDomain extends Domain {
(DebugConnectionInfo info) { (DebugConnectionInfo info) {
final Map<String, dynamic> params = <String, dynamic>{ final Map<String, dynamic> params = <String, dynamic>{
// The web vmservice proxy does not have an http address. // The web vmservice proxy does not have an http address.
'port': info.httpUri?.port ?? info.wsUri.port, 'port': info.httpUri?.port ?? info.wsUri!.port,
'wsUri': info.wsUri.toString(), 'wsUri': info.wsUri.toString(),
}; };
if (info.baseUri != null) { if (info.baseUri != null) {
@ -664,16 +662,16 @@ class AppDomain extends Domain {
final int _hotReloadDebounceDurationMs = 50; final int _hotReloadDebounceDurationMs = 50;
Future<OperationResult> restart(Map<String, dynamic> args) async { Future<OperationResult>? restart(Map<String, dynamic> args) async {
final String appId = _getStringArg(args, 'appId', required: true); final String? appId = _getStringArg(args, 'appId', required: true);
final bool fullRestart = _getBoolArg(args, 'fullRestart') ?? false; final bool fullRestart = _getBoolArg(args, 'fullRestart') ?? false;
final bool pauseAfterRestart = _getBoolArg(args, 'pause') ?? false; final bool pauseAfterRestart = _getBoolArg(args, 'pause') ?? false;
final String restartReason = _getStringArg(args, 'reason'); final String? restartReason = _getStringArg(args, 'reason');
final bool debounce = _getBoolArg(args, 'debounce') ?? false; final bool debounce = _getBoolArg(args, 'debounce') ?? false;
// This is an undocumented parameter used for integration tests. // This is an undocumented parameter used for integration tests.
final int debounceDurationOverrideMs = _getIntArg(args, 'debounceDurationOverrideMs'); final int? debounceDurationOverrideMs = _getIntArg(args, 'debounceDurationOverrideMs');
final AppInstance app = _getApp(appId); final AppInstance? app = _getApp(appId);
if (app == null) { if (app == null) {
throw DaemonException("app '$appId' not found"); throw DaemonException("app '$appId' not found");
} }
@ -689,7 +687,7 @@ class AppDomain extends Domain {
pause: pauseAfterRestart, pause: pauseAfterRestart,
reason: restartReason); reason: restartReason);
}, },
); )!;
} }
/// Debounce and queue reload actions. /// Debounce and queue reload actions.
@ -699,11 +697,11 @@ class AppDomain extends Domain {
/// and all return the same result. If an action is requested after an identical /// and all return the same result. If an action is requested after an identical
/// action has already started, it will be queued and run again once the first /// action has already started, it will be queued and run again once the first
/// action completes. /// action completes.
Future<OperationResult> _queueAndDebounceReloadAction( Future<OperationResult>? _queueAndDebounceReloadAction(
AppInstance app, AppInstance app,
OperationType operationType, OperationType operationType,
bool debounce, bool debounce,
int debounceDurationOverrideMs, int? debounceDurationOverrideMs,
Future<OperationResult> Function() action, Future<OperationResult> Function() action,
) { ) {
final Duration debounceDuration = debounce final Duration debounceDuration = debounce
@ -727,39 +725,40 @@ class AppDomain extends Domain {
/// "method":"ext.flutter.platformOverride" /// "method":"ext.flutter.platformOverride"
/// } /// }
Future<Map<String, dynamic>> callServiceExtension(Map<String, dynamic> args) async { Future<Map<String, dynamic>> callServiceExtension(Map<String, dynamic> args) async {
final String appId = _getStringArg(args, 'appId', required: true); final String? appId = _getStringArg(args, 'appId', required: true);
final String methodName = _getStringArg(args, 'methodName'); final String methodName = _getStringArg(args, 'methodName')!;
final Map<String, dynamic> params = args['params'] == null ? <String, dynamic>{} : castStringKeyedMap(args['params']); final Map<String, dynamic>? params = args['params'] == null ? <String, dynamic>{} : castStringKeyedMap(args['params']);
final AppInstance app = _getApp(appId); final AppInstance? app = _getApp(appId);
if (app == null) { if (app == null) {
throw DaemonException("app '$appId' not found"); throw DaemonException("app '$appId' not found");
} }
final FlutterDevice device = app.runner.flutterDevices.first; final FlutterDevice device = app.runner!.flutterDevices.first!;
final List<FlutterView> views = await device.vmService.getFlutterViews(); final List<FlutterView> views = await device.vmService!.getFlutterViews();
final Map<String, dynamic> result = await device final Map<String, dynamic>? result = await device
.vmService .vmService!
.invokeFlutterExtensionRpcRaw( .invokeFlutterExtensionRpcRaw(
methodName, methodName,
args: params, args: params,
isolateId: views isolateId: views
.first.uiIsolate.id .first.uiIsolate!.id!
); );
if (result == null) { if (result == null) {
throw DaemonException('method not available: $methodName'); throw DaemonException('method not available: $methodName');
} }
if (result.containsKey('error')) { if (result.containsKey('error')) {
throw result['error']; // ignore: only_throw_errors
throw result['error']! as Object;
} }
return result; return result;
} }
Future<bool> stop(Map<String, dynamic> args) async { Future<bool> stop(Map<String, dynamic> args) async {
final String appId = _getStringArg(args, 'appId', required: true); final String? appId = _getStringArg(args, 'appId', required: true);
final AppInstance app = _getApp(appId); final AppInstance? app = _getApp(appId);
if (app == null) { if (app == null) {
throw DaemonException("app '$appId' not found"); throw DaemonException("app '$appId' not found");
} }
@ -776,9 +775,9 @@ class AppDomain extends Domain {
} }
Future<bool> detach(Map<String, dynamic> args) async { Future<bool> detach(Map<String, dynamic> args) async {
final String appId = _getStringArg(args, 'appId', required: true); final String? appId = _getStringArg(args, 'appId', required: true);
final AppInstance app = _getApp(appId); final AppInstance? app = _getApp(appId);
if (app == null) { if (app == null) {
throw DaemonException("app '$appId' not found"); throw DaemonException("app '$appId' not found");
} }
@ -794,11 +793,16 @@ class AppDomain extends Domain {
); );
} }
AppInstance _getApp(String id) { AppInstance? _getApp(String? id) {
return _apps.firstWhere((AppInstance app) => app.id == id, orElse: () => null); for (final AppInstance app in _apps) {
if (app.id == id) {
return app;
}
}
return null;
} }
void _sendAppEvent(AppInstance app, String name, [ Map<String, dynamic> args ]) { void _sendAppEvent(AppInstance app, String name, [ Map<String, dynamic>? args ]) {
sendEvent('app.$name', <String, dynamic>{ sendEvent('app.$name', <String, dynamic>{
'appId': app.id, 'appId': app.id,
...?args, ...?args,
@ -830,12 +834,12 @@ class DeviceDomain extends Domain {
// Use the device manager discovery so that client provided device types // Use the device manager discovery so that client provided device types
// are usable via the daemon protocol. // are usable via the daemon protocol.
globals.deviceManager.deviceDiscoverers.forEach(addDeviceDiscoverer); globals.deviceManager!.deviceDiscoverers.forEach(addDeviceDiscoverer);
} }
/// An incrementing number used to generate unique ids. /// An incrementing number used to generate unique ids.
int _id = 0; int _id = 0;
final Map<String, ApplicationPackage> _applicationPackages = <String, ApplicationPackage>{}; final Map<String, ApplicationPackage?> _applicationPackages = <String, ApplicationPackage?>{};
final Map<String, DeviceLogReader> _logReaders = <String, DeviceLogReader>{}; final Map<String, DeviceLogReader> _logReaders = <String, DeviceLogReader>{};
void addDeviceDiscoverer(DeviceDiscovery discoverer) { void addDeviceDiscoverer(DeviceDiscovery discoverer) {
@ -856,7 +860,7 @@ class DeviceDomain extends Domain {
return (Device device) { return (Device device) {
_serializeDeviceEvents = _serializeDeviceEvents.then<void>((_) async { _serializeDeviceEvents = _serializeDeviceEvents.then<void>((_) async {
try { try {
final Map<String, Object> response = await _deviceToMap(device); final Map<String, Object?> response = await _deviceToMap(device);
sendEvent(eventName, response); sendEvent(eventName, response);
} on Exception catch (err) { } on Exception catch (err) {
globals.printError('$err'); globals.printError('$err');
@ -869,7 +873,7 @@ class DeviceDomain extends Domain {
/// Return a list of the current devices, with each device represented as a map /// Return a list of the current devices, with each device represented as a map
/// of properties (id, name, platform, ...). /// of properties (id, name, platform, ...).
Future<List<Map<String, dynamic>>> getDevices([ Map<String, dynamic> args ]) async { Future<List<Map<String, dynamic>>> getDevices([ Map<String, dynamic>? args ]) async {
return <Map<String, dynamic>>[ return <Map<String, dynamic>>[
for (final PollingDeviceDiscovery discoverer in _discoverers) for (final PollingDeviceDiscovery discoverer in _discoverers)
for (final Device device in await discoverer.devices) for (final Device device in await discoverer.devices)
@ -878,7 +882,7 @@ class DeviceDomain extends Domain {
} }
/// Return a list of the current devices, discarding existing cache of devices. /// Return a list of the current devices, discarding existing cache of devices.
Future<List<Map<String, dynamic>>> discoverDevices([ Map<String, dynamic> args ]) async { Future<List<Map<String, dynamic>>> discoverDevices([ Map<String, dynamic>? args ]) async {
return <Map<String, dynamic>>[ return <Map<String, dynamic>>[
for (final PollingDeviceDiscovery discoverer in _discoverers) for (final PollingDeviceDiscovery discoverer in _discoverers)
for (final Device device in await discoverer.discoverDevices()) for (final Device device in await discoverer.discoverDevices())
@ -902,50 +906,50 @@ class DeviceDomain extends Domain {
/// Forward a host port to a device port. /// Forward a host port to a device port.
Future<Map<String, dynamic>> forward(Map<String, dynamic> args) async { Future<Map<String, dynamic>> forward(Map<String, dynamic> args) async {
final String deviceId = _getStringArg(args, 'deviceId', required: true); final String? deviceId = _getStringArg(args, 'deviceId', required: true);
final int devicePort = _getIntArg(args, 'devicePort', required: true); final int devicePort = _getIntArg(args, 'devicePort', required: true)!;
int hostPort = _getIntArg(args, 'hostPort'); int? hostPort = _getIntArg(args, 'hostPort');
final Device device = await daemon.deviceDomain._getDevice(deviceId); final Device? device = await daemon.deviceDomain._getDevice(deviceId);
if (device == null) { if (device == null) {
throw DaemonException("device '$deviceId' not found"); throw DaemonException("device '$deviceId' not found");
} }
hostPort = await device.portForwarder.forward(devicePort, hostPort: hostPort); hostPort = await device.portForwarder!.forward(devicePort, hostPort: hostPort);
return <String, dynamic>{'hostPort': hostPort}; return <String, dynamic>{'hostPort': hostPort};
} }
/// Removes a forwarded port. /// Removes a forwarded port.
Future<void> unforward(Map<String, dynamic> args) async { Future<void> unforward(Map<String, dynamic> args) async {
final String deviceId = _getStringArg(args, 'deviceId', required: true); final String? deviceId = _getStringArg(args, 'deviceId', required: true);
final int devicePort = _getIntArg(args, 'devicePort', required: true); final int devicePort = _getIntArg(args, 'devicePort', required: true)!;
final int hostPort = _getIntArg(args, 'hostPort', required: true); final int hostPort = _getIntArg(args, 'hostPort', required: true)!;
final Device device = await daemon.deviceDomain._getDevice(deviceId); final Device? device = await daemon.deviceDomain._getDevice(deviceId);
if (device == null) { if (device == null) {
throw DaemonException("device '$deviceId' not found"); throw DaemonException("device '$deviceId' not found");
} }
return device.portForwarder.unforward(ForwardedPort(hostPort, devicePort)); return device.portForwarder!.unforward(ForwardedPort(hostPort, devicePort));
} }
/// Returns whether a device supports runtime mode. /// Returns whether a device supports runtime mode.
Future<bool> supportsRuntimeMode(Map<String, dynamic> args) async { Future<bool> supportsRuntimeMode(Map<String, dynamic> args) async {
final String deviceId = _getStringArg(args, 'deviceId', required: true); final String? deviceId = _getStringArg(args, 'deviceId', required: true);
final Device device = await daemon.deviceDomain._getDevice(deviceId); final Device? device = await daemon.deviceDomain._getDevice(deviceId);
if (device == null) { if (device == null) {
throw DaemonException("device '$deviceId' not found"); throw DaemonException("device '$deviceId' not found");
} }
final String buildMode = _getStringArg(args, 'buildMode', required: true); final String buildMode = _getStringArg(args, 'buildMode', required: true)!;
return await device.supportsRuntimeMode(getBuildModeForName(buildMode)); return await device.supportsRuntimeMode(getBuildModeForName(buildMode));
} }
/// Creates an application package from a file in the temp directory. /// Creates an application package from a file in the temp directory.
Future<String> uploadApplicationPackage(Map<String, dynamic> args) async { Future<String> uploadApplicationPackage(Map<String, dynamic> args) async {
final TargetPlatform targetPlatform = getTargetPlatformForName(_getStringArg(args, 'targetPlatform', required: true)); final TargetPlatform targetPlatform = getTargetPlatformForName(_getStringArg(args, 'targetPlatform', required: true)!);
final File applicationBinary = daemon.proxyDomain.tempDirectory.childFile(_getStringArg(args, 'applicationBinary', required: true)); final File applicationBinary = daemon.proxyDomain.tempDirectory.childFile(_getStringArg(args, 'applicationBinary', required: true)!);
final ApplicationPackage applicationPackage = await ApplicationPackageFactory.instance.getPackageForPlatform( final ApplicationPackage? applicationPackage = await ApplicationPackageFactory.instance!.getPackageForPlatform(
targetPlatform, targetPlatform,
applicationBinary: applicationBinary, applicationBinary: applicationBinary,
); );
@ -956,13 +960,13 @@ class DeviceDomain extends Domain {
/// Starts the log reader on the device. /// Starts the log reader on the device.
Future<String> startLogReader(Map<String, dynamic> args) async { Future<String> startLogReader(Map<String, dynamic> args) async {
final String deviceId = _getStringArg(args, 'deviceId', required: true); final String? deviceId = _getStringArg(args, 'deviceId', required: true);
final Device device = await daemon.deviceDomain._getDevice(deviceId); final Device? device = await daemon.deviceDomain._getDevice(deviceId);
if (device == null) { if (device == null) {
throw DaemonException("device '$deviceId' not found"); throw DaemonException("device '$deviceId' not found");
} }
final String applicationPackageId = _getStringArg(args, 'applicationPackageId'); final String? applicationPackageId = _getStringArg(args, 'applicationPackageId');
final ApplicationPackage applicationPackage = applicationPackageId != null ? _applicationPackages[applicationPackageId] : null; final ApplicationPackage? applicationPackage = applicationPackageId != null ? _applicationPackages[applicationPackageId] : null;
final String id = '${deviceId}_${_id++}'; final String id = '${deviceId}_${_id++}';
final DeviceLogReader logReader = await device.getLogReader(app: applicationPackage); final DeviceLogReader logReader = await device.getLogReader(app: applicationPackage);
@ -975,32 +979,32 @@ class DeviceDomain extends Domain {
/// Stops a log reader that was previously started. /// Stops a log reader that was previously started.
Future<void> stopLogReader(Map<String, dynamic> args) async { Future<void> stopLogReader(Map<String, dynamic> args) async {
final String id = _getStringArg(args, 'id', required: true); final String? id = _getStringArg(args, 'id', required: true);
_logReaders.remove(id)?.dispose(); _logReaders.remove(id)?.dispose();
} }
/// Starts an app on a device. /// Starts an app on a device.
Future<Map<String, dynamic>> startApp(Map<String, dynamic> args) async { Future<Map<String, dynamic>> startApp(Map<String, dynamic> args) async {
final String deviceId = _getStringArg(args, 'deviceId', required: true); final String? deviceId = _getStringArg(args, 'deviceId', required: true);
final Device device = await daemon.deviceDomain._getDevice(deviceId); final Device? device = await daemon.deviceDomain._getDevice(deviceId);
if (device == null) { if (device == null) {
throw DaemonException("device '$deviceId' not found"); throw DaemonException("device '$deviceId' not found");
} }
final String applicationPackageId = _getStringArg(args, 'applicationPackageId', required: true); final String? applicationPackageId = _getStringArg(args, 'applicationPackageId', required: true);
final ApplicationPackage applicationPackage = _applicationPackages[applicationPackageId]; final ApplicationPackage applicationPackage = _applicationPackages[applicationPackageId!]!;
final LaunchResult result = await device.startApp( final LaunchResult result = await device.startApp(
applicationPackage, applicationPackage,
debuggingOptions: DebuggingOptions.fromJson( debuggingOptions: DebuggingOptions.fromJson(
castStringKeyedMap(args['debuggingOptions']), castStringKeyedMap(args['debuggingOptions'])!,
// We are using prebuilts, build info does not matter here. // We are using prebuilts, build info does not matter here.
BuildInfo.debug, BuildInfo.debug,
), ),
mainPath: _getStringArg(args, 'mainPath'), mainPath: _getStringArg(args, 'mainPath'),
route: _getStringArg(args, 'route'), route: _getStringArg(args, 'route'),
platformArgs: castStringKeyedMap(args['platformArgs']), platformArgs: castStringKeyedMap(args['platformArgs']) ?? const <String, Object>{},
prebuiltApplication: _getBoolArg(args, 'prebuiltApplication'), prebuiltApplication: _getBoolArg(args, 'prebuiltApplication') ?? false,
ipv6: _getBoolArg(args, 'ipv6'), ipv6: _getBoolArg(args, 'ipv6') ?? false,
userIdentifier: _getStringArg(args, 'userIdentifier'), userIdentifier: _getStringArg(args, 'userIdentifier'),
); );
return <String, dynamic>{ return <String, dynamic>{
@ -1011,13 +1015,13 @@ class DeviceDomain extends Domain {
/// Stops an app. /// Stops an app.
Future<bool> stopApp(Map<String, dynamic> args) async { Future<bool> stopApp(Map<String, dynamic> args) async {
final String deviceId = _getStringArg(args, 'deviceId', required: true); final String? deviceId = _getStringArg(args, 'deviceId', required: true);
final Device device = await daemon.deviceDomain._getDevice(deviceId); final Device? device = await daemon.deviceDomain._getDevice(deviceId);
if (device == null) { if (device == null) {
throw DaemonException("device '$deviceId' not found"); throw DaemonException("device '$deviceId' not found");
} }
final String applicationPackageId = _getStringArg(args, 'applicationPackageId', required: true); final String? applicationPackageId = _getStringArg(args, 'applicationPackageId', required: true);
final ApplicationPackage applicationPackage = _applicationPackages[applicationPackageId]; final ApplicationPackage applicationPackage = _applicationPackages[applicationPackageId!]!;
return device.stopApp( return device.stopApp(
applicationPackage, applicationPackage,
userIdentifier: _getStringArg(args, 'userIdentifier'), userIdentifier: _getStringArg(args, 'userIdentifier'),
@ -1025,9 +1029,9 @@ class DeviceDomain extends Domain {
} }
/// Takes a screenshot. /// Takes a screenshot.
Future<String> takeScreenshot(Map<String, dynamic> args) async { Future<String?> takeScreenshot(Map<String, dynamic> args) async {
final String deviceId = _getStringArg(args, 'deviceId', required: true); final String? deviceId = _getStringArg(args, 'deviceId', required: true);
final Device device = await daemon.deviceDomain._getDevice(deviceId); final Device? device = await daemon.deviceDomain._getDevice(deviceId);
if (device == null) { if (device == null) {
throw DaemonException("device '$deviceId' not found"); throw DaemonException("device '$deviceId' not found");
} }
@ -1051,9 +1055,15 @@ class DeviceDomain extends Domain {
} }
/// Return the device matching the deviceId field in the args. /// Return the device matching the deviceId field in the args.
Future<Device> _getDevice(String deviceId) async { Future<Device?> _getDevice(String? deviceId) async {
for (final PollingDeviceDiscovery discoverer in _discoverers) { for (final PollingDeviceDiscovery discoverer in _discoverers) {
final Device device = (await discoverer.devices).firstWhere((Device device) => device.id == deviceId, orElse: () => null); final List<Device> devices = await discoverer.devices;
Device? device;
for (final Device localDevice in devices) {
if (localDevice.id == deviceId) {
device = localDevice;
}
}
if (device != null) { if (device != null) {
return device; return device;
} }
@ -1067,11 +1077,11 @@ class DevToolsDomain extends Domain {
registerHandler('serve', serve); registerHandler('serve', serve);
} }
DevtoolsLauncher _devtoolsLauncher; DevtoolsLauncher? _devtoolsLauncher;
Future<Map<String, dynamic>> serve([ Map<String, dynamic> args ]) async { Future<Map<String, dynamic>> serve([ Map<String, dynamic>? args ]) async {
_devtoolsLauncher ??= DevtoolsLauncher.instance; _devtoolsLauncher ??= DevtoolsLauncher.instance;
final DevToolsServerAddress server = await _devtoolsLauncher.serve(); final DevToolsServerAddress? server = await _devtoolsLauncher?.serve();
return<String, dynamic>{ return<String, dynamic>{
'host': server?.host, 'host': server?.host,
'port': server?.port, 'port': server?.port,
@ -1111,8 +1121,8 @@ Map<String, dynamic> _emulatorToMap(Emulator emulator) {
return <String, dynamic>{ return <String, dynamic>{
'id': emulator.id, 'id': emulator.id,
'name': emulator.name, 'name': emulator.name,
'category': emulator.category?.toString(), 'category': emulator.category.toString(),
'platformType': emulator.platformType?.toString(), 'platformType': emulator.platformType.toString(),
}; };
} }
@ -1123,7 +1133,7 @@ Map<String, dynamic> _operationResultToMap(OperationResult result) {
}; };
} }
dynamic _toJsonable(dynamic obj) { Object? _toJsonable(dynamic obj) {
if (obj is String || obj is int || obj is bool || obj is Map<dynamic, dynamic> || obj is List<dynamic> || obj == null) { if (obj is String || obj is int || obj is bool || obj is Map<dynamic, dynamic> || obj is List<dynamic> || obj == null) {
return obj; return obj;
} }
@ -1137,7 +1147,7 @@ dynamic _toJsonable(dynamic obj) {
} }
class NotifyingLogger extends DelegatingLogger { class NotifyingLogger extends DelegatingLogger {
NotifyingLogger({ @required this.verbose, @required Logger parent }) : super(parent) { NotifyingLogger({ required this.verbose, required Logger parent }) : super(parent) {
_messageController = StreamController<LogMessage>.broadcast( _messageController = StreamController<LogMessage>.broadcast(
onListen: _onListen, onListen: _onListen,
); );
@ -1145,7 +1155,7 @@ class NotifyingLogger extends DelegatingLogger {
final bool verbose; final bool verbose;
final List<LogMessage> messageBuffer = <LogMessage>[]; final List<LogMessage> messageBuffer = <LogMessage>[];
StreamController<LogMessage> _messageController; late StreamController<LogMessage> _messageController;
void _onListen() { void _onListen() {
if (messageBuffer.isNotEmpty) { if (messageBuffer.isNotEmpty) {
@ -1159,12 +1169,12 @@ class NotifyingLogger extends DelegatingLogger {
@override @override
void printError( void printError(
String message, { String message, {
StackTrace stackTrace, StackTrace? stackTrace,
bool emphasis = false, bool? emphasis = false,
TerminalColor color, TerminalColor? color,
int indent, int? indent,
int hangingIndent, int? hangingIndent,
bool wrap, bool? wrap,
}) { }) {
_sendMessage(LogMessage('error', message, stackTrace)); _sendMessage(LogMessage('error', message, stackTrace));
} }
@ -1172,11 +1182,11 @@ class NotifyingLogger extends DelegatingLogger {
@override @override
void printWarning( void printWarning(
String message, { String message, {
bool emphasis = false, bool? emphasis = false,
TerminalColor color, TerminalColor? color,
int indent, int? indent,
int hangingIndent, int? hangingIndent,
bool wrap, bool? wrap,
}) { }) {
_sendMessage(LogMessage('warning', message)); _sendMessage(LogMessage('warning', message));
} }
@ -1184,19 +1194,19 @@ class NotifyingLogger extends DelegatingLogger {
@override @override
void printStatus( void printStatus(
String message, { String message, {
bool emphasis = false, bool? emphasis = false,
TerminalColor color, TerminalColor? color,
bool newline = true, bool? newline = true,
int indent, int? indent,
int hangingIndent, int? hangingIndent,
bool wrap, bool? wrap,
}) { }) {
_sendMessage(LogMessage('status', message)); _sendMessage(LogMessage('status', message));
} }
@override @override
void printBox(String message, { void printBox(String message, {
String title, String? title,
}) { }) {
_sendMessage(LogMessage('status', title == null ? message : '$title: $message')); _sendMessage(LogMessage('status', title == null ? message : '$title: $message'));
} }
@ -1212,8 +1222,8 @@ class NotifyingLogger extends DelegatingLogger {
@override @override
Status startProgress( Status startProgress(
String message, { String message, {
@required Duration timeout, Duration? timeout,
String progressId, String? progressId,
bool multilineOutput = false, bool multilineOutput = false,
bool includeTiming = true, bool includeTiming = true,
int progressIndicatorPadding = kDefaultStatusPadding, int progressIndicatorPadding = kDefaultStatusPadding,
@ -1237,7 +1247,7 @@ class NotifyingLogger extends DelegatingLogger {
} }
@override @override
void sendEvent(String name, [Map<String, dynamic> args]) { } void sendEvent(String name, [Map<String, dynamic>? args]) { }
@override @override
bool get supportsColor => throw UnimplementedError(); bool get supportsColor => throw UnimplementedError();
@ -1252,20 +1262,20 @@ class NotifyingLogger extends DelegatingLogger {
/// A running application, started by this daemon. /// A running application, started by this daemon.
class AppInstance { class AppInstance {
AppInstance(this.id, { this.runner, this.logToStdout = false, @required AppRunLogger logger }) AppInstance(this.id, { this.runner, this.logToStdout = false, required AppRunLogger logger })
: _logger = logger; : _logger = logger;
final String id; final String id;
final ResidentRunner runner; final ResidentRunner? runner;
final bool logToStdout; final bool logToStdout;
final AppRunLogger _logger; final AppRunLogger _logger;
Future<OperationResult> restart({ bool fullRestart = false, bool pause = false, String reason }) { Future<OperationResult> restart({ bool fullRestart = false, bool pause = false, String? reason }) {
return runner.restart(fullRestart: fullRestart, pause: pause, reason: reason); return runner!.restart(fullRestart: fullRestart, pause: pause, reason: reason);
} }
Future<void> stop() => runner.exit(); Future<void> stop() => runner!.exit();
Future<void> detach() => runner.detach(); Future<void> detach() => runner!.detach();
void closeLogger() { void closeLogger() {
_logger.close(); _logger.close();
@ -1289,16 +1299,16 @@ class EmulatorDomain extends Domain {
logger: globals.logger, logger: globals.logger,
androidSdk: globals.androidSdk, androidSdk: globals.androidSdk,
processManager: globals.processManager, processManager: globals.processManager,
androidWorkflow: androidWorkflow, androidWorkflow: androidWorkflow!,
); );
Future<List<Map<String, dynamic>>> getEmulators([ Map<String, dynamic> args ]) async { Future<List<Map<String, dynamic>>> getEmulators([ Map<String, dynamic>? args ]) async {
final List<Emulator> list = await emulators.getAllAvailableEmulators(); final List<Emulator> list = await emulators.getAllAvailableEmulators();
return list.map<Map<String, dynamic>>(_emulatorToMap).toList(); return list.map<Map<String, dynamic>>(_emulatorToMap).toList();
} }
Future<void> launch(Map<String, dynamic> args) async { Future<void> launch(Map<String, dynamic> args) async {
final String emulatorId = _getStringArg(args, 'emulatorId', required: true); final String emulatorId = _getStringArg(args, 'emulatorId', required: true)!;
final bool coldBoot = _getBoolArg(args, 'coldBoot') ?? false; final bool coldBoot = _getBoolArg(args, 'coldBoot') ?? false;
final List<Emulator> matches = final List<Emulator> matches =
await emulators.getEmulatorsMatching(emulatorId); await emulators.getEmulatorsMatching(emulatorId);
@ -1312,7 +1322,7 @@ class EmulatorDomain extends Domain {
} }
Future<Map<String, dynamic>> create(Map<String, dynamic> args) async { Future<Map<String, dynamic>> create(Map<String, dynamic> args) async {
final String name = _getStringArg(args, 'name'); final String? name = _getStringArg(args, 'name');
final CreateEmulatorResult res = await emulators.createEmulator(name: name); final CreateEmulatorResult res = await emulators.createEmulator(name: name);
return <String, dynamic>{ return <String, dynamic>{
'success': res.success, 'success': res.success,
@ -1336,16 +1346,16 @@ class ProxyDomain extends Domain {
int _id = 0; int _id = 0;
/// Writes to a file in a local temporary directory. /// Writes to a file in a local temporary directory.
Future<void> writeTempFile(Map<String, dynamic> args, Stream<List<int>> binary) async { Future<void> writeTempFile(Map<String, dynamic> args, Stream<List<int>>? binary) async {
final String path = _getStringArg(args, 'path', required: true); final String path = _getStringArg(args, 'path', required: true)!;
final File file = tempDirectory.childFile(path); final File file = tempDirectory.childFile(path);
await file.parent.create(recursive: true); await file.parent.create(recursive: true);
await file.openWrite().addStream(binary); await file.openWrite().addStream(binary!);
} }
/// Calculate rolling hashes for a file in the local temporary directory. /// Calculate rolling hashes for a file in the local temporary directory.
Future<Map<String, dynamic>> calculateFileHashes(Map<String, dynamic> args) async { Future<Map<String, dynamic>?> calculateFileHashes(Map<String, dynamic> args) async {
final String path = _getStringArg(args, 'path', required: true); final String path = _getStringArg(args, 'path', required: true)!;
final File file = tempDirectory.childFile(path); final File file = tempDirectory.childFile(path);
if (!await file.exists()) { if (!await file.exists()) {
return null; return null;
@ -1354,24 +1364,24 @@ class ProxyDomain extends Domain {
return result.toJson(); return result.toJson();
} }
Future<bool> updateFile(Map<String, dynamic> args, Stream<List<int>> binary) async { Future<bool?> updateFile(Map<String, dynamic> args, Stream<List<int>>? binary) async {
final String path = _getStringArg(args, 'path', required: true); final String path = _getStringArg(args, 'path', required: true)!;
final File file = tempDirectory.childFile(path); final File file = tempDirectory.childFile(path);
if (!await file.exists()) { if (!await file.exists()) {
return null; return null;
} }
final List<Map<String, dynamic>> deltaJson = (args['delta'] as List<dynamic>).cast<Map<String, dynamic>>(); final List<Map<String, dynamic>> deltaJson = (args['delta'] as List<dynamic>).cast<Map<String, dynamic>>();
final List<FileDeltaBlock> delta = FileDeltaBlock.fromJsonList(deltaJson); final List<FileDeltaBlock> delta = FileDeltaBlock.fromJsonList(deltaJson);
final bool result = await FileTransfer().rebuildFile(file, delta, binary); final bool result = await FileTransfer().rebuildFile(file, delta, binary!);
return result; return result;
} }
/// Opens a connection to a local port, and returns the connection id. /// Opens a connection to a local port, and returns the connection id.
Future<String> connect(Map<String, dynamic> args) async { Future<String> connect(Map<String, dynamic> args) async {
final int targetPort = _getIntArg(args, 'port', required: true); final int targetPort = _getIntArg(args, 'port', required: true)!;
final String id = 'portForwarder_${targetPort}_${_id++}'; final String id = 'portForwarder_${targetPort}_${_id++}';
Socket socket; Socket? socket;
try { try {
socket = await Socket.connect(InternetAddress.loopbackIPv4, targetPort); socket = await Socket.connect(InternetAddress.loopbackIPv4, targetPort);
@ -1409,7 +1419,7 @@ class ProxyDomain extends Domain {
/// Disconnects from a previously established connection. /// Disconnects from a previously established connection.
Future<bool> disconnect(Map<String, dynamic> args) async { Future<bool> disconnect(Map<String, dynamic> args) async {
final String id = _getStringArg(args, 'id', required: true); final String? id = _getStringArg(args, 'id', required: true);
if (_forwardedConnections.containsKey(id)) { if (_forwardedConnections.containsKey(id)) {
await _forwardedConnections.remove(id)?.close(); await _forwardedConnections.remove(id)?.close();
return true; return true;
@ -1418,10 +1428,10 @@ class ProxyDomain extends Domain {
} }
/// Writes to a previously established connection. /// Writes to a previously established connection.
Future<bool> write(Map<String, dynamic> args, Stream<List<int>> binary) async { Future<bool> write(Map<String, dynamic> args, Stream<List<int>>? binary) async {
final String id = _getStringArg(args, 'id', required: true); final String? id = _getStringArg(args, 'id', required: true);
if (_forwardedConnections.containsKey(id)) { if (_forwardedConnections.containsKey(id)) {
final StreamSubscription<List<int>> subscription = binary.listen(_forwardedConnections[id].add); final StreamSubscription<List<int>> subscription = binary!.listen(_forwardedConnections[id!]!.add);
await subscription.asFuture<void>(); await subscription.asFuture<void>();
await subscription.cancel(); await subscription.cancel();
return true; return true;
@ -1439,7 +1449,7 @@ class ProxyDomain extends Domain {
// to be reused on any subsequent runs. // to be reused on any subsequent runs.
} }
Directory _tempDirectory; Directory? _tempDirectory;
Directory get tempDirectory => _tempDirectory ??= globals.fs.systemTempDirectory.childDirectory('flutter_tool_daemon')..createSync(); Directory get tempDirectory => _tempDirectory ??= globals.fs.systemTempDirectory.childDirectory('flutter_tool_daemon')..createSync();
} }
@ -1452,19 +1462,19 @@ class ProxyDomain extends Domain {
// TODO(devoncarew): To simplify this code a bit, we could choose to specialize // TODO(devoncarew): To simplify this code a bit, we could choose to specialize
// this class into two, one for each of the above use cases. // this class into two, one for each of the above use cases.
class AppRunLogger extends DelegatingLogger { class AppRunLogger extends DelegatingLogger {
AppRunLogger({ @required Logger parent }) : super(parent); AppRunLogger({ required Logger parent }) : super(parent);
AppDomain domain; AppDomain? domain;
AppInstance app; late AppInstance app;
int _nextProgressId = 0; int _nextProgressId = 0;
Status _status; Status? _status;
@override @override
Status startProgress( Status startProgress(
String message, { String message, {
@required Duration timeout, Duration? timeout,
String progressId, String? progressId,
bool multilineOutput = false, bool multilineOutput = false,
bool includeTiming = true, bool includeTiming = true,
int progressIndicatorPadding = kDefaultStatusPadding, int progressIndicatorPadding = kDefaultStatusPadding,
@ -1486,7 +1496,7 @@ class AppRunLogger extends DelegatingLogger {
finished: true, finished: true,
); );
}, stopwatch: Stopwatch())..start(); }, stopwatch: Stopwatch())..start();
return _status; return _status!;
} }
void close() { void close() {
@ -1494,10 +1504,10 @@ class AppRunLogger extends DelegatingLogger {
} }
void _sendProgressEvent({ void _sendProgressEvent({
@required String eventId, required String eventId,
@required String eventType, required String? eventType,
bool finished = false, bool finished = false,
String message, String? message,
}) { }) {
if (domain == null) { if (domain == null) {
// If we're sending progress events before an app has started, send the // If we're sending progress events before an app has started, send the
@ -1513,16 +1523,16 @@ class AppRunLogger extends DelegatingLogger {
if (finished != null) 'finished': finished, if (finished != null) 'finished': finished,
}; };
domain._sendAppEvent(app, 'progress', event); domain!._sendAppEvent(app, 'progress', event);
} }
} }
@override @override
void sendEvent(String name, [Map<String, dynamic> args, List<int> binary]) { void sendEvent(String name, [Map<String, dynamic>? args, List<int>? binary]) {
if (domain == null) { if (domain == null) {
printStatus('event sent after app closed: $name'); printStatus('event sent after app closed: $name');
} else { } else {
domain.sendEvent(name, args, binary); domain!.sendEvent(name, args, binary);
} }
} }
@ -1542,7 +1552,7 @@ class LogMessage {
final String level; final String level;
final String message; final String message;
final StackTrace stackTrace; final StackTrace? stackTrace;
} }
/// The method by which the Flutter app was launched. /// The method by which the Flutter app was launched.
@ -1574,9 +1584,9 @@ enum OperationType {
class DebounceOperationQueue<T, K> { class DebounceOperationQueue<T, K> {
final Map<K, RestartableTimer> _debounceTimers = <K, RestartableTimer>{}; final Map<K, RestartableTimer> _debounceTimers = <K, RestartableTimer>{};
final Map<K, Future<T>> _operationQueue = <K, Future<T>>{}; final Map<K, Future<T>> _operationQueue = <K, Future<T>>{};
Future<void> _inProgressAction; Future<void>? _inProgressAction;
Future<T> queueAndDebounce( Future<T>? queueAndDebounce(
K operationType, K operationType,
Duration debounceDuration, Duration debounceDuration,
Future<T> Function() action, Future<T> Function() action,

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
@ -49,10 +49,10 @@ import 'run.dart';
class DriveCommand extends RunCommandBase { class DriveCommand extends RunCommandBase {
DriveCommand({ DriveCommand({
bool verboseHelp = false, bool verboseHelp = false,
@visibleForTesting FlutterDriverFactory flutterDriverFactory, @visibleForTesting FlutterDriverFactory? flutterDriverFactory,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required Logger logger, required Logger? logger,
@required Platform platform, required Platform platform,
}) : _flutterDriverFactory = flutterDriverFactory, }) : _flutterDriverFactory = flutterDriverFactory,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_logger = logger, _logger = logger,
@ -156,15 +156,15 @@ class DriveCommand extends RunCommandBase {
// specified not to. // specified not to.
@override @override
bool get shouldRunPub { bool get shouldRunPub {
if (argResults.wasParsed('pub') && !boolArgDeprecated('pub')) { if (argResults!.wasParsed('pub') && !boolArgDeprecated('pub')) {
return false; return false;
} }
return true; return true;
} }
FlutterDriverFactory _flutterDriverFactory; FlutterDriverFactory? _flutterDriverFactory;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final Logger _logger; final Logger? _logger;
final FileSystemUtils _fsUtils; final FileSystemUtils _fsUtils;
@override @override
@ -179,9 +179,9 @@ class DriveCommand extends RunCommandBase {
@override @override
final List<String> aliases = <String>['driver']; final List<String> aliases = <String>['driver'];
String get userIdentifier => stringArgDeprecated(FlutterOptions.kDeviceUser); String? get userIdentifier => stringArgDeprecated(FlutterOptions.kDeviceUser);
String get screenshot => stringArgDeprecated('screenshot'); String? get screenshot => stringArgDeprecated('screenshot');
@override @override
bool get startPausedDefault => true; bool get startPausedDefault => true;
@ -192,7 +192,7 @@ class DriveCommand extends RunCommandBase {
@override @override
Future<void> validateCommand() async { Future<void> validateCommand() async {
if (userIdentifier != null) { if (userIdentifier != null) {
final Device device = await findTargetDevice(); final Device? device = await findTargetDevice();
if (device is! AndroidDevice) { if (device is! AndroidDevice) {
throwToolExit('--${FlutterOptions.kDeviceUser} is only supported for Android'); throwToolExit('--${FlutterOptions.kDeviceUser} is only supported for Android');
} }
@ -202,39 +202,39 @@ class DriveCommand extends RunCommandBase {
@override @override
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
final String testFile = _getTestFile(); final String testFile = _getTestFile()!;
if (testFile == null) { if (testFile == null) {
throwToolExit(null); throwToolExit(null);
} }
if (await _fileSystem.type(testFile) != FileSystemEntityType.file) { if (await _fileSystem.type(testFile) != FileSystemEntityType.file) {
throwToolExit('Test file not found: $testFile'); throwToolExit('Test file not found: $testFile');
} }
final String applicationBinaryPath = stringArgDeprecated(FlutterOptions.kUseApplicationBinary); final String? applicationBinaryPath = stringArgDeprecated(FlutterOptions.kUseApplicationBinary);
final Device device = await findTargetDevice(includeUnsupportedDevices: applicationBinaryPath == null); final Device? device = await findTargetDevice(includeUnsupportedDevices: applicationBinaryPath == null);
if (device == null) { if (device == null) {
throwToolExit(null); throwToolExit(null);
} }
if (screenshot != null && !device.supportsScreenshot) { if (screenshot != null && !device.supportsScreenshot) {
_logger.printError('Screenshot not supported for ${device.name}.'); _logger!.printError('Screenshot not supported for ${device.name}.');
} }
final bool web = device is WebServerDevice || device is ChromiumDevice; final bool web = device is WebServerDevice || device is ChromiumDevice;
_flutterDriverFactory ??= FlutterDriverFactory( _flutterDriverFactory ??= FlutterDriverFactory(
applicationPackageFactory: ApplicationPackageFactory.instance, applicationPackageFactory: ApplicationPackageFactory.instance!,
logger: _logger, logger: _logger!,
processUtils: globals.processUtils, processUtils: globals.processUtils,
dartSdkPath: globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, dartSdkPath: globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path,
devtoolsLauncher: DevtoolsLauncher.instance, devtoolsLauncher: DevtoolsLauncher.instance!,
); );
final PackageConfig packageConfig = await loadPackageConfigWithLogging( final PackageConfig packageConfig = await loadPackageConfigWithLogging(
_fileSystem.file('.packages'), _fileSystem.file('.packages'),
logger: _logger, logger: _logger!,
throwOnError: false, throwOnError: false,
) ?? PackageConfig.empty; );
final DriverService driverService = _flutterDriverFactory.createDriverService(web); final DriverService driverService = _flutterDriverFactory!.createDriverService(web);
final BuildInfo buildInfo = await getBuildInfo(); final BuildInfo buildInfo = await getBuildInfo();
final DebuggingOptions debuggingOptions = await createDebuggingOptions(web); final DebuggingOptions debuggingOptions = await createDebuggingOptions(web);
final File applicationBinary = applicationBinaryPath == null final File? applicationBinary = applicationBinaryPath == null
? null ? null
: _fileSystem.file(applicationBinaryPath); : _fileSystem.file(applicationBinaryPath);
@ -245,7 +245,7 @@ class DriveCommand extends RunCommandBase {
buildInfo, buildInfo,
device, device,
debuggingOptions, debuggingOptions,
ipv6, ipv6 ?? false,
applicationBinary: applicationBinary, applicationBinary: applicationBinary,
route: route, route: route,
userIdentifier: userIdentifier, userIdentifier: userIdentifier,
@ -260,7 +260,7 @@ class DriveCommand extends RunCommandBase {
} }
); );
} else { } else {
final Uri uri = Uri.tryParse(stringArgDeprecated('use-existing-app')); final Uri? uri = Uri.tryParse(stringArgDeprecated('use-existing-app')!);
if (uri == null) { if (uri == null) {
throwToolExit('Invalid VM Service URI: ${stringArgDeprecated('use-existing-app')}'); throwToolExit('Invalid VM Service URI: ${stringArgDeprecated('use-existing-app')}');
} }
@ -268,7 +268,7 @@ class DriveCommand extends RunCommandBase {
uri, uri,
device, device,
debuggingOptions, debuggingOptions,
ipv6, ipv6 ?? false,
); );
} }
@ -279,10 +279,10 @@ class DriveCommand extends RunCommandBase {
packageConfig, packageConfig,
chromeBinary: stringArgDeprecated('chrome-binary'), chromeBinary: stringArgDeprecated('chrome-binary'),
headless: boolArgDeprecated('headless'), headless: boolArgDeprecated('headless'),
browserDimension: stringArgDeprecated('browser-dimension').split(','), browserDimension: stringArgDeprecated('browser-dimension')!.split(','),
browserName: stringArgDeprecated('browser-name'), browserName: stringArgDeprecated('browser-name'),
driverPort: stringArgDeprecated('driver-port') != null driverPort: stringArgDeprecated('driver-port') != null
? int.tryParse(stringArgDeprecated('driver-port')) ? int.tryParse(stringArgDeprecated('driver-port')!)
: null, : null,
androidEmulator: boolArgDeprecated('android-emulator'), androidEmulator: boolArgDeprecated('android-emulator'),
profileMemory: stringArgDeprecated('profile-memory'), profileMemory: stringArgDeprecated('profile-memory'),
@ -293,10 +293,10 @@ class DriveCommand extends RunCommandBase {
screenshotTaken = true; screenshotTaken = true;
} }
if (boolArgDeprecated('keep-app-running') ?? (argResults['use-existing-app'] != null)) { if (boolArgDeprecated('keep-app-running')) {
_logger.printStatus('Leaving the application running.'); _logger!.printStatus('Leaving the application running.');
} else { } else {
final File skslFile = stringArgDeprecated('write-sksl-on-exit') != null final File? skslFile = stringArgDeprecated('write-sksl-on-exit') != null
? _fileSystem.file(stringArgDeprecated('write-sksl-on-exit')) ? _fileSystem.file(stringArgDeprecated('write-sksl-on-exit'))
: null; : null;
await driverService.stop(userIdentifier: userIdentifier, writeSkslOnExit: skslFile); await driverService.stop(userIdentifier: userIdentifier, writeSkslOnExit: skslFile);
@ -316,8 +316,8 @@ class DriveCommand extends RunCommandBase {
return FlutterCommandResult.success(); return FlutterCommandResult.success();
} }
String _getTestFile() { String? _getTestFile() {
if (argResults['driver'] != null) { if (argResults!['driver'] != null) {
return stringArgDeprecated('driver'); return stringArgDeprecated('driver');
} }
@ -332,7 +332,7 @@ class DriveCommand extends RunCommandBase {
// for the corresponding test file relative to it. // for the corresponding test file relative to it.
if (!_fileSystem.path.isRelative(appFile)) { if (!_fileSystem.path.isRelative(appFile)) {
if (!_fileSystem.path.isWithin(packageDir, appFile)) { if (!_fileSystem.path.isWithin(packageDir, appFile)) {
_logger.printError( _logger!.printError(
'Application file $appFile is outside the package directory $packageDir' 'Application file $appFile is outside the package directory $packageDir'
); );
return null; return null;
@ -344,7 +344,7 @@ class DriveCommand extends RunCommandBase {
final List<String> parts = _fileSystem.path.split(appFile); final List<String> parts = _fileSystem.path.split(appFile);
if (parts.length < 2) { if (parts.length < 2) {
_logger.printError( _logger!.printError(
'Application file $appFile must reside in one of the sub-directories ' 'Application file $appFile must reside in one of the sub-directories '
'of the package structure, not in the root directory.' 'of the package structure, not in the root directory.'
); );
@ -372,9 +372,9 @@ class DriveCommand extends RunCommandBase {
'png', 'png',
); );
await device.takeScreenshot(outputFile); await device.takeScreenshot(outputFile);
_logger.printStatus('Screenshot written to ${outputFile.path}'); _logger!.printStatus('Screenshot written to ${outputFile.path}');
} on Exception catch (error) { } on Exception catch (error) {
_logger.printError('Error taking screenshot: $error'); _logger!.printError('Error taking screenshot: $error');
} }
} }
} }

View File

@ -2,10 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:meta/meta.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/platform.dart'; import '../base/platform.dart';
@ -18,10 +14,10 @@ import '../runner/flutter_command.dart';
class PrecacheCommand extends FlutterCommand { class PrecacheCommand extends FlutterCommand {
PrecacheCommand({ PrecacheCommand({
bool verboseHelp = false, bool verboseHelp = false,
@required Cache cache, required Cache? cache,
@required Platform platform, required Platform platform,
@required Logger logger, required Logger logger,
@required FeatureFlags featureFlags, required FeatureFlags featureFlags,
}) : _cache = cache, }) : _cache = cache,
_platform = platform, _platform = platform,
_logger = logger, _logger = logger,
@ -30,39 +26,39 @@ class PrecacheCommand extends FlutterCommand {
help: 'Precache artifacts for all host platforms.'); help: 'Precache artifacts for all host platforms.');
argParser.addFlag('force', abbr: 'f', negatable: false, argParser.addFlag('force', abbr: 'f', negatable: false,
help: 'Force re-downloading of artifacts.'); help: 'Force re-downloading of artifacts.');
argParser.addFlag('android', negatable: true, defaultsTo: false, argParser.addFlag('android',
help: 'Precache artifacts for Android development.', help: 'Precache artifacts for Android development.',
hide: !verboseHelp); hide: !verboseHelp);
argParser.addFlag('android_gen_snapshot', negatable: true, defaultsTo: false, argParser.addFlag('android_gen_snapshot',
help: 'Precache gen_snapshot for Android development.', help: 'Precache gen_snapshot for Android development.',
hide: !verboseHelp); hide: !verboseHelp);
argParser.addFlag('android_maven', negatable: true, defaultsTo: false, argParser.addFlag('android_maven',
help: 'Precache Gradle dependencies for Android development.', help: 'Precache Gradle dependencies for Android development.',
hide: !verboseHelp); hide: !verboseHelp);
argParser.addFlag('android_internal_build', negatable: true, defaultsTo: false, argParser.addFlag('android_internal_build',
help: 'Precache dependencies for internal Android development.', help: 'Precache dependencies for internal Android development.',
hide: !verboseHelp); hide: !verboseHelp);
argParser.addFlag('ios', negatable: true, defaultsTo: false, argParser.addFlag('ios',
help: 'Precache artifacts for iOS development.'); help: 'Precache artifacts for iOS development.');
argParser.addFlag('web', negatable: true, defaultsTo: false, argParser.addFlag('web',
help: 'Precache artifacts for web development.'); help: 'Precache artifacts for web development.');
argParser.addFlag('linux', negatable: true, defaultsTo: false, argParser.addFlag('linux',
help: 'Precache artifacts for Linux desktop development.'); help: 'Precache artifacts for Linux desktop development.');
argParser.addFlag('windows', negatable: true, defaultsTo: false, argParser.addFlag('windows',
help: 'Precache artifacts for Windows desktop development.'); help: 'Precache artifacts for Windows desktop development.');
argParser.addFlag('macos', negatable: true, defaultsTo: false, argParser.addFlag('macos',
help: 'Precache artifacts for macOS desktop development.'); help: 'Precache artifacts for macOS desktop development.');
argParser.addFlag('fuchsia', negatable: true, defaultsTo: false, argParser.addFlag('fuchsia',
help: 'Precache artifacts for Fuchsia development.'); help: 'Precache artifacts for Fuchsia development.');
argParser.addFlag('universal', negatable: true, defaultsTo: true, argParser.addFlag('universal', defaultsTo: true,
help: 'Precache artifacts required for any development platform.'); help: 'Precache artifacts required for any development platform.');
argParser.addFlag('flutter_runner', negatable: true, defaultsTo: false, argParser.addFlag('flutter_runner',
help: 'Precache the flutter runner artifacts.', hide: !verboseHelp); help: 'Precache the flutter runner artifacts.', hide: !verboseHelp);
argParser.addFlag('use-unsigned-mac-binaries', negatable: true, defaultsTo: false, argParser.addFlag('use-unsigned-mac-binaries',
help: 'Precache the unsigned macOS binaries when available.', hide: !verboseHelp); help: 'Precache the unsigned macOS binaries when available.', hide: !verboseHelp);
} }
final Cache _cache; final Cache? _cache;
final Logger _logger; final Logger _logger;
final Platform _platform; final Platform _platform;
final FeatureFlags _featureFlags; final FeatureFlags _featureFlags;
@ -106,9 +102,9 @@ class PrecacheCommand extends FlutterCommand {
Set<String> _explicitArtifactSelections() { Set<String> _explicitArtifactSelections() {
final Map<String, String> umbrellaForArtifact = _umbrellaForArtifactMap(); final Map<String, String> umbrellaForArtifact = _umbrellaForArtifactMap();
final Set<String> selections = <String>{}; final Set<String> selections = <String>{};
bool explicitlySelected(String name) => boolArgDeprecated(name) && argResults.wasParsed(name); bool explicitlySelected(String name) => boolArgDeprecated(name) && argResults!.wasParsed(name);
for (final DevelopmentArtifact artifact in DevelopmentArtifact.values) { for (final DevelopmentArtifact artifact in DevelopmentArtifact.values) {
final String umbrellaName = umbrellaForArtifact[artifact.name]; final String? umbrellaName = umbrellaForArtifact[artifact.name];
if (explicitlySelected(artifact.name) || if (explicitlySelected(artifact.name) ||
(umbrellaName != null && explicitlySelected(umbrellaName))) { (umbrellaName != null && explicitlySelected(umbrellaName))) {
selections.add(artifact.name); selections.add(artifact.name);
@ -120,11 +116,11 @@ class PrecacheCommand extends FlutterCommand {
@override @override
Future<void> validateCommand() { Future<void> validateCommand() {
_expandedArtifacts.forEach((String umbrellaName, List<String> childArtifactNames) { _expandedArtifacts.forEach((String umbrellaName, List<String> childArtifactNames) {
if (!argResults.arguments.contains('--no-$umbrellaName')) { if (!argResults!.arguments.contains('--no-$umbrellaName')) {
return; return;
} }
for (final String childArtifactName in childArtifactNames) { for (final String childArtifactName in childArtifactNames) {
if (argResults.arguments.contains('--$childArtifactName')) { if (argResults!.arguments.contains('--$childArtifactName')) {
throwToolExit('--$childArtifactName requires --$umbrellaName'); throwToolExit('--$childArtifactName requires --$umbrellaName');
} }
} }
@ -137,21 +133,21 @@ class PrecacheCommand extends FlutterCommand {
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
// Re-lock the cache. // Re-lock the cache.
if (_platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') { if (_platform.environment['FLUTTER_ALREADY_LOCKED'] != 'true') {
await _cache.lock(); await _cache!.lock();
} }
if (boolArgDeprecated('force')) { if (boolArgDeprecated('force')) {
_cache.clearStampFiles(); _cache!.clearStampFiles();
} }
final bool includeAllPlatforms = boolArgDeprecated('all-platforms'); final bool includeAllPlatforms = boolArgDeprecated('all-platforms');
if (includeAllPlatforms) { if (includeAllPlatforms) {
_cache.includeAllPlatforms = true; _cache!.includeAllPlatforms = true;
} }
if (boolArgDeprecated('use-unsigned-mac-binaries')) { if (boolArgDeprecated('use-unsigned-mac-binaries')) {
_cache.useUnsignedMacBinaries = true; _cache!.useUnsignedMacBinaries = true;
} }
final Set<String> explicitlyEnabled = _explicitArtifactSelections(); final Set<String> explicitlyEnabled = _explicitArtifactSelections();
_cache.platformOverrideArtifacts = explicitlyEnabled; _cache!.platformOverrideArtifacts = explicitlyEnabled;
// If the user did not provide any artifact flags, then download // If the user did not provide any artifact flags, then download
// all artifacts that correspond to an enabled platform. // all artifacts that correspond to an enabled platform.
@ -159,7 +155,7 @@ class PrecacheCommand extends FlutterCommand {
final Map<String, String> umbrellaForArtifact = _umbrellaForArtifactMap(); final Map<String, String> umbrellaForArtifact = _umbrellaForArtifactMap();
final Set<DevelopmentArtifact> requiredArtifacts = <DevelopmentArtifact>{}; final Set<DevelopmentArtifact> requiredArtifacts = <DevelopmentArtifact>{};
for (final DevelopmentArtifact artifact in DevelopmentArtifact.values) { for (final DevelopmentArtifact artifact in DevelopmentArtifact.values) {
if (artifact.feature != null && !_featureFlags.isEnabled(artifact.feature)) { if (artifact.feature != null && !_featureFlags.isEnabled(artifact.feature!)) {
continue; continue;
} }
@ -168,8 +164,8 @@ class PrecacheCommand extends FlutterCommand {
requiredArtifacts.add(artifact); requiredArtifacts.add(artifact);
} }
} }
if (!await _cache.isUpToDate()) { if (!await _cache!.isUpToDate()) {
await _cache.updateAll(requiredArtifacts); await _cache!.updateAll(requiredArtifacts);
} else { } else {
_logger.printStatus('Already up-to-date.'); _logger.printStatus('Already up-to-date.');
} }

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
@ -31,7 +31,7 @@ import 'daemon.dart';
/// Shared logic between `flutter run` and `flutter drive` commands. /// Shared logic between `flutter run` and `flutter drive` commands.
abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopmentArtifacts { abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
RunCommandBase({ @required bool verboseHelp }) { RunCommandBase({ required bool verboseHelp }) {
addBuildModeFlags(verboseHelp: verboseHelp, defaultToRelease: false); addBuildModeFlags(verboseHelp: verboseHelp, defaultToRelease: false);
usesDartDefineOption(); usesDartDefineOption();
usesFlavorOption(); usesFlavorOption();
@ -182,7 +182,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
bool get purgePersistentCache => boolArgDeprecated('purge-persistent-cache'); bool get purgePersistentCache => boolArgDeprecated('purge-persistent-cache');
bool get disableServiceAuthCodes => boolArgDeprecated('disable-service-auth-codes'); bool get disableServiceAuthCodes => boolArgDeprecated('disable-service-auth-codes');
bool get cacheStartupProfile => boolArgDeprecated('cache-startup-profile'); bool get cacheStartupProfile => boolArgDeprecated('cache-startup-profile');
bool get runningWithPrebuiltApplication => argResults[FlutterOptions.kUseApplicationBinary] != null; bool get runningWithPrebuiltApplication => argResults![FlutterOptions.kUseApplicationBinary] != null;
bool get trackWidgetCreation => boolArgDeprecated('track-widget-creation'); bool get trackWidgetCreation => boolArgDeprecated('track-widget-creation');
bool get enableImpeller => boolArgDeprecated('enable-impeller'); bool get enableImpeller => boolArgDeprecated('enable-impeller');
bool get uninstallFirst => boolArgDeprecated('uninstall-first'); bool get uninstallFirst => boolArgDeprecated('uninstall-first');
@ -193,17 +193,17 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
/// Whether to start the application paused by default. /// Whether to start the application paused by default.
bool get startPausedDefault; bool get startPausedDefault;
String get route => stringArgDeprecated('route'); String? get route => stringArgDeprecated('route');
String get traceAllowlist => stringArgDeprecated('trace-allowlist'); String? get traceAllowlist => stringArgDeprecated('trace-allowlist');
/// Create a debugging options instance for the current `run` or `drive` invocation. /// Create a debugging options instance for the current `run` or `drive` invocation.
@visibleForTesting @visibleForTesting
@protected @protected
Future<DebuggingOptions> createDebuggingOptions(bool webMode) async { Future<DebuggingOptions> createDebuggingOptions(bool webMode) async {
final BuildInfo buildInfo = await getBuildInfo(); final BuildInfo buildInfo = await getBuildInfo();
final int browserDebugPort = featureFlags.isWebEnabled && argResults.wasParsed('web-browser-debug-port') final int? browserDebugPort = featureFlags.isWebEnabled && argResults!.wasParsed('web-browser-debug-port')
? int.parse(stringArgDeprecated('web-browser-debug-port')) ? int.parse(stringArgDeprecated('web-browser-debug-port')!)
: null; : null;
if (buildInfo.mode.isRelease) { if (buildInfo.mode.isRelease) {
return DebuggingOptions.disabled( return DebuggingOptions.disabled(
@ -293,7 +293,6 @@ class RunCommand extends RunCommandBase {
"By default, the widgets library's binding takes care of sending this event.", "By default, the widgets library's binding takes care of sending this event.",
) )
..addFlag('use-test-fonts', ..addFlag('use-test-fonts',
negatable: true,
help: 'Enable (and default to) the "Ahem" font. This is a special font ' help: 'Enable (and default to) the "Ahem" font. This is a special font '
'used in tests to remove any dependencies on the font metrics. It ' 'used in tests to remove any dependencies on the font metrics. It '
'is enabled when you use "flutter test". Set this flag when running ' 'is enabled when you use "flutter test". Set this flag when running '
@ -315,12 +314,10 @@ class RunCommand extends RunCommandBase {
'and progress in machine friendly format.', 'and progress in machine friendly format.',
) )
..addFlag('hot', ..addFlag('hot',
negatable: true,
defaultsTo: kHotReloadDefault, defaultsTo: kHotReloadDefault,
help: 'Run with support for hot reloading. Only available for debug mode. Not available with "--trace-startup".', help: 'Run with support for hot reloading. Only available for debug mode. Not available with "--trace-startup".',
) )
..addFlag('resident', ..addFlag('resident',
negatable: true,
defaultsTo: true, defaultsTo: true,
hide: !verboseHelp, hide: !verboseHelp,
help: 'Stay resident after launching the application. Not available with "--trace-startup".', help: 'Stay resident after launching the application. Not available with "--trace-startup".',
@ -349,8 +346,6 @@ class RunCommand extends RunCommandBase {
// is slower for certain use cases. // is slower for certain use cases.
// See: https://github.com/flutter/flutter/issues/49499 // See: https://github.com/flutter/flutter/issues/49499
..addFlag('fast-start', ..addFlag('fast-start',
negatable: true,
defaultsTo: false,
help: 'Whether to quickly bootstrap applications with a minimal app. ' help: 'Whether to quickly bootstrap applications with a minimal app. '
'Currently this is only supported on Android devices. This option ' 'Currently this is only supported on Android devices. This option '
'cannot be paired with "--${FlutterOptions.kUseApplicationBinary}".', 'cannot be paired with "--${FlutterOptions.kUseApplicationBinary}".',
@ -371,25 +366,25 @@ class RunCommand extends RunCommandBase {
@override @override
String get category => FlutterCommandCategory.project; String get category => FlutterCommandCategory.project;
List<Device> devices; List<Device>? devices;
bool webMode = false; bool webMode = false;
String get userIdentifier => stringArgDeprecated(FlutterOptions.kDeviceUser); String? get userIdentifier => stringArgDeprecated(FlutterOptions.kDeviceUser);
@override @override
bool get startPausedDefault => false; bool get startPausedDefault => false;
@override @override
Future<String> get usagePath async { Future<String?> get usagePath async {
final String command = await super.usagePath; final String? command = await super.usagePath;
if (devices == null) { if (devices == null) {
return command; return command;
} }
if (devices.length > 1) { if (devices!.length > 1) {
return '$command/all'; return '$command/all';
} }
return '$command/${getNameForTargetPlatform(await devices[0].targetPlatform)}'; return '$command/${getNameForTargetPlatform(await devices![0].targetPlatform)}';
} }
@override @override
@ -399,22 +394,22 @@ class RunCommand extends RunCommandBase {
bool anyAndroidDevices = false; bool anyAndroidDevices = false;
bool anyIOSDevices = false; bool anyIOSDevices = false;
if (devices == null || devices.isEmpty) { if (devices == null || devices!.isEmpty) {
deviceType = 'none'; deviceType = 'none';
deviceOsVersion = 'none'; deviceOsVersion = 'none';
isEmulator = false; isEmulator = false;
} else if (devices.length == 1) { } else if (devices!.length == 1) {
final TargetPlatform platform = await devices[0].targetPlatform; final TargetPlatform platform = await devices![0].targetPlatform;
anyAndroidDevices = platform == TargetPlatform.android; anyAndroidDevices = platform == TargetPlatform.android;
anyIOSDevices = platform == TargetPlatform.ios; anyIOSDevices = platform == TargetPlatform.ios;
deviceType = getNameForTargetPlatform(platform); deviceType = getNameForTargetPlatform(platform);
deviceOsVersion = await devices[0].sdkNameAndVersion; deviceOsVersion = await devices![0].sdkNameAndVersion;
isEmulator = await devices[0].isLocalEmulator; isEmulator = await devices![0].isLocalEmulator;
} else { } else {
deviceType = 'multiple'; deviceType = 'multiple';
deviceOsVersion = 'multiple'; deviceOsVersion = 'multiple';
isEmulator = false; isEmulator = false;
for (final Device device in devices) { for (final Device device in devices!) {
final TargetPlatform platform = await device.targetPlatform; final TargetPlatform platform = await device.targetPlatform;
anyAndroidDevices = anyAndroidDevices || (platform == TargetPlatform.android); anyAndroidDevices = anyAndroidDevices || (platform == TargetPlatform.android);
anyIOSDevices = anyIOSDevices || (platform == TargetPlatform.ios); anyIOSDevices = anyIOSDevices || (platform == TargetPlatform.ios);
@ -424,7 +419,7 @@ class RunCommand extends RunCommandBase {
} }
} }
String androidEmbeddingVersion; String? androidEmbeddingVersion;
final List<String> hostLanguage = <String>[]; final List<String> hostLanguage = <String>[];
if (anyAndroidDevices) { if (anyAndroidDevices) {
final AndroidProject androidProject = FlutterProject.current().android; final AndroidProject androidProject = FlutterProject.current().android;
@ -469,7 +464,7 @@ class RunCommand extends RunCommandBase {
} }
bool shouldUseHotMode(BuildInfo buildInfo) { bool shouldUseHotMode(BuildInfo buildInfo) {
final bool hotArg = boolArgDeprecated('hot') ?? false; final bool hotArg = boolArgDeprecated('hot');
final bool shouldUseHotMode = hotArg && !traceStartup; final bool shouldUseHotMode = hotArg && !traceStartup;
return buildInfo.isDebug && shouldUseHotMode; return buildInfo.isDebug && shouldUseHotMode;
} }
@ -489,33 +484,33 @@ class RunCommand extends RunCommandBase {
if (devices == null) { if (devices == null) {
throwToolExit(null); throwToolExit(null);
} }
if (globals.deviceManager.hasSpecifiedAllDevices && runningWithPrebuiltApplication) { if (globals.deviceManager!.hasSpecifiedAllDevices && runningWithPrebuiltApplication) {
throwToolExit('Using "-d all" with "--${FlutterOptions.kUseApplicationBinary}" is not supported'); throwToolExit('Using "-d all" with "--${FlutterOptions.kUseApplicationBinary}" is not supported');
} }
if (userIdentifier != null if (userIdentifier != null
&& devices.every((Device device) => device is! AndroidDevice)) { && devices!.every((Device device) => device is! AndroidDevice)) {
throwToolExit( throwToolExit(
'--${FlutterOptions.kDeviceUser} is only supported for Android. At least one Android device is required.' '--${FlutterOptions.kDeviceUser} is only supported for Android. At least one Android device is required.'
); );
} }
if (devices.any((Device device) => device is AndroidDevice)) { if (devices!.any((Device device) => device is AndroidDevice)) {
_deviceDeprecationBehavior = DeprecationBehavior.exit; _deviceDeprecationBehavior = DeprecationBehavior.exit;
} }
// Only support "web mode" with a single web device due to resident runner // Only support "web mode" with a single web device due to resident runner
// refactoring required otherwise. // refactoring required otherwise.
webMode = featureFlags.isWebEnabled && webMode = featureFlags.isWebEnabled &&
devices.length == 1 && devices!.length == 1 &&
await devices.single.targetPlatform == TargetPlatform.web_javascript; await devices!.single.targetPlatform == TargetPlatform.web_javascript;
} }
@visibleForTesting @visibleForTesting
Future<ResidentRunner> createRunner({ Future<ResidentRunner?> createRunner({
@required bool hotMode, required bool hotMode,
@required List<FlutterDevice> flutterDevices, required List<FlutterDevice> flutterDevices,
@required String applicationBinaryPath, required String? applicationBinaryPath,
@required FlutterProject flutterProject, required FlutterProject flutterProject,
}) async { }) async {
if (hotMode && !webMode) { if (hotMode && !webMode) {
return HotRunner( return HotRunner(
@ -529,11 +524,11 @@ class RunCommand extends RunCommandBase {
projectRootPath: stringArgDeprecated('project-root'), projectRootPath: stringArgDeprecated('project-root'),
dillOutputPath: stringArgDeprecated('output-dill'), dillOutputPath: stringArgDeprecated('output-dill'),
stayResident: stayResident, stayResident: stayResident,
ipv6: ipv6, ipv6: ipv6 ?? false,
multidexEnabled: boolArgDeprecated('multidex'), multidexEnabled: boolArgDeprecated('multidex'),
); );
} else if (webMode) { } else if (webMode) {
return webRunnerFactory.createWebRunner( return webRunnerFactory!.createWebRunner(
flutterDevices.single, flutterDevices.single,
target: targetFile, target: targetFile,
flutterProject: flutterProject, flutterProject: flutterProject,
@ -556,7 +551,7 @@ class RunCommand extends RunCommandBase {
applicationBinary: applicationBinaryPath == null applicationBinary: applicationBinaryPath == null
? null ? null
: globals.fs.file(applicationBinaryPath), : globals.fs.file(applicationBinaryPath),
ipv6: ipv6, ipv6: ipv6 ?? false,
stayResident: stayResident, stayResident: stayResident,
multidexEnabled: boolArgDeprecated('multidex'), multidexEnabled: boolArgDeprecated('multidex'),
); );
@ -583,33 +578,33 @@ class RunCommand extends RunCommandBase {
// debug mode. // debug mode.
final BuildInfo buildInfo = await getBuildInfo(); final BuildInfo buildInfo = await getBuildInfo();
final bool hotMode = shouldUseHotMode(buildInfo); final bool hotMode = shouldUseHotMode(buildInfo);
final String applicationBinaryPath = stringArgDeprecated(FlutterOptions.kUseApplicationBinary); final String? applicationBinaryPath = stringArgDeprecated(FlutterOptions.kUseApplicationBinary);
if (boolArgDeprecated('machine')) { if (boolArgDeprecated('machine')) {
if (devices.length > 1) { if (devices!.length > 1) {
throwToolExit('"--machine" does not support "-d all".'); throwToolExit('"--machine" does not support "-d all".');
} }
final Daemon daemon = createMachineDaemon(); final Daemon daemon = createMachineDaemon();
AppInstance app; late AppInstance app;
try { try {
app = await daemon.appDomain.startApp( app = await daemon.appDomain.startApp(
devices.first, globals.fs.currentDirectory.path, targetFile, route, devices!.first, globals.fs.currentDirectory.path, targetFile, route,
await createDebuggingOptions(webMode), hotMode, await createDebuggingOptions(webMode), hotMode,
applicationBinary: applicationBinaryPath == null applicationBinary: applicationBinaryPath == null
? null ? null
: globals.fs.file(applicationBinaryPath), : globals.fs.file(applicationBinaryPath),
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
projectRootPath: stringArgDeprecated('project-root'), projectRootPath: stringArgDeprecated('project-root'),
packagesFilePath: globalResults['packages'] as String, packagesFilePath: globalResults!['packages'] as String?,
dillOutputPath: stringArgDeprecated('output-dill'), dillOutputPath: stringArgDeprecated('output-dill'),
ipv6: ipv6, ipv6: ipv6 ?? false,
multidexEnabled: boolArgDeprecated('multidex'), multidexEnabled: boolArgDeprecated('multidex'),
); );
} on Exception catch (error) { } on Exception catch (error) {
throwToolExit(error.toString()); throwToolExit(error.toString());
} }
final DateTime appStartedTime = globals.systemClock.now(); final DateTime appStartedTime = globals.systemClock.now();
final int result = await app.runner.waitForAppToFinish(); final int result = await app.runner!.waitForAppToFinish();
if (result != 0) { if (result != 0) {
throwToolExit(null, exitCode: result); throwToolExit(null, exitCode: result);
} }
@ -622,7 +617,7 @@ class RunCommand extends RunCommandBase {
globals.terminal.usesTerminalUi = true; globals.terminal.usesTerminalUi = true;
final BuildMode buildMode = getBuildMode(); final BuildMode buildMode = getBuildMode();
for (final Device device in devices) { for (final Device device in devices!) {
if (!await device.supportsRuntimeMode(buildMode)) { if (!await device.supportsRuntimeMode(buildMode)) {
throwToolExit( throwToolExit(
'${sentenceCase(getFriendlyModeName(buildMode))} ' '${sentenceCase(getFriendlyModeName(buildMode))} '
@ -649,14 +644,14 @@ class RunCommand extends RunCommandBase {
} }
} }
List<String> expFlags; List<String>? expFlags;
if (argParser.options.containsKey(FlutterOptions.kEnableExperiment) && if (argParser.options.containsKey(FlutterOptions.kEnableExperiment) &&
stringsArg(FlutterOptions.kEnableExperiment).isNotEmpty) { stringsArg(FlutterOptions.kEnableExperiment).isNotEmpty) {
expFlags = stringsArg(FlutterOptions.kEnableExperiment); expFlags = stringsArg(FlutterOptions.kEnableExperiment);
} }
final FlutterProject flutterProject = FlutterProject.current(); final FlutterProject flutterProject = FlutterProject.current();
final List<FlutterDevice> flutterDevices = <FlutterDevice>[ final List<FlutterDevice> flutterDevices = <FlutterDevice>[
for (final Device device in devices) for (final Device device in devices!)
await FlutterDevice.create( await FlutterDevice.create(
device, device,
experimentalFlags: expFlags, experimentalFlags: expFlags,
@ -667,21 +662,21 @@ class RunCommand extends RunCommandBase {
), ),
]; ];
final ResidentRunner runner = await createRunner( final ResidentRunner runner = await (createRunner(
applicationBinaryPath: applicationBinaryPath, applicationBinaryPath: applicationBinaryPath,
flutterDevices: flutterDevices, flutterDevices: flutterDevices,
flutterProject: flutterProject, flutterProject: flutterProject,
hotMode: hotMode, hotMode: hotMode,
); ) as FutureOr<ResidentRunner>);
DateTime appStartedTime; DateTime? appStartedTime;
// Sync completer so the completing agent attaching to the resident doesn't // Sync completer so the completing agent attaching to the resident doesn't
// need to know about analytics. // need to know about analytics.
// //
// Do not add more operations to the future. // Do not add more operations to the future.
final Completer<void> appStartedTimeRecorder = Completer<void>.sync(); final Completer<void> appStartedTimeRecorder = Completer<void>.sync();
TerminalHandler handler; TerminalHandler? handler;
// This callback can't throw. // This callback can't throw.
unawaited(appStartedTimeRecorder.future.then<void>( unawaited(appStartedTimeRecorder.future.then<void>(
(_) { (_) {
@ -702,7 +697,7 @@ class RunCommand extends RunCommandBase {
} }
)); ));
try { try {
final int result = await runner.run( final int? result = await runner.run(
appStartedCompleter: appStartedTimeRecorder, appStartedCompleter: appStartedTimeRecorder,
enableDevTools: stayResident && boolArgDeprecated(FlutterCommand.kEnableDevTools), enableDevTools: stayResident && boolArgDeprecated(FlutterCommand.kEnableDevTools),
route: route, route: route,
@ -723,14 +718,14 @@ class RunCommand extends RunCommandBase {
} }
return FlutterCommandResult( return FlutterCommandResult(
ExitStatus.success, ExitStatus.success,
timingLabelParts: <String>[ timingLabelParts: <String?>[
if (hotMode) 'hot' else 'cold', if (hotMode) 'hot' else 'cold',
getModeName(getBuildMode()), getModeName(getBuildMode()),
if (devices.length == 1) if (devices!.length == 1)
getNameForTargetPlatform(await devices[0].targetPlatform) getNameForTargetPlatform(await devices![0].targetPlatform)
else else
'multiple', 'multiple',
if (devices.length == 1 && await devices[0].isLocalEmulator) if (devices!.length == 1 && await devices![0].isLocalEmulator)
'emulator' 'emulator'
else else
null, null,

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math; import 'dart:math' as math;
@ -95,7 +95,6 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
help: 'Run only tests that do not have the specified tags. See: https://pub.dev/packages/test#tagging-tests', help: 'Run only tests that do not have the specified tags. See: https://pub.dev/packages/test#tagging-tests',
) )
..addFlag('start-paused', ..addFlag('start-paused',
defaultsTo: false,
negatable: false, negatable: false,
help: 'Start in a paused mode and wait for a debugger to connect.\n' help: 'Start in a paused mode and wait for a debugger to connect.\n'
'You must specify a single test file to run, explicitly.\n' 'You must specify a single test file to run, explicitly.\n'
@ -103,23 +102,19 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
'console once the test has started.', 'console once the test has started.',
) )
..addFlag('run-skipped', ..addFlag('run-skipped',
defaultsTo: false,
help: 'Run skipped tests instead of skipping them.', help: 'Run skipped tests instead of skipping them.',
) )
..addFlag('disable-service-auth-codes', ..addFlag('disable-service-auth-codes',
defaultsTo: false,
negatable: false, negatable: false,
hide: !verboseHelp, hide: !verboseHelp,
help: '(deprecated) Allow connections to the VM service without using authentication codes. ' help: '(deprecated) Allow connections to the VM service without using authentication codes. '
'(Not recommended! This can open your device to remote code execution attacks!)' '(Not recommended! This can open your device to remote code execution attacks!)'
) )
..addFlag('coverage', ..addFlag('coverage',
defaultsTo: false,
negatable: false, negatable: false,
help: 'Whether to collect coverage information.', help: 'Whether to collect coverage information.',
) )
..addFlag('merge-coverage', ..addFlag('merge-coverage',
defaultsTo: false,
negatable: false, negatable: false,
help: 'Whether to merge coverage data with "coverage/lcov.base.info".\n' help: 'Whether to merge coverage data with "coverage/lcov.base.info".\n'
'Implies collecting coverage data. (Requires lcov.)', 'Implies collecting coverage data. (Requires lcov.)',
@ -153,7 +148,6 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
) )
..addFlag('test-assets', ..addFlag('test-assets',
defaultsTo: true, defaultsTo: true,
negatable: true,
help: 'Whether to build the assets bundle for testing. ' help: 'Whether to build the assets bundle for testing. '
'This takes additional time before running the tests. ' 'This takes additional time before running the tests. '
'Consider using "--no-test-assets" if assets are not required.', 'Consider using "--no-test-assets" if assets are not required.',
@ -191,7 +185,6 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
'them separately.' 'them separately.'
) )
..addFlag('enable-vmservice', ..addFlag('enable-vmservice',
defaultsTo: false,
hide: !verboseHelp, hide: !verboseHelp,
help: 'Enables the VM service without "--start-paused". This flag is ' help: 'Enables the VM service without "--start-paused". This flag is '
'intended for use with tests that will use "dart:developer" to ' 'intended for use with tests that will use "dart:developer" to '
@ -255,8 +248,8 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
String get category => FlutterCommandCategory.project; String get category => FlutterCommandCategory.project;
@override @override
Future<FlutterCommandResult> verifyThenRunCommand(String commandPath) { Future<FlutterCommandResult> verifyThenRunCommand(String? commandPath) {
_testFiles = argResults.rest.map<String>(globals.fs.path.absolute).toList(); _testFiles = argResults!.rest.map<String>(globals.fs.path.absolute).toList();
if (_testFiles.isEmpty) { if (_testFiles.isEmpty) {
// We don't scan the entire package, only the test/ subdirectory, so that // We don't scan the entire package, only the test/ subdirectory, so that
// files with names like "hit_test.dart" don't get run. // files with names like "hit_test.dart" don't get run.
@ -305,8 +298,8 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
final bool buildTestAssets = boolArgDeprecated('test-assets'); final bool buildTestAssets = boolArgDeprecated('test-assets');
final List<String> names = stringsArg('name'); final List<String> names = stringsArg('name');
final List<String> plainNames = stringsArg('plain-name'); final List<String> plainNames = stringsArg('plain-name');
final String tags = stringArgDeprecated('tags'); final String? tags = stringArgDeprecated('tags');
final String excludeTags = stringArgDeprecated('exclude-tags'); final String? excludeTags = stringArgDeprecated('exclude-tags');
final BuildInfo buildInfo = await getBuildInfo(forcedBuildMode: BuildMode.debug); final BuildInfo buildInfo = await getBuildInfo(forcedBuildMode: BuildMode.debug);
if (buildInfo.packageConfig['test_api'] == null) { if (buildInfo.packageConfig['test_api'] == null) {
@ -320,11 +313,11 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
); );
} }
String testAssetDirectory; String? testAssetDirectory;
if (buildTestAssets) { if (buildTestAssets) {
await _buildTestAsset(); await _buildTestAsset();
testAssetDirectory = globals.fs.path. testAssetDirectory = globals.fs.path.
join(flutterProject?.directory?.path ?? '', 'build', 'unit_test_assets'); join(flutterProject.directory.path, 'build', 'unit_test_assets');
} }
final bool startPaused = boolArgDeprecated('start-paused'); final bool startPaused = boolArgDeprecated('start-paused');
@ -335,14 +328,14 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
); );
} }
int jobs = int.tryParse(stringArgDeprecated('concurrency')); int? jobs = int.tryParse(stringArgDeprecated('concurrency')!);
if (jobs == null || jobs <= 0 || !jobs.isFinite) { if (jobs == null || jobs <= 0 || !jobs.isFinite) {
throwToolExit( throwToolExit(
'Could not parse -j/--concurrency argument. It must be an integer greater than zero.' 'Could not parse -j/--concurrency argument. It must be an integer greater than zero.'
); );
} }
if (_isIntegrationTest) { if (_isIntegrationTest) {
if (argResults.wasParsed('concurrency')) { if (argResults!.wasParsed('concurrency')) {
globals.printStatus( globals.printStatus(
'-j/--concurrency was parsed but will be ignored, this option is not ' '-j/--concurrency was parsed but will be ignored, this option is not '
'supported when running Integration Tests.', 'supported when running Integration Tests.',
@ -353,13 +346,13 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
jobs = 1; jobs = 1;
} }
final int shardIndex = int.tryParse(stringArgDeprecated('shard-index') ?? ''); final int? shardIndex = int.tryParse(stringArgDeprecated('shard-index') ?? '');
if (shardIndex != null && (shardIndex < 0 || !shardIndex.isFinite)) { if (shardIndex != null && (shardIndex < 0 || !shardIndex.isFinite)) {
throwToolExit( throwToolExit(
'Could not parse --shard-index=$shardIndex argument. It must be an integer greater than -1.'); 'Could not parse --shard-index=$shardIndex argument. It must be an integer greater than -1.');
} }
final int totalShards = int.tryParse(stringArgDeprecated('total-shards') ?? ''); final int? totalShards = int.tryParse(stringArgDeprecated('total-shards') ?? '');
if (totalShards != null && (totalShards <= 0 || !totalShards.isFinite)) { if (totalShards != null && (totalShards <= 0 || !totalShards.isFinite)) {
throwToolExit( throwToolExit(
'Could not parse --total-shards=$totalShards argument. It must be an integer greater than zero.'); 'Could not parse --total-shards=$totalShards argument. It must be an integer greater than zero.');
@ -375,7 +368,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
} }
final bool machine = boolArgDeprecated('machine'); final bool machine = boolArgDeprecated('machine');
CoverageCollector collector; CoverageCollector? collector;
if (boolArgDeprecated('coverage') || boolArgDeprecated('merge-coverage')) { if (boolArgDeprecated('coverage') || boolArgDeprecated('merge-coverage')) {
final String projectName = flutterProject.manifest.appName; final String projectName = flutterProject.manifest.appName;
collector = CoverageCollector( collector = CoverageCollector(
@ -385,7 +378,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
); );
} }
TestWatcher watcher; TestWatcher? watcher;
if (machine) { if (machine) {
watcher = EventPrinter(parent: collector, out: globals.stdio.stdout); watcher = EventPrinter(parent: collector, out: globals.stdio.stdout);
} else if (collector != null) { } else if (collector != null) {
@ -402,7 +395,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
nullAssertions: boolArgDeprecated(FlutterOptions.kNullAssertions), nullAssertions: boolArgDeprecated(FlutterOptions.kNullAssertions),
); );
Device integrationTestDevice; Device? integrationTestDevice;
if (_isIntegrationTest) { if (_isIntegrationTest) {
integrationTestDevice = await findTargetDevice(); integrationTestDevice = await findTargetDevice();

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
@ -70,12 +70,12 @@ import 'windows/windows_workflow.dart';
Future<T> runInContext<T>( Future<T> runInContext<T>(
FutureOr<T> Function() runner, { FutureOr<T> Function() runner, {
Map<Type, Generator> overrides, Map<Type, Generator>? overrides,
}) async { }) async {
// Wrap runner with any asynchronous initialization that should run with the // Wrap runner with any asynchronous initialization that should run with the
// overrides and callbacks. // overrides and callbacks.
bool runningOnBot; late bool runningOnBot;
FutureOr<T> runnerWrapper() async { FutureOr<T> runnerWrapper() async {
runningOnBot = await globals.isRunningOnBot; runningOnBot = await globals.isRunningOnBot;
return runner(); return runner();
@ -90,9 +90,9 @@ Future<T> runInContext<T>(
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
fileSystem: globals.fs, fileSystem: globals.fs,
artifacts: globals.artifacts, artifacts: globals.artifacts!,
usage: globals.flutterUsage, usage: globals.flutterUsage,
gradleUtils: globals.gradleUtils, gradleUtils: globals.gradleUtils!,
platform: globals.platform, platform: globals.platform,
), ),
AndroidLicenseValidator: () => AndroidLicenseValidator( AndroidLicenseValidator: () => AndroidLicenseValidator(
@ -158,11 +158,11 @@ Future<T> runInContext<T>(
processManager: globals.processManager, processManager: globals.processManager,
logger: globals.logger, logger: globals.logger,
platform: globals.platform, platform: globals.platform,
xcodeProjectInterpreter: globals.xcodeProjectInterpreter, xcodeProjectInterpreter: globals.xcodeProjectInterpreter!,
usage: globals.flutterUsage, usage: globals.flutterUsage,
), ),
CocoaPodsValidator: () => CocoaPodsValidator( CocoaPodsValidator: () => CocoaPodsValidator(
globals.cocoaPods, globals.cocoaPods!,
globals.userMessages, globals.userMessages,
), ),
Config: () => Config( Config: () => Config(
@ -187,29 +187,29 @@ Future<T> runInContext<T>(
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
androidSdk: globals.androidSdk, androidSdk: globals.androidSdk,
iosSimulatorUtils: globals.iosSimulatorUtils, iosSimulatorUtils: globals.iosSimulatorUtils!,
featureFlags: featureFlags, featureFlags: featureFlags,
fileSystem: globals.fs, fileSystem: globals.fs,
iosWorkflow: globals.iosWorkflow, iosWorkflow: globals.iosWorkflow!,
artifacts: globals.artifacts, artifacts: globals.artifacts!,
flutterVersion: globals.flutterVersion, flutterVersion: globals.flutterVersion,
androidWorkflow: androidWorkflow, androidWorkflow: androidWorkflow!,
fuchsiaWorkflow: fuchsiaWorkflow, fuchsiaWorkflow: fuchsiaWorkflow!,
xcDevice: globals.xcdevice, xcDevice: globals.xcdevice!,
userMessages: globals.userMessages, userMessages: globals.userMessages,
windowsWorkflow: windowsWorkflow, windowsWorkflow: windowsWorkflow!,
macOSWorkflow: MacOSWorkflow( macOSWorkflow: MacOSWorkflow(
platform: globals.platform, platform: globals.platform,
featureFlags: featureFlags, featureFlags: featureFlags,
), ),
fuchsiaSdk: globals.fuchsiaSdk, fuchsiaSdk: globals.fuchsiaSdk!,
operatingSystemUtils: globals.os, operatingSystemUtils: globals.os,
terminal: globals.terminal, terminal: globals.terminal,
customDevicesConfig: globals.customDevicesConfig, customDevicesConfig: globals.customDevicesConfig,
), ),
DevtoolsLauncher: () => DevtoolsServerLauncher( DevtoolsLauncher: () => DevtoolsServerLauncher(
processManager: globals.processManager, processManager: globals.processManager,
dartExecutable: globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, dartExecutable: globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path,
logger: globals.logger, logger: globals.logger,
botDetector: globals.botDetector, botDetector: globals.botDetector,
), ),
@ -220,7 +220,7 @@ Future<T> runInContext<T>(
processManager: globals.processManager, processManager: globals.processManager,
logger: globals.logger, logger: globals.logger,
fileSystem: globals.fs, fileSystem: globals.fs,
androidWorkflow: androidWorkflow, androidWorkflow: androidWorkflow!,
), ),
FeatureFlags: () => FlutterFeatureFlags( FeatureFlags: () => FlutterFeatureFlags(
flutterVersion: globals.flutterVersion, flutterVersion: globals.flutterVersion,
@ -234,7 +234,7 @@ Future<T> runInContext<T>(
FuchsiaWorkflow: () => FuchsiaWorkflow( FuchsiaWorkflow: () => FuchsiaWorkflow(
featureFlags: featureFlags, featureFlags: featureFlags,
platform: globals.platform, platform: globals.platform,
fuchsiaArtifacts: globals.fuchsiaArtifacts, fuchsiaArtifacts: globals.fuchsiaArtifacts!,
), ),
GradleUtils: () => GradleUtils( GradleUtils: () => GradleUtils(
fileSystem: globals.fs, fileSystem: globals.fs,
@ -247,11 +247,11 @@ Future<T> runInContext<T>(
IOSSimulatorUtils: () => IOSSimulatorUtils( IOSSimulatorUtils: () => IOSSimulatorUtils(
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
xcode: globals.xcode, xcode: globals.xcode!,
), ),
IOSWorkflow: () => IOSWorkflow( IOSWorkflow: () => IOSWorkflow(
featureFlags: featureFlags, featureFlags: featureFlags,
xcode: globals.xcode, xcode: globals.xcode!,
platform: globals.platform, platform: globals.platform,
), ),
LocalEngineLocator: () => LocalEngineLocator( LocalEngineLocator: () => LocalEngineLocator(
@ -259,7 +259,7 @@ Future<T> runInContext<T>(
logger: globals.logger, logger: globals.logger,
platform: globals.platform, platform: globals.platform,
fileSystem: globals.fs, fileSystem: globals.fs,
flutterRoot: Cache.flutterRoot, flutterRoot: Cache.flutterRoot!,
), ),
Logger: () => globals.platform.isWindows Logger: () => globals.platform.isWindows
? WindowsStdoutLogger( ? WindowsStdoutLogger(
@ -287,7 +287,7 @@ Future<T> runInContext<T>(
processManager: globals.processManager, processManager: globals.processManager,
), ),
OutputPreferences: () => OutputPreferences( OutputPreferences: () => OutputPreferences(
wrapText: globals.stdio.hasTerminal ?? false, wrapText: globals.stdio.hasTerminal,
showColor: globals.platform.stdoutSupportsAnsi, showColor: globals.platform.stdoutSupportsAnsi,
stdio: globals.stdio, stdio: globals.stdio,
), ),
@ -318,7 +318,7 @@ Future<T> runInContext<T>(
SystemClock: () => const SystemClock(), SystemClock: () => const SystemClock(),
Usage: () => Usage( Usage: () => Usage(
runningOnBot: runningOnBot, runningOnBot: runningOnBot,
firstRunMessenger: FirstRunMessenger(persistentToolState: globals.persistentToolState), firstRunMessenger: FirstRunMessenger(persistentToolState: globals.persistentToolState!),
), ),
UserMessages: () => UserMessages(), UserMessages: () => UserMessages(),
VisualStudioValidator: () => VisualStudioValidator( VisualStudioValidator: () => VisualStudioValidator(
@ -343,17 +343,17 @@ Future<T> runInContext<T>(
processManager: globals.processManager, processManager: globals.processManager,
platform: globals.platform, platform: globals.platform,
fileSystem: globals.fs, fileSystem: globals.fs,
xcodeProjectInterpreter: globals.xcodeProjectInterpreter, xcodeProjectInterpreter: globals.xcodeProjectInterpreter!,
), ),
XCDevice: () => XCDevice( XCDevice: () => XCDevice(
processManager: globals.processManager, processManager: globals.processManager,
logger: globals.logger, logger: globals.logger,
artifacts: globals.artifacts, artifacts: globals.artifacts!,
cache: globals.cache, cache: globals.cache,
platform: globals.platform, platform: globals.platform,
xcode: globals.xcode, xcode: globals.xcode!,
iproxy: IProxy( iproxy: IProxy(
iproxyPath: globals.artifacts.getHostArtifact( iproxyPath: globals.artifacts!.getHostArtifact(
HostArtifact.iproxy, HostArtifact.iproxy,
).path, ).path,
logger: globals.logger, logger: globals.logger,

View File

@ -301,7 +301,7 @@ class DaemonConnection {
} }
/// Sends an error response to the other end of the connection. /// Sends an error response to the other end of the connection.
void sendErrorResponse(Object id, Object error, StackTrace trace) { void sendErrorResponse(Object id, Object? error, StackTrace trace) {
_daemonStreams.send(<String, Object?>{ _daemonStreams.send(<String, Object?>{
'id': id, 'id': id,
'error': error, 'error': error,

View File

@ -44,7 +44,7 @@ abstract class DesktopDevice extends Device {
final DesktopLogReader _deviceLogReader = DesktopLogReader(); final DesktopLogReader _deviceLogReader = DesktopLogReader();
@override @override
DevFSWriter createDevFSWriter(covariant ApplicationPackage app, String userIdentifier) { DevFSWriter createDevFSWriter(covariant ApplicationPackage? app, String? userIdentifier) {
return LocalDevFSWriter(fileSystem: _fileSystem); return LocalDevFSWriter(fileSystem: _fileSystem);
} }

View File

@ -477,7 +477,7 @@ class DevFS {
final StopwatchFactory _stopwatchFactory; final StopwatchFactory _stopwatchFactory;
final String fsName; final String fsName;
final Directory rootDirectory; final Directory? rootDirectory;
final Set<String> assetPathsToEvict = <String>{}; final Set<String> assetPathsToEvict = <String>{};
// A flag to indicate whether we have called `setAssetDirectory` on the target device. // A flag to indicate whether we have called `setAssetDirectory` on the target device.
@ -497,7 +497,7 @@ class DevFS {
final String baseUriString = baseUri.toString(); final String baseUriString = baseUri.toString();
if (deviceUriString.startsWith(baseUriString)) { if (deviceUriString.startsWith(baseUriString)) {
final String deviceUriSuffix = deviceUriString.substring(baseUriString.length); final String deviceUriSuffix = deviceUriString.substring(baseUriString.length);
return rootDirectory.uri.resolve(deviceUriSuffix); return rootDirectory!.uri.resolve(deviceUriSuffix);
} }
return deviceUri; return deviceUri;
} }

View File

@ -557,8 +557,8 @@ abstract class Device {
/// For example, the desktop device classes can use a writer which /// For example, the desktop device classes can use a writer which
/// copies the files across the local file system. /// copies the files across the local file system.
DevFSWriter? createDevFSWriter( DevFSWriter? createDevFSWriter(
covariant ApplicationPackage app, covariant ApplicationPackage? app,
String userIdentifier, String? userIdentifier,
) { ) {
return null; return null;
} }
@ -593,7 +593,7 @@ abstract class Device {
/// [platformArgs] allows callers to pass platform-specific arguments to the /// [platformArgs] allows callers to pass platform-specific arguments to the
/// start call. The build mode is not used by all platforms. /// start call. The build mode is not used by all platforms.
Future<LaunchResult> startApp( Future<LaunchResult> startApp(
covariant ApplicationPackage package, { covariant ApplicationPackage? package, {
String? mainPath, String? mainPath,
String? route, String? route,
required DebuggingOptions debuggingOptions, required DebuggingOptions debuggingOptions,
@ -624,7 +624,7 @@ abstract class Device {
/// ///
/// Specify [userIdentifier] to stop app installed to a profile (Android only). /// Specify [userIdentifier] to stop app installed to a profile (Android only).
Future<bool> stopApp( Future<bool> stopApp(
covariant ApplicationPackage app, { covariant ApplicationPackage? app, {
String? userIdentifier, String? userIdentifier,
}); });

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
@ -20,10 +20,10 @@ import 'resident_runner.dart';
/// start a server instance. /// start a server instance.
class DevtoolsServerLauncher extends DevtoolsLauncher { class DevtoolsServerLauncher extends DevtoolsLauncher {
DevtoolsServerLauncher({ DevtoolsServerLauncher({
@required ProcessManager processManager, required ProcessManager processManager,
@required String dartExecutable, required String dartExecutable,
@required Logger logger, required Logger? logger,
@required BotDetector botDetector, required BotDetector botDetector,
}) : _processManager = processManager, }) : _processManager = processManager,
_dartExecutable = dartExecutable, _dartExecutable = dartExecutable,
_logger = logger, _logger = logger,
@ -31,14 +31,14 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
final ProcessManager _processManager; final ProcessManager _processManager;
final String _dartExecutable; final String _dartExecutable;
final Logger _logger; final Logger? _logger;
final BotDetector _botDetector; final BotDetector _botDetector;
final Completer<void> _processStartCompleter = Completer<void>(); final Completer<void> _processStartCompleter = Completer<void>();
io.Process _devToolsProcess; io.Process? _devToolsProcess;
bool _devToolsProcessKilled = false; bool _devToolsProcessKilled = false;
@visibleForTesting @visibleForTesting
Future<void> devToolsProcessExit; Future<void>? devToolsProcessExit;
static final RegExp _serveDevToolsPattern = static final RegExp _serveDevToolsPattern =
RegExp(r'Serving DevTools at ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+?)\.?$'); RegExp(r'Serving DevTools at ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+?)\.?$');
@ -47,7 +47,7 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
Future<void> get processStart => _processStartCompleter.future; Future<void> get processStart => _processStartCompleter.future;
@override @override
Future<void> launch(Uri vmServiceUri, {List<String> additionalArguments}) async { Future<void> launch(Uri? vmServiceUri, {List<String>? additionalArguments}) async {
// Place this entire method in a try/catch that swallows exceptions because // Place this entire method in a try/catch that swallows exceptions because
// this method is guaranteed not to return a Future that throws. // this method is guaranteed not to return a Future that throws.
try { try {
@ -60,23 +60,23 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
]); ]);
_processStartCompleter.complete(); _processStartCompleter.complete();
final Completer<Uri> completer = Completer<Uri>(); final Completer<Uri> completer = Completer<Uri>();
_devToolsProcess.stdout _devToolsProcess!.stdout
.transform(utf8.decoder) .transform(utf8.decoder)
.transform(const LineSplitter()) .transform(const LineSplitter())
.listen((String line) { .listen((String line) {
final Match match = _serveDevToolsPattern.firstMatch(line); final Match? match = _serveDevToolsPattern.firstMatch(line);
if (match != null) { if (match != null) {
final String url = match[1]; final String url = match[1]!;
completer.complete(Uri.parse(url)); completer.complete(Uri.parse(url));
} }
}); });
_devToolsProcess.stderr _devToolsProcess!.stderr
.transform(utf8.decoder) .transform(utf8.decoder)
.transform(const LineSplitter()) .transform(const LineSplitter())
.listen(_logger.printError); .listen(_logger!.printError);
final bool runningOnBot = await _botDetector.isRunningOnBot; final bool runningOnBot = await _botDetector.isRunningOnBot;
devToolsProcessExit = _devToolsProcess.exitCode.then( devToolsProcessExit = _devToolsProcess!.exitCode.then(
(int exitCode) { (int exitCode) {
if (!_devToolsProcessKilled && runningOnBot) { if (!_devToolsProcessKilled && runningOnBot) {
throwToolExit('DevTools process failed: exitCode=$exitCode'); throwToolExit('DevTools process failed: exitCode=$exitCode');
@ -86,12 +86,12 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
devToolsUrl = await completer.future; devToolsUrl = await completer.future;
} on Exception catch (e, st) { } on Exception catch (e, st) {
_logger.printError('Failed to launch DevTools: $e', stackTrace: st); _logger!.printError('Failed to launch DevTools: $e', stackTrace: st);
} }
} }
@override @override
Future<DevToolsServerAddress> serve() async { Future<DevToolsServerAddress?> serve() async {
if (activeDevToolsServer == null) { if (activeDevToolsServer == null) {
await launch(null); await launch(null);
} }
@ -105,7 +105,7 @@ class DevtoolsServerLauncher extends DevtoolsLauncher {
} }
if (_devToolsProcess != null) { if (_devToolsProcess != null) {
_devToolsProcessKilled = true; _devToolsProcessKilled = true;
_devToolsProcess.kill(); _devToolsProcess!.kill();
} }
} }
} }

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'package:dds/dds.dart' as dds; import 'package:dds/dds.dart' as dds;
@ -25,11 +23,11 @@ import 'web_driver_service.dart';
class FlutterDriverFactory { class FlutterDriverFactory {
FlutterDriverFactory({ FlutterDriverFactory({
@required ApplicationPackageFactory applicationPackageFactory, required ApplicationPackageFactory applicationPackageFactory,
@required Logger logger, required Logger logger,
@required ProcessUtils processUtils, required ProcessUtils processUtils,
@required String dartSdkPath, required String dartSdkPath,
@required DevtoolsLauncher devtoolsLauncher, required DevtoolsLauncher devtoolsLauncher,
}) : _applicationPackageFactory = applicationPackageFactory, }) : _applicationPackageFactory = applicationPackageFactory,
_logger = logger, _logger = logger,
_processUtils = processUtils, _processUtils = processUtils,
@ -69,10 +67,10 @@ abstract class DriverService {
Device device, Device device,
DebuggingOptions debuggingOptions, DebuggingOptions debuggingOptions,
bool ipv6, { bool ipv6, {
File applicationBinary, File? applicationBinary,
String route, String? route,
String userIdentifier, String? userIdentifier,
String mainPath, String? mainPath,
Map<String, Object> platformArgs = const <String, Object>{}, Map<String, Object> platformArgs = const <String, Object>{},
}); });
@ -94,13 +92,13 @@ abstract class DriverService {
List<String> arguments, List<String> arguments,
Map<String, String> environment, Map<String, String> environment,
PackageConfig packageConfig, { PackageConfig packageConfig, {
bool headless, bool? headless,
String chromeBinary, String? chromeBinary,
String browserName, String? browserName,
bool androidEmulator, bool? androidEmulator,
int driverPort, int? driverPort,
List<String> browserDimension, List<String>? browserDimension,
String profileMemory, String? profileMemory,
}); });
/// Stop the running application and uninstall it from the device. /// Stop the running application and uninstall it from the device.
@ -109,8 +107,8 @@ abstract class DriverService {
/// and write SkSL to the file. This is only supported on mobile and /// and write SkSL to the file. This is only supported on mobile and
/// desktop devices. /// desktop devices.
Future<void> stop({ Future<void> stop({
File writeSkslOnExit, File? writeSkslOnExit,
String userIdentifier, String? userIdentifier,
}); });
} }
@ -118,11 +116,11 @@ abstract class DriverService {
/// applications. /// applications.
class FlutterDriverService extends DriverService { class FlutterDriverService extends DriverService {
FlutterDriverService({ FlutterDriverService({
@required ApplicationPackageFactory applicationPackageFactory, required ApplicationPackageFactory applicationPackageFactory,
@required Logger logger, required Logger logger,
@required ProcessUtils processUtils, required ProcessUtils processUtils,
@required String dartSdkPath, required String dartSdkPath,
@required DevtoolsLauncher devtoolsLauncher, required DevtoolsLauncher devtoolsLauncher,
@visibleForTesting VMServiceConnector vmServiceConnector = connectToVmService, @visibleForTesting VMServiceConnector vmServiceConnector = connectToVmService,
}) : _applicationPackageFactory = applicationPackageFactory, }) : _applicationPackageFactory = applicationPackageFactory,
_logger = logger, _logger = logger,
@ -140,10 +138,10 @@ class FlutterDriverService extends DriverService {
final VMServiceConnector _vmServiceConnector; final VMServiceConnector _vmServiceConnector;
final DevtoolsLauncher _devtoolsLauncher; final DevtoolsLauncher _devtoolsLauncher;
Device _device; Device? _device;
ApplicationPackage _applicationPackage; ApplicationPackage? _applicationPackage;
String _vmServiceUri; late String _vmServiceUri;
FlutterVmService _vmService; late FlutterVmService _vmService;
@override @override
Future<void> start( Future<void> start(
@ -151,11 +149,11 @@ class FlutterDriverService extends DriverService {
Device device, Device device,
DebuggingOptions debuggingOptions, DebuggingOptions debuggingOptions,
bool ipv6, { bool ipv6, {
File applicationBinary, File? applicationBinary,
String route, String? route,
String userIdentifier, String? userIdentifier,
Map<String, Object> platformArgs = const <String, Object>{}, Map<String, Object> platformArgs = const <String, Object>{},
String mainPath, String? mainPath,
}) async { }) async {
if (buildInfo.isRelease) { if (buildInfo.isRelease) {
throwToolExit( throwToolExit(
@ -173,7 +171,7 @@ class FlutterDriverService extends DriverService {
applicationBinary: applicationBinary, applicationBinary: applicationBinary,
); );
int attempt = 0; int attempt = 0;
LaunchResult result; LaunchResult? result;
bool prebuiltApplication = applicationBinary != null; bool prebuiltApplication = applicationBinary != null;
while (attempt < _kLaunchAttempts) { while (attempt < _kLaunchAttempts) {
result = await device.startApp( result = await device.startApp(
@ -197,7 +195,7 @@ class FlutterDriverService extends DriverService {
throwToolExit('Application failed to start. Will not run test. Quitting.', exitCode: 1); throwToolExit('Application failed to start. Will not run test. Quitting.', exitCode: 1);
} }
return reuseApplication( return reuseApplication(
result.observatoryUri, result.observatoryUri!,
device, device,
debuggingOptions, debuggingOptions,
ipv6, ipv6,
@ -251,13 +249,13 @@ class FlutterDriverService extends DriverService {
List<String> arguments, List<String> arguments,
Map<String, String> environment, Map<String, String> environment,
PackageConfig packageConfig, { PackageConfig packageConfig, {
bool headless, bool? headless,
String chromeBinary, String? chromeBinary,
String browserName, String? browserName,
bool androidEmulator, bool? androidEmulator,
int driverPort, int? driverPort,
List<String> browserDimension, List<String>? browserDimension,
String profileMemory, String? profileMemory,
}) async { }) async {
if (profileMemory != null) { if (profileMemory != null) {
unawaited(_devtoolsLauncher.launch( unawaited(_devtoolsLauncher.launch(
@ -285,35 +283,35 @@ class FlutterDriverService extends DriverService {
@override @override
Future<void> stop({ Future<void> stop({
File writeSkslOnExit, File? writeSkslOnExit,
String userIdentifier, String? userIdentifier,
}) async { }) async {
if (writeSkslOnExit != null) { if (writeSkslOnExit != null) {
final FlutterView flutterView = (await _vmService.getFlutterViews()).first; final FlutterView flutterView = (await _vmService.getFlutterViews()).first;
final Map<String, Object> result = await _vmService.getSkSLs( final Map<String, Object> result = await (_vmService.getSkSLs(
viewId: flutterView.id viewId: flutterView.id
); ) as FutureOr<Map<String, Object>>);
await sharedSkSlWriter(_device, result, outputFile: writeSkslOnExit, logger: _logger); await sharedSkSlWriter(_device!, result, outputFile: writeSkslOnExit, logger: _logger);
} }
// If the application package is available, stop and uninstall. // If the application package is available, stop and uninstall.
if (_applicationPackage != null) { if (_applicationPackage != null) {
if (!await _device.stopApp(_applicationPackage, userIdentifier: userIdentifier)) { if (!await _device!.stopApp(_applicationPackage, userIdentifier: userIdentifier)) {
_logger.printError('Failed to stop app'); _logger.printError('Failed to stop app');
} }
if (!await _device.uninstallApp(_applicationPackage, userIdentifier: userIdentifier)) { if (!await _device!.uninstallApp(_applicationPackage!, userIdentifier: userIdentifier)) {
_logger.printError('Failed to uninstall app'); _logger.printError('Failed to uninstall app');
} }
} else if (_device.supportsFlutterExit) { } else if (_device!.supportsFlutterExit) {
// Otherwise use the VM Service URI to stop the app as a best effort approach. // Otherwise use the VM Service URI to stop the app as a best effort approach.
final vm_service.VM vm = await _vmService.service.getVM(); final vm_service.VM vm = await _vmService.service.getVM();
final vm_service.IsolateRef isolateRef = vm.isolates final vm_service.IsolateRef isolateRef = vm.isolates!
.firstWhere((vm_service.IsolateRef element) { .firstWhere((vm_service.IsolateRef element) {
return !element.isSystemIsolate; return !element.isSystemIsolate!;
}, orElse: () => null); });
unawaited(_vmService.flutterExit(isolateId: isolateRef.id)); unawaited(_vmService.flutterExit(isolateId: isolateRef.id!));
} else { } else {
_logger.printTrace('No application package for $_device, leaving app running'); _logger.printTrace('No application package for $_device, leaving app running');
} }
await _device.dispose(); await _device!.dispose();
} }
} }

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:math' as math; import 'dart:math' as math;
@ -28,9 +28,9 @@ import 'drive_service.dart';
/// An implementation of the driver service for web debug and release applications. /// An implementation of the driver service for web debug and release applications.
class WebDriverService extends DriverService { class WebDriverService extends DriverService {
WebDriverService({ WebDriverService({
@required ProcessUtils processUtils, required ProcessUtils processUtils,
@required String dartSdkPath, required String dartSdkPath,
@required Logger logger, required Logger logger,
}) : _processUtils = processUtils, }) : _processUtils = processUtils,
_dartSdkPath = dartSdkPath, _dartSdkPath = dartSdkPath,
_logger = logger; _logger = logger;
@ -39,15 +39,15 @@ class WebDriverService extends DriverService {
final String _dartSdkPath; final String _dartSdkPath;
final Logger _logger; final Logger _logger;
ResidentRunner _residentRunner; late ResidentRunner _residentRunner;
Uri _webUri; Uri? _webUri;
/// The result of [ResidentRunner.run]. /// The result of [ResidentRunner.run].
/// ///
/// This is expected to stay `null` throughout the test, as the application /// This is expected to stay `null` throughout the test, as the application
/// must be running until [stop] is called. If it becomes non-null, it likely /// must be running until [stop] is called. If it becomes non-null, it likely
/// indicates a bug. /// indicates a bug.
int _runResult; int? _runResult;
@override @override
Future<void> start( Future<void> start(
@ -55,10 +55,10 @@ class WebDriverService extends DriverService {
Device device, Device device,
DebuggingOptions debuggingOptions, DebuggingOptions debuggingOptions,
bool ipv6, { bool ipv6, {
File applicationBinary, File? applicationBinary,
String route, String? route,
String userIdentifier, String? userIdentifier,
String mainPath, String? mainPath,
Map<String, Object> platformArgs = const <String, Object>{}, Map<String, Object> platformArgs = const <String, Object>{},
}) async { }) async {
final FlutterDevice flutterDevice = await FlutterDevice.create( final FlutterDevice flutterDevice = await FlutterDevice.create(
@ -67,7 +67,7 @@ class WebDriverService extends DriverService {
buildInfo: buildInfo, buildInfo: buildInfo,
platform: globals.platform, platform: globals.platform,
); );
_residentRunner = webRunnerFactory.createWebRunner( _residentRunner = webRunnerFactory!.createWebRunner(
flutterDevice, flutterDevice,
target: mainPath, target: mainPath,
ipv6: ipv6, ipv6: ipv6,
@ -90,21 +90,21 @@ class WebDriverService extends DriverService {
systemClock: globals.systemClock, systemClock: globals.systemClock,
); );
final Completer<void> appStartedCompleter = Completer<void>.sync(); final Completer<void> appStartedCompleter = Completer<void>.sync();
final Future<int> runFuture = _residentRunner.run( final Future<int?> runFuture = _residentRunner.run(
appStartedCompleter: appStartedCompleter, appStartedCompleter: appStartedCompleter,
route: route, route: route,
); );
bool isAppStarted = false; bool isAppStarted = false;
await Future.any<Object>(<Future<Object>>[ await Future.any<Object>(<Future<Object>>[
runFuture.then((int result) { runFuture.then((int? result) {
_runResult = result; _runResult = result;
return null; return null;
}), } as FutureOr<Object> Function(int?)),
appStartedCompleter.future.then((_) { appStartedCompleter.future.then((_) {
isAppStarted = true; isAppStarted = true;
return null; return null;
}), } as FutureOr<Object> Function(void)),
]); ]);
if (_runResult != null) { if (_runResult != null) {
@ -126,22 +126,25 @@ class WebDriverService extends DriverService {
} }
@override @override
Future<int> startTest(String testFile, List<String> arguments, Map<String, String> environment, PackageConfig packageConfig, { Future<int> startTest(
@required bool headless, String testFile,
String chromeBinary, List<String> arguments,
@required String browserName, Map<String, String> environment,
bool androidEmulator, PackageConfig packageConfig, {
int driverPort, bool? headless,
List<String> browserDimension, String? chromeBinary,
String profileMemory, String? browserName,
bool? androidEmulator,
int? driverPort,
List<String>? browserDimension,
String? profileMemory,
}) async { }) async {
async_io.WebDriver webDriver; late async_io.WebDriver webDriver;
final Browser browser = _browserNameToEnum(browserName); final Browser browser = _browserNameToEnum(browserName);
try { try {
webDriver = await async_io.createDriver( webDriver = await async_io.createDriver(
uri: Uri.parse('http://localhost:$driverPort/'), uri: Uri.parse('http://localhost:$driverPort/'),
desired: getDesiredCapabilities(browser, headless, chromeBinary), desired: getDesiredCapabilities(browser, headless, chromeBinary),
spec: async_io.WebDriverSpec.Auto
); );
} on SocketException catch (error) { } on SocketException catch (error) {
_logger.printTrace('$error'); _logger.printTrace('$error');
@ -156,11 +159,11 @@ class WebDriverService extends DriverService {
final bool isAndroidChrome = browser == Browser.androidChrome; final bool isAndroidChrome = browser == Browser.androidChrome;
// Do not set the window size for android chrome browser. // Do not set the window size for android chrome browser.
if (!isAndroidChrome) { if (!isAndroidChrome) {
assert(browserDimension.length == 2); assert(browserDimension!.length == 2);
int x; late int x;
int y; late int y;
try { try {
x = int.parse(browserDimension[0]); x = int.parse(browserDimension![0]);
y = int.parse(browserDimension[1]); y = int.parse(browserDimension[1]);
} on FormatException catch (ex) { } on FormatException catch (ex) {
throwToolExit('Dimension provided to --browser-dimension is invalid: $ex'); throwToolExit('Dimension provided to --browser-dimension is invalid: $ex');
@ -184,7 +187,7 @@ class WebDriverService extends DriverService {
} }
@override @override
Future<void> stop({File writeSkslOnExit, String userIdentifier}) async { Future<void> stop({File? writeSkslOnExit, String? userIdentifier}) async {
final bool appDidFinishPrematurely = _runResult != null; final bool appDidFinishPrematurely = _runResult != null;
await _residentRunner.exitApp(); await _residentRunner.exitApp();
await _residentRunner.cleanupAtFinish(); await _residentRunner.cleanupAtFinish();
@ -197,7 +200,7 @@ class WebDriverService extends DriverService {
} }
} }
Map<String, String> _additionalDriverEnvironment(async_io.WebDriver webDriver, String browserName, bool androidEmulator) { Map<String, String> _additionalDriverEnvironment(async_io.WebDriver webDriver, String? browserName, bool? androidEmulator) {
return <String, String>{ return <String, String>{
'DRIVER_SESSION_ID': webDriver.id, 'DRIVER_SESSION_ID': webDriver.id,
'DRIVER_SESSION_URI': webDriver.uri.toString(), 'DRIVER_SESSION_URI': webDriver.uri.toString(),
@ -205,7 +208,7 @@ class WebDriverService extends DriverService {
'DRIVER_SESSION_CAPABILITIES': json.encode(webDriver.capabilities), 'DRIVER_SESSION_CAPABILITIES': json.encode(webDriver.capabilities),
'SUPPORT_TIMELINE_ACTION': (_browserNameToEnum(browserName) == Browser.chrome).toString(), 'SUPPORT_TIMELINE_ACTION': (_browserNameToEnum(browserName) == Browser.chrome).toString(),
'FLUTTER_WEB_TEST': 'true', 'FLUTTER_WEB_TEST': 'true',
'ANDROID_CHROME_ON_EMULATOR': (_browserNameToEnum(browserName) == Browser.androidChrome && androidEmulator).toString(), 'ANDROID_CHROME_ON_EMULATOR': (_browserNameToEnum(browserName) == Browser.androidChrome && androidEmulator!).toString(),
}; };
} }
@ -234,7 +237,7 @@ enum Browser {
/// Returns desired capabilities for given [browser], [headless] and /// Returns desired capabilities for given [browser], [headless] and
/// [chromeBinary]. /// [chromeBinary].
@visibleForTesting @visibleForTesting
Map<String, dynamic> getDesiredCapabilities(Browser browser, bool headless, [String chromeBinary]) { Map<String, dynamic> getDesiredCapabilities(Browser browser, bool? headless, [String? chromeBinary]) {
switch (browser) { switch (browser) {
case Browser.chrome: case Browser.chrome:
return <String, dynamic>{ return <String, dynamic>{
@ -258,7 +261,7 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool headless, [Str
'--no-default-browser-check', '--no-default-browser-check',
'--no-sandbox', '--no-sandbox',
'--no-first-run', '--no-first-run',
if (headless) '--headless', if (headless!) '--headless',
], ],
'perfLoggingPrefs': <String, String>{ 'perfLoggingPrefs': <String, String>{
'traceCategories': 'traceCategories':
@ -268,14 +271,13 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool headless, [Str
}, },
}, },
}; };
break;
case Browser.firefox: case Browser.firefox:
return <String, dynamic>{ return <String, dynamic>{
'acceptInsecureCerts': true, 'acceptInsecureCerts': true,
'browserName': 'firefox', 'browserName': 'firefox',
'moz:firefoxOptions' : <String, dynamic>{ 'moz:firefoxOptions' : <String, dynamic>{
'args': <String>[ 'args': <String>[
if (headless) '-headless', if (headless!) '-headless',
], ],
'prefs': <String, dynamic>{ 'prefs': <String, dynamic>{
'dom.file.createInChild': true, 'dom.file.createInChild': true,
@ -290,18 +292,15 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool headless, [Str
'log': <String, String>{'level': 'trace'}, 'log': <String, String>{'level': 'trace'},
}, },
}; };
break;
case Browser.edge: case Browser.edge:
return <String, dynamic>{ return <String, dynamic>{
'acceptInsecureCerts': true, 'acceptInsecureCerts': true,
'browserName': 'edge', 'browserName': 'edge',
}; };
break;
case Browser.safari: case Browser.safari:
return <String, dynamic>{ return <String, dynamic>{
'browserName': 'safari', 'browserName': 'safari',
}; };
break;
case Browser.iosSafari: case Browser.iosSafari:
return <String, dynamic>{ return <String, dynamic>{
'platformName': 'ios', 'platformName': 'ios',
@ -318,11 +317,10 @@ Map<String, dynamic> getDesiredCapabilities(Browser browser, bool headless, [Str
}, },
}; };
} }
throw UnsupportedError('Browser $browser not supported.'); // dead code; remove with null safety migration
} }
/// Converts [browserName] string to [Browser] /// Converts [browserName] string to [Browser]
Browser _browserNameToEnum(String browserName) { Browser _browserNameToEnum(String? browserName) {
switch (browserName) { switch (browserName) {
case 'android-chrome': return Browser.androidChrome; case 'android-chrome': return Browser.androidChrome;
case 'chrome': return Browser.chrome; case 'chrome': return Browser.chrome;

View File

@ -25,7 +25,7 @@ import 'windows/application_package.dart';
/// A package factory that supports all Flutter target platforms. /// A package factory that supports all Flutter target platforms.
class FlutterApplicationPackageFactory extends ApplicationPackageFactory { class FlutterApplicationPackageFactory extends ApplicationPackageFactory {
FlutterApplicationPackageFactory({ FlutterApplicationPackageFactory({
required AndroidSdk androidSdk, required AndroidSdk? androidSdk,
required ProcessManager processManager, required ProcessManager processManager,
required Logger logger, required Logger logger,
required UserMessages userMessages, required UserMessages userMessages,
@ -38,7 +38,7 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory {
_processUtils = ProcessUtils(logger: logger, processManager: processManager); _processUtils = ProcessUtils(logger: logger, processManager: processManager);
final AndroidSdk _androidSdk; final AndroidSdk? _androidSdk;
final ProcessManager _processManager; final ProcessManager _processManager;
final Logger _logger; final Logger _logger;
final ProcessUtils _processUtils; final ProcessUtils _processUtils;
@ -72,7 +72,7 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory {
applicationBinary, applicationBinary,
processManager: _processManager, processManager: _processManager,
logger: _logger, logger: _logger,
androidSdk: _androidSdk, androidSdk: _androidSdk!,
userMessages: _userMessages, userMessages: _userMessages,
processUtils: _processUtils, processUtils: _processUtils,
); );

View File

@ -40,7 +40,7 @@ class FlutterDeviceManager extends DeviceManager {
required Platform platform, required Platform platform,
required ProcessManager processManager, required ProcessManager processManager,
required FileSystem fileSystem, required FileSystem fileSystem,
required AndroidSdk androidSdk, required AndroidSdk? androidSdk,
required FeatureFlags featureFlags, required FeatureFlags featureFlags,
required IOSSimulatorUtils iosSimulatorUtils, required IOSSimulatorUtils iosSimulatorUtils,
required XCDevice xcDevice, required XCDevice xcDevice,

View File

@ -338,7 +338,7 @@ class IOSSimulator extends Device {
final SimControl _simControl; final SimControl _simControl;
@override @override
DevFSWriter createDevFSWriter(covariant ApplicationPackage app, String userIdentifier) { DevFSWriter createDevFSWriter(covariant ApplicationPackage? app, String? userIdentifier) {
return LocalDevFSWriter(fileSystem: globals.fs); return LocalDevFSWriter(fileSystem: globals.fs);
} }

View File

@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:dwds/data/build_result.dart'; import 'package:dwds/data/build_result.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:dwds/dwds.dart'; import 'package:dwds/dwds.dart';
import 'package:html/dom.dart'; import 'package:html/dom.dart';
import 'package:html/parser.dart'; import 'package:html/parser.dart';
@ -46,24 +45,24 @@ import '../web/memory_fs.dart';
import 'sdk_web_configuration.dart'; import 'sdk_web_configuration.dart';
typedef DwdsLauncher = Future<Dwds> Function({ typedef DwdsLauncher = Future<Dwds> Function({
@required AssetReader assetReader, required AssetReader assetReader,
@required Stream<BuildResult> buildResults, required Stream<BuildResult> buildResults,
@required ConnectionProvider chromeConnection, required ConnectionProvider chromeConnection,
@required LoadStrategy loadStrategy, required LoadStrategy loadStrategy,
@required bool enableDebugging, required bool enableDebugging,
ExpressionCompiler expressionCompiler, ExpressionCompiler? expressionCompiler,
bool enableDebugExtension, bool? enableDebugExtension,
String hostname, String? hostname,
bool useSseForDebugProxy, bool? useSseForDebugProxy,
bool useSseForDebugBackend, bool? useSseForDebugBackend,
bool useSseForInjectedClient, bool? useSseForInjectedClient,
UrlEncoder urlEncoder, UrlEncoder? urlEncoder,
bool spawnDds, bool? spawnDds,
bool enableDevtoolsLaunch, bool? enableDevtoolsLaunch,
DevtoolsLauncher devtoolsLauncher, DevtoolsLauncher? devtoolsLauncher,
bool launchDevToolsInNewWindow, bool? launchDevToolsInNewWindow,
SdkConfigurationProvider sdkConfigurationProvider, SdkConfigurationProvider? sdkConfigurationProvider,
bool emitDebugEvents, bool? emitDebugEvents,
}); });
// A minimal index for projects that do not yet support web. // A minimal index for projects that do not yet support web.
@ -83,11 +82,11 @@ const String _kDefaultIndex = '''
/// This is only used in development mode. /// This is only used in development mode.
class WebExpressionCompiler implements ExpressionCompiler { class WebExpressionCompiler implements ExpressionCompiler {
WebExpressionCompiler(this._generator, { WebExpressionCompiler(this._generator, {
@required FileSystem fileSystem, required FileSystem? fileSystem,
}) : _fileSystem = fileSystem; }) : _fileSystem = fileSystem;
final ResidentCompiler _generator; final ResidentCompiler _generator;
final FileSystem _fileSystem; final FileSystem? _fileSystem;
@override @override
Future<ExpressionCompilationResult> compileExpressionToJs( Future<ExpressionCompilationResult> compileExpressionToJs(
@ -100,13 +99,13 @@ class WebExpressionCompiler implements ExpressionCompiler {
String moduleName, String moduleName,
String expression, String expression,
) async { ) async {
final CompilerOutput compilerOutput = final CompilerOutput? compilerOutput =
await _generator.compileExpressionToJs(libraryUri, line, column, await _generator.compileExpressionToJs(libraryUri, line, column,
jsModules, jsFrameValues, moduleName, expression); jsModules, jsFrameValues, moduleName, expression);
if (compilerOutput != null && compilerOutput.outputFilename != null) { if (compilerOutput != null && compilerOutput.outputFilename != null) {
final String content = utf8.decode( final String content = utf8.decode(
_fileSystem.file(compilerOutput.outputFilename).readAsBytesSync()); _fileSystem!.file(compilerOutput.outputFilename).readAsBytesSync());
return ExpressionCompilationResult( return ExpressionCompilationResult(
content, compilerOutput.errorCount > 0); content, compilerOutput.errorCount > 0);
} }
@ -117,7 +116,7 @@ class WebExpressionCompiler implements ExpressionCompiler {
} }
@override @override
Future<void> initialize({String moduleFormat, bool soundNullSafety}) async {} Future<void> initialize({String? moduleFormat, bool? soundNullSafety}) async {}
@override @override
Future<bool> updateDependencies(Map<String, ModuleInfo> modules) async => true; Future<bool> updateDependencies(Map<String, ModuleInfo> modules) async => true;
@ -180,10 +179,10 @@ class WebAssetServer implements AssetReader {
/// Unhandled exceptions will throw a [ToolExit] with the error and stack /// Unhandled exceptions will throw a [ToolExit] with the error and stack
/// trace. /// trace.
static Future<WebAssetServer> start( static Future<WebAssetServer> start(
ChromiumLauncher chromiumLauncher, ChromiumLauncher? chromiumLauncher,
String hostname, String hostname,
int port, int? port,
UrlTunneller urlTunneller, UrlTunneller? urlTunneller,
bool useSseForDebugProxy, bool useSseForDebugProxy,
bool useSseForDebugBackend, bool useSseForDebugBackend,
bool useSseForInjectedClient, bool useSseForInjectedClient,
@ -191,7 +190,7 @@ class WebAssetServer implements AssetReader {
bool enableDwds, bool enableDwds,
bool enableDds, bool enableDds,
Uri entrypoint, Uri entrypoint,
ExpressionCompiler expressionCompiler, ExpressionCompiler? expressionCompiler,
NullSafetyMode nullSafetyMode, { NullSafetyMode nullSafetyMode, {
bool testMode = false, bool testMode = false,
DwdsLauncher dwdsLauncher = Dwds.start, DwdsLauncher dwdsLauncher = Dwds.start,
@ -202,7 +201,7 @@ class WebAssetServer implements AssetReader {
} else { } else {
address = (await InternetAddress.lookup(hostname)).first; address = (await InternetAddress.lookup(hostname)).first;
} }
HttpServer httpServer; HttpServer? httpServer;
const int kMaxRetries = 4; const int kMaxRetries = 4;
for (int i = 0; i <= kMaxRetries; i++) { for (int i = 0; i <= kMaxRetries; i++) {
try { try {
@ -218,7 +217,7 @@ class WebAssetServer implements AssetReader {
} }
// Allow rendering in a iframe. // Allow rendering in a iframe.
httpServer.defaultResponseHeaders.remove('x-frame-options', 'SAMEORIGIN'); httpServer!.defaultResponseHeaders.remove('x-frame-options', 'SAMEORIGIN');
final PackageConfig packageConfig = buildInfo.packageConfig; final PackageConfig packageConfig = buildInfo.packageConfig;
final Map<String, String> digests = <String, String>{}; final Map<String, String> digests = <String, String>{};
@ -246,7 +245,7 @@ class WebAssetServer implements AssetReader {
basePath: server.basePath, basePath: server.basePath,
); );
runZonedGuarded(() { runZonedGuarded(() {
shelf.serveRequests(httpServer, releaseAssetServer.handle); shelf.serveRequests(httpServer!, releaseAssetServer.handle);
}, (Object e, StackTrace s) { }, (Object e, StackTrace s) {
globals.printTrace('Release asset server: error serving requests: $e:$s'); globals.printTrace('Release asset server: error serving requests: $e:$s');
}); });
@ -284,7 +283,7 @@ class WebAssetServer implements AssetReader {
enableDebugExtension: true, enableDebugExtension: true,
buildResults: const Stream<BuildResult>.empty(), buildResults: const Stream<BuildResult>.empty(),
chromeConnection: () async { chromeConnection: () async {
final Chromium chromium = await chromiumLauncher.connectedInstance; final Chromium chromium = await chromiumLauncher!.connectedInstance;
return chromium.chromeConnection; return chromium.chromeConnection;
}, },
hostname: hostname, hostname: hostname,
@ -297,11 +296,11 @@ class WebAssetServer implements AssetReader {
ReloadConfiguration.none, ReloadConfiguration.none,
server, server,
digestProvider, digestProvider,
server.basePath, server.basePath!,
).strategy, ).strategy,
expressionCompiler: expressionCompiler, expressionCompiler: expressionCompiler,
spawnDds: enableDds, spawnDds: enableDds,
sdkConfigurationProvider: SdkWebConfigurationProvider(globals.artifacts), sdkConfigurationProvider: SdkWebConfigurationProvider(globals.artifacts!),
); );
shelf.Pipeline pipeline = const shelf.Pipeline(); shelf.Pipeline pipeline = const shelf.Pipeline();
if (enableDwds) { if (enableDwds) {
@ -313,42 +312,42 @@ class WebAssetServer implements AssetReader {
final shelf.Cascade cascade = final shelf.Cascade cascade =
shelf.Cascade().add(dwds.handler).add(dwdsHandler); shelf.Cascade().add(dwds.handler).add(dwdsHandler);
runZonedGuarded(() { runZonedGuarded(() {
shelf.serveRequests(httpServer, cascade.handler); shelf.serveRequests(httpServer!, cascade.handler);
}, (Object e, StackTrace s) { }, (Object e, StackTrace s) {
globals.printTrace('Dwds server: error serving requests: $e:$s'); globals.printTrace('Dwds server: error serving requests: $e:$s');
}); });
server.dwds = dwds; server.dwds = dwds;
server._dwdsInit = true;
return server; return server;
} }
final NullSafetyMode _nullSafetyMode; final NullSafetyMode _nullSafetyMode;
final HttpServer _httpServer; final HttpServer _httpServer;
final WebMemoryFS _webMemoryFS = WebMemoryFS(); final WebMemoryFS _webMemoryFS = WebMemoryFS();
final PackageConfig _packages; final PackageConfig _packages;
final InternetAddress internetAddress; final InternetAddress internetAddress;
/* late final */ Dwds dwds; late final Dwds dwds;
Directory entrypointCacheDirectory; late Directory entrypointCacheDirectory;
bool _dwdsInit = false;
@visibleForTesting @visibleForTesting
HttpHeaders get defaultResponseHeaders => _httpServer.defaultResponseHeaders; HttpHeaders get defaultResponseHeaders => _httpServer.defaultResponseHeaders;
@visibleForTesting @visibleForTesting
Uint8List getFile(String path) => _webMemoryFS.files[path]; Uint8List? getFile(String path) => _webMemoryFS.files[path];
@visibleForTesting @visibleForTesting
Uint8List getSourceMap(String path) => _webMemoryFS.sourcemaps[path]; Uint8List? getSourceMap(String path) => _webMemoryFS.sourcemaps[path];
@visibleForTesting @visibleForTesting
Uint8List getMetadata(String path) => _webMemoryFS.metadataFiles[path]; Uint8List? getMetadata(String path) => _webMemoryFS.metadataFiles[path];
@visibleForTesting @visibleForTesting
/// The base path to serve from. /// The base path to serve from.
/// ///
/// It should have no leading or trailing slashes. /// It should have no leading or trailing slashes.
String basePath = ''; String? basePath = '';
// handle requests for JavaScript source, dart sources maps, or asset files. // handle requests for JavaScript source, dart sources maps, or asset files.
@visibleForTesting @visibleForTesting
@ -358,7 +357,7 @@ class WebAssetServer implements AssetReader {
return shelf.Response.notFound(''); return shelf.Response.notFound('');
} }
final String requestPath = _stripBasePath(request.url.path, basePath); final String? requestPath = _stripBasePath(request.url.path, basePath);
if (requestPath == null) { if (requestPath == null) {
return shelf.Response.notFound(''); return shelf.Response.notFound('');
@ -372,7 +371,7 @@ class WebAssetServer implements AssetReader {
final Map<String, String> headers = <String, String>{}; final Map<String, String> headers = <String, String>{};
// Track etag headers for better caching of resources. // Track etag headers for better caching of resources.
final String ifNoneMatch = request.headers[HttpHeaders.ifNoneMatchHeader]; final String? ifNoneMatch = request.headers[HttpHeaders.ifNoneMatchHeader];
headers[HttpHeaders.cacheControlHeader] = 'max-age=0, must-revalidate'; headers[HttpHeaders.cacheControlHeader] = 'max-age=0, must-revalidate';
// If this is a JavaScript file, it must be in the in-memory cache. // If this is a JavaScript file, it must be in the in-memory cache.
@ -380,7 +379,7 @@ class WebAssetServer implements AssetReader {
final String webServerPath = final String webServerPath =
requestPath.replaceFirst('.dart.js', '.dart.lib.js'); requestPath.replaceFirst('.dart.js', '.dart.lib.js');
if (_webMemoryFS.files.containsKey(requestPath) || _webMemoryFS.files.containsKey(webServerPath)) { if (_webMemoryFS.files.containsKey(requestPath) || _webMemoryFS.files.containsKey(webServerPath)) {
final List<int> bytes = getFile(requestPath) ?? getFile(webServerPath); final List<int>? bytes = getFile(requestPath) ?? getFile(webServerPath);
// Use the underlying buffer hashCode as a revision string. This buffer is // Use the underlying buffer hashCode as a revision string. This buffer is
// replaced whenever the frontend_server produces new output files, which // replaced whenever the frontend_server produces new output files, which
// will also change the hashCode. // will also change the hashCode.
@ -388,7 +387,7 @@ class WebAssetServer implements AssetReader {
if (ifNoneMatch == etag) { if (ifNoneMatch == etag) {
return shelf.Response.notModified(); return shelf.Response.notModified();
} }
headers[HttpHeaders.contentLengthHeader] = bytes.length.toString(); headers[HttpHeaders.contentLengthHeader] = bytes!.length.toString();
headers[HttpHeaders.contentTypeHeader] = 'application/javascript'; headers[HttpHeaders.contentTypeHeader] = 'application/javascript';
headers[HttpHeaders.etagHeader] = etag; headers[HttpHeaders.etagHeader] = etag;
return shelf.Response.ok(bytes, headers: headers); return shelf.Response.ok(bytes, headers: headers);
@ -396,12 +395,12 @@ class WebAssetServer implements AssetReader {
// If this is a sourcemap file, then it might be in the in-memory cache. // If this is a sourcemap file, then it might be in the in-memory cache.
// Attempt to lookup the file by URI. // Attempt to lookup the file by URI.
if (_webMemoryFS.sourcemaps.containsKey(requestPath)) { if (_webMemoryFS.sourcemaps.containsKey(requestPath)) {
final List<int> bytes = getSourceMap(requestPath); final List<int>? bytes = getSourceMap(requestPath);
final String etag = bytes.hashCode.toString(); final String etag = bytes.hashCode.toString();
if (ifNoneMatch == etag) { if (ifNoneMatch == etag) {
return shelf.Response.notModified(); return shelf.Response.notModified();
} }
headers[HttpHeaders.contentLengthHeader] = bytes.length.toString(); headers[HttpHeaders.contentLengthHeader] = bytes!.length.toString();
headers[HttpHeaders.contentTypeHeader] = 'application/json'; headers[HttpHeaders.contentTypeHeader] = 'application/json';
headers[HttpHeaders.etagHeader] = etag; headers[HttpHeaders.etagHeader] = etag;
return shelf.Response.ok(bytes, headers: headers); return shelf.Response.ok(bytes, headers: headers);
@ -410,12 +409,12 @@ class WebAssetServer implements AssetReader {
// If this is a metadata file, then it might be in the in-memory cache. // If this is a metadata file, then it might be in the in-memory cache.
// Attempt to lookup the file by URI. // Attempt to lookup the file by URI.
if (_webMemoryFS.metadataFiles.containsKey(requestPath)) { if (_webMemoryFS.metadataFiles.containsKey(requestPath)) {
final List<int> bytes = getMetadata(requestPath); final List<int>? bytes = getMetadata(requestPath);
final String etag = bytes.hashCode.toString(); final String etag = bytes.hashCode.toString();
if (ifNoneMatch == etag) { if (ifNoneMatch == etag) {
return shelf.Response.notModified(); return shelf.Response.notModified();
} }
headers[HttpHeaders.contentLengthHeader] = bytes.length.toString(); headers[HttpHeaders.contentLengthHeader] = bytes!.length.toString();
headers[HttpHeaders.contentTypeHeader] = 'application/json'; headers[HttpHeaders.contentTypeHeader] = 'application/json';
headers[HttpHeaders.etagHeader] = etag; headers[HttpHeaders.etagHeader] = etag;
return shelf.Response.ok(bytes, headers: headers); return shelf.Response.ok(bytes, headers: headers);
@ -475,7 +474,9 @@ class WebAssetServer implements AssetReader {
/// Tear down the http server running. /// Tear down the http server running.
Future<void> dispose() async { Future<void> dispose() async {
await dwds?.stop(); if (_dwdsInit) {
await dwds.stop();
}
return _httpServer.close(); return _httpServer.close();
} }
@ -546,7 +547,7 @@ class WebAssetServer implements AssetReader {
// The file might have been a package file which is signaled by a // The file might have been a package file which is signaled by a
// `/packages/<package>/<path>` request. // `/packages/<package>/<path>` request.
if (segments.first == 'packages') { if (segments.first == 'packages') {
final Uri filePath = _packages final Uri? filePath = _packages
.resolve(Uri(scheme: 'package', pathSegments: segments.skip(1))); .resolve(Uri(scheme: 'package', pathSegments: segments.skip(1)));
if (filePath != null) { if (filePath != null) {
final File packageFile = globals.fs.file(filePath); final File packageFile = globals.fs.file(filePath);
@ -559,7 +560,7 @@ class WebAssetServer implements AssetReader {
// Otherwise it must be a Dart SDK source or a Flutter Web SDK source. // Otherwise it must be a Dart SDK source or a Flutter Web SDK source.
final Directory dartSdkParent = globals.fs final Directory dartSdkParent = globals.fs
.directory( .directory(
globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath)) globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath))
.parent; .parent;
final File dartSdkFile = globals.fs.file(dartSdkParent.uri.resolve(path)); final File dartSdkFile = globals.fs.file(dartSdkParent.uri.resolve(path));
if (dartSdkFile.existsSync()) { if (dartSdkFile.existsSync()) {
@ -567,25 +568,25 @@ class WebAssetServer implements AssetReader {
} }
final Directory flutterWebSdk = globals.fs final Directory flutterWebSdk = globals.fs
.directory(globals.artifacts.getHostArtifact(HostArtifact.flutterWebSdk)); .directory(globals.artifacts!.getHostArtifact(HostArtifact.flutterWebSdk));
final File webSdkFile = globals.fs.file(flutterWebSdk.uri.resolve(path)); final File webSdkFile = globals.fs.file(flutterWebSdk.uri.resolve(path));
return webSdkFile; return webSdkFile;
} }
File get _resolveDartSdkJsFile => File get _resolveDartSdkJsFile =>
globals.fs.file(globals.artifacts.getHostArtifact( globals.fs.file(globals.artifacts!.getHostArtifact(
kDartSdkJsArtifactMap[webRenderer][_nullSafetyMode] kDartSdkJsArtifactMap[webRenderer]![_nullSafetyMode]!
)); ));
File get _resolveDartSdkJsMapFile => File get _resolveDartSdkJsMapFile =>
globals.fs.file(globals.artifacts.getHostArtifact( globals.fs.file(globals.artifacts!.getHostArtifact(
kDartSdkJsMapArtifactMap[webRenderer][_nullSafetyMode] kDartSdkJsMapArtifactMap[webRenderer]![_nullSafetyMode]!
)); ));
@override @override
Future<String> dartSourceContents(String serverPath) async { Future<String?> dartSourceContents(String serverPath) async {
serverPath = _stripBasePath(serverPath, basePath); serverPath = _stripBasePath(serverPath, basePath)!;
final File result = _resolveDartFile(serverPath); final File result = _resolveDartFile(serverPath);
if (result.existsSync()) { if (result.existsSync()) {
return result.readAsString(); return result.readAsString();
@ -595,18 +596,18 @@ class WebAssetServer implements AssetReader {
@override @override
Future<String> sourceMapContents(String serverPath) async { Future<String> sourceMapContents(String serverPath) async {
serverPath = _stripBasePath(serverPath, basePath); serverPath = _stripBasePath(serverPath, basePath)!;
return utf8.decode(_webMemoryFS.sourcemaps[serverPath]); return utf8.decode(_webMemoryFS.sourcemaps[serverPath]!);
} }
@override @override
Future<String> metadataContents(String serverPath) async { Future<String?> metadataContents(String serverPath) async {
serverPath = _stripBasePath(serverPath, basePath); final String? resultPath = _stripBasePath(serverPath, basePath);
if (serverPath == 'main_module.ddc_merged_metadata') { if (resultPath == 'main_module.ddc_merged_metadata') {
return _webMemoryFS.mergedMetadata; return _webMemoryFS.mergedMetadata;
} }
if (_webMemoryFS.metadataFiles.containsKey(serverPath)) { if (_webMemoryFS.metadataFiles.containsKey(resultPath)) {
return utf8.decode(_webMemoryFS.metadataFiles[serverPath]); return utf8.decode(_webMemoryFS.metadataFiles[resultPath]!);
} }
throw Exception('Could not find metadata contents for $serverPath'); throw Exception('Could not find metadata contents for $serverPath');
} }
@ -618,8 +619,8 @@ class WebAssetServer implements AssetReader {
class ConnectionResult { class ConnectionResult {
ConnectionResult(this.appConnection, this.debugConnection, this.vmService); ConnectionResult(this.appConnection, this.debugConnection, this.vmService);
final AppConnection appConnection; final AppConnection? appConnection;
final DebugConnection debugConnection; final DebugConnection? debugConnection;
final vm_service.VmService vmService; final vm_service.VmService vmService;
} }
@ -630,29 +631,29 @@ class WebDevFS implements DevFS {
/// [testMode] is true, do not actually initialize dwds or the shelf static /// [testMode] is true, do not actually initialize dwds or the shelf static
/// server. /// server.
WebDevFS({ WebDevFS({
@required this.hostname, required this.hostname,
@required int port, required int? port,
@required this.packagesFilePath, required this.packagesFilePath,
@required this.urlTunneller, required this.urlTunneller,
@required this.useSseForDebugProxy, required this.useSseForDebugProxy,
@required this.useSseForDebugBackend, required this.useSseForDebugBackend,
@required this.useSseForInjectedClient, required this.useSseForInjectedClient,
@required this.buildInfo, required this.buildInfo,
@required this.enableDwds, required this.enableDwds,
@required this.enableDds, required this.enableDds,
@required this.entrypoint, required this.entrypoint,
@required this.expressionCompiler, required this.expressionCompiler,
@required this.chromiumLauncher, required this.chromiumLauncher,
@required this.nullAssertions, required this.nullAssertions,
@required this.nativeNullAssertions, required this.nativeNullAssertions,
@required this.nullSafetyMode, required this.nullSafetyMode,
this.testMode = false, this.testMode = false,
}) : _port = port; }) : _port = port;
final Uri entrypoint; final Uri entrypoint;
final String hostname; final String hostname;
final String packagesFilePath; final String packagesFilePath;
final UrlTunneller urlTunneller; final UrlTunneller? urlTunneller;
final bool useSseForDebugProxy; final bool useSseForDebugProxy;
final bool useSseForDebugBackend; final bool useSseForDebugBackend;
final bool useSseForInjectedClient; final bool useSseForInjectedClient;
@ -660,14 +661,14 @@ class WebDevFS implements DevFS {
final bool enableDwds; final bool enableDwds;
final bool enableDds; final bool enableDds;
final bool testMode; final bool testMode;
final ExpressionCompiler expressionCompiler; final ExpressionCompiler? expressionCompiler;
final ChromiumLauncher chromiumLauncher; final ChromiumLauncher? chromiumLauncher;
final bool nullAssertions; final bool nullAssertions;
final bool nativeNullAssertions; final bool nativeNullAssertions;
final int _port; final int? _port;
final NullSafetyMode nullSafetyMode; final NullSafetyMode nullSafetyMode;
WebAssetServer webAssetServer; late WebAssetServer webAssetServer;
Dwds get dwds => webAssetServer.dwds; Dwds get dwds => webAssetServer.dwds;
@ -675,13 +676,13 @@ class WebDevFS implements DevFS {
@override @override
bool hasSetAssetDirectory = false; bool hasSetAssetDirectory = false;
Future<DebugConnection> _cachedExtensionFuture; Future<DebugConnection>? _cachedExtensionFuture;
StreamSubscription<void> _connectedApps; StreamSubscription<void>? _connectedApps;
/// Connect and retrieve the [DebugConnection] for the current application. /// Connect and retrieve the [DebugConnection] for the current application.
/// ///
/// Only calls [AppConnection.runMain] on the subsequent connections. /// Only calls [AppConnection.runMain] on the subsequent connections.
Future<ConnectionResult> connect(bool useDebugExtension) { Future<ConnectionResult?> connect(bool useDebugExtension) {
final Completer<ConnectionResult> firstConnection = final Completer<ConnectionResult> firstConnection =
Completer<ConnectionResult>(); Completer<ConnectionResult>();
_connectedApps = _connectedApps =
@ -706,7 +707,7 @@ class WebDevFS implements DevFS {
firstConnection.completeError(error, stackTrace); firstConnection.completeError(error, stackTrace);
} }
} }
}, onError: (dynamic error, StackTrace stackTrace) { }, onError: (Object error, StackTrace stackTrace) {
globals.printError( globals.printError(
'Unknown error while waiting for debug connection:$error\n$stackTrace'); 'Unknown error while waiting for debug connection:$error\n$stackTrace');
if (!firstConnection.isCompleted) { if (!firstConnection.isCompleted) {
@ -720,18 +721,18 @@ class WebDevFS implements DevFS {
List<Uri> sources = <Uri>[]; List<Uri> sources = <Uri>[];
@override @override
DateTime lastCompiled; DateTime? lastCompiled;
@override @override
PackageConfig lastPackageConfig; PackageConfig? lastPackageConfig;
// We do not evict assets on the web. // We do not evict assets on the web.
@override @override
Set<String> get assetPathsToEvict => const <String>{}; Set<String> get assetPathsToEvict => const <String>{};
@override @override
Uri get baseUri => _baseUri; Uri? get baseUri => _baseUri;
Uri _baseUri; Uri? _baseUri;
@override @override
Future<Uri> create() async { Future<Uri> create() async {
@ -758,11 +759,11 @@ class WebDevFS implements DevFS {
webAssetServer.webRenderer = WebRendererMode.canvaskit; webAssetServer.webRenderer = WebRendererMode.canvaskit;
} }
if (hostname == 'any') { if (hostname == 'any') {
_baseUri = Uri.http('localhost:$selectedPort', webAssetServer.basePath); _baseUri = Uri.http('localhost:$selectedPort', webAssetServer.basePath!);
} else { } else {
_baseUri = Uri.http('$hostname:$selectedPort', webAssetServer.basePath); _baseUri = Uri.http('$hostname:$selectedPort', webAssetServer.basePath!);
} }
return _baseUri; return _baseUri!;
} }
@override @override
@ -780,24 +781,24 @@ class WebDevFS implements DevFS {
String get fsName => 'web_asset'; String get fsName => 'web_asset';
@override @override
Directory get rootDirectory => null; Directory? get rootDirectory => null;
@override @override
Future<UpdateFSReport> update({ Future<UpdateFSReport> update({
@required Uri mainUri, required Uri mainUri,
@required ResidentCompiler generator, required ResidentCompiler generator,
@required bool trackWidgetCreation, required bool trackWidgetCreation,
@required String pathToReload, required String pathToReload,
@required List<Uri> invalidatedFiles, required List<Uri> invalidatedFiles,
@required PackageConfig packageConfig, required PackageConfig packageConfig,
@required String dillOutputPath, required String dillOutputPath,
DevFSWriter devFSWriter, DevFSWriter? devFSWriter,
String target, String? target,
AssetBundle bundle, AssetBundle? bundle,
DateTime firstBuildTime, DateTime? firstBuildTime,
bool bundleFirstUpload = false, bool bundleFirstUpload = false,
bool fullRestart = false, bool fullRestart = false,
String projectRootPath, String? projectRootPath,
}) async { }) async {
assert(trackWidgetCreation != null); assert(trackWidgetCreation != null);
assert(generator != null); assert(generator != null);
@ -854,7 +855,7 @@ class WebDevFS implements DevFS {
// the web specific bootstrap logic. To make it easier for DWDS to handle // the web specific bootstrap logic. To make it easier for DWDS to handle
// mapping the file name, this is done via an additional file root and // mapping the file name, this is done via an additional file root and
// special hard-coded scheme. // special hard-coded scheme.
final CompilerOutput compilerOutput = await generator.recompile( final CompilerOutput? compilerOutput = await generator.recompile(
Uri( Uri(
scheme: 'org-dartlang-app', scheme: 'org-dartlang-app',
path: '/${mainUri.pathSegments.last}', path: '/${mainUri.pathSegments.last}',
@ -873,11 +874,11 @@ class WebDevFS implements DevFS {
lastCompiled = candidateCompileTime; lastCompiled = candidateCompileTime;
// list of sources that needs to be monitored are in [compilerOutput.sources] // list of sources that needs to be monitored are in [compilerOutput.sources]
sources = compilerOutput.sources; sources = compilerOutput.sources;
File codeFile; late File codeFile;
File manifestFile; File manifestFile;
File sourcemapFile; File sourcemapFile;
File metadataFile; File metadataFile;
List<String> modules; late List<String> modules;
try { try {
final Directory parentDirectory = globals.fs.directory(outputDirectoryPath); final Directory parentDirectory = globals.fs.directory(outputDirectoryPath);
codeFile = parentDirectory.childFile('${compilerOutput.outputFilename}.sources'); codeFile = parentDirectory.childFile('${compilerOutput.outputFilename}.sources');
@ -898,7 +899,7 @@ class WebDevFS implements DevFS {
@visibleForTesting @visibleForTesting
final File requireJS = globals.fs.file(globals.fs.path.join( final File requireJS = globals.fs.file(globals.fs.path.join(
globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path,
'lib', 'lib',
'dev_compiler', 'dev_compiler',
'kernel', 'kernel',
@ -908,7 +909,7 @@ class WebDevFS implements DevFS {
@visibleForTesting @visibleForTesting
final File stackTraceMapper = globals.fs.file(globals.fs.path.join( final File stackTraceMapper = globals.fs.file(globals.fs.path.join(
globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path,
'lib', 'lib',
'dev_compiler', 'dev_compiler',
'web', 'web',
@ -924,10 +925,10 @@ class WebDevFS implements DevFS {
class ReleaseAssetServer { class ReleaseAssetServer {
ReleaseAssetServer( ReleaseAssetServer(
this.entrypoint, { this.entrypoint, {
@required FileSystem fileSystem, required FileSystem fileSystem,
@required String webBuildDirectory, required String? webBuildDirectory,
@required String flutterRoot, required String? flutterRoot,
@required Platform platform, required Platform platform,
this.basePath = '', this.basePath = '',
}) : _fileSystem = fileSystem, }) : _fileSystem = fileSystem,
_platform = platform, _platform = platform,
@ -937,8 +938,8 @@ class ReleaseAssetServer {
FileSystemUtils(fileSystem: fileSystem, platform: platform); FileSystemUtils(fileSystem: fileSystem, platform: platform);
final Uri entrypoint; final Uri entrypoint;
final String _flutterRoot; final String? _flutterRoot;
final String _webBuildDirectory; final String? _webBuildDirectory;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final FileSystemUtils _fileSystemUtils; final FileSystemUtils _fileSystemUtils;
final Platform _platform; final Platform _platform;
@ -948,7 +949,7 @@ class ReleaseAssetServer {
/// The base path to serve from. /// The base path to serve from.
/// ///
/// It should have no leading or trailing slashes. /// It should have no leading or trailing slashes.
final String basePath; final String? basePath;
// Locations where source files, assets, or source maps may be located. // Locations where source files, assets, or source maps may be located.
List<Uri> _searchPaths() => <Uri>[ List<Uri> _searchPaths() => <Uri>[
@ -965,8 +966,8 @@ class ReleaseAssetServer {
return shelf.Response.notFound(''); return shelf.Response.notFound('');
} }
Uri fileUri; Uri? fileUri;
final String requestPath = _stripBasePath(request.url.path, basePath); final String? requestPath = _stripBasePath(request.url.path, basePath);
if (requestPath == null) { if (requestPath == null) {
return shelf.Response.notFound(''); return shelf.Response.notFound('');
@ -1000,7 +1001,7 @@ class ReleaseAssetServer {
} }
final File file = _fileSystem final File file = _fileSystem
.file(_fileSystem.path.join(_webBuildDirectory, 'index.html')); .file(_fileSystem.path.join(_webBuildDirectory!, 'index.html'));
return shelf.Response.ok(file.readAsBytesSync(), headers: <String, String>{ return shelf.Response.ok(file.readAsBytesSync(), headers: <String, String>{
'Content-Type': 'text/html', 'Content-Type': 'text/html',
}); });
@ -1022,19 +1023,19 @@ void log(logging.LogRecord event) {
Future<Directory> _loadDwdsDirectory( Future<Directory> _loadDwdsDirectory(
FileSystem fileSystem, Logger logger) async { FileSystem fileSystem, Logger logger) async {
final String toolPackagePath = final String toolPackagePath =
fileSystem.path.join(Cache.flutterRoot, 'packages', 'flutter_tools'); fileSystem.path.join(Cache.flutterRoot!, 'packages', 'flutter_tools');
final String packageFilePath = final String packageFilePath =
fileSystem.path.join(toolPackagePath, '.dart_tool', 'package_config.json'); fileSystem.path.join(toolPackagePath, '.dart_tool', 'package_config.json');
final PackageConfig packageConfig = await loadPackageConfigWithLogging( final PackageConfig packageConfig = await loadPackageConfigWithLogging(
fileSystem.file(packageFilePath), fileSystem.file(packageFilePath),
logger: logger, logger: logger,
); );
return fileSystem.directory(packageConfig['dwds'].packageUriRoot); return fileSystem.directory(packageConfig['dwds']!.packageUriRoot);
} }
String _stripBasePath(String path, String basePath) { String? _stripBasePath(String path, String? basePath) {
path = _stripLeadingSlashes(path); path = _stripLeadingSlashes(path);
if (path.startsWith(basePath)) { if (basePath != null && path.startsWith(basePath)) {
path = path.substring(basePath.length); path = path.substring(basePath.length);
} else { } else {
// The given path isn't under base path, return null to indicate that. // The given path isn't under base path, return null to indicate that.
@ -1057,25 +1058,25 @@ String _stripTrailingSlashes(String path) {
return path; return path;
} }
String _parseBasePathFromIndexHtml(File indexHtml) { String? _parseBasePathFromIndexHtml(File indexHtml) {
final String htmlContent = final String htmlContent =
indexHtml.existsSync() ? indexHtml.readAsStringSync() : _kDefaultIndex; indexHtml.existsSync() ? indexHtml.readAsStringSync() : _kDefaultIndex;
final Document document = parse(htmlContent); final Document document = parse(htmlContent);
final Element baseElement = document.querySelector('base'); final Element? baseElement = document.querySelector('base');
String baseHref = String? baseHref =
baseElement?.attributes == null ? null : baseElement.attributes['href']; baseElement?.attributes == null ? null : baseElement!.attributes['href'];
if (baseHref == null || baseHref == kBaseHrefPlaceholder) { if (baseHref == null || baseHref == kBaseHrefPlaceholder) {
baseHref = ''; baseHref = '';
} else if (!baseHref.startsWith('/')) { } else if (!baseHref.startsWith('/')) {
throw ToolExit( throw ToolExit(
'Error: The base href in "web/index.html" must be absolute (i.e. start ' 'Error: The base href in "web/index.html" must be absolute (i.e. start '
'with a "/"), but found: `${baseElement.outerHtml}`.\n' 'with a "/"), but found: `${baseElement!.outerHtml}`.\n'
'$basePathExample', '$basePathExample',
); );
} else if (!baseHref.endsWith('/')) { } else if (!baseHref.endsWith('/')) {
throw ToolExit( throw ToolExit(
'Error: The base href in "web/index.html" must end with a "/", but found: `${baseElement.outerHtml}`.\n' 'Error: The base href in "web/index.html" must end with a "/", but found: `${baseElement!.outerHtml}`.\n'
'$basePathExample', '$basePathExample',
); );
} else { } else {

View File

@ -2,12 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
// ignore: import_of_legacy_library_into_null_safe
import 'package:dwds/dwds.dart'; import 'package:dwds/dwds.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart'; import 'package:package_config/package_config.dart';
import 'package:vm_service/vm_service.dart' as vmservice; import 'package:vm_service/vm_service.dart' as vmservice;
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart' import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
@ -48,16 +46,16 @@ class DwdsWebRunnerFactory extends WebRunnerFactory {
@override @override
ResidentRunner createWebRunner( ResidentRunner createWebRunner(
FlutterDevice device, { FlutterDevice device, {
String target, String? target,
@required bool stayResident, required bool stayResident,
@required FlutterProject flutterProject, required FlutterProject flutterProject,
@required bool ipv6, required bool? ipv6,
@required DebuggingOptions debuggingOptions, required DebuggingOptions debuggingOptions,
@required UrlTunneller urlTunneller, required UrlTunneller? urlTunneller,
@required Logger logger, required Logger? logger,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required SystemClock systemClock, required SystemClock systemClock,
@required Usage usage, required Usage usage,
bool machine = false, bool machine = false,
}) { }) {
return ResidentWebRunner( return ResidentWebRunner(
@ -83,18 +81,18 @@ const String kExitMessage = 'Failed to establish connection with the application
class ResidentWebRunner extends ResidentRunner { class ResidentWebRunner extends ResidentRunner {
ResidentWebRunner( ResidentWebRunner(
FlutterDevice device, { FlutterDevice? device, {
String target, String? target,
bool stayResident = true, bool stayResident = true,
bool machine = false, bool machine = false,
@required this.flutterProject, required this.flutterProject,
@required bool ipv6, required bool? ipv6,
@required DebuggingOptions debuggingOptions, required DebuggingOptions debuggingOptions,
@required FileSystem fileSystem, required FileSystem? fileSystem,
@required Logger logger, required Logger? logger,
@required SystemClock systemClock, required SystemClock systemClock,
@required Usage usage, required Usage usage,
@required UrlTunneller urlTunneller, UrlTunneller? urlTunneller,
ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler, ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler,
}) : _fileSystem = fileSystem, }) : _fileSystem = fileSystem,
_logger = logger, _logger = logger,
@ -102,8 +100,8 @@ class ResidentWebRunner extends ResidentRunner {
_usage = usage, _usage = usage,
_urlTunneller = urlTunneller, _urlTunneller = urlTunneller,
super( super(
<FlutterDevice>[device], <FlutterDevice?>[device],
target: target ?? fileSystem.path.join('lib', 'main.dart'), target: target ?? fileSystem!.path.join('lib', 'main.dart'),
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,
ipv6: ipv6, ipv6: ipv6,
stayResident: stayResident, stayResident: stayResident,
@ -111,25 +109,25 @@ class ResidentWebRunner extends ResidentRunner {
devtoolsHandler: devtoolsHandler, devtoolsHandler: devtoolsHandler,
); );
final FileSystem _fileSystem; final FileSystem? _fileSystem;
final Logger _logger; final Logger? _logger;
final SystemClock _systemClock; final SystemClock _systemClock;
final Usage _usage; final Usage _usage;
final UrlTunneller _urlTunneller; final UrlTunneller? _urlTunneller;
@override @override
Logger get logger => _logger; Logger? get logger => _logger;
@override @override
FileSystem get fileSystem => _fileSystem; FileSystem? get fileSystem => _fileSystem;
FlutterDevice get device => flutterDevices.first; FlutterDevice? get device => flutterDevices.first;
final FlutterProject flutterProject; final FlutterProject flutterProject;
DateTime firstBuildTime; DateTime? firstBuildTime;
// Used with the new compiler to generate a bootstrap file containing plugins // Used with the new compiler to generate a bootstrap file containing plugins
// and platform initialization. // and platform initialization.
Directory _generatedEntrypointDirectory; Directory? _generatedEntrypointDirectory;
// Only the debug builds of the web support the service protocol. // Only the debug builds of the web support the service protocol.
@override @override
@ -139,7 +137,7 @@ class ResidentWebRunner extends ResidentRunner {
bool get debuggingEnabled => isRunningDebug && deviceIsDebuggable; bool get debuggingEnabled => isRunningDebug && deviceIsDebuggable;
/// WebServer device is debuggable when running with --start-paused. /// WebServer device is debuggable when running with --start-paused.
bool get deviceIsDebuggable => device.device is! WebServerDevice || debuggingOptions.startPaused; bool get deviceIsDebuggable => device!.device is! WebServerDevice || debuggingOptions.startPaused;
@override @override
bool get supportsWriteSkSL => false; bool get supportsWriteSkSL => false;
@ -150,24 +148,24 @@ class ResidentWebRunner extends ResidentRunner {
bool get _enableDwds => debuggingEnabled; bool get _enableDwds => debuggingEnabled;
ConnectionResult _connectionResult; ConnectionResult? _connectionResult;
StreamSubscription<vmservice.Event> _stdOutSub; StreamSubscription<vmservice.Event>? _stdOutSub;
StreamSubscription<vmservice.Event> _stdErrSub; StreamSubscription<vmservice.Event>? _stdErrSub;
StreamSubscription<vmservice.Event> _extensionEventSub; StreamSubscription<vmservice.Event>? _extensionEventSub;
bool _exited = false; bool _exited = false;
WipConnection _wipConnection; WipConnection? _wipConnection;
ChromiumLauncher _chromiumLauncher; ChromiumLauncher? _chromiumLauncher;
FlutterVmService get _vmService { FlutterVmService get _vmService {
if (_instance != null) { if (_instance != null) {
return _instance; return _instance!;
} }
final vmservice.VmService service =_connectionResult?.vmService; final vmservice.VmService? service =_connectionResult?.vmService;
final Uri websocketUri = Uri.parse(_connectionResult.debugConnection.uri); final Uri websocketUri = Uri.parse(_connectionResult!.debugConnection!.uri);
final Uri httpUri = _httpUriFromWebsocketUri(websocketUri); final Uri httpUri = _httpUriFromWebsocketUri(websocketUri);
return _instance ??= FlutterVmService(service, wsAddress: websocketUri, httpAddress: httpUri); return _instance ??= FlutterVmService(service!, wsAddress: websocketUri, httpAddress: httpUri);
} }
FlutterVmService _instance; FlutterVmService? _instance;
@override @override
Future<void> cleanupAfterSignal() async { Future<void> cleanupAfterSignal() async {
@ -183,17 +181,17 @@ class ResidentWebRunner extends ResidentRunner {
if (_exited) { if (_exited) {
return; return;
} }
await residentDevtoolsHandler.shutdown(); await residentDevtoolsHandler!.shutdown();
await _stdOutSub?.cancel(); await _stdOutSub?.cancel();
await _stdErrSub?.cancel(); await _stdErrSub?.cancel();
await _extensionEventSub?.cancel(); await _extensionEventSub?.cancel();
await device.device.stopApp(null); await device!.device!.stopApp(null);
try { try {
_generatedEntrypointDirectory?.deleteSync(recursive: true); _generatedEntrypointDirectory?.deleteSync(recursive: true);
} on FileSystemException { } on FileSystemException {
// Best effort to clean up temp dirs. // Best effort to clean up temp dirs.
_logger.printTrace( _logger!.printTrace(
'Failed to clean up temp directory: ${_generatedEntrypointDirectory.path}', 'Failed to clean up temp directory: ${_generatedEntrypointDirectory!.path}',
); );
} }
_exited = true; _exited = true;
@ -212,59 +210,58 @@ class ResidentWebRunner extends ResidentRunner {
const String fire = '🔥'; const String fire = '🔥';
const String rawMessage = const String rawMessage =
' To hot restart changes while running, press "r" or "R".'; ' To hot restart changes while running, press "r" or "R".';
final String message = _logger.terminal.color( final String message = _logger!.terminal.color(
fire + _logger.terminal.bolden(rawMessage), fire + _logger!.terminal.bolden(rawMessage),
TerminalColor.red, TerminalColor.red,
); );
_logger.printStatus(message); _logger!.printStatus(message);
const String quitMessage = 'To quit, press "q".'; const String quitMessage = 'To quit, press "q".';
_logger.printStatus('For a more detailed help message, press "h". $quitMessage'); _logger!.printStatus('For a more detailed help message, press "h". $quitMessage');
_logger.printStatus(''); _logger!.printStatus('');
printDebuggerList(); printDebuggerList();
} }
@override @override
Future<void> stopEchoingDeviceLog() async { Future<void> stopEchoingDeviceLog() async {
// Do nothing for ResidentWebRunner // Do nothing for ResidentWebRunner
await device.stopEchoingDeviceLog(); await device!.stopEchoingDeviceLog();
} }
@override @override
Future<int> run({ Future<int> run({
Completer<DebugConnectionInfo> connectionInfoCompleter, Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void> appStartedCompleter, Completer<void>? appStartedCompleter,
bool enableDevTools = false, // ignored, we don't yet support devtools for web bool enableDevTools = false, // ignored, we don't yet support devtools for web
String route, String? route,
}) async { }) async {
firstBuildTime = DateTime.now(); firstBuildTime = DateTime.now();
final ApplicationPackage package = await ApplicationPackageFactory.instance.getPackageForPlatform( final ApplicationPackage? package = await ApplicationPackageFactory.instance!.getPackageForPlatform(
TargetPlatform.web_javascript, TargetPlatform.web_javascript,
buildInfo: debuggingOptions.buildInfo, buildInfo: debuggingOptions.buildInfo,
applicationBinary: null,
); );
if (package == null) { if (package == null) {
_logger.printStatus('This application is not configured to build on the web.'); _logger!.printStatus('This application is not configured to build on the web.');
_logger.printStatus('To add web support to a project, run `flutter create .`.'); _logger!.printStatus('To add web support to a project, run `flutter create .`.');
} }
final String modeName = debuggingOptions.buildInfo.friendlyModeName; final String modeName = debuggingOptions.buildInfo.friendlyModeName;
_logger.printStatus( _logger!.printStatus(
'Launching ${getDisplayPath(target, _fileSystem)} ' 'Launching ${getDisplayPath(target, _fileSystem!)} '
'on ${device.device.name} in $modeName mode...', 'on ${device!.device!.name} in $modeName mode...',
); );
if (device.device is ChromiumDevice) { if (device!.device is ChromiumDevice) {
_chromiumLauncher = (device.device as ChromiumDevice).chromeLauncher; _chromiumLauncher = (device!.device! as ChromiumDevice).chromeLauncher;
} }
try { try {
return await asyncGuard(() async { return await asyncGuard(() async {
final ExpressionCompiler expressionCompiler = final ExpressionCompiler? expressionCompiler =
debuggingOptions.webEnableExpressionEvaluation debuggingOptions.webEnableExpressionEvaluation
? WebExpressionCompiler(device.generator, fileSystem: _fileSystem) ? WebExpressionCompiler(device!.generator!, fileSystem: _fileSystem)
: null; : null;
device.devFS = WebDevFS( device!.devFS = WebDevFS(
hostname: debuggingOptions.hostname ?? 'localhost', hostname: debuggingOptions.hostname ?? 'localhost',
port: debuggingOptions.port != null port: debuggingOptions.port != null
? int.tryParse(debuggingOptions.port) ? int.tryParse(debuggingOptions.port!)
: null, : null,
packagesFilePath: packagesFilePath, packagesFilePath: packagesFilePath,
urlTunneller: _urlTunneller, urlTunneller: _urlTunneller,
@ -274,22 +271,22 @@ class ResidentWebRunner extends ResidentRunner {
buildInfo: debuggingOptions.buildInfo, buildInfo: debuggingOptions.buildInfo,
enableDwds: _enableDwds, enableDwds: _enableDwds,
enableDds: debuggingOptions.enableDds, enableDds: debuggingOptions.enableDds,
entrypoint: _fileSystem.file(target).uri, entrypoint: _fileSystem!.file(target).uri,
expressionCompiler: expressionCompiler, expressionCompiler: expressionCompiler,
chromiumLauncher: _chromiumLauncher, chromiumLauncher: _chromiumLauncher,
nullAssertions: debuggingOptions.nullAssertions, nullAssertions: debuggingOptions.nullAssertions,
nullSafetyMode: debuggingOptions.buildInfo.nullSafetyMode, nullSafetyMode: debuggingOptions.buildInfo.nullSafetyMode,
nativeNullAssertions: debuggingOptions.nativeNullAssertions, nativeNullAssertions: debuggingOptions.nativeNullAssertions,
); );
final Uri url = await device.devFS.create(); final Uri url = await device!.devFS!.create();
if (debuggingOptions.buildInfo.isDebug) { if (debuggingOptions.buildInfo.isDebug) {
final UpdateFSReport report = await _updateDevFS(fullRestart: true); final UpdateFSReport report = await _updateDevFS(fullRestart: true);
if (!report.success) { if (!report.success) {
_logger.printError('Failed to compile application.'); _logger!.printError('Failed to compile application.');
appFailedToStart(); appFailedToStart();
return 1; return 1;
} }
device.generator.accept(); device!.generator!.accept();
cacheInitialDillCompilation(); cacheInitialDillCompilation();
} else { } else {
await buildWeb( await buildWeb(
@ -304,7 +301,7 @@ class ResidentWebRunner extends ResidentRunner {
null, null,
); );
} }
await device.device.startApp( await device!.device!.startApp(
package, package,
mainPath: target, mainPath: target,
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,
@ -320,19 +317,19 @@ class ResidentWebRunner extends ResidentRunner {
}); });
} on WebSocketException catch (error, stackTrace) { } on WebSocketException catch (error, stackTrace) {
appFailedToStart(); appFailedToStart();
_logger.printError('$error', stackTrace: stackTrace); _logger!.printError('$error', stackTrace: stackTrace);
throwToolExit(kExitMessage); throwToolExit(kExitMessage);
} on ChromeDebugException catch (error, stackTrace) { } on ChromeDebugException catch (error, stackTrace) {
appFailedToStart(); appFailedToStart();
_logger.printError('$error', stackTrace: stackTrace); _logger!.printError('$error', stackTrace: stackTrace);
throwToolExit(kExitMessage); throwToolExit(kExitMessage);
} on AppConnectionException catch (error, stackTrace) { } on AppConnectionException catch (error, stackTrace) {
appFailedToStart(); appFailedToStart();
_logger.printError('$error', stackTrace: stackTrace); _logger!.printError('$error', stackTrace: stackTrace);
throwToolExit(kExitMessage); throwToolExit(kExitMessage);
} on SocketException catch (error, stackTrace) { } on SocketException catch (error, stackTrace) {
appFailedToStart(); appFailedToStart();
_logger.printError('$error', stackTrace: stackTrace); _logger!.printError('$error', stackTrace: stackTrace);
throwToolExit(kExitMessage); throwToolExit(kExitMessage);
} on Exception { } on Exception {
appFailedToStart(); appFailedToStart();
@ -343,12 +340,12 @@ class ResidentWebRunner extends ResidentRunner {
@override @override
Future<OperationResult> restart({ Future<OperationResult> restart({
bool fullRestart = false, bool fullRestart = false,
bool pause = false, bool? pause = false,
String reason, String? reason,
bool benchmarkMode = false, bool benchmarkMode = false,
}) async { }) async {
final DateTime start = _systemClock.now(); final DateTime start = _systemClock.now();
final Status status = _logger.startProgress( final Status status = _logger!.startProgress(
'Performing hot restart...', 'Performing hot restart...',
progressId: 'hot.restart', progressId: 'hot.restart',
); );
@ -358,10 +355,10 @@ class ResidentWebRunner extends ResidentRunner {
// Full restart is always false for web, since the extra recompile is wasteful. // Full restart is always false for web, since the extra recompile is wasteful.
final UpdateFSReport report = await _updateDevFS(); final UpdateFSReport report = await _updateDevFS();
if (report.success) { if (report.success) {
device.generator.accept(); device!.generator!.accept();
} else { } else {
status.stop(); status.stop();
await device.generator.reject(); await device!.generator!.reject();
return OperationResult(1, 'Failed to recompile application.'); return OperationResult(1, 'Failed to recompile application.');
} }
} else { } else {
@ -384,7 +381,7 @@ class ResidentWebRunner extends ResidentRunner {
try { try {
if (!deviceIsDebuggable) { if (!deviceIsDebuggable) {
_logger.printStatus('Recompile complete. Page requires refresh.'); _logger!.printStatus('Recompile complete. Page requires refresh.');
} else if (isRunningDebug) { } else if (isRunningDebug) {
await _vmService.service.callMethod('hotRestart'); await _vmService.service.callMethod('hotRestart');
} else { } else {
@ -402,8 +399,8 @@ class ResidentWebRunner extends ResidentRunner {
final Duration elapsed = _systemClock.now().difference(start); final Duration elapsed = _systemClock.now().difference(start);
final String elapsedMS = getElapsedAsMilliseconds(elapsed); final String elapsedMS = getElapsedAsMilliseconds(elapsed);
_logger.printStatus('Restarted application in $elapsedMS.'); _logger!.printStatus('Restarted application in $elapsedMS.');
unawaited(residentDevtoolsHandler.hotRestart(flutterDevices)); unawaited(residentDevtoolsHandler!.hotRestart(flutterDevices));
// Don't track restart times for dart2js builds or web-server devices. // Don't track restart times for dart2js builds or web-server devices.
if (debuggingOptions.buildInfo.isDebug && deviceIsDebuggable) { if (debuggingOptions.buildInfo.isDebug && deviceIsDebuggable) {
@ -411,7 +408,7 @@ class ResidentWebRunner extends ResidentRunner {
HotEvent( HotEvent(
'restart', 'restart',
targetPlatform: getNameForTargetPlatform(TargetPlatform.web_javascript), targetPlatform: getNameForTargetPlatform(TargetPlatform.web_javascript),
sdkName: await device.device.sdkNameAndVersion, sdkName: await device!.device!.sdkNameAndVersion,
emulator: false, emulator: false,
fullRestart: true, fullRestart: true,
reason: reason, reason: reason,
@ -425,34 +422,34 @@ class ResidentWebRunner extends ResidentRunner {
// Flutter web projects need to include a generated main entrypoint to call the // Flutter web projects need to include a generated main entrypoint to call the
// appropriate bootstrap method and inject plugins. // appropriate bootstrap method and inject plugins.
// Keep this in sync with build_system/targets/web.dart. // Keep this in sync with build_system/targets/web.dart.
Future<Uri> _generateEntrypoint(Uri mainUri, PackageConfig packageConfig) async { Future<Uri> _generateEntrypoint(Uri mainUri, PackageConfig? packageConfig) async {
File result = _generatedEntrypointDirectory?.childFile('web_entrypoint.dart'); File? result = _generatedEntrypointDirectory?.childFile('web_entrypoint.dart');
if (_generatedEntrypointDirectory == null) { if (_generatedEntrypointDirectory == null) {
_generatedEntrypointDirectory ??= _fileSystem.systemTempDirectory.createTempSync('flutter_tools.') _generatedEntrypointDirectory ??= _fileSystem!.systemTempDirectory.createTempSync('flutter_tools.')
..createSync(); ..createSync();
result = _generatedEntrypointDirectory.childFile('web_entrypoint.dart'); result = _generatedEntrypointDirectory!.childFile('web_entrypoint.dart');
// Generates the generated_plugin_registrar // Generates the generated_plugin_registrar
await injectBuildTimePluginFiles(flutterProject, webPlatform: true, destination: _generatedEntrypointDirectory); await injectBuildTimePluginFiles(flutterProject, webPlatform: true, destination: _generatedEntrypointDirectory!);
// The below works because `injectBuildTimePluginFiles` is configured to write // The below works because `injectBuildTimePluginFiles` is configured to write
// the web_plugin_registrant.dart file alongside the generated main.dart // the web_plugin_registrant.dart file alongside the generated main.dart
const String/*?*/ generatedImport = 'web_plugin_registrant.dart'; const String generatedImport = 'web_plugin_registrant.dart';
Uri importedEntrypoint = packageConfig.toPackageUri(mainUri); Uri? importedEntrypoint = packageConfig!.toPackageUri(mainUri);
// Special handling for entrypoints that are not under lib, such as test scripts. // Special handling for entrypoints that are not under lib, such as test scripts.
if (importedEntrypoint == null) { if (importedEntrypoint == null) {
final String parent = _fileSystem.file(mainUri).parent.path; final String parent = _fileSystem!.file(mainUri).parent.path;
flutterDevices.first.generator.addFileSystemRoot(parent); flutterDevices.first!.generator!.addFileSystemRoot(parent);
flutterDevices.first.generator.addFileSystemRoot(_fileSystem.directory('test').absolute.path); flutterDevices.first!.generator!.addFileSystemRoot(_fileSystem!.directory('test').absolute.path);
importedEntrypoint = Uri( importedEntrypoint = Uri(
scheme: 'org-dartlang-app', scheme: 'org-dartlang-app',
path: '/${mainUri.pathSegments.last}', path: '/${mainUri.pathSegments.last}',
); );
} }
final LanguageVersion languageVersion = determineLanguageVersion( final LanguageVersion languageVersion = determineLanguageVersion(
_fileSystem.file(mainUri), _fileSystem!.file(mainUri),
packageConfig[flutterProject.manifest.appName], packageConfig[flutterProject.manifest.appName],
Cache.flutterRoot, Cache.flutterRoot!,
); );
final String entrypoint = main_dart.generateMainDartFile(importedEntrypoint.toString(), final String entrypoint = main_dart.generateMainDartFile(importedEntrypoint.toString(),
@ -462,14 +459,14 @@ class ResidentWebRunner extends ResidentRunner {
result.writeAsStringSync(entrypoint); result.writeAsStringSync(entrypoint);
} }
return result.absolute.uri; return result!.absolute.uri;
} }
Future<UpdateFSReport> _updateDevFS({bool fullRestart = false}) async { Future<UpdateFSReport> _updateDevFS({bool fullRestart = false}) async {
final bool isFirstUpload = !assetBundle.wasBuiltOnce(); final bool isFirstUpload = !assetBundle.wasBuiltOnce();
final bool rebuildBundle = assetBundle.needsBuild(); final bool rebuildBundle = assetBundle.needsBuild();
if (rebuildBundle) { if (rebuildBundle) {
_logger.printTrace('Updating assets'); _logger!.printTrace('Updating assets');
final int result = await assetBundle.build( final int result = await assetBundle.build(
packagesPath: debuggingOptions.buildInfo.packagesPath, packagesPath: debuggingOptions.buildInfo.packagesPath,
targetPlatform: TargetPlatform.web_javascript, targetPlatform: TargetPlatform.web_javascript,
@ -479,67 +476,66 @@ class ResidentWebRunner extends ResidentRunner {
} }
} }
final InvalidationResult invalidationResult = await projectFileInvalidator.findInvalidated( final InvalidationResult invalidationResult = await projectFileInvalidator.findInvalidated(
lastCompiled: device.devFS.lastCompiled, lastCompiled: device!.devFS!.lastCompiled,
urisToMonitor: device.devFS.sources, urisToMonitor: device!.devFS!.sources,
packagesPath: packagesFilePath, packagesPath: packagesFilePath,
packageConfig: device.devFS.lastPackageConfig packageConfig: device!.devFS!.lastPackageConfig
?? debuggingOptions.buildInfo.packageConfig, ?? debuggingOptions.buildInfo.packageConfig,
); );
final Status devFSStatus = _logger.startProgress( final Status devFSStatus = _logger!.startProgress(
'Waiting for connection from debug service on ${device.device.name}...', 'Waiting for connection from debug service on ${device!.device!.name}...',
); );
final UpdateFSReport report = await device.devFS.update( final UpdateFSReport report = await device!.devFS!.update(
mainUri: await _generateEntrypoint( mainUri: await _generateEntrypoint(
_fileSystem.file(mainPath).absolute.uri, _fileSystem!.file(mainPath).absolute.uri,
invalidationResult.packageConfig, invalidationResult.packageConfig,
), ),
target: target, target: target,
bundle: assetBundle, bundle: assetBundle,
firstBuildTime: firstBuildTime, firstBuildTime: firstBuildTime,
bundleFirstUpload: isFirstUpload, bundleFirstUpload: isFirstUpload,
generator: device.generator, generator: device!.generator!,
fullRestart: fullRestart, fullRestart: fullRestart,
dillOutputPath: dillOutputPath, dillOutputPath: dillOutputPath,
projectRootPath: projectRootPath, projectRootPath: projectRootPath,
pathToReload: getReloadPath(fullRestart: fullRestart, swap: false), pathToReload: getReloadPath(fullRestart: fullRestart, swap: false),
invalidatedFiles: invalidationResult.uris, invalidatedFiles: invalidationResult.uris!,
packageConfig: invalidationResult.packageConfig, packageConfig: invalidationResult.packageConfig!,
trackWidgetCreation: debuggingOptions.buildInfo.trackWidgetCreation, trackWidgetCreation: debuggingOptions.buildInfo.trackWidgetCreation,
devFSWriter: null,
); );
devFSStatus.stop(); devFSStatus.stop();
_logger.printTrace('Synced ${getSizeAsMB(report.syncedBytes)}.'); _logger!.printTrace('Synced ${getSizeAsMB(report.syncedBytes)}.');
return report; return report;
} }
@override @override
Future<int> attach({ Future<int> attach({
Completer<DebugConnectionInfo> connectionInfoCompleter, Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void> appStartedCompleter, Completer<void>? appStartedCompleter,
bool allowExistingDdsInstance = false, bool allowExistingDdsInstance = false,
bool enableDevTools = false, // ignored, we don't yet support devtools for web bool enableDevTools = false, // ignored, we don't yet support devtools for web
bool needsFullRestart = true, bool needsFullRestart = true,
}) async { }) async {
if (_chromiumLauncher != null) { if (_chromiumLauncher != null) {
final Chromium chrome = await _chromiumLauncher.connectedInstance; final Chromium chrome = await _chromiumLauncher!.connectedInstance;
final ChromeTab chromeTab = await chrome.chromeConnection.getTab((ChromeTab chromeTab) { final ChromeTab chromeTab = await (chrome.chromeConnection.getTab((ChromeTab chromeTab) {
return !chromeTab.url.startsWith('chrome-extension'); return !chromeTab.url.startsWith('chrome-extension');
}); }) as FutureOr<ChromeTab>);
if (chromeTab == null) { if (chromeTab == null) {
throwToolExit('Failed to connect to Chrome instance.'); throwToolExit('Failed to connect to Chrome instance.');
} }
_wipConnection = await chromeTab.connect(); _wipConnection = await chromeTab.connect();
} }
Uri websocketUri; Uri? websocketUri;
if (supportsServiceProtocol) { if (supportsServiceProtocol) {
final WebDevFS webDevFS = device.devFS as WebDevFS; final WebDevFS webDevFS = device!.devFS! as WebDevFS;
final bool useDebugExtension = device.device is WebServerDevice && debuggingOptions.startPaused; final bool useDebugExtension = device!.device is WebServerDevice && debuggingOptions.startPaused;
_connectionResult = await webDevFS.connect(useDebugExtension); _connectionResult = await webDevFS.connect(useDebugExtension);
unawaited(_connectionResult.debugConnection.onDone.whenComplete(_cleanupAndExit)); unawaited(_connectionResult!.debugConnection!.onDone.whenComplete(_cleanupAndExit));
void onLogEvent(vmservice.Event event) { void onLogEvent(vmservice.Event event) {
final String message = processVmServiceMessage(event); final String message = processVmServiceMessage(event);
_logger.printStatus(message); _logger!.printStatus(message);
} }
_stdOutSub = _vmService.service.onStdoutEvent.listen(onLogEvent); _stdOutSub = _vmService.service.onStdoutEvent.listen(onLogEvent);
@ -564,41 +560,41 @@ class ResidentWebRunner extends ResidentRunner {
} }
await setUpVmService( await setUpVmService(
(String isolateId, { (String isolateId, {
bool force, bool? force,
bool pause, bool? pause,
}) async { }) async {
await restart(pause: pause); await restart(pause: pause);
}, },
null, null,
null, null,
device.device, device!.device,
null, null,
printStructuredErrorLog, printStructuredErrorLog,
_vmService.service, _vmService.service,
); );
websocketUri = Uri.parse(_connectionResult.debugConnection.uri); websocketUri = Uri.parse(_connectionResult!.debugConnection!.uri);
device.vmService = _vmService; device!.vmService = _vmService;
// Run main immediately if the app is not started paused or if there // Run main immediately if the app is not started paused or if there
// is no debugger attached. Otherwise, runMain when a resume event // is no debugger attached. Otherwise, runMain when a resume event
// is received. // is received.
if (!debuggingOptions.startPaused || !supportsServiceProtocol) { if (!debuggingOptions.startPaused || !supportsServiceProtocol) {
_connectionResult.appConnection.runMain(); _connectionResult!.appConnection!.runMain();
} else { } else {
StreamSubscription<void> resumeSub; late StreamSubscription<void> resumeSub;
resumeSub = _vmService.service.onDebugEvent resumeSub = _vmService.service.onDebugEvent
.listen((vmservice.Event event) { .listen((vmservice.Event event) {
if (event.type == vmservice.EventKind.kResume) { if (event.type == vmservice.EventKind.kResume) {
_connectionResult.appConnection.runMain(); _connectionResult!.appConnection!.runMain();
resumeSub.cancel(); resumeSub.cancel();
} }
}); });
} }
if (enableDevTools) { if (enableDevTools) {
// The method below is guaranteed never to return a failing future. // The method below is guaranteed never to return a failing future.
unawaited(residentDevtoolsHandler.serveAndAnnounceDevTools( unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
devToolsServerAddress: debuggingOptions.devToolsServerAddress, devToolsServerAddress: debuggingOptions.devToolsServerAddress,
flutterDevices: flutterDevices, flutterDevices: flutterDevices,
)); ));
@ -606,20 +602,20 @@ class ResidentWebRunner extends ResidentRunner {
} }
if (websocketUri != null) { if (websocketUri != null) {
if (debuggingOptions.vmserviceOutFile != null) { if (debuggingOptions.vmserviceOutFile != null) {
_fileSystem.file(debuggingOptions.vmserviceOutFile) _fileSystem!.file(debuggingOptions.vmserviceOutFile)
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync(websocketUri.toString()); ..writeAsStringSync(websocketUri.toString());
} }
_logger.printStatus('Debug service listening on $websocketUri'); _logger!.printStatus('Debug service listening on $websocketUri');
_logger.printStatus(''); _logger!.printStatus('');
if (debuggingOptions.buildInfo.nullSafetyMode == NullSafetyMode.sound) { if (debuggingOptions.buildInfo.nullSafetyMode == NullSafetyMode.sound) {
_logger.printStatus('💪 Running with sound null safety 💪', emphasis: true); _logger!.printStatus('💪 Running with sound null safety 💪', emphasis: true);
} else { } else {
_logger.printStatus( _logger!.printStatus(
'Running with unsound null safety', 'Running with unsound null safety',
emphasis: true, emphasis: true,
); );
_logger.printStatus( _logger!.printStatus(
'For more information see https://dart.dev/null-safety/unsound-null-safety', 'For more information see https://dart.dev/null-safety/unsound-null-safety',
); );
} }
@ -638,7 +634,7 @@ class ResidentWebRunner extends ResidentRunner {
@override @override
Future<void> exitApp() async { Future<void> exitApp() async {
await device.exitApps(); await device!.exitApps();
appFinished(); appFinished();
} }
} }

View File

@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
// ignore: import_of_legacy_library_into_null_safe
import 'package:dwds/dwds.dart'; import 'package:dwds/dwds.dart';
import '../artifacts.dart'; import '../artifacts.dart';
@ -17,12 +16,12 @@ class SdkWebConfigurationProvider extends SdkConfigurationProvider {
SdkWebConfigurationProvider(this._artifacts); SdkWebConfigurationProvider(this._artifacts);
final Artifacts _artifacts; final Artifacts _artifacts;
SdkConfiguration _configuration; SdkConfiguration? _configuration;
/// Create and validate configuration matching the default SDK layout. /// Create and validate configuration matching the default SDK layout.
/// Create configuration matching the default SDK layout. /// Create configuration matching the default SDK layout.
@override @override
Future<SdkConfiguration> get configuration async { Future<SdkConfiguration?> get configuration async {
if (_configuration == null) { if (_configuration == null) {
final String sdkDir = _artifacts.getHostArtifact(HostArtifact.flutterWebSdk).path; final String sdkDir = _artifacts.getHostArtifact(HostArtifact.flutterWebSdk).path;
final String unsoundSdkSummaryPath = _artifacts.getHostArtifact(HostArtifact.webPlatformKernelDill).path; final String unsoundSdkSummaryPath = _artifacts.getHostArtifact(HostArtifact.webPlatformKernelDill).path;
@ -40,7 +39,7 @@ class SdkWebConfigurationProvider extends SdkConfigurationProvider {
} }
/// Validate that SDK configuration exists on disk. /// Validate that SDK configuration exists on disk.
static void validate(SdkConfiguration configuration, { FileSystem fileSystem }) { static void validate(SdkConfiguration configuration, { required FileSystem fileSystem }) {
configuration.validateSdkDir(fileSystem: fileSystem); configuration.validateSdkDir(fileSystem: fileSystem);
configuration.validateSummaries(fileSystem: fileSystem); configuration.validateSummaries(fileSystem: fileSystem);
configuration.validateLibrariesSpec(fileSystem: fileSystem); configuration.validateLibrariesSpec(fileSystem: fileSystem);

View File

@ -181,7 +181,7 @@ class PreviewDevice extends Device {
} }
@override @override
DevFSWriter createDevFSWriter(covariant ApplicationPackage app, String userIdentifier) { DevFSWriter createDevFSWriter(covariant ApplicationPackage? app, String? userIdentifier) {
return LocalDevFSWriter(fileSystem: _fileSystem); return LocalDevFSWriter(fileSystem: _fileSystem);
} }
} }

View File

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'package:browser_launcher/browser_launcher.dart'; import 'package:browser_launcher/browser_launcher.dart';
@ -14,9 +12,9 @@ import 'build_info.dart';
import 'resident_runner.dart'; import 'resident_runner.dart';
import 'vmservice.dart'; import 'vmservice.dart';
typedef ResidentDevtoolsHandlerFactory = ResidentDevtoolsHandler Function(DevtoolsLauncher, ResidentRunner, Logger); typedef ResidentDevtoolsHandlerFactory = ResidentDevtoolsHandler Function(DevtoolsLauncher?, ResidentRunner, Logger);
ResidentDevtoolsHandler createDefaultHandler(DevtoolsLauncher launcher, ResidentRunner runner, Logger logger) { ResidentDevtoolsHandler createDefaultHandler(DevtoolsLauncher? launcher, ResidentRunner runner, Logger logger) {
return FlutterResidentDevtoolsHandler(launcher, runner, logger); return FlutterResidentDevtoolsHandler(launcher, runner, logger);
} }
@ -24,7 +22,7 @@ ResidentDevtoolsHandler createDefaultHandler(DevtoolsLauncher launcher, Resident
/// the resident runner. /// the resident runner.
abstract class ResidentDevtoolsHandler { abstract class ResidentDevtoolsHandler {
/// The current devtools server, or null if one is not running. /// The current devtools server, or null if one is not running.
DevToolsServerAddress get activeDevToolsServer; DevToolsServerAddress? get activeDevToolsServer;
/// Whether it's ok to announce the [activeDevToolsServer]. /// Whether it's ok to announce the [activeDevToolsServer].
/// ///
@ -32,14 +30,14 @@ abstract class ResidentDevtoolsHandler {
/// of the DevTools. /// of the DevTools.
bool get readyToAnnounce; bool get readyToAnnounce;
Future<void> hotRestart(List<FlutterDevice> flutterDevices); Future<void> hotRestart(List<FlutterDevice?> flutterDevices);
Future<void> serveAndAnnounceDevTools({ Future<void> serveAndAnnounceDevTools({
Uri devToolsServerAddress, Uri? devToolsServerAddress,
@required List<FlutterDevice> flutterDevices, required List<FlutterDevice?> flutterDevices,
}); });
bool launchDevToolsInBrowser({@required List<FlutterDevice> flutterDevices}); bool launchDevToolsInBrowser({required List<FlutterDevice?> flutterDevices});
Future<void> shutdown(); Future<void> shutdown();
} }
@ -49,7 +47,7 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
static const Duration launchInBrowserTimeout = Duration(seconds: 15); static const Duration launchInBrowserTimeout = Duration(seconds: 15);
final DevtoolsLauncher _devToolsLauncher; final DevtoolsLauncher? _devToolsLauncher;
final ResidentRunner _residentRunner; final ResidentRunner _residentRunner;
final Logger _logger; final Logger _logger;
bool _shutdown = false; bool _shutdown = false;
@ -59,7 +57,7 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
bool launchedInBrowser = false; bool launchedInBrowser = false;
@override @override
DevToolsServerAddress get activeDevToolsServer { DevToolsServerAddress? get activeDevToolsServer {
assert(!_readyToAnnounce || _devToolsLauncher?.activeDevToolsServer != null); assert(!_readyToAnnounce || _devToolsLauncher?.activeDevToolsServer != null);
return _devToolsLauncher?.activeDevToolsServer; return _devToolsLauncher?.activeDevToolsServer;
} }
@ -71,26 +69,26 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
// This must be guaranteed not to return a Future that fails. // This must be guaranteed not to return a Future that fails.
@override @override
Future<void> serveAndAnnounceDevTools({ Future<void> serveAndAnnounceDevTools({
Uri devToolsServerAddress, Uri? devToolsServerAddress,
@required List<FlutterDevice> flutterDevices, required List<FlutterDevice?> flutterDevices,
}) async { }) async {
assert(!_readyToAnnounce); assert(!_readyToAnnounce);
if (!_residentRunner.supportsServiceProtocol || _devToolsLauncher == null) { if (!_residentRunner.supportsServiceProtocol || _devToolsLauncher == null) {
return; return;
} }
if (devToolsServerAddress != null) { if (devToolsServerAddress != null) {
_devToolsLauncher.devToolsUrl = devToolsServerAddress; _devToolsLauncher!.devToolsUrl = devToolsServerAddress;
} else { } else {
await _devToolsLauncher.serve(); await _devToolsLauncher!.serve();
_served = true; _served = true;
} }
await _devToolsLauncher.ready; await _devToolsLauncher!.ready;
// Do not attempt to print debugger list if the connection has failed or if we're shutting down. // Do not attempt to print debugger list if the connection has failed or if we're shutting down.
if (_devToolsLauncher.activeDevToolsServer == null || _shutdown) { if (_devToolsLauncher!.activeDevToolsServer == null || _shutdown) {
assert(!_readyToAnnounce); assert(!_readyToAnnounce);
return; return;
} }
final List<FlutterDevice> devicesWithExtension = await _devicesWithExtensions(flutterDevices); final List<FlutterDevice?> devicesWithExtension = await _devicesWithExtensions(flutterDevices);
await _maybeCallDevToolsUriServiceExtension(devicesWithExtension); await _maybeCallDevToolsUriServiceExtension(devicesWithExtension);
await _callConnectedVmServiceUriExtension(devicesWithExtension); await _callConnectedVmServiceUriExtension(devicesWithExtension);
if (_shutdown) { if (_shutdown) {
@ -98,7 +96,7 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
return; return;
} }
_readyToAnnounce = true; _readyToAnnounce = true;
assert(_devToolsLauncher.activeDevToolsServer != null); assert(_devToolsLauncher!.activeDevToolsServer != null);
if (_residentRunner.reportedDebuggers) { if (_residentRunner.reportedDebuggers) {
// Since the DevTools only just became available, we haven't had a chance to // Since the DevTools only just became available, we haven't had a chance to
// report their URLs yet. Do so now. // report their URLs yet. Do so now.
@ -108,13 +106,13 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
// This must be guaranteed not to return a Future that fails. // This must be guaranteed not to return a Future that fails.
@override @override
bool launchDevToolsInBrowser({@required List<FlutterDevice> flutterDevices}) { bool launchDevToolsInBrowser({required List<FlutterDevice?> flutterDevices}) {
if (!_residentRunner.supportsServiceProtocol || _devToolsLauncher == null) { if (!_residentRunner.supportsServiceProtocol || _devToolsLauncher == null) {
return false; return false;
} }
if (_devToolsLauncher.devToolsUrl == null) { if (_devToolsLauncher!.devToolsUrl == null) {
_logger.startProgress('Waiting for Flutter DevTools to be served...'); _logger.startProgress('Waiting for Flutter DevTools to be served...');
unawaited(_devToolsLauncher.ready.then((_) { unawaited(_devToolsLauncher!.ready.then((_) {
_launchDevToolsForDevices(flutterDevices); _launchDevToolsForDevices(flutterDevices);
})); }));
} else { } else {
@ -123,27 +121,27 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
return true; return true;
} }
void _launchDevToolsForDevices(List<FlutterDevice> flutterDevices) { void _launchDevToolsForDevices(List<FlutterDevice?> flutterDevices) {
assert(activeDevToolsServer != null); assert(activeDevToolsServer != null);
for (final FlutterDevice device in flutterDevices) { for (final FlutterDevice? device in flutterDevices) {
final String devToolsUrl = activeDevToolsServer.uri?.replace( final String devToolsUrl = activeDevToolsServer!.uri!.replace(
queryParameters: <String, dynamic>{'uri': '${device.vmService.httpAddress}'}, queryParameters: <String, dynamic>{'uri': '${device!.vmService!.httpAddress}'},
).toString(); ).toString();
_logger.printStatus('Launching Flutter DevTools for ${device.device.name} at $devToolsUrl'); _logger.printStatus('Launching Flutter DevTools for ${device.device!.name} at $devToolsUrl');
unawaited(Chrome.start(<String>[devToolsUrl])); unawaited(Chrome.start(<String>[devToolsUrl]));
} }
launchedInBrowser = true; launchedInBrowser = true;
} }
Future<void> _maybeCallDevToolsUriServiceExtension( Future<void> _maybeCallDevToolsUriServiceExtension(
List<FlutterDevice> flutterDevices, List<FlutterDevice?> flutterDevices,
) async { ) async {
if (_devToolsLauncher?.activeDevToolsServer == null) { if (_devToolsLauncher?.activeDevToolsServer == null) {
return; return;
} }
await Future.wait(<Future<void>>[ await Future.wait(<Future<void>>[
for (final FlutterDevice device in flutterDevices) for (final FlutterDevice? device in flutterDevices)
if (device.vmService != null) _callDevToolsUriExtension(device), if (device?.vmService != null) _callDevToolsUriExtension(device!),
]); ]);
} }
@ -155,7 +153,7 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
'ext.flutter.activeDevToolsServerAddress', 'ext.flutter.activeDevToolsServerAddress',
device: device, device: device,
params: <String, dynamic>{ params: <String, dynamic>{
'value': _devToolsLauncher.activeDevToolsServer.uri.toString(), 'value': _devToolsLauncher!.activeDevToolsServer!.uri.toString(),
}, },
); );
} on Exception catch (e) { } on Exception catch (e) {
@ -166,15 +164,14 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
} }
} }
Future<List<FlutterDevice>> _devicesWithExtensions(List<FlutterDevice> flutterDevices) async { Future<List<FlutterDevice?>> _devicesWithExtensions(List<FlutterDevice?> flutterDevices) async {
final List<FlutterDevice> devices = await Future.wait(<Future<FlutterDevice>>[ return Future.wait(<Future<FlutterDevice?>>[
for (final FlutterDevice device in flutterDevices) _waitForExtensionsForDevice(device), for (final FlutterDevice? device in flutterDevices) _waitForExtensionsForDevice(device!),
]); ]);
return devices.where((FlutterDevice device) => device != null).toList();
} }
/// Returns null if the service extension cannot be found on the device. /// Returns null if the service extension cannot be found on the device.
Future<FlutterDevice> _waitForExtensionsForDevice(FlutterDevice flutterDevice) async { Future<FlutterDevice?> _waitForExtensionsForDevice(FlutterDevice flutterDevice) async {
const String extension = 'ext.flutter.connectedVmServiceUri'; const String extension = 'ext.flutter.connectedVmServiceUri';
try { try {
await flutterDevice.vmService?.findExtensionIsolate( await flutterDevice.vmService?.findExtensionIsolate(
@ -191,15 +188,15 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
} }
} }
Future<void> _callConnectedVmServiceUriExtension(List<FlutterDevice> flutterDevices) async { Future<void> _callConnectedVmServiceUriExtension(List<FlutterDevice?> flutterDevices) async {
await Future.wait(<Future<void>>[ await Future.wait(<Future<void>>[
for (final FlutterDevice device in flutterDevices) for (final FlutterDevice? device in flutterDevices)
if (device.vmService != null) _callConnectedVmServiceExtension(device), if (device?.vmService != null) _callConnectedVmServiceExtension(device!),
]); ]);
} }
Future<void> _callConnectedVmServiceExtension(FlutterDevice device) async { Future<void> _callConnectedVmServiceExtension(FlutterDevice device) async {
final Uri uri = device.vmService.httpAddress ?? device.vmService.wsAddress; final Uri? uri = device.vmService!.httpAddress ?? device.vmService!.wsAddress;
if (uri == null) { if (uri == null) {
return; return;
} }
@ -222,29 +219,30 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
Future<void> _invokeRpcOnFirstView( Future<void> _invokeRpcOnFirstView(
String method, { String method, {
@required FlutterDevice device, required FlutterDevice device,
@required Map<String, dynamic> params, required Map<String, dynamic> params,
}) async { }) async {
if (device.targetPlatform == TargetPlatform.web_javascript) { if (device.targetPlatform == TargetPlatform.web_javascript) {
return device.vmService.callMethodWrapper( await device.vmService!.callMethodWrapper(
method, method,
args: params, args: params,
); );
return;
} }
final List<FlutterView> views = await device.vmService.getFlutterViews(); final List<FlutterView> views = await device.vmService!.getFlutterViews();
if (views.isEmpty) { if (views.isEmpty) {
return; return;
} }
await device.vmService.invokeFlutterExtensionRpcRaw( await device.vmService!.invokeFlutterExtensionRpcRaw(
method, method,
args: params, args: params,
isolateId: views.first.uiIsolate.id, isolateId: views.first.uiIsolate!.id!,
); );
} }
@override @override
Future<void> hotRestart(List<FlutterDevice> flutterDevices) async { Future<void> hotRestart(List<FlutterDevice?> flutterDevices) async {
final List<FlutterDevice> devicesWithExtension = await _devicesWithExtensions(flutterDevices); final List<FlutterDevice?> devicesWithExtension = await _devicesWithExtensions(flutterDevices);
await Future.wait(<Future<void>>[ await Future.wait(<Future<void>>[
_maybeCallDevToolsUriServiceExtension(devicesWithExtension), _maybeCallDevToolsUriServiceExtension(devicesWithExtension),
_callConnectedVmServiceUriExtension(devicesWithExtension), _callConnectedVmServiceUriExtension(devicesWithExtension),
@ -258,12 +256,12 @@ class FlutterResidentDevtoolsHandler implements ResidentDevtoolsHandler {
} }
_shutdown = true; _shutdown = true;
_readyToAnnounce = false; _readyToAnnounce = false;
await _devToolsLauncher.close(); await _devToolsLauncher!.close();
} }
} }
@visibleForTesting @visibleForTesting
NoOpDevtoolsHandler createNoOpHandler(DevtoolsLauncher launcher, ResidentRunner runner, Logger logger) { NoOpDevtoolsHandler createNoOpHandler(DevtoolsLauncher? launcher, ResidentRunner runner, Logger logger) {
return NoOpDevtoolsHandler(); return NoOpDevtoolsHandler();
} }
@ -272,23 +270,23 @@ class NoOpDevtoolsHandler implements ResidentDevtoolsHandler {
bool wasShutdown = false; bool wasShutdown = false;
@override @override
DevToolsServerAddress get activeDevToolsServer => null; DevToolsServerAddress? get activeDevToolsServer => null;
@override @override
bool get readyToAnnounce => false; bool get readyToAnnounce => false;
@override @override
Future<void> hotRestart(List<FlutterDevice> flutterDevices) async { Future<void> hotRestart(List<FlutterDevice?> flutterDevices) async {
return; return;
} }
@override @override
Future<void> serveAndAnnounceDevTools({Uri devToolsServerAddress, List<FlutterDevice> flutterDevices}) async { Future<void> serveAndAnnounceDevTools({Uri? devToolsServerAddress, List<FlutterDevice?>? flutterDevices}) async {
return; return;
} }
@override @override
bool launchDevToolsInBrowser({List<FlutterDevice> flutterDevices}) { bool launchDevToolsInBrowser({List<FlutterDevice?>? flutterDevices}) {
return false; return false;
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,18 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'package:meta/meta.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/logger.dart'; import 'base/logger.dart';
import 'build_info.dart'; import 'build_info.dart';
import 'device.dart';
import 'globals.dart' as globals; import 'globals.dart' as globals;
import 'resident_devtools_handler.dart';
import 'resident_runner.dart'; import 'resident_runner.dart';
import 'tracing.dart'; import 'tracing.dart';
import 'vmservice.dart'; import 'vmservice.dart';
@ -21,31 +15,24 @@ import 'vmservice.dart';
const String kFlutterTestOutputsDirEnvName = 'FLUTTER_TEST_OUTPUTS_DIR'; const String kFlutterTestOutputsDirEnvName = 'FLUTTER_TEST_OUTPUTS_DIR';
class ColdRunner extends ResidentRunner { class ColdRunner extends ResidentRunner {
ColdRunner( ColdRunner(
List<FlutterDevice> devices, { super.devices, {
@required String target, required super.target,
@required DebuggingOptions debuggingOptions, required super.debuggingOptions,
this.traceStartup = false, this.traceStartup = false,
this.awaitFirstFrameWhenTracing = true, this.awaitFirstFrameWhenTracing = true,
this.applicationBinary, this.applicationBinary,
this.multidexEnabled = false, this.multidexEnabled = false,
bool ipv6 = false, bool super.ipv6 = false,
bool stayResident = true, super.stayResident,
bool machine = false, super.machine,
ResidentDevtoolsHandlerFactory devtoolsHandler = createDefaultHandler, super.devtoolsHandler,
}) : super( }) : super(
devices,
target: target,
debuggingOptions: debuggingOptions,
hotMode: false, hotMode: false,
stayResident: stayResident,
ipv6: ipv6,
machine: machine,
devtoolsHandler: devtoolsHandler,
); );
final bool traceStartup; final bool traceStartup;
final bool awaitFirstFrameWhenTracing; final bool awaitFirstFrameWhenTracing;
final File applicationBinary; final File? applicationBinary;
final bool multidexEnabled; final bool multidexEnabled;
bool _didAttach = false; bool _didAttach = false;
@ -60,14 +47,14 @@ class ColdRunner extends ResidentRunner {
@override @override
Future<int> run({ Future<int> run({
Completer<DebugConnectionInfo> connectionInfoCompleter, Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void> appStartedCompleter, Completer<void>? appStartedCompleter,
bool enableDevTools = false, bool enableDevTools = false,
String route, String? route,
}) async { }) async {
try { try {
for (final FlutterDevice device in flutterDevices) { for (final FlutterDevice? device in flutterDevices) {
final int result = await device.runCold( final int result = await device!.runCold(
coldRunner: this, coldRunner: this,
route: route, route: route,
); );
@ -95,38 +82,38 @@ class ColdRunner extends ResidentRunner {
if (enableDevTools && debuggingEnabled) { if (enableDevTools && debuggingEnabled) {
// The method below is guaranteed never to return a failing future. // The method below is guaranteed never to return a failing future.
unawaited(residentDevtoolsHandler.serveAndAnnounceDevTools( unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
devToolsServerAddress: debuggingOptions.devToolsServerAddress, devToolsServerAddress: debuggingOptions.devToolsServerAddress,
flutterDevices: flutterDevices, flutterDevices: flutterDevices,
)); ));
} }
if (flutterDevices.first.observatoryUris != null) { if (flutterDevices.first!.observatoryUris != null) {
// For now, only support one debugger connection. // For now, only support one debugger connection.
connectionInfoCompleter?.complete(DebugConnectionInfo( connectionInfoCompleter?.complete(DebugConnectionInfo(
httpUri: flutterDevices.first.vmService.httpAddress, httpUri: flutterDevices.first!.vmService!.httpAddress,
wsUri: flutterDevices.first.vmService.wsAddress, wsUri: flutterDevices.first!.vmService!.wsAddress,
)); ));
} }
globals.printTrace('Application running.'); globals.printTrace('Application running.');
for (final FlutterDevice device in flutterDevices) { for (final FlutterDevice? device in flutterDevices) {
if (device.vmService == null) { if (device!.vmService == null) {
continue; continue;
} }
await device.initLogReader(); await device.initLogReader();
globals.printTrace('Connected to ${device.device.name}'); globals.printTrace('Connected to ${device.device!.name}');
} }
if (traceStartup) { if (traceStartup) {
// Only trace startup for the first device. // Only trace startup for the first device.
final FlutterDevice device = flutterDevices.first; final FlutterDevice device = flutterDevices.first!;
if (device.vmService != null) { if (device.vmService != null) {
globals.printStatus('Tracing startup on ${device.device.name}.'); globals.printStatus('Tracing startup on ${device.device!.name}.');
final String outputPath = globals.platform.environment[kFlutterTestOutputsDirEnvName] ?? getBuildDirectory(); final String outputPath = globals.platform.environment[kFlutterTestOutputsDirEnvName] ?? getBuildDirectory();
await downloadStartupTrace( await downloadStartupTrace(
device.vmService, device.vmService!,
awaitFirstFrame: awaitFirstFrameWhenTracing, awaitFirstFrame: awaitFirstFrameWhenTracing,
logger: globals.logger, logger: globals.logger,
output: globals.fs.directory(outputPath), output: globals.fs.directory(outputPath),
@ -148,8 +135,8 @@ class ColdRunner extends ResidentRunner {
@override @override
Future<int> attach({ Future<int> attach({
Completer<DebugConnectionInfo> connectionInfoCompleter, Completer<DebugConnectionInfo>? connectionInfoCompleter,
Completer<void> appStartedCompleter, Completer<void>? appStartedCompleter,
bool allowExistingDdsInstance = false, bool allowExistingDdsInstance = false,
bool enableDevTools = false, bool enableDevTools = false,
bool needsFullRestart = true, bool needsFullRestart = true,
@ -165,11 +152,11 @@ class ColdRunner extends ResidentRunner {
return 2; return 2;
} }
for (final FlutterDevice device in flutterDevices) { for (final FlutterDevice? device in flutterDevices) {
await device.initLogReader(); await device!.initLogReader();
} }
for (final FlutterDevice device in flutterDevices) { for (final FlutterDevice? device in flutterDevices) {
final List<FlutterView> views = await device.vmService.getFlutterViews(); final List<FlutterView> views = await device!.vmService!.getFlutterViews();
for (final FlutterView view in views) { for (final FlutterView view in views) {
globals.printTrace('Connected to $view.'); globals.printTrace('Connected to $view.');
} }
@ -177,7 +164,7 @@ class ColdRunner extends ResidentRunner {
if (enableDevTools && debuggingEnabled) { if (enableDevTools && debuggingEnabled) {
// The method below is guaranteed never to return a failing future. // The method below is guaranteed never to return a failing future.
unawaited(residentDevtoolsHandler.serveAndAnnounceDevTools( unawaited(residentDevtoolsHandler!.serveAndAnnounceDevTools(
devToolsServerAddress: debuggingOptions.devToolsServerAddress, devToolsServerAddress: debuggingOptions.devToolsServerAddress,
flutterDevices: flutterDevices, flutterDevices: flutterDevices,
)); ));
@ -202,16 +189,16 @@ class ColdRunner extends ResidentRunner {
@override @override
Future<void> cleanupAtFinish() async { Future<void> cleanupAtFinish() async {
for (final FlutterDevice flutterDevice in flutterDevices) { for (final FlutterDevice? flutterDevice in flutterDevices) {
await flutterDevice.device.dispose(); await flutterDevice!.device!.dispose();
} }
await residentDevtoolsHandler.shutdown(); await residentDevtoolsHandler!.shutdown();
await stopEchoingDeviceLog(); await stopEchoingDeviceLog();
} }
@override @override
void printHelp({ @required bool details }) { void printHelp({ required bool details }) {
globals.printStatus('Flutter run key commands.'); globals.printStatus('Flutter run key commands.');
if (details) { if (details) {
printHelpDetails(); printHelpDetails();
@ -229,10 +216,10 @@ class ColdRunner extends ResidentRunner {
@override @override
Future<void> preExit() async { Future<void> preExit() async {
for (final FlutterDevice device in flutterDevices) { for (final FlutterDevice? device in flutterDevices) {
// If we're running in release mode, stop the app using the device logic. // If we're running in release mode, stop the app using the device logic.
if (device.vmService == null) { if (device!.vmService == null) {
await device.device.stopApp(device.package, userIdentifier: device.userIdentifier); await device.device!.stopApp(device.package, userIdentifier: device.userIdentifier);
} }
} }
await super.preExit(); await super.preExit();

File diff suppressed because it is too large Load Diff

View File

@ -69,7 +69,7 @@ class FlutterCommandResult {
/// Optional data that can be appended to the timing event. /// Optional data that can be appended to the timing event.
/// https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#timingLabel /// https://developers.google.com/analytics/devguides/collection/analyticsjs/field-reference#timingLabel
/// Do not add PII. /// Do not add PII.
final List<String>? timingLabelParts; final List<String?>? timingLabelParts;
/// Optional epoch time when the command's non-interactive wait time is /// Optional epoch time when the command's non-interactive wait time is
/// complete during the command's execution. Use to measure user perceivable /// complete during the command's execution. Use to measure user perceivable
@ -1265,7 +1265,7 @@ abstract class FlutterCommand extends Command<void> {
CommandResultEvent(commandPath, commandResult.toString()).send(); CommandResultEvent(commandPath, commandResult.toString()).send();
// Send timing. // Send timing.
final List<String> labels = <String>[ final List<String?> labels = <String?>[
if (commandResult.exitStatus != null) if (commandResult.exitStatus != null)
getEnumName(commandResult.exitStatus), getEnumName(commandResult.exitStatus),
if (commandResult.timingLabelParts?.isNotEmpty ?? false) if (commandResult.timingLabelParts?.isNotEmpty ?? false)
@ -1273,7 +1273,7 @@ abstract class FlutterCommand extends Command<void> {
]; ];
final String label = labels final String label = labels
.where((String label) => !_isBlank(label)) .where((String? label) => label != null && !_isBlank(label))
.join('-'); .join('-');
globals.flutterUsage.sendTiming( globals.flutterUsage.sendTiming(
'flutter', 'flutter',

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:coverage/coverage.dart' as coverage; import 'package:coverage/coverage.dart' as coverage;
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
@ -19,7 +19,7 @@ import 'watcher.dart';
/// A class that collects code coverage data during test runs. /// A class that collects code coverage data during test runs.
class CoverageCollector extends TestWatcher { class CoverageCollector extends TestWatcher {
CoverageCollector({this.libraryNames, this.verbose = true, @required this.packagesPath}); CoverageCollector({this.libraryNames, this.verbose = true, required this.packagesPath});
/// True when log messages should be emitted. /// True when log messages should be emitted.
final bool verbose; final bool verbose;
@ -29,11 +29,11 @@ class CoverageCollector extends TestWatcher {
final String packagesPath; final String packagesPath;
/// Map of file path to coverage hit map for that file. /// Map of file path to coverage hit map for that file.
Map<String, coverage.HitMap> _globalHitmap; Map<String, coverage.HitMap>? _globalHitmap;
/// The names of the libraries to gather coverage for. If null, all libraries /// The names of the libraries to gather coverage for. If null, all libraries
/// will be accepted. /// will be accepted.
Set<String> libraryNames; Set<String>? libraryNames;
@override @override
Future<void> handleFinishedTest(TestDevice testDevice) async { Future<void> handleFinishedTest(TestDevice testDevice) async {
@ -56,7 +56,7 @@ class CoverageCollector extends TestWatcher {
if (_globalHitmap == null) { if (_globalHitmap == null) {
_globalHitmap = hitmap; _globalHitmap = hitmap;
} else { } else {
_globalHitmap.merge(hitmap); _globalHitmap!.merge(hitmap);
} }
} }
@ -107,7 +107,7 @@ class CoverageCollector extends TestWatcher {
Future<void> collectCoverage(TestDevice testDevice) async { Future<void> collectCoverage(TestDevice testDevice) async {
assert(testDevice != null); assert(testDevice != null);
Map<String, dynamic> data; Map<String, dynamic>? data;
final Future<void> processComplete = testDevice.finished.catchError( final Future<void> processComplete = testDevice.finished.catchError(
(Object error) => throw Exception( (Object error) => throw Exception(
@ -134,7 +134,7 @@ class CoverageCollector extends TestWatcher {
_logMessage('Merging coverage data...'); _logMessage('Merging coverage data...');
_addHitmap(await coverage.HitMap.parseJson( _addHitmap(await coverage.HitMap.parseJson(
data['coverage'] as List<Map<String, dynamic>>, data!['coverage'] as List<Map<String, dynamic>>,
packagePath: packageDirectory, packagePath: packageDirectory,
checkIgnoredLines: true, checkIgnoredLines: true,
)); ));
@ -145,10 +145,10 @@ class CoverageCollector extends TestWatcher {
/// ///
/// This will not start any collection tasks. It us up to the caller of to /// This will not start any collection tasks. It us up to the caller of to
/// call [collectCoverage] for each process first. /// call [collectCoverage] for each process first.
Future<String> finalizeCoverage({ Future<String?> finalizeCoverage({
String Function(Map<String, coverage.HitMap> hitmap) formatter, String Function(Map<String, coverage.HitMap> hitmap)? formatter,
coverage.Resolver resolver, coverage.Resolver? resolver,
Directory coverageDirectory, Directory? coverageDirectory,
}) async { }) async {
if (_globalHitmap == null) { if (_globalHitmap == null) {
return null; return null;
@ -160,15 +160,15 @@ class CoverageCollector extends TestWatcher {
? <String>[globals.fs.path.join(packagePath, 'lib')] ? <String>[globals.fs.path.join(packagePath, 'lib')]
: <String>[coverageDirectory.path]; : <String>[coverageDirectory.path];
formatter = (Map<String, coverage.HitMap> hitmap) => hitmap formatter = (Map<String, coverage.HitMap> hitmap) => hitmap
.formatLcov(resolver, reportOn: reportOn, basePath: packagePath); .formatLcov(resolver!, reportOn: reportOn, basePath: packagePath);
} }
final String result = formatter(_globalHitmap); final String result = formatter(_globalHitmap!);
_globalHitmap = null; _globalHitmap = null;
return result; return result;
} }
Future<bool> collectCoverageData(String coveragePath, { bool mergeCoverageData = false, Directory coverageDirectory }) async { Future<bool> collectCoverageData(String? coveragePath, { bool mergeCoverageData = false, Directory? coverageDirectory }) async {
final String coverageData = await finalizeCoverage( final String? coverageData = await finalizeCoverage(
coverageDirectory: coverageDirectory, coverageDirectory: coverageDirectory,
); );
_logMessage('coverage information collection complete'); _logMessage('coverage information collection complete');
@ -225,15 +225,15 @@ class CoverageCollector extends TestWatcher {
Future<void> handleTestTimedOut(TestDevice testDevice) async { } Future<void> handleTestTimedOut(TestDevice testDevice) async { }
} }
Future<FlutterVmService> _defaultConnect(Uri serviceUri) { Future<FlutterVmService> _defaultConnect(Uri? serviceUri) {
return connectToVmService( return connectToVmService(
serviceUri, compression: CompressionOptions.compressionOff, logger: globals.logger,); serviceUri!, compression: CompressionOptions.compressionOff, logger: globals.logger,);
} }
Future<Map<String, dynamic>> collect(Uri serviceUri, Set<String> libraryNames, { Future<Map<String, dynamic>> collect(Uri? serviceUri, Set<String>? libraryNames, {
bool waitPaused = false, bool waitPaused = false,
String debugName, String? debugName,
Future<FlutterVmService> Function(Uri) connector = _defaultConnect, Future<FlutterVmService> Function(Uri?) connector = _defaultConnect,
@visibleForTesting bool forceSequential = false, @visibleForTesting bool forceSequential = false,
}) async { }) async {
final FlutterVmService vmService = await connector(serviceUri); final FlutterVmService vmService = await connector(serviceUri);
@ -244,31 +244,31 @@ Future<Map<String, dynamic>> collect(Uri serviceUri, Set<String> libraryNames, {
Future<Map<String, dynamic>> _getAllCoverage( Future<Map<String, dynamic>> _getAllCoverage(
vm_service.VmService service, vm_service.VmService service,
Set<String> libraryNames, Set<String>? libraryNames,
bool forceSequential, bool forceSequential,
) async { ) async {
final vm_service.Version version = await service.getVersion(); final vm_service.Version version = await service.getVersion();
final bool libraryFilters = (version.major == 3 && version.minor >= 57) || version.major > 3; final bool libraryFilters = (version.major == 3 && version.minor! >= 57) || version.major! > 3;
final vm_service.VM vm = await service.getVM(); final vm_service.VM vm = await service.getVM();
final List<Map<String, dynamic>> coverage = <Map<String, dynamic>>[]; final List<Map<String, dynamic>> coverage = <Map<String, dynamic>>[];
bool libraryPredicate(String libraryName) { bool libraryPredicate(String? libraryName) {
if (libraryNames == null) { if (libraryNames == null) {
return true; return true;
} }
final Uri uri = Uri.parse(libraryName); final Uri uri = Uri.parse(libraryName!);
if (uri.scheme != 'package') { if (uri.scheme != 'package') {
return false; return false;
} }
final String scope = uri.path.split('/').first; final String scope = uri.path.split('/').first;
return libraryNames.contains(scope); return libraryNames.contains(scope);
} }
for (final vm_service.IsolateRef isolateRef in vm.isolates) { for (final vm_service.IsolateRef isolateRef in vm.isolates!) {
if (isolateRef.isSystemIsolate) { if (isolateRef.isSystemIsolate!) {
continue; continue;
} }
if (libraryFilters) { if (libraryFilters) {
final vm_service.SourceReport sourceReport = await service.getSourceReport( final vm_service.SourceReport sourceReport = await service.getSourceReport(
isolateRef.id, isolateRef.id!,
<String>['Coverage'], <String>['Coverage'],
forceCompile: true, forceCompile: true,
reportLines: true, reportLines: true,
@ -283,7 +283,7 @@ Future<Map<String, dynamic>> _getAllCoverage(
} else { } else {
vm_service.ScriptList scriptList; vm_service.ScriptList scriptList;
try { try {
scriptList = await service.getScripts(isolateRef.id); scriptList = await service.getScripts(isolateRef.id!);
} on vm_service.SentinelException { } on vm_service.SentinelException {
continue; continue;
} }
@ -294,14 +294,14 @@ Future<Map<String, dynamic>> _getAllCoverage(
// For each ScriptRef loaded into the VM, load the corresponding Script // For each ScriptRef loaded into the VM, load the corresponding Script
// and SourceReport object. // and SourceReport object.
for (final vm_service.ScriptRef script in scriptList.scripts) { for (final vm_service.ScriptRef script in scriptList.scripts!) {
final String libraryUri = script.uri; final String? libraryUri = script.uri;
if (!libraryPredicate(libraryUri)) { if (!libraryPredicate(libraryUri)) {
continue; continue;
} }
final String scriptId = script.id; final String? scriptId = script.id;
final Future<void> getSourceReport = service.getSourceReport( final Future<void> getSourceReport = service.getSourceReport(
isolateRef.id, isolateRef.id!,
<String>['Coverage'], <String>['Coverage'],
scriptId: scriptId, scriptId: scriptId,
forceCompile: true, forceCompile: true,
@ -328,36 +328,36 @@ void _buildCoverageMap(
List<vm_service.SourceReport> sourceReports, List<vm_service.SourceReport> sourceReports,
List<Map<String, dynamic>> coverage, List<Map<String, dynamic>> coverage,
) { ) {
final Map<String, Map<int, int>> hitMaps = <String, Map<int, int>>{}; final Map<String?, Map<int, int>> hitMaps = <String?, Map<int, int>>{};
for (final vm_service.SourceReport sourceReport in sourceReports) { for (final vm_service.SourceReport sourceReport in sourceReports) {
for (final vm_service.SourceReportRange range in sourceReport.ranges) { for (final vm_service.SourceReportRange range in sourceReport.ranges!) {
final vm_service.SourceReportCoverage coverage = range.coverage; final vm_service.SourceReportCoverage? coverage = range.coverage;
// Coverage reports may sometimes be null for a Script. // Coverage reports may sometimes be null for a Script.
if (coverage == null) { if (coverage == null) {
continue; continue;
} }
final vm_service.ScriptRef scriptRef = sourceReport.scripts[range.scriptIndex]; final vm_service.ScriptRef scriptRef = sourceReport.scripts![range.scriptIndex!];
final String uri = scriptRef.uri; final String? uri = scriptRef.uri;
hitMaps[uri] ??= <int, int>{}; hitMaps[uri] ??= <int, int>{};
final Map<int, int> hitMap = hitMaps[uri]; final Map<int, int>? hitMap = hitMaps[uri];
final List<int> hits = coverage.hits; final List<int>? hits = coverage.hits;
final List<int> misses = coverage.misses; final List<int>? misses = coverage.misses;
if (hits != null) { if (hits != null) {
for (final int line in hits) { for (final int line in hits) {
final int current = hitMap[line] ?? 0; final int current = hitMap![line] ?? 0;
hitMap[line] = current + 1; hitMap[line] = current + 1;
} }
} }
if (misses != null) { if (misses != null) {
for (final int line in misses) { for (final int line in misses) {
hitMap[line] ??= 0; hitMap![line] ??= 0;
} }
} }
} }
} }
hitMaps.forEach((String uri, Map<int, int> hitMap) { hitMaps.forEach((String? uri, Map<int, int> hitMap) {
coverage.add(_toScriptCoverageJson(uri, hitMap)); coverage.add(_toScriptCoverageJson(uri!, hitMap));
}); });
} }

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
@ -47,22 +47,22 @@ typedef PlatformPluginRegistration = void Function(FlutterPlatform platform);
/// main()`), you can set an observatory port explicitly. /// main()`), you can set an observatory port explicitly.
FlutterPlatform installHook({ FlutterPlatform installHook({
TestWrapper testWrapper = const TestWrapper(), TestWrapper testWrapper = const TestWrapper(),
@required String shellPath, required String shellPath,
@required DebuggingOptions debuggingOptions, required DebuggingOptions debuggingOptions,
TestWatcher watcher, TestWatcher? watcher,
bool enableObservatory = false, bool enableObservatory = false,
bool machine = false, bool machine = false,
String precompiledDillPath, String? precompiledDillPath,
Map<String, String> precompiledDillFiles, Map<String, String>? precompiledDillFiles,
bool updateGoldens = false, bool updateGoldens = false,
String testAssetDirectory, String? testAssetDirectory,
InternetAddressType serverType = InternetAddressType.IPv4, InternetAddressType serverType = InternetAddressType.IPv4,
Uri projectRootDirectory, Uri? projectRootDirectory,
FlutterProject flutterProject, FlutterProject? flutterProject,
String icudtlPath, String? icudtlPath,
PlatformPluginRegistration platformPluginRegistration, PlatformPluginRegistration? platformPluginRegistration,
Device integrationTestDevice, Device? integrationTestDevice,
String integrationTestUserIdentifier, String? integrationTestUserIdentifier,
}) { }) {
assert(testWrapper != null); assert(testWrapper != null);
assert(enableObservatory || (!debuggingOptions.startPaused && debuggingOptions.hostVmServicePort == null)); assert(enableObservatory || (!debuggingOptions.startPaused && debuggingOptions.hostVmServicePort == null));
@ -119,9 +119,9 @@ FlutterPlatform installHook({
// NOTE: this API is used by the fuchsia source tree, do not add new // NOTE: this API is used by the fuchsia source tree, do not add new
// required or position parameters. // required or position parameters.
String generateTestBootstrap({ String generateTestBootstrap({
@required Uri testUrl, required Uri testUrl,
@required InternetAddress host, required InternetAddress host,
File testConfigFile, File? testConfigFile,
bool updateGoldens = false, bool updateGoldens = false,
String languageVersionHeader = '', String languageVersionHeader = '',
bool nullSafety = false, bool nullSafety = false,
@ -271,8 +271,8 @@ typedef Finalizer = Future<void> Function();
/// The flutter test platform used to integrate with package:test. /// The flutter test platform used to integrate with package:test.
class FlutterPlatform extends PlatformPlugin { class FlutterPlatform extends PlatformPlugin {
FlutterPlatform({ FlutterPlatform({
@required this.shellPath, required this.shellPath,
@required this.debuggingOptions, required this.debuggingOptions,
this.watcher, this.watcher,
this.enableObservatory, this.enableObservatory,
this.machine, this.machine,
@ -290,26 +290,26 @@ class FlutterPlatform extends PlatformPlugin {
final String shellPath; final String shellPath;
final DebuggingOptions debuggingOptions; final DebuggingOptions debuggingOptions;
final TestWatcher watcher; final TestWatcher? watcher;
final bool enableObservatory; final bool? enableObservatory;
final bool machine; final bool? machine;
final InternetAddress host; final InternetAddress? host;
final String precompiledDillPath; final String? precompiledDillPath;
final Map<String, String> precompiledDillFiles; final Map<String, String>? precompiledDillFiles;
final bool updateGoldens; final bool? updateGoldens;
final String testAssetDirectory; final String? testAssetDirectory;
final Uri projectRootDirectory; final Uri? projectRootDirectory;
final FlutterProject flutterProject; final FlutterProject? flutterProject;
final String icudtlPath; final String? icudtlPath;
/// The device to run the test on for Integration Tests. /// The device to run the test on for Integration Tests.
/// ///
/// If this is null, the test will run as a regular test with the Flutter /// If this is null, the test will run as a regular test with the Flutter
/// Tester; otherwise it will run as a Integration Test on this device. /// Tester; otherwise it will run as a Integration Test on this device.
final Device integrationTestDevice; final Device? integrationTestDevice;
bool get _isIntegrationTest => integrationTestDevice != null; bool get _isIntegrationTest => integrationTestDevice != null;
final String integrationTestUserIdentifier; final String? integrationTestUserIdentifier;
final FontConfigManager _fontConfigManager = FontConfigManager(); final FontConfigManager _fontConfigManager = FontConfigManager();
@ -317,7 +317,7 @@ class FlutterPlatform extends PlatformPlugin {
/// ///
/// To speed up compilation, each compile is initialized from an existing /// To speed up compilation, each compile is initialized from an existing
/// dill file from previous runs, if possible. /// dill file from previous runs, if possible.
TestCompiler compiler; TestCompiler? compiler;
// Each time loadChannel() is called, we spin up a local WebSocket server, // Each time loadChannel() is called, we spin up a local WebSocket server,
// then spin up the engine in a subprocess. We pass the engine a Dart file // then spin up the engine in a subprocess. We pass the engine a Dart file
@ -361,7 +361,7 @@ class FlutterPlatform extends PlatformPlugin {
_testCount += 1; _testCount += 1;
final StreamController<dynamic> localController = StreamController<dynamic>(); final StreamController<dynamic> localController = StreamController<dynamic>();
final StreamController<dynamic> remoteController = StreamController<dynamic>(); final StreamController<dynamic> remoteController = StreamController<dynamic>();
final Completer<_AsyncError> testCompleteCompleter = Completer<_AsyncError>(); final Completer<_AsyncError?> testCompleteCompleter = Completer<_AsyncError?>();
final _FlutterPlatformStreamSinkWrapper<dynamic> remoteSink = _FlutterPlatformStreamSinkWrapper<dynamic>( final _FlutterPlatformStreamSinkWrapper<dynamic> remoteSink = _FlutterPlatformStreamSinkWrapper<dynamic>(
remoteController.sink, remoteController.sink,
testCompleteCompleter.future, testCompleteCompleter.future,
@ -384,17 +384,17 @@ class FlutterPlatform extends PlatformPlugin {
List<String> definitions, List<String> definitions,
List<String> typeDefinitions, List<String> typeDefinitions,
String libraryUri, String libraryUri,
String klass, String? klass,
bool isStatic, bool isStatic,
) async { ) async {
if (compiler == null || compiler.compiler == null) { if (compiler == null || compiler!.compiler == null) {
throw Exception('Compiler is not set up properly to compile $expression'); throw Exception('Compiler is not set up properly to compile $expression');
} }
final CompilerOutput compilerOutput = final CompilerOutput? compilerOutput =
await compiler.compiler.compileExpression(expression, definitions, await compiler!.compiler!.compileExpression(expression, definitions,
typeDefinitions, libraryUri, klass, isStatic); typeDefinitions, libraryUri, klass, isStatic);
if (compilerOutput != null && compilerOutput.expressionData != null) { if (compilerOutput != null && compilerOutput.expressionData != null) {
return base64.encode(compilerOutput.expressionData); return base64.encode(compilerOutput.expressionData!);
} }
throw Exception('Failed to compile $expression'); throw Exception('Failed to compile $expression');
} }
@ -404,7 +404,7 @@ class FlutterPlatform extends PlatformPlugin {
return IntegrationTestTestDevice( return IntegrationTestTestDevice(
id: ourTestCount, id: ourTestCount,
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,
device: integrationTestDevice, device: integrationTestDevice!,
userIdentifier: integrationTestUserIdentifier, userIdentifier: integrationTestUserIdentifier,
); );
} }
@ -415,7 +415,7 @@ class FlutterPlatform extends PlatformPlugin {
processManager: globals.processManager, processManager: globals.processManager,
logger: globals.logger, logger: globals.logger,
shellPath: shellPath, shellPath: shellPath,
enableObservatory: enableObservatory, enableObservatory: enableObservatory!,
machine: machine, machine: machine,
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,
host: host, host: host,
@ -427,14 +427,14 @@ class FlutterPlatform extends PlatformPlugin {
); );
} }
Future<_AsyncError> _startTest( Future<_AsyncError?> _startTest(
String testPath, String testPath,
StreamChannel<dynamic> testHarnessChannel, StreamChannel<dynamic> testHarnessChannel,
int ourTestCount, int ourTestCount,
) async { ) async {
globals.printTrace('test $ourTestCount: starting test $testPath'); globals.printTrace('test $ourTestCount: starting test $testPath');
_AsyncError outOfBandError; // error that we couldn't send to the harness that we need to send via our future _AsyncError? outOfBandError; // error that we couldn't send to the harness that we need to send via our future
final List<Finalizer> finalizers = <Finalizer>[]; // Will be run in reverse order. final List<Finalizer> finalizers = <Finalizer>[]; // Will be run in reverse order.
bool controllerSinkClosed = false; bool controllerSinkClosed = false;
@ -447,7 +447,7 @@ class FlutterPlatform extends PlatformPlugin {
// If a kernel file is given, then use that to launch the test. // If a kernel file is given, then use that to launch the test.
// If mapping is provided, look kernel file from mapping. // If mapping is provided, look kernel file from mapping.
// If all fails, create a "listener" dart that invokes actual test. // If all fails, create a "listener" dart that invokes actual test.
String mainDart; String? mainDart;
if (precompiledDillPath != null) { if (precompiledDillPath != null) {
mainDart = precompiledDillPath; mainDart = precompiledDillPath;
// When start paused is specified, it means that the user is likely // When start paused is specified, it means that the user is likely
@ -457,10 +457,10 @@ class FlutterPlatform extends PlatformPlugin {
compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject, precompiledDillPath: precompiledDillPath); compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject, precompiledDillPath: precompiledDillPath);
final Uri testUri = globals.fs.file(testPath).uri; final Uri testUri = globals.fs.file(testPath).uri;
// Trigger a compilation to initialize the resident compiler. // Trigger a compilation to initialize the resident compiler.
unawaited(compiler.compile(testUri)); unawaited(compiler!.compile(testUri));
} }
} else if (precompiledDillFiles != null) { } else if (precompiledDillFiles != null) {
mainDart = precompiledDillFiles[testPath]; mainDart = precompiledDillFiles![testPath];
} else { } else {
mainDart = _createListenerDart(finalizers, ourTestCount, testPath); mainDart = _createListenerDart(finalizers, ourTestCount, testPath);
@ -468,7 +468,7 @@ class FlutterPlatform extends PlatformPlugin {
if (integrationTestDevice == null) { if (integrationTestDevice == null) {
// Lazily instantiate compiler so it is built only if it is actually used. // Lazily instantiate compiler so it is built only if it is actually used.
compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject); compiler ??= TestCompiler(debuggingOptions.buildInfo, flutterProject);
mainDart = await compiler.compile(globals.fs.file(mainDart).uri); mainDart = await compiler!.compile(globals.fs.file(mainDart).uri);
if (mainDart == null) { if (mainDart == null) {
testHarnessChannel.sink.addError('Compilation failed for testPath=$testPath'); testHarnessChannel.sink.addError('Compilation failed for testPath=$testPath');
@ -479,7 +479,7 @@ class FlutterPlatform extends PlatformPlugin {
globals.printTrace('test $ourTestCount: starting test device'); globals.printTrace('test $ourTestCount: starting test device');
final TestDevice testDevice = _createTestDevice(ourTestCount); final TestDevice testDevice = _createTestDevice(ourTestCount);
final Future<StreamChannel<String>> remoteChannelFuture = testDevice.start(mainDart); final Future<StreamChannel<String>> remoteChannelFuture = testDevice.start(mainDart!);
finalizers.add(() async { finalizers.add(() async {
globals.printTrace('test $ourTestCount: ensuring test device is terminated.'); globals.printTrace('test $ourTestCount: ensuring test device is terminated.');
await testDevice.kill(); await testDevice.kill();
@ -584,7 +584,7 @@ class FlutterPlatform extends PlatformPlugin {
} }
String _generateTestMain({ String _generateTestMain({
Uri testUrl, required Uri testUrl,
}) { }) {
assert(testUrl.scheme == 'file'); assert(testUrl.scheme == 'file');
final File file = globals.fs.file(testUrl); final File file = globals.fs.file(testUrl);
@ -592,14 +592,14 @@ class FlutterPlatform extends PlatformPlugin {
final LanguageVersion languageVersion = determineLanguageVersion( final LanguageVersion languageVersion = determineLanguageVersion(
file, file,
packageConfig[flutterProject?.manifest?.appName], packageConfig[flutterProject!.manifest.appName],
Cache.flutterRoot, Cache.flutterRoot!,
); );
return generateTestBootstrap( return generateTestBootstrap(
testUrl: testUrl, testUrl: testUrl,
testConfigFile: findTestConfigFile(globals.fs.file(testUrl), globals.logger), testConfigFile: findTestConfigFile(globals.fs.file(testUrl), globals.logger),
host: host, host: host!,
updateGoldens: updateGoldens, updateGoldens: updateGoldens!,
flutterTestDep: packageConfig['flutter_test'] != null, flutterTestDep: packageConfig['flutter_test'] != null,
languageVersionHeader: '// @dart=${languageVersion.major}.${languageVersion.minor}', languageVersionHeader: '// @dart=${languageVersion.major}.${languageVersion.minor}',
integrationTest: _isIntegrationTest, integrationTest: _isIntegrationTest,
@ -609,7 +609,7 @@ class FlutterPlatform extends PlatformPlugin {
@override @override
Future<dynamic> close() async { Future<dynamic> close() async {
if (compiler != null) { if (compiler != null) {
await compiler.dispose(); await compiler!.dispose();
compiler = null; compiler = null;
} }
await _fontConfigManager.dispose(); await _fontConfigManager.dispose();
@ -633,7 +633,7 @@ class _FlutterPlatformStreamSinkWrapper<S> implements StreamSink<S> {
_FlutterPlatformStreamSinkWrapper(this._parent, this._shellProcessClosed); _FlutterPlatformStreamSinkWrapper(this._parent, this._shellProcessClosed);
final StreamSink<S> _parent; final StreamSink<S> _parent;
final Future<_AsyncError> _shellProcessClosed; final Future<_AsyncError?> _shellProcessClosed;
@override @override
Future<void> get done => _done.future; Future<void> get done => _done.future;
@ -650,7 +650,7 @@ class _FlutterPlatformStreamSinkWrapper<S> implements StreamSink<S> {
assert(futureResults.first == null); assert(futureResults.first == null);
final dynamic lastResult = futureResults.last; final dynamic lastResult = futureResults.last;
if (lastResult is _AsyncError) { if (lastResult is _AsyncError) {
_done.completeError(lastResult.error, lastResult.stack); _done.completeError(lastResult.error as Object, lastResult.stack);
} else { } else {
assert(lastResult == null); assert(lastResult == null);
_done.complete(); _done.complete();
@ -664,7 +664,7 @@ class _FlutterPlatformStreamSinkWrapper<S> implements StreamSink<S> {
@override @override
void add(S event) => _parent.add(event); void add(S event) => _parent.add(event);
@override @override
void addError(dynamic errorEvent, [ StackTrace stackTrace ]) => _parent.addError(errorEvent, stackTrace); void addError(Object errorEvent, [ StackTrace? stackTrace ]) => _parent.addError(errorEvent, stackTrace);
@override @override
Future<dynamic> addStream(Stream<S> stream) => _parent.addStream(stream); Future<dynamic> addStream(Stream<S> stream) => _parent.addStream(stream);
} }
@ -681,9 +681,9 @@ class _AsyncError {
/// The returned future completes when either side is closed, which also /// The returned future completes when either side is closed, which also
/// indicates when the tests have finished. /// indicates when the tests have finished.
Future<void> _pipeHarnessToRemote({ Future<void> _pipeHarnessToRemote({
@required int id, required int id,
@required StreamChannel<dynamic> harnessChannel, required StreamChannel<dynamic> harnessChannel,
@required StreamChannel<String> remoteChannel, required StreamChannel<String> remoteChannel,
}) async { }) async {
globals.printTrace('test $id: Waiting for test harness or tests to finish'); globals.printTrace('test $id: Waiting for test harness or tests to finish');

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:io' as io; // flutter_ignore: dart_io_import; import 'dart:io' as io; // flutter_ignore: dart_io_import;
@ -29,25 +29,26 @@ import 'test_device.dart';
/// Implementation of [TestDevice] with the Flutter Tester over a [Process]. /// Implementation of [TestDevice] with the Flutter Tester over a [Process].
class FlutterTesterTestDevice extends TestDevice { class FlutterTesterTestDevice extends TestDevice {
FlutterTesterTestDevice({ FlutterTesterTestDevice({
@required this.id, required this.id,
@required this.platform, required this.platform,
@required this.fileSystem, required this.fileSystem,
@required this.processManager, required this.processManager,
@required this.logger, required this.logger,
@required this.shellPath, required this.shellPath,
@required this.debuggingOptions, required this.debuggingOptions,
@required this.enableObservatory, required this.enableObservatory,
@required this.machine, required this.machine,
@required this.host, required this.host,
@required this.testAssetDirectory, required this.testAssetDirectory,
@required this.flutterProject, required this.flutterProject,
@required this.icudtlPath, required this.icudtlPath,
@required this.compileExpression, required this.compileExpression,
@required this.fontConfigManager, required this.fontConfigManager,
}) : assert(shellPath != null), // Please provide the path to the shell in the SKY_SHELL environment variable. }) : assert(shellPath != null), // Please provide the path to the shell in the SKY_SHELL environment variable.
assert(!debuggingOptions.startPaused || enableObservatory), assert(!debuggingOptions.startPaused || enableObservatory),
_gotProcessObservatoryUri = enableObservatory _gotProcessObservatoryUri = enableObservatory
? Completer<Uri>() : (Completer<Uri>()..complete(null)), // ignore: null_argument_to_non_null_type
? Completer<Uri>() : (Completer<Uri>()..complete()),
_operatingSystemUtils = OperatingSystemUtils( _operatingSystemUtils = OperatingSystemUtils(
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
@ -64,19 +65,19 @@ class FlutterTesterTestDevice extends TestDevice {
final String shellPath; final String shellPath;
final DebuggingOptions debuggingOptions; final DebuggingOptions debuggingOptions;
final bool enableObservatory; final bool enableObservatory;
final bool machine; final bool? machine;
final InternetAddress host; final InternetAddress? host;
final String testAssetDirectory; final String? testAssetDirectory;
final FlutterProject flutterProject; final FlutterProject? flutterProject;
final String icudtlPath; final String? icudtlPath;
final CompileExpression compileExpression; final CompileExpression? compileExpression;
final FontConfigManager fontConfigManager; final FontConfigManager fontConfigManager;
final Completer<Uri> _gotProcessObservatoryUri; final Completer<Uri> _gotProcessObservatoryUri;
final Completer<int> _exitCode = Completer<int>(); final Completer<int> _exitCode = Completer<int>();
Process _process; Process? _process;
HttpServer _server; HttpServer? _server;
final OperatingSystemUtils _operatingSystemUtils; final OperatingSystemUtils _operatingSystemUtils;
/// Starts the device. /// Starts the device.
@ -92,7 +93,7 @@ class FlutterTesterTestDevice extends TestDevice {
// Prepare our WebSocket server to talk to the engine subprocess. // Prepare our WebSocket server to talk to the engine subprocess.
// Let the server choose an unused port. // Let the server choose an unused port.
_server = await bind(host, /*port*/ 0); _server = await bind(host, /*port*/ 0);
logger.printTrace('test $id: test harness socket server is running at port:${_server.port}'); logger.printTrace('test $id: test harness socket server is running at port:${_server!.port}');
final List<String> command = <String>[ final List<String> command = <String>[
// Until an arm64 flutter tester binary is available, force to run in Rosetta // Until an arm64 flutter tester binary is available, force to run in Rosetta
// to avoid "unexpectedly got a signal in sigtramp" crash. // to avoid "unexpectedly got a signal in sigtramp" crash.
@ -118,7 +119,7 @@ class FlutterTesterTestDevice extends TestDevice {
] ]
else else
'--disable-observatory', '--disable-observatory',
if (host.type == InternetAddressType.IPv6) '--ipv6', if (host!.type == InternetAddressType.IPv6) '--ipv6',
if (icudtlPath != null) '--icu-data-file-path=$icudtlPath', if (icudtlPath != null) '--icu-data-file-path=$icudtlPath',
'--enable-checked-mode', '--enable-checked-mode',
'--verify-entry-points', '--verify-entry-points',
@ -143,38 +144,38 @@ class FlutterTesterTestDevice extends TestDevice {
// If FLUTTER_TEST has not been set, assume from this context that this // If FLUTTER_TEST has not been set, assume from this context that this
// call was invoked by the command 'flutter test'. // call was invoked by the command 'flutter test'.
final String flutterTest = platform.environment.containsKey('FLUTTER_TEST') final String flutterTest = platform.environment.containsKey('FLUTTER_TEST')
? platform.environment['FLUTTER_TEST'] ? platform.environment['FLUTTER_TEST']!
: 'true'; : 'true';
final Map<String, String> environment = <String, String>{ final Map<String, String> environment = <String, String>{
'FLUTTER_TEST': flutterTest, 'FLUTTER_TEST': flutterTest,
'FONTCONFIG_FILE': fontConfigManager.fontConfigFile.path, 'FONTCONFIG_FILE': fontConfigManager.fontConfigFile.path,
'SERVER_PORT': _server.port.toString(), 'SERVER_PORT': _server!.port.toString(),
'APP_NAME': flutterProject?.manifest?.appName ?? '', 'APP_NAME': flutterProject?.manifest.appName ?? '',
if (testAssetDirectory != null) if (testAssetDirectory != null)
'UNIT_TEST_ASSETS': testAssetDirectory, 'UNIT_TEST_ASSETS': testAssetDirectory!,
}; };
logger.printTrace('test $id: Starting flutter_tester process with command=$command, environment=$environment'); logger.printTrace('test $id: Starting flutter_tester process with command=$command, environment=$environment');
_process = await processManager.start(command, environment: environment); _process = await processManager.start(command, environment: environment);
// Unawaited to update state. // Unawaited to update state.
unawaited(_process.exitCode.then((int exitCode) { unawaited(_process!.exitCode.then((int exitCode) {
logger.printTrace('test $id: flutter_tester process at pid ${_process.pid} exited with code=$exitCode'); logger.printTrace('test $id: flutter_tester process at pid ${_process!.pid} exited with code=$exitCode');
_exitCode.complete(exitCode); _exitCode.complete(exitCode);
})); }));
logger.printTrace('test $id: Started flutter_tester process at pid ${_process.pid}'); logger.printTrace('test $id: Started flutter_tester process at pid ${_process!.pid}');
// Pipe stdout and stderr from the subprocess to our printStatus console. // Pipe stdout and stderr from the subprocess to our printStatus console.
// We also keep track of what observatory port the engine used, if any. // We also keep track of what observatory port the engine used, if any.
_pipeStandardStreamsToConsole( _pipeStandardStreamsToConsole(
process: _process, process: _process!,
reportObservatoryUri: (Uri detectedUri) async { reportObservatoryUri: (Uri detectedUri) async {
assert(!_gotProcessObservatoryUri.isCompleted); assert(!_gotProcessObservatoryUri.isCompleted);
assert(debuggingOptions.hostVmServicePort == null || assert(debuggingOptions.hostVmServicePort == null ||
debuggingOptions.hostVmServicePort == detectedUri.port); debuggingOptions.hostVmServicePort == detectedUri.port);
Uri forwardingUri; Uri? forwardingUri;
if (debuggingOptions.enableDds) { if (debuggingOptions.enableDds) {
logger.printTrace('test $id: Starting Dart Development Service'); logger.printTrace('test $id: Starting Dart Development Service');
final DartDevelopmentService dds = await startDds(detectedUri); final DartDevelopmentService dds = await startDds(detectedUri);
@ -186,7 +187,7 @@ class FlutterTesterTestDevice extends TestDevice {
logger.printTrace('Connecting to service protocol: $forwardingUri'); logger.printTrace('Connecting to service protocol: $forwardingUri');
final Future<FlutterVmService> localVmService = connectToVmService( final Future<FlutterVmService> localVmService = connectToVmService(
forwardingUri, forwardingUri!,
compileExpression: compileExpression, compileExpression: compileExpression,
logger: logger, logger: logger,
); );
@ -194,7 +195,7 @@ class FlutterTesterTestDevice extends TestDevice {
logger.printTrace('test $id: Successfully connected to service protocol: $forwardingUri'); logger.printTrace('test $id: Successfully connected to service protocol: $forwardingUri');
})); }));
if (debuggingOptions.startPaused && !machine) { if (debuggingOptions.startPaused && !machine!) {
logger.printStatus('The test process has been started.'); logger.printStatus('The test process has been started.');
logger.printStatus('You can now connect to it using observatory. To connect, load the following Web site in your browser:'); logger.printStatus('You can now connect to it using observatory. To connect, load the following Web site in your browser:');
logger.printStatus(' $forwardingUri'); logger.printStatus(' $forwardingUri');
@ -244,7 +245,7 @@ class FlutterTesterTestDevice extends TestDevice {
Uri get _ddsServiceUri { Uri get _ddsServiceUri {
return Uri( return Uri(
scheme: 'http', scheme: 'http',
host: (host.type == InternetAddressType.IPv6 ? host: (host!.type == InternetAddressType.IPv6 ?
InternetAddress.loopbackIPv6 : InternetAddress.loopbackIPv6 :
InternetAddress.loopbackIPv4 InternetAddress.loopbackIPv4
).host, ).host,
@ -259,7 +260,7 @@ class FlutterTesterTestDevice extends TestDevice {
uri, uri,
serviceUri: _ddsServiceUri, serviceUri: _ddsServiceUri,
enableAuthCodes: !debuggingOptions.disableServiceAuthCodes, enableAuthCodes: !debuggingOptions.disableServiceAuthCodes,
ipv6: host.type == InternetAddressType.IPv6, ipv6: host!.type == InternetAddressType.IPv6,
); );
} }
@ -268,7 +269,7 @@ class FlutterTesterTestDevice extends TestDevice {
/// Only intended to be overridden in tests. /// Only intended to be overridden in tests.
@protected @protected
@visibleForTesting @visibleForTesting
Future<HttpServer> bind(InternetAddress host, int port) => HttpServer.bind(host, port); Future<HttpServer> bind(InternetAddress? host, int port) => HttpServer.bind(host, port);
@protected @protected
@visibleForTesting @visibleForTesting
@ -276,7 +277,7 @@ class FlutterTesterTestDevice extends TestDevice {
assert(_server != null); assert(_server != null);
try { try {
final HttpRequest firstRequest = await _server.first; final HttpRequest firstRequest = await _server!.first;
final WebSocket webSocket = await WebSocketTransformer.upgrade(firstRequest); final WebSocket webSocket = await WebSocketTransformer.upgrade(firstRequest);
return _webSocketToStreamChannel(webSocket); return _webSocketToStreamChannel(webSocket);
} on Exception catch (error, stackTrace) { } on Exception catch (error, stackTrace) {
@ -287,14 +288,14 @@ class FlutterTesterTestDevice extends TestDevice {
@override @override
String toString() { String toString() {
final String status = _process != null final String status = _process != null
? 'pid: ${_process.pid}, ${_exitCode.isCompleted ? 'exited' : 'running'}' ? 'pid: ${_process!.pid}, ${_exitCode.isCompleted ? 'exited' : 'running'}'
: 'not started'; : 'not started';
return 'Flutter Tester ($status) for test $id'; return 'Flutter Tester ($status) for test $id';
} }
void _pipeStandardStreamsToConsole({ void _pipeStandardStreamsToConsole({
@required Process process, required Process process,
@required Future<void> Function(Uri uri) reportObservatoryUri, required Future<void> Function(Uri uri) reportObservatoryUri,
}) { }) {
for (final Stream<List<int>> stream in <Stream<List<int>>>[ for (final Stream<List<int>> stream in <Stream<List<int>>>[
process.stderr, process.stderr,
@ -307,10 +308,10 @@ class FlutterTesterTestDevice extends TestDevice {
(String line) async { (String line) async {
logger.printTrace('test $id: Shell: $line'); logger.printTrace('test $id: Shell: $line');
final Match match = globals.kVMServiceMessageRegExp.firstMatch(line); final Match? match = globals.kVMServiceMessageRegExp.firstMatch(line);
if (match != null) { if (match != null) {
try { try {
final Uri uri = Uri.parse(match[1]); final Uri uri = Uri.parse(match[1]!);
if (reportObservatoryUri != null) { if (reportObservatoryUri != null) {
await reportObservatoryUri(uri); await reportObservatoryUri(uri);
} }
@ -357,7 +358,7 @@ StreamChannel<String> _webSocketToStreamChannel(WebSocket webSocket) {
.pipe(webSocket); .pipe(webSocket);
webSocket webSocket
// We're only communicating with string encoded JSON. // We're only communicating with string encoded JSON.
.map<String>((dynamic message) => message as String) .map<String?>((dynamic message) => message as String?)
.pipe(controller.local.sink); .pipe(controller.local.sink);
return controller.foreign; return controller.foreign;

View File

@ -2,12 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:meta/meta.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
@ -28,26 +25,26 @@ import 'test_config.dart';
class TestGoldenComparator { class TestGoldenComparator {
/// Creates a [TestGoldenComparator] instance. /// Creates a [TestGoldenComparator] instance.
TestGoldenComparator(this.shellPath, this.compilerFactory, { TestGoldenComparator(this.shellPath, this.compilerFactory, {
@required Logger logger, required Logger logger,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required ProcessManager processManager, required ProcessManager? processManager,
@required this.webRenderer, required this.webRenderer,
}) : tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_web_platform.'), }) : tempDir = fileSystem.systemTempDirectory.createTempSync('flutter_web_platform.'),
_logger = logger, _logger = logger,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_processManager = processManager; _processManager = processManager;
final String shellPath; final String? shellPath;
final Directory tempDir; final Directory tempDir;
final TestCompiler Function() compilerFactory; final TestCompiler Function() compilerFactory;
final Logger _logger; final Logger _logger;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final ProcessManager _processManager; final ProcessManager? _processManager;
final WebRendererMode webRenderer; final WebRendererMode webRenderer;
TestCompiler _compiler; TestCompiler? _compiler;
TestGoldenComparatorProcess _previousComparator; TestGoldenComparatorProcess? _previousComparator;
Uri _previousTestUri; Uri? _previousTestUri;
Future<void> close() async { Future<void> close() async {
tempDir.deleteSync(recursive: true); tempDir.deleteSync(recursive: true);
@ -57,13 +54,16 @@ class TestGoldenComparator {
/// Start golden comparator in a separate process. Start one file per test file /// Start golden comparator in a separate process. Start one file per test file
/// to reduce the overhead of starting `flutter_tester`. /// to reduce the overhead of starting `flutter_tester`.
Future<TestGoldenComparatorProcess> _processForTestFile(Uri testUri) async { Future<TestGoldenComparatorProcess?> _processForTestFile(Uri testUri) async {
if (testUri == _previousTestUri) { if (testUri == _previousTestUri) {
return _previousComparator; return _previousComparator;
} }
final String bootstrap = TestGoldenComparatorProcess.generateBootstrap(_fileSystem.file(testUri), testUri, logger: _logger); final String bootstrap = TestGoldenComparatorProcess.generateBootstrap(_fileSystem.file(testUri), testUri, logger: _logger);
final Process process = await _startProcess(bootstrap); final Process? process = await _startProcess(bootstrap);
if (process == null) {
return null;
}
unawaited(_previousComparator?.close()); unawaited(_previousComparator?.close());
_previousComparator = TestGoldenComparatorProcess(process, logger: _logger); _previousComparator = TestGoldenComparatorProcess(process, logger: _logger);
_previousTestUri = testUri; _previousTestUri = testUri;
@ -71,16 +71,19 @@ class TestGoldenComparator {
return _previousComparator; return _previousComparator;
} }
Future<Process> _startProcess(String testBootstrap) async { Future<Process?> _startProcess(String testBootstrap) async {
// Prepare the Dart file that will talk to us and start the test. // Prepare the Dart file that will talk to us and start the test.
final File listenerFile = (await tempDir.createTemp('listener')).childFile('listener.dart'); final File listenerFile = (await tempDir.createTemp('listener')).childFile('listener.dart');
await listenerFile.writeAsString(testBootstrap); await listenerFile.writeAsString(testBootstrap);
// Lazily create the compiler // Lazily create the compiler
_compiler = _compiler ?? compilerFactory(); _compiler = _compiler ?? compilerFactory();
final String output = await _compiler.compile(listenerFile.uri); final String? output = await _compiler!.compile(listenerFile.uri);
if (output == null) {
return null;
}
final List<String> command = <String>[ final List<String> command = <String>[
shellPath, shellPath!,
'--disable-observatory', '--disable-observatory',
'--non-interactive', '--non-interactive',
'--packages=${_fileSystem.path.join('.dart_tool', 'package_config.json')}', '--packages=${_fileSystem.path.join('.dart_tool', 'package_config.json')}',
@ -92,12 +95,12 @@ class TestGoldenComparator {
'FLUTTER_TEST_BROWSER': 'chrome', 'FLUTTER_TEST_BROWSER': 'chrome',
'FLUTTER_WEB_RENDERER': webRenderer == WebRendererMode.html ? 'html' : 'canvaskit', 'FLUTTER_WEB_RENDERER': webRenderer == WebRendererMode.html ? 'html' : 'canvaskit',
}; };
return _processManager.start(command, environment: environment); return _processManager!.start(command, environment: environment);
} }
Future<String> compareGoldens(Uri testUri, Uint8List bytes, Uri goldenKey, bool updateGoldens) async { Future<String?> compareGoldens(Uri testUri, Uint8List bytes, Uri goldenKey, bool? updateGoldens) async {
final File imageFile = await (await tempDir.createTemp('image')).childFile('image').writeAsBytes(bytes); final File imageFile = await (await tempDir.createTemp('image')).childFile('image').writeAsBytes(bytes);
final TestGoldenComparatorProcess process = await _processForTestFile(testUri); final TestGoldenComparatorProcess process = await (_processForTestFile(testUri) as FutureOr<TestGoldenComparatorProcess>);
process.sendCommand(imageFile, goldenKey, updateGoldens); process.sendCommand(imageFile, goldenKey, updateGoldens);
final Map<String, dynamic> result = await process.getResponse(); final Map<String, dynamic> result = await process.getResponse();
@ -105,7 +108,7 @@ class TestGoldenComparator {
if (result == null) { if (result == null) {
return 'unknown error'; return 'unknown error';
} else { } else {
return (result['success'] as bool) ? null : ((result['message'] as String) ?? 'does not match'); return (result['success'] as bool) ? null : ((result['message'] as String?) ?? 'does not match');
} }
} }
} }
@ -114,7 +117,7 @@ class TestGoldenComparator {
/// handles communication with the child process. /// handles communication with the child process.
class TestGoldenComparatorProcess { class TestGoldenComparatorProcess {
/// Creates a [TestGoldenComparatorProcess] backed by [process]. /// Creates a [TestGoldenComparatorProcess] backed by [process].
TestGoldenComparatorProcess(this.process, {@required Logger logger}) : _logger = logger { TestGoldenComparatorProcess(this.process, {required Logger logger}) : _logger = logger {
// Pipe stdout and stderr to printTrace and printError. // Pipe stdout and stderr to printTrace and printError.
// Also parse stdout as a stream of JSON objects. // Also parse stdout as a stream of JSON objects.
streamIterator = StreamIterator<Map<String, dynamic>>( streamIterator = StreamIterator<Map<String, dynamic>>(
@ -138,14 +141,14 @@ class TestGoldenComparatorProcess {
final Logger _logger; final Logger _logger;
final Process process; final Process process;
StreamIterator<Map<String, dynamic>> streamIterator; late StreamIterator<Map<String, dynamic>> streamIterator;
Future<void> close() async { Future<void> close() async {
process.kill(); process.kill();
await process.exitCode; await process.exitCode;
} }
void sendCommand(File imageFile, Uri goldenKey, bool updateGoldens) { void sendCommand(File imageFile, Uri? goldenKey, bool? updateGoldens) {
final Object command = jsonEncode(<String, dynamic>{ final Object command = jsonEncode(<String, dynamic>{
'imageFile': imageFile.path, 'imageFile': imageFile.path,
'key': goldenKey.toString(), 'key': goldenKey.toString(),
@ -161,8 +164,8 @@ class TestGoldenComparatorProcess {
return streamIterator.current; return streamIterator.current;
} }
static String generateBootstrap(File testFile, Uri testUri, {@required Logger logger}) { static String generateBootstrap(File testFile, Uri testUri, {required Logger logger}) {
final File testConfigFile = findTestConfigFile(testFile, logger); final File? testConfigFile = findTestConfigFile(testFile, logger);
// Generate comparator process for the file. // Generate comparator process for the file.
return ''' return '''
import 'dart:convert'; // flutter_ignore: dart_convert_import import 'dart:convert'; // flutter_ignore: dart_convert_import

View File

@ -2,14 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:async/async.dart'; import 'package:async/async.dart';
import 'package:http_multi_server/http_multi_server.dart'; import 'package:http_multi_server/http_multi_server.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config.dart'; import 'package:package_config/package_config.dart';
import 'package:pool/pool.dart'; import 'package:pool/pool.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
@ -41,19 +38,19 @@ import 'test_compiler.dart';
class FlutterWebPlatform extends PlatformPlugin { class FlutterWebPlatform extends PlatformPlugin {
FlutterWebPlatform._(this._server, this._config, this._root, { FlutterWebPlatform._(this._server, this._config, this._root, {
FlutterProject flutterProject, FlutterProject? flutterProject,
String shellPath, String? shellPath,
this.updateGoldens, this.updateGoldens,
this.nullAssertions, this.nullAssertions,
@required this.buildInfo, required this.buildInfo,
@required this.webMemoryFS, required this.webMemoryFS,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required PackageConfig flutterToolPackageConfig, required PackageConfig flutterToolPackageConfig,
@required ChromiumLauncher chromiumLauncher, required ChromiumLauncher chromiumLauncher,
@required Logger logger, required Logger logger,
@required Artifacts artifacts, required Artifacts? artifacts,
@required ProcessManager processManager, required ProcessManager processManager,
@required Cache cache, required Cache cache,
}) : _fileSystem = fileSystem, }) : _fileSystem = fileSystem,
_flutterToolPackageConfig = flutterToolPackageConfig, _flutterToolPackageConfig = flutterToolPackageConfig,
_chromiumLauncher = chromiumLauncher, _chromiumLauncher = chromiumLauncher,
@ -63,7 +60,7 @@ class FlutterWebPlatform extends PlatformPlugin {
final shelf.Cascade cascade = shelf.Cascade() final shelf.Cascade cascade = shelf.Cascade()
.add(_webSocketHandler.handler) .add(_webSocketHandler.handler)
.add(createStaticHandler( .add(createStaticHandler(
fileSystem.path.join(Cache.flutterRoot, 'packages', 'flutter_tools'), fileSystem.path.join(Cache.flutterRoot!, 'packages', 'flutter_tools'),
serveFilesOutsidePath: true, serveFilesOutsidePath: true,
)) ))
.add(_handleStaticArtifact) .add(_handleStaticArtifact)
@ -93,9 +90,9 @@ class FlutterWebPlatform extends PlatformPlugin {
final PackageConfig _flutterToolPackageConfig; final PackageConfig _flutterToolPackageConfig;
final ChromiumLauncher _chromiumLauncher; final ChromiumLauncher _chromiumLauncher;
final Logger _logger; final Logger _logger;
final Artifacts _artifacts; final Artifacts? _artifacts;
final bool updateGoldens; final bool? updateGoldens;
final bool nullAssertions; final bool? nullAssertions;
final OneOffHandler _webSocketHandler = OneOffHandler(); final OneOffHandler _webSocketHandler = OneOffHandler();
final AsyncMemoizer<void> _closeMemo = AsyncMemoizer<void>(); final AsyncMemoizer<void> _closeMemo = AsyncMemoizer<void>();
final String _root; final String _root;
@ -106,28 +103,28 @@ class FlutterWebPlatform extends PlatformPlugin {
/// to lead to flaky tests. /// to lead to flaky tests.
final Pool _suiteLock = Pool(1); final Pool _suiteLock = Pool(1);
BrowserManager _browserManager; BrowserManager? _browserManager;
TestGoldenComparator _testGoldenComparator; late TestGoldenComparator _testGoldenComparator;
static Future<FlutterWebPlatform> start(String root, { static Future<FlutterWebPlatform> start(String root, {
FlutterProject flutterProject, FlutterProject? flutterProject,
String shellPath, String? shellPath,
bool updateGoldens = false, bool updateGoldens = false,
bool pauseAfterLoad = false, bool pauseAfterLoad = false,
bool nullAssertions = false, bool nullAssertions = false,
@required BuildInfo buildInfo, required BuildInfo buildInfo,
@required WebMemoryFS webMemoryFS, required WebMemoryFS webMemoryFS,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required Logger logger, required Logger logger,
@required ChromiumLauncher chromiumLauncher, required ChromiumLauncher chromiumLauncher,
@required Artifacts artifacts, required Artifacts? artifacts,
@required ProcessManager processManager, required ProcessManager processManager,
@required Cache cache, required Cache cache,
}) async { }) async {
final shelf_io.IOServer server = shelf_io.IOServer(await HttpMultiServer.loopback(0)); final shelf_io.IOServer server = shelf_io.IOServer(await HttpMultiServer.loopback(0));
final PackageConfig packageConfig = await loadPackageConfigWithLogging( final PackageConfig packageConfig = await loadPackageConfigWithLogging(
fileSystem.file(fileSystem.path.join( fileSystem.file(fileSystem.path.join(
Cache.flutterRoot, Cache.flutterRoot!,
'packages', 'packages',
'flutter_tools', 'flutter_tools',
'.dart_tool', '.dart_tool',
@ -158,7 +155,7 @@ class FlutterWebPlatform extends PlatformPlugin {
bool get _closed => _closeMemo.hasRun; bool get _closed => _closeMemo.hasRun;
/// Uri of the test package. /// Uri of the test package.
Uri get testUri => _flutterToolPackageConfig['test'].packageUriRoot; Uri get testUri => _flutterToolPackageConfig['test']!.packageUriRoot;
WebRendererMode get _rendererMode { WebRendererMode get _rendererMode {
return buildInfo.dartDefines.contains('FLUTTER_WEB_USE_SKIA=true') return buildInfo.dartDefines.contains('FLUTTER_WEB_USE_SKIA=true')
@ -178,7 +175,7 @@ class FlutterWebPlatform extends PlatformPlugin {
/// The ahem text file. /// The ahem text file.
File get _ahem => _fileSystem.file(_fileSystem.path.join( File get _ahem => _fileSystem.file(_fileSystem.path.join(
Cache.flutterRoot, Cache.flutterRoot!,
'packages', 'packages',
'flutter_tools', 'flutter_tools',
'static', 'static',
@ -187,7 +184,7 @@ class FlutterWebPlatform extends PlatformPlugin {
/// The require js binary. /// The require js binary.
File get _requireJs => _fileSystem.file(_fileSystem.path.join( File get _requireJs => _fileSystem.file(_fileSystem.path.join(
_artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, _artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path,
'lib', 'lib',
'dev_compiler', 'dev_compiler',
'kernel', 'kernel',
@ -197,7 +194,7 @@ class FlutterWebPlatform extends PlatformPlugin {
/// The ddc to dart stack trace mapper. /// The ddc to dart stack trace mapper.
File get _stackTraceMapper => _fileSystem.file(_fileSystem.path.join( File get _stackTraceMapper => _fileSystem.file(_fileSystem.path.join(
_artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, _artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path,
'lib', 'lib',
'dev_compiler', 'dev_compiler',
'web', 'web',
@ -205,10 +202,10 @@ class FlutterWebPlatform extends PlatformPlugin {
)); ));
File get _dartSdk => _fileSystem.file( File get _dartSdk => _fileSystem.file(
_artifacts.getHostArtifact(kDartSdkJsArtifactMap[_rendererMode][_nullSafetyMode])); _artifacts!.getHostArtifact(kDartSdkJsArtifactMap[_rendererMode]![_nullSafetyMode]!));
File get _dartSdkSourcemaps => _fileSystem.file( File get _dartSdkSourcemaps => _fileSystem.file(
_artifacts.getHostArtifact(kDartSdkJsMapArtifactMap[_rendererMode][_nullSafetyMode])); _artifacts!.getHostArtifact(kDartSdkJsMapArtifactMap[_rendererMode]![_nullSafetyMode]!));
/// The precompiled test javascript. /// The precompiled test javascript.
File get _testDartJs => _fileSystem.file(_fileSystem.path.join( File get _testDartJs => _fileSystem.file(_fileSystem.path.join(
@ -254,7 +251,7 @@ class FlutterWebPlatform extends PlatformPlugin {
final String leadingPath = request.url.path.split('.dart.bootstrap.js')[0]; final String leadingPath = request.url.path.split('.dart.bootstrap.js')[0];
final String generatedFile = '${_fileSystem.path.split(leadingPath).join('_')}.dart.test.dart.js'; final String generatedFile = '${_fileSystem.path.split(leadingPath).join('_')}.dart.test.dart.js';
return shelf.Response.ok(generateMainModule( return shelf.Response.ok(generateMainModule(
nullAssertions: nullAssertions, nullAssertions: nullAssertions!,
nativeNullAssertions: true, nativeNullAssertions: true,
bootstrapModule: '${_fileSystem.path.basename(leadingPath)}.dart.bootstrap', bootstrapModule: '${_fileSystem.path.basename(leadingPath)}.dart.bootstrap',
entrypoint: '/$generatedFile' entrypoint: '/$generatedFile'
@ -317,7 +314,7 @@ class FlutterWebPlatform extends PlatformPlugin {
FutureOr<shelf.Response> _packageFilesHandler(shelf.Request request) async { FutureOr<shelf.Response> _packageFilesHandler(shelf.Request request) async {
if (request.requestedUri.pathSegments.first == 'packages') { if (request.requestedUri.pathSegments.first == 'packages') {
final Uri fileUri = buildInfo.packageConfig.resolve(Uri( final Uri? fileUri = buildInfo.packageConfig.resolve(Uri(
scheme: 'package', scheme: 'package',
pathSegments: request.requestedUri.pathSegments.skip(1), pathSegments: request.requestedUri.pathSegments.skip(1),
)); ));
@ -344,16 +341,16 @@ class FlutterWebPlatform extends PlatformPlugin {
Future<shelf.Response> _goldenFileHandler(shelf.Request request) async { Future<shelf.Response> _goldenFileHandler(shelf.Request request) async {
if (request.url.path.contains('flutter_goldens')) { if (request.url.path.contains('flutter_goldens')) {
final Map<String, Object> body = json.decode(await request.readAsString()) as Map<String, Object>; final Map<String, Object> body = json.decode(await request.readAsString()) as Map<String, Object>;
final Uri goldenKey = Uri.parse(body['key'] as String); final Uri goldenKey = Uri.parse(body['key']! as String);
final Uri testUri = Uri.parse(body['testUri'] as String); final Uri testUri = Uri.parse(body['testUri']! as String);
final num width = body['width'] as num; final num width = body['width']! as num;
final num height = body['height'] as num; final num height = body['height']! as num;
Uint8List bytes; Uint8List bytes;
try { try {
final ChromeTab chromeTab = await _browserManager._browser.chromeConnection.getTab((ChromeTab tab) { final ChromeTab chromeTab = await (_browserManager!._browser.chromeConnection.getTab((ChromeTab tab) {
return tab.url.contains(_browserManager._browser.url); return tab.url.contains(_browserManager!._browser.url!);
}); }) as FutureOr<ChromeTab>);
final WipConnection connection = await chromeTab.connect(); final WipConnection connection = await chromeTab.connect();
final WipResponse response = await connection.sendCommand('Page.captureScreenshot', <String, Object>{ final WipResponse response = await connection.sendCommand('Page.captureScreenshot', <String, Object>{
// Clip the screenshot to include only the element. // Clip the screenshot to include only the element.
@ -369,7 +366,7 @@ class FlutterWebPlatform extends PlatformPlugin {
'scale': 1.0, 'scale': 1.0,
}, },
}); });
bytes = base64.decode(response.result['data'] as String); bytes = base64.decode(response.result!['data'] as String);
} on WipError catch (ex) { } on WipError catch (ex) {
_logger.printError('Caught WIPError: $ex'); _logger.printError('Caught WIPError: $ex');
return shelf.Response.ok('WIP error: $ex'); return shelf.Response.ok('WIP error: $ex');
@ -382,7 +379,7 @@ class FlutterWebPlatform extends PlatformPlugin {
return shelf.Response.ok('Unknown error, bytes is null'); return shelf.Response.ok('Unknown error, bytes is null');
} }
final String errorMessage = await _testGoldenComparator.compareGoldens(testUri, bytes, goldenKey, updateGoldens); final String? errorMessage = await _testGoldenComparator.compareGoldens(testUri, bytes, goldenKey, updateGoldens);
return shelf.Response.ok(errorMessage ?? 'true'); return shelf.Response.ok(errorMessage ?? 'true');
} else { } else {
return shelf.Response.notFound('Not Found'); return shelf.Response.notFound('Not Found');
@ -473,8 +470,8 @@ class FlutterWebPlatform extends PlatformPlugin {
final String pathFromTest = _fileSystem.path.relative(path, from: _fileSystem.path.join(_root, 'test')); final String pathFromTest = _fileSystem.path.relative(path, from: _fileSystem.path.join(_root, 'test'));
final Uri suiteUrl = url.resolveUri(_fileSystem.path.toUri('${_fileSystem.path.withoutExtension(pathFromTest)}.html')); final Uri suiteUrl = url.resolveUri(_fileSystem.path.toUri('${_fileSystem.path.withoutExtension(pathFromTest)}.html'));
final String relativePath = _fileSystem.path.relative(_fileSystem.path.normalize(path), from: _fileSystem.currentDirectory.path); final String relativePath = _fileSystem.path.relative(_fileSystem.path.normalize(path), from: _fileSystem.currentDirectory.path);
final RunnerSuite suite = await _browserManager.load(relativePath, suiteUrl, suiteConfig, message, onDone: () async { final RunnerSuite suite = await _browserManager!.load(relativePath, suiteUrl, suiteConfig, message, onDone: () async {
await _browserManager.close(); await _browserManager!.close();
_browserManager = null; _browserManager = null;
lockResource.release(); lockResource.release();
}); });
@ -516,7 +513,7 @@ class FlutterWebPlatform extends PlatformPlugin {
@override @override
Future<void> closeEphemeral() async { Future<void> closeEphemeral() async {
if (_browserManager != null) { if (_browserManager != null) {
await _browserManager.close(); await _browserManager!.close();
} }
} }
@ -524,7 +521,7 @@ class FlutterWebPlatform extends PlatformPlugin {
Future<void> close() => _closeMemo.runOnce(() async { Future<void> close() => _closeMemo.runOnce(() async {
await Future.wait<void>(<Future<dynamic>>[ await Future.wait<void>(<Future<dynamic>>[
if (_browserManager != null) if (_browserManager != null)
_browserManager.close(), _browserManager!.close(),
_server.close(), _server.close(),
_testGoldenComparator.close(), _testGoldenComparator.close(),
]); ]);
@ -561,7 +558,7 @@ class OneOffHandler {
return shelf.Response.notFound(null); return shelf.Response.notFound(null);
} }
final String path = components.removeAt(0); final String path = components.removeAt(0);
final FutureOr<shelf.Response> Function(shelf.Request) handler = final FutureOr<shelf.Response> Function(shelf.Request)? handler =
_handlers.remove(path); _handlers.remove(path);
if (handler == null) { if (handler == null) {
return shelf.Response.notFound(null); return shelf.Response.notFound(null);
@ -590,8 +587,8 @@ class BrowserManager {
// Whenever we get a message, no matter which child channel it's for, we know // Whenever we get a message, no matter which child channel it's for, we know
// the browser is still running code which means the user isn't debugging. // the browser is still running code which means the user isn't debugging.
_channel = MultiChannel<dynamic>( _channel = MultiChannel<dynamic>(
webSocket.cast<String>().transform(jsonDocument).changeStream((Stream<Object> stream) { webSocket.cast<String>().transform(jsonDocument).changeStream((Stream<Object?> stream) {
return stream.map((Object message) { return stream.map((Object? message) {
if (!_closed) { if (!_closed) {
_timer.reset(); _timer.reset();
} }
@ -615,7 +612,7 @@ class BrowserManager {
/// The channel used to communicate with the browser. /// The channel used to communicate with the browser.
/// ///
/// This is connected to a page running `static/host.dart`. /// This is connected to a page running `static/host.dart`.
MultiChannel<dynamic> _channel; late MultiChannel<dynamic> _channel;
/// The ID of the next suite to be loaded. /// The ID of the next suite to be loaded.
/// ///
@ -630,14 +627,14 @@ class BrowserManager {
/// ///
/// This will be `null` as long as the browser isn't displaying a pause /// This will be `null` as long as the browser isn't displaying a pause
/// screen. /// screen.
CancelableCompleter<dynamic> _pauseCompleter; CancelableCompleter<dynamic>? _pauseCompleter;
/// The controller for [_BrowserEnvironment.onRestart]. /// The controller for [_BrowserEnvironment.onRestart].
final StreamController<dynamic> _onRestartController = final StreamController<dynamic> _onRestartController =
StreamController<dynamic>.broadcast(); StreamController<dynamic>.broadcast();
/// The environment to attach to each suite. /// The environment to attach to each suite.
Future<_BrowserEnvironment> _environment; late Future<_BrowserEnvironment> _environment;
/// Controllers for every suite in this browser. /// Controllers for every suite in this browser.
/// ///
@ -649,7 +646,7 @@ class BrowserManager {
// //
// Because the browser stops running code when the user is actively debugging, // Because the browser stops running code when the user is actively debugging,
// this lets us detect whether they're debugging reasonably accurately. // this lets us detect whether they're debugging reasonably accurately.
RestartableTimer _timer; late RestartableTimer _timer;
final AsyncMemoizer<dynamic> _closeMemoizer = AsyncMemoizer<dynamic>(); final AsyncMemoizer<dynamic> _closeMemoizer = AsyncMemoizer<dynamic>();
@ -677,25 +674,23 @@ class BrowserManager {
final Chromium chrome = await chromiumLauncher.launch(url.toString(), headless: headless); final Chromium chrome = await chromiumLauncher.launch(url.toString(), headless: headless);
final Completer<BrowserManager> completer = Completer<BrowserManager>(); final Completer<BrowserManager> completer = Completer<BrowserManager>();
unawaited(chrome.onExit.then((int browserExitCode) { unawaited(chrome.onExit.then((int? browserExitCode) {
throwToolExit('${runtime.name} exited with code $browserExitCode before connecting.'); throwToolExit('${runtime.name} exited with code $browserExitCode before connecting.');
}).catchError((dynamic error, StackTrace stackTrace) { }).catchError((Object error, StackTrace stackTrace) {
if (completer.isCompleted) { if (!completer.isCompleted) {
return null; completer.completeError(error, stackTrace);
} }
completer.completeError(error, stackTrace);
})); }));
unawaited(future.then((WebSocketChannel webSocket) { unawaited(future.then((WebSocketChannel webSocket) {
if (completer.isCompleted) { if (completer.isCompleted) {
return; return;
} }
completer.complete(BrowserManager._(chrome, runtime, webSocket)); completer.complete(BrowserManager._(chrome, runtime, webSocket));
}).catchError((dynamic error, StackTrace stackTrace) { }).catchError((Object error, StackTrace stackTrace) {
chrome.close(); chrome.close();
if (completer.isCompleted) { if (!completer.isCompleted) {
return null; completer.completeError(error, stackTrace);
} }
completer.completeError(error, stackTrace);
})); }));
return completer.future; return completer.future;
@ -720,7 +715,7 @@ class BrowserManager {
Uri url, Uri url,
SuiteConfiguration suiteConfig, SuiteConfiguration suiteConfig,
Object message, { Object message, {
Future<void> Function() onDone, Future<void> Function()? onDone,
} }
) async { ) async {
url = url.replace(fragment: Uri.encodeFull(jsonEncode(<String, Object>{ url = url.replace(fragment: Uri.encodeFull(jsonEncode(<String, Object>{
@ -729,7 +724,7 @@ class BrowserManager {
}))); })));
final int suiteID = _suiteID++; final int suiteID = _suiteID++;
RunnerSuiteController controller; RunnerSuiteController? controller;
void closeIframe() { void closeIframe() {
if (_closed) { if (_closed) {
return; return;
@ -747,7 +742,7 @@ class BrowserManager {
StreamTransformer<dynamic, dynamic>.fromHandlers(handleDone: (EventSink<dynamic> sink) { StreamTransformer<dynamic, dynamic>.fromHandlers(handleDone: (EventSink<dynamic> sink) {
closeIframe(); closeIframe();
sink.close(); sink.close();
onDone(); onDone!();
}), }),
); );
@ -774,25 +769,25 @@ class BrowserManager {
/// An implementation of [Environment.displayPause]. /// An implementation of [Environment.displayPause].
CancelableOperation<dynamic> _displayPause() { CancelableOperation<dynamic> _displayPause() {
if (_pauseCompleter != null) { if (_pauseCompleter != null) {
return _pauseCompleter.operation; return _pauseCompleter!.operation;
} }
_pauseCompleter = CancelableCompleter<dynamic>(onCancel: () { _pauseCompleter = CancelableCompleter<dynamic>(onCancel: () {
_channel.sink.add(<String, String>{'command': 'resume'}); _channel.sink.add(<String, String>{'command': 'resume'});
_pauseCompleter = null; _pauseCompleter = null;
}); });
_pauseCompleter.operation.value.whenComplete(() { _pauseCompleter!.operation.value.whenComplete(() {
_pauseCompleter = null; _pauseCompleter = null;
}); });
_channel.sink.add(<String, String>{'command': 'displayPause'}); _channel.sink.add(<String, String>{'command': 'displayPause'});
return _pauseCompleter.operation; return _pauseCompleter!.operation;
} }
/// The callback for handling messages received from the host page. /// The callback for handling messages received from the host page.
void _onMessage(dynamic message) { void _onMessage(dynamic message) {
assert(message is Map<String, dynamic>); assert(message is Map<String, dynamic>);
if (message is Map<String, dynamic>) { if (message is Map<String, dynamic>) {
switch (message['command'] as String) { switch (message['command'] as String?) {
case 'ping': case 'ping':
break; break;
case 'restart': case 'restart':
@ -800,7 +795,7 @@ class BrowserManager {
break; break;
case 'resume': case 'resume':
if (_pauseCompleter != null) { if (_pauseCompleter != null) {
_pauseCompleter.complete(); _pauseCompleter!.complete();
} }
break; break;
default: default:
@ -818,7 +813,7 @@ class BrowserManager {
_closed = true; _closed = true;
_timer.cancel(); _timer.cancel();
if (_pauseCompleter != null) { if (_pauseCompleter != null) {
_pauseCompleter.complete(); _pauseCompleter!.complete();
} }
_pauseCompleter = null; _pauseCompleter = null;
_controllers.clear(); _controllers.clear();
@ -844,7 +839,7 @@ class _BrowserEnvironment implements Environment {
final bool supportsDebugging = true; final bool supportsDebugging = true;
@override @override
final Uri observatoryUrl; final Uri? observatoryUrl;
@override @override
final Uri remoteDebuggerUrl; final Uri remoteDebuggerUrl;

View File

@ -29,7 +29,7 @@ class IntegrationTestTestDevice implements TestDevice {
final int id; final int id;
final Device device; final Device device;
final DebuggingOptions debuggingOptions; final DebuggingOptions debuggingOptions;
final String userIdentifier; final String? userIdentifier;
ApplicationPackage? _applicationPackage; ApplicationPackage? _applicationPackage;
final Completer<void> _finished = Completer<void>(); final Completer<void> _finished = Completer<void>();
@ -50,7 +50,7 @@ class IntegrationTestTestDevice implements TestDevice {
} }
final LaunchResult launchResult = await device.startApp( final LaunchResult launchResult = await device.startApp(
_applicationPackage!, _applicationPackage,
mainPath: entrypointPath, mainPath: entrypointPath,
platformArgs: <String, dynamic>{}, platformArgs: <String, dynamic>{},
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,

View File

@ -2,10 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:meta/meta.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
@ -29,32 +25,32 @@ abstract class FlutterTestRunner {
Future<int> runTests( Future<int> runTests(
TestWrapper testWrapper, TestWrapper testWrapper,
List<String> testFiles, { List<String> testFiles, {
@required DebuggingOptions debuggingOptions, required DebuggingOptions debuggingOptions,
List<String> names = const <String>[], List<String> names = const <String>[],
List<String> plainNames = const <String>[], List<String> plainNames = const <String>[],
String tags, String? tags,
String excludeTags, String? excludeTags,
bool enableObservatory = false, bool enableObservatory = false,
bool ipv6 = false, bool ipv6 = false,
bool machine = false, bool machine = false,
String precompiledDillPath, String? precompiledDillPath,
Map<String, String> precompiledDillFiles, Map<String, String>? precompiledDillFiles,
bool updateGoldens = false, bool updateGoldens = false,
TestWatcher watcher, TestWatcher? watcher,
@required int concurrency, required int? concurrency,
String testAssetDirectory, String? testAssetDirectory,
FlutterProject flutterProject, FlutterProject? flutterProject,
String icudtlPath, String? icudtlPath,
Directory coverageDirectory, Directory? coverageDirectory,
bool web = false, bool web = false,
String randomSeed, String? randomSeed,
String reporter, String? reporter,
String timeout, String? timeout,
bool runSkipped = false, bool runSkipped = false,
int shardIndex, int? shardIndex,
int totalShards, int? totalShards,
Device integrationTestDevice, Device? integrationTestDevice,
String integrationTestUserIdentifier, String? integrationTestUserIdentifier,
}); });
} }
@ -65,35 +61,35 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
Future<int> runTests( Future<int> runTests(
TestWrapper testWrapper, TestWrapper testWrapper,
List<String> testFiles, { List<String> testFiles, {
@required DebuggingOptions debuggingOptions, required DebuggingOptions debuggingOptions,
List<String> names = const <String>[], List<String> names = const <String>[],
List<String> plainNames = const <String>[], List<String> plainNames = const <String>[],
String tags, String? tags,
String excludeTags, String? excludeTags,
bool enableObservatory = false, bool enableObservatory = false,
bool ipv6 = false, bool ipv6 = false,
bool machine = false, bool machine = false,
String precompiledDillPath, String? precompiledDillPath,
Map<String, String> precompiledDillFiles, Map<String, String>? precompiledDillFiles,
bool updateGoldens = false, bool updateGoldens = false,
TestWatcher watcher, TestWatcher? watcher,
@required int concurrency, required int? concurrency,
String testAssetDirectory, String? testAssetDirectory,
FlutterProject flutterProject, FlutterProject? flutterProject,
String icudtlPath, String? icudtlPath,
Directory coverageDirectory, Directory? coverageDirectory,
bool web = false, bool web = false,
String randomSeed, String? randomSeed,
String reporter, String? reporter,
String timeout, String? timeout,
bool runSkipped = false, bool runSkipped = false,
int shardIndex, int? shardIndex,
int totalShards, int? totalShards,
Device integrationTestDevice, Device? integrationTestDevice,
String integrationTestUserIdentifier, String? integrationTestUserIdentifier,
}) async { }) async {
// Configure package:test to use the Flutter engine for child processes. // Configure package:test to use the Flutter engine for child processes.
final String shellPath = globals.artifacts.getArtifactPath(Artifact.flutterTester); final String shellPath = globals.artifacts!.getArtifactPath(Artifact.flutterTester);
// Compute the command-line arguments for package:test. // Compute the command-line arguments for package:test.
final List<String> testArgs = <String>[ final List<String> testArgs = <String>[
@ -136,11 +132,11 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
logger: globals.logger, logger: globals.logger,
fileSystem: globals.fs, fileSystem: globals.fs,
platform: globals.platform, platform: globals.platform,
artifacts: globals.artifacts, artifacts: globals.artifacts!,
processManager: globals.processManager, processManager: globals.processManager,
config: globals.config, config: globals.config,
).initialize( ).initialize(
projectDirectory: flutterProject.directory, projectDirectory: flutterProject!.directory,
testOutputDir: tempBuildDir, testOutputDir: tempBuildDir,
testFiles: testFiles, testFiles: testFiles,
buildInfo: debuggingOptions.buildInfo, buildInfo: debuggingOptions.buildInfo,

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
@ -22,7 +22,7 @@ class CompilationRequest {
CompilationRequest(this.mainUri, this.result); CompilationRequest(this.mainUri, this.result);
Uri mainUri; Uri mainUri;
Completer<String> result; Completer<String?> result;
} }
/// A frontend_server wrapper for the flutter test runner. /// A frontend_server wrapper for the flutter test runner.
@ -43,9 +43,9 @@ class TestCompiler {
TestCompiler( TestCompiler(
this.buildInfo, this.buildInfo,
this.flutterProject, this.flutterProject,
{ String precompiledDillPath } { String? precompiledDillPath }
) : testFilePath = precompiledDillPath ?? globals.fs.path.join( ) : testFilePath = precompiledDillPath ?? globals.fs.path.join(
flutterProject.directory.path, flutterProject!.directory.path,
getBuildDirectory(), getBuildDirectory(),
'test_cache', 'test_cache',
getDefaultCachedKernelPath( getDefaultCachedKernelPath(
@ -69,19 +69,19 @@ class TestCompiler {
final StreamController<CompilationRequest> compilerController = StreamController<CompilationRequest>(); final StreamController<CompilationRequest> compilerController = StreamController<CompilationRequest>();
final List<CompilationRequest> compilationQueue = <CompilationRequest>[]; final List<CompilationRequest> compilationQueue = <CompilationRequest>[];
final FlutterProject flutterProject; final FlutterProject? flutterProject;
final BuildInfo buildInfo; final BuildInfo buildInfo;
final String testFilePath; final String testFilePath;
final bool shouldCopyDillFile; final bool shouldCopyDillFile;
ResidentCompiler compiler; ResidentCompiler? compiler;
File outputDill; late File outputDill;
Future<String> compile(Uri mainDart) { Future<String?> compile(Uri mainDart) {
final Completer<String> completer = Completer<String>(); final Completer<String> completer = Completer<String>();
if (compilerController.isClosed) { if (compilerController.isClosed) {
return Future<String>.value(); return Future<String?>.value();
} }
compilerController.add(CompilationRequest(mainDart, completer)); compilerController.add(CompilationRequest(mainDart, completer));
return completer.future; return completer.future;
@ -91,7 +91,7 @@ class TestCompiler {
// Check for null in case this instance is shut down before the // Check for null in case this instance is shut down before the
// lazily-created compiler has been created. // lazily-created compiler has been created.
if (compiler != null) { if (compiler != null) {
await compiler.shutdown(); await compiler!.shutdown();
compiler = null; compiler = null;
} }
} }
@ -103,10 +103,10 @@ class TestCompiler {
/// Create the resident compiler used to compile the test. /// Create the resident compiler used to compile the test.
@visibleForTesting @visibleForTesting
Future<ResidentCompiler> createCompiler() async { Future<ResidentCompiler?> createCompiler() async {
final ResidentCompiler residentCompiler = ResidentCompiler( final ResidentCompiler residentCompiler = ResidentCompiler(
globals.artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath), globals.artifacts!.getArtifactPath(Artifact.flutterPatchedSdkPath),
artifacts: globals.artifacts, artifacts: globals.artifacts!,
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
buildMode: buildInfo.mode, buildMode: buildInfo.mode,
@ -151,31 +151,30 @@ class TestCompiler {
final String mainUriString = buildInfo.packageConfig.toPackageUri(request.mainUri)?.toString() final String mainUriString = buildInfo.packageConfig.toPackageUri(request.mainUri)?.toString()
?? request.mainUri.toString(); ?? request.mainUri.toString();
await generateMainDartWithPluginRegistrant( await generateMainDartWithPluginRegistrant(
flutterProject, flutterProject!,
buildInfo.packageConfig, buildInfo.packageConfig,
mainUriString, mainUriString,
globals.fs.file(request.mainUri), globals.fs.file(request.mainUri),
throwOnPluginPubspecError: false,
); );
invalidatedRegistrantFiles.add(flutterProject.dartPluginRegistrant.absolute.uri); invalidatedRegistrantFiles.add(flutterProject!.dartPluginRegistrant.absolute.uri);
} }
final CompilerOutput compilerOutput = await compiler.recompile( final CompilerOutput? compilerOutput = await compiler!.recompile(
request.mainUri, request.mainUri,
<Uri>[request.mainUri, ...invalidatedRegistrantFiles], <Uri>[request.mainUri, ...invalidatedRegistrantFiles],
outputPath: outputDill.path, outputPath: outputDill.path,
packageConfig: buildInfo.packageConfig, packageConfig: buildInfo.packageConfig,
projectRootPath: flutterProject?.directory?.absolute?.path, projectRootPath: flutterProject?.directory.absolute.path,
checkDartPluginRegistry: true, checkDartPluginRegistry: true,
fs: globals.fs, fs: globals.fs,
); );
final String outputPath = compilerOutput?.outputFilename; final String? outputPath = compilerOutput?.outputFilename;
// In case compiler didn't produce output or reported compilation // In case compiler didn't produce output or reported compilation
// errors, pass [null] upwards to the consumer and shutdown the // errors, pass [null] upwards to the consumer and shutdown the
// compiler to avoid reusing compiler that might have gotten into // compiler to avoid reusing compiler that might have gotten into
// a weird state. // a weird state.
if (outputPath == null || compilerOutput.errorCount > 0) { if (outputPath == null || compilerOutput!.errorCount > 0) {
request.result.complete(null); request.result.complete(null);
await _shutdown(); await _shutdown();
} else { } else {
@ -197,8 +196,8 @@ class TestCompiler {
} else { } else {
request.result.complete(outputPath); request.result.complete(outputPath);
} }
compiler.accept(); compiler!.accept();
compiler.reset(); compiler!.reset();
} }
globals.printTrace('Compiling ${request.mainUri} took ${compilerTime.elapsedMilliseconds}ms'); globals.printTrace('Compiling ${request.mainUri} took ${compilerTime.elapsedMilliseconds}ms');
// Only remove now when we finished processing the element // Only remove now when we finished processing the element

View File

@ -99,7 +99,7 @@ typedef CompileExpression = Future<String> Function(
/// A method that pulls an SkSL shader from the device and writes it to a file. /// A method that pulls an SkSL shader from the device and writes it to a file.
/// ///
/// The name of the file returned as a result. /// The name of the file returned as a result.
typedef GetSkSLMethod = Future<String> Function(); typedef GetSkSLMethod = Future<String?> Function();
Future<io.WebSocket> _defaultOpenChannel(String url, { Future<io.WebSocket> _defaultOpenChannel(String url, {
io.CompressionOptions compression = io.CompressionOptions.compressionDefault, io.CompressionOptions compression = io.CompressionOptions.compressionDefault,
@ -265,7 +265,14 @@ Future<vm_service.VmService> setUpVmService(
} }
if (skSLMethod != null) { if (skSLMethod != null) {
vmService.registerServiceCallback('flutterGetSkSL', (Map<String, Object?> params) async { vmService.registerServiceCallback('flutterGetSkSL', (Map<String, Object?> params) async {
final String filename = await skSLMethod(); final String? filename = await skSLMethod();
if (filename == null) {
return <String, Object>{
'result': <String, Object>{
'type': 'Success',
},
};
}
return <String, Object>{ return <String, Object>{
'result': <String, Object>{ 'result': <String, Object>{
'type': 'Success', 'type': 'Success',

View File

@ -2,10 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'package:meta/meta.dart';
import '../base/context.dart'; import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/logger.dart'; import '../base/logger.dart';
@ -16,7 +12,7 @@ import '../project.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
import '../resident_runner.dart'; import '../resident_runner.dart';
WebRunnerFactory get webRunnerFactory => context.get<WebRunnerFactory>(); WebRunnerFactory? get webRunnerFactory => context.get<WebRunnerFactory>();
// Hack to hide web imports for google3. // Hack to hide web imports for google3.
abstract class WebRunnerFactory { abstract class WebRunnerFactory {
@ -25,16 +21,16 @@ abstract class WebRunnerFactory {
/// Create a [ResidentRunner] for the web. /// Create a [ResidentRunner] for the web.
ResidentRunner createWebRunner( ResidentRunner createWebRunner(
FlutterDevice device, { FlutterDevice device, {
String target, String? target,
@required bool stayResident, required bool stayResident,
@required FlutterProject flutterProject, required FlutterProject flutterProject,
@required bool ipv6, required bool? ipv6,
@required DebuggingOptions debuggingOptions, required DebuggingOptions debuggingOptions,
@required UrlTunneller urlTunneller, required UrlTunneller? urlTunneller,
@required Logger logger, required Logger? logger,
@required FileSystem fileSystem, required FileSystem fileSystem,
@required SystemClock systemClock, required SystemClock systemClock,
@required Usage usage, required Usage usage,
bool machine = false, bool machine = false,
}); });
} }

View File

@ -173,14 +173,6 @@ void main() {
await device.start('example.dill'); await device.start('example.dill');
expect(processManager.hasRemainingExpectations, isFalse); expect(processManager.hasRemainingExpectations, isFalse);
}); });
testUsingContext('as null when set to null', () async {
platform.environment = <String, String>{'FLUTTER_TEST': null};
processManager.addCommand(flutterTestCommand(null));
await device.start('example.dill');
expect(processManager.hasRemainingExpectations, isFalse);
});
}); });
group('Dart Entrypoint Args', () { group('Dart Entrypoint Args', () {

View File

@ -52,7 +52,6 @@ void main() {
flutterProject: project, flutterProject: project,
debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
systemClock: SystemClock.fixed(DateTime(0, 0, 0)), systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
@ -80,7 +79,6 @@ void main() {
flutterProject: project, flutterProject: project,
debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
systemClock: SystemClock.fixed(DateTime(0, 0, 0)), systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
@ -103,7 +101,6 @@ void main() {
flutterProject: project, flutterProject: project,
debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
systemClock: SystemClock.fixed(DateTime(0, 0, 0)), systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
@ -125,7 +122,6 @@ void main() {
flutterProject: project, flutterProject: project,
debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
systemClock: SystemClock.fixed(DateTime(0, 0, 0)), systemClock: SystemClock.fixed(DateTime(0, 0, 0)),
@ -152,7 +148,6 @@ void main() {
flutterProject: project, flutterProject: project,
debuggingOptions: DebuggingOptions.disabled(BuildInfo.release), debuggingOptions: DebuggingOptions.disabled(BuildInfo.release),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
systemClock: SystemClock.fixed(DateTime(0, 0, 0)), systemClock: SystemClock.fixed(DateTime(0, 0, 0)),

View File

@ -159,7 +159,6 @@ void main() {
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -188,7 +187,6 @@ void main() {
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, startPaused: true), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, startPaused: true),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -207,7 +205,6 @@ void main() {
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -220,7 +217,6 @@ void main() {
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile), debuggingOptions: DebuggingOptions.enabled(BuildInfo.profile),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -322,7 +318,6 @@ void main() {
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
ipv6: true, ipv6: true,
stayResident: false, stayResident: false,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -346,7 +341,6 @@ void main() {
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
ipv6: true, ipv6: true,
stayResident: false, stayResident: false,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -463,7 +457,6 @@ void main() {
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, startPaused: true), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug, startPaused: true),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: BufferLogger.test(), logger: BufferLogger.test(),
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -789,6 +782,7 @@ void main() {
testUsingContext('cleanup of resources is safe to call multiple times', () async { testUsingContext('cleanup of resources is safe to call multiple times', () async {
final ResidentRunner residentWebRunner = setUpResidentRunner(flutterDevice); final ResidentRunner residentWebRunner = setUpResidentRunner(flutterDevice);
mockDevice.dds = DartDevelopmentService();
fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[ fakeVmServiceHost = FakeVmServiceHost(requests: <VmServiceExpectation>[
...kAttachExpectations, ...kAttachExpectations,
]); ]);
@ -882,7 +876,6 @@ void main() {
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -925,7 +918,6 @@ void main() {
flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory), flutterProject: FlutterProject.fromDirectoryTest(fileSystem.currentDirectory),
debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: DebuggingOptions.enabled(BuildInfo.debug),
ipv6: true, ipv6: true,
urlTunneller: null,
fileSystem: fileSystem, fileSystem: fileSystem,
logger: logger, logger: logger,
usage: globals.flutterUsage, usage: globals.flutterUsage,
@ -1075,7 +1067,6 @@ ResidentRunner setUpResidentRunner(FlutterDevice flutterDevice, {
flutterProject: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory), flutterProject: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory),
debuggingOptions: debuggingOptions ?? DebuggingOptions.enabled(BuildInfo.debug), debuggingOptions: debuggingOptions ?? DebuggingOptions.enabled(BuildInfo.debug),
ipv6: true, ipv6: true,
urlTunneller: null,
usage: globals.flutterUsage, usage: globals.flutterUsage,
systemClock: systemClock ?? SystemClock.fixed(DateTime.now()), systemClock: systemClock ?? SystemClock.fixed(DateTime.now()),
fileSystem: globals.fs, fileSystem: globals.fs,

View File

@ -4,6 +4,8 @@
// @dart = 2.8 // @dart = 2.8
// ignore_for_file: avoid_redundant_argument_values
import 'dart:io' hide Directory, File; import 'dart:io' hide Directory, File;
import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/artifacts.dart';

View File

@ -93,7 +93,7 @@ abstract class VmServiceExpectation {
class FakeVmServiceRequest implements VmServiceExpectation { class FakeVmServiceRequest implements VmServiceExpectation {
const FakeVmServiceRequest({ const FakeVmServiceRequest({
required this.method, required this.method,
this.args = const <String, Object>{}, this.args = const <String, Object?>{},
this.jsonResponse, this.jsonResponse,
this.errorCode, this.errorCode,
this.close = false, this.close = false,
@ -107,7 +107,7 @@ class FakeVmServiceRequest implements VmServiceExpectation {
/// If non-null, the error code for a [vm_service.RPCError] in place of a /// If non-null, the error code for a [vm_service.RPCError] in place of a
/// standard response. /// standard response.
final int? errorCode; final int? errorCode;
final Map<String, Object>? args; final Map<String, Object?>? args;
final Map<String, Object?>? jsonResponse; final Map<String, Object?>? jsonResponse;
@override @override