Commit c5750cd7 authored by Alexander Aprelev's avatar Alexander Aprelev Committed by GitHub

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.
parent 8c36ccf5
...@@ -65,6 +65,7 @@ if [ ! -d "$FLUTTER_ROOT/.git" ]; then ...@@ -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"
......
// 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() { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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 { ...@@ -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 { ...@@ -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,16 +336,18 @@ abstract class BaseFlutterTask extends DefaultTask { ...@@ -333,16 +336,18 @@ 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 {
if (!previewDart2) {
args "--snapshot", "${intermediateDir}/snapshot_blob.bin" args "--snapshot", "${intermediateDir}/snapshot_blob.bin"
args "--depfile", "${intermediateDir}/snapshot_blob.bin.d" 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 { ...@@ -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 { ...@@ -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}) { ...@@ -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 ...@@ -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 { ...@@ -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 ...@@ -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 @@ ...@@ -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 { ...@@ -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) { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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'; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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'; ...@@ -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 { ...@@ -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 { ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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 { ...@@ -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 { ...@@ -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({ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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.');
...@@ -300,7 +299,7 @@ class RunCommand extends RunCommandBase { ...@@ -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 { ...@@ -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 { ...@@ -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,
); );
} }
......
// 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'; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 @@ ...@@ -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'; ...@@ -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({ ...@@ -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({ ...@@ -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({ ...@@ -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({ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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'; ...@@ -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'; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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') {
if (printErrors)
printError('Hot reload received invalid response: $reloadReport'); printError('Hot reload received invalid response: $reloadReport');
return false; return false;
} }
if (!reloadReport['success']) { if (!reloadReport['success']) {
if (printErrors) {
printError('Hot reload was rejected:'); printError('Hot reload was rejected:');
for (Map<String, dynamic> notice in reloadReport['details']['notices']) for (Map<String, dynamic> notice in reloadReport['details']['notices'])
printError('${notice['message']}'); printError('${notice['message']}');
}
return false; return false;
} }
return true; return true;
...@@ -464,23 +470,39 @@ class HotRunner extends ResidentRunner { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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'
......
// 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 {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment