Provide placeholder rule class for deserialized Skylark rules
At this time, Skylark-defined rule classes don't get serialized, and
aren't available at package deserialization time. To allow packages
with Skylark-defined rule classes to deserialize, we provide a
placeholder rule class implementation for deserialized Skylark rules.
Resubmitting after previous rollback.
--
MOS_MIGRATED_REVID=97972209
diff --git a/src/main/java/com/google/devtools/build/lib/packages/ProtoUtils.java b/src/main/java/com/google/devtools/build/lib/packages/ProtoUtils.java
index 653e283..b566ba7 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/ProtoUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/ProtoUtils.java
@@ -35,11 +35,17 @@
import static com.google.devtools.build.lib.packages.Type.STRING_LIST_DICT;
import static com.google.devtools.build.lib.packages.Type.TRISTATE;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
import com.google.devtools.build.lib.query2.proto.proto2api.Build.Attribute.Discriminator;
-import java.util.Map;
+import java.util.Set;
/**
* Shared code used in proto buffer output for rules and rule classes.
@@ -48,9 +54,13 @@
/**
* This map contains all attribute types that are recognized by the protocol
* output formatter.
+ *
+ * <p>If you modify this map, please ensure that {@link #getTypeFromDiscriminator} can still
+ * resolve a {@link Discriminator} value to exactly one {@link Type} (using an optional nodep
+ * hint, as described below).
*/
- private static final Map<Type<?>, Discriminator> TYPE_MAP
- = new ImmutableMap.Builder<Type<?>, Discriminator>()
+ static final ImmutableMap<Type<?>, Discriminator> TYPE_MAP =
+ new ImmutableMap.Builder<Type<?>, Discriminator>()
.put(INTEGER, Discriminator.INTEGER)
.put(DISTRIBUTIONS, Discriminator.DISTRIBUTION_SET)
.put(LABEL, Discriminator.LABEL)
@@ -75,11 +85,71 @@
.put(STRING_DICT_UNARY, Discriminator.STRING_DICT_UNARY)
.build();
+ static final ImmutableSet<Type<?>> NODEP_TYPES =
+ ImmutableSet.of(NODEP_LABEL, NODEP_LABEL_LIST);
+
+ static final ImmutableSetMultimap<Discriminator, Type<?>> INVERSE_TYPE_MAP =
+ TYPE_MAP.asMultimap().inverse();
+
/**
* Returns the appropriate Attribute.Discriminator value from an internal attribute type.
*/
public static Discriminator getDiscriminatorFromType(Type<?> type) {
- Preconditions.checkArgument(TYPE_MAP.containsKey(type));
+ Preconditions.checkArgument(TYPE_MAP.containsKey(type), type);
return TYPE_MAP.get(type);
}
+
+ /**
+ * Returns the appropriate set of internal attribute types from an Attribute.Discriminator value.
+ */
+ public static ImmutableSet<Type<?>> getTypesFromDiscriminator(Discriminator discriminator) {
+ Preconditions.checkArgument(INVERSE_TYPE_MAP.containsKey(discriminator), discriminator);
+ return INVERSE_TYPE_MAP.get(discriminator);
+ }
+
+ /**
+ * Returns the appropriate internal attribute type from an Attribute.Discriminator value, given
+ * an optional nodeps hint.
+ */
+ public static Type<?> getTypeFromDiscriminator(Discriminator discriminator,
+ Optional<Boolean> nodeps, String ruleClassName, String attrName) {
+ Preconditions.checkArgument(INVERSE_TYPE_MAP.containsKey(discriminator));
+ ImmutableSet<Type<?>> possibleTypes = ProtoUtils.getTypesFromDiscriminator(discriminator);
+ Type<?> preciseType;
+ if (possibleTypes.size() == 1) {
+ preciseType = Iterables.getOnlyElement(possibleTypes);
+ } else {
+ // If there is more than one possible type associated with the discriminator, then the
+ // discriminator must be either Discriminator.STRING or Discriminator.STRING_LIST.
+ //
+ // If it is Discriminator.STRING, then its possible Type<?>s are {NODEP_LABEL, STRING}. The
+ // nodeps hint must be present in order to distinguish between them. If nodeps is true,
+ // then the Type<?> must be NODEP_LABEL, and if false, it must be STRING.
+ //
+ // A similar relation holds for the Discriminator value STRING_LIST, and its possible
+ // Type<?>s {NODEP_LABEL_LIST, STRING_LIST}.
+
+ Preconditions.checkArgument(nodeps.isPresent(),
+ "Nodeps hint is required when discriminator is associated with more than one type."
+ + " Discriminator: \"%s\", Rule class: \"%s\", Attr: \"%s\"", discriminator,
+ ruleClassName, attrName);
+ if (nodeps.get()) {
+ Set<Type<?>> nodepType = Sets.filter(possibleTypes, Predicates.in(NODEP_TYPES));
+ Preconditions.checkState(nodepType.size() == 1,
+ "There should be exactly one NODEP type associated with discriminator \"%s\""
+ + ", but found these: %s. Rule class: \"%s\", Attr: \"%s\"", discriminator,
+ nodepType, ruleClassName, attrName);
+ preciseType = Iterables.getOnlyElement(nodepType);
+ } else {
+ Set<Type<?>> notNodepType =
+ Sets.filter(possibleTypes, Predicates.not(Predicates.in(NODEP_TYPES)));
+ Preconditions.checkState(notNodepType.size() == 1,
+ "There should be exactly one non-NODEP type associated with discriminator \"%s\""
+ + ", but found these: %s. Rule class: \"%s\", Attr: \"%s\"", discriminator,
+ notNodepType, ruleClassName, attrName);
+ preciseType = Iterables.getOnlyElement(notNodepType);
+ }
+ }
+ return preciseType;
+ }
}