Skip to content

Commit 27729e4

Browse files
committed
Split out post process builder state.
1 parent e8122b2 commit 27729e4

14 files changed

+481
-543
lines changed

build_runner/test/generate/watch_test.dart

+4
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,10 @@ void main() {
426426
cachedGraph,
427427
equalsAssetGraph(expectedGraph, checkPreviousInputsDigest: false),
428428
);
429+
expect(
430+
cachedGraph.postBuildActionApplications,
431+
expectedGraph.postBuildActionApplications,
432+
);
429433
});
430434

431435
test('ignores events from nested packages', () async {

build_runner/test/server/asset_handler_test.dart

+6-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:build_runner/src/server/server.dart';
1010
import 'package:build_runner_core/build_runner_core.dart';
1111
import 'package:build_runner_core/src/asset_graph/graph.dart';
1212
import 'package:build_runner_core/src/asset_graph/node.dart';
13+
import 'package:build_runner_core/src/asset_graph/post_process_build_step_id.dart';
1314
import 'package:build_runner_core/src/generate/build_phases.dart';
1415
import 'package:build_runner_core/src/generate/options.dart';
1516
import 'package:build_runner_core/src/package_graph/target_graph.dart';
@@ -48,9 +49,11 @@ void main() {
4849
void addAsset(String id, String content, {bool deleted = false}) {
4950
var node = makeAssetNode(id, [], computeDigest(AssetId.parse(id), 'a'));
5051
if (deleted) {
51-
node = node.rebuild(
52-
(b) => b..deletedBy.add(node.id.addExtension('.post_anchor.1')),
53-
);
52+
node = node.rebuild((b) {
53+
b.deletedBy.add(
54+
PostProcessBuildStepId(input: node.id, actionNumber: 1),
55+
);
56+
});
5457
}
5558
graph.add(node);
5659
delegate.testing.writeString(node.id, content);

build_runner/test/server/serve_handler_test.dart

+6-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:build_runner/src/server/server.dart';
1515
import 'package:build_runner_core/build_runner_core.dart';
1616
import 'package:build_runner_core/src/asset_graph/graph.dart';
1717
import 'package:build_runner_core/src/asset_graph/node.dart';
18+
import 'package:build_runner_core/src/asset_graph/post_process_build_step_id.dart';
1819
import 'package:build_runner_core/src/generate/build_phases.dart';
1920
import 'package:build_runner_core/src/generate/options.dart';
2021
import 'package:build_runner_core/src/generate/performance_tracker.dart';
@@ -139,9 +140,11 @@ void main() {
139140
void addSource(String id, String content, {bool deleted = false}) {
140141
var node = makeAssetNode(id, [], computeDigest(AssetId.parse(id), content));
141142
if (deleted) {
142-
node = node.rebuild(
143-
(b) => b..deletedBy.add(node.id.addExtension('.post_anchor.1')),
144-
);
143+
node = node.rebuild((b) {
144+
b.deletedBy.add(
145+
PostProcessBuildStepId(input: node.id, actionNumber: 1),
146+
);
147+
});
145148
}
146149
assetGraph.add(node);
147150
readerWriter.testing.writeString(node.id, content);

build_runner_core/lib/src/asset_graph/graph.dart

+59-25
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import '../generate/phase.dart';
2323
import '../util/constants.dart';
2424
import 'exceptions.dart';
2525
import 'node.dart';
26+
import 'post_process_build_step_id.dart';
2627

2728
part 'serialization.dart';
2829

@@ -46,6 +47,9 @@ class AssetGraph implements GeneratedAssetHider {
4647

4748
final BuiltMap<String, LanguageVersion?> packageLanguageVersions;
4849

50+
final Map<PostProcessBuildStepId, Set<AssetId>> _postProcessBuildStepOutputs =
51+
{};
52+
4953
AssetGraph._(
5054
this.buildPhasesDigest,
5155
this.dartVersion,
@@ -158,6 +162,7 @@ class AssetGraph implements GeneratedAssetHider {
158162
}
159163
}
160164
_nodesByPackage.putIfAbsent(node.id.package, () => {})[node.id.path] = node;
165+
161166
return node;
162167
}
163168

@@ -238,16 +243,21 @@ class AssetGraph implements GeneratedAssetHider {
238243
/// Also removes all edges between all removed nodes and remaining nodes.
239244
///
240245
/// Returns the IDs of removed asset nodes.
241-
Set<AssetId> _removeRecursive(AssetId id, {Set<AssetId>? removedIds}) {
246+
Set<AssetId> _removeRecursive(
247+
AssetId id, {
248+
Set<AssetId>? removedIds,
249+
Map<AssetId, Set<AssetId>>? anchorOutputs,
250+
}) {
242251
removedIds ??= <AssetId>{};
243252
var node = get(id);
244253
if (node == null) return removedIds;
245254
removedIds.add(id);
246-
for (var anchor in node.anchorOutputs.toList()) {
247-
_removeRecursive(anchor, removedIds: removedIds);
248-
}
249255
for (var output in node.primaryOutputs.toList()) {
250-
_removeRecursive(output, removedIds: removedIds);
256+
_removeRecursive(
257+
output,
258+
removedIds: removedIds,
259+
anchorOutputs: anchorOutputs,
260+
);
251261
}
252262
for (var output in node.outputs) {
253263
updateNodeIfPresent(output, (nodeBuilder) {
@@ -290,6 +300,12 @@ class AssetGraph implements GeneratedAssetHider {
290300
if (node.type != NodeType.missingSource) {
291301
_nodesByPackage[id.package]!.remove(id.path);
292302
}
303+
304+
// Remove post build action applications with removed assets as inputs.
305+
_postProcessBuildStepOutputs.removeWhere(
306+
(id, _) => removedIds!.contains(id.input),
307+
);
308+
293309
return removedIds;
294310
}
295311

@@ -301,6 +317,26 @@ class AssetGraph implements GeneratedAssetHider {
301317
Iterable<AssetNode> packageNodes(String package) =>
302318
_nodesByPackage[package]?.values ?? [];
303319

320+
Iterable<PostProcessBuildStepId> postProcessBuildStepIds({
321+
required String package,
322+
}) => _postProcessBuildStepOutputs.keys.where(
323+
(a) => a.input.package == package,
324+
);
325+
326+
void updatePostProcessBuildStep(
327+
PostProcessBuildStepId buildStepId, {
328+
required Set<AssetId> outputs,
329+
}) {
330+
_postProcessBuildStepOutputs[buildStepId] = outputs;
331+
}
332+
333+
Iterable<AssetId> postProcessBuildStepOutputs(PostProcessBuildStepId action) {
334+
return _postProcessBuildStepOutputs[action]!;
335+
}
336+
337+
Map<PostProcessBuildStepId, Set<AssetId>> get postBuildActionApplications =>
338+
_postProcessBuildStepOutputs;
339+
304340
/// All the generated outputs in the graph.
305341
Iterable<AssetId> get outputs =>
306342
allNodes.where((n) => n.type == NodeType.generated).map((n) => n.id);
@@ -547,7 +583,7 @@ class AssetGraph implements GeneratedAssetHider {
547583
),
548584
);
549585
} else if (phase is PostBuildPhase) {
550-
_addPostBuildPhaseAnchors(phase, allInputs);
586+
_addPostBuildActionApplications(phase, allInputs);
551587
} else {
552588
throw StateError('Unrecognized phase type $phase');
553589
}
@@ -600,27 +636,22 @@ class AssetGraph implements GeneratedAssetHider {
600636
return phaseOutputs;
601637
}
602638

603-
/// Adds all [AssetNode.postProcessAnchor]s for [phase] given [allInputs];
604-
///
605-
/// Does not return anything because [AssetNode.postProcessAnchor]s are
606-
/// synthetic and should not be treated as inputs.
607-
void _addPostBuildPhaseAnchors(PostBuildPhase phase, Set<AssetId> allInputs) {
608-
var actionNum = 0;
639+
/// Adds all [PostProcessBuildStepId]s for [phase] given [allInputs];
640+
void _addPostBuildActionApplications(
641+
PostBuildPhase phase,
642+
Set<AssetId> allInputs,
643+
) {
644+
var actionNumber = 0;
609645
for (var action in phase.builderActions) {
610646
var inputs = allInputs.where((input) => _actionMatches(action, input));
611647
for (var input in inputs) {
612-
var buildOptionsNodeId = builderOptionsIdForAction(action, actionNum);
613-
var anchor = AssetNode.postProcessAnchorForInputAndAction(
614-
input,
615-
actionNum,
616-
buildOptionsNodeId,
648+
var application = PostProcessBuildStepId(
649+
input: input,
650+
actionNumber: actionNumber,
617651
);
618-
add(anchor);
619-
updateNode(input, (nodeBuilder) {
620-
nodeBuilder.anchorOutputs.add(anchor.id);
621-
});
652+
_postProcessBuildStepOutputs[application] = {};
622653
}
623-
actionNum++;
654+
actionNumber++;
624655
}
625656
}
626657

@@ -762,11 +793,14 @@ class AssetGraph implements GeneratedAssetHider {
762793
Digest computeBuilderOptionsDigest(BuilderOptions options) =>
763794
md5.convert(utf8.encode(json.encode(options.config)));
764795

765-
AssetId builderOptionsIdForAction(BuildAction action, int actionNum) {
796+
AssetId builderOptionsIdForAction(BuildAction action, int actionNumber) {
766797
if (action is InBuildPhase) {
767-
return AssetId(action.package, 'Phase$actionNum.builderOptions');
798+
return AssetId(action.package, 'Phase$actionNumber.builderOptions');
768799
} else if (action is PostBuildAction) {
769-
return AssetId(action.package, 'PostPhase$actionNum.builderOptions');
800+
return PostProcessBuildStepId.builderOptionsIdFor(
801+
package: action.package,
802+
actionNumber: actionNumber,
803+
);
770804
} else {
771805
throw StateError('Unsupported action type $action');
772806
}

build_runner_core/lib/src/asset_graph/node.dart

+9-69
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'package:built_value/built_value.dart';
1010
import 'package:built_value/serializer.dart';
1111
import 'package:crypto/crypto.dart';
1212

13-
import '../generate/phase.dart';
13+
import 'post_process_build_step_id.dart';
1414

1515
part 'node.g.dart';
1616

@@ -23,7 +23,6 @@ class NodeType extends EnumClass {
2323
static const NodeType glob = _$glob;
2424
static const NodeType internal = _$internal;
2525
static const NodeType placeholder = _$placeholder;
26-
static const NodeType postProcessAnchor = _$postProcessAnchor;
2726
static const NodeType source = _$source;
2827
static const NodeType missingSource = _$missingSource;
2928

@@ -54,10 +53,6 @@ abstract class AssetNode implements Built<AssetNode, AssetNodeBuilder> {
5453
/// [AssetNode.glob].
5554
GlobNodeState? get globNodeState;
5655

57-
/// Additional node configuration for an
58-
/// [AssetNode.postProcessAnchorNodeConfiguration].
59-
PostProcessAnchorNodeConfiguration? get postProcessAnchorNodeConfiguration;
60-
6156
/// The assets that any [Builder] in the build graph declares it may output
6257
/// when run on this asset.
6358
BuiltSet<AssetId> get primaryOutputs;
@@ -66,19 +61,14 @@ abstract class AssetNode implements Built<AssetNode, AssetNodeBuilder> {
6661
/// which reads this asset.
6762
BuiltSet<AssetId> get outputs;
6863

69-
/// The [AssetId]s of all [AssetNode.postProcessAnchor] assets for which this
70-
/// node is the primary input.
71-
BuiltSet<AssetId> get anchorOutputs;
72-
7364
/// The [Digest] for this node in its last known state.
7465
///
7566
/// May be `null` if this asset has no outputs, or if it doesn't actually
7667
/// exist.
7768
Digest? get lastKnownDigest;
7869

79-
/// The IDs of the [AssetNode.postProcessAnchor] for post process builder
80-
/// which requested to delete this asset.
81-
BuiltSet<AssetId> get deletedBy;
70+
/// The `PostProcessBuildStep`s which requested to delete this asset.
71+
BuiltSet<PostProcessBuildStepId> get deletedBy;
8272

8373
/// Whether this asset is a normal, readable file.
8474
///
@@ -223,35 +213,6 @@ abstract class AssetNode implements Built<AssetNode, AssetNodeBuilder> {
223213
static AssetId createGlobNodeId(String package, String glob, int phaseNum) =>
224214
AssetId(package, 'glob.$phaseNum.${base64.encode(utf8.encode(glob))}');
225215

226-
/// A [primaryInput] to a [PostBuildAction].
227-
///
228-
/// The [outputs] of this node are the individual outputs created for the
229-
/// [primaryInput] during the [PostBuildAction] at index [actionNumber].
230-
factory AssetNode.postProcessAnchor(
231-
AssetId id, {
232-
required AssetId primaryInput,
233-
required int actionNumber,
234-
required AssetId builderOptionsId,
235-
Digest? previousInputsDigest,
236-
}) => AssetNode((b) {
237-
b.id = id;
238-
b.type = NodeType.postProcessAnchor;
239-
b.postProcessAnchorNodeConfiguration.actionNumber = actionNumber;
240-
b.postProcessAnchorNodeConfiguration.builderOptionsId = builderOptionsId;
241-
b.postProcessAnchorNodeConfiguration.primaryInput = primaryInput;
242-
});
243-
244-
factory AssetNode.postProcessAnchorForInputAndAction(
245-
AssetId primaryInput,
246-
int actionNumber,
247-
AssetId builderOptionsId,
248-
) => AssetNode.postProcessAnchor(
249-
primaryInput.addExtension('.post_anchor.$actionNumber'),
250-
primaryInput: primaryInput,
251-
actionNumber: actionNumber,
252-
builderOptionsId: builderOptionsId,
253-
);
254-
255216
AssetNode._() {
256217
// Check that configuration and state fields are non-null exactly when the
257218
// node is of the corresponding type.
@@ -277,10 +238,6 @@ abstract class AssetNode implements Built<AssetNode, AssetNodeBuilder> {
277238
globNodeConfiguration != null,
278239
globNodeState != null,
279240
);
280-
check(
281-
type == NodeType.postProcessAnchor,
282-
postProcessAnchorNodeConfiguration != null,
283-
);
284241
}
285242
}
286243

@@ -387,27 +344,6 @@ abstract class GlobNodeState
387344
GlobNodeState._();
388345
}
389346

390-
// Additional configuration for an [AssetNode.postProcessAnchor].
391-
abstract class PostProcessAnchorNodeConfiguration
392-
implements
393-
Built<
394-
PostProcessAnchorNodeConfiguration,
395-
PostProcessAnchorNodeConfigurationBuilder
396-
> {
397-
static Serializer<PostProcessAnchorNodeConfiguration> get serializer =>
398-
_$postProcessAnchorNodeConfigurationSerializer;
399-
400-
int get actionNumber;
401-
AssetId get builderOptionsId;
402-
AssetId get primaryInput;
403-
404-
PostProcessAnchorNodeConfiguration._();
405-
406-
factory PostProcessAnchorNodeConfiguration(
407-
void Function(PostProcessAnchorNodeConfigurationBuilder) updates,
408-
) = _$PostProcessAnchorNodeConfiguration;
409-
}
410-
411347
/// Work that needs doing for a node that tracks its inputs.
412348
class PendingBuildAction extends EnumClass {
413349
static Serializer<PendingBuildAction> get serializer =>
@@ -427,8 +363,8 @@ class PendingBuildAction extends EnumClass {
427363
@SerializersFor([AssetNode])
428364
final Serializers serializers =
429365
(_$serializers.toBuilder()
430-
..add(AssetIdSerializer())
431-
..add(DigestSerializer()))
366+
..add(const AssetIdSerializer())
367+
..add(const DigestSerializer()))
432368
.build();
433369

434370
/// Serializer for [AssetId].
@@ -455,6 +391,8 @@ class AssetIdSerializer implements PrimitiveSerializer<AssetId> {
455391
AssetId object, {
456392
FullType specifiedType = FullType.unspecified,
457393
}) => object.toString();
394+
395+
const AssetIdSerializer();
458396
}
459397

460398
/// Serializer for [Digest].
@@ -478,4 +416,6 @@ class DigestSerializer implements PrimitiveSerializer<Digest> {
478416
Digest object, {
479417
FullType specifiedType = FullType.unspecified,
480418
}) => base64.encode(object.bytes);
419+
420+
const DigestSerializer();
481421
}

0 commit comments

Comments
 (0)