diff --git a/src/main/java/com/google/devtools/build/lib/actions/PathMapper.java b/src/main/java/com/google/devtools/build/lib/actions/PathMapper.java index 1d006ed7678737..0e7dcc546dd531 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/PathMapper.java +++ b/src/main/java/com/google/devtools/build/lib/actions/PathMapper.java @@ -33,7 +33,15 @@ * part (e.g. "k8-fastbuild") from exec paths to allow for cross-configuration cache hits. */ public interface PathMapper { - /** Returns the exec path with the path mapping applied. */ + /** + * Returns the exec path with the path mapping applied. + * + *

Path mappers may return paths with different roots for two paths that have the same root + * (e.g., they may map an artifact at {@code bazel-out/k8-fastbuild/bin/pkg/foo} to {@code + * bazel-out//bin/pkg/foo}). Paths of artifacts that should share the same + * parent directory, such as runfiles or tree artifact files, should thus be derived from the + * mapped path of their parent. + */ PathFragment map(PathFragment execPath); /** Returns the exec path of the input with the path mapping applied. */ @@ -80,6 +88,17 @@ default boolean isNoop() { return this == NOOP; } + /** + * Returns an opaque object whose equality class should encode all information that goes into the + * behavior of the {@link #map(PathFragment)} function of this path mapper. This is used as a key + * for in-memory caches. + * + *

The default implementation returns the {@link Class} of the path mapper. + */ + default Object cacheKey() { + return this.getClass(); + } + /** A {@link PathMapper} that doesn't change paths. */ PathMapper NOOP = execPath -> execPath; } 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 index 7ee6986efe5392..16d3359d4cef71 100644 --- a/src/main/java/com/google/devtools/build/lib/exec/SpawnInputExpander.java +++ b/src/main/java/com/google/devtools/build/lib/exec/SpawnInputExpander.java @@ -33,6 +33,7 @@ import com.google.devtools.build.lib.actions.FilesetOutputSymlink; import com.google.devtools.build.lib.actions.ForbiddenActionInputException; import com.google.devtools.build.lib.actions.InputMetadataProvider; +import com.google.devtools.build.lib.actions.PathMapper; import com.google.devtools.build.lib.actions.RunfilesSupplier; import com.google.devtools.build.lib.actions.Spawn; import com.google.devtools.build.lib.actions.cache.VirtualActionInput; @@ -125,6 +126,7 @@ void addRunfilesToInputs( RunfilesSupplier runfilesSupplier, InputMetadataProvider actionFileCache, ArtifactExpander artifactExpander, + PathMapper pathMapper, PathFragment baseDirectory) throws IOException, ForbiddenActionInputException { Map> rootsAndMappings = @@ -145,6 +147,7 @@ void addRunfilesToInputs( ? null : artifactExpander.getArchivedTreeArtifact((SpecialArtifact) localArtifact); if (archivedTreeArtifact != null) { + // TODO(bazel-team): Add path mapping support for archived tree artifacts. addMapping(inputMap, location, localArtifact, baseDirectory); } else { List expandedInputs = @@ -153,11 +156,12 @@ void addRunfilesToInputs( artifactExpander, /* keepEmptyTreeArtifacts= */ false); for (ActionInput input : expandedInputs) { - addMapping( - inputMap, - location.getRelative(((TreeFileArtifact) input).getParentRelativePath()), - input, - baseDirectory); + addMapping( + inputMap, + mapForRunfiles(pathMapper, root, location) + .getRelative(((TreeFileArtifact) input).getParentRelativePath()), + input, + baseDirectory); } } } else if (localArtifact.isFileset()) { @@ -167,15 +171,21 @@ void addRunfilesToInputs( } catch (MissingExpansionException e) { throw new IllegalStateException(e); } + // TODO(bazel-team): Add path mapping support for filesets. addFilesetManifest(location, localArtifact, filesetLinks, inputMap, baseDirectory); } else { if (strict) { failIfDirectory(actionFileCache, localArtifact); } - addMapping(inputMap, location, localArtifact, baseDirectory); + addMapping( + inputMap, mapForRunfiles(pathMapper, root, location), localArtifact, baseDirectory); } } else { - addMapping(inputMap, location, VirtualActionInput.EMPTY_MARKER, baseDirectory); + addMapping( + inputMap, + mapForRunfiles(pathMapper, root, location), + VirtualActionInput.EMPTY_MARKER, + baseDirectory); } } } @@ -186,11 +196,12 @@ public Map addRunfilesToInputs( RunfilesSupplier runfilesSupplier, InputMetadataProvider actionFileCache, ArtifactExpander artifactExpander, + PathMapper pathMapper, PathFragment baseDirectory) throws IOException, ForbiddenActionInputException { Map inputMap = new HashMap<>(); addRunfilesToInputs( - inputMap, runfilesSupplier, actionFileCache, artifactExpander, baseDirectory); + inputMap, runfilesSupplier, actionFileCache, artifactExpander, pathMapper, baseDirectory); return inputMap; } @@ -235,6 +246,7 @@ void addFilesetManifest( value == null ? VirtualActionInput.EMPTY_MARKER : ActionInputHelper.fromPath(execRoot.getRelative(value).asFragment()); + // TODO(bazel-team): Add path mapping support for filesets. addMapping(inputMappings, mapping.getKey(), artifact, baseDirectory); } } @@ -243,6 +255,7 @@ private static void addInputs( Map inputMap, NestedSet inputFiles, ArtifactExpander artifactExpander, + PathMapper pathMapper, PathFragment baseDirectory) { // Actions that accept TreeArtifacts as inputs generally expect the directory corresponding // to the artifact to be created, even if it is empty. We explicitly keep empty TreeArtifacts @@ -251,7 +264,17 @@ private static void addInputs( ActionInputHelper.expandArtifacts( inputFiles, artifactExpander, /* keepEmptyTreeArtifacts= */ true); for (ActionInput input : inputs) { - addMapping(inputMap, input.getExecPath(), input, baseDirectory); + if (input instanceof TreeFileArtifact) { + addMapping( + inputMap, + pathMapper + .map(((TreeFileArtifact) input).getParent().getExecPath()) + .getRelative(((TreeFileArtifact) input).getParentRelativePath()), + input, + baseDirectory); + } else { + addMapping(inputMap, pathMapper.map(input.getExecPath()), input, baseDirectory); + } } } @@ -273,17 +296,37 @@ public SortedMap getInputMapping( InputMetadataProvider actionInputFileCache) throws IOException, ForbiddenActionInputException { TreeMap inputMap = new TreeMap<>(); - addInputs(inputMap, spawn.getInputFiles(), artifactExpander, baseDirectory); + addInputs( + inputMap, spawn.getInputFiles(), artifactExpander, spawn.getPathMapper(), baseDirectory); addRunfilesToInputs( inputMap, spawn.getRunfilesSupplier(), actionInputFileCache, artifactExpander, + spawn.getPathMapper(), baseDirectory); addFilesetManifests(spawn.getFilesetMappings(), inputMap, baseDirectory); return inputMap; } + private static PathFragment mapForRunfiles( + PathMapper pathMapper, PathFragment runfilesDir, PathFragment execPath) { + if (pathMapper.isNoop()) { + return execPath; + } + String runfilesDirName = runfilesDir.getBaseName(); + Preconditions.checkArgument(runfilesDirName.endsWith(".runfiles")); + // Derive the path of the executable, apply the path mapping to it and then rederive the path + // of the runfiles dir. + PathFragment executable = + runfilesDir.replaceName( + runfilesDirName.substring(0, runfilesDirName.length() - ".runfiles".length())); + return pathMapper + .map(executable) + .replaceName(runfilesDirName) + .getRelative(execPath.relativeTo(runfilesDir)); + } + /** The interface for accessing part of the input hierarchy. */ public interface InputWalker { @@ -326,19 +369,25 @@ public void walkInputs( InputMetadataProvider actionInputFileCache, InputVisitor visitor) throws IOException, ForbiddenActionInputException { - walkNestedSetInputs(baseDirectory, spawn.getInputFiles(), artifactExpander, visitor); + walkNestedSetInputs( + baseDirectory, spawn.getInputFiles(), artifactExpander, spawn.getPathMapper(), visitor); RunfilesSupplier runfilesSupplier = spawn.getRunfilesSupplier(); visitor.visit( // Cache key for the sub-mapping containing the runfiles inputs for this spawn. - ImmutableList.of(runfilesSupplier, baseDirectory), + ImmutableList.of(runfilesSupplier, baseDirectory, spawn.getPathMapper().cacheKey()), new InputWalker() { @Override public SortedMap getLeavesInputMapping() throws IOException, ForbiddenActionInputException { TreeMap inputMap = new TreeMap<>(); addRunfilesToInputs( - inputMap, runfilesSupplier, actionInputFileCache, artifactExpander, baseDirectory); + inputMap, + runfilesSupplier, + actionInputFileCache, + artifactExpander, + spawn.getPathMapper(), + baseDirectory); return inputMap; } }); @@ -348,7 +397,7 @@ public SortedMap getLeavesInputMapping() // improved runtime. visitor.visit( // Cache key for the sub-mapping containing the fileset inputs for this spawn. - ImmutableList.of(filesetMappings, baseDirectory), + ImmutableList.of(filesetMappings, baseDirectory, spawn.getPathMapper().cacheKey()), new InputWalker() { @Override public SortedMap getLeavesInputMapping() @@ -365,11 +414,12 @@ private void walkNestedSetInputs( PathFragment baseDirectory, NestedSet someInputFiles, ArtifactExpander artifactExpander, + PathMapper pathMapper, InputVisitor visitor) throws IOException, ForbiddenActionInputException { visitor.visit( // Cache key for the sub-mapping containing the files in this nested set. - ImmutableList.of(someInputFiles.toNode(), baseDirectory), + ImmutableList.of(someInputFiles.toNode(), baseDirectory, pathMapper.cacheKey()), new InputWalker() { @Override public SortedMap getLeavesInputMapping() { @@ -384,6 +434,7 @@ public SortedMap getLeavesInputMapping() { inputMap, NestedSetBuilder.wrap(someInputFiles.getOrder(), leaves), artifactExpander, + pathMapper, baseDirectory); return inputMap; } @@ -394,11 +445,16 @@ public void visitNonLeaves(InputVisitor childVisitor) for (ActionInput input : someInputFiles.getLeaves()) { if (isTreeArtifact(input)) { walkTreeInputs( - baseDirectory, (SpecialArtifact) input, artifactExpander, childVisitor); + baseDirectory, + (SpecialArtifact) input, + artifactExpander, + pathMapper, + childVisitor); } } for (NestedSet subInputs : someInputFiles.getNonLeaves()) { - walkNestedSetInputs(baseDirectory, subInputs, artifactExpander, childVisitor); + walkNestedSetInputs( + baseDirectory, subInputs, artifactExpander, pathMapper, childVisitor); } } }); @@ -409,11 +465,12 @@ private void walkTreeInputs( PathFragment baseDirectory, SpecialArtifact tree, ArtifactExpander artifactExpander, + PathMapper pathMapper, InputVisitor visitor) throws IOException, ForbiddenActionInputException { visitor.visit( // Cache key for the sub-mapping containing the files in this tree artifact. - ImmutableList.of(tree, baseDirectory), + ImmutableList.of(tree, baseDirectory, pathMapper.cacheKey()), new InputWalker() { @Override public SortedMap getLeavesInputMapping() { @@ -422,6 +479,7 @@ public SortedMap getLeavesInputMapping() { inputMap, NestedSetBuilder.create(Order.STABLE_ORDER, tree), artifactExpander, + pathMapper, baseDirectory); return inputMap; } 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 index f1ffe6e5b00dec..e55beea7fd9eda 100644 --- a/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java +++ b/src/test/java/com/google/devtools/build/lib/exec/SpawnInputExpanderTest.java @@ -17,6 +17,7 @@ import static com.google.devtools.build.lib.actions.FilesetManifest.RelativeSymlinkBehavior.ERROR; import static com.google.devtools.build.lib.actions.FilesetManifest.RelativeSymlinkBehavior.IGNORE; import static com.google.devtools.build.lib.actions.FilesetManifest.RelativeSymlinkBehavior.RESOLVE; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; @@ -37,6 +38,7 @@ import com.google.devtools.build.lib.actions.FilesetManifest; import com.google.devtools.build.lib.actions.FilesetOutputSymlink; import com.google.devtools.build.lib.actions.ForbiddenActionInputException; +import com.google.devtools.build.lib.actions.PathMapper; import com.google.devtools.build.lib.actions.RunfilesSupplier; import com.google.devtools.build.lib.actions.Spawn; import com.google.devtools.build.lib.actions.cache.VirtualActionInput; @@ -82,7 +84,12 @@ public void testEmptyRunfiles() throws Exception { RunfilesSupplier supplier = EmptyRunfilesSupplier.INSTANCE; FakeActionInputFileCache mockCache = new FakeActionInputFileCache(); expander.addRunfilesToInputs( - inputMappings, supplier, mockCache, NO_ARTIFACT_EXPANDER, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + mockCache, + NO_ARTIFACT_EXPANDER, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).isEmpty(); } @@ -101,7 +108,12 @@ public void testRunfilesSingleFile() throws Exception { FileArtifactValue.createForNormalFile(FAKE_DIGEST, /*proxy=*/ null, /*size=*/ 0L)); expander.addRunfilesToInputs( - inputMappings, supplier, mockCache, NO_ARTIFACT_EXPANDER, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + mockCache, + NO_ARTIFACT_EXPANDER, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(1); assertThat(inputMappings) .containsEntry(PathFragment.create("runfiles/workspace/dir/file"), artifact); @@ -136,7 +148,12 @@ public ImmutableList getFileset(Artifact artifact) { }; expander.addRunfilesToInputs( - inputMappings, supplier, mockCache, filesetExpander, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + mockCache, + filesetExpander, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(1); assertThat(inputMappings) .containsEntry( @@ -165,6 +182,7 @@ public void testRunfilesDirectoryStrict() { supplier, mockCache, NO_ARTIFACT_EXPANDER, + PathMapper.NOOP, PathFragment.EMPTY_FRAGMENT)); assertThat(expected).hasMessageThat().isEqualTo("Not a file: dir/file"); } @@ -183,7 +201,12 @@ public void testRunfilesDirectoryNonStrict() throws Exception { expander = new SpawnInputExpander(execRoot, /*strict=*/ false); expander.addRunfilesToInputs( - inputMappings, supplier, mockCache, NO_ARTIFACT_EXPANDER, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + mockCache, + NO_ARTIFACT_EXPANDER, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(1); assertThat(inputMappings) .containsEntry(PathFragment.create("runfiles/workspace/dir/file"), artifact); @@ -212,7 +235,12 @@ public void testRunfilesTwoFiles() throws Exception { FileArtifactValue.createForNormalFile(FAKE_DIGEST, /*proxy=*/ null, /*size=*/ 12L)); expander.addRunfilesToInputs( - inputMappings, supplier, mockCache, NO_ARTIFACT_EXPANDER, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + mockCache, + NO_ARTIFACT_EXPANDER, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(2); assertThat(inputMappings) .containsEntry(PathFragment.create("runfiles/workspace/dir/file"), artifact1); @@ -220,6 +248,45 @@ public void testRunfilesTwoFiles() throws Exception { .containsEntry(PathFragment.create("runfiles/workspace/dir/baz"), artifact2); } + @Test + public void testRunfilesTwoFiles_pathMapped() throws Exception { + Artifact artifact1 = + ActionsTestUtil.createArtifact( + ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))), + fs.getPath("/root/dir/file")); + Artifact artifact2 = + ActionsTestUtil.createArtifact( + ArtifactRoot.asSourceRoot(Root.fromPath(fs.getPath("/root"))), + fs.getPath("/root/dir/baz")); + Runfiles runfiles = + new Runfiles.Builder("workspace").addArtifact(artifact1).addArtifact(artifact2).build(); + RunfilesSupplier supplier = + AnalysisTestUtil.createRunfilesSupplier( + PathFragment.create("bazel-out/k8-opt/bin/foo.runfiles"), runfiles); + FakeActionInputFileCache mockCache = new FakeActionInputFileCache(); + mockCache.put( + artifact1, + FileArtifactValue.createForNormalFile(FAKE_DIGEST, /* proxy= */ null, /* size= */ 1L)); + mockCache.put( + artifact2, + FileArtifactValue.createForNormalFile(FAKE_DIGEST, /* proxy= */ null, /* size= */ 12L)); + + expander.addRunfilesToInputs( + inputMappings, + supplier, + mockCache, + NO_ARTIFACT_EXPANDER, + execPath -> PathFragment.create(execPath.getPathString().replace("k8-opt/", "")), + PathFragment.EMPTY_FRAGMENT); + assertThat(inputMappings).hasSize(2); + assertThat(inputMappings) + .containsEntry( + PathFragment.create("bazel-out/bin/foo.runfiles/workspace/dir/file"), artifact1); + assertThat(inputMappings) + .containsEntry( + PathFragment.create("bazel-out/bin/foo.runfiles/workspace/dir/baz"), artifact2); + } + @Test public void testRunfilesSymlink() throws Exception { Artifact artifact = @@ -238,7 +305,12 @@ public void testRunfilesSymlink() throws Exception { FileArtifactValue.createForNormalFile(FAKE_DIGEST, /*proxy=*/ null, /*size=*/ 1L)); expander.addRunfilesToInputs( - inputMappings, supplier, mockCache, NO_ARTIFACT_EXPANDER, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + mockCache, + NO_ARTIFACT_EXPANDER, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(1); assertThat(inputMappings) .containsEntry(PathFragment.create("runfiles/workspace/symlink"), artifact); @@ -262,7 +334,12 @@ public void testRunfilesRootSymlink() throws Exception { FileArtifactValue.createForNormalFile(FAKE_DIGEST, /*proxy=*/ null, /*size=*/ 1L)); expander.addRunfilesToInputs( - inputMappings, supplier, mockCache, NO_ARTIFACT_EXPANDER, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + mockCache, + NO_ARTIFACT_EXPANDER, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(2); assertThat(inputMappings).containsEntry(PathFragment.create("runfiles/symlink"), artifact); // If there's no other entry, Runfiles adds an empty file in the workspace to make sure the @@ -295,7 +372,12 @@ public void testRunfilesWithTreeArtifacts() throws Exception { fakeCache.put(file2, FileArtifactValue.createForTesting(file2)); expander.addRunfilesToInputs( - inputMappings, supplier, fakeCache, artifactExpander, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + fakeCache, + artifactExpander, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(2); assertThat(inputMappings) .containsEntry(PathFragment.create("runfiles/workspace/treeArtifact/file1"), file1); @@ -303,6 +385,64 @@ public void testRunfilesWithTreeArtifacts() throws Exception { .containsEntry(PathFragment.create("runfiles/workspace/treeArtifact/file2"), file2); } + @Test + public void testRunfilesWithTreeArtifacts_pathMapped() throws Exception { + SpecialArtifact treeArtifact = createTreeArtifact("treeArtifact"); + assertThat(treeArtifact.isTreeArtifact()).isTrue(); + TreeFileArtifact file1 = TreeFileArtifact.createTreeOutput(treeArtifact, "file1"); + TreeFileArtifact file2 = TreeFileArtifact.createTreeOutput(treeArtifact, "file2"); + FileSystemUtils.writeContentAsLatin1(file1.getPath(), "foo"); + FileSystemUtils.writeContentAsLatin1(file2.getPath(), "bar"); + + Runfiles runfiles = new Runfiles.Builder("workspace").addArtifact(treeArtifact).build(); + ArtifactExpander artifactExpander = + (Artifact artifact, Collection output) -> { + if (artifact.equals(treeArtifact)) { + output.addAll(Arrays.asList(file1, file2)); + } + }; + RunfilesSupplier supplier = + AnalysisTestUtil.createRunfilesSupplier( + PathFragment.create("bazel-out/k8-opt/bin/foo.runfiles"), runfiles); + FakeActionInputFileCache fakeCache = new FakeActionInputFileCache(); + fakeCache.put(file1, FileArtifactValue.createForTesting(file1)); + fakeCache.put(file2, FileArtifactValue.createForTesting(file2)); + + PathMapper pathMapper = + execPath -> { + // Replace the config segment "k8-opt" in "bazel-bin/k8-opt/bin" with a hash of the full + // path to verify that the new paths are constructed by appending the child paths to the + // mapped parent path, not by mapping the child paths directly. + PathFragment runfilesPath = execPath.subFragment(3); + String runfilesPathHash = + DigestHashFunction.SHA256 + .getHashFunction() + .hashString(runfilesPath.getPathString(), UTF_8) + .toString(); + return execPath + .subFragment(0, 1) + .getRelative(runfilesPathHash.substring(0, 8)) + .getRelative(execPath.subFragment(2)); + }; + + expander.addRunfilesToInputs( + inputMappings, + supplier, + fakeCache, + artifactExpander, + pathMapper, + PathFragment.EMPTY_FRAGMENT); + assertThat(inputMappings).hasSize(2); + assertThat(inputMappings) + .containsEntry( + PathFragment.create("bazel-out/2c26b46b/bin/foo.runfiles/workspace/treeArtifact/file1"), + file1); + assertThat(inputMappings) + .containsEntry( + PathFragment.create("bazel-out/2c26b46b/bin/foo.runfiles/workspace/treeArtifact/file2"), + file2); + } + @Test public void testRunfilesWithArchivedTreeArtifacts() throws Exception { SpecialArtifact treeArtifact = createTreeArtifact("treeArtifact"); @@ -335,6 +475,7 @@ public ArchivedTreeArtifact getArchivedTreeArtifact(SpecialArtifact treeArtifact supplier, new FakeActionInputFileCache(), artifactExpander, + PathMapper.NOOP, PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(1); assertThat(inputMappings) @@ -367,7 +508,12 @@ public void testRunfilesWithTreeArtifactsInSymlinks() throws Exception { fakeCache.put(file2, FileArtifactValue.createForTesting(file2)); expander.addRunfilesToInputs( - inputMappings, supplier, fakeCache, artifactExpander, PathFragment.EMPTY_FRAGMENT); + inputMappings, + supplier, + fakeCache, + artifactExpander, + PathMapper.NOOP, + PathFragment.EMPTY_FRAGMENT); assertThat(inputMappings).hasSize(2); assertThat(inputMappings) .containsEntry(PathFragment.create("runfiles/workspace/symlink/file1"), file1); diff --git a/src/test/java/com/google/devtools/build/lib/exec/util/SpawnBuilder.java b/src/test/java/com/google/devtools/build/lib/exec/util/SpawnBuilder.java index 294ba3396ac4a6..0a8b407d64124a 100644 --- a/src/test/java/com/google/devtools/build/lib/exec/util/SpawnBuilder.java +++ b/src/test/java/com/google/devtools/build/lib/exec/util/SpawnBuilder.java @@ -61,7 +61,7 @@ public final class SpawnBuilder { private RunfilesSupplier runfilesSupplier = EmptyRunfilesSupplier.INSTANCE; private ResourceSet resourceSet = ResourceSet.ZERO; - private PathMapper pathMapper; + private PathMapper pathMapper = PathMapper.NOOP; private boolean builtForToolConfiguration; /** diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java index 3780956a765056..d8fb493413f87e 100644 --- a/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java +++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java @@ -67,6 +67,7 @@ import com.google.devtools.build.lib.actions.ArtifactRoot.RootType; import com.google.devtools.build.lib.actions.EmptyRunfilesSupplier; import com.google.devtools.build.lib.actions.ExecutionRequirements; +import com.google.devtools.build.lib.actions.PathMapper; import com.google.devtools.build.lib.actions.ResourceSet; import com.google.devtools.build.lib.actions.SimpleSpawn; import com.google.devtools.build.lib.actions.Spawn; @@ -2081,12 +2082,21 @@ public void buildMerkleTree_withMemoization_works() throws Exception { verify(service, times(6)).uncachedBuildMerkleTreeVisitor(any(), any(), any()); assertThat(service.getMerkleTreeCache().asMap().keySet()) .containsExactly( - ImmutableList.of(ImmutableMap.of(), PathFragment.EMPTY_FRAGMENT), // fileset mapping - ImmutableList.of(EmptyRunfilesSupplier.INSTANCE, PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(tree, PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(nodeRoot1.toNode(), PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(nodeFoo1.toNode(), PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(nodeBar.toNode(), PathFragment.EMPTY_FRAGMENT)); + ImmutableList.of( + ImmutableMap.of(), + PathFragment.EMPTY_FRAGMENT, + PathMapper.NOOP.getClass()), // fileset mapping + ImmutableList.of( + EmptyRunfilesSupplier.INSTANCE, + PathFragment.EMPTY_FRAGMENT, + PathMapper.NOOP.getClass()), + ImmutableList.of(tree, PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass()), + ImmutableList.of( + nodeRoot1.toNode(), PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass()), + ImmutableList.of( + nodeFoo1.toNode(), PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass()), + ImmutableList.of( + nodeBar.toNode(), PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass())); // act second time service.buildRemoteAction(spawn2, context2); @@ -2095,14 +2105,25 @@ public void buildMerkleTree_withMemoization_works() throws Exception { verify(service, times(6 + 2)).uncachedBuildMerkleTreeVisitor(any(), any(), any()); assertThat(service.getMerkleTreeCache().asMap().keySet()) .containsExactly( - ImmutableList.of(ImmutableMap.of(), PathFragment.EMPTY_FRAGMENT), // fileset mapping - ImmutableList.of(EmptyRunfilesSupplier.INSTANCE, PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(tree, PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(nodeRoot1.toNode(), PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(nodeRoot2.toNode(), PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(nodeFoo1.toNode(), PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(nodeFoo2.toNode(), PathFragment.EMPTY_FRAGMENT), - ImmutableList.of(nodeBar.toNode(), PathFragment.EMPTY_FRAGMENT)); + ImmutableList.of( + ImmutableMap.of(), + PathFragment.EMPTY_FRAGMENT, + PathMapper.NOOP.getClass()), // fileset mapping + ImmutableList.of( + EmptyRunfilesSupplier.INSTANCE, + PathFragment.EMPTY_FRAGMENT, + PathMapper.NOOP.getClass()), + ImmutableList.of(tree, PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass()), + ImmutableList.of( + nodeRoot1.toNode(), PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass()), + ImmutableList.of( + nodeRoot2.toNode(), PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass()), + ImmutableList.of( + nodeFoo1.toNode(), PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass()), + ImmutableList.of( + nodeFoo2.toNode(), PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass()), + ImmutableList.of( + nodeBar.toNode(), PathFragment.EMPTY_FRAGMENT, PathMapper.NOOP.getClass())); } @Test