private static void addOutputGroups(
      Object value, Location loc, RuleConfiguredTargetBuilder builder) throws EvalException {
    Map<String, SkylarkValue> outputGroups =
        SkylarkType.castMap(value, String.class, SkylarkValue.class, "output_groups");

    for (String outputGroup : outputGroups.keySet()) {
      SkylarkValue objects = outputGroups.get(outputGroup);
      NestedSet<Artifact> artifacts;

      String typeErrorMessage =
          "Output group '%s' is of unexpected type. "
              + "Should be list or set of Files, but got '%s' instead.";

      if (objects instanceof SkylarkList) {
        NestedSetBuilder<Artifact> nestedSetBuilder = NestedSetBuilder.stableOrder();
        for (Object o : (SkylarkList) objects) {
          if (o instanceof Artifact) {
            nestedSetBuilder.add((Artifact) o);
          } else {
            throw new EvalException(
                loc,
                String.format(
                    typeErrorMessage,
                    outputGroup,
                    "list with an element of " + EvalUtils.getDataTypeNameFromClass(o.getClass())));
          }
        }
        artifacts = nestedSetBuilder.build();
      } else {
        artifacts =
            SkylarkType.cast(
                    objects,
                    SkylarkNestedSet.class,
                    Artifact.class,
                    loc,
                    typeErrorMessage,
                    outputGroup,
                    EvalUtils.getDataTypeName(objects, true))
                .getSet(Artifact.class);
      }
      builder.addOutputGroup(outputGroup, artifacts);
    }
  }
 private static <T> T cast(
     String paramName, ClassObject struct, Class<T> expectedType, Location loc)
     throws EvalException {
   Object value = struct.getValue(paramName);
   return SkylarkType.cast(
       value,
       expectedType,
       loc,
       "expected %s for '%s' but got %s instead: %s",
       SkylarkType.of(expectedType),
       paramName,
       EvalUtils.getDataTypeName(value, false),
       value);
 }
 private void checkCompositeSkylarkObjectSafe(Object object) {
   if (object instanceof SkylarkApiProvider) {
     return;
   } else if (object instanceof SkylarkList) {
     SkylarkList list = (SkylarkList) object;
     if (list == SkylarkList.EMPTY_LIST
         || isSimpleSkylarkObjectSafe(list.getContentType().getType())) {
       // Try not to iterate over the list if avoidable.
       return;
     }
     // The list can be a tuple or a list of composite items.
     for (Object listItem : list) {
       checkSkylarkObjectSafe(listItem);
     }
     return;
   } else if (object instanceof SkylarkNestedSet) {
     // SkylarkNestedSets cannot have composite items.
     Class<?> contentType = ((SkylarkNestedSet) object).getContentType().getType();
     if (!contentType.equals(Object.class) && !isSimpleSkylarkObjectSafe(contentType)) {
       throw new IllegalArgumentException(EvalUtils.getDataTypeName(contentType));
     }
     return;
   } else if (object instanceof Map<?, ?>) {
     for (Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
       checkSkylarkObjectSafe(entry.getKey());
       checkSkylarkObjectSafe(entry.getValue());
     }
     return;
   } else if (object instanceof ClassObject) {
     ClassObject struct = (ClassObject) object;
     for (String key : struct.getKeys()) {
       checkSkylarkObjectSafe(struct.getValue(key));
     }
     return;
   }
   throw new IllegalArgumentException(EvalUtils.getDataTypeName(object));
 }
 @Override
 public boolean containsKey(Object key, Location loc) throws EvalException {
   if (!(key instanceof SkylarkClassObjectConstructor)) {
     throw new EvalException(
         loc,
         String.format(
             "Type Target only supports querying by object constructors, got %s instead",
             EvalUtils.getDataTypeName(key)));
   }
   SkylarkClassObjectConstructor constructor = (SkylarkClassObjectConstructor) key;
   SkylarkProviders provider = getProvider(SkylarkProviders.class);
   if (provider != null) {
     Object declaredProvider = provider.getDeclaredProvider(constructor.getKey());
     if (declaredProvider != null) {
       return true;
     }
   }
   return false;
 }
 @Override
 public Object getIndex(Object key, Location loc) throws EvalException {
   if (!(key instanceof SkylarkClassObjectConstructor)) {
     throw new EvalException(
         loc,
         String.format(
             "Type Target only supports indexing by object constructors, got %s instead",
             EvalUtils.getDataTypeName(key)));
   }
   SkylarkClassObjectConstructor constructor = (SkylarkClassObjectConstructor) key;
   SkylarkProviders provider = getProvider(SkylarkProviders.class);
   if (provider != null) {
     Object declaredProvider = provider.getDeclaredProvider(constructor.getKey());
     if (declaredProvider != null) {
       return declaredProvider;
     }
   }
   // Either provider or declaredProvider is null
   throw new EvalException(
       loc,
       String.format(
           "Object of type Target doesn't contain declared provider %s",
           constructor.getKey().getExportedName()));
 }
Example #6
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)));
        }
      }
    }
  }