sibling
is not specified, file name is relative to "
+ "package directory, otherwise the file is in the same directory as "
+ "sibling
. "
+ "You must create an action that generates the file. $1
, $2
, "
+ "etc. See ctx.actions.args()."
),
@Param(
name = "mnemonic",
type = String.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = "a one-word description of the action, e.g. CppCompile or GoLink."
),
@Param(
name = "command",
type = Object.class,
allowedTypes = {
@ParamType(type = String.class),
@ParamType(type = SkylarkList.class, generic1 = String.class),
@ParamType(type = Runtime.NoneType.class),
},
defaultValue = "None",
named = true,
positional = false,
doc =
"shell command to execute.arguments
object via "
+ "$1
, $2
, etc.echo foo > $1
\". Blaze uses the same shell to execute the "
+ "command as it does for genrules."
),
@Param(
name = "progress_message",
type = String.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc =
"progress message to show to the user during the build, "
+ "e.g. \"Compiling foo.cc to create foo.o\"."
),
@Param(
name = "use_default_shell_env",
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = "whether the action should use the built in shell environment or not."
),
@Param(
name = "env",
type = SkylarkDict.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc = "sets the dictionary of environment variables."
),
@Param(
name = "execution_requirements",
type = SkylarkDict.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc =
"information for scheduling the action. See "
+ "tags "
+ "for useful keys."
),
@Param(
// TODO(bazel-team): The name here isn't accurate anymore.
// This is technically experimental, so folks shouldn't be too attached,
// but consider renaming to be more accurate/opaque.
name = "input_manifests",
type = SkylarkList.class,
noneable = true,
defaultValue = "None",
named = true,
positional = false,
doc =
"(Experimental) sets the input runfiles metadata; "
+ "they are typically generated by resolve_command."
)
}
)
public void runShell(
SkylarkList outputs,
Object inputs,
Object arguments,
Object mnemonicUnchecked,
Object commandUnchecked,
Object progressMessage,
Boolean useDefaultShellEnv,
Object envUnchecked,
Object executionRequirementsUnchecked,
Object inputManifestsUnchecked)
throws EvalException {
context.checkMutable("actions.run_shell");
// TODO(bazel-team): builder still makes unnecessary copies of inputs, outputs and args.
SkylarkList argumentList = (SkylarkList) arguments;
SpawnAction.Builder builder = new SpawnAction.Builder();
buildCommandLine(builder, argumentList);
if (commandUnchecked instanceof String) {
Map{@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,
Object executionRequirementsUnchecked,
Object inputManifestsUnchecked,
SpawnAction.Builder builder)
throws EvalException {
// TODO(bazel-team): builder still makes unnecessary copies of inputs, outputs and args.
Iterablesubstitutions
dictionary. Whenever a key of the "
+ "dictionary appears in the template, it is replaced with the associated value. "
+ "There is no special syntax for the keys. You may for example use curly braces "
+ "to avoid conflicts (e.g. {KEY}
). "
+ ""
+ "See example of use",
parameters = {
@Param(
name = "template",
type = Artifact.class,
named = true,
positional = false,
doc = "the template file, which is a UTF-8 encoded text file."
),
@Param(
name = "output",
type = Artifact.class,
named = true,
positional = false,
doc = "the output file, which is a UTF-8 encoded text file."
),
@Param(
name = "substitutions",
type = SkylarkDict.class,
named = true,
positional = false,
doc = "substitutions to make when expanding the template."
),
@Param(
name = "is_executable",
type = Boolean.class,
defaultValue = "False",
named = true,
positional = false,
doc = "whether the output file should be executable."
)
}
)
public void expandTemplate(
Artifact template,
Artifact output,
SkylarkDict, ?> substitutionsUnchecked,
Boolean executable)
throws EvalException {
context.checkMutable("actions.expand_template");
ImmutableList.Builder
"
+ "The command lines are memory-efficient because Blaze doesn't fully construct them"
+ " until just before executing the action. "
+ "See ctx.actions.run() or "
+ "ctx.actions.run_shell().
"
+ "Example:"
+ "\n"
+ "# foo_deps and bar_deps are each a large depset of artifacts\n"
+ "args = ctx.actions.args()\n"
+ "args.add(\"--foo\")\n"
+ "args.add(foo_deps)\n"
+ "args.add(\"--bar\")\n"
+ "args.add(bar_deps, join_with=\",\")\n"
+ "ctx.actions.run(\n"
+ " arguments = [args],\n"
+ " ...\n"
+ ")\n"
+ "# Expands to [\n"
+ "# \"--foo\",\n"
+ "# ...artifacts from foo_deps,\n"
+ "# \"--bar\",\n"
+ "# ...artifacts from bar_deps joined with ',',\n"
+ "# ]"
+ "
"
)
static class Args extends SkylarkMutable {
private final Mutability mutability;
private final SkylarkCustomCommandLine.Builder commandLine;
private ParameterFileType parameterFileType = ParameterFileType.SHELL_QUOTED;
private String flagFormatString;
private boolean useAlways;
@SkylarkSignature(
name = "add",
objectType = Args.class,
returnType = NoneType.class,
doc = "Adds an argument to be dynamically expanded at evaluation time.",
parameters = {
@Param(name = "self", type = Args.class, doc = "This args object."),
@Param(
name = "value",
type = Object.class,
doc =
"the object to add to the argument list. "
+ "If the object is scalar, the object's string representation is added. "
+ "If it's a list or "
+ "depset, "
+ "each element's string representation is added."
),
@Param(
name = "format",
type = String.class,
named = true,
positional = false,
defaultValue = "None",
noneable = true,
doc =
"a format string used to format the object(s). "
+ "The format string is as per pattern % tuple. "
+ "Limitations: only %d %s %r %% are supported."
),
@Param(
name = "before_each",
type = String.class,
named = true,
positional = false,
defaultValue = "None",
noneable = true,
doc =
"each object in the list is prepended by this string. "
+ "Only supported for vector arguments."
),
@Param(
name = "join_with",
type = String.class,
named = true,
positional = false,
defaultValue = "None",
noneable = true,
doc =
"each object in the list is joined with this string. "
+ "Only supported for vector arguments."
),
@Param(
name = "map_fn",
type = BaseFunction.class,
named = true,
positional = false,
defaultValue = "None",
noneable = true,
doc =
"The passed objects are passed through a map function. "
+ "For vector args the function is given a list and is expected to return a list."
)
},
useLocation = true
)
public static final BuiltinFunction add =
new BuiltinFunction("add") {
@SuppressWarnings("unused")
public NoneType invoke(
Args self,
Object value,
Object format,
Object beforeEach,
Object joinWith,
Object mapFn,
Location loc)
throws EvalException {
if (self.isImmutable()) {
throw new EvalException(null, "cannot modify frozen value");
}
if (value instanceof SkylarkNestedSet || value instanceof SkylarkList) {
self.addVectorArg(value, format, beforeEach, joinWith, mapFn, loc);
} else {
self.addScalarArg(value, format, beforeEach, joinWith, mapFn, loc);
}
return Runtime.NONE;
}
};
private void addVectorArg(
Object value, Object format, Object beforeEach, Object joinWith, Object mapFn, Location loc)
throws EvalException {
if (beforeEach != Runtime.NONE && joinWith != Runtime.NONE) {
throw new EvalException(null, "cannot pass both 'before_each' and 'join_with'");
}
SkylarkCustomCommandLine.VectorArg.Builder vectorArg;
if (value instanceof SkylarkNestedSet) {
NestedSet> nestedSet = ((SkylarkNestedSet) value).getSet(Object.class);
vectorArg = new SkylarkCustomCommandLine.VectorArg.Builder(nestedSet);
} else {
SkylarkList skylarkList = (SkylarkList) value;
vectorArg = new SkylarkCustomCommandLine.VectorArg.Builder(skylarkList);
}
vectorArg.setLocation(loc);
if (format != Runtime.NONE) {
vectorArg.setFormat((String) format);
}
if (beforeEach != Runtime.NONE) {
vectorArg.setBeforeEach((String) beforeEach);
}
if (joinWith != Runtime.NONE) {
vectorArg.setJoinWith((String) joinWith);
}
if (mapFn != Runtime.NONE) {
vectorArg.setMapFn((BaseFunction) mapFn);
}
commandLine.add(vectorArg);
}
private void addScalarArg(
Object value, Object format, Object beforeEach, Object joinWith, Object mapFn, Location loc)
throws EvalException {
if (!EvalUtils.isImmutable(value)) {
throw new EvalException(null, "arg must be an immutable type");
}
if (beforeEach != Runtime.NONE) {
throw new EvalException(null, "'before_each' is not supported for scalar arguments");
}
if (joinWith != Runtime.NONE) {
throw new EvalException(null, "'join_with' is not supported for scalar arguments");
}
if (format == Runtime.NONE && mapFn == Runtime.NONE) {
commandLine.add(value);
} else {
ScalarArg.Builder scalarArg = new ScalarArg.Builder(value);
scalarArg.setLocation(loc);
if (format != Runtime.NONE) {
scalarArg.setFormat((String) format);
}
if (mapFn != Runtime.NONE) {
scalarArg.setMapFn((BaseFunction) mapFn);
}
commandLine.add(scalarArg);
}
}
@SkylarkCallable(
name = "use_param_file",
doc =
"Spills the args to a params file, replacing them with a pointer to the param file. "
+ "Use when your args may be too large for the system's command length limits ",
parameters = {
@Param(
name = "param_file_arg",
type = String.class,
named = true,
doc =
"a format string with a single \"%s\". "
+ "If the args are spilled to a params file then they are replaced "
+ "with an argument consisting of this string formatted with"
+ "the path of the params file."
),
@Param(
name = "use_always",
type = Boolean.class,
named = true,
positional = false,
defaultValue = "False",
doc =
"whether to always spill the args to a params file. If false, "
+ "bazel will decide whether the arguments need to be spilled "
+ "based on your system and arg length."
)
}
)
public void useParamsFile(String paramFileArg, Boolean useAlways) throws EvalException {
if (isImmutable()) {
throw new EvalException(null, "cannot modify frozen value");
}
if (!paramFileArg.contains("%s")) {
throw new EvalException(
null,
"Invalid value for parameter \"param_file_arg\": Expected string with a single \"%s\"");
}
this.flagFormatString = paramFileArg;
this.useAlways = useAlways;
}
@SkylarkCallable(
name = "set_param_file_format",
doc = "sets the format of the param file when written to disk",
parameters = {
@Param(
name = "format",
type = String.class,
named = true,
doc =
"the format of the param file. Must be one of:
"
+ "\"shell\": All arguments are shell quoted and separated by whitespace
"
+ "\"multiline\": All arguments are unquoted and separated by newline characters"
+ "The format defaults to \"shell\" if not called."
)
}
)
public void setParamFileFormat(String format) throws EvalException {
if (isImmutable()) {
throw new EvalException(null, "cannot modify frozen value");
}
final ParameterFileType parameterFileType;
switch (format) {
case "shell":
parameterFileType = ParameterFileType.SHELL_QUOTED;
break;
case "multiline":
parameterFileType = ParameterFileType.UNQUOTED;
break;
default:
throw new EvalException(
null,
"Invalid value for parameter \"format\": Expected one of \"shell\", \"multiline\"");
}
this.parameterFileType = parameterFileType;
}
private Args(
@Nullable Mutability mutability,
SkylarkSemantics skylarkSemantics,
EventHandler eventHandler) {
this.mutability = mutability != null ? mutability : Mutability.IMMUTABLE;
this.commandLine = new SkylarkCustomCommandLine.Builder(skylarkSemantics, eventHandler);
}
public SkylarkCustomCommandLine build() {
return commandLine.build();
}
@Override
public Mutability mutability() {
return mutability;
}
@Override
public void repr(SkylarkPrinter printer) {
printer.append("context.args() object");
}
static {
SkylarkSignatureProcessor.configureSkylarkFunctions(Args.class);
}
}
@SkylarkSignature(
name = "args",
doc = "returns an Args object that can be used to build memory-efficient command lines.",
objectType = SkylarkActionFactory.class,
returnType = Args.class,
parameters = {
@Param(
name = "self",
type = SkylarkActionFactory.class,
doc = "This 'actions' object."
)
},
useEnvironment = true
)
public static final BuiltinFunction args =
new BuiltinFunction("args") {
public Args invoke(SkylarkActionFactory self, Environment env) {
return new Args(env.mutability(),
env.getSemantics(),
self.ruleContext.getAnalysisEnvironment().getEventHandler());
}
};
@Override
public boolean isImmutable() {
return context.isImmutable();
}
@Override
public void repr(SkylarkPrinter printer) {
printer.append("actions for");
context.repr(printer);
}
void nullify() {
ruleContext = null;
}
static {
SkylarkSignatureProcessor.configureSkylarkFunctions(SkylarkActionFactory.class);
}
}