Unverified Commit 67cf2157 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add basic codegen app to be used for integration testing and benchmarks (#27257)

parent 3205736f
// 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 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:flutter_devicelab/framework/adb.dart';
import 'package:flutter_devicelab/framework/framework.dart';
import 'package:flutter_devicelab/framework/utils.dart';
import 'package:flutter_devicelab/tasks/integration_tests.dart';
final Directory codegenAppPath = dir(path.join(flutterDirectory.path, 'dev/integration_tests/codegen'));
Future<void> main() async {
deviceOperatingSystem = DeviceOperatingSystem.android;
await task(createCodegenerationIntegrationTest());
}
......@@ -61,6 +61,16 @@ TaskFunction createAndroidSemanticsIntegrationTest() {
);
}
TaskFunction createCodegenerationIntegrationTest() {
return DriverTest(
'${flutterDirectory.path}/dev/integration_tests/codegen',
'lib/main.dart',
environment: <String, String>{
'FLUTTER_EXPERIMENTAL_BUILD': 'true'
},
);
}
TaskFunction createFlutterCreateOfflineTest() {
return () async {
final Directory tempDir = Directory.systemTemp.createTempSync('flutter_create_test.');
......@@ -83,12 +93,14 @@ class DriverTest {
this.testDirectory,
this.testTarget, {
this.extraOptions = const <String>[],
this.environment = const <String, String>{},
}
);
final String testDirectory;
final String testTarget;
final List<String> extraOptions;
final Map<String, String> environment;
Future<TaskResult> call() {
return inDirectory<TaskResult>(testDirectory, () async {
......@@ -107,7 +119,7 @@ class DriverTest {
deviceId,
];
options.addAll(extraOptions);
await flutter('drive', options: options);
await flutter('drive', options: options, environment: Map<String, String>.from(environment));
return TaskResult.success(null);
});
......
......@@ -76,6 +76,14 @@ tasks:
stage: devicelab_win
required_agent_capabilities: ["windows/android"]
codegen_integration_test:
description: >
Runs codegeneration and verifies that it can execute
correctly.
stage: devicelab_win
required_agent_capabilities: ["windows/android"]
flaky: true
flutter_gallery_android__compile:
description: >
Collects various performance metrics of compiling the Flutter
......
# codegen
A Flutter project for testing code generation.
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>android_____</name>
<comment>Project android_____ created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withInputStream { stream ->
localProperties.load(stream)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 28
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "0.0.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
aaptOptions {
// TODO(goderbauer): remove when https://github.com/flutter/flutter/issues/8986 is resolved.
if(System.getenv("FLUTTER_CI_WIN")) {
println "AAPT cruncher disabled when running on Win CI."
cruncherEnabled false
}
}
}
flutter {
source '../..'
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yourcompany.platforminteraction">
<!-- The INTERNET permission is required for development. Specifically,
flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application android:name="io.flutter.app.FlutterApplication" android:label="Platform Interaction" android:icon="@mipmap/ic_launcher">
<activity android:name="com.yourcompany.platforminteraction.MainActivity"
android:launchMode="singleTop"
android:theme="@android:style/Theme.Black.NoTitleBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
// 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.
package com.yourcompany.platforminteraction;
import android.os.Bundle;
import io.flutter.app.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
}
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withInputStream { stream -> plugins.load(stream) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
// 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:inject/inject.dart';
// This is a compile-time generated file and does not exist in source.
import 'coffee_app.inject.dart' as generated; // ignore: uri_does_not_exist
import 'src/coffee.dart';
@module
class PourOverCoffeeModule {
@provide
@brandName
String provideBrand() => 'Coffee by Flutter Inc.';
@provide
@modelName
String provideModel() => 'PourOverSupremeFiesta';
@provide
@asynchronous
Future<Heater> provideHeater() async => Stove();
@provide
Pump providePump(Heater heater) => NoOpPump();
}
class NoOpPump extends Pump {
@override
void pump() {
print('nothing to pump...');
}
}
class Stove extends Heater {
@override
bool get isHot => _isHot;
bool _isHot = false;
@override
void off() {
_isHot = true;
}
@override
void on() {
_isHot = true;
}
}
@Injector(<Type>[PourOverCoffeeModule])
abstract class CoffeeApp {
static final Future<CoffeeApp> Function(PourOverCoffeeModule) create = generated.CoffeeApp$Injector.create;
@provide
CoffeeMaker getCoffeeMaker();
}
// 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/material.dart';
import 'package:flutter_driver/driver_extension.dart';
import 'coffee_app.dart';
import 'src/coffee.dart';
Future<void> main() async {
enableFlutterDriverExtension();
coffeeApp = await CoffeeApp.create(PourOverCoffeeModule());
runApp(ExampleWidget());
}
CoffeeApp coffeeApp;
class ExampleWidget extends StatefulWidget {
@override
_ExampleWidgetState createState() => _ExampleWidgetState();
}
class _ExampleWidgetState extends State<ExampleWidget> {
String _message = '';
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: const Text('Press Button, Get Coffee'),
onPressed: () async {
final CoffeeMaker coffeeMaker = coffeeApp.getCoffeeMaker();
setState(() {
_message = coffeeMaker.brew();
});
},
),
Text(_message),
],
),
),
);
}
}
// 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:inject/inject.dart';
const Qualifier brandName = Qualifier(#brandName);
const Qualifier modelName = Qualifier(#modelName);
class CoffeeMaker {
@provide
CoffeeMaker(this._heater, this._pump, this._brand, this._model);
final Heater _heater;
final Pump _pump;
@modelName
final String _model;
@brandName
final String _brand;
String brew() {
_heater.on();
_pump.pump();
print(' [_]P coffee! [_]P');
final String message = 'Thanks for using $_model by $_brand';
_heater.off();
return message;
}
}
abstract class Heater {
void on();
void off();
bool get isHot;
}
abstract class Pump {
void pump();
}
name: codegen
description: A test of Flutter integrating code generation.
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:
flutter:
sdk: flutter
flutter_driver:
sdk: flutter
# TODO(jonahwilliams): replace with pub version when everything is compatible
inject:
git:
url: https://github.com/jonahwilliams/inject.dart
path: package/inject
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"
file: 5.0.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
intl: 0.15.7 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
json_rpc_2: 2.0.9 # 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"
path: 1.6.2 # 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.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stack_trace: 1.9.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_channel: 1.6.8 # 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"
vector_math: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
vm_service_client: 0.2.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
web_socket_channel: 1.0.9 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
dev_dependencies:
test: 1.5.3
analyzer: 0.35.1 # 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"
boolean_selector: 1.0.4 # 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.11 # 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.3+3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http: 0.12.0+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_multi_server: 2.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
http_parser: 3.1.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
io: 0.3.3 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
js: 0.6.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
kernel: 0.3.11 # 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"
matcher: 0.12.3+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
mime: 0.9.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble: 1.4.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
package_config: 1.0.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
package_resolver: 1.0.6 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pedantic: 1.4.0 # 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"
pool: 1.4.0 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf: 0.7.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_packages_handler: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_static: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_web_socket: 0.2.2+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_map_stack_trace: 1.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_maps: 0.10.8 # 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"
test_api: 0.2.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test_core: 0.2.1+1 # 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"
builders:
# TODO(jonahwilliams): replace with pub version when everything is compatible
inject_generator:
git:
url: https://github.com/jonahwilliams/inject.dart
path: package/inject_generator
flutter:
uses-material-design: true
# PUBSPEC CHECKSUM: c26c
// 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_driver/flutter_driver.dart';
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
FlutterDriver driver;
setUpAll(() async {
driver = await FlutterDriver.connect();
});
test('Can execute generated code', () async {
const String button = 'Press Button, Get Coffee';
await driver.tap(find.text(button));
const String message = 'Thanks for using PourOverSupremeFiesta by Coffee by Flutter Inc.';
final String fullMessage = await driver.getText(find.text(message));
expect(fullMessage, message);
});
}
\ No newline at end of file
......@@ -84,6 +84,11 @@ class FlutterKernelBuilder implements Builder {
@override
Future<void> build(BuildStep buildStep) async {
// Do not resolve dependencies if this does not correspond to the main
// entrypoint.
if (!mainPath.contains(buildStep.inputId.path)) {
return;
}
final AssetId outputId = buildStep.inputId.changeExtension(_kFlutterDillOutputExtension);
final AssetId packagesOutputId = buildStep.inputId.changeExtension(_kPackagesExtension);
......@@ -97,9 +102,8 @@ class FlutterKernelBuilder implements Builder {
return;
}
// Do not generate kernel if it has been disabled or if this asset does not
// correspond to the current entrypoint.
if (disabled || !mainPath.contains(buildStep.inputId.path)) {
// Do not generate kernel if it has been disabled.
if (disabled) {
return;
}
......@@ -118,8 +122,14 @@ class FlutterKernelBuilder implements Builder {
// 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:$multiRootScheme:///lib/');
final String newPackagesContents = oldPackagesContents.replaceFirst('$packageName:lib/', '$packageName:$multiRootScheme:/');
await packagesFile.writeAsString(newPackagesContents);
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>[
......@@ -145,14 +155,15 @@ class FlutterKernelBuilder implements Builder {
if (incrementalCompilerByteStorePath != null) {
arguments.add('--incremental');
}
final String generatedRoot = path.join(projectDir.absolute.path, '.dart_tool', 'build', 'generated', '$packageName');
final String generatedRoot = path.join(projectDir.absolute.path, '.dart_tool', 'build', 'generated', '$packageName', 'lib');
final String normalRoot = path.join(projectDir.absolute.path, 'lib');
arguments.addAll(<String>[
'--packages',
packagesFile.path,
'--output-dill',
outputFile.path,
'--filesystem-root',
projectDir.absolute.path,
normalRoot,
'--filesystem-root',
generatedRoot,
'--filesystem-scheme',
......@@ -162,12 +173,12 @@ class FlutterKernelBuilder implements Builder {
arguments.addAll(extraFrontEndOptions);
}
final Uri mainUri = _PackageUriMapper.findUri(
mainPath,
absoluteMainPath,
packagesFile.path,
multiRootScheme,
<String>[projectDir.absolute.path, generatedRoot],
<String>[normalRoot, generatedRoot],
);
arguments.add(mainUri.toString());
arguments.add(mainUri?.toString() ?? absoluteMainPath);
// Invoke the frontend server and copy the dill back to the output
// directory.
try {
......@@ -202,7 +213,6 @@ class _StdoutHandler {
bool _suppressCompilerMessages;
void handler(String message) {
log.info(message);
const String kResultPrefix = 'result ';
if (boundaryKey == null) {
if (message.startsWith(kResultPrefix))
......@@ -256,7 +266,7 @@ class _PackageUriMapper {
if (fileSystemScheme != null && fileSystemRoots != null && prefix.contains(fileSystemScheme)) {
_packageName = packageName;
_uriPrefixes = fileSystemRoots
.map((String name) => Uri.file('$name/lib/', windows: Platform.isWindows).toString())
.map((String name) => Uri.file(name, windows: Platform.isWindows).toString())
.toList();
return;
}
......
......@@ -7,7 +7,7 @@ environment:
dependencies:
# To update these, use "flutter update-packages --force-upgrade".
build: 1.1.1
build_modules: 1.0.7
build_modules: 1.0.7+2
package_config: 1.0.5
path: 1.6.2
......@@ -50,4 +50,4 @@ dartdoc:
# Exclude this package from the hosted API docs.
nodoc: true
# PUBSPEC CHECKSUM: 0361
# PUBSPEC CHECKSUM: dcbe
......@@ -18,6 +18,7 @@ dart_library("flutter_tools") {
"//third_party/dart/third_party/pkg/linter",
"//third_party/dart-pkg/pub/archive",
"//third_party/dart-pkg/pub/args",
"//third_party/dart-pkg/pub/build_daemon",
"//third_party/dart-pkg/pub/build_runner_core",
"//third_party/dart-pkg/pub/collection",
"//third_party/dart-pkg/pub/completion",
......
......@@ -5,6 +5,12 @@
import 'dart:async';
import 'runner.dart' as runner;
import 'src/base/context.dart';
// The build_runner code generation is provided here to make it easier to
// avoid introducing the dependency into google3. Not all build* packages
// are synced internally.
import 'src/build_runner/build_runner.dart';
import 'src/codegen.dart';
import 'src/commands/analyze.dart';
import 'src/commands/attach.dart';
import 'src/commands/build.dart';
......@@ -18,6 +24,7 @@ import 'src/commands/doctor.dart';
import 'src/commands/drive.dart';
import 'src/commands/emulators.dart';
import 'src/commands/format.dart';
import 'src/commands/generate.dart';
import 'src/commands/ide_config.dart';
import 'src/commands/inject_plugins.dart';
import 'src/commands/install.dart';
......@@ -63,6 +70,7 @@ Future<void> main(List<String> args) async {
DriveCommand(),
EmulatorsCommand(),
FormatCommand(),
GenerateCommand(),
IdeConfigCommand(hidden: !verboseHelp),
InjectPluginsCommand(hidden: !verboseHelp),
InstallCommand(),
......@@ -81,5 +89,10 @@ Future<void> main(List<String> args) async {
VersionCommand(),
], verbose: verbose,
muteCommandLogging: muteCommandLogging,
verboseHelp: verboseHelp);
verboseHelp: verboseHelp,
overrides: <Type, Generator>{
// The build runner instance is not supported in google3 because
// the build runner packages are not synced internally.
CodeGenerator: () => experimentalBuildEnabled ? const BuildRunner() : const UnsupportedCodeGenerator(),
});
}
......@@ -302,7 +302,6 @@ class AOTSnapshotter {
printTrace('Extra front-end options: $extraFrontEndOptions');
final String depfilePath = fs.path.join(outputPath, 'kernel_compile.d');
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create();
final CompilerOutput compilerOutput = await kernelCompiler.compile(
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
mainPath: mainPath,
......
// 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 '../base/file_system.dart';
import '../compile.dart';
import '../globals.dart';
import 'build_runner.dart';
/// An implementation of the [KernelCompiler] which delegates to build_runner.
///
/// Only a subset of the arguments provided to the [KernelCompiler] are
/// supported here. Using the build pipeline implies a fixed multiroot
/// filesystem and requires a pubspec.
///
/// This is only safe to use if [experimentalBuildEnabled] is true.
class BuildKernelCompiler implements KernelCompiler {
const BuildKernelCompiler();
@override
Future<CompilerOutput> compile({
String mainPath,
String outputFilePath,
bool linkPlatformKernelIn = false,
bool aot = false,
bool trackWidgetCreation,
List<String> extraFrontEndOptions,
String incrementalCompilerByteStorePath,
bool targetProductVm = false,
// These arguments are currently unused.
String sdkRoot,
String packagesPath,
List<String> fileSystemRoots,
String fileSystemScheme,
String depFilePath,
TargetModel targetModel = TargetModel.flutter,
}) async {
if (fileSystemRoots != null || fileSystemScheme != null || depFilePath != null || targetModel != null || sdkRoot != null || packagesPath != null) {
printTrace('fileSystemRoots, fileSystemScheme, depFilePath, targetModel,'
'sdkRoot, packagesPath are not supported when using the experimental '
'build* pipeline');
}
final BuildRunner buildRunner = buildRunnerFactory.create();
try {
final BuildResult buildResult = await buildRunner.build(
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();
}
await outputFile.writeAsBytes(await buildResult.dillFile.readAsBytes());
return CompilerOutput(outputFilePath, 0);
} on Exception catch (err) {
printError('Compilation Failed: $err');
return const CompilerOutput(null, 1);
}
}
}
......@@ -4,69 +4,45 @@
import 'dart:async';
import 'package:build_daemon/data/build_target.dart';
import 'package:build_runner_core/build_runner_core.dart';
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 '../artifacts.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/platform.dart';
import '../base/process_manager.dart';
import '../cache.dart';
import '../codegen.dart';
import '../convert.dart';
import '../dart/pub.dart';
import '../globals.dart';
import '../project.dart';
import '../resident_runner.dart';
import 'build_script_generator.dart';
/// The [BuildRunnerFactory] instance.
BuildRunnerFactory get buildRunnerFactory => context[BuildRunnerFactory];
/// Whether to attempt to build a flutter project using build* libraries.
///
/// This requires both an experimental opt in via the environment variable
/// 'FLUTTER_EXPERIMENTAL_BUILD' and that the project itself has a
/// dependency on the package 'flutter_build' and 'build_runner.'
bool get experimentalBuildEnabled {
return _experimentalBuildEnabled ??= platform.environment['FLUTTER_EXPERIMENTAL_BUILD']?.toLowerCase() == 'true';
}
bool _experimentalBuildEnabled;
@visibleForTesting
set experimentalBuildEnabled(bool value) {
_experimentalBuildEnabled = value;
}
/// An injectable factory to create instances of [BuildRunner].
class BuildRunnerFactory {
const BuildRunnerFactory();
/// Creates a new [BuildRunner] instance.
BuildRunner create() {
return BuildRunner();
}
}
/// A wrapper for a build_runner process which delegates to a generated
/// build script.
///
/// This is only enabled if [experimentalBuildEnabled] is true, and only for
/// external flutter users.
class BuildRunner {
class BuildRunner extends CodeGenerator {
const BuildRunner();
/// Run a build_runner 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<BuildResult> build({
@override
Future<CodeGenerationResult> build({
@required String mainPath,
@required bool aot,
@required bool linkPlatformKernelIn,
@required bool trackWidgetCreation,
@required bool targetProductVm,
@required String mainPath,
@required List<String> extraFrontEndOptions,
List<String> extraFrontEndOptions = const <String>[],
bool disableKernelGeneration = false,
}) async {
await generateBuildScript();
final FlutterProject flutterProject = await FlutterProject.current();
......@@ -95,7 +71,7 @@ class BuildRunner {
'--packages=$scriptPackagesPath',
buildScript,
'build',
'--define', 'flutter_build|kernel=disabled=false',
'--define', 'flutter_build|kernel=disabled=$disableKernelGeneration',
'--define', 'flutter_build|kernel=aot=$aot',
'--define', 'flutter_build|kernel=linkPlatformKernelIn=$linkPlatformKernelIn',
'--define', 'flutter_build|kernel=trackWidgetCreation=$trackWidgetCreation',
......@@ -121,6 +97,9 @@ class BuildRunner {
} finally {
status.stop();
}
if (disableKernelGeneration) {
return const CodeGenerationResult(null, 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;
......@@ -143,13 +122,10 @@ class BuildRunner {
if (!packagesFile.existsSync() || !dillFile.existsSync()) {
throw Exception('build_runner did not produce output at expected location: ${dillFile.path} missing');
}
return BuildResult(packagesFile, dillFile);
return CodeGenerationResult(packagesFile, dillFile);
}
/// Invalidates a generated build script by deleting it.
///
/// Must be called any time a pubspec file update triggers a corresponding change
/// in .packages.
@override
Future<void> invalidateBuildScript() async {
final FlutterProject flutterProject = await FlutterProject.current();
final File buildScript = flutterProject.dartTool
......@@ -162,8 +138,7 @@ class BuildRunner {
await buildScript.delete();
}
// Generates a synthetic package under .dart_tool/flutter_tool which is in turn
// used to generate a build script.
@override
Future<void> generateBuildScript() async {
final FlutterProject flutterProject = await FlutterProject.current();
final String generatedDirectory = fs.path.join(flutterProject.dartTool.path, 'flutter_tool');
......@@ -180,8 +155,10 @@ class BuildRunner {
stringBuffer.writeln('name: synthetic_example');
stringBuffer.writeln('dependencies:');
for (String builder in await flutterProject.builders) {
stringBuffer.writeln(' $builder: any');
final YamlMap builders = await flutterProject.builders;
for (String name in builders.keys) {
final YamlNode node = builders[name];
stringBuffer.writeln(' $name: $node');
}
stringBuffer.writeln(' build_runner: any');
stringBuffer.writeln(' flutter_build:');
......@@ -195,17 +172,92 @@ class BuildRunner {
checkLastModified: false,
);
final PackageGraph packageGraph = PackageGraph.forPath(syntheticPubspec.parent.path);
final BuildScriptGenerator buildScriptGenerator = buildScriptGeneratorFactory.create(flutterProject, packageGraph);
final BuildScriptGenerator buildScriptGenerator = const BuildScriptGeneratorFactory().create(flutterProject, packageGraph);
await buildScriptGenerator.generateBuildScript();
} finally {
status.stop();
}
}
@override
Future<CodegenDaemon> daemon({
String mainPath,
bool linkPlatformKernelIn = false,
bool targetProductVm = false,
bool trackWidgetCreation = false,
List<String> extraFrontEndOptions = const <String> [],
}) async {
mainPath ??= findMainDartFile();
await generateBuildScript();
final FlutterProject flutterProject = await FlutterProject.current();
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 buildScript = flutterProject
.dartTool
.childDirectory('build')
.childDirectory('entrypoint')
.childFile('build.dart')
.path;
final String scriptPackagesPath = flutterProject
.dartTool
.childDirectory('flutter_tool')
.childFile('.packages')
.path;
final String dartPath = fs.path.join(Cache.flutterRoot, 'bin', 'cache', 'dart-sdk', 'bin', 'dart');
final Status status = logger.startProgress('starting build daemon...', timeout: null);
BuildDaemonClient buildDaemonClient;
try {
final List<String> command = <String>[
dartPath,
'--packages=$scriptPackagesPath',
buildScript,
'daemon',
'--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 {
status.stop();
}
buildDaemonClient.registerBuildTarget(DefaultBuildTarget((DefaultBuildTargetBuilder builder) {
builder.target = flutterProject.manifest.appName;
}));
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')));
return _BuildRunnerCodegenDaemon(buildDaemonClient, generatedPackagesFile, generatedDillFile);
}
}
class BuildResult {
const BuildResult(this.packagesFile, this.dillFile);
class _BuildRunnerCodegenDaemon implements CodegenDaemon {
_BuildRunnerCodegenDaemon(this.buildDaemonClient, this.packagesFile, this.dillFile);
final BuildDaemonClient buildDaemonClient;
@override
final File packagesFile;
@override
final File dillFile;
@override
Stream<bool> get buildResults => buildDaemonClient.buildResults.map((build.BuildResults results) {
return results.results.first.status == build.BuildStatus.succeeded;
});
@override
void startBuild() {
buildDaemonClient.startBuild();
}
}
......@@ -12,12 +12,9 @@ import 'package:dart_style/dart_style.dart';
import 'package:graphs/graphs.dart';
import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../project.dart';
BuildScriptGeneratorFactory get buildScriptGeneratorFactory => context[BuildScriptGeneratorFactory];
class BuildScriptGeneratorFactory {
const BuildScriptGeneratorFactory();
......@@ -227,14 +224,16 @@ class BuildScriptGenerator {
return refer('toNoneByDefault',
'package:build_runner_core/build_runner_core.dart')
.call(<Expression>[]);
case AutoApply.dependents:
return refer('toDependentsOf',
'package:build_runner_core/build_runner_core.dart')
.call(<Expression>[literalString(definition.package)]);
// TODO(jonahwilliams): re-enabled when we have the builders strategy fleshed out.
// case AutoApply.dependents:
// return refer('toDependentsOf',
// 'package:build_runner_core/build_runner_core.dart')
// .call(<Expression>[literalString(definition.package)]);
case AutoApply.allPackages:
return refer('toAllPackages',
'package:build_runner_core/build_runner_core.dart')
.call(<Expression>[]);
case AutoApply.dependents:
case AutoApply.rootPackage:
return refer('toRoot', 'package:build_runner_core/build_runner_core.dart')
.call(<Expression>[]);
......
......@@ -99,7 +99,6 @@ Future<void> build({
if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty)
printTrace('Extra front-end options: $extraFrontEndOptions');
ensureDirectoryExists(applicationKernelFilePath);
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create();
final CompilerOutput compilerOutput = await kernelCompiler.compile(
sdkRoot: artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
incrementalCompilerByteStorePath: compilationTraceFilePath != null ? null :
......
// 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:meta/meta.dart';
import 'artifacts.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/platform.dart';
import 'compile.dart';
import 'globals.dart';
import 'project.dart';
const String _kMultiRootScheme = 'org-dartlang-app';
/// The [CodeGenerator] instance.
///
/// If [experimentalBuildEnabled] is false, this will contain an unsupported
/// implementation.
CodeGenerator get codeGenerator => context[CodeGenerator];
/// Whether to attempt to build a flutter project using build* libraries.
///
/// This requires both an experimental opt in via the environment variable
/// 'FLUTTER_EXPERIMENTAL_BUILD' and that the project itself has a
/// dependency on the package 'flutter_build' and 'build_runner.'
bool get experimentalBuildEnabled {
return _experimentalBuildEnabled ??= platform.environment['FLUTTER_EXPERIMENTAL_BUILD']?.toLowerCase() == 'true';
}
bool _experimentalBuildEnabled;
@visibleForTesting
set experimentalBuildEnabled(bool value) {
_experimentalBuildEnabled = value;
}
/// A wrapper for a build_runner process which delegates to a generated
/// build script.
///
/// This is only enabled if [experimentalBuildEnabled] is true, and only for
/// external flutter users.
abstract class CodeGenerator {
const CodeGenerator();
/// Run a partial build include code generators but not kernel.
Future<void> generate({@required String mainPath}) async {
await build(
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({
@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({
@required String mainPath,
bool linkPlatformKernelIn = false,
bool targetProductVm = false,
bool trackWidgetCreation = false,
List<String> extraFrontEndOptions = const <String>[],
});
/// Invalidates a generated build script by deleting it.
///
/// Must be called any time a pubspec file update triggers a corresponding change
/// in .packages.
Future<void> invalidateBuildScript();
// Generates a synthetic package under .dart_tool/flutter_tool which is in turn
// used to generate a build script.
Future<void> generateBuildScript();
}
class UnsupportedCodeGenerator extends CodeGenerator {
const UnsupportedCodeGenerator();
@override
Future<CodeGenerationResult> build({
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() {
throw UnsupportedError('build_runner is not currently supported.');
}
@override
Future<void> invalidateBuildScript() {
throw UnsupportedError('build_runner is not currently supported.');
}
@override
Future<CodegenDaemon> daemon({
String mainPath,
bool linkPlatformKernelIn = false,
bool targetProductVm = false,
bool trackWidgetCreation = false,
List<String> extraFrontEndOptions = const <String> [],
}) {
throw UnsupportedError('build_runner is not currently supported.');
}
}
abstract class CodegenDaemon {
/// Whether the previously enqueued build was successful.
Stream<bool> get buildResults;
/// Starts a new build.
void startBuild();
File get packagesFile;
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.packagesFile, this.dillFile);
final File packagesFile;
final File dillFile;
}
/// An implementation of the [KernelCompiler] which delegates to build_runner.
///
/// Only a subset of the arguments provided to the [KernelCompiler] are
/// supported here. Using the build pipeline implies a fixed multiroot
/// filesystem and requires a pubspec.
///
/// This is only safe to use if [experimentalBuildEnabled] is true.
class CodeGeneratingKernelCompiler implements KernelCompiler {
const CodeGeneratingKernelCompiler();
@override
Future<CompilerOutput> compile({
String mainPath,
String outputFilePath,
bool linkPlatformKernelIn = false,
bool aot = false,
bool trackWidgetCreation,
List<String> extraFrontEndOptions,
String incrementalCompilerByteStorePath,
bool targetProductVm = false,
// These arguments are currently unused.
String sdkRoot,
String packagesPath,
List<String> fileSystemRoots,
String fileSystemScheme,
String depFilePath,
TargetModel targetModel = TargetModel.flutter,
}) async {
if (fileSystemRoots != null || fileSystemScheme != null || depFilePath != null || targetModel != null || sdkRoot != null || packagesPath != null) {
printTrace('fileSystemRoots, fileSystemScheme, depFilePath, targetModel,'
'sdkRoot, packagesPath are not supported when using the experimental '
'build* pipeline');
}
try {
final CodeGenerationResult buildResult = await codeGenerator.build(
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();
}
await outputFile.writeAsBytes(await buildResult.dillFile.readAsBytes());
return CompilerOutput(outputFilePath, 0);
} on Exception catch (err) {
printError('Compilation Failed: $err');
return const CompilerOutput(null, 1);
}
}
}
/// An implementation of a [ResidentCompiler] which runs a [BuildRunner] before
/// talking to the CFE.
class CodeGeneratingResidentCompiler implements ResidentCompiler {
CodeGeneratingResidentCompiler._(this._residentCompiler, this._codegenDaemon);
/// Creates a new [ResidentCompiler] and configures a [BuildDaemonClient] to
/// run builds.
static Future<CodeGeneratingResidentCompiler> create({
@required String mainPath,
bool trackWidgetCreation = false,
CompilerMessageConsumer compilerMessageConsumer = printError,
bool unsafePackageSerialization = false,
}) async {
final FlutterProject flutterProject = await FlutterProject.current();
final CodegenDaemon codegenDaemon = await codeGenerator.daemon(
extraFrontEndOptions: <String>[],
linkPlatformKernelIn: false,
mainPath: mainPath,
targetProductVm: false,
trackWidgetCreation: trackWidgetCreation,
);
codegenDaemon.startBuild();
await codegenDaemon.buildResults.firstWhere((bool result) => result);
final ResidentCompiler residentCompiler = ResidentCompiler(
artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath),
trackWidgetCreation: trackWidgetCreation,
packagesPath: codegenDaemon.packagesFile.path,
fileSystemRoots: <String>[
flutterProject.generated.absolute.path,
flutterProject.directory.path,
],
fileSystemScheme: _kMultiRootScheme,
targetModel: TargetModel.flutter,
unsafePackageSerialization: unsafePackageSerialization,
);
return CodeGeneratingResidentCompiler._(residentCompiler, codegenDaemon);
}
final ResidentCompiler _residentCompiler;
final CodegenDaemon _codegenDaemon;
@override
void accept() {
_residentCompiler.accept();
}
@override
Future<CompilerOutput> compileExpression(String expression, List<String> definitions, List<String> typeDefinitions, String libraryUri, String klass, bool isStatic) {
return _residentCompiler.compileExpression(expression, definitions, typeDefinitions, libraryUri, klass, isStatic);
}
@override
Future<CompilerOutput> recompile(String mainPath, List<String> invalidatedFiles, {String outputPath, String packagesFilePath}) async {
_codegenDaemon.startBuild();
await _codegenDaemon.buildResults.first;
// 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();
}
return _residentCompiler.recompile(
mainPath,
invalidatedFiles,
outputPath: outputPath,
packagesFilePath: _codegenDaemon.packagesFile.path,
);
}
@override
Future<CompilerOutput> reject() {
return _residentCompiler.reject();
}
@override
void reset() {
_residentCompiler.reset();
}
@override
Future<void> shutdown() {
return _residentCompiler.shutdown();
}
}
// 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 '../base/common.dart';
import '../codegen.dart';
import '../runner/flutter_command.dart';
class GenerateCommand extends FlutterCommand {
GenerateCommand() {
usesTargetOption();
}
@override
String get description => 'run code generators.';
@override
String get name => 'generate';
@override
bool get hidden => true;
@override
Future<FlutterCommandResult> runCommand() async {
if (!experimentalBuildEnabled) {
throwToolExit('FLUTTER_EXPERIMENTAL_BUILD is not enabled, codegen is unsupported.');
}
await codeGenerator.generate(mainPath: argResults['target']);
return null;
}
}
\ No newline at end of file
......@@ -10,6 +10,8 @@ import '../base/time.dart';
import '../base/utils.dart';
import '../build_info.dart';
import '../cache.dart';
import '../codegen.dart';
import '../compile.dart';
import '../device.dart';
import '../globals.dart';
import '../ios/mac.dart';
......@@ -345,6 +347,10 @@ class RunCommand extends RunCommandBase {
expFlags = argResults[FlutterOptions.kEnableExperiment];
}
ResidentCompiler residentCompiler;
if (experimentalBuildEnabled) {
residentCompiler = await CodeGeneratingResidentCompiler.create(mainPath: argResults['target']);
}
final List<FlutterDevice> flutterDevices = devices.map<FlutterDevice>((Device device) {
return FlutterDevice(
device,
......@@ -354,6 +360,7 @@ class RunCommand extends RunCommandBase {
fileSystemScheme: argResults['filesystem-scheme'],
viewFilter: argResults['isolate-filter'],
experimentalFlags: expFlags,
generator: residentCompiler,
);
}).toList();
......
......@@ -390,7 +390,7 @@ class _DependencyLink {
/// "dependency_overrides" sections, as well as the "name" and "version" fields
/// in the pubspec header bucketed into [header]. The others are all bucketed
/// into [other].
enum Section { header, dependencies, devDependencies, dependencyOverrides, other }
enum Section { header, dependencies, devDependencies, dependencyOverrides, builders, other }
/// The various kinds of dependencies we know and care about.
enum DependencyKind {
......@@ -504,6 +504,11 @@ class PubspecYaml {
seenDev = true;
}
result.add(header);
} else if (section == Section.builders) {
// Do nothing.
// This line isn't a section header, and we're not in a section we care about.
// We just stick the line into the output unmodified.
result.add(PubspecLine(line));
} else if (section == Section.other) {
if (line.contains(kDependencyChecksum)) {
// This is the pubspec checksum. After computing it, we remove it from the output data
......@@ -878,6 +883,8 @@ class PubspecHeader extends PubspecLine {
return PubspecHeader(line, Section.devDependencies);
case 'dependency_overrides':
return PubspecHeader(line, Section.dependencyOverrides);
case 'builders':
return PubspecHeader(line, Section.builders);
case 'name':
case 'version':
return PubspecHeader(line, Section.header, name: sectionName, value: value);
......
......@@ -20,21 +20,10 @@ import 'convert.dart';
import 'dart/package_map.dart';
import 'globals.dart';
KernelCompilerFactory get kernelCompilerFactory => context[KernelCompilerFactory];
KernelCompiler get kernelCompiler => context[KernelCompiler];
typedef CompilerMessageConsumer = void Function(String message, {bool emphasis, TerminalColor color});
/// Injectable factory to allow async construction of a [KernelCompiler].
class KernelCompilerFactory {
const KernelCompilerFactory();
/// Return the correct [KernelCompiler] instance for the given project
/// configuration.
FutureOr<KernelCompiler> create() async {
return const KernelCompiler();
}
}
/// The target model describes the set of core libraries that are availible within
/// the SDK.
class TargetModel {
......
......@@ -22,6 +22,7 @@ import 'base/time.dart';
import 'base/user_messages.dart';
import 'base/utils.dart';
import 'cache.dart';
import 'codegen.dart';
import 'compile.dart';
import 'devfs.dart';
import 'device.dart';
......@@ -80,7 +81,7 @@ Future<T> runInContext<T>(
IOSSimulatorUtils: () => IOSSimulatorUtils(),
IOSWorkflow: () => const IOSWorkflow(),
IOSValidator: () => const IOSValidator(),
KernelCompilerFactory: () => const KernelCompilerFactory(),
KernelCompiler: () => experimentalBuildEnabled ? const CodeGeneratingKernelCompiler() : const KernelCompiler(),
LinuxWorkflow: () => const LinuxWorkflow(),
Logger: () => platform.isWindows ? WindowsStdoutLogger() : StdoutLogger(),
MacOSWorkflow: () => const MacOSWorkflow(),
......
......@@ -107,6 +107,13 @@ class FlutterProject {
/// The `.dart-tool` directory of this project.
Directory get dartTool => directory.childDirectory('.dart_tool');
/// The directory containing the generated code for this project.
Directory get generated => directory
.childDirectory('.dart_tool')
.childDirectory('build')
.childDirectory('generated')
.childDirectory(manifest.appName);
/// The example sub-project of this project.
FlutterProject get example => FlutterProject(
_exampleDirectory(directory),
......@@ -147,15 +154,9 @@ class FlutterProject {
}
/// Return the set of builders used by this package.
Future<List<String>> get builders async {
Future<YamlMap> get builders async {
final YamlMap pubspec = loadYaml(await pubspecFile.readAsString());
final YamlList builders = pubspec['builders'];
if (builders == null) {
return <String>[];
}
return builders.map<String>((Object node) {
return node.toString();
}).toList();
return pubspec['builders'];
}
}
......
......@@ -16,6 +16,7 @@ import 'base/logger.dart';
import 'base/terminal.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'codegen.dart';
import 'compile.dart';
import 'dart/dependencies.dart';
import 'dart/package_map.dart';
......@@ -895,6 +896,11 @@ abstract class ResidentRunner {
}
bool hasDirtyDependencies(FlutterDevice device) {
/// When using the build system, dependency analysis is handled by build
/// runner instead.
if (experimentalBuildEnabled) {
return false;
}
final DartDependencySetBuilder dartDependencySetBuilder =
DartDependencySetBuilder(mainPath, packagesFilePath);
final DependencyChecker dependencyChecker =
......
......@@ -15,6 +15,7 @@ import 'base/logger.dart';
import 'base/terminal.dart';
import 'base/utils.dart';
import 'build_info.dart';
import 'codegen.dart';
import 'compile.dart';
import 'convert.dart';
import 'dart/dependencies.dart';
......@@ -122,8 +123,12 @@ class HotRunner extends ResidentRunner {
return false;
}
final DartDependencySetBuilder dartDependencySetBuilder =
DartDependencySetBuilder(mainPath, packagesFilePath);
/// When using the build system, dependency analysis is handled by build
/// runner instead.
if (experimentalBuildEnabled) {
return true;
}
final DartDependencySetBuilder dartDependencySetBuilder = DartDependencySetBuilder(mainPath, packagesFilePath);
try {
_dartDependencies = Set<String>.from(dartDependencySetBuilder.build());
} on DartDependencyException catch (error) {
......
......@@ -39,10 +39,6 @@ dependencies:
flutter_goldens_client:
path: ../flutter_goldens_client
# build_runner depenencies needed for codegen.
build: 1.1.1
build_modules: 1.0.7
# We depend on very specific internal implementation details of the
# 'test' package, which change between versions, so when upgrading
# this, make sure the tests are still running correctly.
......@@ -53,6 +49,9 @@ dependencies:
build_runner_core: 2.0.3
dart_style: 1.2.3
code_builder: 3.2.0
build: 1.1.1
build_modules: 1.0.7+2
build_daemon: 0.4.0
async: 2.0.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
bazel_worker: 0.1.20 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -85,9 +84,12 @@ dependencies:
pub_semver: 1.4.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
pubspec_parse: 0.1.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
scratch_space: 0.0.3+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf: 0.7.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_web_socket: 0.2.2+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_map_stack_trace: 1.1.5 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_maps: 0.10.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
source_span: 1.5.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
stream_transform: 0.0.15 # 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"
timing: 0.1.1+1 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
......@@ -106,14 +108,12 @@ dev_dependencies:
mime: 0.9.6+2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
multi_server_socket: 1.0.2 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
node_preamble: 1.4.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf: 0.7.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_packages_handler: 1.0.4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_static: 0.2.8 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
shelf_web_socket: 0.2.2+4 # THIS LINE IS AUTOGENERATED - TO UPDATE USE "flutter update-packages --force-upgrade"
test: 1.5.3 # 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: c962
# PUBSPEC CHECKSUM: 6c3e
......@@ -4,7 +4,7 @@
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_runner/build_runner.dart';
import 'package:flutter_tools/src/codegen.dart';
import 'package:mockito/mockito.dart';
import '../src/common.dart';
......
......@@ -3,8 +3,8 @@
// found in the LICENSE file.
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_runner/build_kernel_compiler.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';
......@@ -12,8 +12,7 @@ import '../src/common.dart';
import '../src/context.dart';
void main() {
group(BuildKernelCompiler, () {
final MockBuildRunnerFactory mockBuildRunnerFactory = MockBuildRunnerFactory();
group(CodeGeneratingKernelCompiler, () {
final MockBuildRunner mockBuildRunner = MockBuildRunner();
final MockFileSystem mockFileSystem = MockFileSystem();
final MockFile packagesFile = MockFile();
......@@ -26,11 +25,10 @@ void main() {
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(mockBuildRunnerFactory.create()).thenReturn(mockBuildRunner);
when(dillFile.readAsBytes()).thenAnswer((Invocation invocation) async => <int>[0, 1, 2, 3]);
testUsingContext('delegates to build_runner', () async {
const BuildKernelCompiler kernelCompiler = BuildKernelCompiler();
const CodeGeneratingKernelCompiler kernelCompiler = CodeGeneratingKernelCompiler();
when(mockBuildRunner.build(
aot: anyNamed('aot'),
extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
......@@ -39,7 +37,7 @@ void main() {
targetProductVm: anyNamed('targetProductVm'),
trackWidgetCreation: anyNamed('trackWidgetCreation')
)).thenAnswer((Invocation invocation) async {
return BuildResult(fs.file('.packages'), fs.file('main.app.dill'));
return CodeGenerationResult(fs.file('.packages'), fs.file('main.app.dill'));
});
final CompilerOutput buildResult = await kernelCompiler.compile(
outputFilePath: 'output.app.dill',
......@@ -48,13 +46,12 @@ void main() {
expect(buildResult.errorCount, 0);
verify(outputFile.writeAsBytes(<int>[0, 1, 2, 3])).called(1);
}, overrides: <Type, Generator>{
BuildRunnerFactory: () => mockBuildRunnerFactory,
CodeGenerator: () => mockBuildRunner,
FileSystem: () => mockFileSystem,
});
});
}
class MockBuildRunnerFactory extends Mock implements BuildRunnerFactory {}
class MockBuildRunner extends Mock implements BuildRunner {}
class MockFileSystem extends Mock implements FileSystem {}
class MockFile extends Mock implements File {}
......@@ -118,7 +118,6 @@ example:org-dartlang-app:/
'result abc\nline1\nline2\nabc /path/to/main.dart.dill 0'
))
));
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create();
final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
trackWidgetCreation: false,
......@@ -142,7 +141,6 @@ example:org-dartlang-app:/
'result abc\nline1\nline2\nabc'
))
));
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create();
final CompilerOutput output = await kernelCompiler.compile(sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
trackWidgetCreation: false,
......@@ -168,7 +166,6 @@ example:org-dartlang-app:/
'result abc\nline1\nline2\nabc'
))
));
final KernelCompiler kernelCompiler = await kernelCompilerFactory.create();
final CompilerOutput output = await kernelCompiler.compile(
sdkRoot: '/path/to/sdkroot',
mainPath: '/path/to/main.dart',
......
......@@ -78,6 +78,34 @@ void main() {
}
}
});
test('no unauthorized imports of build_runner', () {
final List<String> whitelistedPaths = <String>[
fs.path.join(flutterTools, 'test', 'src', 'build_runner'),
fs.path.join(flutterTools, 'lib', 'src', 'build_runner'),
fs.path.join(flutterTools, 'lib', 'executable.dart')
];
bool _isNotWhitelisted(FileSystemEntity entity) => whitelistedPaths.every((String path) => !entity.path.contains(path));
for (String dirName in <String>['lib']) {
final Iterable<File> files = fs.directory(fs.path.join(flutterTools, dirName))
.listSync(recursive: true)
.where(_isDartFile)
.where(_isNotWhitelisted)
.map(_asFile);
for (File file in files) {
for (String line in file.readAsLinesSync()) {
if (line.startsWith(RegExp(r'import.*package:build_runner_core/build_runner_core.dart')) ||
line.startsWith(RegExp(r'import.*package:build_runner/build_runner.dart')) ||
line.startsWith(RegExp(r'import.*package:build_config/build_config.dart')) ||
line.startsWith(RegExp(r'import.*build_runner/.*.dart'))) {
final String relativePath = fs.path.relative(file.path, from:flutterTools);
fail('$relativePath imports a build_runner package');
}
}
}
}
});
}
bool _isDartFile(FileSystemEntity entity) => entity is File && entity.path.endsWith('.dart');
......
......@@ -102,7 +102,6 @@ void main() {
MockArtifacts mockArtifacts;
MockKernelCompiler mockKernelCompiler;
MockProcessManager mockProcessManager;
MockKernelCompilerFactory mockKernelCompilerFactory;
MockProcess mockProcess;
final Map<Type, Generator> startOverrides = <Type, Generator>{
......@@ -110,7 +109,7 @@ void main() {
FileSystem: () => fs,
Cache: () => Cache(rootOverride: fs.directory(flutterRoot)),
ProcessManager: () => mockProcessManager,
KernelCompilerFactory: () => mockKernelCompilerFactory,
KernelCompiler: () => mockKernelCompiler,
Artifacts: () => mockArtifacts,
};
......@@ -136,10 +135,6 @@ void main() {
when(mockArtifacts.getArtifactPath(any)).thenReturn(artifactPath);
mockKernelCompiler = MockKernelCompiler();
mockKernelCompilerFactory = MockKernelCompilerFactory();
when(mockKernelCompilerFactory.create()).thenAnswer((Invocation invocation) async {
return mockKernelCompiler;
});
});
testUsingContext('not debug', () async {
......@@ -199,4 +194,3 @@ Hello!
class MockArtifacts extends Mock implements Artifacts {}
class MockKernelCompiler extends Mock implements KernelCompiler {}
class MockKernelCompilerFactory extends Mock implements KernelCompilerFactory {}
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