mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[flutter_tool] partial null safety migration of tool source code (#105798)
This commit is contained in:
parent
a7ddb9b64e
commit
92034482f9
@ -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.
|
||||||
|
@ -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) {
|
||||||
|
@ -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>();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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}"');
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.');
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
@ -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
@ -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',
|
||||||
|
@ -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));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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');
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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',
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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', () {
|
||||||
|
@ -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)),
|
||||||
|
@ -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,
|
||||||
|
@ -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';
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user