Detect one version violations while building android_binary targets
PiperOrigin-RevId: 161910195
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index b9b9d78..6fb4a3c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -36,6 +36,7 @@
import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
+import com.google.devtools.build.lib.analysis.OutputGroupProvider;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
@@ -63,11 +64,13 @@
import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.rules.java.JavaConfiguration.JavaOptimizationMode;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel;
import com.google.devtools.build.lib.rules.java.JavaHelper;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider;
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
import com.google.devtools.build.lib.rules.java.JavaToolchainProvider;
+import com.google.devtools.build.lib.rules.java.OneVersionCheckActionBuilder;
import com.google.devtools.build.lib.rules.java.ProguardHelper;
import com.google.devtools.build.lib.rules.java.ProguardHelper.ProguardOutput;
import com.google.devtools.build.lib.syntax.Type;
@@ -370,6 +373,29 @@
Artifact deployJar = createDeployJar(ruleContext, javaSemantics, androidCommon, resourceClasses,
derivedJarFunction);
+ OneVersionEnforcementLevel oneVersionEnforcementLevel =
+ ruleContext.getFragment(JavaConfiguration.class).oneVersionEnforcementLevel();
+ Artifact oneVersionOutputArtifact = null;
+ if (oneVersionEnforcementLevel != OneVersionEnforcementLevel.OFF) {
+ NestedSet<Artifact> transitiveDependencies =
+ NestedSetBuilder.<Artifact>stableOrder()
+ .addAll(
+ Iterables.transform(resourceClasses.getRuntimeClassPath(), derivedJarFunction))
+ .addAll(
+ Iterables.transform(
+ androidCommon.getJarsProducedForRuntime(), derivedJarFunction))
+ .build();
+
+ oneVersionOutputArtifact =
+ OneVersionCheckActionBuilder.newBuilder()
+ .withEnforcementLevel(oneVersionEnforcementLevel)
+ .outputArtifact(
+ ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_ONE_VERSION_ARTIFACT))
+ .useToolchain(JavaToolchainProvider.fromRuleContext(ruleContext))
+ .checkJars(transitiveDependencies)
+ .build(ruleContext);
+ }
+
Artifact proguardMapping = ruleContext.getPrerequisiteArtifact(
"proguard_apply_mapping", Mode.TARGET);
@@ -393,7 +419,8 @@
resourceClasses,
ImmutableList.<Artifact>of(),
ImmutableList.<Artifact>of(),
- proguardMapping);
+ proguardMapping,
+ oneVersionOutputArtifact);
}
public static RuleConfiguredTargetBuilder createAndroidBinary(
@@ -416,7 +443,8 @@
JavaTargetAttributes resourceClasses,
ImmutableList<Artifact> apksUnderTest,
ImmutableList<Artifact> additionalMergedManifests,
- Artifact proguardMapping)
+ Artifact proguardMapping,
+ @Nullable Artifact oneVersionEnforcementArtifact)
throws InterruptedException, RuleErrorException {
ImmutableList<Artifact> proguardSpecs = ProguardHelper.collectTransitiveProguardSpecs(
@@ -786,6 +814,10 @@
ProguardMappingProvider.create(finalProguardMap));
}
+ if (oneVersionEnforcementArtifact != null) {
+ builder.addOutputGroup(OutputGroupProvider.HIDDEN_TOP_LEVEL, oneVersionEnforcementArtifact);
+ }
+
return builder
.setFilesToBuild(filesToBuild)
.addProvider(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
index b562eac..a77e250 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
@@ -15,7 +15,6 @@
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
import static com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression.COMPRESSED;
-import static com.google.devtools.build.lib.vfs.FileSystemUtils.replaceExtension;
import static java.util.stream.Collectors.toCollection;
import com.google.common.collect.ImmutableList;
@@ -25,6 +24,7 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
+import com.google.devtools.build.lib.analysis.OutputGroupProvider;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
@@ -55,6 +55,7 @@
import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider;
import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
+import com.google.devtools.build.lib.rules.java.JavaToolchainProvider;
import com.google.devtools.build.lib.rules.java.OneVersionCheckActionBuilder;
import com.google.devtools.build.lib.rules.java.SingleJarActionBuilder;
import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider;
@@ -191,26 +192,21 @@
Artifact deployJar =
ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_DEPLOY_JAR);
+ Artifact oneVersionOutputArtifact = null;
OneVersionEnforcementLevel oneVersionEnforcementLevel =
ruleContext.getFragment(JavaConfiguration.class).oneVersionEnforcementLevel();
if (oneVersionEnforcementLevel != OneVersionEnforcementLevel.OFF) {
- Artifact oneVersionOutput =
- ruleContext
- .getAnalysisEnvironment()
- .getDerivedArtifact(
- replaceExtension(classJar.getRootRelativePath(), "-one-version.txt"),
- classJar.getRoot());
- filesToBuildBuilder.add(oneVersionOutput);
-
- NestedSet<Artifact> transitiveDependencies =
- NestedSetBuilder.fromNestedSet(helper.getAttributes().getRuntimeClassPath())
- .add(classJar)
- .build();
- OneVersionCheckActionBuilder.build(
- ruleContext,
- transitiveDependencies,
- oneVersionOutput,
- oneVersionEnforcementLevel);
+ oneVersionOutputArtifact =
+ OneVersionCheckActionBuilder.newBuilder()
+ .withEnforcementLevel(oneVersionEnforcementLevel)
+ .outputArtifact(
+ ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_ONE_VERSION_ARTIFACT))
+ .useToolchain(JavaToolchainProvider.fromRuleContext(ruleContext))
+ .checkJars(
+ NestedSetBuilder.fromNestedSet(helper.getAttributes().getRuntimeClassPath())
+ .add(classJar)
+ .build())
+ .build(ruleContext);
}
NestedSet<Artifact> filesToBuild = filesToBuildBuilder.build();
@@ -298,6 +294,10 @@
// TODO(mstaib): remove when static configurations are removed.
AndroidFeatureFlagSetProvider.getAndValidateFlagMapFromRuleContext(ruleContext);
+ if (oneVersionOutputArtifact != null) {
+ builder.addOutputGroup(OutputGroupProvider.HIDDEN_TOP_LEVEL, oneVersionOutputArtifact);
+ }
+
return builder
.setFilesToBuild(filesToBuild)
.addSkylarkTransitiveInfo(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
index 5306249..bafa5e7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
@@ -15,7 +15,6 @@
import static com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression.COMPRESSED;
import static com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression.UNCOMPRESSED;
-import static com.google.devtools.build.lib.vfs.FileSystemUtils.replaceExtension;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
@@ -25,6 +24,7 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FilesToRunProvider;
+import com.google.devtools.build.lib.analysis.OutputGroupProvider;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
@@ -285,21 +285,18 @@
ruleContext, deployJar, common.getBootClasspath(), mainClass, semantics, filesBuilder);
if (javaConfig.oneVersionEnforcementLevel() != OneVersionEnforcementLevel.OFF) {
- Artifact oneVersionOutput =
- ruleContext
- .getAnalysisEnvironment()
- .getDerivedArtifact(
- replaceExtension(classJar.getRootRelativePath(), "-one-version.txt"),
- classJar.getRoot());
- filesBuilder.add(oneVersionOutput);
-
- NestedSet<Artifact> transitiveDependencies =
- NestedSetBuilder.fromNestedSet(attributes.getRuntimeClassPath()).add(classJar).build();
- OneVersionCheckActionBuilder.build(
- ruleContext,
- transitiveDependencies,
- oneVersionOutput,
- javaConfig.oneVersionEnforcementLevel());
+ builder.addOutputGroup(
+ OutputGroupProvider.HIDDEN_TOP_LEVEL,
+ OneVersionCheckActionBuilder.newBuilder()
+ .withEnforcementLevel(javaConfig.oneVersionEnforcementLevel())
+ .outputArtifact(
+ ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_ONE_VERSION_ARTIFACT))
+ .useToolchain(JavaToolchainProvider.fromRuleContext(ruleContext))
+ .checkJars(
+ NestedSetBuilder.fromNestedSet(attributes.getRuntimeClassPath())
+ .add(classJar)
+ .build())
+ .build(ruleContext));
}
NestedSet<Artifact> filesToBuild = filesBuilder.build();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
index 571d517..b7b127d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
@@ -82,6 +82,8 @@
fromTemplates("%{name}_proguard.usage");
SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_CONFIG =
fromTemplates("%{name}_proguard.config");
+ SafeImplicitOutputsFunction JAVA_ONE_VERSION_ARTIFACT =
+ fromTemplates("%{name}-one-version.txt");
SafeImplicitOutputsFunction JAVA_BINARY_DEPLOY_SOURCE_JAR =
fromTemplates("%{name}_deploy-src.jar");
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/OneVersionCheckActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/OneVersionCheckActionBuilder.java
index aab1f12..8a57708 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/OneVersionCheckActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/OneVersionCheckActionBuilder.java
@@ -22,22 +22,58 @@
import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
-import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.Builder;
import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.CustomMultiArgv;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel;
+import com.google.devtools.build.lib.util.Preconditions;
/** Utility for generating a call to the one-version binary. */
-public class OneVersionCheckActionBuilder {
+public final class OneVersionCheckActionBuilder {
- public static void build(
- RuleContext ruleContext,
- NestedSet<Artifact> jarsToCheck,
- Artifact oneVersionOutput,
+ private OneVersionCheckActionBuilder() {}
+
+ private OneVersionEnforcementLevel enforcementLevel;
+ private Artifact outputArtifact;
+ private JavaToolchainProvider javaToolchain;
+ private NestedSet<Artifact> jarsToCheck;
+
+ public static OneVersionCheckActionBuilder newBuilder() {
+ return new OneVersionCheckActionBuilder();
+ }
+
+ public OneVersionCheckActionBuilder useToolchain(JavaToolchainProvider toolchain) {
+ javaToolchain = toolchain;
+ return this;
+ }
+
+ public OneVersionCheckActionBuilder checkJars(NestedSet<Artifact> jarsToCheck) {
+ this.jarsToCheck = jarsToCheck;
+ return this;
+ }
+
+ public OneVersionCheckActionBuilder outputArtifact(Artifact outputArtifact) {
+ this.outputArtifact = outputArtifact;
+ return this;
+ }
+
+ public OneVersionCheckActionBuilder withEnforcementLevel(
OneVersionEnforcementLevel enforcementLevel) {
- JavaToolchainProvider javaToolchain = JavaToolchainProvider.fromRuleContext(ruleContext);
+ Preconditions.checkArgument(
+ enforcementLevel != OneVersionEnforcementLevel.OFF,
+ "one version enforcement actions shouldn't be built if the enforcement "
+ + "level is set to off");
+ this.enforcementLevel = enforcementLevel;
+ return this;
+ }
+
+ public Artifact build(RuleContext ruleContext) {
+ Preconditions.checkNotNull(enforcementLevel);
+ Preconditions.checkNotNull(outputArtifact);
+ Preconditions.checkNotNull(javaToolchain);
+ Preconditions.checkNotNull(jarsToCheck);
+
Artifact oneVersionTool = javaToolchain.getOneVersionBinary();
Artifact oneVersionWhitelist = javaToolchain.getOneVersionWhitelist();
if (oneVersionTool == null || oneVersionWhitelist == null) {
@@ -45,14 +81,15 @@
String.format(
"one version enforcement was requested but it is not supported by the current "
+ "Java toolchain '%s'; see the "
- + "java_toolchain.oneversion and java_toolchain.oneversion_whitelist attributes",
+ + "java_toolchain.oneversion and java_toolchain.oneversion_whitelist "
+ + "attributes",
javaToolchain.getToolchainLabel()));
- return;
+ return outputArtifact;
}
- Builder oneVersionArgsBuilder =
+ CustomCommandLine.Builder oneVersionArgsBuilder =
CustomCommandLine.builder()
- .addExecPath("--output", oneVersionOutput)
+ .addExecPath("--output", outputArtifact)
.addExecPath("--whitelist", oneVersionWhitelist);
if (enforcementLevel == OneVersionEnforcementLevel.WARNING) {
oneVersionArgsBuilder.add("--succeed_on_found_violations");
@@ -61,7 +98,7 @@
CustomCommandLine oneVersionArgs = oneVersionArgsBuilder.build();
ruleContext.registerAction(
new SpawnAction.Builder()
- .addOutput(oneVersionOutput)
+ .addOutput(outputArtifact)
.addInput(oneVersionWhitelist)
.addTransitiveInputs(jarsToCheck)
.setExecutable(oneVersionTool)
@@ -70,6 +107,7 @@
.setMnemonic("JavaOneVersion")
.setProgressMessage("Checking for one-version violations in " + ruleContext.getLabel())
.build(ruleContext));
+ return outputArtifact;
}
private static class OneVersionJarMapArgv extends CustomMultiArgv {