3434import com .google .devtools .build .lib .concurrent .ThreadSafety ;
3535import com .google .devtools .build .lib .skyframe .AspectKeyCreator .AspectKey ;
3636import com .google .devtools .build .lib .skyframe .ConfiguredTargetKey ;
37+ import com .google .devtools .build .lib .skyframe .TopLevelStatusEvents .TopLevelTargetPendingExecutionEvent ;
3738import com .google .devtools .build .lib .view .test .TestStatus .BlazeTestStatus ;
39+ import com .google .errorprone .annotations .CanIgnoreReturnValue ;
3840import com .google .errorprone .annotations .concurrent .GuardedBy ;
3941import java .util .Collection ;
4042import java .util .concurrent .ConcurrentHashMap ;
@@ -79,8 +81,6 @@ public void buildStarting(BuildStartingEvent event) {
7981 */
8082 @ Subscribe
8183 public void populateTargets (TestFilteringCompleteEvent event ) {
82- int expectedCompletions = aspectCount .get () + 1 ; // + 1 for target itself
83- checkState (expectedCompletions > 0 , "Haven't received BuildStartingEvent" );
8484 ImmutableSet <ConfiguredTarget > testTargets =
8585 event .getTestTargets () != null
8686 ? ImmutableSet .copyOf (event .getTestTargets ())
@@ -92,16 +92,48 @@ public void populateTargets(TestFilteringCompleteEvent event) {
9292 // we'll still get (and ignore) a TestSummary event, but that event isn't published to BEP.
9393 continue ;
9494 }
95- // We want target summaries for alias targets, but note they don't receive test summaries.
96- TargetSummaryAggregator aggregator =
97- new TargetSummaryAggregator (
98- target ,
99- expectedCompletions ,
100- !AliasProvider .isAlias (target ) && testTargets .contains (target ));
101- TargetSummaryAggregator oldAggregator = aggregators .put (asKey (target ), aggregator );
95+ TargetSummaryAggregator oldAggregator =
96+ replaceAggregatorForTarget (/*isTest=*/ testTargets .contains (target ), target );
10297 checkState (
103- oldAggregator == null , "target: %s, values: %s %s" , target , oldAggregator , aggregator );
98+ oldAggregator == null ,
99+ "target: %s, values: %s %s" ,
100+ target ,
101+ oldAggregator ,
102+ aggregators .get (asKey (target )));
103+ }
104+ }
105+
106+ /**
107+ * Populates the aggregator for a particular top level target, including test targets.
108+ *
109+ * <p>Since the event is fired from within a SkyFunction, it is possible to receive duplicate
110+ * events. In case of duplication, simply return without creating any new aggregator.
111+ */
112+ @ Subscribe
113+ @ AllowConcurrentEvents
114+ public void populateTarget (TopLevelTargetPendingExecutionEvent event ) {
115+ replaceAggregatorForTarget (event .isTest (), event .configuredTarget ());
116+ }
117+
118+ /**
119+ * Creates a TargetSummaryAggregator for the given target and stores it in {@link aggregators}
120+ *
121+ * @return the existing aggregator, if any.
122+ */
123+ @ Nullable
124+ @ CanIgnoreReturnValue
125+ private TargetSummaryAggregator replaceAggregatorForTarget (
126+ boolean isTest , ConfiguredTarget target ) {
127+ if (aggregators .containsKey (asKey (target ))) {
128+ return null ;
104129 }
130+ int expectedCompletions = aspectCount .get () + 1 ; // + 1 for target itself
131+ checkState (expectedCompletions > 0 , "Haven't received BuildStartingEvent" );
132+ // We want target summaries for alias targets, but note they don't receive test summaries.
133+ TargetSummaryAggregator aggregator =
134+ new TargetSummaryAggregator (
135+ target , expectedCompletions , isTest && !AliasProvider .isAlias (target ));
136+ return aggregators .put (asKey (target ), aggregator );
105137 }
106138
107139 @ Subscribe
0 commit comments