Rollback of commit 59180a4ea66b1395b5b85defd732859ecae919ea.
*** Reason for rollback ***
Break bazel-tests and many other jobs on CI.
http://ci.bazel.io/job/bazel-tests/BAZEL_VERSION=HEAD,PLATFORM_NAME=linux-x86_64/651/console
*** Original change description ***
Add SpawnInputExpander helper class to arrange runfiles for spawn strategies
This new class is a combination of SpawnHelper and our internal code; the
plan is to migrate all spawn strategies to the new class. The strict flag
should be enabled by default, but that's a breaking change, so we need to do
it later.
- Use it in SandboxStrategy.
- Add ActionInput.getExecPath to return a PathFragment; this avoids lots of
back and forth between path fragments and strings.
This is a step towards #159...
***
--
PiperOrigin-RevId: 150610616
MOS_MIGRATED_REVID=150610616
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionInput.java b/src/main/java/com/google/devtools/build/lib/actions/ActionInput.java
index 90d4c5f..a21ed85 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionInput.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionInput.java
@@ -14,8 +14,6 @@
package com.google.devtools.build.lib.actions;
-import com.google.devtools.build.lib.vfs.PathFragment;
-
/**
* Represents an input file to a build action, with an appropriate relative path and digest
* value.
@@ -34,13 +32,6 @@
*/
public interface ActionInput {
- /**
- * @return the relative path to the input file.
- */
- String getExecPathString();
-
- /**
- * @return the relative path to the input file.
- */
- PathFragment getExecPath();
+ /** @return the relative path to the input file. */
+ public String getExecPathString();
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionInputHelper.java b/src/main/java/com/google/devtools/build/lib/actions/ActionInputHelper.java
index c63fd5b..4ca4a1b 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionInputHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionInputHelper.java
@@ -69,7 +69,6 @@
*/
private static class BasicActionInput implements ActionInput {
private final String path;
-
public BasicActionInput(String path) {
this.path = Preconditions.checkNotNull(path);
}
@@ -80,11 +79,6 @@
}
@Override
- public PathFragment getExecPath() {
- return new PathFragment(path);
- }
-
- @Override
public int hashCode() {
return path.hashCode();
}
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index bd54b0f..4b7adbc 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -344,7 +344,6 @@
return root;
}
- @Override
public final PathFragment getExecPath() {
return execPath;
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java b/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java
index 04eaf12..a087ee4 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/Runfiles.java
@@ -134,8 +134,8 @@
private final Artifact artifact;
private SymlinkEntry(PathFragment path, Artifact artifact) {
- this.path = Preconditions.checkNotNull(path);
- this.artifact = Preconditions.checkNotNull(artifact);
+ this.path = path;
+ this.artifact = artifact;
}
public PathFragment getPath() {
@@ -146,12 +146,10 @@
return artifact;
}
- @Override
public boolean isImmutable() {
return true;
}
- @Override
public void write(Appendable buffer, char quotationMark) {
Printer.append(buffer, "SymlinkEntry(path = ");
Printer.write(buffer, getPath().toString(), quotationMark);
@@ -433,11 +431,11 @@
* Returns the symlinks as a map from PathFragment to Artifact.
*
* @param eventHandler Used for throwing an error if we have an obscuring runlink within the
- * normal source tree entries, or runfile conflicts. May be null, in which case obscuring
- * symlinks are silently discarded, and conflicts are overwritten.
+ * normal source tree entries, or runfile conflicts. May be null, in which case obscuring
+ * symlinks are silently discarded, and conflicts are overwritten.
* @param location Location for eventHandler warnings. Ignored if eventHandler is null.
* @return Map<PathFragment, Artifact> path fragment to artifact, of normal source tree entries
- * and elements that live outside the source tree. Null values represent empty input files.
+ * and elements that live outside the source tree. Null values represent empty input files.
*/
public Map<PathFragment, Artifact> getRunfilesInputs(EventHandler eventHandler, Location location)
throws IOException {
@@ -852,13 +850,13 @@
* Adds a symlink.
*/
public Builder addSymlink(PathFragment link, Artifact target) {
+ Preconditions.checkNotNull(link);
+ Preconditions.checkNotNull(target);
symlinksBuilder.add(new SymlinkEntry(link, target));
return this;
}
- /**
- * Adds several symlinks. Neither keys nor values may be null.
- */
+ /** Adds several symlinks. */
public Builder addSymlinks(Map<PathFragment, Artifact> symlinks) {
for (Map.Entry<PathFragment, Artifact> symlink : symlinks.entrySet()) {
symlinksBuilder.add(new SymlinkEntry(symlink.getKey(), symlink.getValue()));
@@ -878,13 +876,13 @@
* Adds a root symlink.
*/
public Builder addRootSymlink(PathFragment link, Artifact target) {
+ Preconditions.checkNotNull(link);
+ Preconditions.checkNotNull(target);
rootSymlinksBuilder.add(new SymlinkEntry(link, target));
return this;
}
- /**
- * Adds several root symlinks. Neither keys nor values may be null.
- */
+ /** Adds several root symlinks. */
public Builder addRootSymlinks(Map<PathFragment, Artifact> symlinks) {
for (Map.Entry<PathFragment, Artifact> symlink : symlinks.entrySet()) {
rootSymlinksBuilder.add(new SymlinkEntry(symlink.getKey(), symlink.getValue()));
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SpawnInputExpander.java b/src/main/java/com/google/devtools/build/lib/exec/SpawnInputExpander.java
deleted file mode 100644
index 4c45aa9..0000000
--- a/src/main/java/com/google/devtools/build/lib/exec/SpawnInputExpander.java
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2017 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.exec;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.io.LineProcessor;
-import com.google.devtools.build.lib.actions.ActionInput;
-import com.google.devtools.build.lib.actions.ActionInputFileCache;
-import com.google.devtools.build.lib.actions.ActionInputHelper;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander;
-import com.google.devtools.build.lib.actions.RunfilesSupplier;
-import com.google.devtools.build.lib.actions.Spawn;
-import com.google.devtools.build.lib.analysis.AnalysisUtils;
-import com.google.devtools.build.lib.rules.fileset.FilesetActionContext;
-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 java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-/**
- * A helper class for spawn strategies to turn runfiles suppliers into input mappings. This class
- * performs no I/O operations, but only rearranges the files according to how the runfiles should be
- * laid out.
- */
-public class SpawnInputExpander {
- public static final ActionInput EMPTY_FILE = ActionInputHelper.fromPath("/dev/null");
-
- private final boolean strict;
-
- /**
- * Creates a new instance. If strict is true, then the expander checks for directories in runfiles
- * and throws an exception if it finds any. Otherwise it silently ignores directories in runfiles
- * and adds a mapping for them. At this time, directories in filesets are always silently added
- * as mappings.
- *
- * <p>Directories in inputs are a correctness issue: Bazel only tracks dependencies at the action
- * level, and it does not track dependencies on directories. Making a directory available to a
- * spawn even though it's contents are not tracked as dependencies leads to incorrect incremental
- * builds, since changes to the contents do not trigger action invalidation.
- *
- * <p>As such, all spawn strategies should always be strict and not make directories available to
- * the subprocess. However, that's a breaking change, and therefore we make it depend on this flag
- * for now.
- */
- public SpawnInputExpander(boolean strict) {
- this.strict = strict;
- }
-
- private void addMapping(
- Map<PathFragment, ActionInput> inputMappings,
- PathFragment targetLocation,
- ActionInput input) {
- if (!inputMappings.containsKey(targetLocation)) {
- inputMappings.put(targetLocation, input);
- }
- }
-
- /** Adds runfiles inputs from runfilesSupplier to inputMappings. */
- @VisibleForTesting
- void addRunfilesToInputs(
- Map<PathFragment, ActionInput> inputMap,
- RunfilesSupplier runfilesSupplier,
- ActionInputFileCache actionFileCache) throws IOException {
- Map<PathFragment, Map<PathFragment, Artifact>> rootsAndMappings = null;
- rootsAndMappings = runfilesSupplier.getMappings();
-
- for (Entry<PathFragment, Map<PathFragment, Artifact>> rootAndMappings :
- rootsAndMappings.entrySet()) {
- PathFragment root = rootAndMappings.getKey();
- for (Entry<PathFragment, Artifact> mapping : rootAndMappings.getValue().entrySet()) {
- PathFragment targetPrefix = root.getRelative(mapping.getKey());
- Artifact localArtifact = mapping.getValue();
- if (localArtifact != null) {
- if (strict && !actionFileCache.isFile(localArtifact)) {
- throw new IOException("Not a file: " + localArtifact.getPath().getPathString());
- }
- addMapping(inputMap, targetPrefix, localArtifact);
- } else {
- addMapping(inputMap, targetPrefix, EMPTY_FILE);
- }
- }
- }
- }
-
- /**
- * Parses the fileset manifest file, adding to the inputMappings where
- * appropriate. Lines referring to directories are recursed.
- */
- @VisibleForTesting
- void parseFilesetManifest(
- Map<PathFragment, ActionInput> inputMappings, Artifact manifest, String workspaceName)
- throws IOException {
- Path file = manifest.getRoot().getPath().getRelative(
- AnalysisUtils.getManifestPathFromFilesetPath(manifest.getExecPath()).getPathString());
- FileSystemUtils.asByteSource(file).asCharSource(UTF_8)
- .readLines(new ManifestLineProcessor(inputMappings, workspaceName, manifest.getExecPath()));
- }
-
- private final class ManifestLineProcessor implements LineProcessor<Object> {
- private final Map<PathFragment, ActionInput> inputMappings;
- private final String workspaceName;
- private final PathFragment targetPrefix;
- private int lineNum = 0;
-
- ManifestLineProcessor(
- Map<PathFragment, ActionInput> inputMappings,
- String workspaceName,
- PathFragment targetPrefix) {
- this.inputMappings = inputMappings;
- this.workspaceName = workspaceName;
- this.targetPrefix = targetPrefix;
- }
-
- @Override
- public boolean processLine(String line) throws IOException {
- if (++lineNum % 2 == 0) {
- // Digest line, skip.
- return true;
- }
- if (line.isEmpty()) {
- return true;
- }
-
- ActionInput artifact;
- PathFragment location;
- int pos = line.indexOf(' ');
- if (pos == -1) {
- location = new PathFragment(line);
- artifact = EMPTY_FILE;
- } else {
- String targetPath = line.substring(pos + 1);
- if (targetPath.charAt(0) != '/') {
- throw new IOException(String.format("runfiles target is not absolute: %s", targetPath));
- }
- artifact = targetPath.isEmpty() ? EMPTY_FILE : ActionInputHelper.fromPath(targetPath);
-
- location = new PathFragment(line.substring(0, pos));
- if (!workspaceName.isEmpty()) {
- if (!location.getSegment(0).equals(workspaceName)) {
- throw new IOException(
- String.format(
- "fileset manifest line must start with '%s': '%s'", workspaceName, location));
- } else {
- // Erase "<workspaceName>/".
- location = location.subFragment(1, location.segmentCount());
- }
- }
- }
-
- addMapping(inputMappings, targetPrefix.getRelative(location), artifact);
- return true;
- }
-
- @Override
- public Object getResult() {
- return null; // Unused.
- }
- }
-
- private void addInputs(
- Map<PathFragment, ActionInput> inputMap, Spawn spawn, ArtifactExpander artifactExpander) {
- List<ActionInput> inputs =
- ActionInputHelper.expandArtifacts(spawn.getInputFiles(), artifactExpander);
- for (ActionInput input : inputs) {
- inputMap.put(input.getExecPath(), input);
- }
- }
-
- /**
- * Convert the inputs of the given spawn to a map from exec-root relative paths to action inputs.
- * In some cases, this generates empty files, for which it uses {@link #EMPTY_FILE}.
- */
- public SortedMap<PathFragment, ActionInput> getInputMapping(
- Spawn spawn, ArtifactExpander artifactExpander, ActionInputFileCache actionInputFileCache,
- FilesetActionContext filesetContext)
- throws IOException {
- TreeMap<PathFragment, ActionInput> inputMap = new TreeMap<>();
- addInputs(inputMap, spawn, artifactExpander);
- addRunfilesToInputs(
- inputMap, spawn.getRunfilesSupplier(), actionInputFileCache);
- for (Artifact manifest : spawn.getFilesetManifests()) {
- parseFilesetManifest(inputMap, manifest, filesetContext.getWorkspaceName());
- }
- return inputMap;
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxStrategy.java
index a8da48e..2743778 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxStrategy.java
@@ -17,8 +17,6 @@
import com.google.common.collect.ImmutableSet;
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.EnvironmentalExecException;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.SandboxedSpawnActionContext;
@@ -30,17 +28,12 @@
import com.google.devtools.build.lib.buildtool.BuildRequest;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
-import com.google.devtools.build.lib.exec.SpawnInputExpander;
-import com.google.devtools.build.lib.rules.fileset.FilesetActionContext;
import com.google.devtools.build.lib.util.io.OutErr;
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.Set;
-import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicReference;
/** Abstract common ancestor for sandbox strategies implementing the common parts. */
@@ -51,7 +44,7 @@
private final Path execRoot;
private final boolean verboseFailures;
private final SandboxOptions sandboxOptions;
- private final SpawnInputExpander spawnInputExpander;
+ private final SpawnHelpers spawnHelpers;
public SandboxStrategy(
BuildRequest buildRequest,
@@ -63,7 +56,7 @@
this.execRoot = blazeDirs.getExecRoot();
this.verboseFailures = verboseFailures;
this.sandboxOptions = sandboxOptions;
- this.spawnInputExpander = new SpawnInputExpander(/*strict=*/false);
+ this.spawnHelpers = new SpawnHelpers(blazeDirs.getExecRoot());
}
protected void runSpawn(
@@ -152,33 +145,7 @@
public Map<PathFragment, Path> getMounts(Spawn spawn, ActionExecutionContext executionContext)
throws ExecException {
try {
- Map<PathFragment, ActionInput> inputMap = spawnInputExpander
- .getInputMapping(
- spawn,
- executionContext.getArtifactExpander(),
- executionContext.getActionInputFileCache(),
- executionContext.getExecutor().getContext(FilesetActionContext.class));
- Map<PathFragment, Path> mounts = new TreeMap<>();
- for (Map.Entry<PathFragment, ActionInput> e : inputMap.entrySet()) {
- mounts.put(e.getKey(), execRoot.getRelative(e.getValue().getExecPath()));
- }
-
- // ActionInputHelper#expandArtifacts above expands empty TreeArtifacts into an empty list.
- // However, actions that accept TreeArtifacts as inputs generally expect that the empty
- // directory is created. So here we explicitly mount the directories of the TreeArtifacts as
- // inputs.
- 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);
- }
- }
- }
- return mounts;
+ return spawnHelpers.getMounts(spawn, executionContext);
} catch (IOException e) {
throw new EnvironmentalExecException("Could not prepare mounts for sandbox execution", e);
}
diff --git a/src/test/java/com/google/devtools/build/lib/exec/DigestTest.java b/src/test/java/com/google/devtools/build/lib/exec/DigestTest.java
index 27edca0..b610641 100644
--- a/src/test/java/com/google/devtools/build/lib/exec/DigestTest.java
+++ b/src/test/java/com/google/devtools/build/lib/exec/DigestTest.java
@@ -23,7 +23,6 @@
import com.google.devtools.build.lib.testutil.Suite;
import com.google.devtools.build.lib.testutil.TestSpec;
import com.google.devtools.build.lib.util.Pair;
-import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.protobuf.ByteString;
import java.io.IOException;
import java.io.OutputStream;
@@ -62,7 +61,7 @@
"8b1a9953c4611296a827abf8c47804d7",
Digest.fromContent("Hello".getBytes(UTF_8)).toStringUtf8());
- assertEquals(UGLY_DIGEST, Digest.fromContent(UGLY.getBytes(UTF_8)).toStringUtf8());
+ assertEquals(UGLY_DIGEST, Digest.fromContent(UGLY.getBytes()).toStringUtf8());
// ByteBuffer digest not idempotent because ByteBuffer manages a "position" internally.
ByteBuffer buffer = ByteBuffer.wrap(UGLY.getBytes(UTF_8));
@@ -107,11 +106,6 @@
public String getExecPathString() {
throw new UnsupportedOperationException();
}
-
- @Override
- public PathFragment getExecPath() {
- throw new UnsupportedOperationException();
- }
});
assertEquals(UGLY_DIGEST, result.first.toStringUtf8());
assertEquals(UGLY.length(), result.second.longValue());
diff --git a/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java b/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java
deleted file mode 100644
index fdfa655..0000000
--- a/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright 2017 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.exec;
-
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.fail;
-
-import com.google.common.collect.Maps;
-import com.google.devtools.build.lib.actions.ActionInput;
-import com.google.devtools.build.lib.actions.ActionInputFileCache;
-import com.google.devtools.build.lib.actions.ActionInputHelper;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.actions.EmptyRunfilesSupplier;
-import com.google.devtools.build.lib.actions.Root;
-import com.google.devtools.build.lib.actions.RunfilesSupplier;
-import com.google.devtools.build.lib.analysis.Runfiles;
-import com.google.devtools.build.lib.analysis.RunfilesSupplierImpl;
-import com.google.devtools.build.lib.vfs.FileSystem;
-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.inmemoryfs.InMemoryFileSystem;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.Mockito;
-
-/**
- * Tests for {@link SpawnInputExpander}.
- */
-@RunWith(JUnit4.class)
-public class SpawnInputExpanderTest {
- private FileSystem fs;
- private SpawnInputExpander expander;
- private Map<PathFragment, ActionInput> inputMappings;
-
- @Before
- public final void createSpawnInputExpander() throws Exception {
- fs = new InMemoryFileSystem();
- expander = new SpawnInputExpander(/*strict=*/true);
- inputMappings = Maps.newHashMap();
- }
-
- private void scratchFile(String file, String... lines) throws Exception {
- Path path = fs.getPath(file);
- FileSystemUtils.createDirectoryAndParents(path.getParentDirectory());
- FileSystemUtils.writeLinesAs(path, StandardCharsets.UTF_8, lines);
- }
-
- @Test
- public void testEmptyRunfiles() throws Exception {
- RunfilesSupplier supplier = EmptyRunfilesSupplier.INSTANCE;
- expander.addRunfilesToInputs(inputMappings, supplier, null);
- assertThat(inputMappings).isEmpty();
- }
-
- @Test
- public void testRunfilesSingleFile() throws Exception {
- Artifact artifact =
- new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
- Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(artifact).build();
- RunfilesSupplier supplier = new RunfilesSupplierImpl(new PathFragment("runfiles"), runfiles);
- ActionInputFileCache mockCache = Mockito.mock(ActionInputFileCache.class);
- Mockito.when(mockCache.isFile(artifact)).thenReturn(true);
-
- expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
- assertThat(inputMappings).hasSize(1);
- assertThat(inputMappings)
- .containsEntry(new PathFragment("runfiles/workspace/dir/file"), artifact);
- }
-
- @Test
- public void testRunfilesDirectoryStrict() throws Exception {
- Artifact artifact =
- new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
- Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(artifact).build();
- RunfilesSupplier supplier = new RunfilesSupplierImpl(new PathFragment("runfiles"), runfiles);
- ActionInputFileCache mockCache = Mockito.mock(ActionInputFileCache.class);
- Mockito.when(mockCache.isFile(artifact)).thenReturn(false);
-
- try {
- expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
- fail();
- } catch (IOException expected) {
- assertThat(expected.getMessage().contains("Not a file: /root/dir/file")).isTrue();
- }
- }
-
- @Test
- public void testRunfilesDirectoryNonStrict() throws Exception {
- Artifact artifact =
- new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
- Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(artifact).build();
- RunfilesSupplier supplier = new RunfilesSupplierImpl(new PathFragment("runfiles"), runfiles);
- ActionInputFileCache mockCache = Mockito.mock(ActionInputFileCache.class);
- Mockito.when(mockCache.isFile(artifact)).thenReturn(false);
-
- expander = new SpawnInputExpander(/*strict=*/false);
- expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
- assertThat(inputMappings).hasSize(1);
- assertThat(inputMappings)
- .containsEntry(new PathFragment("runfiles/workspace/dir/file"), artifact);
- }
-
- @Test
- public void testRunfilesTwoFiles() throws Exception {
- Artifact artifact1 =
- new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
- Artifact artifact2 =
- new Artifact(fs.getPath("/root/dir/baz"), Root.asSourceRoot(fs.getPath("/root")));
- Runfiles runfiles = new Runfiles.Builder("workspace")
- .addArtifact(artifact1)
- .addArtifact(artifact2)
- .build();
- RunfilesSupplier supplier = new RunfilesSupplierImpl(new PathFragment("runfiles"), runfiles);
- ActionInputFileCache mockCache = Mockito.mock(ActionInputFileCache.class);
- Mockito.when(mockCache.isFile(artifact1)).thenReturn(true);
- Mockito.when(mockCache.isFile(artifact2)).thenReturn(true);
-
- expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
- assertThat(inputMappings).hasSize(2);
- assertThat(inputMappings)
- .containsEntry(new PathFragment("runfiles/workspace/dir/file"), artifact1);
- assertThat(inputMappings)
- .containsEntry(new PathFragment("runfiles/workspace/dir/baz"), artifact2);
- }
-
- @Test
- public void testRunfilesSymlink() throws Exception {
- Artifact artifact =
- new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
- Runfiles runfiles = new Runfiles.Builder("workspace")
- .addSymlink(new PathFragment("symlink"), artifact).build();
- RunfilesSupplier supplier = new RunfilesSupplierImpl(new PathFragment("runfiles"), runfiles);
- ActionInputFileCache mockCache = Mockito.mock(ActionInputFileCache.class);
- Mockito.when(mockCache.isFile(artifact)).thenReturn(true);
-
- expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
- assertThat(inputMappings).hasSize(1);
- assertThat(inputMappings)
- .containsEntry(new PathFragment("runfiles/workspace/symlink"), artifact);
- }
-
- @Test
- public void testRunfilesRootSymlink() throws Exception {
- Artifact artifact =
- new Artifact(fs.getPath("/root/dir/file"), Root.asSourceRoot(fs.getPath("/root")));
- Runfiles runfiles = new Runfiles.Builder("workspace")
- .addRootSymlink(new PathFragment("symlink"), artifact).build();
- RunfilesSupplier supplier = new RunfilesSupplierImpl(new PathFragment("runfiles"), runfiles);
- ActionInputFileCache mockCache = Mockito.mock(ActionInputFileCache.class);
- Mockito.when(mockCache.isFile(artifact)).thenReturn(true);
-
- expander.addRunfilesToInputs(inputMappings, supplier, mockCache);
- assertThat(inputMappings).hasSize(2);
- assertThat(inputMappings).containsEntry(new PathFragment("runfiles/symlink"), artifact);
- // If there's no other entry, Runfiles adds an empty file in the workspace to make sure the
- // directory gets created.
- assertThat(inputMappings)
- .containsEntry(
- new PathFragment("runfiles/workspace/.runfile"), SpawnInputExpander.EMPTY_FILE);
- }
-
- @Test
- public void testEmptyManifest() throws Exception {
- // See AnalysisUtils for the mapping from "foo" to "_foo/MANIFEST".
- scratchFile("/root/_foo/MANIFEST");
-
- Artifact artifact =
- new Artifact(fs.getPath("/root/foo"), Root.asSourceRoot(fs.getPath("/root")));
- expander.parseFilesetManifest(inputMappings, artifact, "workspace");
- assertThat(inputMappings).isEmpty();
- }
-
- @Test
- public void testManifestWithSingleFile() throws Exception {
- // See AnalysisUtils for the mapping from "foo" to "_foo/MANIFEST".
- scratchFile(
- "/root/_foo/MANIFEST",
- "workspace/bar /dir/file",
- "<some digest>");
-
- Artifact artifact =
- new Artifact(fs.getPath("/root/foo"), Root.asSourceRoot(fs.getPath("/root")));
- expander.parseFilesetManifest(inputMappings, artifact, "workspace");
- assertThat(inputMappings).hasSize(1);
- assertThat(inputMappings)
- .containsEntry(new PathFragment("foo/bar"), ActionInputHelper.fromPath("/dir/file"));
- }
-
- @Test
- public void testManifestWithTwoFiles() throws Exception {
- // See AnalysisUtils for the mapping from "foo" to "_foo/MANIFEST".
- scratchFile(
- "/root/_foo/MANIFEST",
- "workspace/bar /dir/file",
- "<some digest>",
- "workspace/baz /dir/file",
- "<some digest>");
-
- Artifact artifact =
- new Artifact(fs.getPath("/root/foo"), Root.asSourceRoot(fs.getPath("/root")));
- expander.parseFilesetManifest(inputMappings, artifact, "workspace");
- assertThat(inputMappings).hasSize(2);
- assertThat(inputMappings)
- .containsEntry(new PathFragment("foo/bar"), ActionInputHelper.fromPath("/dir/file"));
- assertThat(inputMappings)
- .containsEntry(new PathFragment("foo/baz"), ActionInputHelper.fromPath("/dir/file"));
- }
-
- @Test
- public void testManifestWithDirectory() throws Exception {
- // See AnalysisUtils for the mapping from "foo" to "_foo/MANIFEST".
- scratchFile(
- "/root/_foo/MANIFEST",
- "workspace/bar /some",
- "<some digest>");
-
- Artifact artifact =
- new Artifact(fs.getPath("/root/foo"), Root.asSourceRoot(fs.getPath("/root")));
- expander.parseFilesetManifest(inputMappings, artifact, "workspace");
- assertThat(inputMappings).hasSize(1);
- assertThat(inputMappings)
- .containsEntry(
- new PathFragment("foo/bar"), ActionInputHelper.fromPath("/some"));
- }
-}