/** * Adds environments specified by the given attribute to the set of supported environments and * returns the environments added. * * <p>If this rule doesn't have the given attributes, returns an empty set. */ private EnvironmentCollection collectEnvironments( String attrName, EnvironmentCollection.Builder supportedEnvironments) { if (!ruleContext.getRule().isAttrDefined(attrName, BuildType.LABEL_LIST)) { return EnvironmentCollection.EMPTY; } EnvironmentCollection.Builder environments = new EnvironmentCollection.Builder(); for (TransitiveInfoCollection envTarget : ruleContext.getPrerequisites(attrName, RuleConfiguredTarget.Mode.DONT_CHECK)) { EnvironmentWithGroup envInfo = resolveEnvironment(envTarget); environments.put(envInfo.group(), envInfo.environment()); supportedEnvironments.put(envInfo.group(), envInfo.environment()); } return environments.build(); }
/** * Given a collection of environments and a collection of expected environments, returns the * missing environments that would cause constraint expectations to be violated. Includes the * effects of environment group defaults. */ public static Collection<Label> getUnsupportedEnvironments( EnvironmentCollection actualEnvironments, EnvironmentCollection expectedEnvironments) { Set<Label> missingEnvironments = new LinkedHashSet<>(); Collection<Label> actualEnvironmentLabels = actualEnvironments.getEnvironments(); // Check if each explicitly expected environment is satisfied. for (EnvironmentWithGroup expectedEnv : expectedEnvironments.getGroupedEnvironments()) { EnvironmentGroup group = expectedEnv.group(); Label environment = expectedEnv.environment(); boolean isSatisfied = false; if (actualEnvironments.getGroups().contains(group)) { // If the actual environments include members from the expected environment's group, we // need to either find the environment itself or another one that transitively fulfills it. if (actualEnvironmentLabels.contains(environment) || intersect(actualEnvironmentLabels, group.getFulfillers(environment))) { isSatisfied = true; } } else { // If the actual environments don't reference the expected environment's group at all, // the group's defaults are implicitly included. So we need to check those defaults for // either the expected environment or another environment that transitively fulfills it. if (group.isDefault(environment) || intersect(group.getFulfillers(environment), group.getDefaults())) { isSatisfied = true; } } if (!isSatisfied) { missingEnvironments.add(environment); } } // For any environment group not referenced by the expected environments, its defaults are // implicitly expected. We can ignore this if the actual environments also don't reference the // group (since in that case the same defaults apply), otherwise we have to check. for (EnvironmentGroup group : actualEnvironments.getGroups()) { if (!expectedEnvironments.getGroups().contains(group)) { for (Label expectedDefault : group.getDefaults()) { if (!actualEnvironmentLabels.contains(expectedDefault) && !intersect(actualEnvironmentLabels, group.getFulfillers(expectedDefault))) { missingEnvironments.add(expectedDefault); } } } } return missingEnvironments; }