@@ -12,6 +12,7 @@ import 'package:build/experiments.dart' as experiments_zone;
1212// ignore: implementation_imports
1313import 'package:build/src/internal.dart' ;
1414import 'package:built_collection/built_collection.dart' ;
15+ import 'package:built_value/serializer.dart' ;
1516import 'package:crypto/crypto.dart' ;
1617import 'package:glob/glob.dart' ;
1718import '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-
852841Set <AssetId > placeholderIdsFor (PackageGraph packageGraph) => Set <AssetId >.from (
853842 packageGraph.allPackages.keys.expand (
854843 (package) => [
0 commit comments