aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
diff options
context:
space:
mode:
authorGravatar Michael Staib <mstaib@google.com>2016-09-16 19:36:49 +0000
committerGravatar Laszlo Csomor <laszlocsomor@google.com>2016-09-19 07:35:07 +0000
commit8618b9d67d20a737908113fa89357ac321a9669b (patch)
treec35e40647b56648f25716aa209525257619ea664 /src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
parent1ca32990938c4b126cbe49895b757403e8fbf07a (diff)
Add deprecation support to Bazel.
Bazel has always had a deprecation attribute, but until now it has been a no-op. After this change, Bazel will warn when a target with the deprecated attribute unset depends on one with the deprecated attribute set. Like all other warnings, this warning will only be displayed when it matches the output filter. It is also bypassed if the two targets are in the same package. RELNOTES: The deprecation attribute of all rules now causes warnings to be printed when other targets depend on a target with that attribute set. -- MOS_MIGRATED_REVID=133415232
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
index 42c935e817..3f018d37eb 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredRuleClassProvider.java
@@ -33,13 +33,19 @@ import com.google.devtools.build.lib.analysis.config.DefaultsPackage;
import com.google.devtools.build.lib.analysis.config.FragmentOptions;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.cmdline.PackageIdentifier;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.graph.Digraph;
import com.google.devtools.build.lib.graph.Node;
import com.google.devtools.build.lib.packages.Attribute;
import com.google.devtools.build.lib.packages.NativeAspectClass;
+import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper;
+import com.google.devtools.build.lib.packages.OutputFile;
+import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClassProvider;
+import com.google.devtools.build.lib.packages.RuleErrorConsumer;
+import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.rules.SkylarkModules;
import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy;
@@ -47,6 +53,7 @@ import com.google.devtools.build.lib.syntax.Environment;
import com.google.devtools.build.lib.syntax.Environment.Extension;
import com.google.devtools.build.lib.syntax.Environment.Phase;
import com.google.devtools.build.lib.syntax.Mutability;
+import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.common.options.OptionsClassProvider;
import java.lang.reflect.Constructor;
@@ -83,6 +90,90 @@ public class ConfiguredRuleClassProvider implements RuleClassProvider {
RuleContext.Builder contextBuilder, ConfiguredTarget prerequisite, Attribute attribute);
}
+ /** Validator to check for and warn on the deprecation of dependencies. */
+ public static final class DeprecationValidator implements PrerequisiteValidator {
+ /** Checks if the given prerequisite is deprecated and prints a warning if so. */
+ @Override
+ public void validate(
+ RuleContext.Builder contextBuilder, ConfiguredTarget prerequisite, Attribute attribute) {
+ validateDirectPrerequisiteForDeprecation(
+ contextBuilder, contextBuilder.getRule(), prerequisite);
+ }
+
+ /**
+ * Returns whether two packages are considered the same for purposes of deprecation warnings.
+ * Dependencies within the same package do not print deprecation warnings; a package in the
+ * javatests directory may also depend on its corresponding java package without a warning.
+ */
+ public static boolean isSameLogicalPackage(
+ PackageIdentifier thisPackage, PackageIdentifier prerequisitePackage) {
+ if (thisPackage.equals(prerequisitePackage)) {
+ // If the packages are equal, they are the same logical package (and just the same package).
+ return true;
+ }
+ if (!thisPackage.getRepository().equals(prerequisitePackage.getRepository())) {
+ // If the packages are in different repositories, they are not the same logical package.
+ return false;
+ }
+ // If the packages are in the same repository, it's allowed iff this package is the javatests
+ // companion to the prerequisite java package.
+ String thisPackagePath = thisPackage.getPackageFragment().getPathString();
+ String prerequisitePackagePath = prerequisitePackage.getPackageFragment().getPathString();
+ return thisPackagePath.startsWith("javatests/")
+ && prerequisitePackagePath.startsWith("java/")
+ && thisPackagePath.substring("javatests/".length()).equals(
+ prerequisitePackagePath.substring("java/".length()));
+ }
+
+ /** Returns whether a deprecation warning should be printed for the prerequisite described. */
+ private static boolean shouldEmitDeprecationWarningFor(
+ String thisDeprecation, PackageIdentifier thisPackage,
+ String prerequisiteDeprecation, PackageIdentifier prerequisitePackage) {
+ // Don't report deprecation edges from javatests to java or within a package;
+ // otherwise tests of deprecated code generate nuisance warnings.
+ // Don't report deprecation if the current target is also deprecated.
+ return (prerequisiteDeprecation != null
+ && !isSameLogicalPackage(thisPackage, prerequisitePackage)
+ && thisDeprecation == null);
+ }
+
+ /** Checks if the given prerequisite is deprecated and prints a warning if so. */
+ public static void validateDirectPrerequisiteForDeprecation(
+ RuleErrorConsumer errors, Rule rule, ConfiguredTarget prerequisite) {
+ Target prerequisiteTarget = prerequisite.getTarget();
+ Label prerequisiteLabel = prerequisiteTarget.getLabel();
+ PackageIdentifier thatPackage = prerequisiteLabel.getPackageIdentifier();
+ PackageIdentifier thisPackage = rule.getLabel().getPackageIdentifier();
+
+ if (prerequisiteTarget instanceof Rule) {
+ Rule prerequisiteRule = (Rule) prerequisiteTarget;
+ String thisDeprecation =
+ NonconfigurableAttributeMapper.of(rule).get("deprecation", Type.STRING);
+ String thatDeprecation =
+ NonconfigurableAttributeMapper.of(prerequisiteRule).get("deprecation", Type.STRING);
+ if (shouldEmitDeprecationWarningFor(
+ thisDeprecation, thisPackage, thatDeprecation, thatPackage)) {
+ errors.ruleWarning("target '" + rule.getLabel() + "' depends on deprecated target '"
+ + prerequisiteLabel + "': " + thatDeprecation);
+ }
+ }
+
+ if (prerequisiteTarget instanceof OutputFile) {
+ Rule generatingRule = ((OutputFile) prerequisiteTarget).getGeneratingRule();
+ String thisDeprecation =
+ NonconfigurableAttributeMapper.of(rule).get("deprecation", Type.STRING);
+ String thatDeprecation =
+ NonconfigurableAttributeMapper.of(generatingRule).get("deprecation", Type.STRING);
+ if (shouldEmitDeprecationWarningFor(
+ thisDeprecation, thisPackage, thatDeprecation, thatPackage)) {
+ errors.ruleWarning("target '" + rule.getLabel() + "' depends on the output file "
+ + prerequisiteLabel + " of a deprecated rule " + generatingRule.getLabel()
+ + "': " + thatDeprecation);
+ }
+ }
+ }
+ }
+
/**
* Builder for {@link ConfiguredRuleClassProvider}.
*/