/** * Validity-checks that no group has its environment referenced in both the "compatible with" * and restricted to" attributes. Returns true if all is good, returns false and reports * appropriate errors if there are any problems. */ boolean validateEnvironmentSpecifications() { ImmutableCollection<EnvironmentGroup> restrictionGroups = restrictionEnvironments.getGroups(); boolean hasErrors = false; for (EnvironmentGroup group : compatibilityEnvironments.getGroups()) { if (restrictionGroups.contains(group)) { // To avoid error-spamming the user, when we find a conflict we only report one example // environment from each attribute for that group. Label compatibilityEnv = compatibilityEnvironments.getEnvironments(group).iterator().next(); Label restrictionEnv = restrictionEnvironments.getEnvironments(group).iterator().next(); if (compatibilityEnv.equals(restrictionEnv)) { ruleContext.attributeError( compatibilityAttr, compatibilityEnv + " cannot appear both here and in " + restrictionAttr); } else { ruleContext.attributeError( compatibilityAttr, compatibilityEnv + " and " + restrictionEnv + " belong to the same environment group. They should be declared " + "together either here or in " + restrictionAttr); } hasErrors = true; } } return !hasErrors; }
@Override public Collection<Label> getDefaults(EnvironmentGroup group) { if (ruleClassDefaults.getGroups().contains(group)) { return ruleClassDefaults.getEnvironments(group); } else { // If there are no rule class defaults for this group, just inherit global defaults. return groupDefaults.getDefaults(group); } }
/** * Adds environments to an {@link EnvironmentCollection} from groups that aren't already a part of * that collection. * * @param environments the collection to add to * @param toAdd the collection to add. All environments in this collection in groups that aren't * represented in {@code environments} are added to {@code environments}. * @return the expanded collection. */ private static EnvironmentCollection addUnknownGroupsToCollection( EnvironmentCollection environments, EnvironmentCollection toAdd) { EnvironmentCollection.Builder builder = new EnvironmentCollection.Builder(); builder.putAll(environments); for (EnvironmentGroup candidateGroup : toAdd.getGroups()) { if (!environments.getGroups().contains(candidateGroup)) { builder.putAll(candidateGroup, toAdd.getEnvironments(candidateGroup)); } } return builder.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; }