8787import com .google .devtools .build .lib .remote .RemoteExecutionService .ActionResultMetadata .DirectoryMetadata ;
8888import com .google .devtools .build .lib .remote .RemoteExecutionService .ActionResultMetadata .FileMetadata ;
8989import com .google .devtools .build .lib .remote .RemoteExecutionService .ActionResultMetadata .SymlinkMetadata ;
90+ import com .google .devtools .build .lib .remote .Scrubber .SpawnScrubber ;
9091import com .google .devtools .build .lib .remote .common .BulkTransferException ;
9192import com .google .devtools .build .lib .remote .common .OperationObserver ;
9293import com .google .devtools .build .lib .remote .common .OutputDigestMismatchException ;
@@ -179,6 +180,8 @@ public class RemoteExecutionService {
179180
180181 @ Nullable private final RemoteOutputChecker remoteOutputChecker ;
181182
183+ @ Nullable private final Scrubber scrubber ;
184+
182185 public RemoteExecutionService (
183186 Executor executor ,
184187 Reporter reporter ,
@@ -210,6 +213,7 @@ public RemoteExecutionService(
210213 if (remoteOptions .remoteMerkleTreeCacheSize != 0 ) {
211214 merkleTreeCacheBuilder .maximumSize (remoteOptions .remoteMerkleTreeCacheSize );
212215 }
216+ this .scrubber = remoteOptions .scrubber ;
213217 this .merkleTreeCache = merkleTreeCacheBuilder .build ();
214218
215219 this .tempPathGenerator = tempPathGenerator ;
@@ -219,12 +223,13 @@ public RemoteExecutionService(
219223 this .remoteOutputChecker = remoteOutputChecker ;
220224 }
221225
222- static Command buildCommand (
226+ private Command buildCommand (
223227 Collection <? extends ActionInput > outputs ,
224228 List <String > arguments ,
225229 ImmutableMap <String , String > env ,
226230 @ Nullable Platform platform ,
227- RemotePathResolver remotePathResolver ) {
231+ RemotePathResolver remotePathResolver ,
232+ @ Nullable SpawnScrubber spawnScrubber ) {
228233 Command .Builder command = Command .newBuilder ();
229234 ArrayList <String > outputFiles = new ArrayList <>();
230235 ArrayList <String > outputDirectories = new ArrayList <>();
@@ -249,6 +254,9 @@ static Command buildCommand(
249254 command .setPlatform (platform );
250255 }
251256 for (String arg : arguments ) {
257+ if (spawnScrubber != null ) {
258+ arg = spawnScrubber .transformArgument (arg );
259+ }
252260 command .addArguments (decodeBytestringUtf8 (arg ));
253261 }
254262 // Sorting the environment pairs by variable name.
@@ -349,15 +357,18 @@ private SortedMap<PathFragment, ActionInput> buildOutputDirMap(Spawn spawn) {
349357 }
350358
351359 private MerkleTree buildInputMerkleTree (
352- Spawn spawn , SpawnExecutionContext context , ToolSignature toolSignature )
360+ Spawn spawn ,
361+ SpawnExecutionContext context ,
362+ ToolSignature toolSignature ,
363+ @ Nullable SpawnScrubber spawnScrubber )
353364 throws IOException , ForbiddenActionInputException {
354365 // Add output directories to inputs so that they are created as empty directories by the
355366 // executor. The spec only requires the executor to create the parent directory of an output
356367 // directory, which differs from the behavior of both local and sandboxed execution.
357368 SortedMap <PathFragment , ActionInput > outputDirMap = buildOutputDirMap (spawn );
358369 boolean useMerkleTreeCache = remoteOptions .remoteMerkleTreeCache ;
359- if (toolSignature != null ) {
360- // Marking tool files is not yet supported in conjunction with the merkle tree cache .
370+ if (toolSignature != null || spawnScrubber != null ) {
371+ // The Merkle tree cache is not yet compatible with scrubbing or marking tool files .
361372 useMerkleTreeCache = false ;
362373 }
363374 if (useMerkleTreeCache ) {
@@ -366,18 +377,22 @@ private MerkleTree buildInputMerkleTree(
366377 remotePathResolver .walkInputs (
367378 spawn ,
368379 context ,
369- (Object nodeKey , InputWalker walker ) -> {
370- subMerkleTrees .add (
371- buildMerkleTreeVisitor (
372- nodeKey , walker , inputMetadataProvider , context .getPathResolver ()));
373- });
380+ (Object nodeKey , InputWalker walker ) ->
381+ subMerkleTrees .add (
382+ buildMerkleTreeVisitor (
383+ nodeKey ,
384+ walker ,
385+ inputMetadataProvider ,
386+ context .getPathResolver (),
387+ spawnScrubber )));
374388 if (!outputDirMap .isEmpty ()) {
375389 subMerkleTrees .add (
376390 MerkleTree .build (
377391 outputDirMap ,
378392 inputMetadataProvider ,
379393 execRoot ,
380394 context .getPathResolver (),
395+ /* spawnScrubber= */ null ,
381396 digestUtil ));
382397 }
383398 return MerkleTree .merge (subMerkleTrees , digestUtil );
@@ -399,6 +414,7 @@ private MerkleTree buildInputMerkleTree(
399414 context .getInputMetadataProvider (),
400415 execRoot ,
401416 context .getPathResolver (),
417+ spawnScrubber ,
402418 digestUtil );
403419 }
404420 }
@@ -407,7 +423,8 @@ private MerkleTree buildMerkleTreeVisitor(
407423 Object nodeKey ,
408424 InputWalker walker ,
409425 InputMetadataProvider inputMetadataProvider ,
410- ArtifactPathResolver artifactPathResolver )
426+ ArtifactPathResolver artifactPathResolver ,
427+ @ Nullable SpawnScrubber spawnScrubber )
411428 throws IOException , ForbiddenActionInputException {
412429 // Deduplicate concurrent computations for the same node. It's not possible to use
413430 // MerkleTreeCache#get(key, loader) because the loading computation may cause other nodes to be
@@ -419,7 +436,8 @@ private MerkleTree buildMerkleTreeVisitor(
419436 // No preexisting cache entry, so we must do the computation ourselves.
420437 try {
421438 freshFuture .complete (
422- uncachedBuildMerkleTreeVisitor (walker , inputMetadataProvider , artifactPathResolver ));
439+ uncachedBuildMerkleTreeVisitor (
440+ walker , inputMetadataProvider , artifactPathResolver , spawnScrubber ));
423441 } catch (Exception e ) {
424442 freshFuture .completeExceptionally (e );
425443 }
@@ -443,7 +461,8 @@ private MerkleTree buildMerkleTreeVisitor(
443461 public MerkleTree uncachedBuildMerkleTreeVisitor (
444462 InputWalker walker ,
445463 InputMetadataProvider inputMetadataProvider ,
446- ArtifactPathResolver artifactPathResolver )
464+ ArtifactPathResolver artifactPathResolver ,
465+ @ Nullable SpawnScrubber scrubber )
447466 throws IOException , ForbiddenActionInputException {
448467 ConcurrentLinkedQueue <MerkleTree > subMerkleTrees = new ConcurrentLinkedQueue <>();
449468 subMerkleTrees .add (
@@ -452,18 +471,18 @@ public MerkleTree uncachedBuildMerkleTreeVisitor(
452471 inputMetadataProvider ,
453472 execRoot ,
454473 artifactPathResolver ,
474+ scrubber ,
455475 digestUtil ));
456476 walker .visitNonLeaves (
457- (Object subNodeKey , InputWalker subWalker ) -> {
458- subMerkleTrees .add (
459- buildMerkleTreeVisitor (
460- subNodeKey , subWalker , inputMetadataProvider , artifactPathResolver ));
461- });
477+ (Object subNodeKey , InputWalker subWalker ) ->
478+ subMerkleTrees .add (
479+ buildMerkleTreeVisitor (
480+ subNodeKey , subWalker , inputMetadataProvider , artifactPathResolver , scrubber )));
462481 return MerkleTree .merge (subMerkleTrees , digestUtil );
463482 }
464483
465484 @ Nullable
466- private static ByteString buildSalt (Spawn spawn ) {
485+ private static ByteString buildSalt (Spawn spawn , @ Nullable SpawnScrubber spawnScrubber ) {
467486 CacheSalt .Builder saltBuilder =
468487 CacheSalt .newBuilder ().setMayBeExecutedRemotely (Spawns .mayBeExecutedRemotely (spawn ));
469488
@@ -473,6 +492,11 @@ private static ByteString buildSalt(Spawn spawn) {
473492 saltBuilder .setWorkspace (workspace );
474493 }
475494
495+ if (spawnScrubber != null ) {
496+ saltBuilder .setScrubSalt (
497+ CacheSalt .ScrubSalt .newBuilder ().setSalt (spawnScrubber .getSalt ()).build ());
498+ }
499+
476500 return saltBuilder .build ().toByteString ();
477501 }
478502
@@ -508,7 +532,9 @@ public RemoteAction buildRemoteAction(Spawn spawn, SpawnExecutionContext context
508532 remoteActionBuildingSemaphore .acquire ();
509533 try {
510534 ToolSignature toolSignature = getToolSignature (spawn , context );
511- final MerkleTree merkleTree = buildInputMerkleTree (spawn , context , toolSignature );
535+ SpawnScrubber spawnScrubber = scrubber != null ? scrubber .forSpawn (spawn ) : null ;
536+ final MerkleTree merkleTree =
537+ buildInputMerkleTree (spawn , context , toolSignature , spawnScrubber );
512538
513539 // Get the remote platform properties.
514540 Platform platform ;
@@ -526,7 +552,8 @@ public RemoteAction buildRemoteAction(Spawn spawn, SpawnExecutionContext context
526552 spawn .getArguments (),
527553 spawn .getEnvironment (),
528554 platform ,
529- remotePathResolver );
555+ remotePathResolver ,
556+ spawnScrubber );
530557 Digest commandHash = digestUtil .compute (command );
531558 Action action =
532559 Utils .buildAction (
@@ -535,7 +562,7 @@ public RemoteAction buildRemoteAction(Spawn spawn, SpawnExecutionContext context
535562 platform ,
536563 context .getTimeout (),
537564 Spawns .mayBeCachedRemotely (spawn ),
538- buildSalt (spawn ));
565+ buildSalt (spawn , spawnScrubber ));
539566
540567 ActionKey actionKey = digestUtil .computeActionKey (action );
541568
@@ -1414,7 +1441,8 @@ public void uploadInputsIfNotPresent(RemoteAction action, boolean force)
14141441 Spawn spawn = action .getSpawn ();
14151442 SpawnExecutionContext context = action .getSpawnExecutionContext ();
14161443 ToolSignature toolSignature = getToolSignature (spawn , context );
1417- merkleTree = buildInputMerkleTree (spawn , context , toolSignature );
1444+ SpawnScrubber spawnScrubber = scrubber != null ? scrubber .forSpawn (spawn ) : null ;
1445+ merkleTree = buildInputMerkleTree (spawn , context , toolSignature , spawnScrubber );
14181446 }
14191447
14201448 remoteExecutionCache .ensureInputsPresent (
0 commit comments