Skip to content

Commit c041360

Browse files
committed
Remove builder options nodes; store and check builder options by phase.
1 parent 79d87ec commit c041360

24 files changed

+308
-404
lines changed

build_runner/test/generate/watch_test.dart

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ void main() {
2626
final copyABuildApplication = applyToRoot(
2727
TestBuilder(buildExtensions: appendExtension('.copy', from: '.txt')),
2828
);
29-
final defaultBuilderOptions = const BuilderOptions({});
3029
final packageConfigId = makeAssetId('a|.dart_tool/package_config.json');
3130
final packageGraph = buildPackageGraph({
3231
rootPackage('a', path: path.absolute('a')): [],
@@ -362,12 +361,6 @@ void main() {
362361
readerWriter,
363362
);
364363

365-
var builderOptionsId = makeAssetId('a|Phase0.builderOptions');
366-
var builderOptionsNode = AssetNode.builderOptions(
367-
builderOptionsId,
368-
lastKnownDigest: computeBuilderOptionsDigest(defaultBuilderOptions),
369-
);
370-
371364
var bCopyId = makeAssetId('a|web/b.txt.copy');
372365
var bTxtId = makeAssetId('a|web/b.txt');
373366
var bCopyNode = AssetNode.generated(
@@ -377,7 +370,6 @@ void main() {
377370
pendingBuildAction: PendingBuildAction.none,
378371
wasOutput: true,
379372
isFailure: false,
380-
builderOptionsId: builderOptionsId,
381373
lastKnownDigest: computeDigest(bCopyId, 'b2'),
382374
inputs: [makeAssetId('a|web/b.txt')],
383375
isHidden: false,
@@ -399,7 +391,6 @@ void main() {
399391
pendingBuildAction: PendingBuildAction.none,
400392
wasOutput: true,
401393
isFailure: false,
402-
builderOptionsId: builderOptionsId,
403394
lastKnownDigest: computeDigest(cCopyId, 'c'),
404395
inputs: [makeAssetId('a|web/c.txt')],
405396
isHidden: false,
@@ -412,8 +403,6 @@ void main() {
412403
], computeDigest(cTxtId, 'c')),
413404
);
414405

415-
expectedGraph.add(builderOptionsNode);
416-
417406
// TODO: We dont have a shared way of computing the combined input
418407
// hashes today, but eventually we should test those here too.
419408
expect(

build_runner/test/server/asset_handler_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ void main() {
136136
graph.add(
137137
AssetNode.generated(
138138
AssetId('a', 'web/main.ddc.js'),
139-
builderOptionsId: AssetId('_\$fake', 'options_id'),
140139
phaseNumber: 0,
141140
pendingBuildAction: PendingBuildAction.none,
142141
isHidden: false,

build_runner/test/server/serve_handler_test.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,6 @@ void main() {
209209
assetGraph.add(
210210
AssetNode.generated(
211211
AssetId('a', 'web/main.ddc.js'),
212-
builderOptionsId: AssetId('_\$fake', 'options_id'),
213212
phaseNumber: 0,
214213
pendingBuildAction: PendingBuildAction.none,
215214
isHidden: false,

build_runner_core/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
- Track post process builder outputs separately from the main graph Instead of
3131
in `postProcessAnchor` nodes.
3232
- Compute outputs as needed instead of storing them in the asset graph.
33+
- Check build options for changes in the phase setup instead of storing them
34+
in the asset graph.
3335

3436
## 8.0.0
3537

build_runner_core/lib/src/asset_graph/graph.dart

Lines changed: 78 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:build/experiments.dart' as experiments_zone;
1212
// ignore: implementation_imports
1313
import 'package:build/src/internal.dart';
1414
import 'package:built_collection/built_collection.dart';
15+
import 'package:built_value/serializer.dart';
1516
import 'package:crypto/crypto.dart';
1617
import 'package:glob/glob.dart';
1718
import 'package:meta/meta.dart';
@@ -61,8 +62,34 @@ class AssetGraph implements GeneratedAssetHider {
6162
final Map<String, Map<PostProcessBuildStepId, Set<AssetId>>>
6263
_postProcessBuildStepOutputs = {};
6364

65+
/// Digests from the previous build's [BuildPhases], or `null` if this is a
66+
/// clean build.
67+
BuiltList<Digest>? previousInBuildPhasesOptionsDigests;
68+
69+
/// Digests from the current build's [BuildPhases].
70+
BuiltList<Digest> inBuildPhasesOptionsDigests;
71+
72+
/// Digests from the previous build's [BuildPhases], or `null` if this is a
73+
/// clean build.
74+
BuiltList<Digest>? previousPostBuildOptionsDigests;
75+
76+
/// Digests from the current build's [BuildPhases].
77+
BuiltList<Digest> postBuildActionsOptionsDigests;
78+
6479
AssetGraph._(
80+
BuildPhases buildPhases,
81+
this.dartVersion,
82+
this.packageLanguageVersions,
83+
this.enabledExperiments,
84+
) : buildPhasesDigest = buildPhases.digest,
85+
inBuildPhasesOptionsDigests = buildPhases.inBuildPhasesOptionsDigests,
86+
postBuildActionsOptionsDigests =
87+
buildPhases.postBuildActionsOptionsDigests;
88+
89+
AssetGraph._fromSerialized(
6590
this.buildPhasesDigest,
91+
this.inBuildPhasesOptionsDigests,
92+
this.postBuildActionsOptionsDigests,
6693
this.dartVersion,
6794
this.packageLanguageVersions,
6895
this.enabledExperiments,
@@ -80,21 +107,19 @@ class AssetGraph implements GeneratedAssetHider {
80107
AssetReader digestReader,
81108
) async {
82109
var graph = AssetGraph._(
83-
buildPhases.digest,
110+
buildPhases,
84111
Platform.version,
85112
packageGraph.languageVersions,
86113
experiments_zone.enabledExperiments.build(),
87114
);
88115
var placeholders = graph._addPlaceHolderNodes(packageGraph);
89116
graph._addSources(sources);
90-
graph
91-
.._addBuilderOptionsNodes(buildPhases)
92-
.._addOutputsForSources(
93-
buildPhases,
94-
sources,
95-
packageGraph.root.name,
96-
placeholders: placeholders,
97-
);
117+
graph._addOutputsForSources(
118+
buildPhases,
119+
sources,
120+
packageGraph.root.name,
121+
placeholders: placeholders,
122+
);
98123
// Pre-emptively compute digests for the nodes we know have outputs.
99124
await graph._setLastKnownDigests(
100125
sources.where((id) => graph.get(id)!.primaryOutputs.isNotEmpty),
@@ -112,6 +137,10 @@ class AssetGraph implements GeneratedAssetHider {
112137
Map<String, Map<PostProcessBuildStepId, Set<AssetId>>>
113138
get allPostProcessBuildStepOutputs => _postProcessBuildStepOutputs;
114139

140+
/// Whether this is a clean build, meaning there was no previous build state
141+
/// loaded or it was discarded as incompatible.
142+
bool get cleanBuild => previousInBuildPhasesOptionsDigests == null;
143+
115144
/// Checks if [id] exists in the graph.
116145
bool contains(AssetId id) =>
117146
_nodesByPackage[id.package]?.containsKey(id.path) ?? false;
@@ -217,36 +246,6 @@ class AssetGraph implements GeneratedAssetHider {
217246
}
218247
}
219248

220-
/// Adds [AssetNode.builderOptions] for all [buildPhases] to this graph.
221-
void _addBuilderOptionsNodes(BuildPhases buildPhases) {
222-
for (var phaseNum = 0; phaseNum < buildPhases.length; phaseNum++) {
223-
var phase = buildPhases[phaseNum];
224-
if (phase is InBuildPhase) {
225-
add(
226-
AssetNode.builderOptions(
227-
builderOptionsIdForAction(phase, phaseNum),
228-
lastKnownDigest: computeBuilderOptionsDigest(phase.builderOptions),
229-
),
230-
);
231-
} else if (phase is PostBuildPhase) {
232-
var actionNum = 0;
233-
for (var builderAction in phase.builderActions) {
234-
add(
235-
AssetNode.builderOptions(
236-
builderOptionsIdForAction(builderAction, actionNum),
237-
lastKnownDigest: computeBuilderOptionsDigest(
238-
builderAction.builderOptions,
239-
),
240-
),
241-
);
242-
actionNum++;
243-
}
244-
} else {
245-
throw StateError('Invalid action type $phase');
246-
}
247-
}
248-
}
249-
250249
/// Uses [digestReader] to compute the [Digest] for nodes with [ids] and set
251250
/// the `lastKnownDigest` field.
252251
Future<void> _setLastKnownDigests(
@@ -333,12 +332,6 @@ class AssetGraph implements GeneratedAssetHider {
333332
for (final input in node.generatedNodeState!.inputs) {
334333
result.putIfAbsent(input, () => {}).add(node.id);
335334
}
336-
result
337-
.putIfAbsent(
338-
node.generatedNodeConfiguration!.builderOptionsId,
339-
() => {},
340-
)
341-
.add(node.id);
342335
} else if (node.type == NodeType.glob) {
343336
for (final input in node.globNodeState!.inputs) {
344337
result.putIfAbsent(input, () => {}).add(node.id);
@@ -496,6 +489,8 @@ class AssetGraph implements GeneratedAssetHider {
496489
var invalidatedIds = <AssetId>{};
497490
final computedOutputs = computeOutputs();
498491

492+
// TODO(davidmorgan): it should be possible to track what needs building in
493+
// the `Build` class instead of this invalidation logic.
499494
void invalidateNodeAndDeps(AssetId startNodeId) {
500495
if (!invalidatedIds.add(startNodeId)) return;
501496
var nodesToInvalidate = [startNodeId];
@@ -536,6 +531,26 @@ class AssetGraph implements GeneratedAssetHider {
536531
invalidateNodeAndDeps(changed);
537532
}
538533

534+
// Invalidate nodes that depend on nodes that will be rebuilt due to changed
535+
// build options.
536+
if (previousInBuildPhasesOptionsDigests != null) {
537+
final invalidatedPhases = <int>{};
538+
for (var i = 0; i != buildPhases.inBuildPhases.length; i++) {
539+
if (previousInBuildPhasesOptionsDigests![i] !=
540+
inBuildPhasesOptionsDigests[i]) {
541+
invalidatedPhases.add(i);
542+
}
543+
}
544+
for (final node in allNodes) {
545+
if (node.type == NodeType.generated &&
546+
invalidatedPhases.contains(
547+
node.generatedNodeConfiguration!.phaseNumber,
548+
)) {
549+
invalidateNodeAndDeps(node.id);
550+
}
551+
}
552+
}
553+
539554
// For all new or deleted assets, check if they match any glob nodes and
540555
// invalidate those.
541556
for (var id in allNewAndDeletedIds) {
@@ -615,25 +630,22 @@ class AssetGraph implements GeneratedAssetHider {
615630
}) {
616631
var allInputs = Set<AssetId>.from(newSources);
617632
if (placeholders != null) allInputs.addAll(placeholders);
618-
619-
for (var phaseNum = 0; phaseNum < buildPhases.length; phaseNum++) {
620-
var phase = buildPhases[phaseNum];
621-
if (phase is InBuildPhase) {
622-
allInputs.addAll(
623-
_addInBuildPhaseOutputs(
624-
phase,
625-
phaseNum,
626-
allInputs,
627-
buildPhases,
628-
rootPackage,
629-
),
630-
);
631-
} else if (phase is PostBuildPhase) {
632-
_addPostBuildActionApplications(phase, allInputs);
633-
} else {
634-
throw StateError('Unrecognized phase type $phase');
635-
}
633+
for (
634+
var phaseNum = 0;
635+
phaseNum < buildPhases.inBuildPhases.length;
636+
phaseNum++
637+
) {
638+
allInputs.addAll(
639+
_addInBuildPhaseOutputs(
640+
buildPhases.inBuildPhases[phaseNum],
641+
phaseNum,
642+
allInputs,
643+
buildPhases,
644+
rootPackage,
645+
),
646+
);
636647
}
648+
_addPostBuildActionApplications(buildPhases.postBuildPhase, allInputs);
637649
return allInputs;
638650
}
639651

@@ -651,8 +663,6 @@ class AssetGraph implements GeneratedAssetHider {
651663
String rootPackage,
652664
) {
653665
var phaseOutputs = <AssetId>{};
654-
var buildOptionsNodeId = builderOptionsIdForAction(phase, phaseNum);
655-
var builderOptionsNode = get(buildOptionsNodeId)!;
656666
var inputs =
657667
allInputs.where((input) => _actionMatches(phase, input)).toList();
658668
for (var input in inputs) {
@@ -667,7 +677,6 @@ class AssetGraph implements GeneratedAssetHider {
667677
var deleted = _addGeneratedOutputs(
668678
outputs,
669679
phaseNum,
670-
builderOptionsNode,
671680
buildPhases,
672681
rootPackage,
673682
primaryInput: input,
@@ -710,15 +719,11 @@ class AssetGraph implements GeneratedAssetHider {
710719
Set<AssetId> _addGeneratedOutputs(
711720
Iterable<AssetId> outputs,
712721
int phaseNumber,
713-
AssetNode builderOptionsNode,
714722
BuildPhases buildPhases,
715723
String rootPackage, {
716724
required AssetId primaryInput,
717725
required bool isHidden,
718726
}) {
719-
if (builderOptionsNode.type != NodeType.builderOptions) {
720-
throw ArgumentError('Expected node of type NodeType.builderOptionsNode');
721-
}
722727
var removed = <AssetId>{};
723728
Map<AssetId, Set<AssetId>>? computedOutputsBeforeRemoves;
724729
for (var output in outputs) {
@@ -734,9 +739,10 @@ class AssetGraph implements GeneratedAssetHider {
734739
throw DuplicateAssetNodeException(
735740
rootPackage,
736741
existing.id,
737-
(buildPhases[existingConfiguration.phaseNumber] as InBuildPhase)
742+
buildPhases
743+
.inBuildPhases[existingConfiguration.phaseNumber]
738744
.builderLabel,
739-
(buildPhases[phaseNumber] as InBuildPhase).builderLabel,
745+
buildPhases.inBuildPhases[phaseNumber].builderLabel,
740746
);
741747
}
742748
_removeRecursive(output, removedIds: removed);
@@ -749,7 +755,6 @@ class AssetGraph implements GeneratedAssetHider {
749755
pendingBuildAction: PendingBuildAction.build,
750756
wasOutput: false,
751757
isFailure: false,
752-
builderOptionsId: builderOptionsNode.id,
753758
isHidden: isHidden,
754759
);
755760
if (existing != null) {
@@ -833,22 +838,6 @@ class AssetGraph implements GeneratedAssetHider {
833838
}
834839
}
835840

836-
Digest computeBuilderOptionsDigest(BuilderOptions options) =>
837-
md5.convert(utf8.encode(json.encode(options.config)));
838-
839-
AssetId builderOptionsIdForAction(BuildAction action, int actionNumber) {
840-
if (action is InBuildPhase) {
841-
return AssetId(action.package, 'Phase$actionNumber.builderOptions');
842-
} else if (action is PostBuildAction) {
843-
return PostProcessBuildStepId.builderOptionsIdFor(
844-
package: action.package,
845-
actionNumber: actionNumber,
846-
);
847-
} else {
848-
throw StateError('Unsupported action type $action');
849-
}
850-
}
851-
852841
Set<AssetId> placeholderIdsFor(PackageGraph packageGraph) => Set<AssetId>.from(
853842
packageGraph.allPackages.keys.expand(
854843
(package) => [

build_runner_core/lib/src/asset_graph/graph_loader.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,18 @@ class AssetGraphLoader {
133133
}
134134
return null;
135135
}
136+
137+
// Move old build phases digests to "previous" fields, set the new ones.
138+
// These are used to check for phases to fully rerun due to changed options.
139+
cachedGraph.previousInBuildPhasesOptionsDigests =
140+
cachedGraph.inBuildPhasesOptionsDigests;
141+
cachedGraph.inBuildPhasesOptionsDigests =
142+
buildPhases.inBuildPhasesOptionsDigests;
143+
cachedGraph.previousPostBuildOptionsDigests =
144+
cachedGraph.postBuildActionsOptionsDigests;
145+
cachedGraph.postBuildActionsOptionsDigests =
146+
buildPhases.postBuildActionsOptionsDigests;
147+
136148
return cachedGraph;
137149
}
138150

0 commit comments

Comments
 (0)