aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/packages/RuleSerializer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/packages/RuleSerializer.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/packages/RuleSerializer.java68
1 files changed, 63 insertions, 5 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleSerializer.java b/src/main/java/com/google/devtools/build/lib/packages/RuleSerializer.java
index 5d49b4b420..658515cb49 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleSerializer.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleSerializer.java
@@ -13,23 +13,81 @@
// limitations under the License.
package com.google.devtools.build.lib.packages;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.packages.Attribute.ComputedDefault;
import com.google.devtools.build.lib.query2.proto.proto2api.Build;
+import com.google.devtools.build.lib.util.Preconditions;
/** Serialize a {@link Rule} as its protobuf representation. */
public class RuleSerializer {
+ // Skylark doesn't support defining rule classes with ComputedDefault attributes. Therefore, the
+ // only ComputedDefault attributes we expect to see for Skylark-defined rule classes are
+ // those declared in those rule classes' natively defined base rule classes, which are:
+ //
+ // 1. The "timeout" attribute in SkylarkRuleClassFunctions.testBaseRule
+ // 2. The "deprecation" attribute in BaseRuleClasses.commonCoreAndSkylarkAttributes
+ // 3. The "testonly" attribute in BaseRuleClasses.commonCoreAndSkylarkAttributes
+ private static final ImmutableSet<String> SKYLARK_RULE_CLASS_COMPUTED_DEFAULT_ATTRIBUTES =
+ ImmutableSet.of("timeout", "deprecation", "testonly");
+
public static Build.Rule.Builder serializeRule(Rule rule) {
Build.Rule.Builder builder = Build.Rule.newBuilder();
builder.setName(rule.getLabel().getName());
builder.setRuleClass(rule.getRuleClass());
builder.setPublicByDefault(rule.getRuleClassObject().isPublicByDefault());
- for (Attribute attribute : rule.getAttributes()) {
+ RawAttributeMapper rawAttributeMapper = RawAttributeMapper.of(rule);
+ for (Attribute attr : rule.getAttributes()) {
+ Object rawAttributeValue = rawAttributeMapper.getRawAttributeValue(rule, attr);
+
+ Object valueToSerialize;
+ if (rawAttributeValue instanceof ComputedDefault) {
+ if (rule.getRuleClassObject().isSkylark()) {
+ // If the rule class is Skylark-defined (i.e. rule.getRuleClassObject().isSkylark() is
+ // true), and the attribute has a ComputedDefault value, we must serialize it. The
+ // Skylark-defined ComputedDefault function won't be available after deserialization due
+ // to Skylark's non-serializability. Fortunately (from the perspective of rule
+ // serialization), Skylark doesn't support defining rule classes with ComputedDefault
+ // attributes, and so the only ComputedDefault attributes we need to worry about for
+ // Skylark-defined rule classes are those declared in those rule classes' natively
+ // defined base rule classes.
+ //
+ // See the comment for SKYLARK_RULE_CLASS_COMPUTED_DEFAULT_ATTRIBUTES for the locations
+ // of these expected attributes.
+ //
+ // The RawAttributeMapper#get method, inherited from AbstractAttributeMapper, evaluates
+ // the ComputedDefault function, so we use that, after verifying the attribute's name is
+ // expected.
+ Preconditions.checkState(
+ SKYLARK_RULE_CLASS_COMPUTED_DEFAULT_ATTRIBUTES.contains(attr.getName()),
+ "Unexpected ComputedDefault value for %s in %s",
+ attr,
+ rule);
+ valueToSerialize = rawAttributeMapper.get(attr.getName(), attr.getType());
+ } else {
+ // If the rule class is native (i.e. not Skylark-defined), we can skip serialization of
+ // attributes with ComputedDefault values. The native rule class can provide the same
+ // ComputedDefault value for the attribute after deserialization.
+ //
+ // TODO(mschaller): While the native rule class *could* provide it, it doesn't yet. Make
+ // it so! For now, we fall back to flattening the set of all possible values, computed
+ // using AggregatingAttributeMapper.
+ Iterable<Object> possibleValues =
+ AggregatingAttributeMapper.of(rule).getPossibleAttributeValues(rule, attr);
+ valueToSerialize =
+ AggregatingAttributeMapper.flattenAttributeValues(attr.getType(), possibleValues);
+ }
+ } else {
+ valueToSerialize = rawAttributeValue;
+ }
+
builder.addAttribute(
AttributeSerializer.getAttributeProto(
- attribute,
- AttributeSerializer.getAttributeValues(rule, attribute),
- rule.isAttributeValueExplicitlySpecified(attribute),
- /*includeGlobs=*/ true));
+ attr,
+ valueToSerialize,
+ rule.isAttributeValueExplicitlySpecified(attr),
+ /*includeGlobs=*/ true,
+ /*encodeBooleanAndTriStateAsIntegerAndString=*/ false));
}
return builder;
}