diff options
author | 2018-02-20 05:57:49 -0800 | |
---|---|---|
committer | 2018-02-20 05:59:23 -0800 | |
commit | 2c05aff6cf12d72b20435b152f71ca1f0bce55ec (patch) | |
tree | 6e07ea080543e7a0f1c0e7ab0a085bf90436da79 /src/main/java/com/google/devtools | |
parent | 9f608c2c17351c1e4e802db55d98542b15c9de88 (diff) |
Provide a hacky way to get an ActionInput from BinTools
We have two places in internal code that require an ActionInput for an embedded
tool. The embedded tool is currently not declared as an input to the
corresponding actions, which in turn causes the remote execution to stat the
file directly through SingleBuildFileCache. I'm working on removing
SingleBuildFileCache, so this needs to be solved. This is the quick-and-dirty
fix. A more principled fix might be to check in the relevant tools instead of
embedding them into Bazel, but it's also significantly more work.
PiperOrigin-RevId: 186292203
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java | 9 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/exec/BinTools.java | 94 |
2 files changed, 103 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java b/src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java index c43b0549bd..e4c52747e2 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java +++ b/src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java @@ -38,6 +38,15 @@ public interface VirtualActionInput extends ActionInput { ByteString getBytes() throws IOException; /** + * Returns the Metadata for this input if available. Null otherwise. + * + * @throws IOException + */ + default Metadata getMetadata() throws IOException { + return null; + } + + /** * In some cases, we want empty files in the runfiles tree that have no corresponding artifact. We * use instances of this class to represent those files. */ diff --git a/src/main/java/com/google/devtools/build/lib/exec/BinTools.java b/src/main/java/com/google/devtools/build/lib/exec/BinTools.java index e6ca7fb382..c754386c56 100644 --- a/src/main/java/com/google/devtools/build/lib/exec/BinTools.java +++ b/src/main/java/com/google/devtools/build/lib/exec/BinTools.java @@ -17,15 +17,26 @@ package com.google.devtools.build.lib.exec; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.hash.Hasher; +import com.google.common.io.ByteStreams; +import com.google.devtools.build.lib.actions.ActionInput; import com.google.devtools.build.lib.actions.EnvironmentalExecException; import com.google.devtools.build.lib.actions.ExecException; +import com.google.devtools.build.lib.actions.cache.Metadata; +import com.google.devtools.build.lib.actions.cache.VirtualActionInput; import com.google.devtools.build.lib.analysis.BlazeDirectories; +import com.google.devtools.build.lib.skyframe.FileArtifactValue; import com.google.devtools.build.lib.vfs.Dirent; +import com.google.devtools.build.lib.vfs.FileSystem.HashFunction; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.Symlinks; +import com.google.protobuf.ByteString; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; /** * Initializes the <execRoot>/_bin/ directory that contains auxiliary tools used during action @@ -36,6 +47,7 @@ public final class BinTools { private final Path embeddedBinariesRoot; private final Path execrootParent; private final ImmutableList<String> embeddedTools; + private ImmutableMap<String, ActionInput> actionInputs; private Path binDir; // the working bin directory under execRoot @@ -61,6 +73,16 @@ public final class BinTools { this.binDir = null; } + private ImmutableMap<String, ActionInput> populateActionInputMap() { + ImmutableMap.Builder<String, ActionInput> result = ImmutableMap.builder(); + for (String embeddedPath : embeddedTools) { + PathFragment execPath = getExecPath(embeddedPath); + Path path = binDir.getRelative(execPath.getBaseName()); + result.put(embeddedPath, new PathActionInput(path, execPath)); + } + return result.build(); + } + /** * Creates an instance with the list of embedded tools obtained from scanning the directory * into which said binaries were extracted by the launcher. @@ -137,6 +159,16 @@ public final class BinTools { } } + /** + * Returns an action input for the given embedded tool. + */ + public ActionInput getActionInput(String embeddedPath) { + if (actionInputs == null) { + actionInputs = populateActionInputMap(); + } + return actionInputs.get(embeddedPath); + } + public PathFragment getExecPath(String embedPath) { if (!embeddedTools.contains(embedPath)) { return null; @@ -194,4 +226,66 @@ public final class BinTools { } } } + + /** An ActionInput pointing at an absolute path. */ + public static final class PathActionInput implements VirtualActionInput { + private final Path path; + private final PathFragment execPath; + private Metadata metadata; + + public PathActionInput(Path path, PathFragment execPath) { + this.path = path; + this.execPath = execPath; + } + + @Override + public void writeTo(OutputStream out) throws IOException { + try (InputStream in = path.getInputStream()) { + ByteStreams.copy(in, out); + } + } + + @Override + public ByteString getBytes() throws IOException { + ByteString.Output out = ByteString.newOutput(); + writeTo(out); + return out.toByteString(); + } + + @Override + public synchronized Metadata getMetadata() throws IOException { + // We intentionally delay hashing until it is necessary. + if (metadata == null) { + metadata = hash(path); + } + return metadata; + } + + private static Metadata hash(Path path) throws IOException { + HashFunction hashFn = path.getFileSystem().getDigestFunction(); + Hasher hasher = hashFn.getHash().newHasher(); + int bytesCopied = 0; + try (InputStream in = path.getInputStream()) { + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) > 0) { + hasher.putBytes(buffer, 0, len); + bytesCopied += len; + } + } + return FileArtifactValue.createForVirtualActionInput( + hasher.hash().asBytes(), + bytesCopied); + } + + @Override + public String getExecPathString() { + return execPath.getPathString(); + } + + @Override + public PathFragment getExecPath() { + return execPath; + } + } } |