15
15
*/
16
16
package com .google .idea .blaze .base .command .buildresult .bepparser ;
17
17
18
+ import static com .google .common .base .Preconditions .checkNotNull ;
18
19
import static com .google .common .collect .ImmutableList .toImmutableList ;
19
20
import static com .google .common .collect .ImmutableMap .toImmutableMap ;
20
21
26
27
import com .google .common .collect .ImmutableSetMultimap ;
27
28
import com .google .common .collect .Interner ;
28
29
import com .google .common .collect .Interners ;
30
+ import com .google .common .collect .Maps ;
29
31
import com .google .common .collect .Queues ;
30
32
import com .google .devtools .build .lib .buildeventstream .BuildEventStreamProtos ;
31
33
import com .google .devtools .build .lib .buildeventstream .BuildEventStreamProtos .WorkspaceStatus .Item ;
38
40
import java .util .HashMap ;
39
41
import java .util .HashSet ;
40
42
import java .util .LinkedHashMap ;
41
- import java .util .List ;
42
43
import java .util .Map ;
43
44
import java .util .Objects ;
44
45
import java .util .Queue ;
45
46
import java .util .Set ;
46
47
import java .util .concurrent .Semaphore ;
47
- import java .util .stream .Collectors ;
48
+ import java .util .stream .Stream ;
48
49
import javax .annotation .Nullable ;
49
50
50
51
public final class BepParser {
@@ -63,6 +64,78 @@ public static ParsedBepOutput parseBepArtifacts(BuildEventStreamProvider stream)
63
64
return parseBepArtifacts (stream , null );
64
65
}
65
66
67
+ /**
68
+ * A record of the top level file sets output by the given {@link #outputGroup}, {@link #target} and {@link #config}.
69
+ */
70
+ private record OutputGroupTargetConfigFileSets (String outputGroup , String target , String config , ImmutableList <String > fileSetNames ){}
71
+
72
+ /**
73
+ * A data structure allowing to associate file set names with output group, targets and configs and allowing to retrieve them efficiently
74
+ * at each level of the hierarchy.
75
+ */
76
+ private static class OutputGroupTargetConfigFileSetMap {
77
+ private final Map <String , Map <String , Map <String , ImmutableList <String >>>> data = new LinkedHashMap <>();
78
+
79
+ private Map <String , Map <String , ImmutableList <String >>> getOutputGroup (String outputGroup ) {
80
+ return data .computeIfAbsent (outputGroup , it -> new LinkedHashMap <>());
81
+ }
82
+
83
+ private Map <String , ImmutableList <String >> getOutputGroupTarget (String outputGroup , String target ) {
84
+ return getOutputGroup (outputGroup ).computeIfAbsent (target , it -> new LinkedHashMap <>());
85
+ }
86
+
87
+ private ImmutableList <String > getOutputGroupTargetConfig (String outputGroup , String target , String config ) {
88
+ final var result = getOutputGroupTarget (outputGroup , target ).get (config );
89
+ return result != null ? result : ImmutableList .of ();
90
+ }
91
+
92
+ public void setOutputGroupTargetConfig (String outputGroup , String target , String config , ImmutableList <String > fileSetNames ) {
93
+ final var previous = getOutputGroupTarget (outputGroup , target ).put (config , fileSetNames );
94
+ if (previous != null ){
95
+ throw new IllegalStateException (outputGroup + ":" + target + ":" + config + " already present" );
96
+ }
97
+ }
98
+
99
+ public Stream <OutputGroupTargetConfigFileSets > fileSetStream () {
100
+ return data .entrySet ().stream ().flatMap (
101
+ outputGroup ->
102
+ outputGroup .getValue ().entrySet ().stream ().flatMap (
103
+ target ->
104
+ target .getValue ().entrySet ().stream ().map (
105
+ config ->
106
+ new OutputGroupTargetConfigFileSets (outputGroup .getKey (), target .getKey (),
107
+ config .getKey (), config .getValue ()))));
108
+ }
109
+
110
+ public Stream <OutputGroupTargetConfigFileSets > outputGroupFileSetStream (String outputGroup ) {
111
+ final var outputGroupData = data .get (outputGroup );
112
+ if (outputGroupData == null ) {
113
+ return Stream .empty ();
114
+ }
115
+ return outputGroupData .entrySet ().stream ().flatMap (
116
+ target ->
117
+ target .getValue ().entrySet ().stream ().map (
118
+ config ->
119
+ new OutputGroupTargetConfigFileSets (outputGroup , target .getKey (),
120
+ config .getKey (), config .getValue ())));
121
+ }
122
+
123
+ public Stream <OutputGroupTargetConfigFileSets > outputGroupTargetFileSetStream (String outputGroup , String target ) {
124
+ final var outputGroupData = data .get (outputGroup );
125
+ if (outputGroupData == null ) {
126
+ return Stream .empty ();
127
+ }
128
+ final var outputGroupTargetData = outputGroupData .get (target );
129
+ if (outputGroupTargetData == null ) {
130
+ return Stream .empty ();
131
+ }
132
+ return outputGroupTargetData .entrySet ().stream ().map (
133
+ config ->
134
+ new OutputGroupTargetConfigFileSets (outputGroup , target ,
135
+ config .getKey (), config .getValue ()));
136
+ }
137
+ }
138
+
66
139
/**
67
140
* Parses BEP events into {@link ParsedBepOutput}. String references in {@link BuildEventStreamProtos.NamedSetOfFiles}
68
141
* are interned to conserve memory.
@@ -71,20 +144,17 @@ public static ParsedBepOutput parseBepArtifacts(BuildEventStreamProvider stream)
71
144
* shards running in parallel, so a {@link Interner} is used to share references.
72
145
*/
73
146
public static ParsedBepOutput parseBepArtifacts (
74
- BuildEventStreamProvider stream , @ Nullable Interner <String > interner )
147
+ BuildEventStreamProvider stream , @ Nullable Interner <String > nullableInterner )
75
148
throws BuildEventStreamProvider .BuildEventStreamException {
76
149
final var semaphore = ApplicationManager .getApplication ().getService (BepParserSemaphore .class );
77
150
semaphore .start ();
78
151
try {
79
- if (interner == null ) {
80
- interner = Interners .newStrongInterner ();
81
- }
152
+ final Interner <String > interner = nullableInterner == null ? Interners .newStrongInterner () : nullableInterner ;
82
153
83
154
BuildEventStreamProtos .BuildEvent event ;
84
155
Map <String , String > configIdToMnemonic = new HashMap <>();
85
- Set <String > topLevelFileSets = new HashSet <>();
86
- Map <String , FileSetBuilder > fileSets = new LinkedHashMap <>();
87
- ImmutableSetMultimap .Builder <String , String > targetToFileSets = ImmutableSetMultimap .builder ();
156
+ Map <String , BuildEventStreamProtos .NamedSetOfFiles > fileSets = new LinkedHashMap <>();
157
+ final var data = new OutputGroupTargetConfigFileSetMap ();
88
158
ImmutableSet .Builder <String > targetsWithErrors = ImmutableSet .builder ();
89
159
String localExecRoot = null ;
90
160
String buildId = null ;
@@ -109,10 +179,7 @@ public static ParsedBepOutput parseBepArtifacts(
109
179
continue ;
110
180
case NAMED_SET :
111
181
BuildEventStreamProtos .NamedSetOfFiles namedSet = internNamedSet (event .getNamedSetOfFiles (), interner );
112
- fileSets .compute (
113
- event .getId ().getNamedSet ().getId (),
114
- (k , v ) ->
115
- v != null ? v .setNamedSet (namedSet ) : new FileSetBuilder ().setNamedSet (namedSet ));
182
+ fileSets .put (interner .intern (event .getId ().getNamedSet ().getId ()), namedSet );
116
183
continue ;
117
184
case ACTION_COMPLETED :
118
185
Preconditions .checkState (event .hasAction ());
@@ -124,26 +191,10 @@ public static ParsedBepOutput parseBepArtifacts(
124
191
String label = event .getId ().getTargetCompleted ().getLabel ();
125
192
String configId = event .getId ().getTargetCompleted ().getConfiguration ().getId ();
126
193
127
- event
128
- .getCompleted ()
129
- .getOutputGroupList ()
130
- .forEach (
131
- o -> {
132
- List <String > sets = getFileSets (o );
133
- targetToFileSets .putAll (label , sets );
134
- topLevelFileSets .addAll (sets );
135
- for (String id : sets ) {
136
- fileSets .compute (
137
- id ,
138
- (k , v ) -> {
139
- FileSetBuilder builder = (v != null ) ? v : new FileSetBuilder ();
140
- return builder
141
- .setConfigId (configId )
142
- .addOutputGroups (ImmutableSet .of (o .getName ()))
143
- .addTargets (ImmutableSet .of (label ));
144
- });
145
- }
146
- });
194
+ for (BuildEventStreamProtos .OutputGroup o : event .getCompleted ().getOutputGroupList ()) {
195
+ final var fileSetNames = getFileSets (o , interner );
196
+ data .setOutputGroupTargetConfig (interner .intern (o .getName ()), interner .intern (label ), interner .intern (configId ), fileSetNames );
197
+ }
147
198
continue ;
148
199
case STARTED :
149
200
buildId = Strings .emptyToNull (event .getStarted ().getUuid ());
@@ -162,13 +213,15 @@ public static ParsedBepOutput parseBepArtifacts(
162
213
}
163
214
ImmutableMap <String , ParsedBepOutput .FileSet > filesMap =
164
215
fillInTransitiveFileSetData (
165
- fileSets , topLevelFileSets , configIdToMnemonic , startTimeMillis );
216
+ fileSets , data , configIdToMnemonic , startTimeMillis );
166
217
return new ParsedBepOutput (
167
218
buildId ,
168
219
localExecRoot ,
169
220
workspaceStatus ,
170
221
filesMap ,
171
- targetToFileSets .build (),
222
+ data .fileSetStream ()
223
+ .collect (ImmutableSetMultimap .flatteningToImmutableSetMultimap (OutputGroupTargetConfigFileSets ::target ,
224
+ it -> it .fileSetNames ().stream ())),
172
225
startTimeMillis ,
173
226
buildResult ,
174
227
stream .getBytesConsumed (),
@@ -179,21 +232,34 @@ public static ParsedBepOutput parseBepArtifacts(
179
232
}
180
233
}
181
234
182
- private static List <String > getFileSets (BuildEventStreamProtos .OutputGroup group ) {
235
+ private static ImmutableList <String > getFileSets (BuildEventStreamProtos .OutputGroup group , Interner < String > interner ) {
183
236
return group .getFileSetsList ().stream ()
184
- .map (BuildEventStreamProtos . BuildEventId . NamedSetOfFilesId :: getId )
185
- .collect (Collectors . toList ());
237
+ .map (namedSetOfFilesId -> interner . intern ( namedSetOfFilesId . getId ()) )
238
+ .collect (toImmutableList ());
186
239
}
187
240
188
241
/**
189
242
* Only top-level targets have configuration mnemonic, producing target, and output group data
190
243
* explicitly provided in BEP. This method fills in that data for the transitive closure.
191
244
*/
192
245
private static ImmutableMap <String , ParsedBepOutput .FileSet > fillInTransitiveFileSetData (
193
- Map <String , FileSetBuilder > fileSets ,
194
- Set < String > topLevelFileSets ,
246
+ Map <String , BuildEventStreamProtos . NamedSetOfFiles > namedFileSets ,
247
+ OutputGroupTargetConfigFileSetMap data ,
195
248
Map <String , String > configIdToMnemonic ,
196
249
long startTimeMillis ) {
250
+ Map <String , FileSetBuilder > fileSets =
251
+ ImmutableMap .copyOf (
252
+ Maps .transformValues (namedFileSets , it -> new FileSetBuilder ().setNamedSet (it )));
253
+ Set <String > topLevelFileSets = new HashSet <>();
254
+ data .fileSetStream ().forEach (entry -> {
255
+ entry .fileSetNames ().forEach (fileSetName -> {
256
+ final var fileSet = checkNotNull (fileSets .get (fileSetName ));
257
+ fileSet .setConfigId (entry .config ());
258
+ fileSet .addOutputGroup (entry .outputGroup ());
259
+ fileSet .addTarget (entry .target ());
260
+ topLevelFileSets .add (fileSetName );
261
+ });
262
+ });
197
263
Queue <String > toVisit = Queues .newArrayDeque (topLevelFileSets );
198
264
Set <String > visited = new HashSet <>(topLevelFileSets );
199
265
while (!toVisit .isEmpty ()) {
@@ -244,10 +310,10 @@ private static BuildEventStreamProtos.NamedSetOfFiles internNamedSet(
244
310
.addAllPathPrefix (
245
311
file .getPathPrefixList ().stream ()
246
312
.map (interner ::intern )
247
- .collect (Collectors . toUnmodifiableList ()));
313
+ .collect (toImmutableList ()));
248
314
return builder .build ();
249
315
})
250
- .collect (Collectors . toUnmodifiableList ()))
316
+ .collect (toImmutableList ()))
251
317
.build ();
252
318
}
253
319
@@ -302,14 +368,14 @@ FileSetBuilder setConfigId(String configId) {
302
368
}
303
369
304
370
@ CanIgnoreReturnValue
305
- FileSetBuilder addOutputGroups ( Set < String > outputGroups ) {
306
- this .outputGroups .addAll ( outputGroups );
371
+ FileSetBuilder addOutputGroup ( String outputGroup ) {
372
+ this .outputGroups .add ( outputGroup );
307
373
return this ;
308
374
}
309
375
310
376
@ CanIgnoreReturnValue
311
- FileSetBuilder addTargets ( Set < String > targets ) {
312
- this .targets .addAll ( targets );
377
+ FileSetBuilder addTarget ( String target ) {
378
+ this .targets .add ( target );
313
379
return this ;
314
380
}
315
381
0 commit comments