aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar asteinb <asteinb@google.com>2018-05-10 11:19:51 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-05-10 11:21:47 -0700
commitb5cd7065aeb0370fb6c341bc2578315ca1c62297 (patch)
treeee969586e61f7f23cd7a836b65e185722b13efc3 /src
parentf9e7529908149e0511cc666c8fed879a50dbaea8 (diff)
Expose android_binary data processing methods to Skylark
Create an AndroidBinaryDataInfo to wrap binary-specific artifacts that shouldn't be exposed for libraries. This is currently only the final resource APK. Continue to extract attribute references from lower-level methods and bubble them up to the top level. RELNOTES: none PiperOrigin-RevId: 196143940
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java157
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryDataInfo.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java478
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java77
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactory.java47
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java5
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java44
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java14
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java6
12 files changed, 712 insertions, 127 deletions
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 835a2f61a7..0b7706918c 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
@@ -73,6 +73,7 @@ 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.rules.java.ProguardSpecProvider;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.ArrayList;
@@ -80,6 +81,7 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import javax.annotation.Nullable;
/** An implementation for the "android_binary" rule. */
@@ -210,7 +212,15 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
/* conditionalKeepRules = */ shouldShrinkResourceCycles(
ruleContext, shrinkResources),
applicationManifest.getManifestValues(),
- aaptVersion)
+ aaptVersion,
+ AndroidResources.from(ruleContext, "resource_files"),
+ AndroidAssets.from(ruleContext),
+ resourceDeps,
+ AssetDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
+ ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext),
+ ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"),
+ ruleContext.attributes().get("crunch_png", Type.BOOLEAN),
+ DataBinding.isEnabled(ruleContext))
.generateRClass(ruleContext, aaptVersion);
} else {
applicationManifest =
@@ -231,7 +241,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK),
resourceDeps,
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
- ResourceFilterFactory.fromRuleContext(ruleContext),
+ ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext),
ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"),
ruleContext.attributes().get("crunch_png", Type.BOOLEAN),
ProguardHelper.getProguardConfigArtifact(ruleContext, ""),
@@ -361,22 +371,18 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
throws InterruptedException, RuleErrorException {
ImmutableList<Artifact> proguardSpecs =
- ProguardHelper.collectTransitiveProguardSpecs(
- ruleContext, ImmutableList.of(resourceApk.getResourceProguardConfig()));
-
- boolean assumeMinSdkVersion =
- ruleContext.getFragment(AndroidConfiguration.class).assumeMinSdkVersion();
- if (!proguardSpecs.isEmpty() && assumeMinSdkVersion) {
- // NB: Order here is important. We're including generated Proguard specs before the user's
- // specs so that they can override values.
- proguardSpecs =
- ImmutableList.<Artifact>builder()
- .addAll(
- androidSemantics.getProguardSpecsForManifest(
- ruleContext, applicationManifest.getManifest()))
- .addAll(proguardSpecs)
- .build();
- }
+ getProguardSpecs(
+ ruleContext,
+ androidSemantics,
+ resourceApk.getResourceProguardConfig(),
+ applicationManifest.getManifest(),
+ ruleContext.attributes().has(ProguardHelper.PROGUARD_SPECS, BuildType.LABEL_LIST)
+ ? ruleContext
+ .getPrerequisiteArtifacts(ProguardHelper.PROGUARD_SPECS, Mode.TARGET)
+ .list()
+ : ImmutableList.<Artifact>of(),
+ ruleContext.getPrerequisiteArtifacts(":extra_proguard_specs", Mode.TARGET).list(),
+ ruleContext.getPrerequisites("deps", Mode.TARGET, ProguardSpecProvider.class));
// TODO(bazel-team): Verify that proguard spec files don't contain -printmapping directions
// which this -printmapping command line flag will override.
@@ -763,6 +769,38 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
return new ProguardOutput(deployJarArtifact, null, null, null, null, null, null);
}
+ static ImmutableList<Artifact> getProguardSpecs(
+ RuleContext ruleContext,
+ AndroidSemantics androidSemantics,
+ Artifact resourceProguardConfig,
+ Artifact mergedManifest,
+ ImmutableList<Artifact> localProguardSpecs,
+ ImmutableList<Artifact> extraProguardSpecs,
+ Iterable<ProguardSpecProvider> proguardDeps) {
+
+ ImmutableList<Artifact> proguardSpecs =
+ ProguardHelper.collectTransitiveProguardSpecs(
+ ruleContext,
+ Iterables.concat(
+ ImmutableList.of(resourceProguardConfig), extraProguardSpecs),
+ localProguardSpecs,
+ proguardDeps);
+
+ boolean assumeMinSdkVersion =
+ ruleContext.getFragment(AndroidConfiguration.class).assumeMinSdkVersion();
+ if (!proguardSpecs.isEmpty() && assumeMinSdkVersion) {
+ // NB: Order here is important. We're including generated Proguard specs before the user's
+ // specs so that they can override values.
+ proguardSpecs =
+ ImmutableList.<Artifact>builder()
+ .addAll(androidSemantics.getProguardSpecsForManifest(ruleContext, mergedManifest))
+ .addAll(proguardSpecs)
+ .build();
+ }
+
+ return proguardSpecs;
+ }
+
/** Returns {@code true} if resource shrinking should be performed. */
private static boolean shouldShrinkResources(RuleContext ruleContext) {
TriState state = ruleContext.attributes().get("shrink_resources", BuildType.TRISTATE);
@@ -776,8 +814,8 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
}
/** Returns {@code true} if resource shrinking should be performed. */
- private static boolean shouldShrinkResourceCycles(
- RuleContext ruleContext, boolean shrinkResources) throws RuleErrorException {
+ static boolean shouldShrinkResourceCycles(RuleContext ruleContext, boolean shrinkResources)
+ throws RuleErrorException {
boolean global =
ruleContext.getFragment(AndroidConfiguration.class).useAndroidResourceCycleShrinking();
if (global && !shrinkResources) {
@@ -793,39 +831,68 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
ImmutableList<Artifact> proguardSpecs,
ProguardOutput proguardOutput,
NestedSetBuilder<Artifact> filesBuilder)
- throws InterruptedException, RuleErrorException {
+ throws RuleErrorException, InterruptedException {
- if (!proguardSpecs.isEmpty()) {
+ Optional<Artifact> maybeShrunkApk =
+ maybeShrinkResources(
+ ruleContext,
+ resourceApk.getValidatedResources(),
+ resourceApk.getResourceDependencies(),
+ proguardSpecs,
+ proguardOutput.getOutputJar(),
+ proguardOutput.getMapping(),
+ AndroidAaptVersion.chooseTargetAaptVersion(ruleContext),
+ ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext),
+ ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"));
- Artifact apk =
- new ResourceShrinkerActionBuilder(ruleContext)
- .setResourceApkOut(
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_APK))
- .setShrunkResourcesOut(
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_ZIP))
- .setLogOut(
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.ANDROID_RESOURCE_SHRINKER_LOG))
- .withResourceFiles(
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP))
- .withShrunkJar(proguardOutput.getOutputJar())
- .withProguardMapping(proguardOutput.getMapping())
- .withPrimary(resourceApk.getValidatedResources())
- .withDependencies(resourceApk.getResourceDependencies())
- .setTargetAaptVersion(AndroidAaptVersion.chooseTargetAaptVersion(ruleContext))
- .setResourceFilterFactory(ResourceFilterFactory.fromRuleContext(ruleContext))
- .setUncompressedExtensions(
- ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"))
- .build();
+ if (maybeShrunkApk.isPresent()) {
filesBuilder.add(
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCE_SHRINKER_LOG));
- return resourceApk.withApk(apk);
+ return resourceApk.withApk(maybeShrunkApk.get());
}
+
return resourceApk;
}
+ static Optional<Artifact> maybeShrinkResources(
+ RuleContext ruleContext,
+ ValidatedAndroidData validatedResources,
+ ResourceDependencies resourceDeps,
+ ImmutableList<Artifact> proguardSpecs,
+ Artifact proguardOutputJar,
+ Artifact proguardMapping,
+ AndroidAaptVersion aaptVersion,
+ ResourceFilterFactory resourceFilterFactory,
+ List<String> noCompressExtensions)
+ throws InterruptedException {
+
+ if (proguardSpecs.isEmpty()) {
+ return Optional.empty();
+ }
+
+ return Optional.of(
+ new ResourceShrinkerActionBuilder(ruleContext)
+ .setResourceApkOut(
+ ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_APK))
+ .setShrunkResourcesOut(
+ ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_RESOURCES_SHRUNK_ZIP))
+ .setLogOut(
+ ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.ANDROID_RESOURCE_SHRINKER_LOG))
+ .withResourceFiles(
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP))
+ .withShrunkJar(proguardOutputJar)
+ .withProguardMapping(proguardMapping)
+ .withPrimary(validatedResources)
+ .withDependencies(resourceDeps)
+ .setTargetAaptVersion(aaptVersion)
+ .setResourceFilterFactory(resourceFilterFactory)
+ .setUncompressedExtensions(noCompressExtensions)
+ .build());
+ }
+
@Immutable
static final class DexingOutput {
private final Artifact classesDexZip;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryDataInfo.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryDataInfo.java
index e17ddefbc9..d3de6d02ba 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryDataInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryDataInfo.java
@@ -79,4 +79,9 @@ public class AndroidBinaryDataInfo extends NativeInfo {
public AndroidManifestInfo getManifestInfo() {
return manifestInfo;
}
+
+ public AndroidBinaryDataInfo withShrunkApk(Artifact shrunkApk) {
+ return new AndroidBinaryDataInfo(
+ shrunkApk, resourceProguardConfig, resourcesInfo, assetsInfo, manifestInfo);
+ }
}
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 7fc06665c0..93cf70a9b9 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
@@ -117,7 +117,7 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK),
resourceDependencies,
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
- ResourceFilterFactory.fromRuleContext(ruleContext),
+ ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext),
ImmutableList.of(), /* list of uncompressed extensions */
false, /* crunch png */
ProguardHelper.getProguardConfigArtifact(ruleContext, ""),
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java
index 44891cd415..fc5cd5ebfb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java
@@ -104,7 +104,7 @@ public class AndroidManifest {
*
* <p>AndroidSemantics-specific processing will be used if a non-null AndroidSemantics is passed.
*/
- private static AndroidManifest from(
+ static AndroidManifest from(
RuleContext ruleContext,
@Nullable Artifact rawManifest,
@Nullable AndroidSemantics androidSemantics,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
index ab8fdb9022..827daaa3c0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java
@@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableMap;
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.TransitiveInfoProvider;
import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
@@ -30,6 +31,7 @@ import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidA
import com.google.devtools.build.lib.rules.android.AndroidLibraryAarInfo.Aar;
import com.google.devtools.build.lib.rules.java.JavaCompilationInfoProvider;
import com.google.devtools.build.lib.rules.java.JavaInfo;
+import com.google.devtools.build.lib.rules.java.ProguardSpecProvider;
import com.google.devtools.build.lib.skylarkinterface.Param;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
@@ -40,6 +42,7 @@ import com.google.devtools.build.lib.syntax.SkylarkList;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import javax.annotation.Nullable;
/** Skylark-visible methods for working with Android data (manifests, resources, and assets). */
@@ -502,11 +505,6 @@ public abstract class AndroidSkylarkData {
+ " resources_from_deps to inherit without defining them.");
}
- ImmutableList.Builder<Artifact> proguardSpecBuilder = ImmutableList.builder();
- for (FileProvider provider : getFileProviders(proguardSpecs)) {
- proguardSpecBuilder.addAll(provider.getFilesToBuild());
- }
-
return Aar.makeAar(
ctx.getRuleContext(),
resources,
@@ -514,7 +512,7 @@ public abstract class AndroidSkylarkData {
resourcesInfo.getManifest(),
resourcesInfo.getRTxt(),
libraryClassJar,
- proguardSpecBuilder.build())
+ filesFromConfiguredTargets(proguardSpecs))
.toProvider(deps, definesLocalResources);
}
@@ -865,6 +863,437 @@ public abstract class AndroidSkylarkData {
}
}
+ /**
+ * Skylark API for bundling common setting for working with resources in android_binary
+ *
+ * <p>TODO(b/79159379): Stop passing SkylarkRuleContext here
+ *
+ * @param ctx the SkylarkRuleContext. We will soon change to using an ActionConstructionContext
+ * instead. See b/79159379
+ */
+ @SkylarkCallable(
+ name = "make_binary_settings",
+ mandatoryPositionals = 1, // SkylarkRuleContext is mandatory
+ parameters = {
+ @Param(
+ name = "shrink_resources",
+ positional = false,
+ noneable = true,
+ defaultValue = "None",
+ type = Boolean.class,
+ named = true,
+ doc =
+ "Whether to shrink resources. Defaults to the value used in Android"
+ + " configuration."),
+ @Param(
+ name = "resource_configuration_filters",
+ positional = false,
+ defaultValue = "[]",
+ type = SkylarkList.class,
+ generic1 = String.class,
+ named = true,
+ doc =
+ "A list of resource configuration filters, such 'en' that will limit the resources"
+ + " in the apk to only the ones in the 'en' configuration."),
+ @Param(
+ name = "densities",
+ positional = false,
+ defaultValue = "[]",
+ type = SkylarkList.class,
+ generic1 = String.class,
+ named = true,
+ doc =
+ "Densities to filter for when building the apk. A corresponding compatible-screens"
+ + " section will also be added to the manifest if it does not already contain a"
+ + " superset listing."),
+ @Param(
+ name = "nocompress_extensions",
+ positional = false,
+ defaultValue = "[]",
+ type = SkylarkList.class,
+ generic1 = String.class,
+ named = true,
+ doc = "A list of file extension to leave uncompressed in apk."),
+ @Param(
+ name = "aapt_version",
+ positional = false,
+ defaultValue = "'auto'",
+ type = String.class,
+ named = true,
+ doc =
+ "The version of aapt to use. Defaults to 'auto'. 'aapt' and 'aapt2' are also"
+ + " supported."),
+ },
+ doc =
+ "Returns a wrapper object containing various settings shared across multiple methods for"
+ + " processing binary data.")
+ public BinaryDataSettings makeBinarySettings(
+ SkylarkRuleContext ctx,
+ Object shrinkResources,
+ SkylarkList<String> resourceConfigurationFilters,
+ SkylarkList<String> densities,
+ SkylarkList<String> rawNoCompressExtensions,
+ String aaptVersionString)
+ throws EvalException {
+ AndroidConfiguration androidConfig = AndroidCommon.getAndroidConfig(ctx.getRuleContext());
+
+ AndroidAaptVersion aaptVersion;
+ try {
+ aaptVersion =
+ AndroidAaptVersion.chooseTargetAaptVersion(
+ ctx.getRuleContext(), androidConfig, aaptVersionString);
+ } catch (RuleErrorException e) {
+ throw new EvalException(Location.BUILTIN, e);
+ }
+
+ return new BinaryDataSettings(
+ aaptVersion,
+ fromNoneableOrDefault(
+ shrinkResources, Boolean.class, androidConfig.useAndroidResourceShrinking()),
+ ResourceFilterFactory.from(aaptVersion, resourceConfigurationFilters, densities),
+ ctx.getRuleContext()
+ .getExpander()
+ .withDataLocations()
+ .tokenized("nocompress_extensions", rawNoCompressExtensions));
+ }
+
+ /**
+ * Helper method to get default {@link
+ * com.google.devtools.build.lib.rules.android.AndroidSkylarkData.BinaryDataSettings}.
+ */
+ private BinaryDataSettings defaultBinaryDataSettings(SkylarkRuleContext ctx)
+ throws EvalException {
+ return makeBinarySettings(
+ ctx,
+ Runtime.NONE,
+ SkylarkList.createImmutable(ImmutableList.of()),
+ SkylarkList.createImmutable(ImmutableList.of()),
+ SkylarkList.createImmutable(ImmutableList.of()),
+ "auto");
+ }
+
+ @SkylarkModule(
+ name = "AndroidBinaryDataSettings",
+ doc = "Wraps common settings for working with android_binary assets, resources, and manifest")
+ private static class BinaryDataSettings {
+ private final AndroidAaptVersion aaptVersion;
+ private final boolean shrinkResources;
+ private final ResourceFilterFactory resourceFilterFactory;
+ private final ImmutableList<String> noCompressExtensions;
+
+ private BinaryDataSettings(
+ AndroidAaptVersion aaptVersion,
+ boolean shrinkResources,
+ ResourceFilterFactory resourceFilterFactory,
+ ImmutableList<String> noCompressExtensions) {
+ this.aaptVersion = aaptVersion;
+ this.shrinkResources = shrinkResources;
+ this.resourceFilterFactory = resourceFilterFactory;
+ this.noCompressExtensions = noCompressExtensions;
+ }
+ }
+
+ /**
+ * Skylark API for processing assets, resources, and manifest for android_binary
+ *
+ * <p>TODO(b/79159379): Stop passing SkylarkRuleContext here
+ *
+ * @param ctx the SkylarkRuleContext. We will soon change to using an ActionConstructionContext
+ * instead. See b/79159379
+ */
+ @SkylarkCallable(
+ name = "process_binary_data",
+ mandatoryPositionals = 1, // SkylarkRuleContext is mandatory
+ parameters = {
+ @Param(
+ name = "resources",
+ positional = false,
+ defaultValue = "[]",
+ type = SkylarkList.class,
+ generic1 = FileProvider.class,
+ named = true,
+ doc = "Providers of this target's resources"),
+ @Param(
+ name = "assets",
+ positional = false,
+ defaultValue = "None",
+ type = SkylarkList.class,
+ generic1 = ConfiguredTarget.class,
+ noneable = true,
+ named = true,
+ doc =
+ "Targets containing raw assets for this target. If passed, 'assets_dir' must also"
+ + " be passed."),
+ @Param(
+ name = "assets_dir",
+ positional = false,
+ defaultValue = "None",
+ type = String.class,
+ noneable = true,
+ named = true,
+ doc =
+ "Directory the assets are contained in. Must be passed if and only if 'assets' is"
+ + " passed. This path will be split off of the asset paths on the device."),
+ @Param(
+ name = "manifest",
+ positional = false,
+ type = Artifact.class,
+ defaultValue = "None",
+ named = true,
+ noneable = true,
+ doc =
+ "If passed, the manifest to use for this target. Otherwise, a dummy manifest will"
+ + " be generated."),
+ @Param(
+ name = "custom_package",
+ positional = false,
+ defaultValue = "None",
+ type = String.class,
+ noneable = true,
+ named = true,
+ doc =
+ "The Android application package to stamp the manifest with. If not provided, the"
+ + " current Java package, derived from the location of this target's BUILD"
+ + " file, will be used. For example, given a BUILD file in"
+ + " 'java/com/foo/bar/BUILD', the package would be 'com.foo.bar'."),
+ @Param(
+ name = "manifest_values",
+ positional = false,
+ defaultValue = "{}",
+ type = SkylarkDict.class,
+ generic1 = String.class,
+ named = true,
+ doc = "A dictionary of values to be overridden in the manifest."),
+ @Param(
+ name = "deps",
+ positional = false,
+ defaultValue = "[]",
+ type = SkylarkList.class,
+ generic1 = ConfiguredTarget.class,
+ named = true,
+ doc =
+ "Dependency targets. Providers will be extracted from these dependencies for each"
+ + " type of data."),
+ @Param(
+ name = "manifest_merger",
+ type = String.class,
+ defaultValue = "'auto'",
+ positional = false,
+ named = true,
+ doc =
+ "The manifest merger to use. Defaults to 'auto', but 'android' and 'legacy' are"
+ + " also supported."),
+ @Param(
+ name = "binary_settings",
+ type = BinaryDataSettings.class,
+ noneable = true,
+ defaultValue = "None",
+ positional = false,
+ named = true,
+ doc =
+ "Settings common to various binary processing methods, created with"
+ + " make_binary_data_settings"),
+ @Param(
+ name = "crunch_png",
+ positional = false,
+ defaultValue = "True",
+ type = Boolean.class,
+ named = true,
+ doc = "Whether PNG crunching should be done. Defaults to True."),
+ @Param(
+ name = "enable_data_binding",
+ positional = false,
+ defaultValue = "False",
+ type = Boolean.class,
+ named = true,
+ doc =
+ "Defaults to False. If True, processes data binding expressions in layout"
+ + " resources."),
+ },
+ doc =
+ "Processes resources, assets, and manifests for android_binary and returns the"
+ + " appropriate providers.")
+ public AndroidBinaryDataInfo processBinaryData(
+ SkylarkRuleContext ctx,
+ SkylarkList<ConfiguredTarget> resources,
+ Object assets,
+ Object assetsDir,
+ Object manifest,
+ Object customPackage,
+ SkylarkDict<String, String> rawManifestValues,
+ SkylarkList<ConfiguredTarget> deps,
+ String manifestMerger,
+ Object maybeSettings,
+ boolean crunchPng,
+ boolean dataBindingEnabled)
+ throws InterruptedException, RuleErrorException, EvalException {
+
+ BinaryDataSettings settings =
+ fromNoneableOrDefault(
+ maybeSettings, BinaryDataSettings.class, defaultBinaryDataSettings(ctx));
+
+ AndroidManifest rawManifest =
+ AndroidManifest.from(
+ ctx.getRuleContext(),
+ fromNoneable(manifest, Artifact.class),
+ getAndroidSemantics(),
+ fromNoneable(customPackage, String.class),
+ /* exportsManifest = */ false);
+
+ ResourceDependencies resourceDeps =
+ ResourceDependencies.fromProviders(
+ getProviders(deps, AndroidResourcesInfo.PROVIDER), /* neverlink = */ false);
+
+ ImmutableMap<String, String> manifestValues =
+ ApplicationManifest.getManifestValues(ctx.getRuleContext(), rawManifestValues);
+
+ StampedAndroidManifest stampedManifest =
+ rawManifest.mergeWithDeps(
+ ctx.getRuleContext(),
+ resourceDeps,
+ manifestValues,
+ ApplicationManifest.useLegacyMerging(ctx.getRuleContext(), manifestMerger));
+
+ ResourceApk resourceApk =
+ ProcessedAndroidData.processBinaryDataFrom(
+ ctx.getRuleContext(),
+ stampedManifest,
+ AndroidBinary.shouldShrinkResourceCycles(
+ ctx.getRuleContext(), settings.shrinkResources),
+ manifestValues,
+ settings.aaptVersion,
+ AndroidResources.from(
+ ctx.getRuleContext(), getFileProviders(resources), "resource_files"),
+ AndroidAssets.from(
+ ctx.getRuleContext(),
+ listFromNoneable(assets, ConfiguredTarget.class),
+ isNone(assetsDir)
+ ? null
+ : PathFragment.create(fromNoneable(assetsDir, String.class))),
+ resourceDeps,
+ AssetDependencies.fromProviders(
+ getProviders(deps, AndroidAssetsInfo.PROVIDER), /* neverlink = */ false),
+ settings.resourceFilterFactory,
+ settings.noCompressExtensions,
+ crunchPng,
+ dataBindingEnabled)
+ .generateRClass(ctx.getRuleContext(), settings.aaptVersion);
+
+ return AndroidBinaryDataInfo.of(
+ resourceApk.getArtifact(),
+ resourceApk.getResourceProguardConfig(),
+ resourceApk.toResourceInfo(ctx.getLabel()),
+ resourceApk.toAssetsInfo(ctx.getLabel()).get(),
+ resourceApk.toManifestInfo().get());
+ }
+
+ /**
+ * Skylark API for shrinking a resource APK
+ *
+ * <p>TODO(b/79159379): Stop passing SkylarkRuleContext here
+ *
+ * @param ctx the SkylarkRuleContext. We will soon change to using an ActionConstructionContext
+ * instead. See b/79159379
+ */
+ @SkylarkCallable(
+ name = "shrink_data_apk",
+ // Required: SkylarkRuleContext, AndroidBinaryDataInfo to shrink, and two proguard outputs
+ mandatoryPositionals = 4,
+ parameters = {
+ @Param(
+ name = "binary_settings",
+ type = BinaryDataSettings.class,
+ noneable = true,
+ defaultValue = "None",
+ positional = false,
+ named = true,
+ doc =
+ "Settings common to various binary processing methods, created with"
+ + " make_binary_data_settings"),
+ @Param(
+ name = "deps",
+ positional = false,
+ defaultValue = "[]",
+ type = SkylarkList.class,
+ generic1 = ConfiguredTarget.class,
+ named = true,
+ doc =
+ "Dependency targets. Providers will be extracted from these dependencies for each"
+ + " type of data."),
+ @Param(
+ name = "proguard_specs",
+ type = SkylarkList.class,
+ generic1 = ConfiguredTarget.class,
+ defaultValue = "[]",
+ positional = false,
+ named = true,
+ doc =
+ "Files to be used as Proguard specification for this target, which will be"
+ + " inherited in the top-level target"),
+ @Param(
+ name = "extra_proguard_specs,",
+ type = SkylarkList.class,
+ generic1 = ConfiguredTarget.class,
+ defaultValue = "[]",
+ positional = false,
+ named = true,
+ doc =
+ "Additional proguard specs that should be added for top-level targets. This value"
+ + " is controlled by Java configuration."),
+ },
+ doc =
+ "Possibly shrinks the data APK by removing resources that were marked as unused during"
+ + " proguarding.")
+ public AndroidBinaryDataInfo shrinkDataApk(
+ SkylarkRuleContext ctx,
+ AndroidBinaryDataInfo binaryDataInfo,
+ Artifact proguardOutputJar,
+ Artifact proguardMapping,
+ Object maybeSettings,
+ SkylarkList<ConfiguredTarget> deps,
+ SkylarkList<ConfiguredTarget> localProguardSpecs,
+ SkylarkList<ConfiguredTarget> extraProguardSpecs)
+ throws EvalException, InterruptedException {
+ BinaryDataSettings settings =
+ fromNoneableOrDefault(
+ maybeSettings, BinaryDataSettings.class, defaultBinaryDataSettings(ctx));
+
+ if (!settings.shrinkResources) {
+ return binaryDataInfo;
+ }
+
+ ImmutableList<Artifact> proguardSpecs =
+ AndroidBinary.getProguardSpecs(
+ ctx.getRuleContext(),
+ getAndroidSemantics(),
+ binaryDataInfo.getResourceProguardConfig(),
+ binaryDataInfo.getManifestInfo().getManifest(),
+ filesFromConfiguredTargets(localProguardSpecs),
+ filesFromConfiguredTargets(extraProguardSpecs),
+ getProviders(deps, ProguardSpecProvider.class));
+
+ // TODO(asteinb): There should never be more than one direct resource exposed in the provider.
+ // Can we adjust its structure to take this into account?
+ if (!binaryDataInfo.getResourcesInfo().getDirectAndroidResources().isSingleton()) {
+ throw new EvalException(Location.BUILTIN, "TODO");
+ }
+
+ Optional<Artifact> maybeShrunkApk =
+ AndroidBinary.maybeShrinkResources(
+ ctx.getRuleContext(),
+ binaryDataInfo.getResourcesInfo().getDirectAndroidResources().toList().get(0),
+ ResourceDependencies.fromProviders(
+ getProviders(deps, AndroidResourcesInfo.PROVIDER), /* neverlink = */ false),
+ proguardSpecs,
+ proguardOutputJar,
+ proguardMapping,
+ settings.aaptVersion,
+ settings.resourceFilterFactory,
+ settings.noCompressExtensions);
+
+ return maybeShrunkApk.map(binaryDataInfo::withShrunkApk).orElse(binaryDataInfo);
+ }
+
public static SkylarkDict<NativeProvider<?>, NativeInfo> getNativeInfosFrom(
ResourceApk resourceApk, Label label) {
ImmutableMap.Builder<NativeProvider<?>, NativeInfo> builder = ImmutableMap.builder();
@@ -943,25 +1372,30 @@ public abstract class AndroidSkylarkData {
return SkylarkList.castList(asList, clazz, null);
}
+ private static ImmutableList<Artifact> filesFromConfiguredTargets(
+ SkylarkList<ConfiguredTarget> targets) {
+ ImmutableList.Builder<Artifact> builder = ImmutableList.builder();
+ for (FileProvider provider : getFileProviders(targets)) {
+ builder.addAll(provider.getFilesToBuild());
+ }
+
+ return builder.build();
+ }
+
private static ImmutableList<FileProvider> getFileProviders(
SkylarkList<ConfiguredTarget> targets) {
+ return getProviders(targets, FileProvider.class);
+ }
+
+ private static <T extends TransitiveInfoProvider> ImmutableList<T> getProviders(
+ SkylarkList<ConfiguredTarget> targets, Class<T> clazz) {
return targets
.stream()
- .map(target -> target.getProvider(FileProvider.class))
+ .map(target -> target.getProvider(clazz))
.filter(Objects::nonNull)
.collect(ImmutableList.toImmutableList());
}
- private static <T> SkylarkList<T> listFromNoneableOrEmpty(Object object, Class<T> clazz)
- throws EvalException {
- List<T> value = listFromNoneable(object, clazz);
- if (value == null) {
- return SkylarkList.createImmutable(ImmutableList.of());
- }
-
- return SkylarkList.createImmutable(value);
- }
-
public static <T extends NativeInfo> SkylarkList<T> getProviders(
SkylarkList<ConfiguredTarget> targets, NativeProvider<T> provider) {
return SkylarkList.createImmutable(
@@ -971,4 +1405,14 @@ public abstract class AndroidSkylarkData {
.filter(Objects::nonNull)
.collect(ImmutableList.toImmutableList()));
}
+
+ private static <T> SkylarkList<T> listFromNoneableOrEmpty(Object object, Class<T> clazz)
+ throws EvalException {
+ List<T> value = listFromNoneable(object, clazz);
+ if (value == null) {
+ return SkylarkList.createImmutable(ImmutableList.of());
+ }
+
+ return SkylarkList.createImmutable(value);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
index deb2cb530e..a5d3be231f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
@@ -528,7 +528,7 @@ public final class ApplicationManifest {
// Filter the resources during analysis to prevent processing of dependencies on unwanted
// resources during execution.
ResourceFilterFactory resourceFilterFactory =
- ResourceFilterFactory.fromRuleContext(ruleContext);
+ ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext);
ResourceFilter resourceFilter =
resourceFilterFactory.getResourceFilter(ruleContext, resourceDeps, resources);
resources = resources.filterLocalResources(ruleContext, resourceFilter);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
index 6cbaa5ee23..3cffbf4dd3 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ProcessedAndroidData.java
@@ -19,9 +19,11 @@ import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.config.CompilationMode;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+import com.google.devtools.build.lib.packages.RuleErrorConsumer;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
import com.google.devtools.build.lib.rules.java.ProguardHelper;
import com.google.devtools.build.lib.syntax.Type;
+import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
@@ -57,10 +59,17 @@ public class ProcessedAndroidData {
StampedAndroidManifest manifest,
boolean conditionalKeepRules,
Map<String, String> manifestValues,
- AndroidAaptVersion aaptVersion)
+ AndroidAaptVersion aaptVersion,
+ AndroidResources resources,
+ AndroidAssets assets,
+ ResourceDependencies resourceDeps,
+ AssetDependencies assetDeps,
+ ResourceFilterFactory resourceFilterFactory,
+ List<String> noCompressExtensions,
+ boolean crunchPng,
+ boolean dataBindingEnabled)
throws RuleErrorException, InterruptedException {
- if (conditionalKeepRules
- && AndroidAaptVersion.chooseTargetAaptVersion(ruleContext) != AndroidAaptVersion.AAPT2) {
+ if (conditionalKeepRules && aaptVersion != AndroidAaptVersion.AAPT2) {
throw ruleContext.throwWithRuleError(
"resource cycle shrinking can only be enabled for builds with aapt2");
}
@@ -68,7 +77,7 @@ public class ProcessedAndroidData {
AndroidResourcesProcessorBuilder builder =
builderForNonIncrementalTopLevelTarget(ruleContext, manifest, manifestValues, aaptVersion)
.setUseCompiledResourcesForMerge(
- AndroidAaptVersion.chooseTargetAaptVersion(ruleContext) == AndroidAaptVersion.AAPT2
+ aaptVersion == AndroidAaptVersion.AAPT2
&& AndroidCommon.getAndroidConfig(ruleContext).skipParsingAction())
.setManifestOut(
ruleContext.getImplicitOutputArtifact(
@@ -78,9 +87,7 @@ public class ProcessedAndroidData {
.setMainDexProguardOut(AndroidBinary.createMainDexProguardSpec(ruleContext))
.conditionalKeepRules(conditionalKeepRules)
.setDataBindingInfoZip(
- DataBinding.isEnabled(ruleContext)
- ? DataBinding.getLayoutInfoFile(ruleContext)
- : null)
+ dataBindingEnabled ? DataBinding.getLayoutInfoFile(ruleContext) : null)
.setFeatureOf(
ruleContext.attributes().isAttributeValueExplicitlySpecified("feature_of")
? ruleContext
@@ -93,7 +100,17 @@ public class ProcessedAndroidData {
.getPrerequisite("feature_after", Mode.TARGET, ApkInfo.PROVIDER)
.getApk()
: null);
- return buildActionForBinary(ruleContext, builder, manifest);
+ return buildActionForBinary(
+ ruleContext,
+ builder,
+ manifest,
+ resources,
+ assets,
+ resourceDeps,
+ assetDeps,
+ resourceFilterFactory,
+ noCompressExtensions,
+ crunchPng);
}
public static ProcessedAndroidData processIncrementalBinaryDataFrom(
@@ -108,36 +125,46 @@ public class ProcessedAndroidData {
builderForTopLevelTarget(ruleContext, manifest, proguardPrefix, manifestValues)
.setApkOut(apkOut);
- return buildActionForBinary(ruleContext, builder, manifest);
+ return buildActionForBinary(
+ ruleContext,
+ builder,
+ manifest,
+ AndroidResources.from(ruleContext, "resource_files"),
+ AndroidAssets.from(ruleContext),
+ ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
+ AssetDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
+ ResourceFilterFactory.fromRuleContextAndAttrs(ruleContext),
+ ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"),
+ ruleContext.attributes().get("crunch_png", Type.BOOLEAN));
}
private static ProcessedAndroidData buildActionForBinary(
- RuleContext ruleContext,
+ RuleErrorConsumer errorConsumer,
AndroidResourcesProcessorBuilder builder,
- StampedAndroidManifest manifest)
+ StampedAndroidManifest manifest,
+ AndroidResources resources,
+ AndroidAssets assets,
+ ResourceDependencies resourceDeps,
+ AssetDependencies assetDeps,
+ ResourceFilterFactory resourceFilterFactory,
+ List<String> noCompressExtensions,
+ boolean crunchPng)
throws RuleErrorException {
- AndroidResources resources = AndroidResources.from(ruleContext, "resource_files");
- ResourceDependencies resourceDeps =
- ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false);
- ResourceFilterFactory resourceFilterFactory =
- ResourceFilterFactory.fromRuleContext(ruleContext);
-
ResourceFilter resourceFilter =
- resourceFilterFactory.getResourceFilter(ruleContext, resourceDeps, resources);
+ resourceFilterFactory.getResourceFilter(errorConsumer, resourceDeps, resources);
// Filter unwanted resources out
- resources = resources.filterLocalResources(ruleContext, resourceFilter);
- resourceDeps = resourceDeps.filter(ruleContext, resourceFilter);
+ resources = resources.filterLocalResources(errorConsumer, resourceFilter);
+ resourceDeps = resourceDeps.filter(errorConsumer, resourceFilter);
return builder
.setResourceFilterFactory(resourceFilterFactory)
- .setUncompressedExtensions(
- ruleContext.getExpander().withDataLocations().tokenized("nocompress_extensions"))
- .setCrunchPng(ruleContext.attributes().get("crunch_png", Type.BOOLEAN))
+ .setUncompressedExtensions(noCompressExtensions)
+ .setCrunchPng(crunchPng)
.withResourceDependencies(resourceDeps)
- .withAssetDependencies(AssetDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false))
- .build(resources, AndroidAssets.from(ruleContext), manifest);
+ .withAssetDependencies(assetDeps)
+ .build(resources, assets, manifest);
}
/** Processes Android data (assets, resources, and manifest) for android_local_test targets. */
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactory.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactory.java
index 14e20362ff..848125a81f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactory.java
@@ -84,13 +84,14 @@ public class ResourceFilterFactory {
this.filterInAnalysis = filterInAnalysis;
}
- private static boolean hasAttr(AttributeMap attrs, String attrName) {
- if (!attrs.isAttributeValueExplicitlySpecified(attrName)) {
- return false;
+ private static List<String> rawFiltersFromAttrs(AttributeMap attrs, String attrName) {
+ if (attrs.isAttributeValueExplicitlySpecified(attrName)) {
+ List<String> rawValue = attrs.get(attrName, Type.STRING_LIST);
+ if (rawValue != null) {
+ return rawValue;
+ }
}
-
- List<String> values = attrs.get(attrName, Type.STRING_LIST);
- return values != null && !values.isEmpty();
+ return ImmutableList.of();
}
/**
@@ -102,8 +103,8 @@ public class ResourceFilterFactory {
*
* @return the values of this attribute contained in the {@link AttributeMap}, as a list.
*/
- private static ImmutableList<String> extractFilters(AttributeMap attrs, String attrName) {
- if (!hasAttr(attrs, attrName)) {
+ private static ImmutableList<String> extractFilters(List<String> rawValues) {
+ if (rawValues.isEmpty()) {
return ImmutableList.of();
}
@@ -117,7 +118,6 @@ public class ResourceFilterFactory {
* empty filter values result in all resources matching the empty filter, meaning that filtering
* does nothing (even if non-empty filters were also provided).
*/
- List<String> rawValues = attrs.get(attrName, Type.STRING_LIST);
// Use an ImmutableSet to remove duplicate values
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
@@ -139,30 +139,37 @@ public class ResourceFilterFactory {
return ImmutableList.sortedCopyOf(builder.build());
}
- static ResourceFilterFactory fromRuleContext(RuleContext ruleContext) throws RuleErrorException {
+ static ResourceFilterFactory fromRuleContextAndAttrs(RuleContext ruleContext)
+ throws RuleErrorException {
Preconditions.checkNotNull(ruleContext);
if (!ruleContext.isLegalFragment(AndroidConfiguration.class)) {
return empty();
}
- // aapt2 must have access to all of the resources in execution, so don't filter in analysis.
- boolean filterInAnalysis =
- AndroidAaptVersion.chooseTargetAaptVersion(ruleContext) != AndroidAaptVersion.AAPT2;
-
- return from(filterInAnalysis, ruleContext.attributes());
+ return fromAttrs(
+ AndroidAaptVersion.chooseTargetAaptVersion(ruleContext), ruleContext.attributes());
}
@VisibleForTesting
- static ResourceFilterFactory from(boolean filterInAnalysis, AttributeMap attrs) {
- if (!hasAttr(attrs, RESOURCE_CONFIGURATION_FILTERS_NAME) && !hasAttr(attrs, DENSITIES_NAME)) {
+ static ResourceFilterFactory fromAttrs(AndroidAaptVersion aaptVersion, AttributeMap attrs) {
+ return from(
+ aaptVersion,
+ rawFiltersFromAttrs(attrs, RESOURCE_CONFIGURATION_FILTERS_NAME),
+ rawFiltersFromAttrs(attrs, DENSITIES_NAME));
+ }
+
+ static ResourceFilterFactory from(
+ AndroidAaptVersion aaptVersion, List<String> configFilters, List<String> densities) {
+ if (configFilters.isEmpty() && densities.isEmpty()) {
return empty();
}
+ // aapt2 must have access to all of the resources in execution, so don't filter in analysis.
+ boolean filterInAnalysis = aaptVersion != AndroidAaptVersion.AAPT2;
+
return new ResourceFilterFactory(
- extractFilters(attrs, RESOURCE_CONFIGURATION_FILTERS_NAME),
- extractFilters(attrs, DENSITIES_NAME),
- filterInAnalysis);
+ extractFilters(configFilters), extractFilters(densities), filterInAnalysis);
}
private ImmutableList<FolderConfiguration> getConfigurationFilters(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java
index 70dfa8b3b8..4e6c395287 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceShrinkerActionBuilder.java
@@ -26,7 +26,6 @@ import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.VectorAr
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.config.CompilationMode;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
import com.google.devtools.build.lib.util.OS;
import java.util.Collections;
@@ -52,7 +51,7 @@ public class ResourceShrinkerActionBuilder {
private ResourceFilterFactory resourceFilterFactory;
/** @param ruleContext The RuleContext of the owning rule. */
- public ResourceShrinkerActionBuilder(RuleContext ruleContext) throws RuleErrorException {
+ public ResourceShrinkerActionBuilder(RuleContext ruleContext) {
this.ruleContext = ruleContext;
this.spawnActionBuilder = new SpawnAction.Builder();
this.sdk = AndroidSdkProvider.fromRuleContext(ruleContext);
@@ -132,7 +131,7 @@ public class ResourceShrinkerActionBuilder {
return this;
}
- public Artifact build() throws RuleErrorException {
+ public Artifact build() {
ImmutableList.Builder<Artifact> inputs = ImmutableList.builder();
ImmutableList.Builder<Artifact> outputs = ImmutableList.builder();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java
index 7296e50a01..398041d7a5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java
@@ -244,16 +244,41 @@ public abstract class ProguardHelper {
*/
public static ImmutableList<Artifact> collectTransitiveProguardSpecs(
RuleContext ruleContext, Iterable<Artifact> specsToInclude) {
+ return collectTransitiveProguardSpecs(
+ ruleContext,
+ Iterables.concat(
+ specsToInclude,
+ ruleContext.getPrerequisiteArtifacts(":extra_proguard_specs", Mode.TARGET).list()),
+ ruleContext.attributes().has(PROGUARD_SPECS, BuildType.LABEL_LIST)
+ ? ruleContext.getPrerequisiteArtifacts(PROGUARD_SPECS, Mode.TARGET).list()
+ : ImmutableList.<Artifact>of(),
+ ruleContext.getPrerequisites("deps", Mode.TARGET, ProguardSpecProvider.class));
+ }
+
+ /**
+ * Retrieves the full set of proguard specs that should be applied to this binary, including the
+ * specs passed in, if Proguard should run on the given rule.
+ *
+ * <p>Unlike {@link #collectTransitiveProguardSpecs(RuleContext, Iterable)}, this method requires
+ * values to be passed in explicitly, and does not extract them from rule attributes.
+ *
+ * <p>If Proguard shouldn't be applied, or the legacy link mode is used and there are no
+ * proguard_specs on this rule, an empty list will be returned, regardless of any given specs or
+ * specs from dependencies. {@link
+ * com.google.devtools.build.lib.rules.android.AndroidBinary#createAndroidBinary} relies on that
+ * behavior.
+ */
+ public static ImmutableList<Artifact> collectTransitiveProguardSpecs(
+ RuleContext ruleContext,
+ Iterable<Artifact> specsToInclude,
+ ImmutableList<Artifact> localProguardSpecs,
+ Iterable<ProguardSpecProvider> proguardDeps) {
JavaOptimizationMode optMode = getJavaOptimizationMode(ruleContext);
if (optMode == JavaOptimizationMode.NOOP) {
return ImmutableList.of();
}
- ImmutableList<Artifact> proguardSpecs =
- ruleContext.attributes().has(PROGUARD_SPECS, BuildType.LABEL_LIST)
- ? ruleContext.getPrerequisiteArtifacts(PROGUARD_SPECS, Mode.TARGET).list()
- : ImmutableList.<Artifact>of();
- if (optMode == JavaOptimizationMode.LEGACY && proguardSpecs.isEmpty()) {
+ if (optMode == JavaOptimizationMode.LEGACY && localProguardSpecs.isEmpty()) {
return ImmutableList.of();
}
@@ -261,12 +286,9 @@ public abstract class ProguardHelper {
// flags since those flags would override the desired optMode
ImmutableSortedSet.Builder<Artifact> builder =
ImmutableSortedSet.orderedBy(Artifact.EXEC_PATH_COMPARATOR)
- .addAll(proguardSpecs)
- .addAll(specsToInclude)
- .addAll(
- ruleContext.getPrerequisiteArtifacts(":extra_proguard_specs", Mode.TARGET).list());
- for (ProguardSpecProvider dep :
- ruleContext.getPrerequisites("deps", Mode.TARGET, ProguardSpecProvider.class)) {
+ .addAll(localProguardSpecs)
+ .addAll(specsToInclude);
+ for (ProguardSpecProvider dep : proguardDeps) {
builder.addAll(dep.getTransitiveProguardSpecs());
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java
index a7bee2486c..ef238c1c56 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidResourcesTest.java
@@ -466,7 +466,19 @@ public class AndroidResourcesTest extends ResourceTestBase {
ResourceApk resourceApk =
ProcessedAndroidData.processBinaryDataFrom(
- ruleContext, getManifest(), false, ImmutableMap.of(), AndroidAaptVersion.AUTO)
+ ruleContext,
+ getManifest(),
+ false,
+ ImmutableMap.of(),
+ AndroidAaptVersion.AUTO,
+ AndroidResources.empty(),
+ AndroidAssets.empty(),
+ ResourceDependencies.empty(),
+ AssetDependencies.empty(),
+ ResourceFilterFactory.empty(),
+ ImmutableList.of(),
+ false,
+ false)
.generateRClass(ruleContext, AndroidAaptVersion.AUTO);
assertThat(resourceApk.getResourceProguardConfig()).isNotNull();
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java
index 6b47a0adde..1793e42b14 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterFactoryTest.java
@@ -25,6 +25,7 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.packages.AttributeMap;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
+import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
import com.google.devtools.build.lib.testutil.FakeAttributeMapper;
import java.util.ArrayList;
import java.util.List;
@@ -477,8 +478,9 @@ public class ResourceFilterFactoryTest extends ResourceTestBase {
ImmutableList<String> densities,
boolean filterInAnalysis) {
- return ResourceFilterFactory.from(
- filterInAnalysis, getAttributeMap(resourceConfigurationFilters, densities));
+ return ResourceFilterFactory.fromAttrs(
+ filterInAnalysis ? AndroidAaptVersion.AAPT : AndroidAaptVersion.AAPT2,
+ getAttributeMap(resourceConfigurationFilters, densities));
}
private AttributeMap getAttributeMap(