Extract part of EnvironmentGroup that's necessary for constraint calculation, so we don't have to have the whole package.
Memory increase should be minimal because there aren't that many environment groups, but it's further minimized by breaking an inner class UnpackagedEnvironmentGroup out of EnvironmentGroup. Previously, each EnvironmentGroup cost 40 bytes (24 bytes for first three fields, 8 for next two, 8 for last field because of alignment). Each UnpackagedEnvironmentGroup costs 32 bytes (4 fields), while the EnvironmentGroup now costs 24 bytes. So a loss of 16 bytes per EnvironmentGroup: shouldn't be noticeable.
PiperOrigin-RevId: 185837140
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/ConstraintSemantics.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/ConstraintSemantics.java
index 28af97d..3d16a02 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/ConstraintSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/ConstraintSemantics.java
@@ -33,6 +33,7 @@
import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.DependencyFilter;
import com.google.devtools.build.lib.packages.EnvironmentGroup;
+import com.google.devtools.build.lib.packages.EnvironmentLabels;
import com.google.devtools.build.lib.packages.RawAttributeMapper;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleClass;
@@ -149,7 +150,7 @@
* Provides a set of default environments for a given environment group.
*/
private interface DefaultsProvider {
- Collection<Label> getDefaults(EnvironmentGroup group);
+ Collection<Label> getDefaults(EnvironmentLabels group);
}
/**
@@ -157,7 +158,7 @@
*/
private static class GroupDefaultsProvider implements DefaultsProvider {
@Override
- public Collection<Label> getDefaults(EnvironmentGroup group) {
+ public Collection<Label> getDefaults(EnvironmentLabels group) {
return group.getDefaults();
}
}
@@ -177,7 +178,7 @@
}
@Override
- public Collection<Label> getDefaults(EnvironmentGroup group) {
+ public Collection<Label> getDefaults(EnvironmentLabels group) {
if (ruleClassDefaults.getGroups().contains(group)) {
return ruleClassDefaults.getEnvironments(group);
} else {
@@ -244,10 +245,11 @@
* appropriate errors if there are any problems.
*/
boolean validateEnvironmentSpecifications() {
- ImmutableCollection<EnvironmentGroup> restrictionGroups = restrictionEnvironments.getGroups();
+ ImmutableCollection<EnvironmentLabels> restrictionGroups =
+ restrictionEnvironments.getGroups();
boolean hasErrors = false;
- for (EnvironmentGroup group : compatibilityEnvironments.getGroups()) {
+ for (EnvironmentLabels 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.
@@ -288,7 +290,7 @@
EnvironmentCollection.Builder supportedEnvironments) {
EnvironmentCollection compatibilityEnvironments =
collectEnvironments(compatibilityAttr, supportedEnvironments);
- for (EnvironmentGroup group : compatibilityEnvironments.getGroups()) {
+ for (EnvironmentLabels group : compatibilityEnvironments.getGroups()) {
supportedEnvironments.putAll(group, defaultsProvider.getDefaults(group));
}
return compatibilityEnvironments;
@@ -445,7 +447,7 @@
EnvironmentCollection environments, EnvironmentCollection toAdd) {
EnvironmentCollection.Builder builder = new EnvironmentCollection.Builder();
builder.putAll(environments);
- for (EnvironmentGroup candidateGroup : toAdd.getGroups()) {
+ for (EnvironmentLabels candidateGroup : toAdd.getGroups()) {
if (!environments.getGroups().contains(candidateGroup)) {
builder.putAll(candidateGroup, toAdd.getEnvironments(candidateGroup));
}
@@ -513,7 +515,8 @@
* this collection, the rule is assumed to support the defaults for that group.
* @param refinedEnvironments a builder for populating this rule's refined environments
* @param removedEnvironmentCulprits a builder for populating the core dependencies that trigger
- * pruning away environments through refinement. If multiple dependencies qualify (e.g.
+ * pruning away environments through refinement. If multiple dependencies qualify (e.g. two
+ * direct deps under the current rule), one is arbitrarily chosen.
*/
public static void checkConstraints(
RuleContext ruleContext,
@@ -523,7 +526,7 @@
Set<EnvironmentWithGroup> refinedEnvironmentsSoFar = new LinkedHashSet<>();
// Start with the full set of static environments:
refinedEnvironmentsSoFar.addAll(staticEnvironments.getGroupedEnvironments());
- Set<EnvironmentGroup> groupsWithEnvironmentsRemoved = new LinkedHashSet<>();
+ Set<EnvironmentLabels> groupsWithEnvironmentsRemoved = new LinkedHashSet<>();
// Maps the label results of getUnsupportedEnvironments() to EnvironmentWithGroups. We can't
// have that method just return EnvironmentWithGroups because it also collects group defaults,
// which we only have labels for.
@@ -583,7 +586,7 @@
TransitiveInfoCollection dep,
Map<Label, EnvironmentWithGroup> labelsToEnvironments,
Set<EnvironmentWithGroup> refinedEnvironmentsSoFar,
- Set<EnvironmentGroup> groupsWithEnvironmentsRemoved,
+ Set<EnvironmentLabels> groupsWithEnvironmentsRemoved,
Map<Label, LabelAndLocation> removedEnvironmentCulprits) {
SupportedEnvironmentsProvider depEnvironments =
@@ -641,18 +644,19 @@
*/
private static void checkRefinedConstraints(
RuleContext ruleContext,
- Set<EnvironmentGroup> groupsWithEnvironmentsRemoved,
+ Set<EnvironmentLabels> groupsWithEnvironmentsRemoved,
Set<EnvironmentWithGroup> refinedEnvironmentsSoFar,
EnvironmentCollection.Builder refinedEnvironments,
Map<Label, LabelAndLocation> removedEnvironmentCulprits) {
- Set<EnvironmentGroup> refinedGroups = new LinkedHashSet<>();
+ Set<EnvironmentLabels> refinedGroups = new LinkedHashSet<>();
for (EnvironmentWithGroup envWithGroup : refinedEnvironmentsSoFar) {
refinedEnvironments.put(envWithGroup.group(), envWithGroup.environment());
refinedGroups.add(envWithGroup.group());
}
- Set<EnvironmentGroup> newlyEmptyGroups = groupsWithEnvironmentsRemoved.isEmpty()
- ? ImmutableSet.<EnvironmentGroup>of()
- : Sets.difference(groupsWithEnvironmentsRemoved, refinedGroups);
+ Set<EnvironmentLabels> newlyEmptyGroups =
+ groupsWithEnvironmentsRemoved.isEmpty()
+ ? ImmutableSet.of()
+ : Sets.difference(groupsWithEnvironmentsRemoved, refinedGroups);
if (!newlyEmptyGroups.isEmpty()) {
ruleContext.ruleError(getOverRefinementError(newlyEmptyGroups, removedEnvironmentCulprits));
}
@@ -663,11 +667,11 @@
* environment groups due to refining.
*/
private static String getOverRefinementError(
- Set<EnvironmentGroup> newlyEmptyGroups,
+ Set<EnvironmentLabels> newlyEmptyGroups,
Map<Label, LabelAndLocation> removedEnvironmentCulprits) {
StringBuilder message = new StringBuilder("the current command-line flags disqualify "
+ "all supported environments because of incompatible select() paths:");
- for (EnvironmentGroup group : newlyEmptyGroups) {
+ for (EnvironmentLabels group : newlyEmptyGroups) {
if (newlyEmptyGroups.size() > 1) {
message.append("\n\nenvironment group: " + group.getLabel() + ":");
}
@@ -688,7 +692,6 @@
*
* <p>For example, say we have R -> D1 -> D2 and all rules support environment E. If the
* refinement happens because D2 has
- *
* <pre>
* deps = select({":foo": ["restricted_to_E"], ":bar": ["restricted_to_F"]}} # Choose F.
* </pre>
@@ -709,8 +712,8 @@
*/
private static Collection<EnvironmentWithGroup> getDefaults(Label env,
EnvironmentCollection allEnvironments) {
- EnvironmentGroup group = null;
- for (EnvironmentGroup candidateGroup : allEnvironments.getGroups()) {
+ EnvironmentLabels group = null;
+ for (EnvironmentLabels candidateGroup : allEnvironments.getGroups()) {
if (candidateGroup.getDefaults().contains(env)) {
group = candidateGroup;
break;
@@ -726,17 +729,17 @@
/**
* 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.
+ * missing environments that would cause constraint expectations to be violated. Includes the
+ * effects of environment group defaults.
*/
- public static Collection<Label> getUnsupportedEnvironments(
+ 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();
+ EnvironmentLabels group = expectedEnv.group();
Label environment = expectedEnv.environment();
boolean isSatisfied = false;
if (actualEnvironments.getGroups().contains(group)) {
@@ -763,7 +766,7 @@
// 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()) {
+ for (EnvironmentLabels group : actualEnvironments.getGroups()) {
if (!expectedEnvironments.getGroups().contains(group)) {
for (Label expectedDefault : group.getDefaults()) {
if (!actualEnvironmentLabels.contains(expectedDefault)
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/Environment.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/Environment.java
index 0114088..f31d26c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/Environment.java
@@ -45,7 +45,8 @@
return null;
}
- EnvironmentCollection env = new EnvironmentCollection.Builder().put(group, label).build();
+ EnvironmentCollection env =
+ new EnvironmentCollection.Builder().put(group.getEnvironmentLabels(), label).build();
return new RuleConfiguredTargetBuilder(ruleContext)
.addProvider(SupportedEnvironmentsProvider.class,
new SupportedEnvironments(env, env, ImmutableMap.of()))
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/EnvironmentCollection.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/EnvironmentCollection.java
index ad582f8..7dc850e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/EnvironmentCollection.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/EnvironmentCollection.java
@@ -20,8 +20,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.packages.EnvironmentGroup;
-
+import com.google.devtools.build.lib.packages.EnvironmentLabels;
import java.util.Map;
/**
@@ -29,9 +28,9 @@
*/
@Immutable
public class EnvironmentCollection {
- private final ImmutableMultimap<EnvironmentGroup, Label> map;
+ private final ImmutableMultimap<EnvironmentLabels, Label> map;
- private EnvironmentCollection(ImmutableMultimap<EnvironmentGroup, Label> map) {
+ private EnvironmentCollection(ImmutableMultimap<EnvironmentLabels, Label> map) {
this.map = map;
}
@@ -40,11 +39,12 @@
*/
@AutoValue
abstract static class EnvironmentWithGroup {
- static EnvironmentWithGroup create(Label environment, EnvironmentGroup group) {
+ static EnvironmentWithGroup create(Label environment, EnvironmentLabels group) {
return new AutoValue_EnvironmentCollection_EnvironmentWithGroup(environment, group);
}
abstract Label environment();
- abstract EnvironmentGroup group();
+
+ abstract EnvironmentLabels group();
}
/**
@@ -56,10 +56,10 @@
}
/**
- * Returns the set of groups the environments in this collection belong to, ordered by
- * their insertion order in {@link Builder}
+ * Returns the set of groups the environments in this collection belong to, ordered by their
+ * insertion order in {@link Builder}
*/
- ImmutableSet<EnvironmentGroup> getGroups() {
+ ImmutableSet<EnvironmentLabels> getGroups() {
return map.keySet();
}
@@ -69,46 +69,39 @@
*/
ImmutableCollection<EnvironmentWithGroup> getGroupedEnvironments() {
ImmutableSet.Builder<EnvironmentWithGroup> builder = ImmutableSet.builder();
- for (Map.Entry<EnvironmentGroup, Label> entry : map.entries()) {
+ for (Map.Entry<EnvironmentLabels, Label> entry : map.entries()) {
builder.add(EnvironmentWithGroup.create(entry.getValue(), entry.getKey()));
}
return builder.build();
}
/**
- * Returns the environments in this collection that belong to the given group, ordered by
- * their insertion order in {@link Builder}. If no environments belong to the given group,
- * returns an empty collection.
+ * Returns the environments in this collection that belong to the given group, ordered by their
+ * insertion order in {@link Builder}. If no environments belong to the given group, returns an
+ * empty collection.
*/
- ImmutableCollection<Label> getEnvironments(EnvironmentGroup group) {
+ ImmutableCollection<Label> getEnvironments(EnvironmentLabels group) {
return map.get(group);
}
- /**
- * An empty collection.
- */
- static final EnvironmentCollection EMPTY =
- new EnvironmentCollection(ImmutableMultimap.<EnvironmentGroup, Label>of());
+ /** An empty collection. */
+ static final EnvironmentCollection EMPTY = new EnvironmentCollection(ImmutableMultimap.of());
/**
* Builder for {@link EnvironmentCollection}.
*/
public static class Builder {
- private final ImmutableMultimap.Builder<EnvironmentGroup, Label> mapBuilder =
+ private final ImmutableMultimap.Builder<EnvironmentLabels, Label> mapBuilder =
ImmutableMultimap.builder();
- /**
- * Inserts the given environment / owning group pair.
- */
- public Builder put(EnvironmentGroup group, Label environment) {
+ /** Inserts the given environment / owning group pair. */
+ public Builder put(EnvironmentLabels group, Label environment) {
mapBuilder.put(group, environment);
return this;
}
- /**
- * Inserts the given set of environments, all belonging to the specified group.
- */
- public Builder putAll(EnvironmentGroup group, Iterable<Label> environments) {
+ /** Inserts the given set of environments, all belonging to the specified group. */
+ public Builder putAll(EnvironmentLabels group, Iterable<Label> environments) {
mapBuilder.putAll(group, environments);
return this;
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java
index 54ad585..4e1f099 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/TopLevelConstraintSemantics.java
@@ -187,7 +187,8 @@
for (Label envLabel : expectedEnvironmentLabels) {
try {
Target env = packageManager.getTarget(eventHandler, envLabel);
- expectedEnvironmentsBuilder.put(ConstraintSemantics.getEnvironmentGroup(env), envLabel);
+ expectedEnvironmentsBuilder.put(
+ ConstraintSemantics.getEnvironmentGroup(env).getEnvironmentLabels(), envLabel);
} catch (NoSuchPackageException | NoSuchTargetException
| ConstraintSemantics.EnvironmentLookupException e) {
throw new ViewCreationFailedException("invalid target environment", e);
diff --git a/src/main/java/com/google/devtools/build/lib/packages/EnvironmentGroup.java b/src/main/java/com/google/devtools/build/lib/packages/EnvironmentGroup.java
index 0536dc3..a0e8b23 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/EnvironmentGroup.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/EnvironmentGroup.java
@@ -17,7 +17,6 @@
import com.google.common.base.Predicate;
import com.google.common.base.Verify;
import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
@@ -28,10 +27,8 @@
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.Location;
-
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -67,18 +64,9 @@
*/
@Immutable
public class EnvironmentGroup implements Target {
- private final Label label;
+ private final EnvironmentLabels environmentLabels;
private final Location location;
private final Package containingPackage;
- private final Set<Label> environments;
- private final Set<Label> defaults;
-
- /**
- * Maps a member environment to the set of environments that directly fulfill it. Note that
- * we can't populate this map until all Target instances for member environments have been
- * initialized, which may occur after group instantiation (this makes the class mutable).
- */
- private final Map<Label, NestedSet<Label>> fulfillersMap = new HashMap<>();
/**
* Predicate that matches labels from a different package than the initialized package.
@@ -106,13 +94,19 @@
* @param defaults the environments a rule implicitly supports unless otherwise specified
* @param location location in the BUILD file of this group
*/
- EnvironmentGroup(Label label, Package pkg, final List<Label> environments, List<Label> defaults,
+ EnvironmentGroup(
+ Label label,
+ Package pkg,
+ final List<Label> environments,
+ List<Label> defaults,
Location location) {
- this.label = label;
+ this.environmentLabels = new EnvironmentLabels(label, environments, defaults);
this.location = location;
this.containingPackage = pkg;
- this.environments = ImmutableSet.copyOf(environments);
- this.defaults = ImmutableSet.copyOf(defaults);
+ }
+
+ public EnvironmentLabels getEnvironmentLabels() {
+ return environmentLabels;
}
/**
@@ -130,13 +124,16 @@
// All environments should belong to the same package as this group.
for (Label environment :
- Iterables.filter(environments, new DifferentPackage(containingPackage))) {
- events.add(Event.error(location,
- environment + " is not in the same package as group " + label));
+ Iterables.filter(environmentLabels.environments, new DifferentPackage(containingPackage))) {
+ events.add(
+ Event.error(
+ location,
+ environment + " is not in the same package as group " + environmentLabels.label));
}
// The defaults must be a subset of the member environments.
- for (Label unknownDefault : Sets.difference(defaults, environments)) {
+ for (Label unknownDefault :
+ Sets.difference(environmentLabels.defaults, environmentLabels.environments)) {
events.add(Event.error(location, "default " + unknownDefault + " is not a "
+ "declared environment for group " + getLabel()));
}
@@ -145,9 +142,9 @@
}
/**
- * Checks that the group's declared environments are legitimate same-package environment
- * rules and prepares the "fulfills" relationships between these environments to support
- * {@link #getFulfillers}.
+ * Checks that the group's declared environments are legitimate same-package environment rules and
+ * prepares the "fulfills" relationships between these environments to support {@link
+ * EnvironmentLabels#getFulfillers}.
*
* @param pkgTargets mapping from label name to target instance for this group's package
* @return a list of validation errors that occurred
@@ -157,7 +154,7 @@
// Maps an environment to the environments that directly fulfill it.
Multimap<Label, Label> directFulfillers = HashMultimap.create();
- for (Label envName : environments) {
+ for (Label envName : environmentLabels.environments) {
Target env = pkgTargets.get(envName.getName());
if (isValidEnvironment(env, envName, "", events)) {
AttributeMap attr = NonconfigurableAttributeMapper.of((Rule) env);
@@ -174,9 +171,9 @@
// transitively fulfill each other. We could alternatively compute this on-demand, but since
// we don't expect these chains to be very large we opt toward computing them once at package
// load time.
- Verify.verify(fulfillersMap.isEmpty());
- for (Label envName : environments) {
- setTransitiveFulfillers(envName, directFulfillers, fulfillersMap);
+ Verify.verify(environmentLabels.fulfillersMap.isEmpty());
+ for (Label envName : environmentLabels.environments) {
+ setTransitiveFulfillers(envName, directFulfillers, environmentLabels.fulfillersMap);
}
return events;
@@ -216,7 +213,7 @@
} else if (!env.getTargetKind().equals("environment rule")) {
events.add(Event.error(location, prefix + env.getLabel() + " is not a valid environment"));
return false;
- } else if (!environments.contains(env.getLabel())) {
+ } else if (!environmentLabels.environments.contains(env.getLabel())) {
events.add(Event.error(location, prefix + env.getLabel() + " is not a member of this group"));
return false;
}
@@ -227,7 +224,7 @@
* Returns the environments that belong to this group.
*/
public Set<Label> getEnvironments() {
- return environments;
+ return environmentLabels.environments;
}
/**
@@ -235,39 +232,17 @@
* environments in this group.
*/
public Set<Label> getDefaults() {
- return defaults;
- }
-
- /**
- * Determines whether or not an environment is a default. Returns false if the environment
- * doesn't belong to this group.
- */
- public boolean isDefault(Label environment) {
- return defaults.contains(environment);
- }
-
- /**
- * Returns the set of environments that transitively fulfill the specified environment.
- * The environment must be a valid member of this group.
- *
- * <p>>For example, if the input is <code>":foo"</code> and <code>":bar"</code> fulfills
- * <code>":foo"</code> and <code>":baz"</code> fulfills <code>":bar"</code>, this returns
- * <code>[":foo", ":bar", ":baz"]</code>.
- *
- * <p>If no environments fulfill the input, returns an empty set.
- */
- public Iterable<Label> getFulfillers(Label environment) {
- return Verify.verifyNotNull(fulfillersMap.get(environment));
+ return environmentLabels.defaults;
}
@Override
public Label getLabel() {
- return label;
+ return environmentLabels.label;
}
@Override
public String getName() {
- return label.getName();
+ return environmentLabels.label.getName();
}
@Override
@@ -297,7 +272,7 @@
@Override
public String toString() {
- return targetKind() + " " + getLabel();
+ return targetKind() + " " + getLabel();
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/packages/EnvironmentLabels.java b/src/main/java/com/google/devtools/build/lib/packages/EnvironmentLabels.java
new file mode 100644
index 0000000..e756a8e
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/packages/EnvironmentLabels.java
@@ -0,0 +1,82 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.packages;
+
+import com.google.common.base.Verify;
+import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Parts of an {@link EnvironmentGroup} that are needed for analysis. Since {@link EnvironmentGroup}
+ * keeps a reference to a {@link Package} object, it is too heavyweight to store in analysis.
+ */
+@AutoCodec
+public class EnvironmentLabels {
+ final Label label;
+ final ImmutableSet<Label> environments;
+ final ImmutableSet<Label> defaults;
+ /**
+ * Maps a member environment to the set of environments that directly fulfill it. Note that we
+ * can't populate this map until all Target instances for member environments have been
+ * initialized, which may occur after group instantiation (this makes the class mutable).
+ */
+ final Map<Label, NestedSet<Label>> fulfillersMap = new HashMap<>();
+
+ EnvironmentLabels(Label label, Collection<Label> environments, Collection<Label> defaults) {
+ this.label = label;
+ this.environments = ImmutableSet.copyOf(environments);
+ this.defaults = ImmutableSet.copyOf(defaults);
+ }
+
+ public Set<Label> getEnvironments() {
+ return environments;
+ }
+
+ public Set<Label> getDefaults() {
+ return defaults;
+ }
+
+ /**
+ * Determines whether or not an environment is a default. Returns false if the environment doesn't
+ * belong to this group.
+ */
+ public boolean isDefault(Label environment) {
+ return defaults.contains(environment);
+ }
+
+ /**
+ * Returns the set of environments that transitively fulfill the specified environment. The
+ * environment must be a valid member of this group.
+ *
+ * <p>>For example, if the input is <code>":foo"</code> and <code>":bar"</code> fulfills <code>
+ * ":foo"</code> and <code>":baz"</code> fulfills <code>":bar"</code>, this returns <code>
+ * [":foo", ":bar", ":baz"]</code>.
+ *
+ * <p>If no environments fulfill the input, returns an empty set.
+ */
+ public Iterable<Label> getFulfillers(Label environment) {
+ return Verify.verifyNotNull(fulfillersMap.get(environment));
+ }
+
+ public Label getLabel() {
+ return label;
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/packages/EnvironmentGroupTest.java b/src/test/java/com/google/devtools/build/lib/packages/EnvironmentGroupTest.java
index f9dde14..a1835bc 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/EnvironmentGroupTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/EnvironmentGroupTest.java
@@ -73,18 +73,20 @@
@Test
public void testIsDefault() throws Exception {
- assertThat(group.isDefault(Label.parseAbsolute("//pkg:foo"))).isTrue();
- assertThat(group.isDefault(Label.parseAbsolute("//pkg:bar"))).isFalse();
- assertThat(group.isDefault(Label.parseAbsolute("//pkg:baz"))).isFalse();
- assertThat(group.isDefault(Label.parseAbsolute("//pkg:not_in_group"))).isFalse();
+ EnvironmentLabels unpackedGroup = group.getEnvironmentLabels();
+ assertThat(unpackedGroup.isDefault(Label.parseAbsolute("//pkg:foo"))).isTrue();
+ assertThat(unpackedGroup.isDefault(Label.parseAbsolute("//pkg:bar"))).isFalse();
+ assertThat(unpackedGroup.isDefault(Label.parseAbsolute("//pkg:baz"))).isFalse();
+ assertThat(unpackedGroup.isDefault(Label.parseAbsolute("//pkg:not_in_group"))).isFalse();
}
@Test
public void testFulfillers() throws Exception {
- assertThat(group.getFulfillers(Label.parseAbsolute("//pkg:baz")))
+ EnvironmentLabels unpackedGroup = group.getEnvironmentLabels();
+ assertThat(unpackedGroup.getFulfillers(Label.parseAbsolute("//pkg:baz")))
.containsExactly(Label.parseAbsolute("//pkg:foo"), Label.parseAbsolute("//pkg:bar"));
- assertThat(group.getFulfillers(Label.parseAbsolute("//pkg:bar")))
+ assertThat(unpackedGroup.getFulfillers(Label.parseAbsolute("//pkg:bar")))
.containsExactly(Label.parseAbsolute("//pkg:foo"));
- assertThat(group.getFulfillers(Label.parseAbsolute("//pkg:foo"))).isEmpty();
+ assertThat(unpackedGroup.getFulfillers(Label.parseAbsolute("//pkg:foo"))).isEmpty();
}
}