sandbox: Use the SpawnInputExpander everywhere and delete SpawnHelpers.
This unifies our code to use just one standard implementation to get the
entire expanded input files for a Spawn, including from Filesets and
Runfiles.
Change-Id: I1e286508adf0a9aeddf70934b010e6fcc144c4a7
PiperOrigin-RevId: 155497273
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
index 364ab38..37f2ce8 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxHelpers.java
@@ -18,14 +18,23 @@
import com.google.common.collect.ImmutableSet.Builder;
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionInput;
+import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.Executor;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.buildtool.BuildRequest;
+import com.google.devtools.build.lib.exec.SpawnInputExpander;
+import com.google.devtools.build.lib.rules.fileset.FilesetActionContext;
import com.google.devtools.build.lib.standalone.StandaloneSpawnStrategy;
import com.google.devtools.build.lib.util.Preconditions;
+import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
/** Helper methods that are shared by the different sandboxing strategies in this package. */
public final class SandboxHelpers {
@@ -44,6 +53,50 @@
}
}
+ /**
+ * Returns the inputs of a Spawn as a map of PathFragments relative to an execRoot to paths in the
+ * host filesystem where the input files can be found.
+ */
+ public static Map<PathFragment, Path> getInputFiles(
+ SpawnInputExpander spawnInputExpander,
+ Path execRoot,
+ Spawn spawn,
+ ActionExecutionContext executionContext)
+ throws IOException {
+ Map<PathFragment, ActionInput> inputMap =
+ spawnInputExpander.getInputMapping(
+ spawn,
+ executionContext.getArtifactExpander(),
+ executionContext.getActionInputFileCache(),
+ executionContext.getExecutor().getContext(FilesetActionContext.class));
+ // SpawnInputExpander#getInputMapping uses ArtifactExpander#expandArtifacts to expand
+ // middlemen and tree artifacts, which expands empty tree artifacts to no entry. However,
+ // actions that accept TreeArtifacts as inputs generally expect that the empty directory is
+ // created. So we add those explicitly here.
+ // TODO(ulfjack): Move this code to SpawnInputExpander.
+ for (ActionInput input : spawn.getInputFiles()) {
+ if (input instanceof Artifact && ((Artifact) input).isTreeArtifact()) {
+ List<Artifact> containedArtifacts = new ArrayList<>();
+ executionContext.getArtifactExpander().expand((Artifact) input, containedArtifacts);
+ // Attempting to mount a non-empty directory results in ERR_DIRECTORY_NOT_EMPTY, so we
+ // only mount empty TreeArtifacts as directories.
+ if (containedArtifacts.isEmpty()) {
+ inputMap.put(input.getExecPath(), input);
+ }
+ }
+ }
+
+ Map<PathFragment, Path> inputFiles = new TreeMap<>();
+ for (Map.Entry<PathFragment, ActionInput> e : inputMap.entrySet()) {
+ Path inputPath =
+ e.getValue() == SpawnInputExpander.EMPTY_FILE
+ ? null
+ : execRoot.getRelative(e.getValue().getExecPath());
+ inputFiles.put(e.getKey(), inputPath);
+ }
+ return inputFiles;
+ }
+
public static ImmutableSet<PathFragment> getOutputFiles(Spawn spawn) {
Builder<PathFragment> outputFiles = ImmutableSet.builder();
for (ActionInput output : spawn.getOutputFiles()) {