/**
  * Returns the configurable attribute conditions necessary to evaluate the given configured
  * target, or null if not all dependencies have yet been SkyFrame-evaluated.
  */
 @Nullable
 private Set<ConfigMatchingProvider> getConfigurableAttributeConditions(
     TargetAndConfiguration ctg, Environment env) {
   if (!(ctg.getTarget() instanceof Rule)) {
     return ImmutableSet.of();
   }
   Rule rule = (Rule) ctg.getTarget();
   RawAttributeMapper mapper = RawAttributeMapper.of(rule);
   Set<SkyKey> depKeys = new LinkedHashSet<>();
   for (Attribute attribute : rule.getAttributes()) {
     for (Label label : mapper.getConfigurabilityKeys(attribute.getName(), attribute.getType())) {
       if (!BuildType.Selector.isReservedLabel(label)) {
         depKeys.add(ConfiguredTargetValue.key(label, ctg.getConfiguration()));
       }
     }
   }
   Map<SkyKey, SkyValue> cts = env.getValues(depKeys);
   if (env.valuesMissing()) {
     return null;
   }
   ImmutableSet.Builder<ConfigMatchingProvider> conditions = ImmutableSet.builder();
   for (SkyValue ctValue : cts.values()) {
     ConfiguredTarget ct = ((ConfiguredTargetValue) ctValue).getConfiguredTarget();
     conditions.add(Preconditions.checkNotNull(ct.getProvider(ConfigMatchingProvider.class)));
   }
   return conditions.build();
 }
示例#2
0
 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;
 }
示例#3
0
 @Test
 public void testNonEmpty() throws Exception {
   Attribute attr = attr("foo", Type.LABEL_LIST).nonEmpty().legacyAllowAnyFileType().build();
   assertEquals("foo", attr.getName());
   assertEquals(Type.LABEL_LIST, attr.getType());
   assertTrue(attr.isNonEmpty());
 }
示例#4
0
  private void visitRule(
      Rule rule,
      AspectDefinition aspect,
      AspectParameters aspectParameters,
      ListMultimap<Attribute, LabelAndConfiguration> labelMap,
      ListMultimap<Attribute, Dependency> outgoingEdges) {
    Preconditions.checkNotNull(labelMap);
    for (Map.Entry<Attribute, Collection<LabelAndConfiguration>> entry :
        labelMap.asMap().entrySet()) {
      Attribute attribute = entry.getKey();
      for (LabelAndConfiguration dep : entry.getValue()) {
        Label label = dep.getLabel();
        BuildConfiguration config = dep.getConfiguration();

        Target toTarget;
        try {
          toTarget = getTarget(label);
        } catch (NoSuchThingException e) {
          throw new IllegalStateException(
              "not found: " + label + " from " + rule + " in " + attribute.getName());
        }
        if (toTarget == null) {
          continue;
        }
        BuildConfiguration.TransitionApplier transitionApplier = config.getTransitionApplier();
        if (config.useDynamicConfigurations()
            && config.isHostConfiguration()
            && !BuildConfiguration.usesNullConfiguration(toTarget)) {
          // This condition is needed because resolveLateBoundAttributes may switch config to
          // the host configuration, which is the only case DependencyResolver applies a
          // configuration transition outside of this method. We need to reflect that
          // transition in the results of this method, but config.evaluateTransition is hard-set
          // to return a NONE transition when the input is a host config. Since the outside
          // caller originally passed the *original* value of config (before the possible
          // switch), it can mistakenly interpret the result as a NONE transition from the
          // original value of config. This condition fixes that. Another fix would be to have
          // config.evaluateTransition return a HOST transition when the input config is a host,
          // but since this blemish is specific to DependencyResolver it seems best to keep the
          // fix here.
          // TODO(bazel-team): eliminate this special case by passing transitionApplier to
          // resolveLateBoundAttributes, so that method uses the same interface for transitions.
          transitionApplier.applyTransition(Attribute.ConfigurationTransition.HOST);
        } else {
          config.evaluateTransition(rule, attribute, toTarget, transitionApplier);
        }
        for (Dependency dependency :
            transitionApplier.getDependencies(
                label, requiredAspects(aspect, aspectParameters, attribute, toTarget, rule))) {
          outgoingEdges.put(entry.getKey(), dependency);
        }
      }
    }
  }
