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

Remove extra build_runner modes, remove flutter_build (#28873)

parent 64d31016
# Use the analysis options settings from the top level of the repo (not
# the ones from above, which include the `public_member_api_docs` rule).
include: ../../analysis_options.yaml
# Read about `build.yaml` at https://pub.dartlang.org/packages/build_config
builders:
kernel:
import: "package:flutter_build/flutter_build.dart"
builder_factories:
- "flutterKernelBuilder"
build_extensions:
".dart":
- ".app.dill"
- ".packages"
required_inputs: [".dart", ".flutter.module"]
auto_apply: root_package
build_to: cache
defaults:
generate_for:
include:
- lib/**
// Copyright 2019 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 'package:build/build.dart';
import 'src/kernel_builder.dart';
/// Utility method called by build_runner to generate a build script.
///
/// This method does not need to be invoked manually, and instead should
/// be configured via the `build.yaml` file.
Builder flutterKernelBuilder(BuilderOptions builderOptions) {
final Map<String, Object> config = builderOptions.config;
final List<Object> extraFrontEndOptions = config['extraFrontEndOptions'] ?? const <String>[];
return FlutterKernelBuilder(
aot: config['aot'],
disabled: config['disabled'],
engineDartBinaryPath: config['engineDartBinaryPath'],
frontendServerPath: config['frontendServerPath'],
incrementalCompilerByteStorePath: config['incrementalCompilerByteStorePath'],
linkPlatformKernelIn: config['linkPlatformKernelIn'],
mainPath: config['mainPath'],
packagesPath: config['packagesPath'],
sdkRoot: config['sdkRoot'],
targetProductVm: config['targetProductVm'],
trackWidgetCreation: config['trackWidgetCreation'],
extraFrontEndOptions: extraFrontEndOptions.cast<String>(),
);
}
// Copyright 2019 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.
// Note: this Builder does not run in the same process as the flutter_tool, so
// the DI provided getters such as `fs` will not work.
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:build/build.dart';
import 'package:package_config/packages_file.dart' as packages_file;
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
const String _kFlutterDillOutputExtension = '.app.dill';
const String _kPackagesExtension = '.packages';
const String _kMultirootScheme = 'org-dartlang-app';
/// A builder which creates a kernel and packages file for a Flutter app.
///
/// Unlike the package:build kernel builders, this creates a single kernel from
/// dart source using the frontend server binary. The newly created .package
/// file replaces the relative root of the current package with a multi-root
/// which includes the generated directory.
class FlutterKernelBuilder implements Builder {
const FlutterKernelBuilder({
@required this.disabled,
@required this.mainPath,
@required this.aot,
@required this.trackWidgetCreation,
@required this.targetProductVm,
@required this.linkPlatformKernelIn,
@required this.extraFrontEndOptions,
@required this.sdkRoot,
@required this.packagesPath,
@required this.incrementalCompilerByteStorePath,
@required this.frontendServerPath,
@required this.engineDartBinaryPath,
});
/// The path to the entrypoint that will be compiled.
final String mainPath;
/// The path to the pub generated .packages file.
final String packagesPath;
/// The path to the root of the flutter patched SDK.
final String sdkRoot;
/// The path to the frontend server snapshot.
final String frontendServerPath;
/// The path to the dart executable to use to run the frontend server
/// snapshot.
final String engineDartBinaryPath;
/// Whether to build an ahead of time build.
final bool aot;
/// Whether to disable production of kernel.
final bool disabled;
/// Whether the `trackWidgetCreation` flag is provided to the frontend
/// server.
final bool trackWidgetCreation;
/// Whether to provide the Dart product define to the frontend server.
final bool targetProductVm;
/// When in batch mode, link platform kernel file into result kernel file.
final bool linkPlatformKernelIn;
/// Whether to compile incrementally.
final String incrementalCompilerByteStorePath;
/// Additional arguments to pass to the frontend server.
final List<String> extraFrontEndOptions;
@override
Map<String, List<String>> get buildExtensions => const <String, List<String>>{
'.dart': <String>[_kFlutterDillOutputExtension, _kPackagesExtension],
};
@override
Future<void> build(BuildStep buildStep) async {
// Do not resolve dependencies if this does not correspond to the main
// entrypoint. Do not generate kernel if it has been disabled.
if (!mainPath.contains(buildStep.inputId.path) || disabled) {
return;
}
final AssetId outputId = buildStep.inputId.changeExtension(_kFlutterDillOutputExtension);
// 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
// from the temp directory at the end of the build step.
final Directory tempDirecory = await Directory.systemTemp.createTemp('_flutter_build');
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'));
await outputFile.create();
final String packageName = buildStep.inputId.package;
String absoluteMainPath;
if (path.isAbsolute(mainPath)) {
absoluteMainPath = mainPath;
} else {
absoluteMainPath = path.join(projectDir.absolute.path, mainPath);
}
// start up the frontend server with configuration.
final List<String> arguments = <String>[
frontendServerPath,
'--sdk-root',
sdkRoot,
'--strong',
'--target=flutter',
];
if (trackWidgetCreation) {
arguments.add('--track-widget-creation');
}
if (!linkPlatformKernelIn) {
arguments.add('--no-link-platform');
}
if (aot) {
arguments.add('--aot');
arguments.add('--tfa');
}
if (targetProductVm) {
arguments.add('-Ddart.vm.product=true');
}
if (incrementalCompilerByteStorePath != null) {
arguments.add('--incremental');
}
final String generatedRoot = path.join(projectDir.absolute.path, '.dart_tool', 'build', 'generated', '$packageName', 'lib${Platform.pathSeparator}');
final String normalRoot = path.join(projectDir.absolute.path, 'lib${Platform.pathSeparator}');
arguments.addAll(<String>[
'--packages',
packagesFilePath,
'--output-dill',
outputFile.path,
'--filesystem-root',
normalRoot,
'--filesystem-root',
generatedRoot,
'--filesystem-scheme',
_kMultirootScheme,
]);
if (extraFrontEndOptions != null) {
arguments.addAll(extraFrontEndOptions);
}
final Uri mainUri = _PackageUriMapper.findUri(
absoluteMainPath,
packagesFilePath,
_kMultirootScheme,
<String>[normalRoot, generatedRoot],
);
arguments.add(mainUri?.toString() ?? absoluteMainPath);
// Invoke the frontend server and copy the dill back to the output
// directory.
try {
final Process server = await Process.start(engineDartBinaryPath, arguments);
final _StdoutHandler _stdoutHandler = _StdoutHandler();
server.stderr
.transform<String>(utf8.decoder)
.listen(log.shout);
server.stdout
.transform<String>(utf8.decoder)
.transform<String>(const LineSplitter())
.listen(_stdoutHandler.handler);
await server.exitCode;
await _stdoutHandler.compilerOutput.future;
await buildStep.writeAsBytes(outputId, await outputFile.readAsBytes());
} catch (err, stackTrace) {
log.shout('frontend server failed to start: $err, $stackTrace');
}
}
}
class _StdoutHandler {
_StdoutHandler() {
reset();
}
bool compilerMessageReceived = false;
String boundaryKey;
Completer<_CompilerOutput> compilerOutput;
bool _suppressCompilerMessages;
void handler(String message) {
const String kResultPrefix = 'result ';
if (boundaryKey == null) {
if (message.startsWith(kResultPrefix))
boundaryKey = message.substring(kResultPrefix.length);
} else if (message.startsWith(boundaryKey)) {
if (message.length <= boundaryKey.length) {
compilerOutput.complete(null);
return;
}
final int spaceDelimiter = message.lastIndexOf(' ');
compilerOutput.complete(
_CompilerOutput(
message.substring(boundaryKey.length + 1, spaceDelimiter),
int.parse(message.substring(spaceDelimiter + 1).trim())));
} else if (!_suppressCompilerMessages) {
if (compilerMessageReceived == false) {
log.info('\nCompiler message:');
compilerMessageReceived = true;
}
log.info(message);
}
}
// This is needed to get ready to process next compilation result output,
// with its own boundary key and new completer.
void reset({bool suppressCompilerMessages = false}) {
boundaryKey = null;
compilerMessageReceived = false;
compilerOutput = Completer<_CompilerOutput>();
_suppressCompilerMessages = suppressCompilerMessages;
}
}
class _CompilerOutput {
const _CompilerOutput(this.outputFilename, this.errorCount);
final String outputFilename;
final int errorCount;
}
/// Converts filesystem paths to package URIs.
class _PackageUriMapper {
_PackageUriMapper(String scriptPath, String packagesPath, String fileSystemScheme, List<String> fileSystemRoots) {
final List<int> bytes = File(path.absolute(packagesPath)).readAsBytesSync();
final Map<String, Uri> packageMap = packages_file.parse(bytes, Uri.file(packagesPath, windows: Platform.isWindows));
final String scriptUri = Uri.file(scriptPath, windows: Platform.isWindows).toString();
for (String packageName in packageMap.keys) {
final String prefix = packageMap[packageName].toString();
if (fileSystemScheme != null && fileSystemRoots != null && prefix.contains(fileSystemScheme)) {
_packageName = packageName;
_uriPrefixes = fileSystemRoots
.map((String name) => Uri.file(name, windows: Platform.isWindows).toString())
.toList();
return;
}
if (scriptUri.startsWith(prefix)) {
_packageName = packageName;
_uriPrefixes = <String>[prefix];
return;
}
}
}
String _packageName;
List<String> _uriPrefixes;
Uri map(String scriptPath) {
if (_packageName == null) {
return null;
}
final String scriptUri = Uri.file(scriptPath, windows: Platform.isWindows).toString();
for (String uriPrefix in _uriPrefixes) {
if (scriptUri.startsWith(uriPrefix)) {
return Uri.parse('package:$_packageName/${scriptUri.substring(uriPrefix.length)}');
}
}
return null;
}
static Uri findUri(String scriptPath, String packagesPath, String fileSystemScheme, List<String> fileSystemRoots) {
return _PackageUriMapper(scriptPath, packagesPath, fileSystemScheme, fileSystemRoots).map(scriptPath);
}
}
name: flutter_build
environment:
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
sdk: ">=2.0.0-dev.68.0 <3.0.0"
dependencies:
# To update these, use "flutter update-packages --force-upgrade".
build: 1.1.1
package_config: 1.0.5
path: 1.6.2
analyzer: 0.35.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
args: 1.5.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
async: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
charcode: 1.1.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
collection: 1.14.11 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
convert: 2.1.1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
crypto: 2.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
csslib: 0.14.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
front_end: 0.1.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
glob: 1.1.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
html: 0.13.4+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
kernel: 0.3.13 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
logging: 0.11.3+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
meta: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
plugin: 0.2.0+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pub_semver: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.5.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
string_scanner: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
term_glyph: 1.1.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
typed_data: 1.1.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
utf: 0.9.0+5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
watcher: 0.9.7+10 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
yaml: 2.1.15 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dartdoc:
# Exclude this package from the hosted API docs.
nodoc: true
# PUBSPEC CHECKSUM: eed2
......@@ -10,7 +10,6 @@ import 'package:build_runner_core/build_runner_core.dart' hide BuildStatus;
import 'package:build_daemon/data/server_log.dart';
import 'package:build_daemon/data/build_status.dart' as build;
import 'package:build_daemon/client.dart';
import 'package:meta/meta.dart';
import 'package:yaml/yaml.dart';
import 'package:crypto/crypto.dart' show md5;
......@@ -21,14 +20,15 @@ import '../base/io.dart';
import '../base/logger.dart';
import '../base/process_manager.dart';
import '../codegen.dart';
import '../convert.dart';
import '../dart/package_map.dart';
import '../dart/pub.dart';
import '../globals.dart';
import '../project.dart';
import '../resident_runner.dart';
import 'build_script_generator.dart';
/// The minimum version of build_runner we can support in the flutter tool.
const String kMinimumBuildRunnerVersion = '1.2.8';
// 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.
......@@ -42,92 +42,6 @@ const String _kMultirootScheme = 'org-dartlang-app';
class BuildRunner extends CodeGenerator {
const BuildRunner();
@override
Future<CodeGenerationResult> build(FlutterProject flutterProject, {
@required String mainPath,
@required bool aot,
@required bool linkPlatformKernelIn,
@required bool trackWidgetCreation,
@required bool targetProductVm,
List<String> extraFrontEndOptions = const <String>[],
bool disableKernelGeneration = false,
}) async {
await generateBuildScript(flutterProject);
final String frontendServerPath = artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk
);
final String sdkRoot = artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath);
final String engineDartBinaryPath = artifacts.getArtifactPath(Artifact.engineDartBinary);
final String packagesPath = flutterProject.packagesFile.absolute.path;
final String buildSnapshot = flutterProject
.dartTool
.childDirectory('build')
.childDirectory('entrypoint')
.childFile('build.dart.snapshot')
.path;
final String scriptPackagesPath = flutterProject
.dartTool
.childDirectory('flutter_tool')
.childFile('.packages')
.path;
final Status status = logger.startProgress('running builders...', timeout: null);
try {
final Process buildProcess = await processManager.start(<String>[
engineDartBinaryPath,
'--packages=$scriptPackagesPath',
buildSnapshot,
'build',
'--skip-build-script-check',
'--define', 'flutter_build|kernel=disabled=$disableKernelGeneration',
'--define', 'flutter_build|kernel=aot=$aot',
'--define', 'flutter_build|kernel=linkPlatformKernelIn=$linkPlatformKernelIn',
'--define', 'flutter_build|kernel=trackWidgetCreation=$trackWidgetCreation',
'--define', 'flutter_build|kernel=targetProductVm=$targetProductVm',
'--define', 'flutter_build|kernel=mainPath=$mainPath',
'--define', 'flutter_build|kernel=packagesPath=$packagesPath',
'--define', 'flutter_build|kernel=sdkRoot=$sdkRoot',
'--define', 'flutter_build|kernel=frontendServerPath=$frontendServerPath',
'--define', 'flutter_build|kernel=engineDartBinaryPath=$engineDartBinaryPath',
'--define', 'flutter_build|kernel=extraFrontEndOptions=${extraFrontEndOptions ?? const <String>[]}',
]);
buildProcess
.stdout
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(printTrace);
buildProcess
.stderr
.transform(utf8.decoder)
.transform(const LineSplitter())
.listen(printError);
} finally {
status.stop();
}
if (disableKernelGeneration) {
return const CodeGenerationResult(null);
}
/// We don't check for this above because it might be generated for the
/// first time by invoking the build.
final Directory dartTool = flutterProject.dartTool;
final String projectName = flutterProject.manifest.appName;
final Directory generatedDirectory = dartTool
.absolute
.childDirectory('build')
.childDirectory('generated')
.childDirectory(projectName);
if (!generatedDirectory.existsSync()) {
throw Exception('build_runner cannot find generated directory');
}
final String relativeMain = fs.path.relative(mainPath, from: flutterProject.directory.path);
final File dillFile = fs.file(
fs.path.join(generatedDirectory.path, fs.path.setExtension(relativeMain, '.app.dill'))
);
if (!dillFile.existsSync()) {
throw Exception('build_runner did not produce output at expected location: ${dillFile.path} missing');
}
return CodeGenerationResult(dillFile);
}
@override
Future<void> generateBuildScript(FlutterProject flutterProject) async {
final Directory entrypointDirectory = fs.directory(fs.path.join(flutterProject.dartTool.path, 'build', 'entrypoint'));
......@@ -177,10 +91,9 @@ class BuildRunner extends CodeGenerator {
stringBuffer.writeln(' $name: $node');
}
}
stringBuffer.writeln(' build_runner: any');
stringBuffer.writeln(' flutter_build:');
stringBuffer.writeln(' sdk: flutter');
syntheticPubspec.writeAsStringSync(stringBuffer.toString());
stringBuffer.writeln(' build_runner: ^$kMinimumBuildRunnerVersion');
await syntheticPubspec.writeAsString(stringBuffer.toString());
await pubGet(
context: PubContext.pubGet,
directory: generatedDirectory.path,
......@@ -217,15 +130,9 @@ class BuildRunner extends CodeGenerator {
bool trackWidgetCreation = false,
List<String> extraFrontEndOptions = const <String> [],
}) async {
mainPath ??= findMainDartFile();
await generateBuildScript(flutterProject);
_generatePackages(flutterProject);
final String frontendServerPath = artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk
);
final String sdkRoot = artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath);
final String engineDartBinaryPath = artifacts.getArtifactPath(Artifact.engineDartBinary);
final String packagesPath = flutterProject.packagesFile.absolute.path;
final File buildSnapshot = flutterProject
.dartTool
.childDirectory('build')
......@@ -245,17 +152,6 @@ class BuildRunner extends CodeGenerator {
buildSnapshot.path,
'daemon',
'--skip-build-script-check',
'--define', 'flutter_build|kernel=disabled=false',
'--define', 'flutter_build|kernel=aot=false',
'--define', 'flutter_build|kernel=linkPlatformKernelIn=$linkPlatformKernelIn',
'--define', 'flutter_build|kernel=trackWidgetCreation=$trackWidgetCreation',
'--define', 'flutter_build|kernel=targetProductVm=$targetProductVm',
'--define', 'flutter_build|kernel=mainPath=$mainPath',
'--define', 'flutter_build|kernel=packagesPath=$packagesPath',
'--define', 'flutter_build|kernel=sdkRoot=$sdkRoot',
'--define', 'flutter_build|kernel=frontendServerPath=$frontendServerPath',
'--define', 'flutter_build|kernel=engineDartBinaryPath=$engineDartBinaryPath',
'--define', 'flutter_build|kernel=extraFrontEndOptions=${extraFrontEndOptions ?? const <String>[]}',
];
buildDaemonClient = await BuildDaemonClient.connect(flutterProject.directory.path, command, logHandler: (ServerLog log) => printTrace(log.toString()));
} finally {
......@@ -264,9 +160,7 @@ class BuildRunner extends CodeGenerator {
buildDaemonClient.registerBuildTarget(DefaultBuildTarget((DefaultBuildTargetBuilder builder) {
builder.target = flutterProject.manifest.appName;
}));
final String relativeMain = fs.path.relative(mainPath, from: flutterProject.directory.path);
final File generatedDillFile = fs.file(fs.path.join(flutterProject.generated.path, fs.path.setExtension(relativeMain, '.app.dill')));
return _BuildRunnerCodegenDaemon(buildDaemonClient, generatedDillFile);
return _BuildRunnerCodegenDaemon(buildDaemonClient);
}
// Create generated packages file which adds a multi-root scheme to the user's
......@@ -283,11 +177,10 @@ class BuildRunner extends CodeGenerator {
}
class _BuildRunnerCodegenDaemon implements CodegenDaemon {
_BuildRunnerCodegenDaemon(this.buildDaemonClient, this.dillFile);
_BuildRunnerCodegenDaemon(this.buildDaemonClient);
final BuildDaemonClient buildDaemonClient;
@override
final File dillFile;
@override
CodegenStatus get lastStatus => _lastStatus;
CodegenStatus _lastStatus;
......
......@@ -138,11 +138,7 @@ class BuildScriptGenerator {
if (definition.isOptional) {
namedArgs['isOptional'] = literalTrue;
}
if (definition.buildTo == BuildTo.cache) {
namedArgs['hideOutput'] = literalTrue;
} else {
namedArgs['hideOutput'] = literalFalse;
}
namedArgs['hideOutput'] = literalTrue;
if (!identical(definition.defaults?.generateFor, InputSet.anything)) {
final Map<String, Expression> inputSetArgs = <String, Expression>{};
if (definition.defaults.generateFor.include != null) {
......
......@@ -5,6 +5,7 @@
import 'package:meta/meta.dart';
import 'artifacts.dart';
import 'base/common.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/platform.dart';
......@@ -44,44 +45,11 @@ set experimentalBuildEnabled(bool value) {
abstract class CodeGenerator {
const CodeGenerator();
/// Run a partial build include code generators but not kernel.
Future<void> generate(FlutterProject flutterProject, {@required String mainPath}) async {
await build(
flutterProject,
mainPath: mainPath,
aot: false,
linkPlatformKernelIn: false,
trackWidgetCreation: false,
targetProductVm: false,
disableKernelGeneration: true,
);
}
/// Run a full build and return the resulting .packages and dill file.
///
/// The defines of the build command are the arguments required in the
/// flutter_build kernel builder.
Future<CodeGenerationResult> build(FlutterProject flutterProject, {
@required String mainPath,
@required bool aot,
@required bool linkPlatformKernelIn,
@required bool trackWidgetCreation,
@required bool targetProductVm,
List<String> extraFrontEndOptions = const <String>[],
bool disableKernelGeneration = false,
});
/// Starts a persistent code generting daemon.
///
/// The defines of the daemon command are the arguments required in the
/// flutter_build kernel builder.
Future<CodegenDaemon> daemon(FlutterProject flutterProject, {
@required String mainPath,
bool linkPlatformKernelIn = false,
bool targetProductVm = false,
bool trackWidgetCreation = false,
List<String> extraFrontEndOptions = const <String>[],
});
Future<CodegenDaemon> daemon(FlutterProject flutterProject);
// Generates a synthetic package under .dart_tool/flutter_tool which is in turn
// used to generate a build script.
......@@ -91,32 +59,13 @@ abstract class CodeGenerator {
class UnsupportedCodeGenerator extends CodeGenerator {
const UnsupportedCodeGenerator();
@override
Future<CodeGenerationResult> build(FlutterProject flutterProject, {
String mainPath,
bool aot,
bool linkPlatformKernelIn,
bool trackWidgetCreation,
bool targetProductVm,
List<String> extraFrontEndOptions = const <String> [],
bool disableKernelGeneration = false,
}) {
throw UnsupportedError('build_runner is not currently supported.');
}
@override
Future<void> generateBuildScript(FlutterProject flutterProject) {
throw UnsupportedError('build_runner is not currently supported.');
}
@override
Future<CodegenDaemon> daemon(FlutterProject flutterProject, {
String mainPath,
bool linkPlatformKernelIn = false,
bool targetProductVm = false,
bool trackWidgetCreation = false,
List<String> extraFrontEndOptions = const <String> [],
}) {
Future<CodegenDaemon> daemon(FlutterProject flutterProject) {
throw UnsupportedError('build_runner is not currently supported.');
}
}
......@@ -129,17 +78,6 @@ abstract class CodegenDaemon {
/// Starts a new build.
void startBuild();
File get dillFile;
}
/// The result of running a build through a [CodeGenerator].
///
/// If no dill or packages file is generated, they will be null.
class CodeGenerationResult {
const CodeGenerationResult(this.dillFile);
final File dillFile;
}
/// An implementation of the [KernelCompiler] which delegates to build_runner.
......@@ -152,6 +90,8 @@ class CodeGenerationResult {
class CodeGeneratingKernelCompiler implements KernelCompiler {
const CodeGeneratingKernelCompiler();
static const KernelCompiler _delegate = KernelCompiler();
@override
Future<CompilerOutput> compile({
String mainPath,
......@@ -176,26 +116,35 @@ class CodeGeneratingKernelCompiler implements KernelCompiler {
'build* pipeline');
}
final FlutterProject flutterProject = await FlutterProject.current();
try {
final CodeGenerationResult buildResult = await codeGenerator.build(
flutterProject,
aot: aot,
linkPlatformKernelIn: linkPlatformKernelIn,
trackWidgetCreation: trackWidgetCreation,
mainPath: mainPath,
targetProductVm: targetProductVm,
extraFrontEndOptions: extraFrontEndOptions,
);
final File outputFile = fs.file(outputFilePath);
if (!await outputFile.exists()) {
await outputFile.create();
final CodegenDaemon codegenDaemon = await codeGenerator.daemon(flutterProject);
codegenDaemon.startBuild();
await for (CodegenStatus codegenStatus in codegenDaemon.buildResults) {
if (codegenStatus == CodegenStatus.Failed) {
throwToolExit('Code generation failed');
}
if (codegenStatus == CodegenStatus.Succeeded) {
break;
}
await outputFile.writeAsBytes(await buildResult.dillFile.readAsBytes());
return CompilerOutput(outputFilePath, 0);
} on Exception catch (err) {
printError('Compilation Failed: $err');
return const CompilerOutput(null, 1);
}
return _delegate.compile(
mainPath: mainPath,
outputFilePath: outputFilePath,
linkPlatformKernelIn: linkPlatformKernelIn,
aot: aot,
trackWidgetCreation: trackWidgetCreation,
extraFrontEndOptions: extraFrontEndOptions,
incrementalCompilerByteStorePath: incrementalCompilerByteStorePath,
targetProductVm: targetProductVm,
sdkRoot: sdkRoot,
packagesPath: PackageMap.globalGeneratedPackagesPath,
fileSystemRoots: <String>[
fs.path.join(flutterProject.generated.path, 'lib${platform.pathSeparator}'),
fs.path.join(flutterProject.directory.path, 'lib${platform.pathSeparator}'),
],
fileSystemScheme: _kMultiRootScheme,
depFilePath: depFilePath,
targetModel: targetModel,
);
}
}
......@@ -208,27 +157,19 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
/// run builds.
static Future<CodeGeneratingResidentCompiler> create({
@required FlutterProject flutterProject,
String mainPath,
bool trackWidgetCreation = false,
CompilerMessageConsumer compilerMessageConsumer = printError,
bool unsafePackageSerialization = false,
String outputPath,
String initializeFromDill,
}) async {
final CodegenDaemon codegenDaemon = await codeGenerator.daemon(
flutterProject,
extraFrontEndOptions: <String>[],
linkPlatformKernelIn: false,
mainPath: mainPath,
targetProductVm: false,
trackWidgetCreation: trackWidgetCreation,
);
final CodegenDaemon codegenDaemon = await codeGenerator.daemon(flutterProject);
codegenDaemon.startBuild();
final CodegenStatus status = await codegenDaemon.buildResults.firstWhere((CodegenStatus status) {
return status == CodegenStatus.Succeeded || status == CodegenStatus.Failed;
});
if (status == CodegenStatus.Failed) {
printError('Code generation failed, build may have compile errors');
printError('Code generation failed, build may have compile errors.');
}
final ResidentCompiler residentCompiler = ResidentCompiler(
artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
......@@ -263,7 +204,7 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
Future<CompilerOutput> recompile(String mainPath, List<String> invalidatedFiles, {String outputPath, String packagesFilePath}) async {
if (_codegenDaemon.lastStatus != CodegenStatus.Succeeded && _codegenDaemon.lastStatus != CodegenStatus.Failed) {
await _codegenDaemon.buildResults.firstWhere((CodegenStatus status) {
return status ==CodegenStatus.Succeeded || status == CodegenStatus.Failed;
return status == CodegenStatus.Succeeded || status == CodegenStatus.Failed;
});
}
if (_codegenDaemon.lastStatus == CodegenStatus.Failed) {
......@@ -272,8 +213,8 @@ class CodeGeneratingResidentCompiler implements ResidentCompiler {
// Delete this file so that the frontend_server can handle multi-root.
// TODO(jonahwilliams): investigate frontend_server behavior in the presence
// of multi-root and initialize from dill.
if (await fs.file(outputPath).exists()) {
await fs.file(outputPath).delete();
if (outputPath != null && fs.file(outputPath).existsSync()) {
fs.file(outputPath).deleteSync();
}
return _residentCompiler.recompile(
mainPath,
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import '../base/common.dart';
import '../cache.dart';
import '../codegen.dart';
import '../project.dart';
import '../runner/flutter_command.dart';
......@@ -22,11 +23,21 @@ class GenerateCommand extends FlutterCommand {
@override
Future<FlutterCommandResult> runCommand() async {
Cache.releaseLockEarly();
if (!experimentalBuildEnabled) {
throwToolExit('FLUTTER_EXPERIMENTAL_BUILD is not enabled, codegen is unsupported.');
}
final FlutterProject flutterProject = await FlutterProject.current();
await codeGenerator.generate(flutterProject, mainPath: argResults['target']);
final CodegenDaemon codegenDaemon = await codeGenerator.daemon(flutterProject);
codegenDaemon.startBuild();
await for (CodegenStatus codegenStatus in codegenDaemon.buildResults) {
if (codegenStatus == CodegenStatus.Failed) {
throwToolExit('Code generation failed');
}
if (codegenStatus ==CodegenStatus.Succeeded) {
break;
}
}
return null;
}
}
......@@ -64,7 +64,9 @@ class FlutterDevice {
ResidentCompiler generator;
final FlutterProject flutterProject = await FlutterProject.current();
if (experimentalBuildEnabled && await flutterProject.hasBuilders) {
generator = await CodeGeneratingResidentCompiler.create(flutterProject: flutterProject, mainPath: target);
generator = await CodeGeneratingResidentCompiler.create(
flutterProject: flutterProject,
);
} else {
generator = ResidentCompiler(
artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
......
// Copyright 2019 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 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_runner/build_runner.dart';
import 'package:flutter_tools/src/codegen.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
import '../src/context.dart';
void main() {
group(CodeGeneratingKernelCompiler, () {
final MockBuildRunner mockBuildRunner = MockBuildRunner();
final MockFileSystem mockFileSystem = MockFileSystem();
final MockFile packagesFile = MockFile();
final MockFile dillFile = MockFile();
final MockFile outputFile = MockFile();
when(mockFileSystem.file('main.app.dill')).thenReturn(dillFile);
when(mockFileSystem.file('.packages')).thenReturn(packagesFile);
when(mockFileSystem.file('output.app.dill')).thenReturn(outputFile);
when(packagesFile.exists()).thenAnswer((Invocation invocation) async => true);
when(dillFile.exists()).thenAnswer((Invocation invocation) async => true);
when(outputFile.exists()).thenAnswer((Invocation invocation) async => true);
when(dillFile.readAsBytes()).thenAnswer((Invocation invocation) async => <int>[0, 1, 2, 3]);
testUsingContext('delegates to build_runner', () async {
const CodeGeneratingKernelCompiler kernelCompiler = CodeGeneratingKernelCompiler();
when(mockBuildRunner.build(
any,
aot: anyNamed('aot'),
extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
linkPlatformKernelIn: anyNamed('linkPlatformKernelIn'),
mainPath: anyNamed('mainPath'),
targetProductVm: anyNamed('targetProductVm'),
trackWidgetCreation: anyNamed('trackWidgetCreation'),
)).thenAnswer((Invocation invocation) async {
return CodeGenerationResult(fs.file('main.app.dill'));
});
final CompilerOutput buildResult = await kernelCompiler.compile(
outputFilePath: 'output.app.dill',
);
expect(buildResult.outputFilename, 'output.app.dill');
expect(buildResult.errorCount, 0);
verify(outputFile.writeAsBytes(<int>[0, 1, 2, 3])).called(1);
}, overrides: <Type, Generator>{
CodeGenerator: () => mockBuildRunner,
FileSystem: () => mockFileSystem,
});
});
}
class MockBuildRunner extends Mock implements BuildRunner {}
class MockFileSystem extends Mock implements FileSystem {}
class MockFile extends Mock implements File {}
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