mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
![auto-submit[bot]](/assets/img/avatar_default.png)
Reverts flutter/flutter#137618 Initiated by: Jasguerrero This change reverts the following previous change: Original Description: It's now possible to natively compile a flutter app for windows-arm64. Cross-compilation is not yet implemented. Uses arm64 artifacts now available for Dart/Flutter. Platform detection is based on Abi class, provided by Dart. Depending if Dart is an arm64 or x64 binary, the Abi is set accordingly. Initial bootstrap of dart artifacts (update_dart_sdk.ps1) is checking PROCESSOR_ARCHITECTURE environment variable, which is the way to detect host architecture on Windows. This is available only for master channel (on other channels, it fallbacks to windows-x64). On windows-x64, it produces an x64 app. On windows-arm64, it produces an arm64 app.
384 lines
11 KiB
Dart
384 lines
11 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import '../framework/devices.dart';
|
|
import '../framework/framework.dart';
|
|
import '../framework/task_result.dart';
|
|
import '../framework/utils.dart';
|
|
|
|
TaskFunction createAndroidRunDebugTest() {
|
|
return AndroidRunOutputTest(release: false).call;
|
|
}
|
|
|
|
TaskFunction createAndroidRunReleaseTest() {
|
|
return AndroidRunOutputTest(release: true).call;
|
|
}
|
|
|
|
TaskFunction createLinuxRunDebugTest() {
|
|
return DesktopRunOutputTest(
|
|
'${flutterDirectory.path}/dev/integration_tests/ui',
|
|
'lib/empty.dart',
|
|
release: false,
|
|
).call;
|
|
}
|
|
|
|
TaskFunction createLinuxRunReleaseTest() {
|
|
return DesktopRunOutputTest(
|
|
'${flutterDirectory.path}/dev/integration_tests/ui',
|
|
'lib/empty.dart',
|
|
release: true,
|
|
).call;
|
|
}
|
|
|
|
TaskFunction createMacOSRunDebugTest() {
|
|
return DesktopRunOutputTest(
|
|
// TODO(cbracken): https://github.com/flutter/flutter/issues/87508#issuecomment-1043753201
|
|
// Switch to dev/integration_tests/ui once we have CocoaPods working on M1 Macs.
|
|
'${flutterDirectory.path}/examples/hello_world',
|
|
'lib/main.dart',
|
|
release: false,
|
|
allowStderr: true,
|
|
).call;
|
|
}
|
|
|
|
TaskFunction createMacOSRunReleaseTest() {
|
|
return DesktopRunOutputTest(
|
|
// TODO(cbracken): https://github.com/flutter/flutter/issues/87508#issuecomment-1043753201
|
|
// Switch to dev/integration_tests/ui once we have CocoaPods working on M1 Macs.
|
|
'${flutterDirectory.path}/examples/hello_world',
|
|
'lib/main.dart',
|
|
release: true,
|
|
allowStderr: true,
|
|
).call;
|
|
}
|
|
|
|
TaskFunction createWindowsRunDebugTest() {
|
|
return WindowsRunOutputTest(
|
|
'${flutterDirectory.path}/dev/integration_tests/ui',
|
|
'lib/empty.dart',
|
|
release: false,
|
|
).call;
|
|
}
|
|
|
|
TaskFunction createWindowsRunReleaseTest() {
|
|
return WindowsRunOutputTest(
|
|
'${flutterDirectory.path}/dev/integration_tests/ui',
|
|
'lib/empty.dart',
|
|
release: true,
|
|
).call;
|
|
}
|
|
|
|
class AndroidRunOutputTest extends RunOutputTask {
|
|
AndroidRunOutputTest({required super.release}) : super(
|
|
'${flutterDirectory.path}/dev/integration_tests/ui',
|
|
'lib/main.dart',
|
|
);
|
|
|
|
@override
|
|
Future<void> prepare(String deviceId) async {
|
|
// Uninstall if the app is already installed on the device to get to a clean state.
|
|
final List<String> stderr = <String>[];
|
|
print('uninstalling...');
|
|
final Process uninstall = await startFlutter(
|
|
'install',
|
|
options: <String>['--suppress-analytics', '--uninstall-only', '-d', deviceId],
|
|
isBot: false,
|
|
);
|
|
uninstall.stdout
|
|
.transform<String>(utf8.decoder)
|
|
.transform<String>(const LineSplitter())
|
|
.listen((String line) {
|
|
print('uninstall:stdout: $line');
|
|
});
|
|
uninstall.stderr
|
|
.transform<String>(utf8.decoder)
|
|
.transform<String>(const LineSplitter())
|
|
.listen((String line) {
|
|
print('uninstall:stderr: $line');
|
|
stderr.add(line);
|
|
});
|
|
if (await uninstall.exitCode != 0) {
|
|
throw 'flutter install --uninstall-only failed.';
|
|
}
|
|
if (stderr.isNotEmpty) {
|
|
throw 'flutter install --uninstall-only had output on standard error.';
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool isExpectedStderr(String line) {
|
|
// TODO(egarciad): Remove once https://github.com/flutter/flutter/issues/95131 is fixed.
|
|
return line.contains('Mapping new ns');
|
|
}
|
|
|
|
@override
|
|
TaskResult verify(List<String> stdout, List<String> stderr) {
|
|
final String gradleTask = release ? 'assembleRelease' : 'assembleDebug';
|
|
final String apk = release ? 'app-release.apk' : 'app-debug.apk';
|
|
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line.startsWith('Launching lib/main.dart on ') &&
|
|
line.endsWith(' in ${release ? 'release' : 'debug'} mode...'),
|
|
'Launching lib/main.dart on',
|
|
);
|
|
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line.startsWith("Running Gradle task '$gradleTask'..."),
|
|
"Running Gradle task '$gradleTask'...",
|
|
);
|
|
|
|
// Size information is only included in release builds.
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line.contains('Built build/app/outputs/flutter-apk/$apk') &&
|
|
(!release || line.contains('MB).')),
|
|
'Built build/app/outputs/flutter-apk/$apk',
|
|
);
|
|
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line.startsWith('Installing build/app/outputs/flutter-apk/$apk...'),
|
|
'Installing build/app/outputs/flutter-apk/$apk...',
|
|
);
|
|
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line.contains('Quit (terminate the application on the device).'),
|
|
'q Quit (terminate the application on the device)',
|
|
);
|
|
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line == 'Application finished.',
|
|
'Application finished.',
|
|
);
|
|
|
|
return TaskResult.success(null);
|
|
}
|
|
}
|
|
|
|
class WindowsRunOutputTest extends DesktopRunOutputTest {
|
|
WindowsRunOutputTest(
|
|
super.testDirectory,
|
|
super.testTarget, {
|
|
required super.release,
|
|
super.allowStderr = false,
|
|
}
|
|
);
|
|
|
|
static final RegExp _buildOutput = RegExp(
|
|
r'Building Windows application\.\.\.\s*\d+(\.\d+)?(ms|s)',
|
|
multiLine: true,
|
|
);
|
|
static final RegExp _builtOutput = RegExp(
|
|
r'Built build\\windows\\x64\\runner\\(Debug|Release)\\\w+\.exe( \(\d+(\.\d+)?MB\))?\.',
|
|
);
|
|
|
|
@override
|
|
void verifyBuildOutput(List<String> stdout) {
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
_buildOutput.hasMatch,
|
|
'Building Windows application...',
|
|
);
|
|
|
|
final String buildMode = release ? 'Release' : 'Debug';
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) {
|
|
if (!_builtOutput.hasMatch(line) || !line.contains(buildMode)) {
|
|
return false;
|
|
}
|
|
|
|
// Size information is only included in release builds.
|
|
final bool hasSize = line.contains('MB).');
|
|
if (release != hasSize) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
},
|
|
'Built build\\windows\\x64\\runner\\$buildMode\\app.exe',
|
|
);
|
|
}
|
|
}
|
|
|
|
class DesktopRunOutputTest extends RunOutputTask {
|
|
DesktopRunOutputTest(
|
|
super.testDirectory,
|
|
super.testTarget, {
|
|
required super.release,
|
|
this.allowStderr = false,
|
|
}
|
|
);
|
|
|
|
/// Whether `flutter run` is expected to produce output on stderr.
|
|
final bool allowStderr;
|
|
|
|
@override
|
|
bool isExpectedStderr(String line) => allowStderr;
|
|
|
|
@override
|
|
TaskResult verify(List<String> stdout, List<String> stderr) {
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line.startsWith('Launching $testTarget on ') &&
|
|
line.endsWith(' in ${release ? 'release' : 'debug'} mode...'),
|
|
'Launching $testTarget on',
|
|
);
|
|
|
|
verifyBuildOutput(stdout);
|
|
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line.contains('Quit (terminate the application on the device).'),
|
|
'q Quit (terminate the application on the device)',
|
|
);
|
|
|
|
_findNextMatcherInList(
|
|
stdout,
|
|
(String line) => line == 'Application finished.',
|
|
'Application finished.',
|
|
);
|
|
|
|
return TaskResult.success(null);
|
|
}
|
|
|
|
/// Verify the output from `flutter run`'s build step.
|
|
void verifyBuildOutput(List<String> stdout) {}
|
|
}
|
|
|
|
/// Test that the output of `flutter run` is expected.
|
|
abstract class RunOutputTask {
|
|
RunOutputTask(
|
|
this.testDirectory,
|
|
this.testTarget, {
|
|
required this.release,
|
|
}
|
|
);
|
|
|
|
static final RegExp _engineLogRegex = RegExp(
|
|
r'\[(VERBOSE|INFO|WARNING|ERROR|FATAL):.+\(\d+\)\]',
|
|
);
|
|
|
|
/// The directory where the app under test is defined.
|
|
final String testDirectory;
|
|
/// The main entry-point file of the application, as run on the device.
|
|
final String testTarget;
|
|
/// Whether to run the app in release mode.
|
|
final bool release;
|
|
|
|
Future<TaskResult> call() {
|
|
return inDirectory<TaskResult>(testDirectory, () async {
|
|
final Device device = await devices.workingDevice;
|
|
await device.unlock();
|
|
final String deviceId = device.deviceId;
|
|
|
|
final Completer<void> ready = Completer<void>();
|
|
final List<String> stdout = <String>[];
|
|
final List<String> stderr = <String>[];
|
|
|
|
await prepare(deviceId);
|
|
|
|
final List<String> options = <String>[
|
|
testTarget,
|
|
'-d',
|
|
deviceId,
|
|
if (release) '--release',
|
|
];
|
|
|
|
final Process run = await startFlutter(
|
|
'run',
|
|
options: options,
|
|
isBot: false,
|
|
);
|
|
|
|
int? runExitCode;
|
|
run.stdout
|
|
.transform<String>(utf8.decoder)
|
|
.transform<String>(const LineSplitter())
|
|
.listen((String line) {
|
|
print('run:stdout: $line');
|
|
stdout.add(line);
|
|
if (line.contains('Quit (terminate the application on the device).')) {
|
|
ready.complete();
|
|
}
|
|
});
|
|
final Stream<String> runStderr = run.stderr
|
|
.transform<String>(utf8.decoder)
|
|
.transform<String>(const LineSplitter())
|
|
.asBroadcastStream();
|
|
runStderr.listen((String line) => print('run:stderr: $line'));
|
|
runStderr
|
|
.skipWhile(isExpectedStderr)
|
|
.listen((String line) => stderr.add(line));
|
|
unawaited(run.exitCode.then<void>((int exitCode) { runExitCode = exitCode; }));
|
|
await Future.any<dynamic>(<Future<dynamic>>[ ready.future, run.exitCode ]);
|
|
if (runExitCode != null) {
|
|
throw 'Failed to run test app; runner unexpected exited, with exit code $runExitCode.';
|
|
}
|
|
run.stdin.write('q');
|
|
|
|
await run.exitCode;
|
|
|
|
if (stderr.isNotEmpty) {
|
|
throw 'flutter run ${release ? '--release' : ''} had unexpected output on standard error.';
|
|
}
|
|
|
|
final List<String> engineLogs = List<String>.from(
|
|
stdout.where(_engineLogRegex.hasMatch),
|
|
);
|
|
if (engineLogs.isNotEmpty) {
|
|
throw 'flutter run had unexpected Flutter engine logs $engineLogs';
|
|
}
|
|
|
|
return verify(stdout, stderr);
|
|
});
|
|
}
|
|
|
|
/// Prepare the device for running the test app.
|
|
Future<void> prepare(String deviceId) => Future<void>.value();
|
|
|
|
/// Returns true if this stderr output line is expected.
|
|
bool isExpectedStderr(String line) => false;
|
|
|
|
/// Verify the output of `flutter run`.
|
|
TaskResult verify(List<String> stdout, List<String> stderr) => throw UnimplementedError('verify is not implemented');
|
|
|
|
/// Helper that verifies a line in [list] matches [matcher].
|
|
/// The [list] is updated to contain the lines remaining after the match.
|
|
void _findNextMatcherInList(
|
|
List<String> list,
|
|
bool Function(String testLine) matcher,
|
|
String errorMessageExpectedLine
|
|
) {
|
|
final List<String> copyOfListForErrorMessage = List<String>.from(list);
|
|
|
|
while (list.isNotEmpty) {
|
|
final String nextLine = list.first;
|
|
list.removeAt(0);
|
|
|
|
if (matcher(nextLine)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
throw '''
|
|
Did not find expected line
|
|
|
|
$errorMessageExpectedLine
|
|
|
|
in flutter run ${release ? '--release' : ''} stdout
|
|
|
|
$copyOfListForErrorMessage
|
|
''';
|
|
}
|
|
}
|