2
2
// for details. All rights reserved. Use of this source code is governed by a
3
3
// BSD-style license that can be found in the LICENSE file.
4
4
5
+ // ignore_for_file: lines_longer_than_80_chars
6
+
5
7
import 'dart:async' ;
6
8
import 'dart:collection' ;
7
9
import 'dart:convert' ;
@@ -72,6 +74,13 @@ class Build {
72
74
int actionsStartedCount = 0 ;
73
75
final pendingActions = SplayTreeMap <int , Set <String >>();
74
76
77
+ /// Glob assets and generated assets that have been processed.
78
+ ///
79
+ /// That means they have been checked to determine whether they
80
+ /// need building; if so, built; and the build state here and in the asset
81
+ /// graph have been updated accordingly.
82
+ final Set <AssetId > processedAssets = {};
83
+
75
84
/// Inputs that changed since the last build.
76
85
///
77
86
/// Filled from the `updates` passed in to the build.
@@ -95,8 +104,6 @@ class Build {
95
104
/// checked against the digest from the previous build.
96
105
final Set <AssetId > changedOutputs = {};
97
106
98
- final Set <AssetId > builtAssets = {};
99
-
100
107
static final debugging = false ;
101
108
102
109
Build ({
@@ -153,17 +160,16 @@ class Build {
153
160
buildPhases,
154
161
);
155
162
if (result.status == BuildStatus .success) {
156
- // ignore_for_file: lines_longer_than_80_chars
157
- if (logFine) {
158
- _logger.fine ('Failed? $builtAssets ' );
163
+ /*if (logFine) {
164
+ _logger.fine('Failed? $processedAssets');
159
165
_logger.fine(
160
- 'Failed?? ${builtAssets .map ((id ) => assetGraph .get (id )!).where ((node ) => node .type == NodeType .generated ).map ((node ) => node .id )}' ,
166
+ 'Failed?? ${processedAssets .map((id) => assetGraph.get(id)!).where((node) => node.type == NodeType.generated).map((node) => node.id)}',
161
167
);
162
168
_logger.fine(
163
- 'Failed??? ${builtAssets .map ((id ) => assetGraph .get (id )!).where ((node ) => node .type == NodeType .generated && node .generatedNodeState !.result == false ).map ((node ) => node .id )}' ,
169
+ 'Failed??? ${processedAssets .map((id) => assetGraph.get(id)!).where((node) => node.type == NodeType.generated && node.generatedNodeState!.result == false).map((node) => node.id)}',
164
170
);
165
- }
166
- final failures = builtAssets
171
+ }*/
172
+ final failures = processedAssets
167
173
.map ((id) => assetGraph.get (id)! )
168
174
.where ((node) => node.type == NodeType .generated)
169
175
.where ((node) => node.generatedNodeState! .result == false )
@@ -192,34 +198,15 @@ class Build {
192
198
if (result.status == BuildStatus .success) {
193
199
_logger.info (
194
200
'Succeeded after ${humanReadable (watch .elapsed )} with '
195
- '${result .outputs .length } outputs, ($actionsCompletedCount actions)\n ' ,
201
+ '${result .outputs .length } outputs '
202
+ '($actionsCompletedCount actions)\n ' ,
196
203
);
197
204
} else {
198
205
_logger.severe ('Failed after ${humanReadable (watch .elapsed )}' );
199
206
}
200
207
return result;
201
208
}
202
209
203
- bool generatedNodeHasWorkToDo (AssetId id) {
204
- if (logFine) {
205
- _logger.fine (
206
- 'work to do $id ? $builtAssets , at ${StackTrace .current .toString ().replaceAll ('\n ' , ' ' )}' ,
207
- );
208
- }
209
- return ! builtAssets.contains (id);
210
- }
211
-
212
- bool generatedNodeIsForcedBuild (AssetId id) {
213
- return deletedAssets.contains (id) ||
214
- newPrimaryInputs.contains (
215
- assetGraph.get (id)! .generatedNodeConfiguration! .primaryInput,
216
- );
217
- }
218
-
219
- bool globNodeHasWorkToDo (AssetId id) {
220
- return ! builtAssets.contains (id);
221
- }
222
-
223
210
Future <void > _updateAssetGraph (Map <AssetId , ChangeType > updates) async {
224
211
await logTimedAsync (_logger, 'Updating asset graph' , () async {
225
212
changedInputs.clear ();
@@ -491,7 +478,7 @@ class Build {
491
478
492
479
Future <void > _buildAsset (AssetId id) async {
493
480
final node = assetGraph.get (id)! ;
494
- if (node.type == NodeType .generated && generatedNodeHasWorkToDo (id)) {
481
+ if (node.type == NodeType .generated && ! processedAssets. contains (id)) {
495
482
final nodeConfiguration = node.generatedNodeConfiguration! ;
496
483
await _runLazyPhaseForInput (
497
484
nodeConfiguration.phaseNumber,
@@ -782,24 +769,25 @@ class Build {
782
769
Iterable <AssetId > outputs,
783
770
AssetReader reader,
784
771
) async {
785
- if (logFine) {
772
+ /* if (logFine) {
786
773
_logger.fine('_buildShouldRun $forInput');
787
- }
774
+ }*/
788
775
789
776
// _logger.fine('_buildShouldRun for $forInput');
790
- assert (
791
- outputs.every (assetGraph.contains),
792
- 'Outputs should be known statically. Missing '
793
- '${outputs .where ((o ) => !assetGraph .contains (o )).toList ()}' ,
794
- );
795
- assert (outputs.isNotEmpty, 'Can\' t run a build with no outputs' );
796
777
797
778
var inputNode = assetGraph.get (forInput)! ;
779
+ if (inputNode.type == NodeType .generated) {
780
+ if (! processedAssets.contains (forInput)) {
781
+ await _buildAsset (forInput);
782
+ }
783
+ }
784
+
798
785
if (deletedAssets.contains (forInput)) {
799
786
if (inputNode.type == NodeType .missingSource) {
800
787
if (logFine) {
801
788
_logger.fine (
802
- 'Skip ${renderer .build (forInput , outputs )} because input was deleted.' ,
789
+ 'Skip ${renderer .build (forInput , outputs )} because $forInput '
790
+ ' was deleted.' ,
803
791
);
804
792
}
805
793
for (final output in outputs) {
@@ -813,16 +801,18 @@ class Build {
813
801
await failureReporter.markSkipped (
814
802
outputs.map ((id) => assetGraph.get (id)! ),
815
803
);
804
+ processedAssets.add (forInput);
816
805
return false ;
817
806
} else if (inputNode.type == NodeType .generated) {
818
807
_logger.fine (
819
- 'Build ${renderer .build (forInput , outputs )} because it is a generated file that was deleted.' ,
808
+ 'Build ${renderer .build (forInput , outputs )} because $forInput is a '
809
+ 'generated file that was deleted.' ,
820
810
);
821
811
}
822
812
}
823
813
824
814
if (inputNode.type == NodeType .generated) {
825
- if (generatedNodeHasWorkToDo (forInput)) {
815
+ if (! processedAssets. contains (forInput)) {
826
816
await _buildAsset (forInput);
827
817
}
828
818
inputNode = assetGraph.get (forInput)! ;
@@ -831,7 +821,8 @@ class Build {
831
821
! inputNode.wasOutput) {
832
822
if (logFine) {
833
823
_logger.fine (
834
- 'Skip ${renderer .build (forInput , outputs )} because input was not written.' ,
824
+ 'Skip ${renderer .build (forInput , outputs )} because $forInput is a '
825
+ ' generated file that was not output.' ,
835
826
);
836
827
}
837
828
for (final output in outputs) {
@@ -845,6 +836,7 @@ class Build {
845
836
await failureReporter.markSkipped (
846
837
outputs.map ((id) => assetGraph.get (id)! ),
847
838
);
839
+ processedAssets.add (forInput);
848
840
return false ;
849
841
}
850
842
@@ -853,14 +845,14 @@ class Build {
853
845
for (final output in outputs) {
854
846
if (logFine) {
855
847
_logger.fine (
856
- 'Skip ${renderer .build (forInput , outputs )} because input failed.' ,
848
+ 'Skip ${renderer .build (forInput , outputs )} because $forInput is '
849
+ 'a generated file that failed.' ,
857
850
);
858
851
}
859
852
assetGraph.updateNode (output, (nodeBuilder) {
860
853
if (nodeBuilder.digest != null ||
861
854
nodeBuilder.generatedNodeState.result != false ) {
862
- _logger.fine ('Changed output due to skip: $output ' );
863
- changedOutputs.add (output);
855
+ //changedOutputs.add(output);
864
856
}
865
857
866
858
// TODO(davidmorgan): deleting the file here may be the fix for
@@ -872,6 +864,7 @@ class Build {
872
864
await failureReporter.markSkipped (
873
865
outputs.map ((id) => assetGraph.get (id)! ),
874
866
);
867
+ processedAssets.add (forInput);
875
868
return false ;
876
869
}
877
870
}
@@ -884,9 +877,7 @@ class Build {
884
877
);
885
878
}
886
879
return true ;
887
- }
888
-
889
- if (assetGraph.previousInBuildPhasesOptionsDigests! [phaseNumber] !=
880
+ } else if (assetGraph.previousInBuildPhasesOptionsDigests! [phaseNumber] !=
890
881
assetGraph.inBuildPhasesOptionsDigests[phaseNumber]) {
891
882
if (logFine) {
892
883
_logger.fine (
@@ -897,71 +888,40 @@ class Build {
897
888
return true ;
898
889
}
899
890
900
- // We check if any output definitely needs an update - its possible during
901
- // manual deletions that only one of the outputs would be marked.
902
- for (var output in outputs.skip (1 )) {
903
- if (generatedNodeIsForcedBuild (output)) {
891
+ if (newPrimaryInputs.contains (forInput)) {
892
+ if (logFine) {
893
+ _logger.fine (
894
+ 'Build ${renderer .build (forInput , outputs )} because $forInput '
895
+ 'was created.' ,
896
+ );
897
+ }
898
+ return true ;
899
+ }
900
+
901
+ for (var output in outputs) {
902
+ if (deletedAssets.contains (output)) {
904
903
if (logFine) {
905
904
_logger.fine (
906
905
'Build ${renderer .build (forInput , outputs )} because '
907
- '${renderer .id (output )} was marked for build .' ,
906
+ '${renderer .id (output )} was deleted .' ,
908
907
);
909
908
}
910
909
return true ;
911
910
}
912
911
}
913
912
914
- // Otherwise, we only check the first output, because all outputs share the
915
- // same inputs and invalidation state.
916
913
var firstNode = assetGraph.get (outputs.first)! ;
917
- assert (
918
- outputs
919
- .skip (1 )
920
- .every (
921
- (output) =>
922
- assetGraph
923
- .get (output)!
924
- .generatedNodeState!
925
- .inputs
926
- .difference (firstNode.generatedNodeState! .inputs)
927
- .isEmpty,
928
- ),
929
- 'All outputs of a build action should share the same inputs.' ,
930
- );
931
-
932
914
final firstNodeState = firstNode.generatedNodeState! ;
933
915
934
- // No need to build an up to date output
935
- if (! generatedNodeHasWorkToDo (firstNode.id)) {
936
- if (logFine) {
937
- _logger.fine (
938
- 'Do not build ${renderer .build (forInput , outputs )} because '
939
- 'it is marked as done.' ,
940
- );
941
- }
942
- return false ;
943
- }
944
-
945
- // Early bail out condition, this is a forced update.
946
- if (generatedNodeIsForcedBuild (firstNode.id)) {
947
- if (logFine) {
948
- _logger.fine (
949
- 'Build ${renderer .build (forInput , outputs )} because '
950
- '${renderer .id (firstNode .id )} was marked for build.' ,
951
- );
952
- }
953
- return true ;
954
- }
955
-
956
- if (firstNodeState.result == null ) {
916
+ /*if (firstNodeState.result == null) {
957
917
if (logFine) {
958
918
_logger.fine(
959
919
'Build ${renderer.build(forInput, outputs)} because '
960
920
'it was skipped.',
961
921
);
962
922
}
963
923
return true;
964
- }
924
+ }*/
965
925
966
926
final inputs = firstNodeState.inputs;
967
927
/*if (logFine) {
@@ -977,7 +937,7 @@ class Build {
977
937
continue ;
978
938
}
979
939
// Check that the input was built, so [changedOutputs] is updated.
980
- if (generatedNodeHasWorkToDo (input)) {
940
+ if (! processedAssets. contains (input)) {
981
941
await _buildAsset (node.id);
982
942
}
983
943
if (changedOutputs.contains (input)) {
@@ -991,7 +951,7 @@ class Build {
991
951
}
992
952
} else if (node.type == NodeType .glob) {
993
953
// Check that the glob was evaluated, so [changedOutputs] is updated.
994
- if (globNodeHasWorkToDo (input)) {
954
+ if (! processedAssets. contains (input)) {
995
955
await _buildGlobNode (input);
996
956
}
997
957
if (changedOutputs.contains (input)) {
@@ -1026,30 +986,20 @@ class Build {
1026
986
}
1027
987
}
1028
988
1029
- // Mark outputs as not needing building.
1030
- /*for (var id in outputs) {
1031
- assetGraph.updateNode(id, (nodeBuilder) {
1032
- if (nodeBuilder.type == NodeType.generated) {
1033
- builtAssets.add(id);
1034
- } else if (nodeBuilder.type == NodeType.glob) {
1035
- builtAssets.add(id);
1036
- }
1037
- });
1038
- }*/
1039
- builtAssets.add (forInput);
1040
-
1041
- _logger.fine (
989
+ /*_logger.fine(
1042
990
'Do not build ${renderer.build(forInput, outputs)} because '
1043
991
'there is no reason to build it.',
1044
- );
992
+ );*/
1045
993
// builtAssets.addAll(outputs);
1046
994
995
+ // add so that the assets are "live" so they are considered as failures
996
+ // Is this sufficient for 'should fail if a severe was logged on a previous
997
+ // build' for a chain of deps?
1047
998
for (final output in outputs) {
1048
- if (! generatedNodeIsForcedBuild (output)) {
1049
- builtAssets.add (output);
1050
- }
999
+ processedAssets.add (output);
1051
1000
}
1052
1001
1002
+ processedAssets.add (forInput);
1053
1003
return false ;
1054
1004
}
1055
1005
@@ -1075,7 +1025,7 @@ class Build {
1075
1025
1076
1026
if (node.type == NodeType .generated) {
1077
1027
// Check that the input was built, so [changedOutputs] is updated.
1078
- if (generatedNodeHasWorkToDo (node.id)) {
1028
+ if (! processedAssets. contains (node.id)) {
1079
1029
await _buildAsset (node.id);
1080
1030
}
1081
1031
if (changedOutputs.contains (input)) {
@@ -1124,7 +1074,7 @@ class Build {
1124
1074
///
1125
1075
///
1126
1076
Future <void > _buildGlobNode (AssetId globId) async {
1127
- if (! globNodeHasWorkToDo (globId)) {
1077
+ if (processedAssets. contains (globId)) {
1128
1078
return ;
1129
1079
}
1130
1080
@@ -1176,7 +1126,7 @@ class Build {
1176
1126
if (nodeBuilder.digest != digest) {
1177
1127
changedOutputs.add (globId);
1178
1128
}
1179
- builtAssets .add (globId);
1129
+ processedAssets .add (globId);
1180
1130
nodeBuilder
1181
1131
..globNodeState.results.replace (results)
1182
1132
..globNodeState.inputs.replace (
@@ -1218,7 +1168,7 @@ class Build {
1218
1168
var wasOutput = readerWriter.assetsWritten.contains (output);
1219
1169
var digest = wasOutput ? await this .readerWriter.digest (output) : null ;
1220
1170
1221
- builtAssets .add (output);
1171
+ processedAssets .add (output);
1222
1172
assetGraph.updateNode (output, (nodeBuilder) {
1223
1173
/*_logger.fine(
1224
1174
'Generated output $output, digest ${nodeBuilder.lastKnownDigest} '
0 commit comments