示例#5
0
  /** Returns all dependencies that should be constraint-checked against the current rule. */
  private static Iterable<TransitiveInfoCollection> getConstraintCheckedDependencies(
      RuleContext ruleContext) {
    Set<TransitiveInfoCollection> depsToCheck = new LinkedHashSet<>();
    AttributeMap attributes = ruleContext.attributes();

    for (String attr : attributes.getAttributeNames()) {
      Attribute attrDef = attributes.getAttributeDefinition(attr);
      Type<?> attrType = attributes.getAttributeType(attr);

      // TODO(bazel-team): support a user-definable API for choosing which attributes are checked
      if (!attrDef.checkConstraintsOverride()) {
        if ((attrType != BuildType.LABEL && attrType != BuildType.LABEL_LIST)
            || RuleClass.isConstraintAttribute(attr)
            || attr.equals("visibility")
            // Use the same implicit deps check that query uses. This facilitates running queries to
            // determine exactly which rules need to be constraint-annotated for depot migrations.
            || !Rule.NO_IMPLICIT_DEPS.apply(ruleContext.getRule(), attrDef)
            // We can't identify host deps by calling BuildConfiguration.isHostConfiguration()
            // because --nodistinct_host_configuration subverts that call.
            || attrDef.getConfigurationTransition() == Attribute.ConfigurationTransition.HOST) {
          continue;
        }
      }

      for (TransitiveInfoCollection dep :
          ruleContext.getPrerequisites(attr, RuleConfiguredTarget.Mode.DONT_CHECK)) {
        // Output files inherit the environment spec of their generating rule.
        if (dep instanceof OutputFileConfiguredTarget) {
          // Note this reassignment means constraint violation errors reference the generating
          // rule, not the file. This makes the source of the environmental mismatch more clear.
          dep = ((OutputFileConfiguredTarget) dep).getGeneratingRule();
        }
        // Input files don't support environments. We may subsequently opt them into constraint
        // checking, but for now just pass them by.
        if (dep.getProvider(SupportedEnvironmentsProvider.class) != null) {
          depsToCheck.add(dep);
        }
      }
    }

    return depsToCheck;
  }
  @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);
  }
示例#7
0
 @Test
 public void testBasics() throws Exception {
   Attribute attr = attr("foo", Type.INTEGER).mandatory().value(3).build();
   assertEquals("foo", attr.getName());
   assertEquals(3, attr.getDefaultValue(null));
   assertEquals(Type.INTEGER, attr.getType());
   assertTrue(attr.isMandatory());
   assertTrue(attr.isDocumented());
   attr = attr("$foo", Type.INTEGER).build();
   assertFalse(attr.isDocumented());
 }
示例#8
0
  @Override
  public Iterable<String> getAttrAsString(Target target, String attrName) {
    Preconditions.checkArgument(target instanceof Rule);
    List<String> values = new ArrayList<>(); // May hold null values.
    Attribute attribute = ((Rule) target).getAttributeDefinition(attrName);
    if (attribute != null) {
      Type<?> attributeType = attribute.getType();
      for (Object attrValue :
          AggregatingAttributeMapper.of((Rule) target)
              .visitAttribute(attribute.getName(), attributeType)) {

        // Ugly hack to maintain backward 'attr' query compatibility for BOOLEAN and TRISTATE
        // attributes. These are internally stored as actual Boolean or TriState objects but were
        // historically queried as integers. To maintain compatibility, we inspect their actual
        // value and return the integer equivalent represented as a String. This code is the
        // opposite of the code in BooleanType and TriStateType respectively.
        if (attributeType == BOOLEAN) {
          values.add(Type.BOOLEAN.cast(attrValue) ? "1" : "0");
        } else if (attributeType == TRISTATE) {
          switch (BuildType.TRISTATE.cast(attrValue)) {
            case AUTO:
              values.add("-1");
              break;
            case NO:
              values.add("0");
              break;
            case YES:
              values.add("1");
              break;
            default:
              throw new AssertionError("This can't happen!");
          }
        } else {
          values.add(attrValue == null ? null : attrValue.toString());
        }
      }
    }
    return values;
  }
示例#9
0
  private void resolveLateBoundAttributes(
      Rule rule,
      BuildConfiguration configuration,
      BuildConfiguration hostConfiguration,
      AttributeMap attributeMap,
      Iterable<Attribute> attributes,
      ImmutableSortedKeyListMultimap.Builder<Attribute, LabelAndConfiguration> builder)
      throws EvalException, InterruptedException {
    for (Attribute attribute : attributes) {
      if (!attribute.isLateBound() || !attribute.getCondition().apply(attributeMap)) {
        continue;
      }

      List<BuildConfiguration> actualConfigurations = ImmutableList.of(configuration);
      if (attribute.getConfigurationTransition() instanceof SplitTransition<?>) {
        Preconditions.checkState(attribute.getConfigurator() == null);
        // TODO(bazel-team): This ends up applying the split transition twice, both here and in the
        // visitRule method below - this is not currently a problem, because the configuration graph
        // never contains nested split transitions, so the second application is idempotent.
        actualConfigurations =
            configuration.getSplitConfigurations(
                (SplitTransition<?>) attribute.getConfigurationTransition());
      }

      for (BuildConfiguration actualConfig : actualConfigurations) {
        @SuppressWarnings("unchecked")
        LateBoundDefault<BuildConfiguration> lateBoundDefault =
            (LateBoundDefault<BuildConfiguration>) attribute.getLateBoundDefault();
        if (lateBoundDefault.useHostConfiguration()) {
          actualConfig = hostConfiguration;
        }
        // TODO(bazel-team): This might be too expensive - can we cache this somehow?
        if (!lateBoundDefault.getRequiredConfigurationFragments().isEmpty()) {
          if (!actualConfig.hasAllFragments(lateBoundDefault.getRequiredConfigurationFragments())) {
            continue;
          }
        }

        // TODO(bazel-team): We should check if the implementation tries to access an undeclared
        // fragment.
        Object actualValue = lateBoundDefault.getDefault(rule, actualConfig);
        if (EvalUtils.isNullOrNone(actualValue)) {
          continue;
        }
        try {
          if (attribute.getType() == BuildType.LABEL) {
            Label label = BuildType.LABEL.cast(actualValue);
            builder.put(attribute, LabelAndConfiguration.of(label, actualConfig));
          } else if (attribute.getType() == BuildType.LABEL_LIST) {
            for (Label label : BuildType.LABEL_LIST.cast(actualValue)) {
              builder.put(attribute, LabelAndConfiguration.of(label, actualConfig));
            }
          } else {
            throw new IllegalStateException(
                String.format(
                    "Late bound attribute '%s' is not a label or a label list",
                    attribute.getName()));
          }
        } catch (ClassCastException e) {
          throw new EvalException(
              rule.getLocation(),
              String.format(
                  "When computing the default value of %s, expected '%s', got '%s'",
                  attribute.getName(),
                  attribute.getType(),
                  EvalUtils.getDataTypeName(actualValue, true)));
        }
      }
    }
  }
