diff options
author | 2016-05-19 15:33:38 +0000 | |
---|---|---|
committer | 2016-05-19 18:03:22 +0000 | |
commit | 6d42e336ed540fd5abfcd1bd208a6cadc41206cc (patch) | |
tree | a77d194a83659f15d5719901fa4561573fe585d4 | |
parent | 584259f8955399b8132a0385fe7aa7d188dc074c (diff) |
CommandLine: Add support for tree artifact expansions.
ParameterFileWriteAction: Add support to write out CommandLine with tree artifact expansions.
--
MOS_MIGRATED_REVID=122734422
6 files changed, 421 insertions, 40 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/CommandLine.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/CommandLine.java index 0eb8c4bac9..53adca39bd 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/actions/CommandLine.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/CommandLine.java @@ -17,6 +17,7 @@ package com.google.devtools.build.lib.analysis.actions; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; import com.google.devtools.build.lib.collect.CollectionUtils; import com.google.devtools.build.lib.util.Preconditions; @@ -30,6 +31,18 @@ public abstract class CommandLine { public abstract Iterable<String> arguments(); /** + * Returns the evaluated command line with enclosed artifacts expanded by {@code artifactExpander} + * at execution time. + * + * <p>By default, this method just delegates to {@link #arguments()}, without performing any + * artifact expansion. Subclasses should override this method if they contain TreeArtifacts and + * need to expand them for proper argument evaluation. + */ + public Iterable<String> arguments(ArtifactExpander artifactExpander) { + return arguments(); + } + + /** * Returns whether the command line represents a shell command with the given shell executable. * This is used to give better error messages. * @@ -89,6 +102,11 @@ public abstract class CommandLine { } @Override + public Iterable<String> arguments(ArtifactExpander artifactExpander) { + return Iterables.concat(executableArgs, commandLine.arguments(artifactExpander)); + } + + @Override public boolean isShellCommand() { return isShellCommand; } 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 3ee894640f..2af93fe92b 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 @@ -19,6 +19,7 @@ import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.CollectionUtils; @@ -30,6 +31,10 @@ import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import javax.annotation.Nullable; /** * A customizable, serializable class for building memory efficient command lines. @@ -41,7 +46,6 @@ public final class CustomCommandLine extends CommandLine { abstract void eval(ImmutableList.Builder<String> builder); } - /** * A command line argument for {@link TreeFileArtifact}. * @@ -61,6 +65,43 @@ public final class CustomCommandLine extends CommandLine { abstract Object substituteTreeArtifact(Map<Artifact, TreeFileArtifact> substitutionMap); } + /** + * A command line argument that can expand enclosed TreeArtifacts into a list of child + * {@link TreeFileArtifact}s at execution time before argument evaluation. + * + * <p>The main difference between this class and {@link TreeFileArtifactArgvFragment} is that + * {@link TreeFileArtifactArgvFragment} is used in {@link SpawnActionTemplate} to substitutes a + * TreeArtifact with *one* of its child TreeFileArtifacts, while this class expands a TreeArtifact + * into *all* of its child TreeFileArtifacts. + * + */ + private abstract static class TreeArtifactExpansionArgvFragment extends ArgvFragment { + /** + * Evaluates this argument fragment into an argument string and adds it into {@code builder}. + * The enclosed TreeArtifact will be expanded using {@code artifactExpander}. + */ + abstract void eval(ImmutableList.Builder<String> builder, ArtifactExpander artifactExpander); + + /** + * Returns a string that describes this argument fragment. The string can be used as part of + * an action key for the command line at analysis time. + */ + abstract String describe(); + + /** + * Evaluates this argument fragment by serializing it into a string. Note that the returned + * argument is not suitable to be used as part of an actual command line. The purpose of this + * method is to provide a unique command line argument string to be used as part of an action + * key at analysis time. + * + * <p>Internally this method just calls {@link #describe}. + */ + @Override + void eval(ImmutableList.Builder<String> builder) { + builder.add(describe()); + } + } + // It's better to avoid anonymous classes if we want to serialize command lines private static final class JoinExecPathsArg extends ArgvFragment { @@ -78,6 +119,40 @@ public final class CustomCommandLine extends CommandLine { } } + private static final class JoinExpandedTreeArtifactExecPathsArg + extends TreeArtifactExpansionArgvFragment { + + private final String delimiter; + private final Artifact treeArtifact; + + private JoinExpandedTreeArtifactExecPathsArg(String delimiter, Artifact treeArtifact) { + Preconditions.checkArgument( + treeArtifact.isTreeArtifact(), "%s is not a TreeArtifact", treeArtifact); + this.delimiter = delimiter; + this.treeArtifact = treeArtifact; + } + + @Override + void eval(ImmutableList.Builder<String> builder, ArtifactExpander artifactExpander) { + Set<Artifact> expandedArtifacts = new TreeSet<>(); + artifactExpander.expand(treeArtifact, expandedArtifacts); + Preconditions.checkState( + !expandedArtifacts.isEmpty(), + "%s expanded into nothing, maybe it's not added as a input for the associated action?", + treeArtifact); + + builder.add(Artifact.joinExecPaths(delimiter, expandedArtifacts)); + } + + @Override + public String describe() { + return String.format( + "JoinExpandedTreeArtifactExecPathsArg{ delimiter: %s, treeArtifact: %s}", + delimiter, + treeArtifact.getExecPathString()); + } + } + private static final class PathWithTemplateArg extends ArgvFragment { private final String template; @@ -424,6 +499,18 @@ public final class CustomCommandLine extends CommandLine { return this; } + /** + * Adds a string joined together by the exec paths of all {@link TreeFileArtifact}s under + * {@code treeArtifact}. + * + * @param delimiter the delimiter used to join the artifact exec paths. + * @param treeArtifact the TreeArtifact containing the {@link TreeFileArtifact}s to join. + */ + public Builder addJoinExpandedTreeArtifactExecPath(String delimiter, Artifact treeArtifact) { + arguments.add(new JoinExpandedTreeArtifactExecPathsArg(delimiter, treeArtifact)); + return this; + } + public Builder addBeforeEachPath(String repeated, Iterable<PathFragment> paths) { if (repeated != null && paths != null) { arguments.add(InterspersingArgs.fromStrings(paths, repeated, "%s")); @@ -515,11 +602,27 @@ public final class CustomCommandLine extends CommandLine { @Override public Iterable<String> arguments() { + return argumentsInternal(null); + } + + @Override + public Iterable<String> arguments(ArtifactExpander artifactExpander) { + return argumentsInternal(Preconditions.checkNotNull(artifactExpander)); + } + + private Iterable<String> argumentsInternal(@Nullable ArtifactExpander artifactExpander) { ImmutableList.Builder<String> builder = ImmutableList.builder(); for (Object arg : arguments) { Object substitutedArg = substituteTreeFileArtifactArgvFragment(arg); if (substitutedArg instanceof ArgvFragment) { - ((ArgvFragment) substitutedArg).eval(builder); + if (artifactExpander != null + && substitutedArg instanceof TreeArtifactExpansionArgvFragment) { + TreeArtifactExpansionArgvFragment expansionArg = + (TreeArtifactExpansionArgvFragment) substitutedArg; + expansionArg.eval(builder, artifactExpander); + } else { + ((ArgvFragment) substitutedArg).eval(builder); + } } else { builder.add(substitutedArg.toString()); } diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParameterFileWriteAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParameterFileWriteAction.java index 2a1c9b8e21..659dae632d 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParameterFileWriteAction.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParameterFileWriteAction.java @@ -16,12 +16,16 @@ package com.google.devtools.build.lib.analysis.actions; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.ActionExecutionContext; import com.google.devtools.build.lib.actions.ActionOwner; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; +import com.google.devtools.build.lib.analysis.actions.AbstractFileWriteAction.DeterministicWriter; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.util.Fingerprint; +import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.lib.util.ShellEscaper; import java.io.IOException; @@ -40,6 +44,7 @@ public final class ParameterFileWriteAction extends AbstractFileWriteAction { private final CommandLine commandLine; private final ParameterFileType type; private final Charset charset; + private final boolean hasInputArtifactToExpand; /** * Creates a new instance. @@ -52,10 +57,27 @@ public final class ParameterFileWriteAction extends AbstractFileWriteAction { */ public ParameterFileWriteAction(ActionOwner owner, Artifact output, CommandLine commandLine, ParameterFileType type, Charset charset) { - super(owner, ImmutableList.<Artifact>of(), output, false); + this(owner, ImmutableList.<Artifact>of(), output, commandLine, type, charset); + } + + /** + * Creates a new instance. + * + * @param owner the action owner + * @param inputs the list of TreeArtifacts that must be resolved and expanded before evaluating + * the contents of {@link commandLine}. + * @param output the Artifact that will be created by executing this Action + * @param commandLine the contents to be written to the file + * @param type the type of the file + * @param charset the charset of the file + */ + public ParameterFileWriteAction(ActionOwner owner, Iterable<Artifact> inputs, Artifact output, + CommandLine commandLine, ParameterFileType type, Charset charset) { + super(owner, ImmutableList.copyOf(inputs), output, false); this.commandLine = commandLine; this.type = type; this.charset = charset; + this.hasInputArtifactToExpand = !Iterables.isEmpty(inputs); } /** @@ -65,51 +87,73 @@ public final class ParameterFileWriteAction extends AbstractFileWriteAction { */ @VisibleForTesting public Iterable<String> getContents() { + Preconditions.checkState( + !hasInputArtifactToExpand, + "This action contains a CommandLine with TreeArtifacts: %s, which must be expanded using " + + "ArtifactExpander first before we can evaluate the CommandLine.", + getInputs()); return commandLine.arguments(); } + @VisibleForTesting + public Iterable<String> getContents(ArtifactExpander artifactExpander) { + return commandLine.arguments(artifactExpander); + } + @Override public DeterministicWriter newDeterministicWriter(ActionExecutionContext ctx) { - return new DeterministicWriter() { - @Override - public void writeOutputFile(OutputStream out) throws IOException { - switch (type) { - case SHELL_QUOTED : - writeContentQuoted(out); - break; - case UNQUOTED : - writeContentUnquoted(out); - break; - default : - throw new AssertionError(); - } - } - }; + return new ParamFileWriter(Preconditions.checkNotNull(ctx.getArtifactExpander())); } - /** - * Writes the arguments from the list into the parameter file. - */ - private void writeContentUnquoted(OutputStream outputStream) throws IOException { - OutputStreamWriter out = new OutputStreamWriter(outputStream, charset); - for (String line : commandLine.arguments()) { - out.write(line); - out.write('\n'); + private class ParamFileWriter implements DeterministicWriter { + private final ArtifactExpander artifactExpander; + + ParamFileWriter(ArtifactExpander artifactExpander) { + this.artifactExpander = artifactExpander; } - out.flush(); - } - /** - * Writes the arguments from the list into the parameter file with shell - * quoting (if required). - */ - private void writeContentQuoted(OutputStream outputStream) throws IOException { - OutputStreamWriter out = new OutputStreamWriter(outputStream, charset); - for (String line : ShellEscaper.escapeAll(commandLine.arguments())) { - out.write(line); - out.write('\n'); + @Override + public void writeOutputFile(OutputStream out) throws IOException { + Iterable<String> arguments = commandLine.arguments(artifactExpander); + + switch (type) { + case SHELL_QUOTED : + writeContentQuoted(out, arguments); + break; + case UNQUOTED : + writeContentUnquoted(out, arguments); + break; + default : + throw new AssertionError(); + } + } + + /** + * Writes the arguments from the list into the parameter file. + */ + private void writeContentUnquoted(OutputStream outputStream, Iterable<String> arguments) + throws IOException { + OutputStreamWriter out = new OutputStreamWriter(outputStream, charset); + for (String line : arguments) { + out.write(line); + out.write('\n'); + } + out.flush(); + } + + /** + * Writes the arguments from the list into the parameter file with shell + * quoting (if required). + */ + private void writeContentQuoted(OutputStream outputStream, Iterable<String> arguments) + throws IOException { + OutputStreamWriter out = new OutputStreamWriter(outputStream, charset); + for (String line : ShellEscaper.escapeAll(arguments)) { + out.write(line); + out.write('\n'); + } + out.flush(); } - out.flush(); } @Override 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 2af98f4b5a..531baefda5 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 @@ -18,9 +18,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact; import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType; import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; +import com.google.devtools.build.lib.analysis.actions.CommandLine; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.CustomArgv; import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.CustomMultiArgv; @@ -35,6 +37,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.Collection; + /** * Tests for CustomCommandLine. */ @@ -238,6 +242,39 @@ public class CustomCommandLineTest { } + @Test + public void testJoinExpandedTreeArtifactExecPath() { + Artifact treeArtifact = createTreeArtifact("myTreeArtifact"); + + CommandLine commandLine = CustomCommandLine.builder() + .add("hello") + .addJoinExpandedTreeArtifactExecPath(":", treeArtifact) + .build(); + + assertThat(commandLine.arguments()).containsExactly( + "hello", + "JoinExpandedTreeArtifactExecPathsArg{ delimiter: :, treeArtifact: myTreeArtifact}"); + + final Iterable<TreeFileArtifact> treeFileArtifacts = ImmutableList.of( + createTreeFileArtifact(treeArtifact, "children/child1"), + createTreeFileArtifact(treeArtifact, "children/child2")); + + ArtifactExpander artifactExpander = new ArtifactExpander() { + @Override + public void expand(Artifact artifact, Collection<? super Artifact> output) { + for (TreeFileArtifact treeFileArtifact : treeFileArtifacts) { + if (treeFileArtifact.getParent().equals(artifact)) { + output.add(treeFileArtifact); + } + } + } + }; + + assertThat(commandLine.arguments(artifactExpander)).containsExactly( + "hello", + "myTreeArtifact/children/child1:myTreeArtifact/children/child2"); + } + private Artifact createTreeArtifact(String rootRelativePath) { PathFragment relpath = new PathFragment(rootRelativePath); return new SpecialArtifact( diff --git a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java index aae837f087..0ba8f7a20c 100644 --- a/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java +++ b/src/test/java/com/google/devtools/build/lib/actions/util/ActionsTestUtil.java @@ -31,6 +31,7 @@ import com.google.devtools.build.lib.actions.ActionGraph; import com.google.devtools.build.lib.actions.ActionInputHelper; import com.google.devtools.build.lib.actions.ActionOwner; import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; import com.google.devtools.build.lib.actions.ArtifactOwner; import com.google.devtools.build.lib.actions.Executor; import com.google.devtools.build.lib.actions.MutableActionGraph; @@ -91,7 +92,7 @@ public final class ActionsTestUtil { metadataHandler, fileOutErr, actionGraph == null - ? null + ? createDummyArtifactExpander() : ActionInputHelper.actionGraphArtifactExpander(actionGraph)); } @@ -108,7 +109,17 @@ public final class ActionsTestUtil { public static ActionExecutionContext createContext(EventHandler eventHandler) { DummyExecutor dummyExecutor = new DummyExecutor(eventHandler); - return new ActionExecutionContext(dummyExecutor, null, null, null, null); + return new ActionExecutionContext( + dummyExecutor, null, null, null, createDummyArtifactExpander()); + } + + private static ArtifactExpander createDummyArtifactExpander() { + return new ArtifactExpander() { + @Override + public void expand(Artifact artifact, Collection<? super Artifact> output) { + return; + } + }; } diff --git a/src/test/java/com/google/devtools/build/lib/analysis/actions/ParamFileWriteActionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/actions/ParamFileWriteActionTest.java new file mode 100644 index 0000000000..21b79759fd --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/analysis/actions/ParamFileWriteActionTest.java @@ -0,0 +1,168 @@ +// Copyright 2015 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.analysis.actions; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.actions.Action; +import com.google.devtools.build.lib.actions.ActionExecutionContext; +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.Artifact.SpecialArtifact; +import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType; +import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact; +import com.google.devtools.build.lib.actions.ArtifactOwner; +import com.google.devtools.build.lib.actions.Executor; +import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; +import com.google.devtools.build.lib.actions.Root; +import com.google.devtools.build.lib.actions.util.ActionsTestUtil; +import com.google.devtools.build.lib.analysis.util.BuildViewTestCase; +import com.google.devtools.build.lib.exec.util.TestExecutorBuilder; +import com.google.devtools.build.lib.util.io.FileOutErr; +import com.google.devtools.build.lib.vfs.FileSystemUtils; +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.nio.charset.StandardCharsets; +import java.util.Collection; + +/** Tests for ParamFileWriteAction. */ +@RunWith(JUnit4.class) +public class ParamFileWriteActionTest extends BuildViewTestCase { + private Root rootDir; + private Artifact outputArtifact; + private Artifact treeArtifact; + + @Before + public void createArtifacts() throws Exception { + rootDir = Root.asDerivedRoot(scratch.dir("/exec/root")); + outputArtifact = getBinArtifactWithNoOwner("destination.txt"); + FileSystemUtils.createDirectoryAndParents(outputArtifact.getPath().getParentDirectory()); + treeArtifact = createTreeArtifact("artifact/myTreeFileArtifact"); + } + + + @Test + public void testOutputs() { + Action action = createParameterFileWriteAction( + ImmutableList.<Artifact>of(), createNormalCommandLine()); + assertThat(Artifact.toRootRelativePaths(action.getOutputs())).containsExactly( + "destination.txt"); + } + + @Test + public void testInputs() { + Action action = createParameterFileWriteAction( + ImmutableList.of(treeArtifact), + createTreeArtifactExpansionCommandLine()); + assertThat(Artifact.toExecPaths(action.getInputs())).containsExactly( + "artifact/myTreeFileArtifact"); + } + + @Test + public void testWriteCommandLineWithoutTreeArtifactExpansion() throws Exception { + Action action = createParameterFileWriteAction( + ImmutableList.<Artifact>of(), createNormalCommandLine()); + ActionExecutionContext context = actionExecutionContext(); + action.execute(context); + String content = new String(FileSystemUtils.readContentAsLatin1(outputArtifact.getPath())); + assertEquals("--flag1\n--flag2\n--flag3\nvalue1\nvalue2", content.trim()); + } + + @Test + public void testWriteCommandLineWithTreeArtifactExpansion() throws Exception { + Action action = createParameterFileWriteAction( + ImmutableList.of(treeArtifact), + createTreeArtifactExpansionCommandLine()); + ActionExecutionContext context = actionExecutionContext(); + action.execute(context); + String content = new String(FileSystemUtils.readContentAsLatin1(outputArtifact.getPath())); + assertEquals( + "--flag1\n" + + "artifact/myTreeFileArtifact/artifacts/treeFileArtifact1:" + + "artifact/myTreeFileArtifact/artifacts/treeFileArtifact2", + content.trim()); + } + + private Artifact createTreeArtifact(String rootRelativePath) { + PathFragment relpath = new PathFragment(rootRelativePath); + return new SpecialArtifact( + rootDir.getPath().getRelative(relpath), + rootDir, + rootDir.getExecPath().getRelative(relpath), + ArtifactOwner.NULL_OWNER, + SpecialArtifactType.TREE); + } + + private TreeFileArtifact createTreeFileArtifact( + Artifact inputTreeArtifact, String parentRelativePath) { + return ActionInputHelper.treeFileArtifact( + inputTreeArtifact, + new PathFragment(parentRelativePath)); + } + + private ParameterFileWriteAction createParameterFileWriteAction( + Iterable<Artifact> inputTreeArtifacts, CommandLine commandLine) { + return new ParameterFileWriteAction( + ActionsTestUtil.NULL_ACTION_OWNER, + inputTreeArtifacts, + outputArtifact, + commandLine, + ParameterFileType.UNQUOTED, + StandardCharsets.ISO_8859_1); + } + + private CommandLine createNormalCommandLine() { + return CustomCommandLine.builder() + .add("--flag1") + .add("--flag2") + .add("--flag3", ImmutableList.of("value1", "value2")) + .build(); + } + + private CommandLine createTreeArtifactExpansionCommandLine() { + return CustomCommandLine.builder() + .add("--flag1") + .addJoinExpandedTreeArtifactExecPath(":", treeArtifact) + .build(); + } + + private ActionExecutionContext actionExecutionContext() throws Exception { + final Iterable<TreeFileArtifact> treeFileArtifacts = ImmutableList.of( + createTreeFileArtifact(treeArtifact, "artifacts/treeFileArtifact1"), + createTreeFileArtifact(treeArtifact, "artifacts/treeFileArtifact2")); + + ArtifactExpander artifactExpander = new ArtifactExpander() { + @Override + public void expand(Artifact artifact, Collection<? super Artifact> output) { + for (TreeFileArtifact treeFileArtifact : treeFileArtifacts) { + if (treeFileArtifact.getParent().equals(artifact)) { + output.add(treeFileArtifact); + } + } + } + }; + + Executor executor = new TestExecutorBuilder(directories, binTools).build(); + return new ActionExecutionContext( + executor, null, null, new FileOutErr(), artifactExpander); + } +} |