Skip to content

Commit ab5c986

Browse files
authored
Refactor file outputs to BuildOutputReader. (#4222)
1 parent 310cd82 commit ab5c986

22 files changed

+772
-838
lines changed

build_runner/lib/src/build/build.dart

Lines changed: 42 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import 'package:path/path.dart' as p;
1515
import 'package:watcher/watcher.dart';
1616

1717
import '../bootstrap/build_process_state.dart';
18-
import '../build_plan/build_directory.dart';
1918
import '../build_plan/build_options.dart';
2019
import '../build_plan/build_phases.dart';
2120
import '../build_plan/build_plan.dart';
@@ -24,6 +23,7 @@ import '../build_plan/phase.dart';
2423
import '../build_plan/target_graph.dart';
2524
import '../build_plan/testing_overrides.dart';
2625
import '../constants.dart';
26+
import '../io/build_output_reader.dart';
2727
import '../io/create_merged_dir.dart';
2828
import '../io/reader_writer.dart';
2929
import '../logging/build_log.dart';
@@ -33,12 +33,10 @@ import 'asset_graph/node.dart';
3333
import 'asset_graph/post_process_build_step_id.dart';
3434
import 'build_dirs.dart';
3535
import 'build_result.dart';
36-
import 'finalized_assets_view.dart';
3736
import 'input_tracker.dart';
3837
import 'library_cycle_graph/asset_deps_loader.dart';
3938
import 'library_cycle_graph/library_cycle_graph.dart';
4039
import 'library_cycle_graph/library_cycle_graph_loader.dart';
41-
import 'optional_output_tracker.dart';
4240
import 'performance_tracker.dart';
4341
import 'performance_tracking_resolvers.dart';
4442
import 'resolver/analysis_driver_model.dart';
@@ -110,6 +108,9 @@ class Build {
110108
/// transitive source.
111109
final Map<LibraryCycleGraph, bool> changedGraphs = Map.identity();
112110

111+
/// The build output.
112+
final BuildOutputReader buildOutputReader;
113+
113114
Build({
114115
required this.buildPlan,
115116
required this.readerWriter,
@@ -122,7 +123,12 @@ class Build {
122123
previousDepsLoader =
123124
assetGraph.previousPhasedAssetDeps == null
124125
? null
125-
: AssetDepsLoader.fromDeps(assetGraph.previousPhasedAssetDeps!);
126+
: AssetDepsLoader.fromDeps(assetGraph.previousPhasedAssetDeps!),
127+
buildOutputReader = BuildOutputReader(
128+
buildPlan: buildPlan,
129+
readerWriter: readerWriter,
130+
assetGraph: assetGraph,
131+
);
126132

127133
BuildOptions get buildOptions => buildPlan.buildOptions;
128134
TestingOverrides get testingOverrides => buildPlan.testingOverrides;
@@ -138,13 +144,6 @@ class Build {
138144
(b) => b..rootPackageName = packageGraph.root.name,
139145
);
140146
var result = await _safeBuild(updates);
141-
final optionalOutputTracker = OptionalOutputTracker(
142-
assetGraph,
143-
targetGraph,
144-
BuildDirectory.buildPaths(buildPlan.buildOptions.buildDirs),
145-
buildPlan.buildOptions.buildFilters,
146-
buildPhases,
147-
);
148147
if (result.status == BuildStatus.success) {
149148
final failures = <AssetNode>[];
150149
for (final output in processedOutputs) {
@@ -169,21 +168,31 @@ class Build {
169168
logger.severe(error);
170169
}
171170
}
172-
result = BuildResult(
173-
BuildStatus.failure,
174-
result.outputs,
175-
performance: result.performance,
176-
);
171+
result = result.copyWith(status: BuildStatus.failure);
177172
}
178173
}
179174
readerWriter.cache.flush();
180175
await resourceManager.disposeAll();
181-
result = await _finalizeBuild(
182-
result,
183-
FinalizedAssetsView(assetGraph, packageGraph, optionalOutputTracker),
184-
readerWriter,
185-
buildPlan.buildOptions.buildDirs,
186-
);
176+
177+
// If requested, create output directories. If that fails, fail the build.
178+
if (buildPlan.buildOptions.buildDirs.any(
179+
(target) => target.outputLocation?.path.isNotEmpty ?? false,
180+
) &&
181+
result.status == BuildStatus.success) {
182+
if (!await createMergedOutputDirectories(
183+
packageGraph: packageGraph,
184+
outputSymlinksOnly: buildOptions.outputSymlinksOnly,
185+
buildDirs: buildOptions.buildDirs,
186+
buildOutputReader: buildOutputReader,
187+
readerWriter: readerWriter,
188+
)) {
189+
result = result.copyWith(
190+
status: BuildStatus.failure,
191+
failureType: FailureType.cantCreate,
192+
);
193+
}
194+
}
195+
187196
_resolvers.reset();
188197
buildLog.finishBuild(
189198
result: result.status == BuildStatus.success,
@@ -282,7 +291,13 @@ class Build {
282291
buildLog.error(
283292
buildLog.renderThrowable('Unhandled build failure!', e, st),
284293
);
285-
done.complete(BuildResult(BuildStatus.failure, []));
294+
done.complete(
295+
BuildResult(
296+
status: BuildStatus.failure,
297+
outputs: BuiltList(),
298+
buildOutputReader: buildOutputReader,
299+
),
300+
);
286301
}
287302
},
288303
);
@@ -372,9 +387,10 @@ class Build {
372387
);
373388
// Assume success, `_assetGraph.failedOutputs` will be checked later.
374389
return BuildResult(
375-
BuildStatus.success,
376-
outputs,
390+
status: BuildStatus.success,
391+
outputs: outputs.build(),
377392
performance: performanceTracker,
393+
buildOutputReader: buildOutputReader,
378394
);
379395
});
380396
}
@@ -394,7 +410,7 @@ class Build {
394410
.toList(growable: false)) {
395411
if (!shouldBuildForDirs(
396412
node.id,
397-
buildDirs: BuildDirectory.buildPaths(buildPlan.buildOptions.buildDirs),
413+
buildDirs: buildPlan.buildOptions.buildDirs,
398414
buildFilters: buildPlan.buildOptions.buildFilters,
399415
phase: phase,
400416
targetGraph: targetGraph,
@@ -1211,60 +1227,6 @@ class Build {
12111227
}
12121228

12131229
Future _delete(AssetId id) => readerWriter.delete(id);
1214-
1215-
/// Invoked after each build, can modify the [BuildResult] in any way, even
1216-
/// converting it to a failure.
1217-
///
1218-
/// The [finalizedAssetsView] can only be used until the returned [Future]
1219-
/// completes, it will expire afterwords since it can no longer guarantee a
1220-
/// consistent state.
1221-
///
1222-
/// By default this returns the original result.
1223-
///
1224-
/// Any operation may be performed, as determined by environment.
1225-
Future<BuildResult> _finalizeBuild(
1226-
BuildResult buildResult,
1227-
FinalizedAssetsView finalizedAssetsView,
1228-
ReaderWriter readerWriter,
1229-
BuiltSet<BuildDirectory> buildDirs,
1230-
) async {
1231-
if (testingOverrides.finalizeBuild != null) {
1232-
return testingOverrides.finalizeBuild!(
1233-
buildResult,
1234-
finalizedAssetsView,
1235-
readerWriter,
1236-
buildDirs,
1237-
);
1238-
}
1239-
if (buildDirs.any(
1240-
(target) => target.outputLocation?.path.isNotEmpty ?? false,
1241-
) &&
1242-
buildResult.status == BuildStatus.success) {
1243-
if (!await createMergedOutputDirectories(
1244-
buildDirs,
1245-
packageGraph,
1246-
readerWriter,
1247-
finalizedAssetsView,
1248-
buildOptions.outputSymlinksOnly,
1249-
)) {
1250-
return _convertToFailure(
1251-
buildResult,
1252-
failureType: FailureType.cantCreate,
1253-
);
1254-
}
1255-
}
1256-
return buildResult;
1257-
}
12581230
}
12591231

12601232
String _twoDigits(int n) => '$n'.padLeft(2, '0');
1261-
1262-
BuildResult _convertToFailure(
1263-
BuildResult previous, {
1264-
FailureType? failureType,
1265-
}) => BuildResult(
1266-
BuildStatus.failure,
1267-
previous.outputs,
1268-
performance: previous.performance,
1269-
failureType: failureType,
1270-
);

build_runner/lib/src/build/build_dirs.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:build/build.dart';
66
import 'package:built_collection/built_collection.dart';
77

8+
import '../build_plan/build_directory.dart';
89
import '../build_plan/build_filter.dart';
910
import '../build_plan/phase.dart';
1011
import '../build_plan/target_graph.dart';
@@ -23,18 +24,20 @@ import '../build_plan/target_graph.dart';
2324
/// `id.path` must start with one of the specified directory names.
2425
bool shouldBuildForDirs(
2526
AssetId id, {
26-
required BuiltSet<String> buildDirs,
27+
required BuiltSet<BuildDirectory> buildDirs,
2728
required BuildPhase phase,
2829
required TargetGraph targetGraph,
2930
BuiltSet<BuildFilter>? buildFilters,
3031
}) {
32+
// Empty paths means "build everything".
33+
final paths = BuildDirectory.buildPaths(buildDirs);
3134
buildFilters ??= BuiltSet();
3235
if (buildFilters.isEmpty) {
3336
// Build asset if: It's built to source, it's public or if it's matched by
3437
// a build directory.
3538
return !phase.hideOutput ||
36-
buildDirs.isEmpty ||
37-
buildDirs.any(id.path.startsWith) ||
39+
paths.isEmpty ||
40+
paths.any(id.path.startsWith) ||
3841
targetGraph.isPublicAsset(id);
3942
} else {
4043
// Don't build assets not matched by build filters
@@ -44,8 +47,8 @@ bool shouldBuildForDirs(
4447

4548
// In filtered assets, build the public ones or those inside a build
4649
// directory.
47-
return buildDirs.isEmpty ||
48-
buildDirs.any(id.path.startsWith) ||
50+
return paths.isEmpty ||
51+
paths.any(id.path.startsWith) ||
4952
targetGraph.isPublicAsset(id);
5053
}
5154
}

build_runner/lib/src/build/build_result.dart

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
4-
import 'dart:async';
54

65
import 'package:build/build.dart';
6+
import 'package:built_collection/built_collection.dart';
77
import 'package:meta/meta.dart';
88

9+
import '../io/build_output_reader.dart';
910
import 'performance_tracker.dart';
1011

1112
/// The result of an individual build, this may be an incremental build or
@@ -18,22 +19,36 @@ class BuildResult {
1819
final FailureType? failureType;
1920

2021
/// All outputs created/updated during this build.
21-
final List<AssetId> outputs;
22+
final BuiltList<AssetId> outputs;
2223

23-
/// The [BuildPerformance] broken out by build action, may be `null`.
24+
// The build output.
25+
final BuildOutputReader buildOutputReader;
26+
27+
/// The [BuildPerformance] broken out by build action.
2428
@experimental
2529
final BuildPerformance? performance;
2630

27-
BuildResult(
28-
this.status,
29-
List<AssetId> outputs, {
31+
BuildResult({
32+
required this.status,
33+
BuiltList<AssetId>? outputs,
34+
required this.buildOutputReader,
3035
this.performance,
3136
FailureType? failureType,
32-
}) : outputs = List.unmodifiable(outputs),
33-
failureType =
37+
}) : failureType =
3438
failureType == null && status == BuildStatus.failure
3539
? FailureType.general
36-
: failureType;
40+
: failureType,
41+
outputs = outputs ?? BuiltList();
42+
43+
BuildResult copyWith({BuildStatus? status, FailureType? failureType}) =>
44+
BuildResult(
45+
status: status ?? this.status,
46+
outputs: outputs,
47+
buildOutputReader: buildOutputReader,
48+
performance: performance,
49+
failureType: failureType ?? this.failureType,
50+
);
51+
3752
@override
3853
String toString() {
3954
if (status == BuildStatus.success) {
@@ -50,9 +65,9 @@ Build Failed :(
5065
}
5166

5267
factory BuildResult.buildScriptChanged() => BuildResult(
53-
BuildStatus.failure,
54-
const [],
68+
status: BuildStatus.failure,
5569
failureType: FailureType.buildScriptChanged,
70+
buildOutputReader: BuildOutputReader.empty(),
5671
);
5772
}
5873

@@ -68,8 +83,3 @@ class FailureType {
6883
final int exitCode;
6984
FailureType._(this.exitCode);
7085
}
71-
72-
abstract class BuildState {
73-
Future<BuildResult>? get currentBuild;
74-
Stream<BuildResult> get buildResults;
75-
}

0 commit comments

Comments
 (0)