Introduce --preview-dart-2
option to run new frontend compiler in flutter tools. (#11741)
This adds --preview-dart-2 flag that enables use of Dart 2.0 Frontend in Flutter tools.
This commit is contained in:
parent
8c36ccf534
commit
c5750cd7ea
@ -65,6 +65,7 @@ if [ ! -d "$FLUTTER_ROOT/.git" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
FLUTTER_TOOL_ARGS="--assert-initializer $FLUTTER_TOOL_ARGS"
|
||||||
# To debug the tool, you can uncomment the following lines to enable checked mode and set an observatory port:
|
# To debug the tool, you can uncomment the following lines to enable checked mode and set an observatory port:
|
||||||
# FLUTTER_TOOL_ARGS="--checked $FLUTTER_TOOL_ARGS"
|
# FLUTTER_TOOL_ARGS="--checked $FLUTTER_TOOL_ARGS"
|
||||||
# FLUTTER_TOOL_ARGS="$FLUTTER_TOOL_ARGS --observe=65432"
|
# FLUTTER_TOOL_ARGS="$FLUTTER_TOOL_ARGS --observe=65432"
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2017 The Chromium 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 'package:flutter_devicelab/tasks/perf_tests.dart';
|
||||||
|
import 'package:flutter_devicelab/framework/framework.dart';
|
||||||
|
|
||||||
|
Future<Null> main() async {
|
||||||
|
await task(createFlutterGalleryPreviewDart2BuildTest());
|
||||||
|
}
|
@ -42,6 +42,10 @@ TaskFunction createFlutterGalleryBuildTest() {
|
|||||||
return new BuildTest('${flutterDirectory.path}/examples/flutter_gallery');
|
return new BuildTest('${flutterDirectory.path}/examples/flutter_gallery');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TaskFunction createFlutterGalleryPreviewDart2BuildTest() {
|
||||||
|
return new BuildTest('${flutterDirectory.path}/examples/flutter_gallery', previewDart2: true);
|
||||||
|
}
|
||||||
|
|
||||||
TaskFunction createComplexLayoutBuildTest() {
|
TaskFunction createComplexLayoutBuildTest() {
|
||||||
return new BuildTest('${flutterDirectory.path}/dev/benchmarks/complex_layout');
|
return new BuildTest('${flutterDirectory.path}/dev/benchmarks/complex_layout');
|
||||||
}
|
}
|
||||||
@ -165,9 +169,9 @@ class PerfTest {
|
|||||||
/// Measures how long it takes to build a Flutter app and how big the compiled
|
/// Measures how long it takes to build a Flutter app and how big the compiled
|
||||||
/// code is.
|
/// code is.
|
||||||
class BuildTest {
|
class BuildTest {
|
||||||
|
const BuildTest(this.testDirectory, {this.previewDart2: false});
|
||||||
|
|
||||||
const BuildTest(this.testDirectory);
|
final bool previewDart2;
|
||||||
|
|
||||||
final String testDirectory;
|
final String testDirectory;
|
||||||
|
|
||||||
Future<TaskResult> call() async {
|
Future<TaskResult> call() async {
|
||||||
@ -176,8 +180,8 @@ class BuildTest {
|
|||||||
await device.unlock();
|
await device.unlock();
|
||||||
await flutter('packages', options: <String>['get']);
|
await flutter('packages', options: <String>['get']);
|
||||||
|
|
||||||
final Map<String, dynamic> aotResults = await _buildAot();
|
final Map<String, dynamic> aotResults = await _buildAot(previewDart2);
|
||||||
final Map<String, dynamic> debugResults = await _buildDebug();
|
final Map<String, dynamic> debugResults = await _buildDebug(previewDart2);
|
||||||
|
|
||||||
final Map<String, dynamic> metrics = <String, dynamic>{}
|
final Map<String, dynamic> metrics = <String, dynamic>{}
|
||||||
..addAll(aotResults)
|
..addAll(aotResults)
|
||||||
@ -187,16 +191,19 @@ class BuildTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Map<String, dynamic>> _buildAot() async {
|
static Future<Map<String, dynamic>> _buildAot(bool previewDart2) async {
|
||||||
await flutter('build', options: <String>['clean']);
|
await flutter('build', options: <String>['clean']);
|
||||||
final Stopwatch watch = new Stopwatch()..start();
|
final Stopwatch watch = new Stopwatch()..start();
|
||||||
final String buildLog = await evalFlutter('build', options: <String>[
|
final List<String> options = <String>[
|
||||||
'aot',
|
'aot',
|
||||||
'-v',
|
'-v',
|
||||||
'--release',
|
'--release',
|
||||||
'--no-pub',
|
'--no-pub',
|
||||||
'--target-platform', 'android-arm' // Generate blobs instead of assembly.
|
'--target-platform', 'android-arm', // Generate blobs instead of assembly.
|
||||||
]);
|
];
|
||||||
|
if (previewDart2)
|
||||||
|
options.add('--preview-dart-2');
|
||||||
|
final String buildLog = await evalFlutter('build', options: options);
|
||||||
watch.stop();
|
watch.stop();
|
||||||
|
|
||||||
final RegExp metricExpression = new RegExp(r'([a-zA-Z]+)\(CodeSize\)\: (\d+)');
|
final RegExp metricExpression = new RegExp(r'([a-zA-Z]+)\(CodeSize\)\: (\d+)');
|
||||||
@ -210,7 +217,7 @@ class BuildTest {
|
|||||||
return metrics;
|
return metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<Map<String, dynamic>> _buildDebug() async {
|
static Future<Map<String, dynamic>> _buildDebug(bool previewDart2) async {
|
||||||
await flutter('build', options: <String>['clean']);
|
await flutter('build', options: <String>['clean']);
|
||||||
|
|
||||||
final Stopwatch watch = new Stopwatch();
|
final Stopwatch watch = new Stopwatch();
|
||||||
@ -221,7 +228,10 @@ class BuildTest {
|
|||||||
watch.stop();
|
watch.stop();
|
||||||
} else {
|
} else {
|
||||||
watch.start();
|
watch.start();
|
||||||
await flutter('build', options: <String>['apk', '--debug']);
|
final List<String> options = <String>['apk', '--debug'];
|
||||||
|
if (previewDart2)
|
||||||
|
options.add('--preview-dart-2');
|
||||||
|
await flutter('build', options: options);
|
||||||
watch.stop();
|
watch.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,9 +222,9 @@ class FlutterPlugin implements Plugin<Project> {
|
|||||||
target = project.property('target')
|
target = project.property('target')
|
||||||
}
|
}
|
||||||
|
|
||||||
File kernel
|
Boolean previewDart2Value = false
|
||||||
if (project.hasProperty('kernel')) {
|
if (project.hasProperty('preview-dart-2')) {
|
||||||
kernel = project.file(project.property('kernel'))
|
previewDart2Value = project.property('preview-dart-2')
|
||||||
}
|
}
|
||||||
|
|
||||||
project.android.applicationVariants.all { variant ->
|
project.android.applicationVariants.all { variant ->
|
||||||
@ -243,7 +243,7 @@ class FlutterPlugin implements Plugin<Project> {
|
|||||||
localEngine this.localEngine
|
localEngine this.localEngine
|
||||||
localEngineSrcPath this.localEngineSrcPath
|
localEngineSrcPath this.localEngineSrcPath
|
||||||
targetPath target
|
targetPath target
|
||||||
kernelFile kernel
|
previewDart2 previewDart2Value
|
||||||
sourceDir project.file(project.flutter.source)
|
sourceDir project.file(project.flutter.source)
|
||||||
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}")
|
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}")
|
||||||
}
|
}
|
||||||
@ -256,7 +256,7 @@ class FlutterPlugin implements Plugin<Project> {
|
|||||||
localEngine this.localEngine
|
localEngine this.localEngine
|
||||||
localEngineSrcPath this.localEngineSrcPath
|
localEngineSrcPath this.localEngineSrcPath
|
||||||
targetPath target
|
targetPath target
|
||||||
kernelFile kernel
|
previewDart2 previewDart2Value
|
||||||
sourceDir project.file(project.flutter.source)
|
sourceDir project.file(project.flutter.source)
|
||||||
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}")
|
intermediateDir project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}")
|
||||||
}
|
}
|
||||||
@ -285,8 +285,8 @@ abstract class BaseFlutterTask extends DefaultTask {
|
|||||||
String localEngineSrcPath
|
String localEngineSrcPath
|
||||||
@Input
|
@Input
|
||||||
String targetPath
|
String targetPath
|
||||||
@Optional @InputFile
|
@Optional
|
||||||
File kernelFile
|
Boolean previewDart2
|
||||||
File sourceDir
|
File sourceDir
|
||||||
File intermediateDir
|
File intermediateDir
|
||||||
|
|
||||||
@ -319,6 +319,9 @@ abstract class BaseFlutterTask extends DefaultTask {
|
|||||||
args "--target", targetPath
|
args "--target", targetPath
|
||||||
args "--target-platform", "android-arm"
|
args "--target-platform", "android-arm"
|
||||||
args "--output-dir", "${intermediateDir}"
|
args "--output-dir", "${intermediateDir}"
|
||||||
|
if (previewDart2) {
|
||||||
|
args "--preview-dart-2"
|
||||||
|
}
|
||||||
args "--${buildMode}"
|
args "--${buildMode}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,15 +336,17 @@ abstract class BaseFlutterTask extends DefaultTask {
|
|||||||
args "build", "flx"
|
args "build", "flx"
|
||||||
args "--suppress-analytics"
|
args "--suppress-analytics"
|
||||||
args "--target", targetPath
|
args "--target", targetPath
|
||||||
if (kernelFile != null) {
|
if (previewDart2) {
|
||||||
args "--kernel", kernelFile.absolutePath
|
args "--preview-dart-2"
|
||||||
}
|
}
|
||||||
args "--output-file", "${intermediateDir}/app.flx"
|
args "--output-file", "${intermediateDir}/app.flx"
|
||||||
if (buildMode != "debug") {
|
if (buildMode != "debug") {
|
||||||
args "--precompiled"
|
args "--precompiled"
|
||||||
} else {
|
} else {
|
||||||
args "--snapshot", "${intermediateDir}/snapshot_blob.bin"
|
if (!previewDart2) {
|
||||||
args "--depfile", "${intermediateDir}/snapshot_blob.bin.d"
|
args "--snapshot", "${intermediateDir}/snapshot_blob.bin"
|
||||||
|
args "--depfile", "${intermediateDir}/snapshot_blob.bin.d"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
args "--working-dir", "${intermediateDir}/flx"
|
args "--working-dir", "${intermediateDir}/flx"
|
||||||
}
|
}
|
||||||
|
@ -343,7 +343,6 @@ class AndroidDevice extends Device {
|
|||||||
String route,
|
String route,
|
||||||
DebuggingOptions debuggingOptions,
|
DebuggingOptions debuggingOptions,
|
||||||
Map<String, dynamic> platformArgs,
|
Map<String, dynamic> platformArgs,
|
||||||
String kernelPath,
|
|
||||||
bool prebuiltApplication: false,
|
bool prebuiltApplication: false,
|
||||||
bool applicationNeedsRebuild: false,
|
bool applicationNeedsRebuild: false,
|
||||||
bool usesTerminalUi: true,
|
bool usesTerminalUi: true,
|
||||||
@ -361,7 +360,6 @@ class AndroidDevice extends Device {
|
|||||||
await buildApk(
|
await buildApk(
|
||||||
target: mainPath,
|
target: mainPath,
|
||||||
buildInfo: debuggingOptions.buildInfo,
|
buildInfo: debuggingOptions.buildInfo,
|
||||||
kernelPath: kernelPath,
|
|
||||||
);
|
);
|
||||||
// Package has been built, so we can get the updated application ID and
|
// Package has been built, so we can get the updated application ID and
|
||||||
// activity name from the .apk.
|
// activity name from the .apk.
|
||||||
|
@ -192,7 +192,7 @@ void updateLocalProperties({String projectPath, BuildInfo buildInfo}) {
|
|||||||
settings.writeContents(localProperties);
|
settings.writeContents(localProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Null> buildGradleProject(BuildInfo buildInfo, String target, String kernelPath) async {
|
Future<Null> buildGradleProject(BuildInfo buildInfo, String target) async {
|
||||||
// Update the local.properties file with the build mode.
|
// Update the local.properties file with the build mode.
|
||||||
// FlutterPlugin v1 reads local.properties to determine build mode. Plugin v2
|
// FlutterPlugin v1 reads local.properties to determine build mode. Plugin v2
|
||||||
// uses the standard Android way to determine what to build, but we still
|
// uses the standard Android way to determine what to build, but we still
|
||||||
@ -211,7 +211,7 @@ Future<Null> buildGradleProject(BuildInfo buildInfo, String target, String kerne
|
|||||||
case FlutterPluginVersion.managed:
|
case FlutterPluginVersion.managed:
|
||||||
// Fall through. Managed plugin builds the same way as plugin v2.
|
// Fall through. Managed plugin builds the same way as plugin v2.
|
||||||
case FlutterPluginVersion.v2:
|
case FlutterPluginVersion.v2:
|
||||||
return _buildGradleProjectV2(gradle, buildInfo, target, kernelPath);
|
return _buildGradleProjectV2(gradle, buildInfo, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ Future<Null> _buildGradleProjectV1(String gradle) async {
|
|||||||
printStatus('Built $gradleAppOutV1 (${getSizeAsMB(apkFile.lengthSync())}).');
|
printStatus('Built $gradleAppOutV1 (${getSizeAsMB(apkFile.lengthSync())}).');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String target, String kernelPath) async {
|
Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String target) async {
|
||||||
final GradleProject project = await _gradleProject();
|
final GradleProject project = await _gradleProject();
|
||||||
final String assembleTask = project.assembleTaskFor(buildInfo);
|
final String assembleTask = project.assembleTaskFor(buildInfo);
|
||||||
if (assembleTask == null) {
|
if (assembleTask == null) {
|
||||||
@ -266,8 +266,8 @@ Future<Null> _buildGradleProjectV2(String gradle, BuildInfo buildInfo, String ta
|
|||||||
if (target != null) {
|
if (target != null) {
|
||||||
command.add('-Ptarget=$target');
|
command.add('-Ptarget=$target');
|
||||||
}
|
}
|
||||||
if (kernelPath != null)
|
if (buildInfo.previewDart2)
|
||||||
command.add('-Pkernel=$kernelPath');
|
command.add('-Ppreview-dart-2=true');
|
||||||
command.add(assembleTask);
|
command.add(assembleTask);
|
||||||
final int exitCode = await runCommandAndStreamOutput(
|
final int exitCode = await runCommandAndStreamOutput(
|
||||||
command,
|
command,
|
||||||
|
@ -2,6 +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.
|
||||||
|
|
||||||
|
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/platform.dart';
|
import 'base/platform.dart';
|
||||||
@ -16,7 +18,12 @@ enum Artifact {
|
|||||||
snapshotDart,
|
snapshotDart,
|
||||||
flutterFramework,
|
flutterFramework,
|
||||||
vmSnapshotData,
|
vmSnapshotData,
|
||||||
isolateSnapshotData
|
isolateSnapshotData,
|
||||||
|
platformKernelDill,
|
||||||
|
platformLibrariesJson,
|
||||||
|
flutterPatchedSdkPath,
|
||||||
|
frontendServerSnapshotForEngineDartSdk,
|
||||||
|
engineDartSdkPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
String _artifactToFileName(Artifact artifact) {
|
String _artifactToFileName(Artifact artifact) {
|
||||||
@ -37,17 +44,37 @@ String _artifactToFileName(Artifact artifact) {
|
|||||||
return 'vm_isolate_snapshot.bin';
|
return 'vm_isolate_snapshot.bin';
|
||||||
case Artifact.isolateSnapshotData:
|
case Artifact.isolateSnapshotData:
|
||||||
return 'isolate_snapshot.bin';
|
return 'isolate_snapshot.bin';
|
||||||
|
case Artifact.platformKernelDill:
|
||||||
|
return 'platform.dill';
|
||||||
|
case Artifact.platformLibrariesJson:
|
||||||
|
return 'libraries.json';
|
||||||
|
case Artifact.flutterPatchedSdkPath:
|
||||||
|
assert(false, 'No filename for sdk path, should not be invoked');
|
||||||
|
return null;
|
||||||
|
case Artifact.engineDartSdkPath:
|
||||||
|
return 'dart-sdk';
|
||||||
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
|
return 'frontend_server.dart.snapshot';
|
||||||
}
|
}
|
||||||
assert(false, 'Invalid artifact $artifact.');
|
assert(false, 'Invalid artifact $artifact.');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EngineBuildPaths {
|
||||||
|
const EngineBuildPaths({ @required this.targetEngine, @required this.hostEngine }):
|
||||||
|
assert(targetEngine != null),
|
||||||
|
assert(hostEngine != null);
|
||||||
|
|
||||||
|
final String targetEngine;
|
||||||
|
final String hostEngine;
|
||||||
|
}
|
||||||
|
|
||||||
// Manages the engine artifacts of Flutter.
|
// Manages the engine artifacts of Flutter.
|
||||||
abstract class Artifacts {
|
abstract class Artifacts {
|
||||||
static Artifacts get instance => context[Artifacts];
|
static Artifacts get instance => context[Artifacts];
|
||||||
|
|
||||||
static void useLocalEngine(String engineSrcPath, String engineOutPath) {
|
static void useLocalEngine(String engineSrcPath, EngineBuildPaths engineBuildPaths) {
|
||||||
context.setVariable(Artifacts, new LocalEngineArtifacts(engineSrcPath, engineOutPath));
|
context.setVariable(Artifacts, new LocalEngineArtifacts(engineSrcPath, engineBuildPaths.targetEngine, engineBuildPaths.hostEngine));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the requested [artifact] for the [platform] and [mode] combination.
|
// Returns the requested [artifact] for the [platform] and [mode] combination.
|
||||||
@ -91,6 +118,7 @@ class CachedArtifacts extends Artifacts {
|
|||||||
switch (artifact) {
|
switch (artifact) {
|
||||||
case Artifact.dartIoEntriesTxt:
|
case Artifact.dartIoEntriesTxt:
|
||||||
case Artifact.dartVmEntryPointsTxt:
|
case Artifact.dartVmEntryPointsTxt:
|
||||||
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
|
assert(mode != BuildMode.debug, 'Artifact $artifact only available in non-debug mode.');
|
||||||
return fs.path.join(engineDir, _artifactToFileName(artifact));
|
return fs.path.join(engineDir, _artifactToFileName(artifact));
|
||||||
case Artifact.genSnapshot:
|
case Artifact.genSnapshot:
|
||||||
@ -111,6 +139,7 @@ class CachedArtifacts extends Artifacts {
|
|||||||
case Artifact.genSnapshot:
|
case Artifact.genSnapshot:
|
||||||
case Artifact.snapshotDart:
|
case Artifact.snapshotDart:
|
||||||
case Artifact.flutterFramework:
|
case Artifact.flutterFramework:
|
||||||
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
return fs.path.join(engineDir, _artifactToFileName(artifact));
|
return fs.path.join(engineDir, _artifactToFileName(artifact));
|
||||||
default:
|
default:
|
||||||
assert(false, 'Artifact $artifact not available for platform $platform.');
|
assert(false, 'Artifact $artifact not available for platform $platform.');
|
||||||
@ -118,6 +147,11 @@ class CachedArtifacts extends Artifacts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _getFlutterPatchedSdkPath() {
|
||||||
|
final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
|
||||||
|
return fs.path.join(engineArtifactsPath, 'common', 'flutter_patched_sdk');
|
||||||
|
}
|
||||||
|
|
||||||
String _getHostArtifactPath(Artifact artifact, TargetPlatform platform) {
|
String _getHostArtifactPath(Artifact artifact, TargetPlatform platform) {
|
||||||
switch (artifact) {
|
switch (artifact) {
|
||||||
case Artifact.genSnapshot:
|
case Artifact.genSnapshot:
|
||||||
@ -131,9 +165,17 @@ class CachedArtifacts extends Artifacts {
|
|||||||
fallThrough:
|
fallThrough:
|
||||||
case Artifact.vmSnapshotData:
|
case Artifact.vmSnapshotData:
|
||||||
case Artifact.isolateSnapshotData:
|
case Artifact.isolateSnapshotData:
|
||||||
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
|
case Artifact.engineDartSdkPath:
|
||||||
final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
|
final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
|
||||||
final String platformDirName = getNameForTargetPlatform(platform);
|
final String platformDirName = getNameForTargetPlatform(platform);
|
||||||
return fs.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact));
|
return fs.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact));
|
||||||
|
case Artifact.platformKernelDill:
|
||||||
|
return fs.path.join(_getFlutterPatchedSdkPath(), _artifactToFileName(artifact));
|
||||||
|
case Artifact.platformLibrariesJson:
|
||||||
|
return fs.path.join(_getFlutterPatchedSdkPath(), 'lib', _artifactToFileName(artifact));
|
||||||
|
case Artifact.flutterPatchedSdkPath:
|
||||||
|
return _getFlutterPatchedSdkPath();
|
||||||
default:
|
default:
|
||||||
assert(false, 'Artifact $artifact not available for platform $platform.');
|
assert(false, 'Artifact $artifact not available for platform $platform.');
|
||||||
return null;
|
return null;
|
||||||
@ -179,8 +221,9 @@ class CachedArtifacts extends Artifacts {
|
|||||||
class LocalEngineArtifacts extends Artifacts {
|
class LocalEngineArtifacts extends Artifacts {
|
||||||
final String _engineSrcPath;
|
final String _engineSrcPath;
|
||||||
final String engineOutPath; // TODO(goderbauer): This should be private.
|
final String engineOutPath; // TODO(goderbauer): This should be private.
|
||||||
|
String _hostEngineOutPath;
|
||||||
|
|
||||||
LocalEngineArtifacts(this._engineSrcPath, this.engineOutPath);
|
LocalEngineArtifacts(this._engineSrcPath, this.engineOutPath, this._hostEngineOutPath);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
|
String getArtifactPath(Artifact artifact, [TargetPlatform platform, BuildMode mode]) {
|
||||||
@ -198,8 +241,18 @@ class LocalEngineArtifacts extends Artifacts {
|
|||||||
case Artifact.isolateSnapshotData:
|
case Artifact.isolateSnapshotData:
|
||||||
case Artifact.vmSnapshotData:
|
case Artifact.vmSnapshotData:
|
||||||
return fs.path.join(engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', _artifactToFileName(artifact));
|
return fs.path.join(engineOutPath, 'gen', 'flutter', 'lib', 'snapshot', _artifactToFileName(artifact));
|
||||||
|
case Artifact.platformKernelDill:
|
||||||
|
return fs.path.join(_getFlutterPatchedSdkPath(), _artifactToFileName(artifact));
|
||||||
|
case Artifact.platformLibrariesJson:
|
||||||
|
return fs.path.join(_getFlutterPatchedSdkPath(), 'lib', _artifactToFileName(artifact));
|
||||||
case Artifact.flutterFramework:
|
case Artifact.flutterFramework:
|
||||||
return fs.path.join(engineOutPath, _artifactToFileName(artifact));
|
return fs.path.join(engineOutPath, _artifactToFileName(artifact));
|
||||||
|
case Artifact.flutterPatchedSdkPath:
|
||||||
|
return _getFlutterPatchedSdkPath();
|
||||||
|
case Artifact.frontendServerSnapshotForEngineDartSdk:
|
||||||
|
return fs.path.join(_hostEngineOutPath, 'gen', _artifactToFileName(artifact));
|
||||||
|
case Artifact.engineDartSdkPath:
|
||||||
|
return fs.path.join(_hostEngineOutPath, 'dart-sdk');
|
||||||
}
|
}
|
||||||
assert(false, 'Invalid artifact $artifact.');
|
assert(false, 'Invalid artifact $artifact.');
|
||||||
return null;
|
return null;
|
||||||
@ -210,6 +263,10 @@ class LocalEngineArtifacts extends Artifacts {
|
|||||||
return fs.path.basename(engineOutPath);
|
return fs.path.basename(engineOutPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _getFlutterPatchedSdkPath() {
|
||||||
|
return fs.path.join(engineOutPath, 'flutter_patched_sdk');
|
||||||
|
}
|
||||||
|
|
||||||
String _genSnapshotPath() {
|
String _genSnapshotPath() {
|
||||||
const List<String> clangDirs = const <String>['clang_x86', 'clang_x64', 'clang_i386'];
|
const List<String> clangDirs = const <String>['clang_x86', 'clang_x64', 'clang_i386'];
|
||||||
final String genSnapshotName = _artifactToFileName(Artifact.genSnapshot);
|
final String genSnapshotName = _artifactToFileName(Artifact.genSnapshot);
|
||||||
|
@ -10,7 +10,7 @@ import 'globals.dart';
|
|||||||
|
|
||||||
/// Information about a build to be performed or used.
|
/// Information about a build to be performed or used.
|
||||||
class BuildInfo {
|
class BuildInfo {
|
||||||
const BuildInfo(this.mode, this.flavor);
|
const BuildInfo(this.mode, this.flavor, { this.previewDart2 });
|
||||||
|
|
||||||
final BuildMode mode;
|
final BuildMode mode;
|
||||||
/// Represents a custom Android product flavor or an Xcode scheme, null for
|
/// Represents a custom Android product flavor or an Xcode scheme, null for
|
||||||
@ -21,6 +21,9 @@ class BuildInfo {
|
|||||||
/// Mode-Flavor (e.g. Release-Paid).
|
/// Mode-Flavor (e.g. Release-Paid).
|
||||||
final String flavor;
|
final String flavor;
|
||||||
|
|
||||||
|
// Whether build should be done using Dart2 Frontend parser.
|
||||||
|
final bool previewDart2;
|
||||||
|
|
||||||
static const BuildInfo debug = const BuildInfo(BuildMode.debug, null);
|
static const BuildInfo debug = const BuildInfo(BuildMode.debug, null);
|
||||||
static const BuildInfo profile = const BuildInfo(BuildMode.profile, null);
|
static const BuildInfo profile = const BuildInfo(BuildMode.profile, null);
|
||||||
static const BuildInfo release = const BuildInfo(BuildMode.release, null);
|
static const BuildInfo release = const BuildInfo(BuildMode.release, null);
|
||||||
|
@ -255,6 +255,8 @@ class FlutterEngine extends CachedArtifact {
|
|||||||
List<List<String>> _getBinaryDirs() {
|
List<List<String>> _getBinaryDirs() {
|
||||||
final List<List<String>> binaryDirs = <List<String>>[];
|
final List<List<String>> binaryDirs = <List<String>>[];
|
||||||
|
|
||||||
|
binaryDirs.add(<String>['common', 'flutter_patched_sdk.zip']);
|
||||||
|
|
||||||
if (cache.includeAllPlatforms)
|
if (cache.includeAllPlatforms)
|
||||||
binaryDirs
|
binaryDirs
|
||||||
..addAll(_osxBinaryDirs)
|
..addAll(_osxBinaryDirs)
|
||||||
@ -281,18 +283,21 @@ class FlutterEngine extends CachedArtifact {
|
|||||||
|
|
||||||
List<List<String>> get _osxBinaryDirs => <List<String>>[
|
List<List<String>> get _osxBinaryDirs => <List<String>>[
|
||||||
<String>['darwin-x64', 'darwin-x64/artifacts.zip'],
|
<String>['darwin-x64', 'darwin-x64/artifacts.zip'],
|
||||||
|
<String>['darwin-x64', 'dart-sdk-darwin-x64.zip'],
|
||||||
<String>['android-arm-profile/darwin-x64', 'android-arm-profile/darwin-x64.zip'],
|
<String>['android-arm-profile/darwin-x64', 'android-arm-profile/darwin-x64.zip'],
|
||||||
<String>['android-arm-release/darwin-x64', 'android-arm-release/darwin-x64.zip'],
|
<String>['android-arm-release/darwin-x64', 'android-arm-release/darwin-x64.zip'],
|
||||||
];
|
];
|
||||||
|
|
||||||
List<List<String>> get _linuxBinaryDirs => <List<String>>[
|
List<List<String>> get _linuxBinaryDirs => <List<String>>[
|
||||||
<String>['linux-x64', 'linux-x64/artifacts.zip'],
|
<String>['linux-x64', 'linux-x64/artifacts.zip'],
|
||||||
|
<String>['linux-x64', 'dart-sdk-linux-x64.zip'],
|
||||||
<String>['android-arm-profile/linux-x64', 'android-arm-profile/linux-x64.zip'],
|
<String>['android-arm-profile/linux-x64', 'android-arm-profile/linux-x64.zip'],
|
||||||
<String>['android-arm-release/linux-x64', 'android-arm-release/linux-x64.zip'],
|
<String>['android-arm-release/linux-x64', 'android-arm-release/linux-x64.zip'],
|
||||||
];
|
];
|
||||||
|
|
||||||
List<List<String>> get _windowsBinaryDirs => <List<String>>[
|
List<List<String>> get _windowsBinaryDirs => <List<String>>[
|
||||||
<String>['windows-x64', 'windows-x64/artifacts.zip'],
|
<String>['windows-x64', 'windows-x64/artifacts.zip'],
|
||||||
|
<String>['windows-x64', 'dart-sdk-windows-x64.zip'],
|
||||||
<String>['android-arm-profile/windows-x64', 'android-arm-profile/windows-x64.zip'],
|
<String>['android-arm-profile/windows-x64', 'android-arm-profile/windows-x64.zip'],
|
||||||
<String>['android-arm-release/windows-x64', 'android-arm-release/windows-x64.zip'],
|
<String>['android-arm-release/windows-x64', 'android-arm-release/windows-x64.zip'],
|
||||||
];
|
];
|
||||||
|
@ -13,6 +13,7 @@ import '../base/process.dart';
|
|||||||
import '../base/process_manager.dart';
|
import '../base/process_manager.dart';
|
||||||
import '../base/utils.dart';
|
import '../base/utils.dart';
|
||||||
import '../build_info.dart';
|
import '../build_info.dart';
|
||||||
|
import '../compile.dart';
|
||||||
import '../dart/package_map.dart';
|
import '../dart/package_map.dart';
|
||||||
import '../globals.dart';
|
import '../globals.dart';
|
||||||
import '../resident_runner.dart';
|
import '../resident_runner.dart';
|
||||||
@ -35,7 +36,8 @@ class BuildAotCommand extends BuildSubCommand {
|
|||||||
allowed: <String>['android-arm', 'ios']
|
allowed: <String>['android-arm', 'ios']
|
||||||
)
|
)
|
||||||
..addFlag('interpreter')
|
..addFlag('interpreter')
|
||||||
..addFlag('quiet', defaultsTo: false);
|
..addFlag('quiet', defaultsTo: false)
|
||||||
|
..addFlag('preview-dart-2', negatable: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -63,7 +65,8 @@ class BuildAotCommand extends BuildSubCommand {
|
|||||||
platform,
|
platform,
|
||||||
getBuildMode(),
|
getBuildMode(),
|
||||||
outputPath: argResults['output-dir'],
|
outputPath: argResults['output-dir'],
|
||||||
interpreter: argResults['interpreter']
|
interpreter: argResults['interpreter'],
|
||||||
|
previewDart2: argResults['preview-dart-2'],
|
||||||
);
|
);
|
||||||
status?.stop();
|
status?.stop();
|
||||||
|
|
||||||
@ -90,7 +93,8 @@ Future<String> buildAotSnapshot(
|
|||||||
TargetPlatform platform,
|
TargetPlatform platform,
|
||||||
BuildMode buildMode, {
|
BuildMode buildMode, {
|
||||||
String outputPath,
|
String outputPath,
|
||||||
bool interpreter: false
|
bool interpreter: false,
|
||||||
|
bool previewDart2: false,
|
||||||
}) async {
|
}) async {
|
||||||
outputPath ??= getAotBuildDirectory();
|
outputPath ??= getAotBuildDirectory();
|
||||||
try {
|
try {
|
||||||
@ -99,7 +103,8 @@ Future<String> buildAotSnapshot(
|
|||||||
platform,
|
platform,
|
||||||
buildMode,
|
buildMode,
|
||||||
outputPath: outputPath,
|
outputPath: outputPath,
|
||||||
interpreter: interpreter
|
interpreter: interpreter,
|
||||||
|
previewDart2: previewDart2,
|
||||||
);
|
);
|
||||||
} on String catch (error) {
|
} on String catch (error) {
|
||||||
// Catch the String exceptions thrown from the `runCheckedSync` methods below.
|
// Catch the String exceptions thrown from the `runCheckedSync` methods below.
|
||||||
@ -114,7 +119,8 @@ Future<String> _buildAotSnapshot(
|
|||||||
TargetPlatform platform,
|
TargetPlatform platform,
|
||||||
BuildMode buildMode, {
|
BuildMode buildMode, {
|
||||||
String outputPath,
|
String outputPath,
|
||||||
bool interpreter: false
|
bool interpreter: false,
|
||||||
|
bool previewDart2: false,
|
||||||
}) async {
|
}) async {
|
||||||
outputPath ??= getAotBuildDirectory();
|
outputPath ??= getAotBuildDirectory();
|
||||||
if (!isAotBuildMode(buildMode) && !interpreter) {
|
if (!isAotBuildMode(buildMode) && !interpreter) {
|
||||||
@ -137,7 +143,11 @@ Future<String> _buildAotSnapshot(
|
|||||||
final String isolateSnapshotInstructions = fs.path.join(outputDir.path, 'isolate_snapshot_instr');
|
final String isolateSnapshotInstructions = fs.path.join(outputDir.path, 'isolate_snapshot_instr');
|
||||||
final String dependencies = fs.path.join(outputDir.path, 'snapshot.d');
|
final String dependencies = fs.path.join(outputDir.path, 'snapshot.d');
|
||||||
|
|
||||||
final String vmEntryPoints = artifacts.getArtifactPath(Artifact.dartVmEntryPointsTxt, platform, buildMode);
|
final String vmEntryPoints = artifacts.getArtifactPath(
|
||||||
|
Artifact.dartVmEntryPointsTxt,
|
||||||
|
platform,
|
||||||
|
buildMode,
|
||||||
|
);
|
||||||
final String ioEntryPoints = artifacts.getArtifactPath(Artifact.dartIoEntriesTxt, platform, buildMode);
|
final String ioEntryPoints = artifacts.getArtifactPath(Artifact.dartIoEntriesTxt, platform, buildMode);
|
||||||
|
|
||||||
final PackageMap packageMap = new PackageMap(PackageMap.globalPackagesPath);
|
final PackageMap packageMap = new PackageMap(PackageMap.globalPackagesPath);
|
||||||
@ -266,6 +276,13 @@ Future<String> _buildAotSnapshot(
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (previewDart2) {
|
||||||
|
mainPath = await compile(
|
||||||
|
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
|
||||||
|
mainPath: mainPath,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
genSnapshotCmd.add(mainPath);
|
genSnapshotCmd.add(mainPath);
|
||||||
|
|
||||||
final SnapshotType snapshotType = new SnapshotType(platform, buildMode);
|
final SnapshotType snapshotType = new SnapshotType(platform, buildMode);
|
||||||
|
@ -35,6 +35,7 @@ class BuildApkCommand extends BuildSubCommand {
|
|||||||
BuildApkCommand() {
|
BuildApkCommand() {
|
||||||
usesTargetOption();
|
usesTargetOption();
|
||||||
addBuildModeFlags();
|
addBuildModeFlags();
|
||||||
|
argParser.addFlag('preview-dart-2', negatable: false);
|
||||||
usesFlavorOption();
|
usesFlavorOption();
|
||||||
usesPubOption();
|
usesPubOption();
|
||||||
}
|
}
|
||||||
@ -51,16 +52,13 @@ class BuildApkCommand extends BuildSubCommand {
|
|||||||
@override
|
@override
|
||||||
Future<Null> runCommand() async {
|
Future<Null> runCommand() async {
|
||||||
await super.runCommand();
|
await super.runCommand();
|
||||||
|
await buildApk(buildInfo: getBuildInfo(), target: targetFile);
|
||||||
final BuildInfo buildInfo = getBuildInfo();
|
|
||||||
await buildApk(buildInfo: buildInfo, target: targetFile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Null> buildApk({
|
Future<Null> buildApk({
|
||||||
String target,
|
String target,
|
||||||
BuildInfo buildInfo: BuildInfo.debug,
|
BuildInfo buildInfo: BuildInfo.debug
|
||||||
String kernelPath,
|
|
||||||
}) async {
|
}) async {
|
||||||
if (!isProjectUsingGradle()) {
|
if (!isProjectUsingGradle()) {
|
||||||
throwToolExit(
|
throwToolExit(
|
||||||
@ -81,5 +79,5 @@ Future<Null> buildApk({
|
|||||||
throwToolExit('Try re-installing or updating your Android SDK.');
|
throwToolExit('Try re-installing or updating your Android SDK.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildGradleProject(buildInfo, target, kernelPath);
|
return buildGradleProject(buildInfo, target);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ class BuildFlxCommand extends BuildSubCommand {
|
|||||||
argParser.addOption('output-file', abbr: 'o', defaultsTo: defaultFlxOutputPath);
|
argParser.addOption('output-file', abbr: 'o', defaultsTo: defaultFlxOutputPath);
|
||||||
argParser.addOption('snapshot', defaultsTo: defaultSnapshotPath);
|
argParser.addOption('snapshot', defaultsTo: defaultSnapshotPath);
|
||||||
argParser.addOption('depfile', defaultsTo: defaultDepfilePath);
|
argParser.addOption('depfile', defaultsTo: defaultDepfilePath);
|
||||||
argParser.addOption('kernel');
|
argParser.addFlag('preview-dart-2', negatable: false);
|
||||||
argParser.addOption('working-dir', defaultsTo: getAssetBuildDirectory());
|
argParser.addOption('working-dir', defaultsTo: getAssetBuildDirectory());
|
||||||
argParser.addFlag('report-licensed-packages', help: 'Whether to report the names of all the packages that are included in the application\'s LICENSE file.', defaultsTo: false);
|
argParser.addFlag('report-licensed-packages', help: 'Whether to report the names of all the packages that are included in the application\'s LICENSE file.', defaultsTo: false);
|
||||||
usesPubOption();
|
usesPubOption();
|
||||||
@ -49,7 +49,7 @@ class BuildFlxCommand extends BuildSubCommand {
|
|||||||
depfilePath: argResults['depfile'],
|
depfilePath: argResults['depfile'],
|
||||||
privateKeyPath: argResults['private-key'],
|
privateKeyPath: argResults['private-key'],
|
||||||
workingDirPath: argResults['working-dir'],
|
workingDirPath: argResults['working-dir'],
|
||||||
kernelPath: argResults['kernel'],
|
previewDart2: argResults['preview-dart-2'],
|
||||||
precompiledSnapshot: argResults['precompiled'],
|
precompiledSnapshot: argResults['precompiled'],
|
||||||
reportLicensedPackages: argResults['report-licensed-packages']
|
reportLicensedPackages: argResults['report-licensed-packages']
|
||||||
);
|
);
|
||||||
|
@ -110,11 +110,10 @@ class RunCommand extends RunCommandBase {
|
|||||||
argParser.addOption('use-application-binary',
|
argParser.addOption('use-application-binary',
|
||||||
hide: !verboseHelp,
|
hide: !verboseHelp,
|
||||||
help: 'Specify a pre-built application binary to use when running.');
|
help: 'Specify a pre-built application binary to use when running.');
|
||||||
argParser.addOption('kernel',
|
argParser.addFlag('preview-dart-2',
|
||||||
hide: !verboseHelp,
|
hide: !verboseHelp,
|
||||||
help: 'Path to a pre-built kernel blob to use when running.\n'
|
defaultsTo: false,
|
||||||
'This option only exists for testing new kernel code execution on devices\n'
|
help: 'Preview Dart 2.0 functionality.');
|
||||||
'and is not needed during normal application development.');
|
|
||||||
argParser.addOption('packages',
|
argParser.addOption('packages',
|
||||||
hide: !verboseHelp,
|
hide: !verboseHelp,
|
||||||
help: 'Specify the path to the .packages file.');
|
help: 'Specify the path to the .packages file.');
|
||||||
@ -177,7 +176,7 @@ class RunCommand extends RunCommandBase {
|
|||||||
@override
|
@override
|
||||||
Future<Map<String, String>> get usageValues async {
|
Future<Map<String, String>> get usageValues async {
|
||||||
final bool isEmulator = await devices[0].isLocalEmulator;
|
final bool isEmulator = await devices[0].isLocalEmulator;
|
||||||
final String deviceType = devices.length == 1
|
final String deviceType = devices.length == 1
|
||||||
? getNameForTargetPlatform(await devices[0].targetPlatform)
|
? getNameForTargetPlatform(await devices[0].targetPlatform)
|
||||||
: 'multiple';
|
: 'multiple';
|
||||||
|
|
||||||
@ -300,7 +299,7 @@ class RunCommand extends RunCommandBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final List<FlutterDevice> flutterDevices = devices.map((Device device) {
|
final List<FlutterDevice> flutterDevices = devices.map((Device device) {
|
||||||
return new FlutterDevice(device);
|
return new FlutterDevice(device, previewDart2: argResults['preview-dart-2']);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
ResidentRunner runner;
|
ResidentRunner runner;
|
||||||
@ -311,7 +310,7 @@ class RunCommand extends RunCommandBase {
|
|||||||
debuggingOptions: _createDebuggingOptions(),
|
debuggingOptions: _createDebuggingOptions(),
|
||||||
benchmarkMode: argResults['benchmark'],
|
benchmarkMode: argResults['benchmark'],
|
||||||
applicationBinary: argResults['use-application-binary'],
|
applicationBinary: argResults['use-application-binary'],
|
||||||
kernelFilePath: argResults['kernel'],
|
previewDart2: argResults['preview-dart-2'],
|
||||||
projectRootPath: argResults['project-root'],
|
projectRootPath: argResults['project-root'],
|
||||||
packagesFilePath: argResults['packages'],
|
packagesFilePath: argResults['packages'],
|
||||||
projectAssets: argResults['project-assets'],
|
projectAssets: argResults['project-assets'],
|
||||||
@ -324,6 +323,7 @@ class RunCommand extends RunCommandBase {
|
|||||||
debuggingOptions: _createDebuggingOptions(),
|
debuggingOptions: _createDebuggingOptions(),
|
||||||
traceStartup: traceStartup,
|
traceStartup: traceStartup,
|
||||||
applicationBinary: argResults['use-application-binary'],
|
applicationBinary: argResults['use-application-binary'],
|
||||||
|
previewDart2: argResults['preview-dart-2'],
|
||||||
stayResident: stayResident,
|
stayResident: stayResident,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
149
packages/flutter_tools/lib/src/compile.dart
Normal file
149
packages/flutter_tools/lib/src/compile.dart
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2017 The Chromium 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 'package:flutter_tools/src/base/process_manager.dart';
|
||||||
|
import 'package:usage/uuid/uuid.dart';
|
||||||
|
|
||||||
|
import 'artifacts.dart';
|
||||||
|
import 'base/file_system.dart';
|
||||||
|
import 'base/io.dart';
|
||||||
|
import 'base/process_manager.dart';
|
||||||
|
import 'globals.dart';
|
||||||
|
|
||||||
|
String _dartExecutable() {
|
||||||
|
final String engineDartSdkPath = artifacts.getArtifactPath(
|
||||||
|
Artifact.engineDartSdkPath
|
||||||
|
);
|
||||||
|
return fs.path.join(engineDartSdkPath, 'bin', 'dart');
|
||||||
|
}
|
||||||
|
|
||||||
|
class _StdoutHandler {
|
||||||
|
String boundaryKey;
|
||||||
|
Completer<String> outputFilename = new Completer<String>();
|
||||||
|
|
||||||
|
void handler(String string) {
|
||||||
|
const String kResultPrefix = 'result ';
|
||||||
|
if (boundaryKey == null) {
|
||||||
|
if (string.startsWith(kResultPrefix))
|
||||||
|
boundaryKey = string.substring(kResultPrefix.length);
|
||||||
|
} else if (string.startsWith(boundaryKey))
|
||||||
|
outputFilename.complete(string.length > boundaryKey.length
|
||||||
|
? string.substring(boundaryKey.length + 1)
|
||||||
|
: null);
|
||||||
|
else
|
||||||
|
printTrace('compile debug message: $string');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> compile({String sdkRoot, String mainPath}) async {
|
||||||
|
final String frontendServer = artifacts.getArtifactPath(
|
||||||
|
Artifact.frontendServerSnapshotForEngineDartSdk
|
||||||
|
);
|
||||||
|
|
||||||
|
// This is a URI, not a file path, so the forward slash is correct even on Windows.
|
||||||
|
if (!sdkRoot.endsWith('/'))
|
||||||
|
sdkRoot = '$sdkRoot/';
|
||||||
|
final Process server = await processManager.start(<String>[
|
||||||
|
_dartExecutable(),
|
||||||
|
frontendServer,
|
||||||
|
'--sdk-root',
|
||||||
|
sdkRoot,
|
||||||
|
mainPath
|
||||||
|
]);
|
||||||
|
|
||||||
|
final _StdoutHandler stdoutHandler = new _StdoutHandler();
|
||||||
|
server.stderr
|
||||||
|
.transform(UTF8.decoder)
|
||||||
|
.listen((String s) { printTrace('compile debug message: $s'); });
|
||||||
|
server.stdout
|
||||||
|
.transform(UTF8.decoder)
|
||||||
|
.transform(const LineSplitter())
|
||||||
|
.listen(stdoutHandler.handler);
|
||||||
|
await server.exitCode;
|
||||||
|
return stdoutHandler.outputFilename.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper around incremental frontend server compiler, that communicates with
|
||||||
|
/// server via stdin/stdout.
|
||||||
|
///
|
||||||
|
/// The wrapper is intended to stay resident in memory as user changes, reloads,
|
||||||
|
/// restarts the Flutter app.
|
||||||
|
class ResidentCompiler {
|
||||||
|
ResidentCompiler(this._sdkRoot) {
|
||||||
|
assert(_sdkRoot != null);
|
||||||
|
// This is a URI, not a file path, so the forward slash is correct even on Windows.
|
||||||
|
if (!_sdkRoot.endsWith('/'))
|
||||||
|
_sdkRoot = '$_sdkRoot/';
|
||||||
|
}
|
||||||
|
|
||||||
|
String _sdkRoot;
|
||||||
|
Process _server;
|
||||||
|
final _StdoutHandler stdoutHandler = new _StdoutHandler();
|
||||||
|
|
||||||
|
/// If invoked for the first time, it compiles Dart script identified by
|
||||||
|
/// [mainPath], [invalidatedFiles] list is ignored.
|
||||||
|
/// Otherwise, [mainPath] is ignored, but [invalidatedFiles] is recompiled
|
||||||
|
/// into new binary.
|
||||||
|
/// Binary file name is returned if compilation was successful, otherwise
|
||||||
|
/// `null` is returned.
|
||||||
|
Future<String> recompile(String mainPath, List<String> invalidatedFiles) async {
|
||||||
|
// First time recompile is called we actually have to compile the app from
|
||||||
|
// scratch ignoring list of invalidated files.
|
||||||
|
if (_server == null)
|
||||||
|
return _compile(mainPath);
|
||||||
|
|
||||||
|
final String inputKey = new Uuid().generateV4();
|
||||||
|
_server.stdin.writeln('recompile $inputKey');
|
||||||
|
for (String invalidatedFile in invalidatedFiles)
|
||||||
|
_server.stdin.writeln(invalidatedFile);
|
||||||
|
_server.stdin.writeln(inputKey);
|
||||||
|
|
||||||
|
return stdoutHandler.outputFilename.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _compile(String scriptFilename) async {
|
||||||
|
if (_server == null) {
|
||||||
|
final String frontendServer = artifacts.getArtifactPath(
|
||||||
|
Artifact.frontendServerSnapshotForEngineDartSdk
|
||||||
|
);
|
||||||
|
_server = await processManager.start(<String>[
|
||||||
|
_dartExecutable(),
|
||||||
|
frontendServer,
|
||||||
|
'--sdk-root',
|
||||||
|
_sdkRoot,
|
||||||
|
'--incremental'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
_server.stdout
|
||||||
|
.transform(UTF8.decoder)
|
||||||
|
.transform(const LineSplitter())
|
||||||
|
.listen(stdoutHandler.handler);
|
||||||
|
_server.stderr
|
||||||
|
.transform(UTF8.decoder)
|
||||||
|
.transform(const LineSplitter())
|
||||||
|
.listen((String s) { printTrace('compile debug message: $s'); });
|
||||||
|
|
||||||
|
_server.stdin.writeln('compile $scriptFilename');
|
||||||
|
|
||||||
|
return stdoutHandler.outputFilename.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Should be invoked when results of compilation are accepted by the client.
|
||||||
|
///
|
||||||
|
/// Either [accept] or [reject] should be called after every [recompile] call.
|
||||||
|
void accept() {
|
||||||
|
_server.stdin.writeln('accept');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should be invoked when results of compilation are rejected by the client.
|
||||||
|
///
|
||||||
|
/// Either [accept] or [reject] should be called after every [recompile] call.
|
||||||
|
void reject() {
|
||||||
|
_server.stdin.writeln('reject');
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ import 'base/context.dart';
|
|||||||
import 'base/file_system.dart';
|
import 'base/file_system.dart';
|
||||||
import 'base/io.dart';
|
import 'base/io.dart';
|
||||||
import 'build_info.dart';
|
import 'build_info.dart';
|
||||||
|
import 'compile.dart';
|
||||||
import 'dart/package_map.dart';
|
import 'dart/package_map.dart';
|
||||||
import 'globals.dart';
|
import 'globals.dart';
|
||||||
import 'vmservice.dart';
|
import 'vmservice.dart';
|
||||||
@ -361,9 +362,12 @@ class DevFS {
|
|||||||
|
|
||||||
/// Update files on the device and return the number of bytes sync'd
|
/// Update files on the device and return the number of bytes sync'd
|
||||||
Future<int> update({
|
Future<int> update({
|
||||||
|
String mainPath,
|
||||||
|
String target,
|
||||||
AssetBundle bundle,
|
AssetBundle bundle,
|
||||||
bool bundleDirty: false,
|
bool bundleDirty: false,
|
||||||
Set<String> fileFilter,
|
Set<String> fileFilter,
|
||||||
|
ResidentCompiler generator,
|
||||||
}) async {
|
}) async {
|
||||||
// Mark all entries as possibly deleted.
|
// Mark all entries as possibly deleted.
|
||||||
for (DevFSContent content in _entries.values) {
|
for (DevFSContent content in _entries.values) {
|
||||||
@ -427,6 +431,18 @@ class DevFS {
|
|||||||
});
|
});
|
||||||
if (dirtyEntries.isNotEmpty) {
|
if (dirtyEntries.isNotEmpty) {
|
||||||
printTrace('Updating files');
|
printTrace('Updating files');
|
||||||
|
if (generator != null) {
|
||||||
|
final List<String> invalidatedFiles = <String>[];
|
||||||
|
dirtyEntries.forEach((Uri deviceUri, DevFSContent content) {
|
||||||
|
if (content is DevFSFileContent)
|
||||||
|
invalidatedFiles.add(content.file.uri.toString());
|
||||||
|
});
|
||||||
|
final String compiledBinary = await generator.recompile(mainPath, invalidatedFiles);
|
||||||
|
if (compiledBinary != null && compiledBinary.isNotEmpty)
|
||||||
|
dirtyEntries.putIfAbsent(Uri.parse(target + '.dill'),
|
||||||
|
() => new DevFSFileContent(fs.file(compiledBinary)));
|
||||||
|
}
|
||||||
|
|
||||||
if (_httpWriter != null) {
|
if (_httpWriter != null) {
|
||||||
try {
|
try {
|
||||||
await _httpWriter.write(dirtyEntries);
|
await _httpWriter.write(dirtyEntries);
|
||||||
|
@ -240,7 +240,6 @@ abstract class Device {
|
|||||||
String route,
|
String route,
|
||||||
DebuggingOptions debuggingOptions,
|
DebuggingOptions debuggingOptions,
|
||||||
Map<String, dynamic> platformArgs,
|
Map<String, dynamic> platformArgs,
|
||||||
String kernelPath,
|
|
||||||
bool prebuiltApplication: false,
|
bool prebuiltApplication: false,
|
||||||
bool applicationNeedsRebuild: false,
|
bool applicationNeedsRebuild: false,
|
||||||
bool usesTerminalUi: true,
|
bool usesTerminalUi: true,
|
||||||
|
@ -4,11 +4,13 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'artifacts.dart';
|
||||||
import 'asset.dart';
|
import 'asset.dart';
|
||||||
import 'base/build.dart';
|
import 'base/build.dart';
|
||||||
import 'base/common.dart';
|
import 'base/common.dart';
|
||||||
import 'base/file_system.dart';
|
import 'base/file_system.dart';
|
||||||
import 'build_info.dart';
|
import 'build_info.dart';
|
||||||
|
import 'compile.dart';
|
||||||
import 'dart/package_map.dart';
|
import 'dart/package_map.dart';
|
||||||
import 'devfs.dart';
|
import 'devfs.dart';
|
||||||
import 'globals.dart';
|
import 'globals.dart';
|
||||||
@ -25,6 +27,7 @@ const String defaultPrivateKeyPath = 'privatekey.der';
|
|||||||
const String _kKernelKey = 'kernel_blob.bin';
|
const String _kKernelKey = 'kernel_blob.bin';
|
||||||
const String _kSnapshotKey = 'snapshot_blob.bin';
|
const String _kSnapshotKey = 'snapshot_blob.bin';
|
||||||
const String _kDylibKey = 'libapp.so';
|
const String _kDylibKey = 'libapp.so';
|
||||||
|
const String _kPlatformKernelKey = 'platform.dill';
|
||||||
|
|
||||||
Future<Null> build({
|
Future<Null> build({
|
||||||
String mainPath: defaultMainPath,
|
String mainPath: defaultMainPath,
|
||||||
@ -35,7 +38,7 @@ Future<Null> build({
|
|||||||
String privateKeyPath: defaultPrivateKeyPath,
|
String privateKeyPath: defaultPrivateKeyPath,
|
||||||
String workingDirPath,
|
String workingDirPath,
|
||||||
String packagesPath,
|
String packagesPath,
|
||||||
String kernelPath,
|
bool previewDart2 : false,
|
||||||
bool precompiledSnapshot: false,
|
bool precompiledSnapshot: false,
|
||||||
bool reportLicensedPackages: false
|
bool reportLicensedPackages: false
|
||||||
}) async {
|
}) async {
|
||||||
@ -46,7 +49,7 @@ Future<Null> build({
|
|||||||
packagesPath ??= fs.path.absolute(PackageMap.globalPackagesPath);
|
packagesPath ??= fs.path.absolute(PackageMap.globalPackagesPath);
|
||||||
File snapshotFile;
|
File snapshotFile;
|
||||||
|
|
||||||
if (!precompiledSnapshot) {
|
if (!precompiledSnapshot && !previewDart2) {
|
||||||
ensureDirectoryExists(snapshotPath);
|
ensureDirectoryExists(snapshotPath);
|
||||||
|
|
||||||
// In a precompiled snapshot, the instruction buffer contains script
|
// In a precompiled snapshot, the instruction buffer contains script
|
||||||
@ -65,8 +68,13 @@ Future<Null> build({
|
|||||||
}
|
}
|
||||||
|
|
||||||
DevFSContent kernelContent;
|
DevFSContent kernelContent;
|
||||||
if (kernelPath != null)
|
if (!precompiledSnapshot && previewDart2) {
|
||||||
kernelContent = new DevFSFileContent(fs.file(kernelPath));
|
final String kernelBinaryFilename = await compile(
|
||||||
|
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
|
||||||
|
mainPath: fs.file(mainPath).absolute.path
|
||||||
|
);
|
||||||
|
kernelContent = new DevFSFileContent(fs.file(kernelBinaryFilename));
|
||||||
|
}
|
||||||
|
|
||||||
return assemble(
|
return assemble(
|
||||||
manifestPath: manifestPath,
|
manifestPath: manifestPath,
|
||||||
@ -118,8 +126,11 @@ Future<List<String>> assemble({
|
|||||||
.expand((DevFSContent content) => content.fileDependencies)
|
.expand((DevFSContent content) => content.fileDependencies)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (kernelContent != null)
|
if (kernelContent != null) {
|
||||||
|
final String platformKernelDill = artifacts.getArtifactPath(Artifact.platformKernelDill);
|
||||||
zipBuilder.entries[_kKernelKey] = kernelContent;
|
zipBuilder.entries[_kKernelKey] = kernelContent;
|
||||||
|
zipBuilder.entries[_kPlatformKernelKey] = new DevFSFileContent(fs.file(platformKernelDill));
|
||||||
|
}
|
||||||
if (snapshotFile != null)
|
if (snapshotFile != null)
|
||||||
zipBuilder.entries[_kSnapshotKey] = new DevFSFileContent(snapshotFile);
|
zipBuilder.entries[_kSnapshotKey] = new DevFSFileContent(snapshotFile);
|
||||||
if (dylibFile != null)
|
if (dylibFile != null)
|
||||||
|
@ -65,7 +65,7 @@ class FuchsiaDevice extends Device {
|
|||||||
DebuggingOptions debuggingOptions,
|
DebuggingOptions debuggingOptions,
|
||||||
Map<String, dynamic> platformArgs,
|
Map<String, dynamic> platformArgs,
|
||||||
bool prebuiltApplication: false,
|
bool prebuiltApplication: false,
|
||||||
String kernelPath,
|
bool previewDart2: false,
|
||||||
bool applicationNeedsRebuild: false,
|
bool applicationNeedsRebuild: false,
|
||||||
bool usesTerminalUi: false,
|
bool usesTerminalUi: false,
|
||||||
}) => new Future<Null>.error('unimplemented');
|
}) => new Future<Null>.error('unimplemented');
|
||||||
|
@ -170,7 +170,7 @@ class IOSDevice extends Device {
|
|||||||
DebuggingOptions debuggingOptions,
|
DebuggingOptions debuggingOptions,
|
||||||
Map<String, dynamic> platformArgs,
|
Map<String, dynamic> platformArgs,
|
||||||
bool prebuiltApplication: false,
|
bool prebuiltApplication: false,
|
||||||
String kernelPath,
|
bool previewDart2: false,
|
||||||
bool applicationNeedsRebuild: false,
|
bool applicationNeedsRebuild: false,
|
||||||
bool usesTerminalUi: true,
|
bool usesTerminalUi: true,
|
||||||
}) async {
|
}) async {
|
||||||
|
@ -311,7 +311,7 @@ class IOSSimulator extends Device {
|
|||||||
String route,
|
String route,
|
||||||
DebuggingOptions debuggingOptions,
|
DebuggingOptions debuggingOptions,
|
||||||
Map<String, dynamic> platformArgs,
|
Map<String, dynamic> platformArgs,
|
||||||
String kernelPath,
|
bool previewDart2: false,
|
||||||
bool prebuiltApplication: false,
|
bool prebuiltApplication: false,
|
||||||
bool applicationNeedsRebuild: false,
|
bool applicationNeedsRebuild: false,
|
||||||
bool usesTerminalUi: true,
|
bool usesTerminalUi: true,
|
||||||
|
@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
|
|||||||
|
|
||||||
import 'android/gradle.dart';
|
import 'android/gradle.dart';
|
||||||
import 'application_package.dart';
|
import 'application_package.dart';
|
||||||
|
import 'artifacts.dart';
|
||||||
import 'asset.dart';
|
import 'asset.dart';
|
||||||
import 'base/common.dart';
|
import 'base/common.dart';
|
||||||
import 'base/file_system.dart';
|
import 'base/file_system.dart';
|
||||||
@ -16,6 +17,7 @@ import 'base/logger.dart';
|
|||||||
import 'base/terminal.dart';
|
import 'base/terminal.dart';
|
||||||
import 'base/utils.dart';
|
import 'base/utils.dart';
|
||||||
import 'build_info.dart';
|
import 'build_info.dart';
|
||||||
|
import 'compile.dart';
|
||||||
import 'dart/dependencies.dart';
|
import 'dart/dependencies.dart';
|
||||||
import 'dart/package_map.dart';
|
import 'dart/package_map.dart';
|
||||||
import 'dependency_checker.dart';
|
import 'dependency_checker.dart';
|
||||||
@ -32,10 +34,15 @@ class FlutterDevice {
|
|||||||
List<VMService> vmServices;
|
List<VMService> vmServices;
|
||||||
DevFS devFS;
|
DevFS devFS;
|
||||||
ApplicationPackage package;
|
ApplicationPackage package;
|
||||||
|
ResidentCompiler generator;
|
||||||
|
|
||||||
StreamSubscription<String> _loggingSubscription;
|
StreamSubscription<String> _loggingSubscription;
|
||||||
|
|
||||||
FlutterDevice(this.device);
|
FlutterDevice(this.device, { bool previewDart2 : false }) {
|
||||||
|
if (previewDart2)
|
||||||
|
generator = new ResidentCompiler(
|
||||||
|
artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath));
|
||||||
|
}
|
||||||
|
|
||||||
String viewFilter;
|
String viewFilter;
|
||||||
|
|
||||||
@ -244,7 +251,6 @@ class FlutterDevice {
|
|||||||
platformArgs: platformArgs,
|
platformArgs: platformArgs,
|
||||||
route: route,
|
route: route,
|
||||||
prebuiltApplication: prebuiltMode,
|
prebuiltApplication: prebuiltMode,
|
||||||
kernelPath: hotRunner.kernelFilePath,
|
|
||||||
applicationNeedsRebuild: shouldBuild || hasDirtyDependencies,
|
applicationNeedsRebuild: shouldBuild || hasDirtyDependencies,
|
||||||
usesTerminalUi: hotRunner.usesTerminalUI,
|
usesTerminalUi: hotRunner.usesTerminalUI,
|
||||||
);
|
);
|
||||||
@ -319,6 +325,8 @@ class FlutterDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> updateDevFS({
|
Future<bool> updateDevFS({
|
||||||
|
String mainPath,
|
||||||
|
String target,
|
||||||
AssetBundle bundle,
|
AssetBundle bundle,
|
||||||
bool bundleDirty: false,
|
bool bundleDirty: false,
|
||||||
Set<String> fileFilter
|
Set<String> fileFilter
|
||||||
@ -330,9 +338,12 @@ class FlutterDevice {
|
|||||||
int bytes = 0;
|
int bytes = 0;
|
||||||
try {
|
try {
|
||||||
bytes = await devFS.update(
|
bytes = await devFS.update(
|
||||||
|
mainPath: mainPath,
|
||||||
|
target: target,
|
||||||
bundle: bundle,
|
bundle: bundle,
|
||||||
bundleDirty: bundleDirty,
|
bundleDirty: bundleDirty,
|
||||||
fileFilter: fileFilter
|
fileFilter: fileFilter,
|
||||||
|
generator: generator
|
||||||
);
|
);
|
||||||
} on DevFSException {
|
} on DevFSException {
|
||||||
devFSStatus.cancel();
|
devFSStatus.cancel();
|
||||||
@ -342,6 +353,13 @@ class FlutterDevice {
|
|||||||
printTrace('Synced ${getSizeAsMB(bytes)}.');
|
printTrace('Synced ${getSizeAsMB(bytes)}.');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateReloadStatus(bool wasReloadSuccessful) {
|
||||||
|
if (wasReloadSuccessful)
|
||||||
|
generator?.accept();
|
||||||
|
else
|
||||||
|
generator?.reject();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shared code between different resident application runners.
|
// Shared code between different resident application runners.
|
||||||
|
@ -20,6 +20,7 @@ class ColdRunner extends ResidentRunner {
|
|||||||
bool usesTerminalUI: true,
|
bool usesTerminalUI: true,
|
||||||
this.traceStartup: false,
|
this.traceStartup: false,
|
||||||
this.applicationBinary,
|
this.applicationBinary,
|
||||||
|
this.previewDart2 : false,
|
||||||
bool stayResident: true,
|
bool stayResident: true,
|
||||||
}) : super(devices,
|
}) : super(devices,
|
||||||
target: target,
|
target: target,
|
||||||
@ -29,6 +30,7 @@ class ColdRunner extends ResidentRunner {
|
|||||||
|
|
||||||
final bool traceStartup;
|
final bool traceStartup;
|
||||||
final String applicationBinary;
|
final String applicationBinary;
|
||||||
|
final bool previewDart2;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<int> run({
|
Future<int> run({
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:meta/meta.dart';
|
|
||||||
import 'package:json_rpc_2/error_code.dart' as rpc_error_code;
|
import 'package:json_rpc_2/error_code.dart' as rpc_error_code;
|
||||||
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
|
import 'package:json_rpc_2/json_rpc_2.dart' as rpc;
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import 'base/context.dart';
|
import 'base/context.dart';
|
||||||
import 'base/file_system.dart';
|
import 'base/file_system.dart';
|
||||||
@ -39,7 +39,7 @@ class HotRunner extends ResidentRunner {
|
|||||||
bool usesTerminalUI: true,
|
bool usesTerminalUI: true,
|
||||||
this.benchmarkMode: false,
|
this.benchmarkMode: false,
|
||||||
this.applicationBinary,
|
this.applicationBinary,
|
||||||
this.kernelFilePath,
|
this.previewDart2: false,
|
||||||
String projectRootPath,
|
String projectRootPath,
|
||||||
String packagesFilePath,
|
String packagesFilePath,
|
||||||
String projectAssets,
|
String projectAssets,
|
||||||
@ -60,7 +60,7 @@ class HotRunner extends ResidentRunner {
|
|||||||
final Map<String, int> benchmarkData = <String, int>{};
|
final Map<String, int> benchmarkData = <String, int>{};
|
||||||
// The initial launch is from a snapshot.
|
// The initial launch is from a snapshot.
|
||||||
bool _runningFromSnapshot = true;
|
bool _runningFromSnapshot = true;
|
||||||
String kernelFilePath;
|
bool previewDart2 = false;
|
||||||
|
|
||||||
bool _refreshDartDependencies() {
|
bool _refreshDartDependencies() {
|
||||||
if (!hotRunnerConfig.computeDartDependencies) {
|
if (!hotRunnerConfig.computeDartDependencies) {
|
||||||
@ -112,7 +112,6 @@ class HotRunner extends ResidentRunner {
|
|||||||
|
|
||||||
for (FlutterDevice device in flutterDevices)
|
for (FlutterDevice device in flutterDevices)
|
||||||
device.initLogReader();
|
device.initLogReader();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final List<Uri> baseUris = await _initDevFS();
|
final List<Uri> baseUris = await _initDevFS();
|
||||||
if (connectionInfoCompleter != null) {
|
if (connectionInfoCompleter != null) {
|
||||||
@ -251,6 +250,8 @@ class HotRunner extends ResidentRunner {
|
|||||||
|
|
||||||
for (FlutterDevice device in flutterDevices) {
|
for (FlutterDevice device in flutterDevices) {
|
||||||
final bool result = await device.updateDevFS(
|
final bool result = await device.updateDevFS(
|
||||||
|
mainPath: mainPath,
|
||||||
|
target: target,
|
||||||
bundle: assetBundle,
|
bundle: assetBundle,
|
||||||
bundleDirty: rebuildBundle,
|
bundleDirty: rebuildBundle,
|
||||||
fileFilter: _dartDependencies,
|
fileFilter: _dartDependencies,
|
||||||
@ -363,15 +364,20 @@ class HotRunner extends ResidentRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns [true] if the reload was successful.
|
/// Returns [true] if the reload was successful.
|
||||||
static bool validateReloadReport(Map<String, dynamic> reloadReport) {
|
/// Prints errors if [printErrors] is [true].
|
||||||
|
static bool validateReloadReport(Map<String, dynamic> reloadReport,
|
||||||
|
{ bool printErrors: true }) {
|
||||||
if (reloadReport['type'] != 'ReloadReport') {
|
if (reloadReport['type'] != 'ReloadReport') {
|
||||||
printError('Hot reload received invalid response: $reloadReport');
|
if (printErrors)
|
||||||
|
printError('Hot reload received invalid response: $reloadReport');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!reloadReport['success']) {
|
if (!reloadReport['success']) {
|
||||||
printError('Hot reload was rejected:');
|
if (printErrors) {
|
||||||
for (Map<String, dynamic> notice in reloadReport['details']['notices'])
|
printError('Hot reload was rejected:');
|
||||||
printError('${notice['message']}');
|
for (Map<String, dynamic> notice in reloadReport['details']['notices'])
|
||||||
|
printError('${notice['message']}');
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -464,23 +470,39 @@ class HotRunner extends ResidentRunner {
|
|||||||
return new OperationResult(1, 'Dart source error');
|
return new OperationResult(1, 'Dart source error');
|
||||||
String reloadMessage;
|
String reloadMessage;
|
||||||
try {
|
try {
|
||||||
final String entryPath = fs.path.relative(mainPath, from: projectRootPath);
|
final String entryPath = fs.path.relative(
|
||||||
|
previewDart2 ? mainPath + '.dill' : mainPath,
|
||||||
|
from: projectRootPath
|
||||||
|
);
|
||||||
if (benchmarkMode)
|
if (benchmarkMode)
|
||||||
vmReloadTimer.start();
|
vmReloadTimer.start();
|
||||||
final List<Future<Map<String, dynamic>>> reloadReportFutures = <Future<Map<String, dynamic>>>[];
|
final Completer<Map<String, dynamic>> retrieveFirstReloadReport = new Completer<Map<String, dynamic>>();
|
||||||
|
|
||||||
|
int countExpectedReports = 0;
|
||||||
for (FlutterDevice device in flutterDevices) {
|
for (FlutterDevice device in flutterDevices) {
|
||||||
|
// List has one report per Flutter view.
|
||||||
final List<Future<Map<String, dynamic>>> reports = device.reloadSources(
|
final List<Future<Map<String, dynamic>>> reports = device.reloadSources(
|
||||||
entryPath,
|
entryPath,
|
||||||
pause: pause
|
pause: pause
|
||||||
);
|
);
|
||||||
reloadReportFutures.addAll(reports);
|
countExpectedReports += reports.length;
|
||||||
|
Future.wait(reports).then((List<Map<String, dynamic>> list) {
|
||||||
|
// TODO(aam): Investigate why we are validating only first reload report,
|
||||||
|
// which seems to be current behavior
|
||||||
|
final Map<String, dynamic> firstReport = list.first;
|
||||||
|
// Don't print errors because they will be printed further down when
|
||||||
|
// `validateReloadReport` is called again.
|
||||||
|
device.updateReloadStatus(validateReloadReport(firstReport,
|
||||||
|
printErrors: false));
|
||||||
|
retrieveFirstReloadReport.complete(firstReport);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (reloadReportFutures.isEmpty) {
|
|
||||||
|
if (countExpectedReports == 0) {
|
||||||
printError('Unable to hot reload. No instance of Flutter is currently running.');
|
printError('Unable to hot reload. No instance of Flutter is currently running.');
|
||||||
return new OperationResult(1, 'No instances running');
|
return new OperationResult(1, 'No instances running');
|
||||||
}
|
}
|
||||||
final Map<String, dynamic> reloadReport = (await Future.wait(reloadReportFutures)).first;
|
final Map<String, dynamic> reloadReport = await retrieveFirstReloadReport.future;
|
||||||
|
|
||||||
if (!validateReloadReport(reloadReport)) {
|
if (!validateReloadReport(reloadReport)) {
|
||||||
// Reload failed.
|
// Reload failed.
|
||||||
flutterUsage.sendEvent('hot', 'reload-reject');
|
flutterUsage.sendEvent('hot', 'reload-reject');
|
||||||
|
@ -143,10 +143,13 @@ abstract class FlutterCommand extends Command<Null> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BuildInfo getBuildInfo() {
|
BuildInfo getBuildInfo() {
|
||||||
if (argParser.options.containsKey('flavor'))
|
return new BuildInfo(getBuildMode(),
|
||||||
return new BuildInfo(getBuildMode(), argResults['flavor']);
|
argParser.options.containsKey('flavor')
|
||||||
else
|
? argResults['flavor']
|
||||||
return new BuildInfo(getBuildMode(), null);
|
: null,
|
||||||
|
previewDart2: argParser.options.containsKey('preview-dart-2')
|
||||||
|
? argResults['preview-dart-2']
|
||||||
|
: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupApplicationPackages() {
|
void setupApplicationPackages() {
|
||||||
|
@ -270,8 +270,7 @@ class FlutterCommandRunner extends CommandRunner<Null> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (globalResults['machine']) {
|
if (globalResults['machine']) {
|
||||||
printError('The --machine flag is only valid with the --version flag.');
|
throwToolExit('The --machine flag is only valid with the --version flag.', exitCode: 2);
|
||||||
throw new ProcessExit(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await super.runCommand(globalResults);
|
await super.runCommand(globalResults);
|
||||||
@ -304,40 +303,44 @@ class FlutterCommandRunner extends CommandRunner<Null> {
|
|||||||
engineSourcePath ??= _tryEnginePath(fs.path.join(Cache.flutterRoot, '../engine/src'));
|
engineSourcePath ??= _tryEnginePath(fs.path.join(Cache.flutterRoot, '../engine/src'));
|
||||||
|
|
||||||
if (engineSourcePath == null) {
|
if (engineSourcePath == null) {
|
||||||
printError('Unable to detect local Flutter engine build directory.\n'
|
throwToolExit('Unable to detect local Flutter engine build directory.\n'
|
||||||
'Either specify a dependency_override for the $kFlutterEnginePackageName package in your pubspec.yaml and\n'
|
'Either specify a dependency_override for the $kFlutterEnginePackageName package in your pubspec.yaml and\n'
|
||||||
'ensure --package-root is set if necessary, or set the \$$kFlutterEngineEnvironmentVariableName environment variable, or\n'
|
'ensure --package-root is set if necessary, or set the \$$kFlutterEngineEnvironmentVariableName environment variable, or\n'
|
||||||
'use --local-engine-src-path to specify the path to the root of your flutter/engine repository.');
|
'use --local-engine-src-path to specify the path to the root of your flutter/engine repository.',
|
||||||
throw new ProcessExit(2);
|
exitCode: 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engineSourcePath != null && _tryEnginePath(engineSourcePath) == null) {
|
if (engineSourcePath != null && _tryEnginePath(engineSourcePath) == null) {
|
||||||
printError('Unable to detect a Flutter engine build directory in $engineSourcePath.\n'
|
throwToolExit('Unable to detect a Flutter engine build directory in $engineSourcePath.\n'
|
||||||
'Please ensure that $engineSourcePath is a Flutter engine \'src\' directory and that\n'
|
'Please ensure that $engineSourcePath is a Flutter engine \'src\' directory and that\n'
|
||||||
'you have compiled the engine in that directory, which should produce an \'out\' directory');
|
'you have compiled the engine in that directory, which should produce an \'out\' directory',
|
||||||
throw new ProcessExit(2);
|
exitCode: 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return engineSourcePath;
|
return engineSourcePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _findEngineBuildPath(ArgResults globalResults, String enginePath) {
|
EngineBuildPaths _findEngineBuildPath(ArgResults globalResults, String enginePath) {
|
||||||
String localEngine;
|
String localEngine;
|
||||||
if (globalResults['local-engine'] != null) {
|
if (globalResults['local-engine'] != null) {
|
||||||
localEngine = globalResults['local-engine'];
|
localEngine = globalResults['local-engine'];
|
||||||
} else {
|
} else {
|
||||||
printError('You must specify --local-engine if you are using a locally built engine.');
|
throwToolExit('You must specify --local-engine if you are using a locally built engine.', exitCode: 2);
|
||||||
throw new ProcessExit(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final String engineBuildPath = fs.path.normalize(fs.path.join(enginePath, 'out', localEngine));
|
final String engineBuildPath = fs.path.normalize(fs.path.join(enginePath, 'out', localEngine));
|
||||||
if (!fs.isDirectorySync(engineBuildPath)) {
|
if (!fs.isDirectorySync(engineBuildPath)) {
|
||||||
printError('No Flutter engine build found at $engineBuildPath.');
|
throwToolExit('No Flutter engine build found at $engineBuildPath.', exitCode: 2);
|
||||||
throw new ProcessExit(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return engineBuildPath;
|
final String hostLocalEngine = 'host_' + localEngine.substring(localEngine.indexOf('_') + 1);
|
||||||
|
final String engineHostBuildPath = fs.path.normalize(fs.path.join(enginePath, 'out', hostLocalEngine));
|
||||||
|
if (!fs.isDirectorySync(engineHostBuildPath)) {
|
||||||
|
throwToolExit('No Flutter host engine build found at $engineHostBuildPath.', exitCode: 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new EngineBuildPaths(targetEngine: engineBuildPath, hostEngine: engineHostBuildPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initFlutterRoot() {
|
static void initFlutterRoot() {
|
||||||
|
@ -31,7 +31,6 @@ void main() {
|
|||||||
artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, BuildMode.release),
|
artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, BuildMode.release),
|
||||||
fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'ios-release', 'Flutter.framework')
|
fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'ios-release', 'Flutter.framework')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
artifacts.getArtifactPath(Artifact.flutterTester),
|
artifacts.getArtifactPath(Artifact.flutterTester),
|
||||||
fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'linux-x64', 'flutter_tester')
|
fs.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'engine', 'linux-x64', 'flutter_tester')
|
||||||
@ -50,7 +49,6 @@ void main() {
|
|||||||
artifacts.getEngineType(TargetPlatform.ios, BuildMode.release),
|
artifacts.getEngineType(TargetPlatform.ios, BuildMode.release),
|
||||||
'ios-release'
|
'ios-release'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
artifacts.getEngineType(TargetPlatform.darwin_x64),
|
artifacts.getEngineType(TargetPlatform.darwin_x64),
|
||||||
'darwin-x64'
|
'darwin-x64'
|
||||||
@ -68,7 +66,10 @@ void main() {
|
|||||||
|
|
||||||
setUp(() {
|
setUp(() {
|
||||||
tempDir = fs.systemTempDirectory.createTempSync('flutter_temp');
|
tempDir = fs.systemTempDirectory.createTempSync('flutter_temp');
|
||||||
artifacts = new LocalEngineArtifacts(tempDir.path, fs.path.join(tempDir.path, 'out', 'android_debug_unopt'));
|
artifacts = new LocalEngineArtifacts(tempDir.path,
|
||||||
|
fs.path.join(tempDir.path, 'out', 'android_debug_unopt'),
|
||||||
|
fs.path.join(tempDir.path, 'out', 'host_debug_unopt'),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
tearDown(() {
|
tearDown(() {
|
||||||
@ -84,11 +85,14 @@ void main() {
|
|||||||
artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, BuildMode.release),
|
artifacts.getArtifactPath(Artifact.flutterFramework, TargetPlatform.ios, BuildMode.release),
|
||||||
fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'Flutter.framework')
|
fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'Flutter.framework')
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
artifacts.getArtifactPath(Artifact.flutterTester),
|
artifacts.getArtifactPath(Artifact.flutterTester),
|
||||||
fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'flutter_tester')
|
fs.path.join(tempDir.path, 'out', 'android_debug_unopt', 'flutter_tester')
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
artifacts.getArtifactPath(Artifact.engineDartSdkPath),
|
||||||
|
fs.path.join(tempDir.path, 'out', 'host_debug_unopt', 'dart-sdk')
|
||||||
|
);
|
||||||
}, overrides: <Type, Generator> {
|
}, overrides: <Type, Generator> {
|
||||||
Platform: () => new FakePlatform(operatingSystem: 'linux')
|
Platform: () => new FakePlatform(operatingSystem: 'linux')
|
||||||
});
|
});
|
||||||
@ -102,7 +106,6 @@ void main() {
|
|||||||
artifacts.getEngineType(TargetPlatform.ios, BuildMode.release),
|
artifacts.getEngineType(TargetPlatform.ios, BuildMode.release),
|
||||||
'android_debug_unopt'
|
'android_debug_unopt'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
artifacts.getEngineType(TargetPlatform.darwin_x64),
|
artifacts.getEngineType(TargetPlatform.darwin_x64),
|
||||||
'android_debug_unopt'
|
'android_debug_unopt'
|
||||||
|
153
packages/flutter_tools/test/compile_test.dart
Normal file
153
packages/flutter_tools/test/compile_test.dart
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// Copyright 2017 The Chromium 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 'package:flutter_tools/src/base/io.dart';
|
||||||
|
import 'package:flutter_tools/src/base/context.dart';
|
||||||
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
|
import 'package:flutter_tools/src/compile.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:process/process.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
import 'src/context.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('batch compile', () {
|
||||||
|
ProcessManager mockProcessManager;
|
||||||
|
MockProcess mockFrontendServer;
|
||||||
|
MockStdIn mockFrontendServerStdIn;
|
||||||
|
MockStream mockFrontendServerStdErr;
|
||||||
|
setUp(() {
|
||||||
|
mockProcessManager = new MockProcessManager();
|
||||||
|
mockFrontendServer = new MockProcess();
|
||||||
|
mockFrontendServerStdIn = new MockStdIn();
|
||||||
|
mockFrontendServerStdErr = new MockStream();
|
||||||
|
|
||||||
|
when(mockFrontendServer.stderr).thenReturn(mockFrontendServerStdErr);
|
||||||
|
final StreamController<String> stdErrStreamController = new StreamController<String>();
|
||||||
|
when(mockFrontendServerStdErr.transform<String>(any)).thenReturn(stdErrStreamController.stream);
|
||||||
|
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
|
||||||
|
when(mockProcessManager.start(any)).thenReturn(new Future<Process>.value(mockFrontendServer));
|
||||||
|
when(mockFrontendServer.exitCode).thenReturn(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('single dart successful compilation', () async {
|
||||||
|
final BufferLogger logger = context[Logger];
|
||||||
|
when(mockFrontendServer.stdout).thenReturn(new Stream<List<int>>.fromFuture(
|
||||||
|
new Future<List<int>>.value(UTF8.encode(
|
||||||
|
'result abc\nline1\nline2\nabc /path/to/main.dart.dill'
|
||||||
|
))
|
||||||
|
));
|
||||||
|
final String output = await compile(sdkRoot: '/path/to/sdkroot',
|
||||||
|
mainPath: '/path/to/main.dart'
|
||||||
|
);
|
||||||
|
verifyNever(mockFrontendServerStdIn.writeln(any));
|
||||||
|
expect(logger.traceText, equals('compile debug message: line1\ncompile debug message: line2\n'));
|
||||||
|
expect(output, equals('/path/to/main.dart.dill'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
ProcessManager: () => mockProcessManager,
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('single dart failed compilation', () async {
|
||||||
|
final BufferLogger logger = context[Logger];
|
||||||
|
|
||||||
|
when(mockFrontendServer.stdout).thenReturn(new Stream<List<int>>.fromFuture(
|
||||||
|
new Future<List<int>>.value(UTF8.encode(
|
||||||
|
'result abc\nline1\nline2\nabc'
|
||||||
|
))
|
||||||
|
));
|
||||||
|
|
||||||
|
final String output = await compile(sdkRoot: '/path/to/sdkroot',
|
||||||
|
mainPath: '/path/to/main.dart'
|
||||||
|
);
|
||||||
|
verifyNever(mockFrontendServerStdIn.writeln(any));
|
||||||
|
expect(logger.traceText, equals('compile debug message: line1\ncompile debug message: line2\n'));
|
||||||
|
expect(output, equals(null));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
ProcessManager: () => mockProcessManager,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('incremental compile', () {
|
||||||
|
ProcessManager mockProcessManager;
|
||||||
|
ResidentCompiler generator;
|
||||||
|
MockProcess mockFrontendServer;
|
||||||
|
MockStdIn mockFrontendServerStdIn;
|
||||||
|
MockStream mockFrontendServerStdErr;
|
||||||
|
StreamController<String> stdErrStreamController;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
generator = new ResidentCompiler('sdkroot');
|
||||||
|
mockProcessManager = new MockProcessManager();
|
||||||
|
mockFrontendServer = new MockProcess();
|
||||||
|
mockFrontendServerStdIn = new MockStdIn();
|
||||||
|
mockFrontendServerStdErr = new MockStream();
|
||||||
|
|
||||||
|
when(mockFrontendServer.stdin).thenReturn(mockFrontendServerStdIn);
|
||||||
|
when(mockFrontendServer.stderr).thenReturn(mockFrontendServerStdErr);
|
||||||
|
stdErrStreamController = new StreamController<String>();
|
||||||
|
when(mockFrontendServerStdErr.transform<String>(any)).thenReturn(stdErrStreamController.stream);
|
||||||
|
|
||||||
|
when(mockProcessManager.start(any)).thenReturn(
|
||||||
|
new Future<Process>.value(mockFrontendServer)
|
||||||
|
);
|
||||||
|
when(mockFrontendServer.exitCode).thenReturn(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('single dart compile', () async {
|
||||||
|
final BufferLogger logger = context[Logger];
|
||||||
|
|
||||||
|
when(mockFrontendServer.stdout).thenReturn(new Stream<List<int>>.fromFuture(
|
||||||
|
new Future<List<int>>.value(UTF8.encode(
|
||||||
|
'result abc\nline1\nline2\nabc /path/to/main.dart.dill'
|
||||||
|
))
|
||||||
|
));
|
||||||
|
|
||||||
|
final String output = await generator.recompile(
|
||||||
|
'/path/to/main.dart', null /* invalidatedFiles */
|
||||||
|
);
|
||||||
|
verify(mockFrontendServerStdIn.writeln('compile /path/to/main.dart'));
|
||||||
|
verifyNoMoreInteractions(mockFrontendServerStdIn);
|
||||||
|
expect(logger.traceText, equals('compile debug message: line1\ncompile debug message: line2\n'));
|
||||||
|
expect(output, equals('/path/to/main.dart.dill'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
ProcessManager: () => mockProcessManager,
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('compile and recompile', () async {
|
||||||
|
final BufferLogger logger = context[Logger];
|
||||||
|
|
||||||
|
when(mockFrontendServer.stdout).thenReturn(new Stream<List<int>>.fromFuture(
|
||||||
|
new Future<List<int>>.value(UTF8.encode(
|
||||||
|
'result abc\nline1\nline2\nabc /path/to/main.dart.dill'
|
||||||
|
))
|
||||||
|
));
|
||||||
|
|
||||||
|
await generator.recompile('/path/to/main.dart', null /* invalidatedFiles */);
|
||||||
|
verify(mockFrontendServerStdIn.writeln('compile /path/to/main.dart'));
|
||||||
|
|
||||||
|
final String output = await generator.recompile(
|
||||||
|
null /* mainPath */,
|
||||||
|
<String>['/path/to/main.dart']
|
||||||
|
);
|
||||||
|
final String recompileCommand = verify(mockFrontendServerStdIn.writeln(captureThat(startsWith('recompile ')))).captured[0];
|
||||||
|
final String token = recompileCommand.split(' ')[1];
|
||||||
|
verify(mockFrontendServerStdIn.writeln('/path/to/main.dart'));
|
||||||
|
verify(mockFrontendServerStdIn.writeln(token));
|
||||||
|
verifyNoMoreInteractions(mockFrontendServerStdIn);
|
||||||
|
expect(logger.traceText, equals('compile debug message: line1\ncompile debug message: line2\n'));
|
||||||
|
expect(output, equals('/path/to/main.dart.dill'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
ProcessManager: () => mockProcessManager,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockProcessManager extends Mock implements ProcessManager {}
|
||||||
|
class MockProcess extends Mock implements Process {}
|
||||||
|
class MockStream extends Mock implements Stream<List<int>> {}
|
||||||
|
class MockStdIn extends Mock implements IOSink {}
|
Loading…
x
Reference in New Issue
Block a user