private static Set<AspectWithParameters> extractAspectCandidates( AspectDefinition aspectDefinition, AspectParameters aspectParameters, Attribute attribute, Rule originalRule) { // The order of this set will be deterministic. This is necessary because this order eventually // influences the order in which aspects are merged into the main configured target, which in // turn influences which aspect takes precedence if two emit the same provider (maybe this // should be an error) Set<AspectWithParameters> aspectCandidates = new LinkedHashSet<>(); for (Map.Entry<Class<? extends AspectFactory<?, ?, ?>>, AspectParameters> aspectWithParameters : attribute.getAspectsWithParameters(originalRule).entrySet()) { aspectCandidates.add( new AspectWithParameters( aspectWithParameters.getKey().asSubclass(ConfiguredAspectFactory.class), aspectWithParameters.getValue())); } if (aspectDefinition != null) { for (Class<? extends AspectFactory<?, ?, ?>> aspect : aspectDefinition.getAttributeAspects().get(attribute.getName())) { aspectCandidates.add( new AspectWithParameters( aspect.asSubclass(ConfiguredAspectFactory.class), aspectParameters)); } } return aspectCandidates; }
@Override public ImmutableMultimap<Attribute, Label> computeAspectDependencies(Target target) throws InterruptedException { if (!(target instanceof Rule)) { return ImmutableMultimap.of(); } Multimap<Attribute, Label> result = LinkedHashMultimap.create(); for (Attribute attribute : ((Rule) target).getAttributes()) { for (Class<? extends AspectFactory<?, ?, ?>> aspectFactory : attribute.getAspects()) { AspectDefinition.addAllAttributesOfAspect( (Rule) target, result, AspectFactory.Util.create(aspectFactory).getDefinition(), Rule.ALL_DEPS); } } return ImmutableMultimap.copyOf(result); }
private ListMultimap<Attribute, LabelAndConfiguration> resolveAttributes( Rule rule, AspectDefinition aspect, BuildConfiguration configuration, BuildConfiguration hostConfiguration, Set<ConfigMatchingProvider> configConditions) throws EvalException, InterruptedException { ConfiguredAttributeMapper attributeMap = ConfiguredAttributeMapper.of(rule, configConditions); attributeMap.validateAttributes(); List<Attribute> attributes; if (aspect == null) { attributes = rule.getRuleClassObject().getAttributes(); } else { attributes = new ArrayList<>(); attributes.addAll(rule.getRuleClassObject().getAttributes()); if (aspect != null) { attributes.addAll(aspect.getAttributes().values()); } } ImmutableSortedKeyListMultimap.Builder<Attribute, LabelAndConfiguration> result = ImmutableSortedKeyListMultimap.builder(); resolveExplicitAttributes(rule, configuration, attributeMap, result); resolveImplicitAttributes(rule, configuration, attributeMap, attributes, result); resolveLateBoundAttributes( rule, configuration, hostConfiguration, attributeMap, attributes, result); // Add the rule's visibility labels (which may come from the rule or from package defaults). addExplicitDeps( result, rule, "visibility", rule.getVisibility().getDependencyLabels(), configuration); // Add package default constraints when the rule doesn't explicitly declare them. // // Note that this can have subtle implications for constraint semantics. For example: say that // package defaults declare compatibility with ':foo' and rule R declares compatibility with // ':bar'. Does that mean that R is compatible with [':foo', ':bar'] or just [':bar']? In other // words, did R's author intend to add additional compatibility to the package defaults or to // override them? More severely, what if package defaults "restrict" support to just [':baz']? // Should R's declaration signify [':baz'] + ['bar'], [ORIGINAL_DEFAULTS] + ['bar'], or // something else? // // Rather than try to answer these questions with possibly confusing logic, we take the // simple approach of assigning the rule's "restriction" attribute to the rule-declared value if // it exists, else the package defaults value (and likewise for "compatibility"). This may not // always provide what users want, but it makes it easy for them to understand how rule // declarations and package defaults intermix (and how to refactor them to get what they want). // // An alternative model would be to apply the "rule declaration" / "rule class defaults" // relationship, i.e. the rule class' "compatibility" and "restriction" declarations are merged // to generate a set of default environments, then the rule's declarations are independently // processed on top of that. This protects against obscure coupling behavior between // declarations from wildly different places (e.g. it offers clear answers to the examples posed // above). But within the scope of a single package it seems better to keep the model simple and // make the user responsible for resolving ambiguities. if (!rule.isAttributeValueExplicitlySpecified(RuleClass.COMPATIBLE_ENVIRONMENT_ATTR)) { addExplicitDeps( result, rule, RuleClass.COMPATIBLE_ENVIRONMENT_ATTR, rule.getPackage().getDefaultCompatibleWith(), configuration); } if (!rule.isAttributeValueExplicitlySpecified(RuleClass.RESTRICTED_ENVIRONMENT_ATTR)) { addExplicitDeps( result, rule, RuleClass.RESTRICTED_ENVIRONMENT_ATTR, rule.getPackage().getDefaultRestrictedTo(), configuration); } return result.build(); }