diff options
5 files changed, 202 insertions, 19 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java b/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java index 62c60e40fd..9221ae5d41 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java +++ b/src/main/java/com/google/devtools/build/lib/actions/BaseSpawn.java @@ -30,7 +30,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; /** @@ -100,24 +99,6 @@ public class BaseSpawn implements Spawn { public BaseSpawn(List<String> arguments, Map<String, String> environment, Map<String, String> executionInfo, - // TODO(bazel-team): have this always be non-null. - @Nullable Artifact runfilesManifest, - ActionMetadata action, - ResourceSet localResources) { - this(arguments, environment, executionInfo, - ((runfilesManifest != null) - ? ImmutableMap.of(runfilesForFragment(new PathFragment(arguments.get(0))), - runfilesManifest) - : ImmutableMap.<PathFragment, Artifact>of()), - action, localResources); - } - - /** - * Returns a new Spawn. - */ - public BaseSpawn(List<String> arguments, - Map<String, String> environment, - Map<String, String> executionInfo, ActionMetadata action, ResourceSet localResources) { this(arguments, environment, executionInfo, diff --git a/src/main/java/com/google/devtools/build/lib/analysis/CompositeRunfilesSupplier.java b/src/main/java/com/google/devtools/build/lib/analysis/CompositeRunfilesSupplier.java new file mode 100644 index 0000000000..51307b8cad --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/analysis/CompositeRunfilesSupplier.java @@ -0,0 +1,63 @@ +// Copyright 2015 Google Inc. 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.analysis; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Maps; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.RunfilesSupplier; +import com.google.devtools.build.lib.vfs.PathFragment; + +import java.io.IOException; +import java.util.Map; + +/** RunfilesSupplier implementation composing instances. */ +public class CompositeRunfilesSupplier implements RunfilesSupplier { + + private final RunfilesSupplier first; + private final RunfilesSupplier second; + + /** Create an instance with {@code first} taking precedence over {@code second}. */ + public CompositeRunfilesSupplier(RunfilesSupplier first, RunfilesSupplier second) { + this.first = Preconditions.checkNotNull(first); + this.second = Preconditions.checkNotNull(second); + } + + @Override + public Iterable<Artifact> getArtifacts() { + ImmutableSet.Builder<Artifact> result = ImmutableSet.builder(); + result.addAll(first.getArtifacts()); + result.addAll(second.getArtifacts()); + return result.build(); + } + + @Override + public ImmutableSet<PathFragment> getRunfilesDirs() { + ImmutableSet.Builder<PathFragment> result = ImmutableSet.builder(); + result.addAll(first.getRunfilesDirs()); + result.addAll(second.getRunfilesDirs()); + return result.build(); + } + + @Override + public ImmutableMap<PathFragment, Map<PathFragment, Artifact>> getMappings() throws IOException { + Map<PathFragment, Map<PathFragment, Artifact>> result = Maps.newHashMap(); + result.putAll(second.getMappings()); + result.putAll(first.getMappings()); + return ImmutableMap.copyOf(result); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/analysis/FilesToRunProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/FilesToRunProvider.java index c915cae16f..216a782e92 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/FilesToRunProvider.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/FilesToRunProvider.java @@ -16,6 +16,8 @@ package com.google.devtools.build.lib.analysis; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.EmptyRunfilesSupplier; +import com.google.devtools.build.lib.actions.RunfilesSupplier; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.syntax.Label; @@ -84,4 +86,13 @@ public final class FilesToRunProvider implements TransitiveInfoProvider { @Nullable public Artifact getRunfilesManifest() { return runfilesSupport != null ? runfilesSupport.getRunfilesManifest() : null; } + + /** Return a {@link RunfilesSupplier} encapsulating runfiles for this tool. */ + public RunfilesSupplier getRunfilesSupplier() { + if (executable != null && runfilesSupport != null) { + return new RunfilesSupplierImpl(executable, runfilesSupport.getRunfiles()); + } else { + return EmptyRunfilesSupplier.INSTANCE; + } + } } diff --git a/src/test/java/BUILD b/src/test/java/BUILD index 1f2620d768..5bdb5a693f 100644 --- a/src/test/java/BUILD +++ b/src/test/java/BUILD @@ -356,6 +356,7 @@ java_test( "//third_party:guava-testlib", "//third_party:jsr305", "//third_party:junit4", + "//third_party:mockito", "//third_party:truth", ], ) diff --git a/src/test/java/com/google/devtools/build/lib/analysis/CompositeRunfilesSupplierTest.java b/src/test/java/com/google/devtools/build/lib/analysis/CompositeRunfilesSupplierTest.java new file mode 100644 index 0000000000..f2d7d9c452 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/analysis/CompositeRunfilesSupplierTest.java @@ -0,0 +1,127 @@ +// Copyright 2015 Google Inc. 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.analysis; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.Root; +import com.google.devtools.build.lib.actions.RunfilesSupplier; +import com.google.devtools.build.lib.testutil.Scratch; +import com.google.devtools.build.lib.vfs.PathFragment; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** Tests for CompositeRunfilesSupplier */ +@RunWith(JUnit4.class) +public class CompositeRunfilesSupplierTest { + + private RunfilesSupplier mockFirst; + private RunfilesSupplier mockSecond; + + private Root rootDir; + + private CompositeRunfilesSupplier underTest; + + @Before + public void setup() throws IOException { + Scratch scratch = new Scratch(); + rootDir = Root.asDerivedRoot(scratch.dir("/fake/root/dont/matter")); + + mockFirst = mock(RunfilesSupplier.class); + mockSecond = mock(RunfilesSupplier.class); + underTest = new CompositeRunfilesSupplier(mockFirst, mockSecond); + } + + @Test + public void testGetArtifactsReturnsCombinedArtifacts() { + when(mockFirst.getArtifacts()).thenReturn(mkArtifacts(rootDir, "first", "shared")); + when(mockSecond.getArtifacts()).thenReturn(mkArtifacts(rootDir, "second", "shared")); + + assertThat(underTest.getArtifacts()).containsExactlyElementsIn( + mkArtifacts(rootDir, "first", "second", "shared")); + } + + @Test + public void testGetRunfilesDirsReturnsCombinedPaths() { + PathFragment first = new PathFragment("first"); + PathFragment second = new PathFragment("second"); + PathFragment shared = new PathFragment("shared"); + + when(mockFirst.getRunfilesDirs()).thenReturn(ImmutableSet.of(first, shared)); + when(mockSecond.getRunfilesDirs()).thenReturn(ImmutableSet.of(second, shared)); + + assertThat(underTest.getRunfilesDirs()).containsExactlyElementsIn( + ImmutableSet.of(first, second, shared)); + } + + @Test + public void testGetMappingsReturnsMappingsWithFirstPrecedenceOverSecond() throws IOException { + PathFragment first = new PathFragment("first"); + Map<PathFragment, Artifact> firstMappings = mkMappings(rootDir, "first1", "first2"); + + PathFragment second = new PathFragment("second"); + Map<PathFragment, Artifact> secondMappings = mkMappings(rootDir, "second1", "second2"); + + PathFragment shared = new PathFragment("shared"); + Map<PathFragment, Artifact> firstSharedMappings = mkMappings(rootDir, "shared1", "shared2"); + Map<PathFragment, Artifact> secondSharedMappings = mkMappings(rootDir, "lost1", "lost2"); + + when(mockFirst.getMappings()).thenReturn(ImmutableMap.of( + first, firstMappings, + shared, firstSharedMappings)); + when(mockSecond.getMappings()).thenReturn(ImmutableMap.of( + second, secondMappings, + shared, secondSharedMappings)); + + // We expect the mappings for shared added by mockSecond to be dropped. + assertThat(underTest.getMappings()).isEqualTo(ImmutableMap.of( + first, firstMappings, + second, secondMappings, + shared, firstSharedMappings)); + } + + private static Map<PathFragment, Artifact> mkMappings(Root rootDir, String... paths) { + ImmutableMap.Builder<PathFragment, Artifact> builder = ImmutableMap.builder(); + for (String path : paths) { + builder.put(new PathFragment(path), mkArtifact(rootDir, path)); + } + return builder.build(); + } + + private static Artifact mkArtifact(Root rootDir, String path) { + return new Artifact(new PathFragment(path), rootDir); + } + + private static List<Artifact> mkArtifacts(Root rootDir, String... paths) { + ImmutableList.Builder<Artifact> builder = ImmutableList.builder(); + for (String path : paths) { + builder.add(mkArtifact(rootDir, path)); + } + return builder.build(); + } +} |