diff options
Diffstat (limited to 'src')
3 files changed, 77 insertions, 20 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java index d314388fe4..e6f9792637 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java @@ -15,6 +15,7 @@ package com.google.devtools.build.lib.analysis.actions; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -28,6 +29,7 @@ import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -282,6 +284,34 @@ public final class CustomCommandLine extends CommandLine { } } + private static final class JoinValuesTransformed<T> extends ArgvFragment { + + private final String delimiter; + private final Iterable<T> values; + private final Function<T, String> toString; + + private JoinValuesTransformed( + String delimiter, Iterable<T> values, Function<T, String> toString) { + this.delimiter = delimiter; + this.values = CollectionUtils.makeImmutable(values); + this.toString = toString; + } + + @Override + void eval(ImmutableList.Builder<String> builder) { + StringBuilder arg = new StringBuilder(); + Iterator<T> parts = values.iterator(); + if (parts.hasNext()) { + arg.append(toString.apply(parts.next())); + while (parts.hasNext()) { + arg.append(delimiter); + arg.append(toString.apply(parts.next())); + } + } + builder.add(arg.toString()); + } + } + /** * Arguments that intersperse strings between the items in a sequence. There are two forms of * interspersing, and either may be used by this implementation: @@ -480,6 +510,27 @@ public final class CustomCommandLine extends CommandLine { } return this; } + + /** + * Adds a list of values transformed by a function and delimited by a string. + * + * <p>Prefer this to transforming nested sets yourself as it is more memory-efficient. By using + * this class, expansion of the nested set is deferred until action execution instead of + * retained on the heap. + * + * @param arg The argument + * @param delimiter A delimiter string placed in between each transformed value + * @param values The values to expand into a list + * @param toString A function that transforms a value into a string + */ + public <T> Builder addJoinValues( + String arg, String delimiter, Iterable<T> values, Function<T, String> toString) { + if (arg != null && arguments != null) { + arguments.add(arg); + arguments.add(new JoinValuesTransformed<T>(delimiter, values, toString)); + } + return this; + } public Builder addJoinExecPaths(String arg, String delimiter, Iterable<Artifact> artifacts) { if (arg != null && artifacts != null) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainerConverter.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainerConverter.java index 028c6321a1..a78344077a 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainerConverter.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceContainerConverter.java @@ -20,7 +20,6 @@ import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; @@ -216,25 +215,13 @@ public class ResourceContainerConverter { ToArtifacts toArtifacts) { if (dependencies != null) { - // TODO(bazel-team): Find an appropriately lazy method to deduplicate the dependencies between - // the direct and transitive data. - // Add transitive data inside an unmodifiableIterable to ensure it won't be expanded until - // iteration. if (!dependencies.getTransitiveResources().isEmpty()) { - cmdBuilder.addJoinStrings( - "--data", - toArg.listSeparator(), - Iterables.unmodifiableIterable( - Iterables.transform(dependencies.getTransitiveResources(), toArg))); + cmdBuilder.addJoinValues( + "--data", toArg.listSeparator(), dependencies.getTransitiveResources(), toArg); } - // Add direct data inside an unmodifiableIterable to ensure it won't be expanded until - // iteration. if (!dependencies.getDirectResources().isEmpty()) { - cmdBuilder.addJoinStrings( - "--directData", - toArg.listSeparator(), - Iterables.unmodifiableIterable( - Iterables.transform(dependencies.getDirectResources(), toArg))); + cmdBuilder.addJoinValues( + "--directData", toArg.listSeparator(), dependencies.getDirectResources(), toArg); } // This flattens the nested set. Since each ResourceContainer needs to be transformed into // Artifacts, and the NestedSetBuilder.wrap doesn't support lazy Iterator evaluation diff --git a/src/test/java/com/google/devtools/build/lib/actions/CustomCommandLineTest.java b/src/test/java/com/google/devtools/build/lib/actions/CustomCommandLineTest.java index c0a808e921..eff6c637c1 100644 --- a/src/test/java/com/google/devtools/build/lib/actions/CustomCommandLineTest.java +++ b/src/test/java/com/google/devtools/build/lib/actions/CustomCommandLineTest.java @@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact; @@ -31,14 +32,13 @@ import com.google.devtools.build.lib.cmdline.LabelSyntaxException; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.testutil.Scratch; import com.google.devtools.build.lib.vfs.PathFragment; - +import java.util.Collection; +import javax.annotation.Nullable; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.util.Collection; - /** * Tests for CustomCommandLine. */ @@ -85,6 +85,25 @@ public class CustomCommandLineTest { } @Test + public void testJoinValues() { + CustomCommandLine cl = + CustomCommandLine.builder() + .addJoinValues( + "--path", + ":", + ImmutableList.of("foo", "bar", "baz"), + new Function<String, String>() { + @Nullable + @Override + public String apply(@Nullable String s) { + return s.toUpperCase(); + } + }) + .build(); + assertEquals(ImmutableList.of("--path", "FOO:BAR:BAZ"), cl.arguments()); + } + + @Test public void testArtifactExecPathArgs() { CustomCommandLine cl = CustomCommandLine.builder().addExecPath("--path", artifact1).build(); assertEquals(ImmutableList.of("--path", "dir/file1.txt"), cl.arguments()); |