diff options
author | László Csomor <laszlocsomor@google.com> | 2017-08-31 14:35:12 +0200 |
---|---|---|
committer | Vladimir Moskva <vladmos@google.com> | 2017-08-31 18:25:48 +0200 |
commit | 36c2ac577fc1da711b47aeb42928f678ca164deb (patch) | |
tree | e23b0e86019f301aae0dec600e7fe3a81a710ff0 /src/main | |
parent | 2fec2c71d3f00af694ebe4f0d99699aaafded2c4 (diff) |
Skylark: ctx.actions.run_shell uses helper script
If the shell command in
ctx.actions.run_shell.command is longer than the
platform's shell's limit, Bazel will dump the
command to a helper shell script and execute that
script in the run_shell action.
Genrules also write a helper script when
genrule.cmd is longer than the shell's limit, and
ctx.actions.run_shell now uses the same machinery.
Fixes https://github.com/bazelbuild/bazel/issues/3589
Change-Id: Ib24dce90182ef69552deb2d400e00ae061537309
PiperOrigin-RevId: 167126560
Diffstat (limited to 'src/main')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java | 21 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java | 32 |
2 files changed, 48 insertions, 5 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java b/src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java index 70afd0f1b3..330c017a1d 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/CommandHelper.java @@ -246,6 +246,27 @@ public final class CommandHelper { } /** + * If {@code command} is too long, creates a helper shell script that runs that command. + * + * <p>Returns the {@link Artifact} corresponding to that script. + * + * <p>Otherwise, when {@code command} is shorter than the platform's shell's command length limit, + * this method does nothing and returns null. + */ + @Nullable + public static Artifact shellCommandHelperScriptMaybe( + RuleContext ruleCtx, + String command, + String scriptPostFix, + Map<String, String> executionInfo) { + if (command.length() <= maxCommandLength) { + return null; + } else { + return buildCommandLineArtifact(ruleCtx, command, scriptPostFix); + } + } + + /** * Builds the set of command-line arguments. Creates a bash script if the * command line is longer than the allowed maximum {@link #maxCommandLength}. * Fixes up the input artifact list with the created bash script when required. diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java index 88080e05eb..2433cdb6c7 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java @@ -20,6 +20,7 @@ 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.actions.extra.SpawnInfo; +import com.google.devtools.build.lib.analysis.CommandHelper; import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.PseudoAction; import com.google.devtools.build.lib.analysis.RuleContext; @@ -34,6 +35,7 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.events.EventHandler; import com.google.devtools.build.lib.events.Location; +import com.google.devtools.build.lib.packages.TargetUtils; import com.google.devtools.build.lib.skylarkinterface.Param; import com.google.devtools.build.lib.skylarkinterface.ParamType; import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; @@ -72,6 +74,8 @@ public class SkylarkActionFactory implements SkylarkValue { private final SkylarkRuleContext context; private final SkylarkSemanticsOptions skylarkSemanticsOptions; private RuleContext ruleContext; + /** Counter for actions.run_shell helper scripts. Every script must have a unique name. */ + private int runShellOutputCounter = 0; public SkylarkActionFactory( SkylarkRuleContext context, @@ -573,7 +577,23 @@ public class SkylarkActionFactory implements SkylarkValue { } if (commandUnchecked instanceof String) { - builder.setShellCommand((String) commandUnchecked); + Map<String, String> executionInfo = + ImmutableMap.copyOf(TargetUtils.getExecutionInfo(ruleContext.getRule())); + String helperScriptSuffix = String.format(".run_shell_%d.sh", runShellOutputCounter++); + String command = (String) commandUnchecked; + Artifact helperScript = + CommandHelper.shellCommandHelperScriptMaybe( + ruleContext, command, helperScriptSuffix, executionInfo); + if (helperScript == null) { + builder.setShellCommand(command); + } else { + builder.setShellCommand(helperScript.getExecPathString()); + builder.addInput(helperScript); + FilesToRunProvider provider = context.getExecutableRunfiles(helperScript); + if (provider != null) { + builder.addTool(provider); + } + } } else if (commandUnchecked instanceof SkylarkList) { SkylarkList commandList = (SkylarkList) commandUnchecked; if (commandList.size() < 3) { @@ -601,18 +621,20 @@ public class SkylarkActionFactory implements SkylarkValue { } /** - * Stup for spawn actions common between {@link #run} and {@link #runShell}. + * Setup for spawn actions common between {@link #run} and {@link #runShell}. * - * {@code builder} should have either executable or a command set. + * <p>{@code builder} should have either executable or a command set. */ private void registerSpawnAction( SkylarkList outputs, Object inputs, Object mnemonicUnchecked, Object progressMessage, - Boolean useDefaultShellEnv, Object envUnchecked, + Boolean useDefaultShellEnv, + Object envUnchecked, Object executionRequirementsUnchecked, - Object inputManifestsUnchecked, SpawnAction.Builder builder) + Object inputManifestsUnchecked, + SpawnAction.Builder builder) throws EvalException { // TODO(bazel-team): builder still makes unnecessary copies of inputs, outputs and args. Iterable<Artifact> inputArtifacts; |