mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
cleanup use of build runner internals (#40045)
This commit is contained in:
parent
eb7eb3ce3c
commit
477ae6b8ce
@ -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<bool> 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<core.BuildDirectory> buildDirs = <core.BuildDirectory>{
|
||||
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<bool> invalidate({@required List<Uri> inputs}) async {
|
||||
final Status status =
|
||||
logger.startProgress('Recompiling sources...', timeout: null);
|
||||
final Map<AssetId, ChangeType> updates = <AssetId, ChangeType>{};
|
||||
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<core.BuildResult> _runBuilder(core.BuildEnvironment buildEnvironment, BuildOptions buildOptions, BuildMode buildMode, Set<core.BuildDirectory> buildDirs) async {
|
||||
_builder = await BuildImpl.create(
|
||||
buildOptions,
|
||||
buildEnvironment,
|
||||
builders,
|
||||
<String, Map<String, dynamic>>{
|
||||
'flutter_tools:ddc': <String, dynamic>{
|
||||
'flutterWebSdk': artifacts.getArtifactPath(Artifact.flutterWebSdk),
|
||||
},
|
||||
'flutter_tools:entrypoint': <String, dynamic>{
|
||||
'release': buildMode == BuildMode.release,
|
||||
'flutterWebSdk': artifacts.getArtifactPath(Artifact.flutterWebSdk),
|
||||
'profile': buildMode == BuildMode.profile,
|
||||
},
|
||||
'flutter_tools:test_entrypoint': <String, dynamic>{
|
||||
'release': buildMode == BuildMode.release,
|
||||
'profile': buildMode == BuildMode.profile,
|
||||
},
|
||||
},
|
||||
isReleaseBuild: false,
|
||||
);
|
||||
return _builder.run(
|
||||
const <AssetId, ChangeType>{},
|
||||
buildDirs: buildDirs,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _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<void> _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<Directory> childDirectories = rootDirectory
|
||||
.listSync()
|
||||
.whereType<Directory>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<BuildDaemonClient> startBuildDaemon(String workingDirectory, {bool release = false, bool profile = false, bool hasPlugins = false}) async {
|
||||
Future<BuildDaemonClient> 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<BuildDaemonClient> _connectClient(
|
||||
|
||||
@ -69,6 +69,7 @@ Future<int> runTests(
|
||||
final bool result = await webCompilationProxy.initialize(
|
||||
projectDirectory: flutterProject.directory,
|
||||
testOutputDir: tempBuildDir,
|
||||
projectName: flutterProject.manifest.appName,
|
||||
);
|
||||
if (!result) {
|
||||
throwToolExit('Failed to compile tests');
|
||||
|
||||
@ -31,6 +31,7 @@ Future<void> 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<bool> 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<void> invalidate({@required List<Uri> inputs}) async {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user