aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
diff options
context:
space:
mode:
authorGravatar Dmitry Lomov <dslomov@google.com>2015-11-26 10:07:32 +0000
committerGravatar Philipp Wollermann <philwo@google.com>2015-11-26 13:19:28 +0000
commit7b599453389b3a00eebf25c58cde322a0e7bdf02 (patch)
treeb3c5860bf77e7d7665319316701f472c5f345a7e /src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
parentc89366f6d7fe092af74f25949f00ed409a86caab (diff)
Refactor Skylark rules and attributes in preparation to Skylark aspects.
1. attr.<type> functions return a wrapper object instead of Attribute.Builder dierctly. 2. RuleClass is created once per the life-time of RuleFunction, during export 3. Attributes are added to the RuleClass at exporting. -- MOS_MIGRATED_REVID=108774581
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java80
1 files changed, 51 insertions, 29 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index ed5892486a..63b6307525 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -84,6 +84,7 @@ import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor;
import com.google.devtools.build.lib.syntax.SkylarkValue;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.syntax.Type.ConversionException;
+import com.google.devtools.build.lib.util.Pair;
import java.util.HashMap;
import java.util.Map;
@@ -264,18 +265,22 @@ public class SkylarkRuleClassFunctions {
// We'll set the name later, pass the empty string for now.
RuleClass.Builder builder = new RuleClass.Builder("", type, true, parent);
+ ImmutableList.Builder<Pair<String, SkylarkAttr.Descriptor>> attributes =
+ ImmutableList.builder();
if (attrs != Runtime.NONE) {
- for (Map.Entry<String, Attribute.Builder> attr :
- castMap(attrs, String.class, Attribute.Builder.class, "attrs").entrySet()) {
- Attribute.Builder<?> attrBuilder = (Attribute.Builder<?>) attr.getValue();
+ for (Map.Entry<String, SkylarkAttr.Descriptor> attr :
+ castMap(attrs, String.class, SkylarkAttr.Descriptor.class, "attrs").entrySet()) {
+ SkylarkAttr.Descriptor attrDescriptor = attr.getValue();
String attrName =
- attributeToNative(attr.getKey(), ast.getLocation(), attrBuilder.hasLateBoundValue());
- addAttribute(builder, attrBuilder.build(attrName));
+ attributeToNative(attr.getKey(), ast.getLocation(),
+ attrDescriptor.getAttributeBuilder().hasLateBoundValue());
+ attributes.add(Pair.of(attrName, attrDescriptor));
}
}
if (executable || test) {
addAttribute(
+ ast.getLocation(),
builder,
attr("$is_executable", BOOLEAN)
.value(true)
@@ -307,16 +312,9 @@ public class SkylarkRuleClassFunctions {
registerRequiredFragments(fragments, hostFragments, builder);
builder.setConfiguredTargetFunction(implementation);
builder.setRuleDefinitionEnvironment(funcallEnv);
- return new RuleFunction(builder, type);
+ return new RuleFunction(builder, type, attributes.build(), ast.getLocation());
}
- private void addAttribute(RuleClass.Builder builder, Attribute attribute) throws EvalException {
- try {
- builder.addOrOverrideAttribute(attribute);
- } catch (IllegalArgumentException ex) {
- throw new EvalException(location, ex);
- }
- }
private void registerRequiredFragments(
SkylarkList fragments, SkylarkList hostFragments, RuleClass.Builder builder)
@@ -336,6 +334,16 @@ public class SkylarkRuleClassFunctions {
}
};
+ private static void addAttribute(
+ Location location, RuleClass.Builder builder, Attribute attribute) throws EvalException {
+ try {
+ builder.addOrOverrideAttribute(attribute);
+ } catch (IllegalArgumentException ex) {
+ throw new EvalException(location, ex);
+ }
+ }
+
+
@SkylarkSignature(
name = "aspect",
returnType = SkylarkAspect.class,
@@ -367,17 +375,22 @@ public class SkylarkRuleClassFunctions {
/** The implementation for the magic function "rule" that creates Skylark rule classes */
public static final class RuleFunction extends BaseFunction {
- // Note that this means that we can reuse the same builder.
- // This is fine since we don't modify the builder from here.
- private final RuleClass.Builder builder;
+ private RuleClass.Builder builder;
+
+ private RuleClass ruleClass;
private final RuleClassType type;
+ private ImmutableList<Pair<String, SkylarkAttr.Descriptor>> attributes;
+ private final Location definitionLocation;
private Label skylarkLabel;
- private String ruleClassName;
- public RuleFunction(Builder builder, RuleClassType type) {
+ public RuleFunction(Builder builder, RuleClassType type,
+ ImmutableList<Pair<String, SkylarkAttr.Descriptor>> attributes,
+ Location definitionLocation) {
super("rule", FunctionSignature.KWARGS);
this.builder = builder;
this.type = type;
+ this.attributes = attributes;
+ this.definitionLocation = definitionLocation;
}
@Override
@@ -387,15 +400,10 @@ public class SkylarkRuleClassFunctions {
throws EvalException, InterruptedException, ConversionException {
env.checkLoadingPhase(getName(), ast.getLocation());
try {
- if (ruleClassName == null || skylarkLabel == null) {
+ if (ruleClass == null) {
throw new EvalException(ast.getLocation(),
"Invalid rule class hasn't been exported by a Skylark file");
}
- if (type == RuleClassType.TEST != TargetUtils.isTestRuleName(ruleClassName)) {
- throw new EvalException(ast.getLocation(), "Invalid rule class name '" + ruleClassName
- + "', test rule class names must end with '_test' and other rule classes must not");
- }
- RuleClass ruleClass = builder.build(ruleClassName);
PackageContext pkgContext = (PackageContext) env.lookup(PackageFactory.PKG_CONTEXT);
return RuleFactory.createAndAddRule(
pkgContext, ruleClass, (Map<String, Object>) args[0], ast, env);
@@ -407,18 +415,32 @@ public class SkylarkRuleClassFunctions {
/**
* Export a RuleFunction from a Skylark file with a given name.
*/
- void export(Label skylarkLabel, String ruleClassName) {
+ void export(Label skylarkLabel, String ruleClassName) throws EvalException {
+ Preconditions.checkState(ruleClass == null && builder != null);
this.skylarkLabel = skylarkLabel;
- this.ruleClassName = ruleClassName;
+ if (type == RuleClassType.TEST != TargetUtils.isTestRuleName(ruleClassName)) {
+ throw new EvalException(definitionLocation, "Invalid rule class name '" + ruleClassName
+ + "', test rule class names must end with '_test' and other rule classes must not");
+ }
+ for (Pair<String, SkylarkAttr.Descriptor> attribute : attributes) {
+ addAttribute(definitionLocation, builder,
+ attribute.getSecond().getAttributeBuilder().build(attribute.getFirst()));
+ }
+ this.ruleClass = builder.build(ruleClassName);
+
+ this.builder = null;
+ this.attributes = null;
}
@VisibleForTesting
- public RuleClass.Builder getBuilder() {
- return builder;
+ public RuleClass getRuleClass() {
+ Preconditions.checkState(ruleClass != null && builder == null);
+ return ruleClass;
}
}
- public static void exportRuleFunctionsAndAspects(Environment env, Label skylarkLabel) {
+ public static void exportRuleFunctionsAndAspects(Environment env, Label skylarkLabel)
+ throws EvalException {
for (String name : env.getGlobals().getDirectVariableNames()) {
try {
Object value = env.lookup(name);