diff --git a/packages/flutter_tools/lib/src/build_runner/build_runner.dart b/packages/flutter_tools/lib/src/build_runner/build_runner.dart index a550c8f1f9..beba4a5be1 100644 --- a/packages/flutter_tools/lib/src/build_runner/build_runner.dart +++ b/packages/flutter_tools/lib/src/build_runner/build_runner.dart @@ -4,14 +4,13 @@ import 'dart:async'; -import 'package:build_daemon/data/build_status.dart'; -import 'package:build_daemon/data/build_target.dart'; -import 'package:build_runner_core/build_runner_core.dart' hide BuildStatus, OutputLocation; -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:yaml/yaml.dart'; +import 'package:build_daemon/data/build_status.dart'; +import 'package:build_daemon/data/build_status.dart' as build; +import 'package:build_daemon/data/build_target.dart'; +import 'package:build_daemon/data/server_log.dart'; import 'package:crypto/crypto.dart' show md5; +import 'package:yaml/yaml.dart'; import '../artifacts.dart'; import '../base/common.dart'; @@ -24,7 +23,6 @@ import '../codegen.dart'; import '../dart/pub.dart'; import '../globals.dart'; import '../project.dart'; -import 'build_script_generator.dart'; /// The minimum version of build_runner we can support in the flutter tool. const String kMinimumBuildRunnerVersion = '1.6.5'; @@ -42,7 +40,6 @@ class BuildRunner extends CodeGenerator { Future generateBuildScript(FlutterProject flutterProject) async { final Directory entrypointDirectory = fs.directory(fs.path.join(flutterProject.dartTool.path, 'build', 'entrypoint')); final Directory generatedDirectory = fs.directory(fs.path.join(flutterProject.dartTool.path, 'flutter_tool')); - final File buildScript = entrypointDirectory.childFile('build.dart'); final File buildSnapshot = entrypointDirectory.childFile('build.dart.snapshot'); final File scriptIdFile = entrypointDirectory.childFile('id'); final File syntheticPubspec = generatedDirectory.childFile('pubspec.yaml'); @@ -114,9 +111,13 @@ class BuildRunner extends CodeGenerator { scriptIdFile.createSync(recursive: true); } scriptIdFile.writeAsBytesSync(appliedBuilderDigest); - final PackageGraph packageGraph = PackageGraph.forPath(syntheticPubspec.parent.path); - final BuildScriptGenerator buildScriptGenerator = const BuildScriptGeneratorFactory().create(flutterProject, packageGraph); - await buildScriptGenerator.generateBuildScript(); + final ProcessResult generateResult = await processManager.run([ + 'pub', 'run', 'build_runner', 'generate-build-script' + ], workingDirectory: syntheticPubspec.parent.path); + if (generateResult.exitCode != 0) { + throwToolExit('Error generating build_script snapshot: ${generateResult.stderr}'); + } + final File buildScript = fs.file(generateResult.stdout.trim()); final ProcessResult result = await processManager.run([ artifacts.getArtifactPath(Artifact.engineDartBinary), '--snapshot=${buildSnapshot.path}', diff --git a/packages/flutter_tools/lib/src/build_runner/build_script_generator.dart b/packages/flutter_tools/lib/src/build_runner/build_script_generator.dart deleted file mode 100644 index 8b59f9b8ee..0000000000 --- a/packages/flutter_tools/lib/src/build_runner/build_script_generator.dart +++ /dev/null @@ -1,282 +0,0 @@ -// 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 'package:build_runner_core/build_runner_core.dart'; -import 'package:build/build.dart' show BuilderOptions; -import 'package:build_config/build_config.dart'; -import 'package:code_builder/code_builder.dart'; -import 'package:dart_style/dart_style.dart'; -import 'package:graphs/graphs.dart'; - -import '../base/common.dart'; -import '../base/file_system.dart'; -import '../project.dart'; - -class BuildScriptGeneratorFactory { - const BuildScriptGeneratorFactory(); - - /// Creates a [BuildScriptGenerator] for the current flutter project. - BuildScriptGenerator create(FlutterProject flutterProject, PackageGraph packageGraph) { - return BuildScriptGenerator(flutterProject, packageGraph); - } -} - -/// Generates a build_script for the current flutter project. -class BuildScriptGenerator { - const BuildScriptGenerator(this.flutterProject, this.packageGraph); - - final FlutterProject flutterProject; - final PackageGraph packageGraph; - - /// Generate a build script for the curent flutter project. - /// - /// Requires the project to have a pubspec.yaml. - Future generateBuildScript() async { - final Iterable builders = await _findBuilderApplications(); - final Library library = Library((LibraryBuilder libraryBuilder) => libraryBuilder.body.addAll([ - literalList(builders, refer('BuilderApplication', 'package:build_runner_core/build_runner_core.dart')) - .assignFinal('_builders') - .statement, - _createMain(), - ])); - final DartEmitter emitter = DartEmitter(Allocator.simplePrefixing()); - try { - final String location = fs.path.join(flutterProject.dartTool.path, 'build', 'entrypoint', 'build.dart'); - final String result = DartFormatter().format(''' - // ignore_for_file: directives_ordering - ${library.accept(emitter)}'''); - final File output = fs.file(location); - output.createSync(recursive: true); - fs.file(location).writeAsStringSync(result); - } on FormatterException { - throwToolExit('Generated build script could not be parsed. ' - 'This is likely caused by a misconfigured builder definition.'); - } - } - - /// Finds expressions to create all the `BuilderApplication` instances that - /// should be applied packages in the build. - /// - /// Adds `apply` expressions based on the BuildefDefinitions from any package - /// which has a `build.yaml`. - Future> _findBuilderApplications() async { - final List builderApplications = []; - final Iterable orderedPackages = stronglyConnectedComponents( - [packageGraph.root], - (PackageNode node) => node.dependencies, - equals: (PackageNode a, PackageNode b) => a.name == b.name, - hashCode: (PackageNode n) => n.name.hashCode, - ).expand((List nodes) => nodes); - Future _packageBuildConfig(PackageNode package) async { - try { - return await BuildConfig.fromBuildConfigDir(package.name, package.dependencies.map((PackageNode node) => node.name), package.path); - } on ArgumentError catch (_) { - // During the build an error will be logged. - return BuildConfig.useDefault(package.name, package.dependencies.map((PackageNode node) => node.name)); - } - } - - final Iterable orderedConfigs = await Future.wait(orderedPackages.map(_packageBuildConfig)); - final List builderDefinitions = orderedConfigs - .expand((BuildConfig buildConfig) => buildConfig.builderDefinitions.values) - .where((BuilderDefinition builderDefinition) { - if (builderDefinition.import.startsWith('package:')) { - return true; - } - return builderDefinition.package == packageGraph.root.name; - }) - .toList(); - - final List orderedBuilders = _findBuilderOrder(builderDefinitions).toList(); - builderApplications.addAll(orderedBuilders.map(_applyBuilder)); - - final List postProcessBuilderDefinitions = orderedConfigs - .expand((BuildConfig buildConfig) => buildConfig.postProcessBuilderDefinitions.values) - .where((PostProcessBuilderDefinition builderDefinition) { - if (builderDefinition.import.startsWith('package:')) { - return true; - } - return builderDefinition.package == packageGraph.root.name; - }) - .toList(); - builderApplications.addAll(postProcessBuilderDefinitions.map(_applyPostProcessBuilder)); - - return builderApplications; - } - - /// A method forwarding to `run`. - Method _createMain() { - return Method((MethodBuilder b) => b - ..name = 'main' - ..modifier = MethodModifier.async - ..requiredParameters.add(Parameter((ParameterBuilder parameterBuilder) => parameterBuilder - ..name = 'args' - ..type = TypeReference((TypeReferenceBuilder typeReferenceBuilder) => typeReferenceBuilder - ..symbol = 'List' - ..types.add(refer('String'))))) - ..optionalParameters.add(Parameter((ParameterBuilder parameterBuilder) => parameterBuilder - ..name = 'sendPort' - ..type = refer('SendPort', 'dart:isolate'))) - ..body = Block.of([ - refer('run', 'package:build_runner/build_runner.dart') - .call([refer('args'), refer('_builders')]) - .awaited - .assignVar('result') - .statement, - refer('sendPort') - .nullSafeProperty('send') - .call([refer('result')]).statement, - ])); - } - - /// An expression calling `apply` with appropriate setup for a Builder. - Expression _applyBuilder(BuilderDefinition definition) { - final Map namedArgs = {}; - if (definition.isOptional) { - namedArgs['isOptional'] = literalTrue; - } - if (definition.buildTo == BuildTo.cache) { - namedArgs['hideOutput'] = literalTrue; - } else { - namedArgs['hideOutput'] = literalFalse; - } - if (!identical(definition.defaults?.generateFor, InputSet.anything)) { - final Map inputSetArgs = {}; - if (definition.defaults.generateFor.include != null) { - inputSetArgs['include'] = literalConstList(definition.defaults.generateFor.include); - } - if (definition.defaults.generateFor.exclude != null) { - inputSetArgs['exclude'] = literalConstList(definition.defaults.generateFor.exclude); - } - namedArgs['defaultGenerateFor'] = - refer('InputSet', 'package:build_config/build_config.dart') - .constInstance([], inputSetArgs); - } - if (!identical(definition.defaults?.options, BuilderOptions.empty)) { - namedArgs['defaultOptions'] = _constructBuilderOptions(definition.defaults.options); - } - if (!identical(definition.defaults?.devOptions, BuilderOptions.empty)) { - namedArgs['defaultDevOptions'] = _constructBuilderOptions(definition.defaults.devOptions); - } - if (!identical(definition.defaults?.releaseOptions, BuilderOptions.empty)) { - namedArgs['defaultReleaseOptions'] = _constructBuilderOptions(definition.defaults.releaseOptions); - } - if (definition.appliesBuilders.isNotEmpty) { - namedArgs['appliesBuilders'] = literalList(definition.appliesBuilders); - } - final String import = _buildScriptImport(definition.import); - return refer('apply', 'package:build_runner_core/build_runner_core.dart') - .call([ - literalString(definition.key), - literalList( - definition.builderFactories.map((String f) => refer(f, import)).toList()), - _findToExpression(definition), - ], namedArgs); - } - - /// An expression calling `applyPostProcess` with appropriate setup for a - /// PostProcessBuilder. - Expression _applyPostProcessBuilder(PostProcessBuilderDefinition definition) { - final Map namedArgs = {}; - if (definition.defaults?.generateFor != null) { - final Map inputSetArgs = {}; - if (definition.defaults.generateFor.include != null) { - inputSetArgs['include'] = literalConstList(definition.defaults.generateFor.include); - } - if (definition.defaults.generateFor.exclude != null) { - inputSetArgs['exclude'] = literalConstList(definition.defaults.generateFor.exclude); - } - if (!identical(definition.defaults?.options, BuilderOptions.empty)) { - namedArgs['defaultOptions'] = _constructBuilderOptions(definition.defaults.options); - } - if (!identical(definition.defaults?.devOptions, BuilderOptions.empty)) { - namedArgs['defaultDevOptions'] = _constructBuilderOptions(definition.defaults.devOptions); - } - if (!identical(definition.defaults?.releaseOptions, BuilderOptions.empty)) { - namedArgs['defaultReleaseOptions'] = _constructBuilderOptions(definition.defaults.releaseOptions); - } - namedArgs['defaultGenerateFor'] = refer('InputSet', 'package:build_config/build_config.dart').constInstance([], inputSetArgs); - } - final String import = _buildScriptImport(definition.import); - return refer('applyPostProcess', 'package:build_runner_core/build_runner_core.dart') - .call([ - literalString(definition.key), - refer(definition.builderFactory, import), - ], namedArgs); - } - - /// Returns the actual import to put in the generated script based on an import - /// found in the build.yaml. - String _buildScriptImport(String import) { - if (import.startsWith('package:')) { - return import; - } - throwToolExit('non-package import syntax in build.yaml is not supported'); - return null; - } - - Expression _findToExpression(BuilderDefinition definition) { - switch (definition.autoApply) { - case AutoApply.none: - return refer('toNoneByDefault', - 'package:build_runner_core/build_runner_core.dart') - .call([]); - // 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([literalString(definition.package)]); - case AutoApply.allPackages: - return refer('toAllPackages', - 'package:build_runner_core/build_runner_core.dart') - .call([]); - case AutoApply.dependents: - case AutoApply.rootPackage: - return refer('toRoot', 'package:build_runner_core/build_runner_core.dart') - .call([]); - } - throw ArgumentError('Unhandled AutoApply type: ${definition.autoApply}'); - } - - /// An expression creating a [BuilderOptions] from a json string. - Expression _constructBuilderOptions(Map options) { - return refer('BuilderOptions', 'package:build/build.dart').newInstance([literalMap(options)]); - } - - /// Put [builders] into an order such that any builder which specifies - /// [BuilderDefinition.requiredInputs] will come after any builder which - /// produces a desired output. - /// - /// Builders will be ordered such that their `required_inputs` and `runs_before` - /// constraints are met, but the rest of the ordering is arbitrary. - Iterable _findBuilderOrder(Iterable builders) { - Iterable dependencies(BuilderDefinition parent) { - return builders.where((BuilderDefinition child) => _hasInputDependency(parent, child) || _mustRunBefore(parent, child)); - } - final List> components = stronglyConnectedComponents( - builders, - dependencies, - equals: (BuilderDefinition a, BuilderDefinition b) => a.key == b.key, - hashCode: (BuilderDefinition b) => b.key.hashCode, - ); - return components.map((List component) { - if (component.length > 1) { - throw ArgumentError('Required input cycle for ${component.toList()}'); - } - return component.single; - }).toList(); - } - - /// Whether [parent] has a `required_input` that wants to read outputs produced - /// by [child]. - bool _hasInputDependency(BuilderDefinition parent, BuilderDefinition child) { - final Set childOutputs = child.buildExtensions.values.expand((List values) => values).toSet(); - return parent.requiredInputs.any((String input) => childOutputs.any((String output) => output.endsWith(input))); - } - - /// Whether [child] specifies that it wants to run before [parent]. - bool _mustRunBefore(BuilderDefinition parent, BuilderDefinition child) => child.runsBefore.contains(parent.key); -}