Provide clearer messaging when a build fails because a rule's
supported environments get refined away by incompatible
select paths.
This is a fix of TODO:
https://github.com/bazelbuild/bazel/blob/master/src/main/java/com/google/devtools/build/lib/analysis/constraints/ConstraintSemantics.java#L597
Old message:
ERROR: /workspace/foo/BUILD:3:1: in cc_binary rule //foo:main: all environments have been refined out of the following groups: //buildenv:environment_group
New message:
ERROR: /workspace/foo/BUILD:3:1: in cc_binary rule //foo:main: the current command-line flags disqualify all supported environments because of incompatible select() paths:
environment: //buildenv:gce removed by: //util/lib:some_dep_with_select (/workspace/util/lib/BUILD:12:1)
--
MOS_MIGRATED_REVID=125788804
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
index 17617e7..eb9822f 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
@@ -24,10 +24,12 @@
import com.google.devtools.build.lib.analysis.constraints.EnvironmentCollection;
import com.google.devtools.build.lib.analysis.constraints.SupportedEnvironments;
import com.google.devtools.build.lib.analysis.constraints.SupportedEnvironmentsProvider;
+import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.rules.test.ExecutionInfoProvider;
import com.google.devtools.build.lib.rules.test.InstrumentedFilesProvider;
@@ -180,9 +182,12 @@
ConstraintSemantics.getSupportedEnvironments(ruleContext);
if (supportedEnvironments != null) {
EnvironmentCollection.Builder refinedEnvironments = new EnvironmentCollection.Builder();
- ConstraintSemantics.checkConstraints(ruleContext, supportedEnvironments, refinedEnvironments);
+ Map<Label, Target> removedEnvironmentCulprits = new LinkedHashMap<>();
+ ConstraintSemantics.checkConstraints(ruleContext, supportedEnvironments, refinedEnvironments,
+ removedEnvironmentCulprits);
add(SupportedEnvironmentsProvider.class,
- new SupportedEnvironments(supportedEnvironments, refinedEnvironments.build()));
+ new SupportedEnvironments(supportedEnvironments, refinedEnvironments.build(),
+ removedEnvironmentCulprits));
}
}
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 398056c..cab7c42 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
@@ -511,9 +511,13 @@
* value of {@link #getSupportedEnvironments}. In particular, for any environment group that's
* not in 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.
+ * two direct deps under the current rule), one is arbitrarily chosen.
*/
public static void checkConstraints(RuleContext ruleContext,
- EnvironmentCollection staticEnvironments, EnvironmentCollection.Builder refinedEnvironments) {
+ EnvironmentCollection staticEnvironments, EnvironmentCollection.Builder refinedEnvironments,
+ Map<Label, Target> removedEnvironmentCulprits) {
Set<EnvironmentWithGroup> refinedEnvironmentsSoFar = new LinkedHashSet<>();
// Start with the full set of static environments:
refinedEnvironmentsSoFar.addAll(staticEnvironments.getGroupedEnvironments());
@@ -565,11 +569,13 @@
}
refinedEnvironmentsSoFar.remove(envToPrune);
groupsWithEnvironmentsRemoved.add(envToPrune.group());
+ removedEnvironmentCulprits.put(envToPrune.environment(),
+ findOriginalRefiner(ruleContext, depEnvironments, envToPrune));
}
}
checkRefinedEnvironmentConstraints(ruleContext, groupsWithEnvironmentsRemoved,
- refinedEnvironmentsSoFar, refinedEnvironments);
+ refinedEnvironmentsSoFar, refinedEnvironments, removedEnvironmentCulprits);
}
/**
@@ -582,9 +588,11 @@
* <p>Violations of this expectation trigger rule analysis errors.
*/
private static void checkRefinedEnvironmentConstraints(
- RuleContext ruleContext, Set<EnvironmentGroup> groupsWithEnvironmentsRemoved,
+ RuleContext ruleContext,
+ Set<EnvironmentGroup> groupsWithEnvironmentsRemoved,
Set<EnvironmentWithGroup> refinedEnvironmentsSoFar,
- EnvironmentCollection.Builder refinedEnvironments) {
+ EnvironmentCollection.Builder refinedEnvironments,
+ Map<Label, Target> removedEnvironmentCulprits) {
Set<EnvironmentGroup> refinedGroups = new LinkedHashSet<>();
for (EnvironmentWithGroup envWithGroup : refinedEnvironmentsSoFar) {
refinedEnvironments.put(envWithGroup.group(), envWithGroup.environment());
@@ -594,17 +602,54 @@
? ImmutableSet.<EnvironmentGroup>of()
: Sets.difference(groupsWithEnvironmentsRemoved, refinedGroups);
if (!newlyEmptyGroups.isEmpty()) {
- // TODO(bazel-team): specify exactly which deps violated expectations.
- Set<Label> groupsAsLabels = new LinkedHashSet<>();
- for (EnvironmentGroup group : newlyEmptyGroups) {
- groupsAsLabels.add(group.getLabel());
- }
- ruleContext.ruleError("all environments have been refined out of the following groups: "
- + Joiner.on(", ").join(groupsAsLabels));
+ ruleContext.ruleError(getOverRefinementError(newlyEmptyGroups, removedEnvironmentCulprits));
}
}
/**
+ * Constructs an error message for when all environments have been pruned out of one
+ * or more environment groups due to refining.
+ */
+ private static String getOverRefinementError(Set<EnvironmentGroup> newlyEmptyGroups,
+ Map<Label, Target> removedEnvironmentCulprits) {
+ StringBuilder message = new StringBuilder("the current command-line flags disqualify "
+ + "all supported environments because of incompatible select() paths:");
+ for (EnvironmentGroup group : newlyEmptyGroups) {
+ if (newlyEmptyGroups.size() > 1) {
+ message.append("\n\nenvironment group: " + group.getLabel() + ":");
+ }
+ for (Label prunedEnvironment : group.getEnvironments()) {
+ Target culprit = removedEnvironmentCulprits.get(prunedEnvironment);
+ if (culprit != null) { // Only environments this rule declared support for have culprits.
+ message.append("\n environment: " + prunedEnvironment
+ + " removed by: " + culprit.getLabel() + " (" + culprit.getLocation() + ")");
+ }
+ }
+ }
+ return message.toString();
+ }
+
+ /**
+ * Given an environment that should be refined out of the current rule because of the given dep,
+ * returns the original dep that caused the removal.
+ *
+ * <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>
+ *
+ * <p>then D2 is the original refiner (even though D1 and R inherit the same pruning).
+ */
+ private static Target findOriginalRefiner(RuleContext ruleContext,
+ SupportedEnvironmentsProvider dep, EnvironmentWithGroup envToPrune) {
+ Target depCulprit = dep.getRemovedEnvironmentCulprit(envToPrune.environment());
+ // If the dep has no record of this environment being refined, that means the current rule
+ // is the culprit.
+ return depCulprit == null ? ruleContext.getTarget() : depCulprit;
+ }
+
+ /**
* Finds the given environment in the given set and returns the default environments for its
* group.
*/
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 52e10c8..dfdc7e4 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
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.analysis.constraints;
+import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -23,6 +24,7 @@
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.packages.EnvironmentGroup;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
/**
@@ -47,7 +49,8 @@
EnvironmentCollection env = new EnvironmentCollection.Builder().put(group, label).build();
return new RuleConfiguredTargetBuilder(ruleContext)
- .addProvider(SupportedEnvironmentsProvider.class, new SupportedEnvironments(env, env))
+ .addProvider(SupportedEnvironmentsProvider.class,
+ new SupportedEnvironments(env, env, ImmutableMap.<Label, Target>of()))
.addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
.add(FileProvider.class, FileProvider.EMPTY)
.add(FilesToRunProvider.class, FilesToRunProvider.EMPTY)
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/SupportedEnvironments.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/SupportedEnvironments.java
index 681bea0..f1fcae1 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/SupportedEnvironments.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/SupportedEnvironments.java
@@ -14,17 +14,25 @@
package com.google.devtools.build.lib.analysis.constraints;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.packages.Target;
+
+import java.util.Map;
+
/**
* Standard {@link SupportedEnvironmentsProvider} implementation.
*/
public class SupportedEnvironments implements SupportedEnvironmentsProvider {
private final EnvironmentCollection staticEnvironments;
private final EnvironmentCollection refinedEnvironments;
+ private final ImmutableMap<Label, Target> removedEnvironmentCulprits;
public SupportedEnvironments(EnvironmentCollection staticEnvironments,
- EnvironmentCollection refinedEnvironments) {
+ EnvironmentCollection refinedEnvironments, Map<Label, Target> removedEnvironmentCulprits) {
this.staticEnvironments = staticEnvironments;
this.refinedEnvironments = refinedEnvironments;
+ this.removedEnvironmentCulprits = ImmutableMap.copyOf(removedEnvironmentCulprits);
}
@Override
@@ -36,4 +44,9 @@
public EnvironmentCollection getRefinedEnvironments() {
return refinedEnvironments;
}
+
+ @Override
+ public Target getRemovedEnvironmentCulprit(Label environment) {
+ return removedEnvironmentCulprits.get(environment);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/SupportedEnvironmentsProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/SupportedEnvironmentsProvider.java
index 3337a44..81909fc 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/SupportedEnvironmentsProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/SupportedEnvironmentsProvider.java
@@ -15,6 +15,8 @@
package com.google.devtools.build.lib.analysis.constraints;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.packages.Target;
/**
* A provider that advertises which environments the associated target is compatible with
@@ -39,4 +41,20 @@
* {@link ConstraintSemantics} for details.
*/
EnvironmentCollection getRefinedEnvironments();
+
+ /**
+ * If the given environment was refined away from this target's set of supported environments,
+ * returns the dependency that originally removed the environment.
+ *
+ * <p>For example, if the current rule is restricted_to [E] and depends on D1, D1 is
+ * restricted_to [E] and depends on D2, and D2 is restricted_to [E, F] and has a select()
+ * with one path following an E-restricted dep and the other path following an F-restricted dep,
+ * then when the build chooses the F path the current rule has [E] refined to [] and D2 is the
+ * culprit.
+ *
+ * <p>If the given environment was not refined away for this rule, returns null.
+ *
+ * <p>See {@link ConstraintSemantics} class documentation for more details on refinement.
+ */
+ Target getRemovedEnvironmentCulprit(Label environment);
}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/constraints/ConstraintsTest.java b/src/test/java/com/google/devtools/build/lib/analysis/constraints/ConstraintsTest.java
index 721a796..4d4b382 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/constraints/ConstraintsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/constraints/ConstraintsTest.java
@@ -210,7 +210,7 @@
* environment set is empty.
*/
@Test
- public void testDefaultSupportedEnvironments() throws Exception {
+ public void defaultSupportedEnvironments() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
String ruleDef = getDependencyRule();
assertThat(supportedEnvironments("dep", ruleDef)).isEmpty();
@@ -220,7 +220,7 @@
* "Constraining" a rule's environments explicitly sets them.
*/
@Test
- public void testConstrainedSupportedEnvironments() throws Exception {
+ public void constrainedSupportedEnvironments() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
String ruleDef = getDependencyRule(constrainedTo("//buildenv/foo:c"));
@@ -232,7 +232,7 @@
* Specifying compatibility adds the specified environments to the defaults.
*/
@Test
- public void testCompatibleSupportedEnvironments() throws Exception {
+ public void compatibleSupportedEnvironments() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
String ruleDef = getDependencyRule(compatibleWith("//buildenv/foo:c"));
@@ -244,7 +244,7 @@
* A rule can't support *no* environments.
*/
@Test
- public void testSupportedEnvironmentsConstrainedtoNothing() throws Exception {
+ public void supportedEnvironmentsConstrainedtoNothing() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
reporter.removeHandler(failFastHandler);
String ruleDef = getDependencyRule(constrainedTo());
@@ -256,7 +256,7 @@
* Restrict the environments within one group, declare compatibility for another.
*/
@Test
- public void testSupportedEnvironmentsInMultipleGroups() throws Exception {
+ public void supportedEnvironmentsInMultipleGroups() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
new EnvironmentGroupMaker("buildenv/bar").setEnvironments("c", "d").setDefaults("c").make();
String ruleDef = getDependencyRule(
@@ -270,7 +270,7 @@
* The same label can't appear in both a constraint and a compatibility declaration.
*/
@Test
- public void testSameEnvironmentCompatibleAndRestricted() throws Exception {
+ public void sameEnvironmentCompatibleAndRestricted() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
reporter.removeHandler(failFastHandler);
String ruleDef = getDependencyRule(
@@ -283,7 +283,7 @@
* Two labels from the same group can't appear in different attributes.
*/
@Test
- public void testSameGroupCompatibleAndRestricted() throws Exception {
+ public void sameGroupCompatibleAndRestricted() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
reporter.removeHandler(failFastHandler);
String ruleDef = getDependencyRule(
@@ -297,7 +297,7 @@
* Tests that rule class defaults change a rule's default set of environments.
*/
@Test
- public void testSupportedEnvironmentsRuleClassDefaults() throws Exception {
+ public void supportedEnvironmentsRuleClassDefaults() throws Exception {
writeRuleClassDefaultEnvironments();
String ruleDef = "rule_class_default(name = 'a')";
Set<Label> expectedEnvironments = asLabelSet("//buildenv/rule_class_compat:a",
@@ -309,7 +309,7 @@
* Tests that explicit declarations override rule class defaults.
*/
@Test
- public void testExplicitAttributesOverrideRuleClassDefaults() throws Exception {
+ public void explicitAttributesOverrideRuleClassDefaults() throws Exception {
writeRuleClassDefaultEnvironments();
String ruleDef = "rule_class_default("
+ " name = 'a',"
@@ -326,7 +326,7 @@
* in rule class defaults but not in explicit rule attributes.
*/
@Test
- public void testKnownEnvironmentsIncludesThoseFromRuleClassDefaults() throws Exception {
+ public void knownEnvironmentsIncludesThoseFromRuleClassDefaults() throws Exception {
writeRuleClassDefaultEnvironments();
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
String ruleDef = "rule_class_default("
@@ -344,7 +344,7 @@
* compatibility rule class defaults.
*/
@Test
- public void testSameEnvironmentRuleClassCompatibleAndRestricted() throws Exception {
+ public void sameEnvironmentRuleClassCompatibleAndRestricted() throws Exception {
writeRuleClassDefaultEnvironments();
reporter.removeHandler(failFastHandler);
String ruleDef = "bad_rule_class_default(name = 'a')";
@@ -357,7 +357,7 @@
* Tests that a dependency is valid if both rules implicitly inherit all default environments.
*/
@Test
- public void testAllDefaults() throws Exception {
+ public void allDefaults() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
getDependencyRule(),
@@ -370,7 +370,7 @@
* Tests that a dependency is valid when both rules explicitly declare the same constraints.
*/
@Test
- public void testSameConstraintsDeclaredExplicitly() throws Exception {
+ public void sameConstraintsDeclaredExplicitly() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
getDependencyRule(constrainedTo("//buildenv/foo:b")),
@@ -384,7 +384,7 @@
* their constraints and the depender supports a subset of the dependency's environments
*/
@Test
- public void testValidConstraintsDeclaredExplicitly() throws Exception {
+ public void validConstraintsDeclaredExplicitly() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
getDependencyRule(constrainedTo("//buildenv/foo:a", "//buildenv/foo:b")),
@@ -398,7 +398,7 @@
* their constraints and the depender supports an environment the dependency doesn't.
*/
@Test
- public void testInvalidConstraintsDeclaredExplicitly() throws Exception {
+ public void invalidConstraintsDeclaredExplicitly() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
getDependencyRule(constrainedTo("//buildenv/foo:b")),
@@ -414,7 +414,7 @@
* defaults.
*/
@Test
- public void testSameCompatibilityConstraints() throws Exception {
+ public void sameCompatibilityConstraints() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
scratch.file("hello/BUILD",
@@ -429,7 +429,7 @@
* the depender only adds environments also added by the dependency.
*/
@Test
- public void testValidCompatibilityConstraints() throws Exception {
+ public void validCompatibilityConstraints() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
scratch.file("hello/BUILD",
@@ -444,7 +444,7 @@
* the depender adds environments not added by the dependency.
*/
@Test
- public void testInvalidCompatibilityConstraints() throws Exception {
+ public void invalidCompatibilityConstraints() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
scratch.file("hello/BUILD",
@@ -460,7 +460,7 @@
* Tests the error message when the dependency is missing multiple expected environments.
*/
@Test
- public void testMultipleMissingEnvironments() throws Exception {
+ public void multipleMissingEnvironments() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
scratch.file("hello/BUILD",
@@ -476,7 +476,7 @@
* Tests a valid dependency including environments from different groups.
*/
@Test
- public void testValidMultigroupConstraints() throws Exception {
+ public void validMultigroupConstraints() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
new EnvironmentGroupMaker("buildenv/bar").setEnvironments("d", "e", "f").setDefaults("d")
@@ -493,7 +493,7 @@
* Tests an invalid dependency including environments from different groups.
*/
@Test
- public void testInvalidMultigroupConstraints() throws Exception {
+ public void invalidMultigroupConstraints() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
new EnvironmentGroupMaker("buildenv/bar").setEnvironments("d", "e", "f").setDefaults("d")
@@ -513,7 +513,7 @@
* group, but implicitly supports it because that environment is a default.
*/
@Test
- public void testValidConstraintsUnknownEnvironmentToDependency() throws Exception {
+ public void validConstraintsUnknownEnvironmentToDependency() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a", "b")
.make();
scratch.file("hello/BUILD",
@@ -528,7 +528,7 @@
* environment's group and doesn't support it because it isn't a default.
*/
@Test
- public void testInvalidConstraintsUnknownEnvironmentToDependency() throws Exception {
+ public void invalidConstraintsUnknownEnvironmentToDependency() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a", "b")
.make();
scratch.file("hello/BUILD",
@@ -546,7 +546,7 @@
* are accounted for in the dependency.
*/
@Test
- public void testValidConstraintsUnknownEnvironmentToDependender() throws Exception {
+ public void validConstraintsUnknownEnvironmentToDependender() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
scratch.file("hello/BUILD",
@@ -562,7 +562,7 @@
* isn't accounted for in the dependency.
*/
@Test
- public void testInvalidConstraintsUnknownEnvironmentToDependender() throws Exception {
+ public void invalidConstraintsUnknownEnvironmentToDependender() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
scratch.file("hello/BUILD",
@@ -578,7 +578,7 @@
* Tests the case where one dependency is valid and another one isn't.
*/
@Test
- public void testOneDependencyIsInvalid() throws Exception {
+ public void oneDependencyIsInvalid() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
getRuleDef("sh_library", "bad_dep", constrainedTo("//buildenv/foo:b")),
@@ -593,7 +593,7 @@
}
@Test
- public void testConstraintEnforcementDisabled() throws Exception {
+ public void constraintEnforcementDisabled() throws Exception {
useConfiguration("--experimental_enforce_constraints=0");
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b", "c").setDefaults("a")
.make();
@@ -609,7 +609,7 @@
* be invalid.
*/
@Test
- public void testCompatibilityPackageDefaults() throws Exception {
+ public void compatibilityPackageDefaults() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
"package(default_compatible_with = ['//buildenv/foo:b'])",
@@ -623,7 +623,7 @@
* Tests that a rule's compatibility declaration overrides its package defaults compatibility.
*/
@Test
- public void testPackageDefaultsCompatibilityOverride() throws Exception {
+ public void packageDefaultsCompatibilityOverride() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
// We intentionally create an invalid dependency structure vs. a valid one. If we tested on
// a valid one, this test wouldn't be able to distinguish between rule declarations overriding
@@ -643,7 +643,7 @@
* be invalid.
*/
@Test
- public void testRestrictionPackageDefaults() throws Exception {
+ public void restrictionPackageDefaults() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a", "b")
.make();
scratch.file("hello/BUILD",
@@ -658,7 +658,7 @@
* Tests that a rule's restriction declaration overrides its package defaults restriction.
*/
@Test
- public void testPackageDefaultsRestrictionOverride() throws Exception {
+ public void packageDefaultsRestrictionOverride() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
// We intentionally create an invalid dependency structure vs. a valid one. If we tested on
// a valid one, this test wouldn't be able to distinguish between rule declarations overriding
@@ -680,7 +680,7 @@
* before being supplied to the rule. See comments in DependencyResolver for more discussion.
*/
@Test
- public void testPackageDefaultsDirectlyFillRuleAttributes() throws Exception {
+ public void packageDefaultsDirectlyFillRuleAttributes() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
scratch.file("hello/BUILD",
"package(default_restricted_to = ['//buildenv/foo:b'])",
@@ -692,7 +692,7 @@
}
@Test
- public void testHostDependenciesAreNotChecked() throws Exception {
+ public void hostDependenciesAreNotChecked() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
"sh_binary(name = 'host_tool',",
@@ -710,7 +710,7 @@
}
@Test
- public void testHostDependenciesNotCheckedNoDistinctHostConfiguration() throws Exception {
+ public void hostDependenciesNotCheckedNoDistinctHostConfiguration() throws Exception {
useConfiguration("--nodistinct_host_configuration");
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
@@ -729,7 +729,7 @@
}
@Test
- public void testImplicitAndLateBoundDependenciesAreNotChecked() throws Exception {
+ public void implicitAndLateBoundDependenciesAreNotChecked() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
"rule_with_implicit_and_latebound_deps(",
@@ -744,7 +744,7 @@
}
@Test
- public void testImplicitDepsWithWhiteListedAttributeAreChecked() throws Exception {
+ public void implicitDepsWithWhiteListedAttributeAreChecked() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("a").make();
scratch.file("hello/BUILD",
"rule_with_enforced_implicit_deps(",
@@ -757,7 +757,7 @@
}
@Test
- public void testOutputFilesAreChecked() throws Exception {
+ public void outputFilesAreChecked() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
scratch.file("hello/BUILD",
"genrule(name = 'gen', srcs = [], outs = ['shlib.sh'], cmd = '')",
@@ -773,7 +773,7 @@
}
@Test
- public void testConfigSettingRulesAreNotChecked() throws Exception {
+ public void configSettingRulesAreNotChecked() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
scratch.file("hello/BUILD",
"sh_library(",
@@ -788,7 +788,7 @@
}
@Test
- public void testFulfills() throws Exception {
+ public void fulfills() throws Exception {
new EnvironmentGroupMaker("buildenv/foo")
.setEnvironments("a", "b")
.setFulfills("a", "b")
@@ -802,7 +802,7 @@
}
@Test
- public void testFulfillsIsNotSymmetric() throws Exception {
+ public void fulfillsIsNotSymmetric() throws Exception {
new EnvironmentGroupMaker("buildenv/foo")
.setEnvironments("a", "b")
.setFulfills("a", "b")
@@ -818,7 +818,7 @@
}
@Test
- public void testFulfillsIsTransitive() throws Exception {
+ public void fulfillsIsTransitive() throws Exception {
new EnvironmentGroupMaker("buildenv/foo")
.setEnvironments("a", "b", "c")
.setFulfills("a", "b")
@@ -833,7 +833,7 @@
}
@Test
- public void testDefaultEnvironmentDirectlyFulfills() throws Exception {
+ public void defaultEnvironmentDirectlyFulfills() throws Exception {
new EnvironmentGroupMaker("buildenv/foo")
.setEnvironments("a", "b")
.setFulfills("a", "b")
@@ -847,7 +847,7 @@
}
@Test
- public void testDefaultEnvironmentIndirectlyFulfills() throws Exception {
+ public void defaultEnvironmentIndirectlyFulfills() throws Exception {
new EnvironmentGroupMaker("buildenv/foo")
.setEnvironments("a", "b", "c")
.setFulfills("a", "b")
@@ -862,7 +862,7 @@
}
@Test
- public void testEnvironmentFulfillsExpectedDefault() throws Exception {
+ public void environmentFulfillsExpectedDefault() throws Exception {
new EnvironmentGroupMaker("buildenv/foo")
.setEnvironments("a", "b")
.setFulfills("a", "b")
@@ -876,7 +876,7 @@
}
@Test
- public void testConstraintExemptRulesDontHaveConstraintAttributes() throws Exception {
+ public void constraintExemptRulesDontHaveConstraintAttributes() throws Exception {
new EnvironmentGroupMaker("buildenv/foo")
.setEnvironments("a", "b")
.setDefaults("a")
@@ -893,7 +893,7 @@
}
@Test
- public void testBuildingEnvironmentGroupDirectlyDoesntCrash() throws Exception {
+ public void buildingEnvironmentGroupDirectlyDoesntCrash() throws Exception {
new EnvironmentGroupMaker("buildenv/foo")
.setEnvironments("a", "b")
.setDefaults("a")
@@ -914,7 +914,7 @@
}
@Test
- public void testSelectableDepsCanMissEnvironments() throws Exception {
+ public void selectableDepsCanMissEnvironments() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
writeDepsForSelectTests();
scratch.file("hello/BUILD",
@@ -931,7 +931,7 @@
}
@Test
- public void testStaticCheckingOnSelectsTemporarilyDisabled() throws Exception {
+ public void staticCheckingOnSelectsTemporarilyDisabled() throws Exception {
// TODO(bazel-team): update this test once static checking on selects is implemented. When
// that happens, the union of all deps in the select must support the environments in the
// depending rule. So the logic here is constraint-invalid because //buildenv/foo:c isn't
@@ -952,7 +952,7 @@
}
@Test
- public void testDepInBothSelectAndUnconditionalListIsAlwaysChecked() throws Exception {
+ public void depInBothSelectAndUnconditionalListIsAlwaysChecked() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
writeDepsForSelectTests();
scratch.file("hello/BUILD",
@@ -973,7 +973,7 @@
}
@Test
- public void testUnconditionalSelectsAlwaysChecked() throws Exception {
+ public void unconditionalSelectsAlwaysChecked() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
writeDepsForSelectTests();
scratch.file("hello/BUILD",
@@ -991,7 +991,7 @@
}
@Test
- public void testRefinedEnvironmentCheckingValidCaseDirect() throws Exception {
+ public void refinedEnvironmentCheckingValidCaseDirect() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
writeDepsForSelectTests();
scratch.file("hello/BUILD",
@@ -1009,7 +1009,7 @@
}
@Test
- public void testRefinedEnvironmentCheckingBadCaseDirect() throws Exception {
+ public void refinedEnvironmentCheckingBadCaseDirect() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
writeDepsForSelectTests();
scratch.file("hello/BUILD",
@@ -1025,12 +1025,13 @@
reporter.removeHandler(failFastHandler);
// Invalid because "--define mode=a" refines :lib to "compatible_with = []" (empty).
assertNull(getConfiguredTarget("//hello:lib"));
- assertContainsEvent("//hello:lib: all environments have been refined out of the following"
- + " groups: //buildenv/foo:foo");
+ assertContainsEvent("//hello:lib: the current command-line flags disqualify all supported "
+ + "environments because of incompatible select() paths:\n"
+ + " environment: //buildenv/foo:b removed by: //hello:lib (/workspace/hello/BUILD:1:1)");
}
@Test
- public void testRefinedEnvironmentCheckingValidCaseTransitive() throws Exception {
+ public void refinedEnvironmentCheckingValidCaseTransitive() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
writeDepsForSelectTests();
scratch.file("hello/BUILD",
@@ -1053,7 +1054,7 @@
}
@Test
- public void testRefinedEnvironmentCheckingBadCaseTransitive() throws Exception {
+ public void refinedEnvironmentCheckingBadCaseTransitive() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
writeDepsForSelectTests();
scratch.file("hello/BUILD",
@@ -1074,12 +1075,48 @@
reporter.removeHandler(failFastHandler);
// Invalid because "--define mode=a" refines :lib to "compatible_with = ['//buildenv/foo:a']".
assertNull(getConfiguredTarget("//hello:depender"));
- assertContainsEvent("//hello:depender: all environments have been refined out of the following"
- + " groups: //buildenv/foo:foo");
+ assertContainsEvent("//hello:depender: the current command-line flags disqualify all supported "
+ + "environments because of incompatible select() paths:\n"
+ + " environment: //buildenv/foo:b removed by: //hello:lib (/workspace/hello/BUILD:1:1)");
}
@Test
- public void testEnvironmentRefiningAccountsForImplicitDefaults() throws Exception {
+ public void refinedEnvironmentCheckingBadCaseChooseLowestLevelCulprit() throws Exception {
+ new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
+ writeDepsForSelectTests();
+ scratch.file("hello/BUILD",
+ "cc_library(",
+ " name = 'lib2',", // Even though both lib1 and lib2 refine away b, lib2 is the culprit.
+ " srcs = [],",
+ " deps = select({",
+ " '//config:a': ['//deps:dep_a'],",
+ " '//config:b': ['//deps:dep_b'],",
+ " }),",
+ " compatible_with = ['//buildenv/foo:a', '//buildenv/foo:b'])",
+ "cc_library(",
+ " name = 'lib1',",
+ " srcs = [],",
+ " deps = select({",
+ " '//config:a': [':lib2'],",
+ " '//config:b': ['//deps:dep_b'],",
+ " }),",
+ " compatible_with = ['//buildenv/foo:a', '//buildenv/foo:b'])",
+ "cc_library(",
+ " name = 'depender',",
+ " srcs = [],",
+ " deps = [':lib1'],",
+ " compatible_with = ['//buildenv/foo:b'])");
+ useConfiguration("--define", "mode=a");
+ reporter.removeHandler(failFastHandler);
+ // Invalid because "--define mode=a" refines :lib to "compatible_with = ['//buildenv/foo:a']".
+ assertNull(getConfiguredTarget("//hello:depender"));
+ assertContainsEvent("//hello:depender: the current command-line flags disqualify all supported "
+ + "environments because of incompatible select() paths:\n"
+ + " environment: //buildenv/foo:b removed by: //hello:lib2 (/workspace/hello/BUILD:1:1)");
+ }
+
+ @Test
+ public void environmentRefiningAccountsForImplicitDefaults() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults("b").make();
writeDepsForSelectTests();
scratch.file("hello/BUILD",
@@ -1095,12 +1132,13 @@
// Invalid because :lib has an implicit default of ['//buildenv/foo:b'] and "--define mode=a"
// refines it to "compatible_with = []" (empty).
assertNull(getConfiguredTarget("//hello:lib"));
- assertContainsEvent("//hello:lib: all environments have been refined out of the following"
- + " groups: //buildenv/foo:foo");
+ assertContainsEvent("//hello:lib: the current command-line flags disqualify all supported "
+ + "environments because of incompatible select() paths:\n"
+ + " environment: //buildenv/foo:b removed by: //hello:lib (/workspace/hello/BUILD:1:1)");
}
@Test
- public void testEnvironmentRefiningChecksAllEnvironmentGroups() throws Exception {
+ public void environmentRefiningChecksAllEnvironmentGroups() throws Exception {
new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
new EnvironmentGroupMaker("buildenv/bar").setEnvironments("c", "d").setDefaults().make();
scratch.file("deps/BUILD",
@@ -1126,8 +1164,45 @@
// Invalid because while the //buildenv/foo refinement successfully refines :lib to
// ['//buildenv/foo:a'], the bar refinement refines it to [].
assertNull(getConfiguredTarget("//hello:lib"));
- assertContainsEvent("//hello:lib: all environments have been refined out of the following"
- + " groups: //buildenv/bar:bar");
+ assertContainsEvent("//hello:lib: the current command-line flags disqualify all supported "
+ + "environments because of incompatible select() paths:\n"
+ + " environment: //buildenv/bar:c removed by: //hello:lib (/workspace/hello/BUILD:1:1)");
+ }
+
+ /**
+ * When multiple environment groups get cleared out by refinement, batch the missing environments
+ * by group membership.
+ */
+ @Test
+ public void refinedEnvironmentCheckingPartitionsErrorsbyEnvironmentGroup() throws Exception {
+ new EnvironmentGroupMaker("buildenv/foo").setEnvironments("a", "b").setDefaults().make();
+ new EnvironmentGroupMaker("buildenv/bar").setEnvironments("c", "d").setDefaults().make();
+ scratch.file("hello/BUILD",
+ "cc_library(",
+ " name = 'all_groups_gone',",
+ " srcs = [],",
+ " restricted_to = ['//buildenv/foo:b', '//buildenv/bar:d'])",
+ "cc_library(",
+ " name = 'all_groups_there',",
+ " srcs = [],",
+ " restricted_to = ['//buildenv/foo:a', '//buildenv/bar:c'])",
+ "cc_library(",
+ " name = 'lib',",
+ " srcs = [],",
+ " deps = select({",
+ " '//config:a': [':all_groups_gone'],",
+ " '//config:b': [':all_groups_there'],",
+ " }),",
+ " compatible_with = ['//buildenv/foo:a', '//buildenv/bar:c'])");
+ useConfiguration("--define", "mode=a");
+ reporter.removeHandler(failFastHandler);
+ assertNull(getConfiguredTarget("//hello:lib"));
+ assertContainsEvent("//hello:lib: the current command-line flags disqualify all supported "
+ + "environments because of incompatible select() paths:\n"
+ + "\nenvironment group: //buildenv/foo:foo:\n"
+ + " environment: //buildenv/foo:a removed by: //hello:lib (/workspace/hello/BUILD:9:1)\n"
+ + "\nenvironment group: //buildenv/bar:bar:\n"
+ + " environment: //buildenv/bar:c removed by: //hello:lib (/workspace/hello/BUILD:9:1)");
}
}