Skylark: allow attributes to specify a list of allowed values
e.g. attr.string(values = ["opt1", "opt2"])
--
MOS_MIGRATED_REVID=96187591
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
index 46d31e22..4d46e2d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java
@@ -16,7 +16,9 @@
import static com.google.devtools.build.lib.syntax.SkylarkType.castList;
+import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet;
import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
import com.google.devtools.build.lib.packages.Attribute.SkylarkLateBound;
import com.google.devtools.build.lib.packages.Type;
@@ -42,39 +44,42 @@
/**
* A helper class to provide Attr module in Skylark.
*/
-@SkylarkModule(name = "attr", namespace = true, onlyLoadingPhase = true,
- doc = "Module for creating new attributes. "
- + "They are only for use with the <code>rule</code> function.")
+@SkylarkModule(
+ name = "attr",
+ namespace = true,
+ onlyLoadingPhase = true,
+ doc =
+ "Module for creating new attributes. "
+ + "They are only for use with the <code>rule</code> function.")
public final class SkylarkAttr {
private static final String MANDATORY_DOC =
"set to True if users have to explicitely specify the value";
- private static final String NON_EMPTY_DOC =
- "set to True if the attribute must not be empty";
+ private static final String NON_EMPTY_DOC = "set to True if the attribute must not be empty";
private static final String ALLOW_FILES_DOC =
- "whether File targets are allowed. Can be True, False (default), or "
- + "a FileType filter.";
+ "whether File targets are allowed. Can be True, False (default), or " + "a FileType filter.";
private static final String ALLOW_RULES_DOC =
"which rule targets (name of the classes) are allowed. This is deprecated (kept only for "
- + "compatiblity), use providers instead.";
+ + "compatiblity), use providers instead.";
- private static final String FLAGS_DOC =
- "deprecated, will be removed";
+ private static final String FLAGS_DOC = "deprecated, will be removed";
- private static final String DEFAULT_DOC =
- "sets the default value of the attribute.";
+ private static final String DEFAULT_DOC = "sets the default value of the attribute.";
private static final String CONFIGURATION_DOC =
- "configuration of the attribute. "
- + "For example, use DATA_CFG or HOST_CFG.";
+ "configuration of the attribute. " + "For example, use DATA_CFG or HOST_CFG.";
private static final String EXECUTABLE_DOC =
"set to True if the labels have to be executable. This means the label must refer to an "
- + "executable file, or to a rule that outputs an executable file. Access the labels with "
- + "<code>ctx.executable.<attribute_name></code>.";
+ + "executable file, or to a rule that outputs an executable file. Access the labels "
+ + "with <code>ctx.executable.<attribute_name></code>.";
+
+ private static final String VALUES_DOC =
+ "specify the list of allowed values for the attribute. An error is raised if any other "
+ + "value is given.";
private static boolean containsNonNoneKey(Map<String, Object> arguments, String key) {
return arguments.containsKey(key) && arguments.get(key) != Environment.NONE;
@@ -139,6 +144,11 @@
"allowed rule classes for attribute definition"));
}
+ Iterable<String> values = castList(arguments.get("values"), String.class);
+ if (!Iterables.isEmpty(values)) {
+ builder.allowedValues(new AllowedValueSet(values));
+ }
+
if (containsNonNoneKey(arguments, "providers")) {
builder.mandatoryProviders(castList(arguments.get("providers"), String.class));
}
@@ -169,16 +179,19 @@
defaultValue = "[]", doc = FLAGS_DOC),
@Param(name = "mandatory", type = Boolean.class, defaultValue = "False",
doc = MANDATORY_DOC),
+ @Param(name = "values", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = VALUES_DOC),
@Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
defaultValue = "None", doc = CONFIGURATION_DOC)},
useAst = true, useEnvironment = true)
private static BuiltinFunction integer = new BuiltinFunction("int") {
public Attribute.Builder<?> invoke(Integer defaultInt,
- SkylarkList flags, Boolean mandatory, Object cfg,
+ SkylarkList flags, Boolean mandatory, SkylarkList values, Object cfg,
FuncallExpression ast, Environment env) throws EvalException {
return createAttribute(
EvalUtils.optionMap(
- "default", defaultInt, "flags", flags, "mandatory", mandatory, "cfg", cfg),
+ "default", defaultInt, "flags", flags, "mandatory", mandatory, "values", values,
+ "cfg", cfg),
Type.INTEGER, ast, env);
}
};
@@ -194,16 +207,19 @@
defaultValue = "[]", doc = FLAGS_DOC),
@Param(name = "mandatory", type = Boolean.class,
defaultValue = "False", doc = MANDATORY_DOC),
+ @Param(name = "values", type = SkylarkList.class, generic1 = String.class,
+ defaultValue = "[]", doc = VALUES_DOC),
@Param(name = "cfg", type = ConfigurationTransition.class, noneable = true,
defaultValue = "None", doc = CONFIGURATION_DOC)},
useAst = true, useEnvironment = true)
private static BuiltinFunction string = new BuiltinFunction("string") {
public Attribute.Builder<?> invoke(String defaultString,
- SkylarkList flags, Boolean mandatory, Object cfg,
+ SkylarkList flags, Boolean mandatory, SkylarkList values, Object cfg,
FuncallExpression ast, Environment env) throws EvalException {
return createAttribute(
EvalUtils.optionMap(
- "default", defaultString, "flags", flags, "mandatory", mandatory, "cfg", cfg),
+ "default", defaultString, "flags", flags, "mandatory", mandatory, "values", values,
+ "cfg", cfg),
Type.STRING, ast, env);
}
};