[flutter_tool] Fuchsia AOT builds (#45187)

This commit is contained in:
Zachary Anderson 2019-11-21 08:32:58 -08:00 committed by GitHub
parent 43a8a1902e
commit a57dddd217
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 264 additions and 130 deletions

View file

@ -61,7 +61,7 @@ enum Artifact {
// Fuchsia artifacts from the engine prebuilts.
fuchsiaKernelCompiler,
fuchsiaFlutterJitRunner,
fuchsiaFlutterRunner,
}
String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMode mode ]) {
@ -136,11 +136,10 @@ String _artifactToFileName(Artifact artifact, [ TargetPlatform platform, BuildMo
return 'flutter_ddc_sdk.dill';
case Artifact.fuchsiaKernelCompiler:
return 'kernel_compiler.snapshot';
case Artifact.fuchsiaFlutterJitRunner:
if (mode == BuildMode.debug || mode == BuildMode.profile) {
return 'flutter_jit_runner-0.far';
}
return 'flutter_jit_product_runner-0.far';
case Artifact.fuchsiaFlutterRunner:
final String jitOrAot = mode.isJit ? '_jit' : '_aot';
final String productOrNo = mode.isRelease ? '_product' : '';
return 'flutter$jitOrAot${productOrNo}_runner-0.far';
}
assert(false, 'Invalid artifact $artifact.');
return null;
@ -278,21 +277,25 @@ class CachedArtifacts extends Artifacts {
cache.getArtifactDirectory('flutter_runner').path,
'flutter',
fuchsiaArchForTargetPlatform(platform),
getNameForBuildMode(mode),
mode.isRelease ? 'release' : mode.toString(),
);
final String runtime = mode.isJit ? 'jit' : 'aot';
switch (artifact) {
case Artifact.genSnapshot:
final String genSnapshot = mode.isRelease ? 'gen_snapshot_product' : 'gen_snapshot';
return fs.path.join(root, runtime, 'dart_binaries', genSnapshot);
case Artifact.flutterPatchedSdkPath:
const String artifactFileName = 'flutter_runner_patched_sdk';
return fs.path.join(root, 'jit', artifactFileName);
return fs.path.join(root, runtime, artifactFileName);
case Artifact.platformKernelDill:
final String artifactFileName = _artifactToFileName(artifact, platform, mode);
return fs.path.join(root, 'jit', 'flutter_runner_patched_sdk', artifactFileName);
return fs.path.join(root, runtime, 'flutter_runner_patched_sdk', artifactFileName);
case Artifact.fuchsiaKernelCompiler:
final String artifactFileName = _artifactToFileName(artifact, platform, mode);
return fs.path.join(root, 'jit', 'dart_binaries', artifactFileName);
case Artifact.fuchsiaFlutterJitRunner:
return fs.path.join(root, runtime, 'dart_binaries', artifactFileName);
case Artifact.fuchsiaFlutterRunner:
final String artifactFileName = _artifactToFileName(artifact, platform, mode);
return fs.path.join(root, 'jit', artifactFileName);
return fs.path.join(root, runtime, artifactFileName);
default:
return _getHostArtifactPath(artifact, platform, mode);
}
@ -413,7 +416,7 @@ class LocalEngineArtifacts extends Artifacts {
@override
String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode }) {
platform ??= _currentHostPlatform;
final String artifactFileName = _artifactToFileName(artifact, platform);
final String artifactFileName = _artifactToFileName(artifact, platform, mode);
switch (artifact) {
case Artifact.snapshotDart:
return fs.path.join(_engineSrcPath, 'flutter', 'lib', 'snapshot', artifactFileName);
@ -482,13 +485,13 @@ class LocalEngineArtifacts extends Artifacts {
return fs.path.join(_getFlutterWebSdkPath(), 'kernel', _artifactToFileName(artifact));
case Artifact.fuchsiaKernelCompiler:
final String hostPlatform = getNameForHostPlatform(getCurrentHostPlatform());
final String dartBinaries = 'dart_binaries-$mode-$hostPlatform';
final String modeName = mode.isRelease ? 'release' : mode.toString();
final String dartBinaries = 'dart_binaries-$modeName-$hostPlatform';
return fs.path.join(engineOutPath, 'host_bundle', dartBinaries, 'kernel_compiler.dart.snapshot');
case Artifact.fuchsiaFlutterJitRunner:
if (mode == BuildMode.debug || mode == BuildMode.profile) {
return fs.path.join(engineOutPath, 'flutter_jit_runner-0.far');
}
return fs.path.join(engineOutPath, 'flutter_jit_product_runner-0.far');
case Artifact.fuchsiaFlutterRunner:
final String jitOrAot = mode.isJit ? '_jit' : '_aot';
final String productOrNo = mode.isRelease ? '_product' : '';
return fs.path.join(engineOutPath, 'flutter$jitOrAot${productOrNo}_runner-0.far');
}
assert(false, 'Invalid artifact $artifact.');
return null;

View file

@ -59,6 +59,7 @@ class BuildInfo {
static const BuildInfo debug = BuildInfo(BuildMode.debug, null);
static const BuildInfo profile = BuildInfo(BuildMode.profile, null);
static const BuildInfo jitRelease = BuildInfo(BuildMode.jitRelease, null);
static const BuildInfo release = BuildInfo(BuildMode.release, null);
/// Returns whether a debug build is requested.
@ -68,14 +69,22 @@ class BuildInfo {
/// Returns whether a profile build is requested.
///
/// Exactly one of [isDebug], [isProfile], or [isRelease] is true.
/// Exactly one of [isDebug], [isProfile], [isJitRelease],
/// or [isRelease] is true.
bool get isProfile => mode == BuildMode.profile;
/// Returns whether a release build is requested.
///
/// Exactly one of [isDebug], [isProfile], or [isRelease] is true.
/// Exactly one of [isDebug], [isProfile], [isJitRelease],
/// or [isRelease] is true.
bool get isRelease => mode == BuildMode.release;
/// Returns whether a JIT release build is requested.
///
/// Exactly one of [isDebug], [isProfile], [isJitRelease],
/// or [isRelease] is true.
bool get isJitRelease => mode == BuildMode.jitRelease;
bool get usesAot => isAotBuildMode(mode);
bool get supportsEmulator => isEmulatorBuildMode(mode);
bool get supportsSimulator => isEmulatorBuildMode(mode);

View file

@ -214,7 +214,7 @@ class AttachCommand extends FlutterCommand {
if (module == null) {
throwToolExit('\'--module\' is required for attaching to a Fuchsia device');
}
usesIpv6 = device.ipv6;
usesIpv6 = await device.ipv6;
FuchsiaIsolateDiscoveryProtocol isolateDiscoveryProtocol;
try {
isolateDiscoveryProtocol = device.getIsolateDiscoveryProtocol(module);

View file

@ -31,6 +31,11 @@ class BuildFuchsiaCommand extends BuildSubCommand {
],
defaultsTo: FuchsiaPackageServer.toolHost,
);
argParser.addOption('target-platform',
defaultsTo: 'fuchsia-x64',
allowed: <String>['fuchsia-arm64', 'fuchsia-x64'],
help: 'The target platform for which the app is compiled.',
);
}
@override
@ -69,6 +74,7 @@ class BuildFuchsiaCommand extends BuildSubCommand {
await buildFuchsia(
fuchsiaProject: flutterProject.fuchsia,
target: targetFile,
targetPlatform: getTargetPlatformForName(argResults['target-platform']),
buildInfo: buildInfo,
runnerPackageSource: stringArg('runner-source'),
);

View file

@ -19,24 +19,13 @@ import 'build.dart';
/// .ipas, see https://flutter.dev/docs/deployment/ios.
class BuildIOSCommand extends BuildSubCommand {
BuildIOSCommand() {
addBuildModeFlags(defaultToRelease: false);
usesTargetOption();
usesFlavorOption();
usesPubOption();
usesBuildNumberOption();
usesBuildNameOption();
argParser
..addFlag('debug',
negatable: false,
help: 'Build a debug version of your app (default mode for iOS simulator builds).',
)
..addFlag('profile',
negatable: false,
help: 'Build a version of your app specialized for performance profiling.',
)
..addFlag('release',
negatable: false,
help: 'Build a release version of your app (default mode for device builds).',
)
..addFlag('simulator',
help: 'Build for the iOS simulator instead of the device.',
)

View file

@ -17,19 +17,8 @@ import 'build.dart';
/// A command to build a linux desktop target through a build shell script.
class BuildLinuxCommand extends BuildSubCommand {
BuildLinuxCommand() {
addBuildModeFlags(defaultToRelease: false);
usesTargetOption();
argParser.addFlag('debug',
negatable: false,
help: 'Build a debug version of your app.',
);
argParser.addFlag('profile',
negatable: false,
help: 'Build a version of your app specialized for performance profiling.',
);
argParser.addFlag('release',
negatable: false,
help: 'Build a version of your app specialized for performance profiling.',
);
}
@override

View file

@ -17,19 +17,8 @@ import 'build.dart';
/// A command to build a windows desktop target through a build shell script.
class BuildWindowsCommand extends BuildSubCommand {
BuildWindowsCommand() {
addBuildModeFlags(defaultToRelease: false);
usesTargetOption();
argParser.addFlag('debug',
negatable: false,
help: 'Build a debug version of your app.',
);
argParser.addFlag('profile',
negatable: false,
help: 'Build a version of your app specialized for performance profiling.',
);
argParser.addFlag('release',
negatable: false,
help: 'Build a version of your app specialized for performance profiling.',
);
}
@override

View file

@ -295,7 +295,7 @@ class RunCommand extends RunCommandBase {
DebuggingOptions _createDebuggingOptions() {
final BuildInfo buildInfo = getBuildInfo();
if (buildInfo.isRelease) {
if (buildInfo.mode.isRelease) {
return DebuggingOptions.disabled(
buildInfo,
initializePlatform: boolArg('web-initialize-platform'),

View file

@ -6,10 +6,13 @@ import 'dart:async';
import 'package:meta/meta.dart';
import '../artifacts.dart';
import '../asset.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/process.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../bundle.dart';
@ -37,6 +40,7 @@ Future<void> _timedBuildStep(String name, Future<void> Function() action) async
// Fuchsia package.
Future<void> buildFuchsia({
@required FuchsiaProject fuchsiaProject,
@required TargetPlatform targetPlatform,
@required String target, // E.g., lib/main.dart
BuildInfo buildInfo = BuildInfo.debug,
String runnerPackageSource = FuchsiaPackageServer.toolHost,
@ -49,12 +53,66 @@ Future<void> buildFuchsia({
await _timedBuildStep('fuchsia-kernel-compile',
() => fuchsiaSdk.fuchsiaKernelCompiler.build(
fuchsiaProject: fuchsiaProject, target: target, buildInfo: buildInfo));
if (buildInfo.usesAot) {
await _timedBuildStep('fuchsia-gen-snapshot',
() => _genSnapshot(fuchsiaProject, target, buildInfo, targetPlatform));
}
await _timedBuildStep('fuchsia-build-assets',
() => _buildAssets(fuchsiaProject, target, buildInfo));
await _timedBuildStep('fuchsia-build-package',
() => _buildPackage(fuchsiaProject, target, buildInfo, runnerPackageSource));
}
Future<void> _genSnapshot(
FuchsiaProject fuchsiaProject,
String target, // lib/main.dart
BuildInfo buildInfo,
TargetPlatform targetPlatform,
) async {
final String outDir = getFuchsiaBuildDirectory();
final String appName = fuchsiaProject.project.manifest.appName;
final String dilPath = fs.path.join(outDir, '$appName.dil');
final String vmSnapshotData = fs.path.join(outDir, 'vm_data.aotsnapshot');
final String vmSnapshotInstructions = fs.path.join(outDir, 'vm_instructions.aotsnapshot');
final String snapshotData = fs.path.join(outDir, 'data.aotsnapshot');
final String snapshotInstructions = fs.path.join(outDir, 'instructions.aotsnapshot');
final String genSnapshot = artifacts.getArtifactPath(
Artifact.genSnapshot,
platform: targetPlatform,
mode: buildInfo.mode,
);
final List<String> command = <String>[
genSnapshot,
'--no_causal_async_stacks',
'--deterministic',
'--snapshot_kind=app-aot-blobs',
'--vm_snapshot_data=$vmSnapshotData',
'--vm_snapshot_instructions=$vmSnapshotInstructions',
'--isolate_snapshot_data=$snapshotData',
'--isolate_snapshot_instructions=$snapshotInstructions',
if (buildInfo.isDebug) '--enable-asserts',
dilPath,
];
int result;
final Status status = logger.startProgress(
'Compiling Fuchsia application to native code...',
timeout: null,
);
try {
result = await processUtils.stream(command, trace: true);
} finally {
status.cancel();
}
if (result != 0) {
throwToolExit('Build process failed');
}
}
Future<void> _buildAssets(
FuchsiaProject fuchsiaProject,
String target, // lib/main.dart
@ -98,12 +156,17 @@ void _rewriteCmx(BuildMode mode, String runnerPackageSource, File src, File dst)
String runner;
switch (mode) {
case BuildMode.debug:
case BuildMode.profile:
runner = 'flutter_jit_runner';
break;
case BuildMode.release:
case BuildMode.profile:
runner = 'flutter_aot_runner';
break;
case BuildMode.jitRelease:
runner = 'flutter_jit_product_runner';
break;
case BuildMode.release:
runner = 'flutter_aot_product_runner';
break;
default:
throwToolExit('Fuchsia does not support build mode "$mode"');
break;
@ -122,7 +185,6 @@ Future<void> _buildPackage(
final String outDir = getFuchsiaBuildDirectory();
final String pkgDir = fs.path.join(outDir, 'pkg');
final String appName = fuchsiaProject.project.manifest.appName;
final String dilpmanifest = fs.path.join(outDir, '$appName.dilpmanifest');
final String pkgassets = fs.path.join(outDir, '${appName}_pkgassets');
final String packageManifest = fs.path.join(pkgDir, 'package_manifest');
final String devKeyPath = fs.path.join(pkgDir, 'development.key');
@ -137,9 +199,29 @@ Future<void> _buildPackage(
final File dstCmx = fs.file(fs.path.join(outDir, '$appName.cmx'));
_rewriteCmx(buildInfo.mode, runnerPackageSource, srcCmx, dstCmx);
// Concatenate dilpmanifest and pkgassets into package_manifest.
final File manifestFile = fs.file(packageManifest);
if (buildInfo.usesAot) {
final String vmSnapshotData = fs.path.join(outDir, 'vm_data.aotsnapshot');
final String vmSnapshotInstructions = fs.path.join(outDir, 'vm_instructions.aotsnapshot');
final String snapshotData = fs.path.join(outDir, 'data.aotsnapshot');
final String snapshotInstructions = fs.path.join(outDir, 'instructions.aotsnapshot');
manifestFile.writeAsStringSync(
'data/$appName/vm_snapshot_data.bin=$vmSnapshotData\n');
manifestFile.writeAsStringSync(
'data/$appName/vm_snapshot_instructions.bin=$vmSnapshotInstructions\n',
mode: FileMode.append);
manifestFile.writeAsStringSync(
'data/$appName/isolate_snapshot_data.bin=$snapshotData\n',
mode: FileMode.append);
manifestFile.writeAsStringSync(
'data/$appName/isolate_snapshot_instructions.bin=$snapshotInstructions\n',
mode: FileMode.append);
} else {
final String dilpmanifest = fs.path.join(outDir, '$appName.dilpmanifest');
manifestFile.writeAsStringSync(fs.file(dilpmanifest).readAsStringSync());
}
manifestFile.writeAsStringSync(fs.file(pkgassets).readAsStringSync(),
mode: FileMode.append);
manifestFile.writeAsStringSync('meta/$appName.cmx=${dstCmx.path}\n',

View file

@ -40,12 +40,14 @@ class FuchsiaDevFinder {
return result.stdout.split('\n');
}
/// Returns the host address by which the device [deviceName] should use for
/// the host.
/// Returns the address of the named device.
///
/// If local is true, then gives the address by which the device reaches the
/// host.
///
/// The string [deviceName] should be the name of the device from the
/// 'list' command, e.g. 'scare-cable-skip-joy'.
Future<String> resolve(String deviceName) async {
Future<String> resolve(String deviceName, {bool local = false}) async {
if (fuchsiaArtifacts.devFinder == null ||
!fuchsiaArtifacts.devFinder.existsSync()) {
throwToolExit('Fuchsia dev_finder tool not found.');
@ -53,7 +55,7 @@ class FuchsiaDevFinder {
final List<String> command = <String>[
fuchsiaArtifacts.devFinder.path,
'resolve',
'-local',
if (local) '-local',
'-device-limit', '1',
deviceName,
];

View file

@ -230,13 +230,17 @@ class FuchsiaDevice extends Device {
}) async {
if (!prebuiltApplication) {
await buildFuchsia(fuchsiaProject: FlutterProject.current().fuchsia,
targetPlatform: await targetPlatform,
target: mainPath,
buildInfo: debuggingOptions.buildInfo);
}
// Stop the app if it's currently running.
await stopApp(package);
// Find out who the device thinks we are.
final String host = await fuchsiaSdk.fuchsiaDevFinder.resolve(name);
final String host = await fuchsiaSdk.fuchsiaDevFinder.resolve(
name,
local: true,
);
if (host == null) {
printError('Failed to resolve host for Fuchsia device');
return LaunchResult.failed();
@ -301,7 +305,7 @@ class FuchsiaDevice extends Device {
// Serve the flutter_runner.
final File flutterRunnerArchive = fs.file(artifacts.getArtifactPath(
Artifact.fuchsiaFlutterJitRunner,
Artifact.fuchsiaFlutterRunner,
platform: await targetPlatform,
mode: debuggingOptions.buildInfo.mode,
));
@ -318,10 +322,19 @@ class FuchsiaDevice extends Device {
serverRegistered = true;
// Tell the package controller to prefetch the flutter_runner.
String flutterRunnerName = 'flutter_jit_runner';
if (!debuggingOptions.buildInfo.isDebug &&
!debuggingOptions.buildInfo.isProfile) {
String flutterRunnerName;
if (debuggingOptions.buildInfo.usesAot) {
if (debuggingOptions.buildInfo.mode.isRelease) {
flutterRunnerName = 'flutter_aot_product_runner';
} else {
flutterRunnerName = 'flutter_aot_runner';
}
} else {
if (debuggingOptions.buildInfo.mode.isRelease) {
flutterRunnerName = 'flutter_jit_product_runner';
} else {
flutterRunnerName = 'flutter_jit_runner';
}
}
if (!await fuchsiaDeviceTools.amberCtl.pkgCtlResolve(
this, fuchsiaPackageServer, flutterRunnerName)) {
@ -367,10 +380,11 @@ class FuchsiaDevice extends Device {
status.cancel();
}
if (!debuggingOptions.buildInfo.isDebug &&
!debuggingOptions.buildInfo.isProfile) {
if (debuggingOptions.buildInfo.mode.isRelease) {
printTrace('App succesfully started in a release mode.');
return LaunchResult.succeeded();
}
printTrace('App started in a non-release mode. Setting up vmservice connection.');
// In a debug or profile build, try to find the observatory uri.
final FuchsiaIsolateDiscoveryProtocol discovery =
@ -452,9 +466,9 @@ class FuchsiaDevice extends Device {
@override
bool get supportsScreenshot => false;
bool get ipv6 {
Future<bool> get ipv6 async {
// Workaround for https://github.com/dart-lang/sdk/issues/29456
final String fragment = id.split('%').first;
final String fragment = (await _resolvedIp).split('%').first;
try {
Uri.parseIPv6Address(fragment);
return true;
@ -468,7 +482,7 @@ class FuchsiaDevice extends Device {
const String findCommand = 'find /hub -name vmservice-port';
final RunResult findResult = await shell(findCommand);
if (findResult.exitCode != 0) {
throwToolExit("'$findCommand' on device $id failed. stderr: '${findResult.stderr}'");
throwToolExit("'$findCommand' on device $name failed. stderr: '${findResult.stderr}'");
return null;
}
final String findOutput = findResult.stdout;
@ -485,7 +499,7 @@ class FuchsiaDevice extends Device {
final String lsCommand = 'ls $path';
final RunResult lsResult = await shell(lsCommand);
if (lsResult.exitCode != 0) {
throwToolExit("'$lsCommand' on device $id failed");
throwToolExit("'$lsCommand' on device $name failed");
return null;
}
final String lsOutput = lsResult.stdout;
@ -502,6 +516,15 @@ class FuchsiaDevice extends Device {
return ports;
}
String _cachedResolvedIp;
Future<String> get _resolvedIp async {
return _cachedResolvedIp ??= await fuchsiaSdk.fuchsiaDevFinder.resolve(
name,
local: false,
);
}
/// Run `command` on the Fuchsia device shell.
Future<RunResult> shell(String command) async {
if (fuchsiaArtifacts.sshConfig == null) {
@ -512,7 +535,7 @@ class FuchsiaDevice extends Device {
'ssh',
'-F',
fuchsiaArtifacts.sshConfig.absolute.path,
id,
await _resolvedIp,
command,
]);
}
@ -633,7 +656,7 @@ class FuchsiaIsolateDiscoveryProtocol {
}
final Uri address = flutterView.owner.vmService.httpAddress;
if (flutterView.uiIsolate.name.contains(_isolateName)) {
_foundUri.complete(_device.ipv6
_foundUri.complete(await _device.ipv6
? Uri.parse('http://[$_ipv6Loopback]:${address.port}/')
: Uri.parse('http://$_ipv4Loopback:${address.port}/'));
_status.stop();
@ -674,7 +697,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
'-f',
'-L',
'$hostPort:$_ipv4Loopback:$devicePort',
device.id,
await device._resolvedIp,
'true',
];
final Process process = await processManager.start(command);
@ -706,7 +729,7 @@ class _FuchsiaPortForwarder extends DevicePortForwarder {
'-vvv',
'-L',
'${forwardedPort.hostPort}:$_ipv4Loopback:${forwardedPort.devicePort}',
device.id,
await device._resolvedIp,
];
final ProcessResult result = await processManager.run(command);
if (result.exitCode != 0) {

View file

@ -7,11 +7,9 @@ import 'package:meta/meta.dart';
import '../artifacts.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/process.dart';
import '../build_info.dart';
import '../convert.dart';
import '../globals.dart';
import '../project.dart';
@ -58,35 +56,31 @@ class FuchsiaKernelCompiler {
'--filesystem-root', fsRoot,
'--packages', '$multiRootScheme:///$relativePackagesFile',
'--output', fs.path.join(outDir, '$appName.dil'),
'--component-name', appName,
// AOT/JIT:
if (buildInfo.usesAot) ...<String>['--aot', '--tfa']
else ...<String>[
// TODO(zra): Add back when this is supported again.
// See: https://github.com/flutter/flutter/issues/44925
// '--no-link-platform',
'--split-output-by-packages',
'--manifest', manifestPath,
'--component-name', appName,
];
'--manifest', manifestPath
],
if (buildInfo.isDebug) {
flags += <String>[
'--embed-sources',
];
} else if (buildInfo.isProfile) {
flags += <String>[
'--no-embed-sources',
'-Ddart.vm.profile=true',
// debug, profile, jit release, release:
if (buildInfo.isDebug) '--embed-sources'
else '--no-embed-sources',
if (buildInfo.isProfile) '-Ddart.vm.profile=true',
if (buildInfo.mode.isRelease) '-Ddart.vm.release=true',
// Use bytecode and drop the ast in JIT release mode.
if (buildInfo.isJitRelease) ...<String>[
'--gen-bytecode',
'--drop-ast',
],
];
} else if (buildInfo.isRelease) {
flags += <String>[
'--no-embed-sources',
'-Ddart.vm.release=true',
'--gen-bytecode',
'--drop-ast',
];
} else {
throwToolExit('Expected build type to be debug, profile, or release');
}
flags += <String>[
'$multiRootScheme:///$target',
@ -97,22 +91,13 @@ class FuchsiaKernelCompiler {
kernelCompiler,
...flags,
];
final Process process = await processUtils.start(command);
final Status status = logger.startProgress(
'Building Fuchsia application...',
timeout: null,
);
int result;
try {
process.stderr
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(printError);
process.stdout
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(printTrace);
result = await process.exitCode;
result = await processUtils.stream(command, trace: true);
} finally {
status.cancel();
}

View file

@ -337,6 +337,10 @@ abstract class FlutterCommand extends Command<void> {
argParser.addFlag('release',
negatable: false,
help: 'Build a release version of your app${defaultToRelease ? ' (default mode)' : ''}.');
argParser.addFlag('jit-release',
negatable: false,
hide: !verboseHelp,
help: 'Build a JIT release version of your app${defaultToRelease ? ' (default mode)' : ''}.');
}
void addShrinkingFlag() {
@ -374,10 +378,18 @@ abstract class FlutterCommand extends Command<void> {
}
BuildMode getBuildMode() {
// No debug when _excludeDebug is true.
// If debug is not excluded, then take the command line flag.
final bool debugResult = !_excludeDebug && boolArg('debug');
final List<bool> modeFlags = <bool>[debugResult, boolArg('profile'), boolArg('release')];
final List<bool> modeFlags = <bool>[
debugResult,
boolArg('jit-release'),
boolArg('profile'),
boolArg('release'),
];
if (modeFlags.where((bool flag) => flag).length > 1) {
throw UsageException('Only one of --debug, --profile, or --release can be specified.', null);
throw UsageException('Only one of --debug, --profile, --jit-release, '
'or --release can be specified.', null);
}
if (debugResult) {
return BuildMode.debug;
@ -388,6 +400,9 @@ abstract class FlutterCommand extends Command<void> {
if (boolArg('release')) {
return BuildMode.release;
}
if (boolArg('jit-release')) {
return BuildMode.jitRelease;
}
return _defaultBuildMode;
}

View file

@ -25,6 +25,7 @@ import 'package:flutter_tools/src/fuchsia/fuchsia_kernel_compiler.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_pm.dart';
import 'package:flutter_tools/src/fuchsia/fuchsia_sdk.dart';
import 'package:flutter_tools/src/fuchsia/tiles_ctl.dart';
import 'package:flutter_tools/src/globals.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/vmservice.dart';
import 'package:meta/meta.dart';
@ -111,6 +112,7 @@ void main() {
expect(await device.targetPlatform, TargetPlatform.fuchsia_arm64);
}, overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
ProcessUtils: () => mockProcessUtils,
});
@ -122,6 +124,7 @@ void main() {
expect(await device.targetPlatform, TargetPlatform.fuchsia_x64);
}, overrides: <Type, Generator>{
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
ProcessUtils: () => mockProcessUtils,
});
});
@ -180,6 +183,7 @@ void main() {
sshConfig: mockFile,
devFinder: mockFile,
),
FuchsiaSdk: () => MockFuchsiaSdk(),
});
group('device logs', () {
@ -378,7 +382,38 @@ void main() {
});
});
group('fuchsia app start and stop: ', () {
testUsingContext('Correct flutter runner', () async {
expect(artifacts.getArtifactPath(
Artifact.fuchsiaFlutterRunner,
platform: TargetPlatform.fuchsia_x64,
mode: BuildMode.debug,
),
contains('flutter_jit_runner'),
);
expect(artifacts.getArtifactPath(
Artifact.fuchsiaFlutterRunner,
platform: TargetPlatform.fuchsia_x64,
mode: BuildMode.profile,
),
contains('flutter_aot_runner'),
);
expect(artifacts.getArtifactPath(
Artifact.fuchsiaFlutterRunner,
platform: TargetPlatform.fuchsia_x64,
mode: BuildMode.release,
),
contains('flutter_aot_product_runner'),
);
expect(artifacts.getArtifactPath(
Artifact.fuchsiaFlutterRunner,
platform: TargetPlatform.fuchsia_x64,
mode: BuildMode.jitRelease,
),
contains('flutter_jit_product_runner'),
);
});
group('Fuchsia app start and stop: ', () {
MemoryFileSystem memoryFileSystem;
FakeOperatingSystemUtils osUtils;
FakeFuchsiaDeviceTools fuchsiaDeviceTools;
@ -420,7 +455,7 @@ void main() {
mode: anyNamed('mode'),
)).thenReturn(patchedSdk.path);
when(mockArtifacts.getArtifactPath(
Artifact.fuchsiaFlutterJitRunner,
Artifact.fuchsiaFlutterRunner,
platform: anyNamed('platform'),
mode: anyNamed('mode'),
)).thenReturn(runner.path);
@ -650,6 +685,7 @@ void main() {
}, overrides: <Type, Generator>{
ProcessManager: () => mockSuccessProcessManager,
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
});
testUsingContext('returns "Fuchsia" when device command fails', () async {
@ -658,6 +694,7 @@ void main() {
}, overrides: <Type, Generator>{
ProcessManager: () => mockFailureProcessManager,
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
});
testUsingContext('returns "Fuchsia" when device gives an empty result', () async {
@ -666,6 +703,7 @@ void main() {
}, overrides: <Type, Generator>{
ProcessManager: () => emptyStdoutProcessManager,
FuchsiaArtifacts: () => FuchsiaArtifacts(sshConfig: sshConfig),
FuchsiaSdk: () => MockFuchsiaSdk(),
});
});
}
@ -722,12 +760,16 @@ Process _createMockProcess({
}
class MockFuchsiaDevice extends Mock implements FuchsiaDevice {
MockFuchsiaDevice(this.id, this.portForwarder, this.ipv6);
MockFuchsiaDevice(this.id, this.portForwarder, this._ipv6);
final bool _ipv6;
@override
final bool ipv6;
Future<bool> get ipv6 async => _ipv6;
@override
final String id;
@override
final DevicePortForwarder portForwarder;
@ -1073,7 +1115,7 @@ class FakeFuchsiaDevFinder implements FuchsiaDevFinder {
}
@override
Future<String> resolve(String deviceName) async {
Future<String> resolve(String deviceName, {bool local = false}) async {
return '192.168.42.10';
}
}
@ -1085,7 +1127,7 @@ class FailingDevFinder implements FuchsiaDevFinder {
}
@override
Future<String> resolve(String deviceName) async {
Future<String> resolve(String deviceName, {bool local = false}) async {
return null;
}
}