aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib
diff options
context:
space:
mode:
authorGravatar Dmitry Lomov <dslomov@google.com>2015-11-26 10:49:16 +0000
committerGravatar Philipp Wollermann <philwo@google.com>2015-11-26 13:19:53 +0000
commit5a8f1c0b1a7a791092f8d274d9f16bae5396bc9c (patch)
tree6904371344f5aebaf038977051a25946a8314316 /src/main/java/com/google/devtools/build/lib
parent1f02a434a42cb7ce2cbdad8592709ad518772eb7 (diff)
Implement Skylark aspects originating from Skylark rules.
-- MOS_MIGRATED_REVID=108777120
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/Attribute.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkAttr.java107
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java38
3 files changed, 130 insertions, 42 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
index c2b3eea933..9898294377 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
@@ -725,11 +725,36 @@ public final class Attribute implements Comparable<Attribute> {
*/
public <T extends NativeAspectFactory> Builder<TYPE> aspect(
Class<T> aspect, Function<Rule, AspectParameters> evaluator) {
- this.aspects.add(new RuleAspect(new NativeAspectClass<T>(aspect), evaluator));
+ return this.aspect(new NativeAspectClass<T>(aspect), evaluator);
+ }
+
+ /**
+ * Asserts that a particular parameterized aspect probably needs to be computed for all direct
+ * dependencies through this attribute.
+ *
+ * @param evaluator function that extracts aspect parameters from rule.
+ */
+ public Builder<TYPE> aspect(AspectClass aspect, Function<Rule, AspectParameters> evaluator) {
+ this.aspects.add(new RuleAspect(aspect, evaluator));
return this;
}
/**
+ * Asserts that a particular parameterized aspect probably needs to be computed for all direct
+ * dependencies through this attribute.
+ */
+ public Builder<TYPE> aspect(AspectClass aspect) {
+ Function<Rule, AspectParameters> noParameters =
+ new Function<Rule, AspectParameters>() {
+ @Override
+ public AspectParameters apply(Rule input) {
+ return AspectParameters.EMPTY;
+ }
+ };
+ return this.aspect(aspect, noParameters);
+ }
+
+ /**
* Sets the predicate-like edge validity checker.
*/
public Builder<TYPE> validityPredicate(ValidityPredicate validityPredicate) {
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 f445eb6699..58b9386ac7 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
@@ -14,6 +14,8 @@
package com.google.devtools.build.lib.rules;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.Attribute;
@@ -21,6 +23,7 @@ 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.BuildType;
+import com.google.devtools.build.lib.rules.SkylarkRuleClassFunctions.SkylarkAspect;
import com.google.devtools.build.lib.syntax.BuiltinFunction;
import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.EvalException;
@@ -68,6 +71,10 @@ public final class SkylarkAttr {
"which rule targets (name of the classes) are allowed. This is deprecated (kept only for "
+ "compatiblity), use providers instead.";
+ private static final String ASPECTS_ARG = "aspects";
+ private static final String ASPECT_ARG_DOC =
+ "aspects that should be applied to dependencies specified by this attribute";
+
private static final String CONFIGURATION_ARG = "cfg";
private static final String CONFIGURATION_DOC =
"configuration of the attribute. " + "For example, use DATA_CFG or HOST_CFG.";
@@ -184,7 +191,7 @@ public final class SkylarkAttr {
return builder;
}
- private static Descriptor createAttribute(
+ private static Descriptor createAttrDescriptor(
Map<String, Object> kwargs, Type<?> type, FuncallExpression ast, Environment env)
throws EvalException {
try {
@@ -230,7 +237,7 @@ public final class SkylarkAttr {
throws EvalException {
// TODO(bazel-team): Replace literal strings with constants.
env.checkLoadingPhase("attr.int", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(
DEFAULT_ARG, defaultInt, MANDATORY_ARG, mandatory, VALUES_ARG, values),
Type.INTEGER,
@@ -274,7 +281,7 @@ public final class SkylarkAttr {
Environment env)
throws EvalException {
env.checkLoadingPhase("attr.string", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(
DEFAULT_ARG, defaultString, MANDATORY_ARG, mandatory, VALUES_ARG, values),
Type.STRING,
@@ -362,7 +369,7 @@ public final class SkylarkAttr {
Environment env)
throws EvalException {
env.checkLoadingPhase("attr.label", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(
DEFAULT_ARG,
defaultO,
@@ -417,7 +424,7 @@ public final class SkylarkAttr {
Environment env)
throws EvalException {
env.checkLoadingPhase("attr.string_list", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(
DEFAULT_ARG, defaultList, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
Type.STRING_LIST,
@@ -457,7 +464,7 @@ public final class SkylarkAttr {
Environment env)
throws EvalException {
env.checkLoadingPhase("attr.int_list", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(
DEFAULT_ARG, defaultList, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
Type.INTEGER_LIST,
@@ -522,6 +529,13 @@ public final class SkylarkAttr {
noneable = true,
defaultValue = "None",
doc = CONFIGURATION_DOC
+ ),
+ @Param(
+ name = ASPECTS_ARG,
+ type = SkylarkList.class,
+ generic1 = SkylarkAspect.class,
+ defaultValue = "[]",
+ doc = ASPECT_ARG_DOC
)
},
useAst = true,
@@ -538,31 +552,48 @@ public final class SkylarkAttr {
Boolean mandatory,
Boolean nonEmpty,
Object cfg,
+ SkylarkList aspects,
FuncallExpression ast,
Environment env)
throws EvalException {
env.checkLoadingPhase("attr.label_list", ast.getLocation());
- return createAttribute(
- EvalUtils.optionMap(
- DEFAULT_ARG,
- defaultList,
- ALLOW_FILES_ARG,
- allowFiles,
- ALLOW_RULES_ARG,
- allowRules,
- PROVIDERS_ARG,
- providers,
- FLAGS_ARG,
- flags,
- MANDATORY_ARG,
- mandatory,
- NON_EMPTY_ARG,
- nonEmpty,
- CONFIGURATION_ARG,
- cfg),
- BuildType.LABEL_LIST,
- ast,
- env);
+ ImmutableMap<String, Object> kwargs = EvalUtils.optionMap(
+ DEFAULT_ARG, defaultList,
+ ALLOW_FILES_ARG,
+ allowFiles,
+ ALLOW_RULES_ARG,
+ allowRules,
+ PROVIDERS_ARG,
+ providers,
+ FLAGS_ARG,
+ flags,
+ MANDATORY_ARG,
+ mandatory,
+ NON_EMPTY_ARG,
+ nonEmpty,
+ CONFIGURATION_ARG,
+ cfg);
+ try {
+ Attribute.Builder<?> attribute = createAttribute(
+ BuildType.LABEL_LIST, kwargs, ast, env);
+
+ ImmutableList<SkylarkAspect> skylarkAspects = getSkylarkAspects(aspects);
+ return new Descriptor(attribute, skylarkAspects);
+ } catch (ConversionException e) {
+ throw new EvalException(ast.getLocation(), e.getMessage());
+ }
+ }
+
+ protected ImmutableList<SkylarkAspect> getSkylarkAspects(SkylarkList aspects)
+ throws ConversionException {
+ ImmutableList.Builder<SkylarkAspect> aspectBuilder = ImmutableList.builder();
+ for (Object aspect : aspects) {
+ if (!(aspect instanceof SkylarkAspect)) {
+ throw new ConversionException("Expected a list of aspects for 'aspects'");
+ }
+ aspectBuilder.add((SkylarkAspect) aspect);
+ }
+ return aspectBuilder.build();
}
};
@@ -585,7 +616,7 @@ public final class SkylarkAttr {
Boolean defaultO, Boolean mandatory, FuncallExpression ast, Environment env)
throws EvalException {
env.checkLoadingPhase("attr.bool", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
Type.BOOLEAN,
ast,
@@ -621,7 +652,7 @@ public final class SkylarkAttr {
Object defaultO, Boolean mandatory, FuncallExpression ast, Environment env)
throws EvalException {
env.checkLoadingPhase("attr.output", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
BuildType.OUTPUT,
ast,
@@ -662,7 +693,7 @@ public final class SkylarkAttr {
Environment env)
throws EvalException {
env.checkLoadingPhase("attr.output_list", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(
DEFAULT_ARG, defaultList, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
BuildType.OUTPUT_LIST,
@@ -698,7 +729,7 @@ public final class SkylarkAttr {
Environment env)
throws EvalException {
env.checkLoadingPhase("attr.string_dict", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(
DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
Type.STRING_DICT,
@@ -734,7 +765,7 @@ public final class SkylarkAttr {
Environment env)
throws EvalException {
env.checkLoadingPhase("attr.string_list_dict", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(
DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory, NON_EMPTY_ARG, nonEmpty),
Type.STRING_LIST_DICT,
@@ -764,7 +795,7 @@ public final class SkylarkAttr {
Object defaultO, Boolean mandatory, FuncallExpression ast, Environment env)
throws EvalException {
env.checkLoadingPhase("attr.license", ast.getLocation());
- return createAttribute(
+ return createAttrDescriptor(
EvalUtils.optionMap(DEFAULT_ARG, defaultO, MANDATORY_ARG, mandatory),
BuildType.LICENSE,
ast,
@@ -777,14 +808,24 @@ public final class SkylarkAttr {
*/
public static final class Descriptor {
private final Attribute.Builder<?> attributeBuilder;
+ private final ImmutableList<SkylarkAspect> aspects;
public Descriptor(Attribute.Builder<?> attributeBuilder) {
+ this(attributeBuilder, ImmutableList.<SkylarkAspect>of());
+ }
+
+ public Descriptor(Attribute.Builder<?> attributeBuilder, ImmutableList<SkylarkAspect> aspects) {
this.attributeBuilder = attributeBuilder;
+ this.aspects = aspects;
}
public Attribute.Builder<?> getAttributeBuilder() {
return attributeBuilder;
}
+
+ public ImmutableList<SkylarkAspect> getAspects() {
+ return aspects;
+ }
}
static {
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 63b6307525..df27c88169 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
@@ -89,6 +89,7 @@ import com.google.devtools.build.lib.util.Pair;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
/**
@@ -423,8 +424,17 @@ public class SkylarkRuleClassFunctions {
+ "', test rule class names must end with '_test' and other rule classes must not");
}
for (Pair<String, SkylarkAttr.Descriptor> attribute : attributes) {
+ SkylarkAttr.Descriptor descriptor = attribute.getSecond();
+ Attribute.Builder<?> attributeBuilder = descriptor.getAttributeBuilder();
+ for (SkylarkAspect skylarkAspect : descriptor.getAspects()) {
+ if (!skylarkAspect.isExported()) {
+ throw new EvalException(definitionLocation,
+ "All aspects applied to rule dependencies must be top-level values");
+ }
+ attributeBuilder.aspect(new SkylarkAspectClass(skylarkAspect));
+ }
addAttribute(definitionLocation, builder,
- attribute.getSecond().getAttributeBuilder().build(attribute.getFirst()));
+ descriptor.getAttributeBuilder().build(attribute.getFirst()));
}
this.ruleClass = builder.build(ruleClassName);
@@ -441,7 +451,25 @@ public class SkylarkRuleClassFunctions {
public static void exportRuleFunctionsAndAspects(Environment env, Label skylarkLabel)
throws EvalException {
- for (String name : env.getGlobals().getDirectVariableNames()) {
+ Set<String> globalNames = env.getGlobals().getDirectVariableNames();
+
+ // Export aspects first since rules can depend on aspects.
+ for (String name : globalNames) {
+ Object value;
+ try {
+ value = env.lookup(name);
+ } catch (NoSuchVariableException e) {
+ throw new AssertionError(e);
+ }
+ if (value instanceof SkylarkAspect) {
+ SkylarkAspect skylarkAspect = (SkylarkAspect) value;
+ if (!skylarkAspect.isExported()) {
+ skylarkAspect.export(skylarkLabel, name);
+ }
+ }
+ }
+
+ for (String name : globalNames) {
try {
Object value = env.lookup(name);
if (value instanceof RuleFunction) {
@@ -450,12 +478,6 @@ public class SkylarkRuleClassFunctions {
function.export(skylarkLabel, name);
}
}
- if (value instanceof SkylarkAspect) {
- SkylarkAspect skylarkAspect = (SkylarkAspect) value;
- if (!skylarkAspect.isExported()) {
- skylarkAspect.export(skylarkLabel, name);
- }
- }
} catch (NoSuchVariableException e) {
throw new AssertionError(e);
}