/** * Returns ids for dependent nodes of a given node, sorted by attribute. Note that some * dependencies do not have a corresponding attribute here, and we use the null attribute to * represent those edges. Visibility attributes are only visited if {@code visitVisibility} is * {@code true}. * * <p>If {@code aspect} is null, returns the dependent nodes of the configured target node * representing the given target and configuration, otherwise that of the aspect node accompanying * the aforementioned configured target node for the specified aspect. * * <p>The values are not simply labels because this also implements the first step of applying * configuration transitions, namely, split transitions. This needs to be done before the labels * are resolved because late bound attributes depend on the configuration. A good example for this * is @{code :cc_toolchain}. * * <p>The long-term goal is that most configuration transitions be applied here. However, in order * to do that, we first have to eliminate transitions that depend on the rule class of the * dependency. */ public final ListMultimap<Attribute, Dependency> dependentNodeMap( TargetAndConfiguration node, BuildConfiguration hostConfig, AspectDefinition aspect, AspectParameters aspectParameters, Set<ConfigMatchingProvider> configConditions) throws EvalException, InterruptedException { Target target = node.getTarget(); BuildConfiguration config = node.getConfiguration(); ListMultimap<Attribute, Dependency> outgoingEdges = ArrayListMultimap.create(); if (target instanceof OutputFile) { Preconditions.checkNotNull(config); visitTargetVisibility(node, outgoingEdges.get(null)); Rule rule = ((OutputFile) target).getGeneratingRule(); outgoingEdges.put(null, new Dependency(rule.getLabel(), config)); } else if (target instanceof InputFile) { visitTargetVisibility(node, outgoingEdges.get(null)); } else if (target instanceof EnvironmentGroup) { visitTargetVisibility(node, outgoingEdges.get(null)); } else if (target instanceof Rule) { Preconditions.checkNotNull(config); visitTargetVisibility(node, outgoingEdges.get(null)); Rule rule = (Rule) target; ListMultimap<Attribute, LabelAndConfiguration> labelMap = resolveAttributes(rule, aspect, config, hostConfig, configConditions); visitRule(rule, aspect, aspectParameters, labelMap, outgoingEdges); } else if (target instanceof PackageGroup) { visitPackageGroup(node, (PackageGroup) target, outgoingEdges.get(null)); } else { throw new IllegalStateException(target.getLabel().toString()); } return outgoingEdges; }
/** * Converts the given multimap of attributes to labels into a multi map of attributes to {@link * Dependency} objects using the proper configuration transition for each attribute. * * @throws IllegalArgumentException if the {@code node} does not refer to a {@link Rule} instance */ public final Collection<Dependency> resolveRuleLabels( TargetAndConfiguration node, ListMultimap<Attribute, LabelAndConfiguration> labelMap) { Preconditions.checkArgument(node.getTarget() instanceof Rule); Rule rule = (Rule) node.getTarget(); ListMultimap<Attribute, Dependency> outgoingEdges = ArrayListMultimap.create(); visitRule(rule, labelMap, outgoingEdges); return outgoingEdges.values(); }
private void visitTargetVisibility( TargetAndConfiguration node, Collection<Dependency> outgoingEdges) { for (Label label : node.getTarget().getVisibility().getDependencyLabels()) { try { Target visibilityTarget = getTarget(label); if (visibilityTarget == null) { return; } if (!(visibilityTarget instanceof PackageGroup)) { // Note that this error could also be caught in // AbstractConfiguredTarget.convertVisibility(), but we have an // opportunity here to avoid dependency cycles that result from // the visibility attribute of a rule referring to a rule that // depends on it (instead of its package) invalidVisibilityReferenceHook(node, label); continue; } // Visibility always has null configuration outgoingEdges.add(new Dependency(label, null)); } catch (NoSuchThingException e) { // Don't visit targets that don't exist (--keep_going) } } }