33
33
import com .google .devtools .build .lib .actions .RunfilesSupplier ;
34
34
import com .google .devtools .build .lib .actions .Spawn ;
35
35
import com .google .devtools .build .lib .actions .cache .VirtualActionInput ;
36
+ import com .google .devtools .build .lib .collect .nestedset .NestedSet ;
36
37
import com .google .devtools .build .lib .collect .nestedset .NestedSetBuilder ;
37
38
import com .google .devtools .build .lib .collect .nestedset .Order ;
38
39
import com .google .devtools .build .lib .vfs .Path ;
39
40
import com .google .devtools .build .lib .vfs .PathFragment ;
40
41
import java .io .IOException ;
42
+ import java .util .Arrays ;
41
43
import java .util .HashMap ;
42
44
import java .util .List ;
43
45
import java .util .Map ;
@@ -95,7 +97,7 @@ public SpawnInputExpander(
95
97
this .relSymlinkBehavior = relSymlinkBehavior ;
96
98
}
97
99
98
- private void addMapping (
100
+ private static void addMapping (
99
101
Map <PathFragment , ActionInput > inputMappings ,
100
102
PathFragment targetLocation ,
101
103
ActionInput input ,
@@ -215,13 +217,12 @@ void addFilesetManifest(
215
217
}
216
218
}
217
219
218
- private void addInputs (
220
+ private static void addInputs (
219
221
Map <PathFragment , ActionInput > inputMap ,
220
- Spawn spawn ,
222
+ NestedSet <? extends ActionInput > inputFiles ,
221
223
ArtifactExpander artifactExpander ,
222
224
PathFragment baseDirectory ) {
223
- List <ActionInput > inputs =
224
- ActionInputHelper .expandArtifacts (spawn .getInputFiles (), artifactExpander );
225
+ List <ActionInput > inputs = ActionInputHelper .expandArtifacts (inputFiles , artifactExpander );
225
226
for (ActionInput input : inputs ) {
226
227
addMapping (inputMap , input .getExecPath (), input , baseDirectory );
227
228
}
@@ -243,7 +244,7 @@ public SortedMap<PathFragment, ActionInput> getInputMapping(
243
244
MetadataProvider actionInputFileCache )
244
245
throws IOException , ForbiddenActionInputException {
245
246
TreeMap <PathFragment , ActionInput > inputMap = new TreeMap <>();
246
- addInputs (inputMap , spawn , artifactExpander , baseDirectory );
247
+ addInputs (inputMap , spawn . getInputFiles () , artifactExpander , baseDirectory );
247
248
addRunfilesToInputs (
248
249
inputMap ,
249
250
spawn .getRunfilesSupplier (),
@@ -254,6 +255,126 @@ public SortedMap<PathFragment, ActionInput> getInputMapping(
254
255
return inputMap ;
255
256
}
256
257
258
+ /** The interface for accessing part of the input hierarchy. */
259
+ public interface InputWalker {
260
+ SortedMap <PathFragment , ActionInput > getLeavesInputMapping ()
261
+ throws IOException , ForbiddenActionInputException ;
262
+
263
+ void visitNonLeaves (InputVisitor visitor ) throws IOException , ForbiddenActionInputException ;
264
+ }
265
+
266
+ /** The interface for visiting part of the input hierarchy. */
267
+ public interface InputVisitor {
268
+ /**
269
+ * Visits a part of the input hierarchy.
270
+ *
271
+ * <p>{@code nodeKey} can be used as key when memoizing visited parts of the hierarchy.
272
+ */
273
+ void visit (Object nodeKey , InputWalker walker )
274
+ throws IOException , ForbiddenActionInputException ;
275
+ }
276
+
277
+ /**
278
+ * Visits the input files hierarchy in a depth first manner.
279
+ *
280
+ * <p>Similar to {@link #getInputMapping} but allows for early exit, by not visiting children,
281
+ * when walking through the input hierarchy. By applying memoization, the retrieval process of the
282
+ * inputs can be speeded up.
283
+ *
284
+ * <p>{@code baseDirectory} is prepended to every path in the input key. This is useful if the
285
+ * mapping is used in a context where the directory relative to which the keys are interpreted is
286
+ * not the same as the execroot.
287
+ */
288
+ public void walkInputs (
289
+ Spawn spawn ,
290
+ ArtifactExpander artifactExpander ,
291
+ PathFragment baseDirectory ,
292
+ MetadataProvider actionInputFileCache ,
293
+ InputVisitor visitor )
294
+ throws IOException , ForbiddenActionInputException {
295
+ walkNestedSetInputs (baseDirectory , spawn .getInputFiles (), artifactExpander , visitor );
296
+
297
+ RunfilesSupplier runfilesSupplier = spawn .getRunfilesSupplier ();
298
+ visitor .visit (
299
+ // The list of variables affecting the functional expressions below.
300
+ Arrays .asList (
301
+ // Assuming that artifactExpander and actionInputFileCache, different for each spawn,
302
+ // always expand the same way.
303
+ this , // For accessing addRunfilesToInputs.
304
+ runfilesSupplier ,
305
+ baseDirectory ),
306
+ new InputWalker () {
307
+ @ Override
308
+ public SortedMap <PathFragment , ActionInput > getLeavesInputMapping ()
309
+ throws IOException , ForbiddenActionInputException {
310
+ TreeMap <PathFragment , ActionInput > inputMap = new TreeMap <>();
311
+ addRunfilesToInputs (
312
+ inputMap , runfilesSupplier , actionInputFileCache , artifactExpander , baseDirectory );
313
+ return inputMap ;
314
+ }
315
+
316
+ @ Override
317
+ public void visitNonLeaves (InputVisitor childVisitor ) {}
318
+ });
319
+
320
+ Map <Artifact , ImmutableList <FilesetOutputSymlink >> filesetMappings = spawn .getFilesetMappings ();
321
+ // filesetMappings is assumed to be very small, so no need to implement visitNonLeaves() for
322
+ // improved runtime.
323
+ visitor .visit (
324
+ // The list of variables affecting the functional expressions below.
325
+ Arrays .asList (
326
+ this , // For accessing addFilesetManifests.
327
+ filesetMappings ,
328
+ baseDirectory ),
329
+ new InputWalker () {
330
+ @ Override
331
+ public SortedMap <PathFragment , ActionInput > getLeavesInputMapping ()
332
+ throws ForbiddenRelativeSymlinkException {
333
+ TreeMap <PathFragment , ActionInput > inputMap = new TreeMap <>();
334
+ addFilesetManifests (filesetMappings , inputMap , baseDirectory );
335
+ return inputMap ;
336
+ }
337
+
338
+ @ Override
339
+ public void visitNonLeaves (InputVisitor childVisitor ) {}
340
+ });
341
+ }
342
+
343
+ /** Walks through one level of a {@link NestedSet} of {@link ActionInput}s. */
344
+ private void walkNestedSetInputs (
345
+ PathFragment baseDirectory ,
346
+ NestedSet <? extends ActionInput > someInputFiles ,
347
+ ArtifactExpander artifactExpander ,
348
+ InputVisitor visitor )
349
+ throws IOException , ForbiddenActionInputException {
350
+ visitor .visit (
351
+ // addInputs is static so no need to add 'this' as dependent key.
352
+ Arrays .asList (
353
+ // Assuming that artifactExpander, different for each spawn, always expands the same
354
+ // way.
355
+ someInputFiles .toNode (), baseDirectory ),
356
+ new InputWalker () {
357
+ @ Override
358
+ public SortedMap <PathFragment , ActionInput > getLeavesInputMapping () {
359
+ TreeMap <PathFragment , ActionInput > inputMap = new TreeMap <>();
360
+ addInputs (
361
+ inputMap ,
362
+ NestedSetBuilder .wrap (someInputFiles .getOrder (), someInputFiles .getLeaves ()),
363
+ artifactExpander ,
364
+ baseDirectory );
365
+ return inputMap ;
366
+ }
367
+
368
+ @ Override
369
+ public void visitNonLeaves (InputVisitor childVisitor )
370
+ throws IOException , ForbiddenActionInputException {
371
+ for (NestedSet <? extends ActionInput > subInputs : someInputFiles .getNonLeaves ()) {
372
+ walkNestedSetInputs (baseDirectory , subInputs , artifactExpander , childVisitor );
373
+ }
374
+ }
375
+ });
376
+ }
377
+
257
378
/**
258
379
* Exception signaling that an input was not a regular file: most likely a directory. This
259
380
* exception is currently never thrown in practice since we do not enforce "strict" mode.
0 commit comments