@@ -12,6 +12,7 @@ import 'package:build/experiments.dart' as experiments_zone;
12
12
// ignore: implementation_imports
13
13
import 'package:build/src/internal.dart' ;
14
14
import 'package:built_collection/built_collection.dart' ;
15
+ import 'package:built_value/serializer.dart' ;
15
16
import 'package:crypto/crypto.dart' ;
16
17
import 'package:glob/glob.dart' ;
17
18
import 'package:meta/meta.dart' ;
@@ -61,8 +62,34 @@ class AssetGraph implements GeneratedAssetHider {
61
62
final Map <String , Map <PostProcessBuildStepId , Set <AssetId >>>
62
63
_postProcessBuildStepOutputs = {};
63
64
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
+
64
79
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 (
65
90
this .buildPhasesDigest,
91
+ this .inBuildPhasesOptionsDigests,
92
+ this .postBuildActionsOptionsDigests,
66
93
this .dartVersion,
67
94
this .packageLanguageVersions,
68
95
this .enabledExperiments,
@@ -80,21 +107,19 @@ class AssetGraph implements GeneratedAssetHider {
80
107
AssetReader digestReader,
81
108
) async {
82
109
var graph = AssetGraph ._(
83
- buildPhases.digest ,
110
+ buildPhases,
84
111
Platform .version,
85
112
packageGraph.languageVersions,
86
113
experiments_zone.enabledExperiments.build (),
87
114
);
88
115
var placeholders = graph._addPlaceHolderNodes (packageGraph);
89
116
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
+ );
98
123
// Pre-emptively compute digests for the nodes we know have outputs.
99
124
await graph._setLastKnownDigests (
100
125
sources.where ((id) => graph.get (id)! .primaryOutputs.isNotEmpty),
@@ -112,6 +137,10 @@ class AssetGraph implements GeneratedAssetHider {
112
137
Map <String , Map <PostProcessBuildStepId , Set <AssetId >>>
113
138
get allPostProcessBuildStepOutputs => _postProcessBuildStepOutputs;
114
139
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
+
115
144
/// Checks if [id] exists in the graph.
116
145
bool contains (AssetId id) =>
117
146
_nodesByPackage[id.package]? .containsKey (id.path) ?? false ;
@@ -217,36 +246,6 @@ class AssetGraph implements GeneratedAssetHider {
217
246
}
218
247
}
219
248
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
-
250
249
/// Uses [digestReader] to compute the [Digest] for nodes with [ids] and set
251
250
/// the `lastKnownDigest` field.
252
251
Future <void > _setLastKnownDigests (
@@ -333,12 +332,6 @@ class AssetGraph implements GeneratedAssetHider {
333
332
for (final input in node.generatedNodeState! .inputs) {
334
333
result.putIfAbsent (input, () => {}).add (node.id);
335
334
}
336
- result
337
- .putIfAbsent (
338
- node.generatedNodeConfiguration! .builderOptionsId,
339
- () => {},
340
- )
341
- .add (node.id);
342
335
} else if (node.type == NodeType .glob) {
343
336
for (final input in node.globNodeState! .inputs) {
344
337
result.putIfAbsent (input, () => {}).add (node.id);
@@ -496,6 +489,8 @@ class AssetGraph implements GeneratedAssetHider {
496
489
var invalidatedIds = < AssetId > {};
497
490
final computedOutputs = computeOutputs ();
498
491
492
+ // TODO(davidmorgan): it should be possible to track what needs building in
493
+ // the `Build` class instead of this invalidation logic.
499
494
void invalidateNodeAndDeps (AssetId startNodeId) {
500
495
if (! invalidatedIds.add (startNodeId)) return ;
501
496
var nodesToInvalidate = [startNodeId];
@@ -536,6 +531,24 @@ class AssetGraph implements GeneratedAssetHider {
536
531
invalidateNodeAndDeps (changed);
537
532
}
538
533
534
+ // Invalidate nodes that depend on nodes that will be rebuilt due to changed
535
+ // build options.
536
+ final invalidatedPhases = < int > {};
537
+ for (var i = 0 ; i != buildPhases.inBuildPhases.length; i++ ) {
538
+ if (previousInBuildPhasesOptionsDigests! [i] !=
539
+ inBuildPhasesOptionsDigests[i]) {
540
+ invalidatedPhases.add (i);
541
+ }
542
+ }
543
+ for (final node in allNodes) {
544
+ if (node.type == NodeType .generated &&
545
+ invalidatedPhases.contains (
546
+ node.generatedNodeConfiguration! .phaseNumber,
547
+ )) {
548
+ invalidateNodeAndDeps (node.id);
549
+ }
550
+ }
551
+
539
552
// For all new or deleted assets, check if they match any glob nodes and
540
553
// invalidate those.
541
554
for (var id in allNewAndDeletedIds) {
@@ -615,25 +628,22 @@ class AssetGraph implements GeneratedAssetHider {
615
628
}) {
616
629
var allInputs = Set <AssetId >.from (newSources);
617
630
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
- }
631
+ for (
632
+ var phaseNum = 0 ;
633
+ phaseNum < buildPhases.inBuildPhases.length;
634
+ phaseNum++
635
+ ) {
636
+ allInputs.addAll (
637
+ _addInBuildPhaseOutputs (
638
+ buildPhases.inBuildPhases[phaseNum],
639
+ phaseNum,
640
+ allInputs,
641
+ buildPhases,
642
+ rootPackage,
643
+ ),
644
+ );
636
645
}
646
+ _addPostBuildActionApplications (buildPhases.postBuildPhase, allInputs);
637
647
return allInputs;
638
648
}
639
649
@@ -651,8 +661,6 @@ class AssetGraph implements GeneratedAssetHider {
651
661
String rootPackage,
652
662
) {
653
663
var phaseOutputs = < AssetId > {};
654
- var buildOptionsNodeId = builderOptionsIdForAction (phase, phaseNum);
655
- var builderOptionsNode = get (buildOptionsNodeId)! ;
656
664
var inputs =
657
665
allInputs.where ((input) => _actionMatches (phase, input)).toList ();
658
666
for (var input in inputs) {
@@ -667,7 +675,6 @@ class AssetGraph implements GeneratedAssetHider {
667
675
var deleted = _addGeneratedOutputs (
668
676
outputs,
669
677
phaseNum,
670
- builderOptionsNode,
671
678
buildPhases,
672
679
rootPackage,
673
680
primaryInput: input,
@@ -710,15 +717,11 @@ class AssetGraph implements GeneratedAssetHider {
710
717
Set <AssetId > _addGeneratedOutputs (
711
718
Iterable <AssetId > outputs,
712
719
int phaseNumber,
713
- AssetNode builderOptionsNode,
714
720
BuildPhases buildPhases,
715
721
String rootPackage, {
716
722
required AssetId primaryInput,
717
723
required bool isHidden,
718
724
}) {
719
- if (builderOptionsNode.type != NodeType .builderOptions) {
720
- throw ArgumentError ('Expected node of type NodeType.builderOptionsNode' );
721
- }
722
725
var removed = < AssetId > {};
723
726
Map <AssetId , Set <AssetId >>? computedOutputsBeforeRemoves;
724
727
for (var output in outputs) {
@@ -734,9 +737,10 @@ class AssetGraph implements GeneratedAssetHider {
734
737
throw DuplicateAssetNodeException (
735
738
rootPackage,
736
739
existing.id,
737
- (buildPhases[existingConfiguration.phaseNumber] as InBuildPhase )
740
+ buildPhases
741
+ .inBuildPhases[existingConfiguration.phaseNumber]
738
742
.builderLabel,
739
- ( buildPhases[phaseNumber] as InBuildPhase ) .builderLabel,
743
+ buildPhases.inBuildPhases [phaseNumber].builderLabel,
740
744
);
741
745
}
742
746
_removeRecursive (output, removedIds: removed);
@@ -749,7 +753,6 @@ class AssetGraph implements GeneratedAssetHider {
749
753
pendingBuildAction: PendingBuildAction .build,
750
754
wasOutput: false ,
751
755
isFailure: false ,
752
- builderOptionsId: builderOptionsNode.id,
753
756
isHidden: isHidden,
754
757
);
755
758
if (existing != null ) {
@@ -833,22 +836,6 @@ class AssetGraph implements GeneratedAssetHider {
833
836
}
834
837
}
835
838
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
-
852
839
Set <AssetId > placeholderIdsFor (PackageGraph packageGraph) => Set <AssetId >.from (
853
840
packageGraph.allPackages.keys.expand (
854
841
(package) => [
0 commit comments