3333import  com .google .devtools .build .lib .actions .RunfilesSupplier ;
3434import  com .google .devtools .build .lib .actions .Spawn ;
3535import  com .google .devtools .build .lib .actions .cache .VirtualActionInput ;
36+ import  com .google .devtools .build .lib .collect .nestedset .NestedSet ;
3637import  com .google .devtools .build .lib .collect .nestedset .NestedSetBuilder ;
3738import  com .google .devtools .build .lib .collect .nestedset .Order ;
3839import  com .google .devtools .build .lib .vfs .Path ;
3940import  com .google .devtools .build .lib .vfs .PathFragment ;
4041import  java .io .IOException ;
42+ import  java .util .Arrays ;
4143import  java .util .HashMap ;
4244import  java .util .List ;
4345import  java .util .Map ;
@@ -95,7 +97,7 @@ public SpawnInputExpander(
9597    this .relSymlinkBehavior  = relSymlinkBehavior ;
9698  }
9799
98-   private  void  addMapping (
100+   private  static   void  addMapping (
99101      Map <PathFragment , ActionInput > inputMappings ,
100102      PathFragment  targetLocation ,
101103      ActionInput  input ,
@@ -215,13 +217,12 @@ void addFilesetManifest(
215217      }
216218  }
217219
218-   private  void  addInputs (
220+   private  static   void  addInputs (
219221      Map <PathFragment , ActionInput > inputMap ,
220-       Spawn   spawn ,
222+       NestedSet <?  extends   ActionInput >  inputFiles ,
221223      ArtifactExpander  artifactExpander ,
222224      PathFragment  baseDirectory ) {
223-     List <ActionInput > inputs  =
224-         ActionInputHelper .expandArtifacts (spawn .getInputFiles (), artifactExpander );
225+     List <ActionInput > inputs  = ActionInputHelper .expandArtifacts (inputFiles , artifactExpander );
225226    for  (ActionInput  input  : inputs ) {
226227      addMapping (inputMap , input .getExecPath (), input , baseDirectory );
227228    }
@@ -243,7 +244,7 @@ public SortedMap<PathFragment, ActionInput> getInputMapping(
243244      MetadataProvider  actionInputFileCache )
244245      throws  IOException , ForbiddenActionInputException  {
245246    TreeMap <PathFragment , ActionInput > inputMap  = new  TreeMap <>();
246-     addInputs (inputMap , spawn , artifactExpander , baseDirectory );
247+     addInputs (inputMap , spawn . getInputFiles () , artifactExpander , baseDirectory );
247248    addRunfilesToInputs (
248249        inputMap ,
249250        spawn .getRunfilesSupplier (),
@@ -254,6 +255,126 @@ public SortedMap<PathFragment, ActionInput> getInputMapping(
254255    return  inputMap ;
255256  }
256257
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+ 
257378  /** 
258379   * Exception signaling that an input was not a regular file: most likely a directory. This 
259380   * exception is currently never thrown in practice since we do not enforce "strict" mode. 
0 commit comments