예제 #1
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;
  }
예제 #2
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)));
        }
      }
    }
  }