From 477ae6b8ce31d075bc41c216062b35f9bdc2ea79 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 9 Sep 2019 18:16:03 -0700 Subject: [PATCH] cleanup use of build runner internals (#40045) --- .../web_compilation_delegate.dart | 215 ++++-------------- .../lib/src/build_runner/web_fs.dart | 15 +- .../flutter_tools/lib/src/test/runner.dart | 1 + .../flutter_tools/lib/src/web/compile.dart | 7 +- .../commands/build_web_test.dart | 1 + 5 files changed, 59 insertions(+), 180 deletions(-) diff --git a/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart b/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart index 60d8be39a50..4425a726eb3 100644 --- a/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart +++ b/packages/flutter_tools/lib/src/build_runner/web_compilation_delegate.dart @@ -7,205 +7,74 @@ import 'dart:async'; import 'dart:io' as io; // ignore: dart_io_import import 'package:build/build.dart'; +import 'package:build_daemon/client.dart'; +import 'package:build_daemon/data/build_status.dart'; import 'package:build_runner_core/build_runner_core.dart' as core; -import 'package:build_runner_core/src/asset_graph/graph.dart'; -import 'package:build_runner_core/src/asset_graph/node.dart'; -import 'package:build_runner_core/src/generate/build_impl.dart'; -import 'package:build_runner_core/src/generate/options.dart'; import 'package:glob/glob.dart'; -import 'package:logging/logging.dart'; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as path; -import 'package:watcher/watcher.dart'; -import '../artifacts.dart'; import '../base/file_system.dart'; -import '../base/logger.dart'; -import '../base/platform.dart'; import '../build_info.dart'; -import '../compile.dart'; import '../convert.dart'; -import '../dart/package_map.dart'; -import '../globals.dart'; import '../web/compile.dart'; -import 'build_script.dart'; +import 'web_fs.dart'; /// A build_runner specific implementation of the [WebCompilationProxy]. class BuildRunnerWebCompilationProxy extends WebCompilationProxy { BuildRunnerWebCompilationProxy(); - core.PackageGraph _packageGraph; - BuildImpl _builder; - PackageUriMapper _packageUriMapper; - @override Future initialize({ Directory projectDirectory, String testOutputDir, BuildMode mode, + String projectName }) async { // Create the .dart_tool directory if it doesn't exist. - projectDirectory.childDirectory('.dart_tool').createSync(); - final Directory generatedDirectory = projectDirectory + projectDirectory .childDirectory('.dart_tool') - .childDirectory('build') - .childDirectory('generated'); - - // Override the generated output directory so this does not conflict with - // other build_runner output. - core.overrideGeneratedOutputDirectory('flutter_web'); - _packageUriMapper = PackageUriMapper( - path.absolute('lib/main.dart'), PackageMap.globalPackagesPath, null, null); - _packageGraph = core.PackageGraph.forPath(projectDirectory.path); - - final core.BuildEnvironment buildEnvironment = core.OverrideableEnvironment( - core.IOEnvironment(_packageGraph), onLog: (LogRecord record) { - if (record.level == Level.SEVERE || record.level == Level.SHOUT) { - printError(record.message); - } else { - printTrace(record.message); - } - }, reader: MultirootFileBasedAssetReader(_packageGraph, generatedDirectory)); - final LogSubscription logSubscription = LogSubscription( - buildEnvironment, - verbose: false, - logLevel: Level.FINE, - ); - final BuildOptions buildOptions = await BuildOptions.create( - logSubscription, - packageGraph: _packageGraph, - skipBuildScriptCheck: true, - trackPerformance: false, - deleteFilesByDefault: true, - enableLowResourcesMode: platform.environment['FLUTTER_LOW_RESOURCE_MODE']?.toLowerCase() == 'true', - ); - final Set buildDirs = { - if (testOutputDir != null) - core.BuildDirectory( - 'test', - outputLocation: core.OutputLocation( - testOutputDir, - useSymlinks: !platform.isWindows, - ), - ), - }; - core.BuildResult result; - try { - result = await _runBuilder( - buildEnvironment, - buildOptions, - mode, - buildDirs, - ); - return result.status == core.BuildStatus.success; - } on core.BuildConfigChangedException { - await _cleanAssets(projectDirectory); - result = await _runBuilder( - buildEnvironment, - buildOptions, - mode, - buildDirs, - ); - return result.status == core.BuildStatus.success; - } on core.BuildScriptChangedException { - await _cleanAssets(projectDirectory); - result = await _runBuilder( - buildEnvironment, - buildOptions, - mode, - buildDirs, - ); - return result.status == core.BuildStatus.success; - } - } - - @override - Future invalidate({@required List inputs}) async { - final Status status = - logger.startProgress('Recompiling sources...', timeout: null); - final Map updates = {}; - for (Uri input in inputs) { - final AssetId assetId = AssetId.resolve(_packageUriMapper.map(input.toFilePath()).toString()); - updates[assetId] = ChangeType.MODIFY; - } - core.BuildResult result; - try { - result = await _builder.run(updates); - } finally { - status.cancel(); - } - return result.status == core.BuildStatus.success; - } - - Future _runBuilder(core.BuildEnvironment buildEnvironment, BuildOptions buildOptions, BuildMode buildMode, Set buildDirs) async { - _builder = await BuildImpl.create( - buildOptions, - buildEnvironment, - builders, - >{ - 'flutter_tools:ddc': { - 'flutterWebSdk': artifacts.getArtifactPath(Artifact.flutterWebSdk), - }, - 'flutter_tools:entrypoint': { - 'release': buildMode == BuildMode.release, - 'flutterWebSdk': artifacts.getArtifactPath(Artifact.flutterWebSdk), - 'profile': buildMode == BuildMode.profile, - }, - 'flutter_tools:test_entrypoint': { - 'release': buildMode == BuildMode.release, - 'profile': buildMode == BuildMode.profile, - }, - }, - isReleaseBuild: false, - ); - return _builder.run( - const {}, - buildDirs: buildDirs, - ); - } - - Future _cleanAssets(Directory projectDirectory) async { - final File assetGraphFile = fs.file(core.assetGraphPath); - AssetGraph assetGraph; - try { - assetGraph = AssetGraph.deserialize(await assetGraphFile.readAsBytes()); - } catch (_) { - printTrace('Failed to clean up asset graph.'); - } - final core.PackageGraph packageGraph = core.PackageGraph.forThisPackage(); - await _cleanUpSourceOutputs(assetGraph, packageGraph); - final Directory cacheDirectory = fs.directory(fs.path.join( + .createSync(); + final BuildDaemonClient client = await buildDaemonCreator.startBuildDaemon( projectDirectory.path, - '.dart_tool', - 'build', - 'flutter_web', - )); - if (assetGraphFile.existsSync()) { - assetGraphFile.deleteSync(); + release: mode == BuildMode.release, + profile: mode == BuildMode.profile, + hasPlugins: false, + includeTests: true, + ); + client.startBuild(); + bool success = true; + await for (BuildResults results in client.buildResults) { + final BuildResult result = results.results.firstWhere((BuildResult result) { + return result.target == 'web'; + }); + if (result.status == BuildStatus.failed) { + success = false; + break; + } + if (result.status == BuildStatus.succeeded) { + break; + } } - if (cacheDirectory.existsSync()) { - cacheDirectory.deleteSync(recursive: true); - } - } + if (success && testOutputDir != null) { + final Directory rootDirectory = projectDirectory + .childDirectory('.dart_tool') + .childDirectory('build') + .childDirectory('flutter_web'); - Future _cleanUpSourceOutputs(AssetGraph assetGraph, core.PackageGraph packageGraph) async { - final core.FileBasedAssetWriter writer = core.FileBasedAssetWriter(packageGraph); - if (assetGraph?.outputs == null) { - return; - } - for (AssetId id in assetGraph.outputs) { - if (id.package != packageGraph.root.name) { - continue; - } - final GeneratedAssetNode node = assetGraph.get(id); - if (node.wasOutput) { - // Note that this does a file.exists check in the root package and - // only tries to delete the file if it exists. This way we only - // actually delete to_source outputs, without reading in the build - // actions. - await writer.delete(id); + final Iterable childDirectories = rootDirectory + .listSync() + .whereType(); + for (Directory childDirectory in childDirectories) { + final String path = fs.path.join(testOutputDir, 'packages', + fs.path.basename(childDirectory.path)); + copyDirectorySync(childDirectory.childDirectory('lib'), fs.directory(path)); } + final Directory outputDirectory = rootDirectory + .childDirectory(projectName) + .childDirectory('test'); + copyDirectorySync(outputDirectory, fs.directory(fs.path.join(testOutputDir))); } + return success; } } diff --git a/packages/flutter_tools/lib/src/build_runner/web_fs.dart b/packages/flutter_tools/lib/src/build_runner/web_fs.dart index fa7aa71e908..36c3611bbaa 100644 --- a/packages/flutter_tools/lib/src/build_runner/web_fs.dart +++ b/packages/flutter_tools/lib/src/build_runner/web_fs.dart @@ -336,7 +336,12 @@ class BuildDaemonCreator { static const String _ignoredLine3 = 'have your dependencies specified fully in your pubspec.yaml'; /// Start a build daemon and register the web targets. - Future startBuildDaemon(String workingDirectory, {bool release = false, bool profile = false, bool hasPlugins = false}) async { + Future startBuildDaemon(String workingDirectory, { + bool release = false, + bool profile = false, + bool hasPlugins = false, + bool includeTests = false, + }) async { try { final BuildDaemonClient client = await _connectClient( workingDirectory, @@ -344,7 +349,7 @@ class BuildDaemonCreator { profile: profile, hasPlugins: hasPlugins, ); - _registerBuildTargets(client); + _registerBuildTargets(client, includeTests); return client; } on OptionsSkew { throwToolExit( @@ -357,6 +362,7 @@ class BuildDaemonCreator { void _registerBuildTargets( BuildDaemonClient client, + bool includeTests, ) { final OutputLocation outputLocation = OutputLocation((OutputLocationBuilder b) => b ..output = '' @@ -365,6 +371,11 @@ class BuildDaemonCreator { client.registerBuildTarget(DefaultBuildTarget((DefaultBuildTargetBuilder b) => b ..target = 'web' ..outputLocation = outputLocation?.toBuilder())); + if (includeTests) { + client.registerBuildTarget(DefaultBuildTarget((DefaultBuildTargetBuilder b) => b + ..target = 'test' + ..outputLocation = outputLocation?.toBuilder())); + } } Future _connectClient( diff --git a/packages/flutter_tools/lib/src/test/runner.dart b/packages/flutter_tools/lib/src/test/runner.dart index a230b211910..dc83d9bf779 100644 --- a/packages/flutter_tools/lib/src/test/runner.dart +++ b/packages/flutter_tools/lib/src/test/runner.dart @@ -69,6 +69,7 @@ Future runTests( final bool result = await webCompilationProxy.initialize( projectDirectory: flutterProject.directory, testOutputDir: tempBuildDir, + projectName: flutterProject.manifest.appName, ); if (!result) { throwToolExit('Failed to compile tests'); diff --git a/packages/flutter_tools/lib/src/web/compile.dart b/packages/flutter_tools/lib/src/web/compile.dart index 94bd2aced19..f74985147f1 100644 --- a/packages/flutter_tools/lib/src/web/compile.dart +++ b/packages/flutter_tools/lib/src/web/compile.dart @@ -31,6 +31,7 @@ Future buildWeb(FlutterProject flutterProject, String target, BuildInfo bu result = await webCompilationProxy.initialize( projectDirectory: FlutterProject.current().directory, mode: buildInfo.mode, + projectName: flutterProject.manifest.appName, ); if (result) { // Places assets adjacent to the web stuff. @@ -80,14 +81,10 @@ class WebCompilationProxy { /// the entrypoints for dart2js to later take over. Future initialize({ @required Directory projectDirectory, + @required String projectName, String testOutputDir, BuildMode mode, }) async { throw UnimplementedError(); } - - /// Invalidate the source files in `inputs` and recompile them to JavaScript. - Future invalidate({@required List inputs}) async { - throw UnimplementedError(); - } } diff --git a/packages/flutter_tools/test/general.shard/commands/build_web_test.dart b/packages/flutter_tools/test/general.shard/commands/build_web_test.dart index 6f2341a3af4..dab520ef478 100644 --- a/packages/flutter_tools/test/general.shard/commands/build_web_test.dart +++ b/packages/flutter_tools/test/general.shard/commands/build_web_test.dart @@ -41,6 +41,7 @@ void main() { fs.file(fs.path.join('web', 'index.html')).createSync(recursive: true); fs.file(fs.path.join('lib', 'main.dart')).createSync(recursive: true); when(mockWebCompilationProxy.initialize( + projectName: anyNamed('projectName'), projectDirectory: anyNamed('projectDirectory'), mode: anyNamed('mode') )).thenAnswer((Invocation invocation) {