Unverified Commit a2d349c4 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

select ResidentCompiler during FlutterDevice initialization (#28603)

parent df465c77
...@@ -32,6 +32,9 @@ ...@@ -32,6 +32,9 @@
/packages/flutter/coverage/ /packages/flutter/coverage/
version version
# packages file containing multi-root paths
.packages.generated
# Flutter/Dart/Pub related # Flutter/Dart/Pub related
**/doc/api/ **/doc/api/
.dart_tool/ .dart_tool/
......
...@@ -17,7 +17,7 @@ class ExampleWidget extends StatefulWidget { ...@@ -17,7 +17,7 @@ class ExampleWidget extends StatefulWidget {
} }
class _ExampleWidgetState extends State<ExampleWidget> { class _ExampleWidgetState extends State<ExampleWidget> {
String _message = ''; bool _pressed = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -30,14 +30,21 @@ class _ExampleWidgetState extends State<ExampleWidget> { ...@@ -30,14 +30,21 @@ class _ExampleWidgetState extends State<ExampleWidget> {
child: const Text('Press Button, Get Coffee'), child: const Text('Press Button, Get Coffee'),
onPressed: () async { onPressed: () async {
setState(() { setState(() {
_message = generated.message; _pressed = true;
}); });
}, },
), ),
Text(_message), _pressed ? GeneratedWidget() : const SizedBox(),
], ],
), ),
), ),
); );
} }
} }
class GeneratedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(generated.message);
}
}
final String message = 'Thanks for using PourOverSupremeFiesta by Coffee by Flutter Inc.'; String get message => 'Thanks for using PourOverSupremeFiesta by Coffee by Flutter Inc.';
import 'package:codegen/main.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('can reference generated code', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(home: GeneratedWidget()));
expect(find.text('Thanks for using PourOverSupremeFiesta by Coffee by Flutter Inc.'), findsOneWidget);
});
}
...@@ -24,4 +24,4 @@ void main() { ...@@ -24,4 +24,4 @@ void main() {
final String fullMessage = await driver.getText(find.text(message)); final String fullMessage = await driver.getText(find.text(message));
expect(fullMessage, message); expect(fullMessage, message);
}); });
} }
\ No newline at end of file
...@@ -89,25 +89,18 @@ class FlutterKernelBuilder implements Builder { ...@@ -89,25 +89,18 @@ class FlutterKernelBuilder implements Builder {
return; return;
} }
final AssetId outputId = buildStep.inputId.changeExtension(_kFlutterDillOutputExtension); final AssetId outputId = buildStep.inputId.changeExtension(_kFlutterDillOutputExtension);
final AssetId packagesOutputId = buildStep.inputId.changeExtension(_kPackagesExtension);
// Create a scratch space file that can be read/written by the frontend server. // Create a scratch space file that can be read/written by the frontend server.
// It is okay to hard-code these file names because we will copy them back // It is okay to hard-code these file names because we will copy them back
// from the temp directory at the end of the build step. // from the temp directory at the end of the build step.
final Directory tempDirecory = await Directory.systemTemp.createTemp('_flutter_build'); final Directory tempDirecory = await Directory.systemTemp.createTemp('_flutter_build');
final File packagesFile = File(path.join(tempDirecory.path, _kPackagesExtension)); final Directory projectDir = File(packagesPath).parent;
final String packagesFilePath = path.join(projectDir.path, '.packages.generated');
final File outputFile = File(path.join(tempDirecory.path, 'main.app.dill')); final File outputFile = File(path.join(tempDirecory.path, 'main.app.dill'));
await outputFile.create(); await outputFile.create();
await packagesFile.create();
final Directory projectDir = File(packagesPath).parent;
final String packageName = buildStep.inputId.package; final String packageName = buildStep.inputId.package;
final String oldPackagesContents = await File(packagesPath).readAsString();
// Note: currently we only replace the root package with a multiroot
// scheme. To support codegen on arbitrary packages we will need to do
// this for each dependency.
final String newPackagesContents = oldPackagesContents.replaceFirst('$packageName:lib/', '$packageName:$_kMultirootScheme:/');
await packagesFile.writeAsString(newPackagesContents);
String absoluteMainPath; String absoluteMainPath;
if (path.isAbsolute(mainPath)) { if (path.isAbsolute(mainPath)) {
absoluteMainPath = mainPath; absoluteMainPath = mainPath;
...@@ -143,7 +136,7 @@ class FlutterKernelBuilder implements Builder { ...@@ -143,7 +136,7 @@ class FlutterKernelBuilder implements Builder {
final String normalRoot = path.join(projectDir.absolute.path, 'lib${Platform.pathSeparator}'); final String normalRoot = path.join(projectDir.absolute.path, 'lib${Platform.pathSeparator}');
arguments.addAll(<String>[ arguments.addAll(<String>[
'--packages', '--packages',
Uri.file(packagesFile.path).toString(), packagesFilePath,
'--output-dill', '--output-dill',
outputFile.path, outputFile.path,
'--filesystem-root', '--filesystem-root',
...@@ -158,7 +151,7 @@ class FlutterKernelBuilder implements Builder { ...@@ -158,7 +151,7 @@ class FlutterKernelBuilder implements Builder {
} }
final Uri mainUri = _PackageUriMapper.findUri( final Uri mainUri = _PackageUriMapper.findUri(
absoluteMainPath, absoluteMainPath,
packagesFile.path, packagesFilePath,
_kMultirootScheme, _kMultirootScheme,
<String>[normalRoot, generatedRoot], <String>[normalRoot, generatedRoot],
); );
...@@ -178,7 +171,6 @@ class FlutterKernelBuilder implements Builder { ...@@ -178,7 +171,6 @@ class FlutterKernelBuilder implements Builder {
await server.exitCode; await server.exitCode;
await _stdoutHandler.compilerOutput.future; await _stdoutHandler.compilerOutput.future;
await buildStep.writeAsBytes(outputId, await outputFile.readAsBytes()); await buildStep.writeAsBytes(outputId, await outputFile.readAsBytes());
await buildStep.writeAsBytes(packagesOutputId, await packagesFile.readAsBytes());
} catch (err, stackTrace) { } catch (err, stackTrace) {
log.shout('frontend server failed to start: $err, $stackTrace'); log.shout('frontend server failed to start: $err, $stackTrace');
} }
......
...@@ -22,12 +22,18 @@ import '../base/logger.dart'; ...@@ -22,12 +22,18 @@ import '../base/logger.dart';
import '../base/process_manager.dart'; import '../base/process_manager.dart';
import '../codegen.dart'; import '../codegen.dart';
import '../convert.dart'; import '../convert.dart';
import '../dart/package_map.dart';
import '../dart/pub.dart'; import '../dart/pub.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart'; import '../project.dart';
import '../resident_runner.dart'; import '../resident_runner.dart';
import 'build_script_generator.dart'; import 'build_script_generator.dart';
// Arbitrarily choosen multi-root file scheme. This is used to configure the
// frontend_server to resolve a package uri to multiple filesystem directories.
// In this case, the source directory and a generated directory.
const String _kMultirootScheme = 'org-dartlang-app';
/// A wrapper for a build_runner process which delegates to a generated /// A wrapper for a build_runner process which delegates to a generated
/// build script. /// build script.
/// ///
...@@ -37,7 +43,7 @@ class BuildRunner extends CodeGenerator { ...@@ -37,7 +43,7 @@ class BuildRunner extends CodeGenerator {
const BuildRunner(); const BuildRunner();
@override @override
Future<CodeGenerationResult> build({ Future<CodeGenerationResult> build(FlutterProject flutterProject, {
@required String mainPath, @required String mainPath,
@required bool aot, @required bool aot,
@required bool linkPlatformKernelIn, @required bool linkPlatformKernelIn,
...@@ -46,8 +52,7 @@ class BuildRunner extends CodeGenerator { ...@@ -46,8 +52,7 @@ class BuildRunner extends CodeGenerator {
List<String> extraFrontEndOptions = const <String>[], List<String> extraFrontEndOptions = const <String>[],
bool disableKernelGeneration = false, bool disableKernelGeneration = false,
}) async { }) async {
await generateBuildScript(); await generateBuildScript(flutterProject);
final FlutterProject flutterProject = await FlutterProject.current();
final String frontendServerPath = artifacts.getArtifactPath( final String frontendServerPath = artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk Artifact.frontendServerSnapshotForEngineDartSdk
); );
...@@ -99,7 +104,7 @@ class BuildRunner extends CodeGenerator { ...@@ -99,7 +104,7 @@ class BuildRunner extends CodeGenerator {
status.stop(); status.stop();
} }
if (disableKernelGeneration) { if (disableKernelGeneration) {
return const CodeGenerationResult(null, null); return const CodeGenerationResult(null);
} }
/// We don't check for this above because it might be generated for the /// We don't check for this above because it might be generated for the
/// first time by invoking the build. /// first time by invoking the build.
...@@ -114,21 +119,17 @@ class BuildRunner extends CodeGenerator { ...@@ -114,21 +119,17 @@ class BuildRunner extends CodeGenerator {
throw Exception('build_runner cannot find generated directory'); throw Exception('build_runner cannot find generated directory');
} }
final String relativeMain = fs.path.relative(mainPath, from: flutterProject.directory.path); final String relativeMain = fs.path.relative(mainPath, from: flutterProject.directory.path);
final File packagesFile = fs.file(
fs.path.join(generatedDirectory.path, fs.path.setExtension(relativeMain, '.packages'))
);
final File dillFile = fs.file( final File dillFile = fs.file(
fs.path.join(generatedDirectory.path, fs.path.setExtension(relativeMain, '.app.dill')) fs.path.join(generatedDirectory.path, fs.path.setExtension(relativeMain, '.app.dill'))
); );
if (!packagesFile.existsSync() || !dillFile.existsSync()) { if (!dillFile.existsSync()) {
throw Exception('build_runner did not produce output at expected location: ${dillFile.path} missing'); throw Exception('build_runner did not produce output at expected location: ${dillFile.path} missing');
} }
return CodeGenerationResult(packagesFile, dillFile); return CodeGenerationResult(dillFile);
} }
@override @override
Future<void> generateBuildScript() async { Future<void> generateBuildScript(FlutterProject flutterProject) async {
final FlutterProject flutterProject = await FlutterProject.current();
final Directory entrypointDirectory = fs.directory(fs.path.join(flutterProject.dartTool.path, 'build', 'entrypoint')); final Directory entrypointDirectory = fs.directory(fs.path.join(flutterProject.dartTool.path, 'build', 'entrypoint'));
final Directory generatedDirectory = fs.directory(fs.path.join(flutterProject.dartTool.path, 'flutter_tool')); final Directory generatedDirectory = fs.directory(fs.path.join(flutterProject.dartTool.path, 'flutter_tool'));
final File buildScript = entrypointDirectory.childFile('build.dart'); final File buildScript = entrypointDirectory.childFile('build.dart');
...@@ -180,7 +181,6 @@ class BuildRunner extends CodeGenerator { ...@@ -180,7 +181,6 @@ class BuildRunner extends CodeGenerator {
stringBuffer.writeln(' flutter_build:'); stringBuffer.writeln(' flutter_build:');
stringBuffer.writeln(' sdk: flutter'); stringBuffer.writeln(' sdk: flutter');
syntheticPubspec.writeAsStringSync(stringBuffer.toString()); syntheticPubspec.writeAsStringSync(stringBuffer.toString());
await pubGet( await pubGet(
context: PubContext.pubGet, context: PubContext.pubGet,
directory: generatedDirectory.path, directory: generatedDirectory.path,
...@@ -210,7 +210,7 @@ class BuildRunner extends CodeGenerator { ...@@ -210,7 +210,7 @@ class BuildRunner extends CodeGenerator {
} }
@override @override
Future<CodegenDaemon> daemon({ Future<CodegenDaemon> daemon(FlutterProject flutterProject, {
String mainPath, String mainPath,
bool linkPlatformKernelIn = false, bool linkPlatformKernelIn = false,
bool targetProductVm = false, bool targetProductVm = false,
...@@ -218,8 +218,8 @@ class BuildRunner extends CodeGenerator { ...@@ -218,8 +218,8 @@ class BuildRunner extends CodeGenerator {
List<String> extraFrontEndOptions = const <String> [], List<String> extraFrontEndOptions = const <String> [],
}) async { }) async {
mainPath ??= findMainDartFile(); mainPath ??= findMainDartFile();
await generateBuildScript(); await generateBuildScript(flutterProject);
final FlutterProject flutterProject = await FlutterProject.current(); _generatePackages(flutterProject);
final String frontendServerPath = artifacts.getArtifactPath( final String frontendServerPath = artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk Artifact.frontendServerSnapshotForEngineDartSdk
); );
...@@ -265,19 +265,28 @@ class BuildRunner extends CodeGenerator { ...@@ -265,19 +265,28 @@ class BuildRunner extends CodeGenerator {
builder.target = flutterProject.manifest.appName; builder.target = flutterProject.manifest.appName;
})); }));
final String relativeMain = fs.path.relative(mainPath, from: flutterProject.directory.path); final String relativeMain = fs.path.relative(mainPath, from: flutterProject.directory.path);
final File generatedPackagesFile = fs.file(fs.path.join(flutterProject.generated.path, fs.path.setExtension(relativeMain, '.packages')));
final File generatedDillFile = fs.file(fs.path.join(flutterProject.generated.path, fs.path.setExtension(relativeMain, '.app.dill'))); final File generatedDillFile = fs.file(fs.path.join(flutterProject.generated.path, fs.path.setExtension(relativeMain, '.app.dill')));
return _BuildRunnerCodegenDaemon(buildDaemonClient, generatedPackagesFile, generatedDillFile); return _BuildRunnerCodegenDaemon(buildDaemonClient, generatedDillFile);
}
// Create generated packages file which adds a multi-root scheme to the user's
// project directory. Currently we only replace the root package with a multiroot
// scheme. To support codegen on arbitrary packages we would need to do
// this for each dependency.
void _generatePackages(FlutterProject flutterProject) {
final String oldPackagesContents = fs.file(PackageMap.globalPackagesPath).readAsStringSync();
final String appName = flutterProject.manifest.appName;
final String newPackagesContents = oldPackagesContents.replaceFirst('$appName:lib/', '$appName:$_kMultirootScheme:/');
final String generatedPackagesPath = fs.path.setExtension(PackageMap.globalPackagesPath, '.generated');
fs.file(generatedPackagesPath).writeAsStringSync(newPackagesContents);
} }
} }
class _BuildRunnerCodegenDaemon implements CodegenDaemon { class _BuildRunnerCodegenDaemon implements CodegenDaemon {
_BuildRunnerCodegenDaemon(this.buildDaemonClient, this.packagesFile, this.dillFile); _BuildRunnerCodegenDaemon(this.buildDaemonClient, this.dillFile);
final BuildDaemonClient buildDaemonClient; final BuildDaemonClient buildDaemonClient;
@override @override
final File packagesFile;
@override
final File dillFile; final File dillFile;
@override @override
CodegenStatus get lastStatus => _lastStatus; CodegenStatus get lastStatus => _lastStatus;
......
...@@ -9,6 +9,7 @@ import 'base/context.dart'; ...@@ -9,6 +9,7 @@ import 'base/context.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/platform.dart'; import 'base/platform.dart';
import 'compile.dart'; import 'compile.dart';
import 'dart/package_map.dart';
import 'globals.dart'; import 'globals.dart';
import 'project.dart'; import 'project.dart';
...@@ -44,8 +45,9 @@ abstract class CodeGenerator { ...@@ -44,8 +45,9 @@ abstract class CodeGenerator {
const CodeGenerator(); const CodeGenerator();
/// Run a partial build include code generators but not kernel. /// Run a partial build include code generators but not kernel.
Future<void> generate({@required String mainPath}) async { Future<void> generate(FlutterProject flutterProject, {@required String mainPath}) async {
await build( await build(
flutterProject,
mainPath: mainPath, mainPath: mainPath,
aot: false, aot: false,
linkPlatformKernelIn: false, linkPlatformKernelIn: false,
...@@ -59,7 +61,7 @@ abstract class CodeGenerator { ...@@ -59,7 +61,7 @@ abstract class CodeGenerator {
/// ///
/// The defines of the build command are the arguments required in the /// The defines of the build command are the arguments required in the
/// flutter_build kernel builder. /// flutter_build kernel builder.
Future<CodeGenerationResult> build({ Future<CodeGenerationResult> build(FlutterProject flutterProject, {
@required String mainPath, @required String mainPath,
@required bool aot, @required bool aot,
@required bool linkPlatformKernelIn, @required bool linkPlatformKernelIn,
...@@ -73,7 +75,7 @@ abstract class CodeGenerator { ...@@ -73,7 +75,7 @@ abstract class CodeGenerator {
/// ///
/// The defines of the daemon command are the arguments required in the /// The defines of the daemon command are the arguments required in the
/// flutter_build kernel builder. /// flutter_build kernel builder.
Future<CodegenDaemon> daemon({ Future<CodegenDaemon> daemon(FlutterProject flutterProject, {
@required String mainPath, @required String mainPath,
bool linkPlatformKernelIn = false, bool linkPlatformKernelIn = false,
bool targetProductVm = false, bool targetProductVm = false,
...@@ -83,14 +85,14 @@ abstract class CodeGenerator { ...@@ -83,14 +85,14 @@ abstract class CodeGenerator {
// Generates a synthetic package under .dart_tool/flutter_tool which is in turn // Generates a synthetic package under .dart_tool/flutter_tool which is in turn
// used to generate a build script. // used to generate a build script.
Future<void> generateBuildScript(); Future<void> generateBuildScript(FlutterProject flutterProject);
} }
class UnsupportedCodeGenerator extends CodeGenerator { class UnsupportedCodeGenerator extends CodeGenerator {
const UnsupportedCodeGenerator(); const UnsupportedCodeGenerator();
@override @override
Future<CodeGenerationResult> build({ Future<CodeGenerationResult> build(FlutterProject flutterProject, {
String mainPath, String mainPath,
bool aot, bool aot,
bool linkPlatformKernelIn, bool linkPlatformKernelIn,
...@@ -103,12 +105,12 @@ class UnsupportedCodeGenerator extends CodeGenerator { ...@@ -103,12 +105,12 @@ class UnsupportedCodeGenerator extends CodeGenerator {
} }
@override @override
Future<void> generateBuildScript() { Future<void> generateBuildScript(FlutterProject flutterProject) {
throw UnsupportedError('build_runner is not currently supported.'); throw UnsupportedError('build_runner is not currently supported.');
} }
@override @override
Future<CodegenDaemon> daemon({ Future<CodegenDaemon> daemon(FlutterProject flutterProject, {
String mainPath, String mainPath,
bool linkPlatformKernelIn = false, bool linkPlatformKernelIn = false,
bool targetProductVm = false, bool targetProductVm = false,
...@@ -128,8 +130,6 @@ abstract class CodegenDaemon { ...@@ -128,8 +130,6 @@ abstract class CodegenDaemon {
/// Starts a new build. /// Starts a new build.
void startBuild(); void startBuild();
File get packagesFile;
File get dillFile; File get dillFile;
} }
...@@ -137,9 +137,8 @@ abstract class CodegenDaemon { ...@@ -137,9 +137,8 @@ abstract class CodegenDaemon {
/// ///
/// If no dill or packages file is generated, they will be null. /// If no dill or packages file is generated, they will be null.
class CodeGenerationResult { class CodeGenerationResult {
const CodeGenerationResult(this.packagesFile, this.dillFile); const CodeGenerationResult(this.dillFile);
final File packagesFile;
final File dillFile; final File dillFile;
} }
...@@ -176,8 +175,10 @@ class CodeGeneratingKernelCompiler implements KernelCompiler { ...@@ -176,8 +175,10 @@ class CodeGeneratingKernelCompiler implements KernelCompiler {
'sdkRoot, packagesPath are not supported when using the experimental ' 'sdkRoot, packagesPath are not supported when using the experimental '
'build* pipeline'); 'build* pipeline');
} }
final FlutterProject flutterProject = await FlutterProject.current();
try { try {
final CodeGenerationResult buildResult = await codeGenerator.build( final CodeGenerationResult buildResult = await codeGenerator.build(
flutterProject,
aot: aot, aot: aot,
linkPlatformKernelIn: linkPlatformKernelIn, linkPlatformKernelIn: linkPlatformKernelIn,
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
...@@ -206,13 +207,16 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler { ...@@ -206,13 +207,16 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
/// Creates a new [ResidentCompiler] and configures a [BuildDaemonClient] to /// Creates a new [ResidentCompiler] and configures a [BuildDaemonClient] to
/// run builds. /// run builds.
static Future<CodeGeneratingResidentCompiler> create({ static Future<CodeGeneratingResidentCompiler> create({
@required String mainPath, @required FlutterProject flutterProject,
String mainPath,
bool trackWidgetCreation = false, bool trackWidgetCreation = false,
CompilerMessageConsumer compilerMessageConsumer = printError, CompilerMessageConsumer compilerMessageConsumer = printError,
bool unsafePackageSerialization = false, bool unsafePackageSerialization = false,
String outputPath,
String initializeFromDill,
}) async { }) async {
final FlutterProject flutterProject = await FlutterProject.current();
final CodegenDaemon codegenDaemon = await codeGenerator.daemon( final CodegenDaemon codegenDaemon = await codeGenerator.daemon(
flutterProject,
extraFrontEndOptions: <String>[], extraFrontEndOptions: <String>[],
linkPlatformKernelIn: false, linkPlatformKernelIn: false,
mainPath: mainPath, mainPath: mainPath,
...@@ -221,22 +225,23 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler { ...@@ -221,22 +225,23 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
); );
codegenDaemon.startBuild(); codegenDaemon.startBuild();
final CodegenStatus status = await codegenDaemon.buildResults.firstWhere((CodegenStatus status) { final CodegenStatus status = await codegenDaemon.buildResults.firstWhere((CodegenStatus status) {
return status ==CodegenStatus.Succeeded || status == CodegenStatus.Failed; return status == CodegenStatus.Succeeded || status == CodegenStatus.Failed;
}); });
if (status == CodegenStatus.Failed) { if (status == CodegenStatus.Failed) {
printError('Codegeneration failed, halting build.'); printError('Code generation failed, build may have compile errors');
} }
final ResidentCompiler residentCompiler = ResidentCompiler( final ResidentCompiler residentCompiler = ResidentCompiler(
artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath), artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
packagesPath: codegenDaemon.packagesFile.path, packagesPath: PackageMap.globalGeneratedPackagesPath,
fileSystemRoots: <String>[ fileSystemRoots: <String>[
fs.path.join(flutterProject.generated.absolute.path, 'lib${platform.pathSeparator}'), fs.path.join(flutterProject.generated.path, 'lib${platform.pathSeparator}'),
fs.path.join(flutterProject.directory.path, 'lib${platform.pathSeparator}'), fs.path.join(flutterProject.directory.path, 'lib${platform.pathSeparator}'),
], ],
fileSystemScheme: _kMultiRootScheme, fileSystemScheme: _kMultiRootScheme,
targetModel: TargetModel.flutter, targetModel: TargetModel.flutter,
unsafePackageSerialization: unsafePackageSerialization, unsafePackageSerialization: unsafePackageSerialization,
initializeFromDill: initializeFromDill,
); );
return CodeGeneratingResidentCompiler._(residentCompiler, codegenDaemon); return CodeGeneratingResidentCompiler._(residentCompiler, codegenDaemon);
} }
...@@ -274,7 +279,7 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler { ...@@ -274,7 +279,7 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
mainPath, mainPath,
invalidatedFiles, invalidatedFiles,
outputPath: outputPath, outputPath: outputPath,
packagesFilePath: _codegenDaemon.packagesFile.path, packagesFilePath: PackageMap.globalGeneratedPackagesPath,
); );
} }
......
...@@ -205,13 +205,14 @@ class AttachCommand extends FlutterCommand { ...@@ -205,13 +205,14 @@ class AttachCommand extends FlutterCommand {
} }
try { try {
final bool useHot = getBuildInfo().isDebug; final bool useHot = getBuildInfo().isDebug;
final FlutterDevice flutterDevice = FlutterDevice( final FlutterDevice flutterDevice = await FlutterDevice.create(
device, device,
trackWidgetCreation: false, trackWidgetCreation: false,
dillOutputPath: argResults['output-dill'], dillOutputPath: argResults['output-dill'],
fileSystemRoots: argResults['filesystem-root'], fileSystemRoots: argResults['filesystem-root'],
fileSystemScheme: argResults['filesystem-scheme'], fileSystemScheme: argResults['filesystem-scheme'],
viewFilter: argResults['isolate-filter'], viewFilter: argResults['isolate-filter'],
target: argResults['target'],
targetModel: TargetModel(argResults['target-model']), targetModel: TargetModel(argResults['target-model']),
); );
flutterDevice.observatoryUris = <Uri>[ observatoryUri ]; flutterDevice.observatoryUris = <Uri>[ observatoryUri ];
......
...@@ -346,11 +346,12 @@ class AppDomain extends Domain { ...@@ -346,11 +346,12 @@ class AppDomain extends Domain {
final Directory cwd = fs.currentDirectory; final Directory cwd = fs.currentDirectory;
fs.currentDirectory = fs.directory(projectDirectory); fs.currentDirectory = fs.directory(projectDirectory);
final FlutterDevice flutterDevice = FlutterDevice( final FlutterDevice flutterDevice = await FlutterDevice.create(
device, device,
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
dillOutputPath: dillOutputPath, dillOutputPath: dillOutputPath,
viewFilter: isolateFilter, viewFilter: isolateFilter,
target: target,
); );
ResidentRunner runner; ResidentRunner runner;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import '../base/common.dart'; import '../base/common.dart';
import '../codegen.dart'; import '../codegen.dart';
import '../project.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
class GenerateCommand extends FlutterCommand { class GenerateCommand extends FlutterCommand {
...@@ -24,7 +25,8 @@ class GenerateCommand extends FlutterCommand { ...@@ -24,7 +25,8 @@ class GenerateCommand extends FlutterCommand {
if (!experimentalBuildEnabled) { if (!experimentalBuildEnabled) {
throwToolExit('FLUTTER_EXPERIMENTAL_BUILD is not enabled, codegen is unsupported.'); throwToolExit('FLUTTER_EXPERIMENTAL_BUILD is not enabled, codegen is unsupported.');
} }
await codeGenerator.generate(mainPath: argResults['target']); final FlutterProject flutterProject = await FlutterProject.current();
await codeGenerator.generate(flutterProject, mainPath: argResults['target']);
return null; return null;
} }
} }
...@@ -10,8 +10,6 @@ import '../base/time.dart'; ...@@ -10,8 +10,6 @@ import '../base/time.dart';
import '../base/utils.dart'; import '../base/utils.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart'; import '../cache.dart';
import '../codegen.dart';
import '../compile.dart';
import '../device.dart'; import '../device.dart';
import '../globals.dart'; import '../globals.dart';
import '../ios/mac.dart'; import '../ios/mac.dart';
...@@ -346,13 +344,9 @@ class RunCommand extends RunCommandBase { ...@@ -346,13 +344,9 @@ class RunCommand extends RunCommandBase {
argResults[FlutterOptions.kEnableExperiment].isNotEmpty) { argResults[FlutterOptions.kEnableExperiment].isNotEmpty) {
expFlags = argResults[FlutterOptions.kEnableExperiment]; expFlags = argResults[FlutterOptions.kEnableExperiment];
} }
final List<FlutterDevice> flutterDevices = <FlutterDevice>[];
ResidentCompiler residentCompiler; for (Device device in devices) {
if (experimentalBuildEnabled) { final FlutterDevice flutterDevice = await FlutterDevice.create(
residentCompiler = await CodeGeneratingResidentCompiler.create(mainPath: argResults['target']);
}
final List<FlutterDevice> flutterDevices = devices.map<FlutterDevice>((Device device) {
return FlutterDevice(
device, device,
trackWidgetCreation: argResults['track-widget-creation'], trackWidgetCreation: argResults['track-widget-creation'],
dillOutputPath: argResults['output-dill'], dillOutputPath: argResults['output-dill'],
...@@ -360,9 +354,10 @@ class RunCommand extends RunCommandBase { ...@@ -360,9 +354,10 @@ class RunCommand extends RunCommandBase {
fileSystemScheme: argResults['filesystem-scheme'], fileSystemScheme: argResults['filesystem-scheme'],
viewFilter: argResults['isolate-filter'], viewFilter: argResults['isolate-filter'],
experimentalFlags: expFlags, experimentalFlags: expFlags,
generator: residentCompiler, target: argResults['target'],
); );
}).toList(); flutterDevices.add(flutterDevice);
}
ResidentRunner runner; ResidentRunner runner;
final String applicationBinaryPath = argResults['use-application-binary']; final String applicationBinaryPath = argResults['use-application-binary'];
......
...@@ -9,6 +9,7 @@ import '../base/common.dart'; ...@@ -9,6 +9,7 @@ import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/platform.dart'; import '../base/platform.dart';
import '../cache.dart'; import '../cache.dart';
import '../project.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
import '../test/coverage_collector.dart'; import '../test/coverage_collector.dart';
import '../test/event_printer.dart'; import '../test/event_printer.dart';
...@@ -104,6 +105,7 @@ class TestCommand extends FlutterCommand { ...@@ -104,6 +105,7 @@ class TestCommand extends FlutterCommand {
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
final List<String> names = argResults['name']; final List<String> names = argResults['name'];
final List<String> plainNames = argResults['plain-name']; final List<String> plainNames = argResults['plain-name'];
final FlutterProject flutterProject = await FlutterProject.current();
Iterable<String> files = argResults.rest.map<String>((String testPath) => fs.path.absolute(testPath)).toList(); Iterable<String> files = argResults.rest.map<String>((String testPath) => fs.path.absolute(testPath)).toList();
...@@ -170,6 +172,7 @@ class TestCommand extends FlutterCommand { ...@@ -170,6 +172,7 @@ class TestCommand extends FlutterCommand {
trackWidgetCreation: argResults['track-widget-creation'], trackWidgetCreation: argResults['track-widget-creation'],
updateGoldens: argResults['update-goldens'], updateGoldens: argResults['update-goldens'],
concurrency: jobs, concurrency: jobs,
flutterProject: flutterProject,
); );
if (collector != null) { if (collector != null) {
......
...@@ -661,7 +661,11 @@ class ResidentCompiler { ...@@ -661,7 +661,11 @@ class ResidentCompiler {
return null; return null;
} }
Future<dynamic> shutdown() { Future<dynamic> shutdown() async {
// Server was never sucessfully created.
if (_server == null) {
return 0;
}
_server.kill(); _server.kill();
return _server.exitCode; return _server.exitCode;
} }
......
...@@ -20,6 +20,8 @@ class PackageMap { ...@@ -20,6 +20,8 @@ class PackageMap {
static String get globalPackagesPath => _globalPackagesPath ?? kPackagesFileName; static String get globalPackagesPath => _globalPackagesPath ?? kPackagesFileName;
static String get globalGeneratedPackagesPath => fs.path.setExtension(globalPackagesPath, '.generated');
static set globalPackagesPath(String value) { static set globalPackagesPath(String value) {
_globalPackagesPath = value; _globalPackagesPath = value;
} }
......
...@@ -113,6 +113,7 @@ class FlutterProject { ...@@ -113,6 +113,7 @@ class FlutterProject {
/// The directory containing the generated code for this project. /// The directory containing the generated code for this project.
Directory get generated => directory Directory get generated => directory
.absolute
.childDirectory('.dart_tool') .childDirectory('.dart_tool')
.childDirectory('build') .childDirectory('build')
.childDirectory('generated') .childDirectory('generated')
...@@ -165,6 +166,12 @@ class FlutterProject { ...@@ -165,6 +166,12 @@ class FlutterProject {
final YamlMap pubspec = loadYaml(await pubspecFile.readAsString()); final YamlMap pubspec = loadYaml(await pubspecFile.readAsString());
return pubspec['builders']; return pubspec['builders'];
} }
/// Whether there are any builders used by this package.
Future<bool> get hasBuilders async {
final YamlMap result = await builders;
return result != null && result.isNotEmpty;
}
} }
/// Represents the iOS sub-project of a Flutter project. /// Represents the iOS sub-project of a Flutter project.
......
...@@ -49,6 +49,45 @@ class FlutterDevice { ...@@ -49,6 +49,45 @@ class FlutterDevice {
experimentalFlags: experimentalFlags, experimentalFlags: experimentalFlags,
); );
/// Create a [FlutterDevice] with optional code generation enabled.
static Future<FlutterDevice> create(Device device, {
@required bool trackWidgetCreation,
String dillOutputPath,
List<String> fileSystemRoots,
String fileSystemScheme,
String viewFilter,
@required String target,
TargetModel targetModel = TargetModel.flutter,
List<String> experimentalFlags,
ResidentCompiler generator,
}) async {
ResidentCompiler generator;
final FlutterProject flutterProject = await FlutterProject.current();
if (experimentalBuildEnabled && await flutterProject.hasBuilders) {
generator = await CodeGeneratingResidentCompiler.create(flutterProject: flutterProject, mainPath: target);
} else {
generator = ResidentCompiler(
artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
trackWidgetCreation: trackWidgetCreation,
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
targetModel: targetModel,
experimentalFlags: experimentalFlags,
);
}
return FlutterDevice(
device,
trackWidgetCreation: trackWidgetCreation,
dillOutputPath: dillOutputPath,
fileSystemRoots: fileSystemRoots,
fileSystemScheme:fileSystemScheme,
viewFilter: viewFilter,
experimentalFlags: experimentalFlags,
targetModel: targetModel,
generator: generator,
);
}
final Device device; final Device device;
final ResidentCompiler generator; final ResidentCompiler generator;
List<Uri> observatoryUris; List<Uri> observatoryUris;
......
...@@ -24,10 +24,12 @@ import '../base/process_manager.dart'; ...@@ -24,10 +24,12 @@ import '../base/process_manager.dart';
import '../base/terminal.dart'; import '../base/terminal.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../bundle.dart'; import '../bundle.dart';
import '../codegen.dart';
import '../compile.dart'; import '../compile.dart';
import '../convert.dart'; import '../convert.dart';
import '../dart/package_map.dart'; import '../dart/package_map.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart';
import '../vmservice.dart'; import '../vmservice.dart';
import 'watcher.dart'; import 'watcher.dart';
...@@ -89,6 +91,7 @@ void installHook({ ...@@ -89,6 +91,7 @@ void installHook({
int observatoryPort, int observatoryPort,
InternetAddressType serverType = InternetAddressType.IPv4, InternetAddressType serverType = InternetAddressType.IPv4,
Uri projectRootDirectory, Uri projectRootDirectory,
FlutterProject flutterProject,
}) { }) {
assert(enableObservatory || (!startPaused && observatoryPort == null)); assert(enableObservatory || (!startPaused && observatoryPort == null));
hack.registerPlatformPlugin( hack.registerPlatformPlugin(
...@@ -107,6 +110,7 @@ void installHook({ ...@@ -107,6 +110,7 @@ void installHook({
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
updateGoldens: updateGoldens, updateGoldens: updateGoldens,
projectRootDirectory: projectRootDirectory, projectRootDirectory: projectRootDirectory,
flutterProject: flutterProject,
), ),
); );
} }
...@@ -232,7 +236,7 @@ class _CompilationRequest { ...@@ -232,7 +236,7 @@ class _CompilationRequest {
// This class is a wrapper around compiler that allows multiple isolates to // This class is a wrapper around compiler that allows multiple isolates to
// enqueue compilation requests, but ensures only one compilation at a time. // enqueue compilation requests, but ensures only one compilation at a time.
class _Compiler { class _Compiler {
_Compiler(bool trackWidgetCreation, Uri projectRootDirectory) { _Compiler(bool trackWidgetCreation, Uri projectRootDirectory, FlutterProject flutterProject) {
// Compiler maintains and updates single incremental dill file. // Compiler maintains and updates single incremental dill file.
// Incremental compilation requests done for each test copy that file away // Incremental compilation requests done for each test copy that file away
// for independent execution. // for independent execution.
...@@ -265,7 +269,16 @@ class _Compiler { ...@@ -265,7 +269,16 @@ class _Compiler {
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
); );
ResidentCompiler createCompiler() { Future<ResidentCompiler> createCompiler() async {
if (experimentalBuildEnabled && await flutterProject.hasBuilders) {
return CodeGeneratingResidentCompiler.create(
flutterProject: flutterProject,
trackWidgetCreation: trackWidgetCreation,
initializeFromDill: null, // TODO(jonahwilliams): investigate multi-root support in init from dill.
unsafePackageSerialization: false,
compilerMessageConsumer: reportCompilerMessage,
);
}
return ResidentCompiler( return ResidentCompiler(
artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath), artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
packagesPath: PackageMap.globalPackagesPath, packagesPath: PackageMap.globalPackagesPath,
...@@ -290,7 +303,7 @@ class _Compiler { ...@@ -290,7 +303,7 @@ class _Compiler {
final Stopwatch compilerTime = Stopwatch()..start(); final Stopwatch compilerTime = Stopwatch()..start();
bool firstCompile = false; bool firstCompile = false;
if (compiler == null) { if (compiler == null) {
compiler = createCompiler(); compiler = await createCompiler();
firstCompile = true; firstCompile = true;
} }
suppressOutput = false; suppressOutput = false;
...@@ -374,6 +387,7 @@ class _FlutterPlatform extends PlatformPlugin { ...@@ -374,6 +387,7 @@ class _FlutterPlatform extends PlatformPlugin {
this.trackWidgetCreation, this.trackWidgetCreation,
this.updateGoldens, this.updateGoldens,
this.projectRootDirectory, this.projectRootDirectory,
this.flutterProject,
}) : assert(shellPath != null); }) : assert(shellPath != null);
final String shellPath; final String shellPath;
...@@ -389,6 +403,7 @@ class _FlutterPlatform extends PlatformPlugin { ...@@ -389,6 +403,7 @@ class _FlutterPlatform extends PlatformPlugin {
final bool trackWidgetCreation; final bool trackWidgetCreation;
final bool updateGoldens; final bool updateGoldens;
final Uri projectRootDirectory; final Uri projectRootDirectory;
final FlutterProject flutterProject;
Directory fontsDirectory; Directory fontsDirectory;
_Compiler compiler; _Compiler compiler;
...@@ -545,7 +560,7 @@ class _FlutterPlatform extends PlatformPlugin { ...@@ -545,7 +560,7 @@ class _FlutterPlatform extends PlatformPlugin {
if (precompiledDillPath == null && precompiledDillFiles == null) { if (precompiledDillPath == null && precompiledDillFiles == null) {
// Lazily instantiate compiler so it is built only if it is actually used. // Lazily instantiate compiler so it is built only if it is actually used.
compiler ??= _Compiler(trackWidgetCreation, projectRootDirectory); compiler ??= _Compiler(trackWidgetCreation, projectRootDirectory, flutterProject);
mainDart = await compiler.compile(mainDart); mainDart = await compiler.compile(mainDart);
if (mainDart == null) { if (mainDart == null) {
......
...@@ -15,6 +15,7 @@ import '../base/process_manager.dart'; ...@@ -15,6 +15,7 @@ import '../base/process_manager.dart';
import '../base/terminal.dart'; import '../base/terminal.dart';
import '../dart/package_map.dart'; import '../dart/package_map.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart';
import 'flutter_platform.dart' as loader; import 'flutter_platform.dart' as loader;
import 'watcher.dart'; import 'watcher.dart';
...@@ -34,6 +35,7 @@ Future<int> runTests( ...@@ -34,6 +35,7 @@ Future<int> runTests(
bool updateGoldens = false, bool updateGoldens = false,
TestWatcher watcher, TestWatcher watcher,
@required int concurrency, @required int concurrency,
FlutterProject flutterProject,
}) async { }) async {
// Compute the command-line arguments for package:test. // Compute the command-line arguments for package:test.
final List<String> testArgs = <String>[]; final List<String> testArgs = <String>[];
...@@ -80,6 +82,7 @@ Future<int> runTests( ...@@ -80,6 +82,7 @@ Future<int> runTests(
trackWidgetCreation: trackWidgetCreation, trackWidgetCreation: trackWidgetCreation,
updateGoldens: updateGoldens, updateGoldens: updateGoldens,
projectRootDirectory: fs.currentDirectory.uri, projectRootDirectory: fs.currentDirectory.uri,
flutterProject: flutterProject,
); );
// Make the global packages path absolute. // Make the global packages path absolute.
......
...@@ -30,6 +30,7 @@ void main() { ...@@ -30,6 +30,7 @@ void main() {
testUsingContext('delegates to build_runner', () async { testUsingContext('delegates to build_runner', () async {
const CodeGeneratingKernelCompiler kernelCompiler = CodeGeneratingKernelCompiler(); const CodeGeneratingKernelCompiler kernelCompiler = CodeGeneratingKernelCompiler();
when(mockBuildRunner.build( when(mockBuildRunner.build(
any,
aot: anyNamed('aot'), aot: anyNamed('aot'),
extraFrontEndOptions: anyNamed('extraFrontEndOptions'), extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
linkPlatformKernelIn: anyNamed('linkPlatformKernelIn'), linkPlatformKernelIn: anyNamed('linkPlatformKernelIn'),
...@@ -37,7 +38,7 @@ void main() { ...@@ -37,7 +38,7 @@ void main() {
targetProductVm: anyNamed('targetProductVm'), targetProductVm: anyNamed('targetProductVm'),
trackWidgetCreation: anyNamed('trackWidgetCreation'), trackWidgetCreation: anyNamed('trackWidgetCreation'),
)).thenAnswer((Invocation invocation) async { )).thenAnswer((Invocation invocation) async {
return CodeGenerationResult(fs.file('.packages'), fs.file('main.app.dill')); return CodeGenerationResult(fs.file('main.app.dill'));
}); });
final CompilerOutput buildResult = await kernelCompiler.compile( final CompilerOutput buildResult = await kernelCompiler.compile(
outputFilePath: 'output.app.dill', outputFilePath: 'output.app.dill',
......
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