示例#10
0
  private void resolveImplicitAttributes(
      Rule rule,
      BuildConfiguration configuration,
      AttributeMap attributeMap,
      Iterable<Attribute> attributes,
      ImmutableSortedKeyListMultimap.Builder<Attribute, LabelAndConfiguration> builder) {
    // Since the attributes that come from aspects do not appear in attributeMap, we have to get
    // their values from somewhere else. This incidentally means that aspects attributes are not
    // configurable. It would be nice if that wasn't the case, but we'd have to revamp how
    // attribute mapping works, which is a large chunk of work.
    ImmutableSet<String> mappedAttributes = ImmutableSet.copyOf(attributeMap.getAttributeNames());
    for (Attribute attribute : attributes) {
      if (!attribute.isImplicit() || !attribute.getCondition().apply(attributeMap)) {
        continue;
      }

      if (attribute.getType() == BuildType.LABEL) {
        Label label =
            mappedAttributes.contains(attribute.getName())
                ? attributeMap.get(attribute.getName(), BuildType.LABEL)
                : BuildType.LABEL.cast(attribute.getDefaultValue(rule));

        if (label != null) {
          builder.put(attribute, LabelAndConfiguration.of(label, configuration));
        }
      } else if (attribute.getType() == BuildType.LABEL_LIST) {
        List<Label> labelList =
            mappedAttributes.contains(attribute.getName())
                ? attributeMap.get(attribute.getName(), BuildType.LABEL_LIST)
                : BuildType.LABEL_LIST.cast(attribute.getDefaultValue(rule));

        for (Label label : labelList) {
          builder.put(attribute, LabelAndConfiguration.of(label, configuration));
        }
      }
    }
  }
示例#11
0
 private void assertType(Type<?> expectedType, Attribute attr) {
   assertEquals(expectedType, attr.getType());
 }
示例#12
0
 private void assertDefaultValue(Object expected, Attribute attr) {
   assertEquals(expected, attr.getDefaultValue(null));
 }
示例#13
0
  @Test
  public void testCloneBuilder() {
    FileTypeSet txtFiles = FileTypeSet.of(FileType.of("txt"));
    RuleClass.Builder.RuleClassNamePredicate ruleClasses =
        new RuleClass.Builder.RuleClassNamePredicate("mock_rule");

    Attribute parentAttr = attr("x", LABEL_LIST).allowedFileTypes(txtFiles).mandatory().build();

    Attribute childAttr1 = parentAttr.cloneBuilder().build();
    assertEquals("x", childAttr1.getName());
    assertEquals(txtFiles, childAttr1.getAllowedFileTypesPredicate());
    assertEquals(Predicates.alwaysTrue(), childAttr1.getAllowedRuleClassesPredicate());
    assertTrue(childAttr1.isMandatory());
    assertFalse(childAttr1.isNonEmpty());

    Attribute childAttr2 =
        parentAttr.cloneBuilder().nonEmpty().allowedRuleClasses(ruleClasses).build();
    assertEquals("x", childAttr2.getName());
    assertEquals(txtFiles, childAttr2.getAllowedFileTypesPredicate());
    assertEquals(ruleClasses, childAttr2.getAllowedRuleClassesPredicate());
    assertTrue(childAttr2.isMandatory());
    assertTrue(childAttr2.isNonEmpty());

    // Check if the parent attribute is unchanged
    assertFalse(parentAttr.isNonEmpty());
    assertEquals(Predicates.alwaysTrue(), parentAttr.getAllowedRuleClassesPredicate());
  }
 @Override
 public void acceptLabelAttribute(Label label, Attribute attribute) {
   if (attribute.getName().equals("srcs")) {
     labelsVisited.add(label.toString());
   }
 }