Expose process_test_data (for android_test) to Skylark Explicitly work with rele attributes at (or closer to) the top level rather than deep in the code. RELNOTES: none PiperOrigin-RevId: 196004542
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java index 32c5989..11ddc1b 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidAssets.java
@@ -61,12 +61,13 @@ } } - /** Collects this rule's android assets. */ + /** Collects this rule's android assets, based on rule attributes. */ public static AndroidAssets from(RuleContext ruleContext) throws RuleErrorException { return from(ruleContext, getAssetTargets(ruleContext), getAssetDir(ruleContext)); } - static AndroidAssets from( + /** Collects Android assets from the specified values */ + public static AndroidAssets from( RuleErrorConsumer errorConsumer, @Nullable Iterable<? extends TransitiveInfoCollection> assetTargets, @Nullable PathFragment assetsDir)
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 eed11af..4619862 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
@@ -202,13 +202,16 @@ applicationManifest = ApplicationManifest.fromExplicitManifest(ruleContext, manifest.getManifest()); + AndroidAaptVersion aaptVersion = AndroidAaptVersion.chooseTargetAaptVersion(ruleContext); resourceApk = ProcessedAndroidData.processBinaryDataFrom( ruleContext, manifest, /* conditionalKeepRules = */ shouldShrinkResourceCycles( - ruleContext, shrinkResources)) - .generateRClass(ruleContext); + ruleContext, shrinkResources), + applicationManifest.getManifestValues(), + aaptVersion) + .generateRClass(ruleContext, aaptVersion); } else { applicationManifest = androidSemantics.getManifestForRule(ruleContext).mergeWith(ruleContext, resourceDeps);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java index 64d0cd7..1042e2c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java
@@ -76,7 +76,8 @@ manifest.addMobileInstallStubApplication(ruleContext), ruleContext.getImplicitOutputArtifact( AndroidRuleClasses.ANDROID_INCREMENTAL_RESOURCES_APK), - "incremental") + "incremental", + applicationManifest.getManifestValues()) // Intentionally skip building an R class JAR - incremental binaries handle this // separately. .withValidatedResources(null); @@ -86,7 +87,8 @@ ruleContext, manifest.createSplitManifest(ruleContext, "android_resources", false), getMobileInstallArtifact(ruleContext, "android_resources.ap_"), - "incremental_split") + "incremental_split", + applicationManifest.getManifestValues()) // Intentionally skip building an R class JAR - incremental binaries handle this // separately. .withValidatedResources(null);
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 d9f1fee..c88e369 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
@@ -36,6 +36,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.BuildType; +import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion; import com.google.devtools.build.lib.rules.java.ClasspathConfiguredFragment; import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder; import com.google.devtools.build.lib.rules.java.JavaCommon; @@ -93,9 +94,14 @@ StampedAndroidManifest manifest = AndroidManifest.from(ruleContext).mergeWithDeps(ruleContext); + AndroidAaptVersion aaptVersion = AndroidAaptVersion.chooseTargetAaptVersion(ruleContext); resourceApk = - ProcessedAndroidData.processLocalTestDataFrom(ruleContext, manifest) - .generateRClass(ruleContext); + ProcessedAndroidData.processLocalTestDataFrom( + ruleContext, + manifest, + ApplicationManifest.getManifestValues(ruleContext), + aaptVersion) + .generateRClass(ruleContext, aaptVersion); } else { // Create the final merged manifest ResourceDependencies resourceDependencies =
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 dfe7a01..b90d28b 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
@@ -13,7 +13,6 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; -import com.google.common.annotations.VisibleForTesting; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; @@ -21,6 +20,7 @@ import com.google.devtools.build.lib.rules.java.JavaUtil; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.vfs.PathFragment; +import java.util.Map; import java.util.Objects; import javax.annotation.Nullable; @@ -91,8 +91,11 @@ this(manifest, other.pkg, other.exported); } - @VisibleForTesting - AndroidManifest(Artifact manifest, @Nullable String pkg, boolean exported) { + /** + * Creates a manifest wrapper without doing any processing. From within a rule, use {@link + * #from(RuleContext, AndroidSemantics)} instead. + */ + public AndroidManifest(Artifact manifest, @Nullable String pkg, boolean exported) { this.manifest = manifest; this.pkg = pkg; this.exported = exported; @@ -112,11 +115,15 @@ * <p>If no manifest values are specified, the manifest will remain unstamped. */ public StampedAndroidManifest stampWithManifestValues(RuleContext ruleContext) { - return mergeWithDeps(ruleContext, ResourceDependencies.empty()); + return mergeWithDeps( + ruleContext, + ResourceDependencies.empty(), + ApplicationManifest.getManifestValues(ruleContext), + ApplicationManifest.useLegacyMerging(ruleContext)); } /** - * Merges the manifest with any dependent manifests. + * Merges the manifest with any dependent manifests, extracted from rule attributes. * * <p>The manifest will also be stamped with any manifest values specified in the target's * attributes @@ -126,17 +133,20 @@ */ public StampedAndroidManifest mergeWithDeps(RuleContext ruleContext) { return mergeWithDeps( - ruleContext, ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false)); + ruleContext, + ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false), + ApplicationManifest.getManifestValues(ruleContext), + ApplicationManifest.useLegacyMerging(ruleContext)); } - private StampedAndroidManifest mergeWithDeps( - RuleContext ruleContext, ResourceDependencies resourceDeps) { + public StampedAndroidManifest mergeWithDeps( + RuleContext ruleContext, + ResourceDependencies resourceDeps, + Map<String, String> manifestValues, + boolean useLegacyMerger) { Artifact newManifest = ApplicationManifest.maybeMergeWith( - ruleContext, - manifest, - resourceDeps, - ApplicationManifest.getManifestValues(ruleContext)) + ruleContext, manifest, resourceDeps, manifestValues, useLegacyMerger, pkg) .orElse(manifest); return new StampedAndroidManifest(newManifest, pkg, exported); @@ -165,7 +175,7 @@ } /** Gets the default Java package */ - static String getDefaultPackage(RuleContext ruleContext) { + public static String getDefaultPackage(RuleContext ruleContext) { PathFragment dummyJar = ruleContext.getPackageDirectory().getChild("Dummy.jar"); return getJavaPackageFromPath(ruleContext, dummyJar); }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java index 7858091..842b4ed 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidResources.java
@@ -138,7 +138,7 @@ resourcesAttr); } - static AndroidResources from( + public static AndroidResources from( RuleErrorConsumer errorConsumer, Iterable<FileProvider> resourcesTargets, String resourcesAttr)
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 cb13f6a..389115a 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
@@ -19,6 +19,7 @@ import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.FileProvider; 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; import com.google.devtools.build.lib.collect.nestedset.Order; import com.google.devtools.build.lib.events.Location; @@ -396,16 +397,7 @@ aaptVersion) .validate(ctx.getRuleContext(), aaptVersion); - JavaInfo javaInfo = - JavaInfo.Builder.create() - .setNeverlink(true) - .addProvider( - JavaCompilationInfoProvider.class, - new JavaCompilationInfoProvider.Builder() - .setCompilationClasspath( - NestedSetBuilder.create(Order.NAIVE_LINK_ORDER, validated.getClassJar())) - .build()) - .build(); + JavaInfo javaInfo = getJavaInfoForRClassJar(validated.getClassJar()); return SkylarkDict.of( /* env = */ null, @@ -742,8 +734,35 @@ .build()); } + public static SkylarkDict<NativeProvider<?>, NativeInfo> getNativeInfosFrom( + ResourceApk resourceApk, Label label) { + ImmutableMap.Builder<NativeProvider<?>, NativeInfo> builder = ImmutableMap.builder(); + + builder.put(AndroidResourcesInfo.PROVIDER, resourceApk.toResourceInfo(label)); + + resourceApk + .toAssetsInfo(label) + .ifPresent(info -> builder.put(AndroidAssetsInfo.PROVIDER, info)); + resourceApk.toManifestInfo().ifPresent(info -> builder.put(AndroidManifestInfo.PROVIDER, info)); + + builder.put(JavaInfo.PROVIDER, getJavaInfoForRClassJar(resourceApk.getResourceJavaClassJar())); + + return SkylarkDict.copyOf(/* env = */ null, builder.build()); + } + + private static JavaInfo getJavaInfoForRClassJar(Artifact rClassJar) { + return JavaInfo.Builder.create() + .setNeverlink(true) + .addProvider( + JavaCompilationInfoProvider.class, + new JavaCompilationInfoProvider.Builder() + .setCompilationClasspath(NestedSetBuilder.create(Order.NAIVE_LINK_ORDER, rClassJar)) + .build()) + .build(); + } + /** Checks if a "Noneable" object passed by Skylark is "None", which Java should treat as null. */ - private static boolean isNone(Object object) { + public static boolean isNone(Object object) { return object == Runtime.NONE; } @@ -760,7 +779,7 @@ * @return {@code null}, if the noneable argument was None, or the cast object, otherwise. */ @Nullable - private static <T> T fromNoneable(Object object, Class<T> clazz) { + public static <T> T fromNoneable(Object object, Class<T> clazz) { if (isNone(object)) { return null; } @@ -768,7 +787,7 @@ return clazz.cast(object); } - private static <T> T fromNoneableOrDefault(Object object, Class<T> clazz, T defaultValue) { + public static <T> T fromNoneableOrDefault(Object object, Class<T> clazz, T defaultValue) { T value = fromNoneable(object, clazz); if (value == null) { return defaultValue; @@ -784,7 +803,7 @@ * casts it to a list with the appropriate generic. */ @Nullable - private static <T> List<T> listFromNoneable(Object object, Class<T> clazz) throws EvalException { + public static <T> List<T> listFromNoneable(Object object, Class<T> clazz) throws EvalException { SkylarkList<?> asList = fromNoneable(object, SkylarkList.class); if (asList == null) { return null; @@ -803,7 +822,7 @@ return SkylarkList.createImmutable(value); } - private static <T extends NativeInfo> SkylarkList<T> getProviders( + public static <T extends NativeInfo> SkylarkList<T> getProviders( SkylarkList<ConfiguredTarget> targets, NativeProvider<T> provider) { return SkylarkList.createImmutable( targets
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 783f0f2..deb2cb5 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
@@ -192,7 +192,7 @@ * * @return an artifact for the generated manifest */ - static Artifact generateManifest(RuleContext ruleContext, String manifestPackage) { + public static Artifact generateManifest(RuleContext ruleContext, String manifestPackage) { Artifact generatedManifest = ruleContext.getUniqueDirectoryArtifact( ruleContext.getRule().getName() + "_generated", @@ -216,19 +216,35 @@ return generatedManifest; } + /** Gets a map of manifest values from this rule's 'manifest_values' attribute */ static ImmutableMap<String, String> getManifestValues(RuleContext context) { + return getManifestValues( + context, + context.attributes().isAttributeValueExplicitlySpecified("manifest_values") + ? context.attributes().get("manifest_values", Type.STRING_DICT) + : null); + } + + /** Gets and expands an expanded map of manifest values from some raw map of manifest values. */ + static ImmutableMap<String, String> getManifestValues( + RuleContext ruleContext, @Nullable Map<String, String> rawMap) { Map<String, String> manifestValues = new TreeMap<>(); - if (context.attributes().isAttributeValueExplicitlySpecified("manifest_values")) { - manifestValues.putAll(context.attributes().get("manifest_values", Type.STRING_DICT)); + if (rawMap != null) { + manifestValues.putAll(rawMap); } for (String variable : manifestValues.keySet()) { manifestValues.put( - variable, context.getExpander().expand("manifest_values", manifestValues.get(variable))); + variable, + ruleContext.getExpander().expand("manifest_values", manifestValues.get(variable))); } return ImmutableMap.copyOf(manifestValues); } + public ImmutableMap<String, String> getManifestValues() { + return manifestValues; + } + private final Artifact manifest; private final ImmutableMap<String, String> manifestValues; private final AndroidAaptVersion targetAaptVersion; @@ -241,7 +257,13 @@ } public ApplicationManifest mergeWith(RuleContext ruleContext, ResourceDependencies resourceDeps) { - return maybeMergeWith(ruleContext, manifest, resourceDeps, manifestValues) + return maybeMergeWith( + ruleContext, + manifest, + resourceDeps, + manifestValues, + useLegacyMerging(ruleContext), + AndroidCommon.getJavaPackage(ruleContext)) .map(merged -> new ApplicationManifest(ruleContext, merged, targetAaptVersion)) .orElse(this); } @@ -250,11 +272,14 @@ RuleContext ruleContext, Artifact primaryManifest, ResourceDependencies resourceDeps, - Map<String, String> manifestValues) { + Map<String, String> manifestValues, + boolean useLegacyMerging, + String customPackage) { Map<Artifact, Label> mergeeManifests = getMergeeManifests(resourceDeps.getResourceContainers()); - if (useLegacyMerging(ruleContext)) { + if (useLegacyMerging) { if (!mergeeManifests.isEmpty()) { + Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact( ruleContext.getRule().getName() + "_merged", @@ -285,7 +310,7 @@ .setMergeeManifests(mergeeManifests) .setLibrary(false) .setManifestValues(manifestValues) - .setCustomPackage(AndroidCommon.getJavaPackage(ruleContext)) + .setCustomPackage(customPackage) .setManifestOutput(outputManifest) .setLogOut(mergeLog) .build(ruleContext); @@ -295,24 +320,30 @@ return Optional.empty(); } - private static boolean useLegacyMerging(RuleContext ruleContext) { - boolean legacy = false; - if (ruleContext.isLegalFragment(AndroidConfiguration.class) - && ruleContext.getRule().isAttrDefined("manifest_merger", STRING)) { - AndroidManifestMerger merger = - AndroidManifestMerger.fromString(ruleContext.attributes().get("manifest_merger", STRING)); - if (merger == null) { - merger = ruleContext.getFragment(AndroidConfiguration.class).getManifestMerger(); - } - if (merger == AndroidManifestMerger.LEGACY) { - ruleContext.ruleWarning( - "manifest_merger 'legacy' is deprecated. Please update to 'android'.\n" - + "See https://developer.android.com/studio/build/manifest-merge.html for more " - + "information about the manifest merger."); - } - legacy = merger == AndroidManifestMerger.LEGACY; + /** Checks if the legacy manifest merger should be used, based on a rule attribute */ + static boolean useLegacyMerging(RuleContext ruleContext) { + return ruleContext.isLegalFragment(AndroidConfiguration.class) + && ruleContext.getRule().isAttrDefined("manifest_merger", STRING) + && useLegacyMerging(ruleContext, ruleContext.attributes().get("manifest_merger", STRING)); + } + + /** + * Checks if the legacy manifest merger should be used, based on an optional string specifying the + * merger to use. + */ + public static boolean useLegacyMerging(RuleContext ruleContext, @Nullable String mergerString) { + AndroidManifestMerger merger = AndroidManifestMerger.fromString(mergerString); + if (merger == null) { + merger = ruleContext.getFragment(AndroidConfiguration.class).getManifestMerger(); } - return legacy; + if (merger == AndroidManifestMerger.LEGACY) { + ruleContext.ruleWarning( + "manifest_merger 'legacy' is deprecated. Please update to 'android'.\n" + + "See https://developer.android.com/studio/build/manifest-merge.html for more " + + "information about the manifest merger."); + } + + return merger == AndroidManifestMerger.LEGACY; } private static Map<Artifact, Label> getMergeeManifests(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AssetDependencies.java b/src/main/java/com/google/devtools/build/lib/rules/android/AssetDependencies.java index cc9c8dc..1cfe929 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AssetDependencies.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AssetDependencies.java
@@ -38,14 +38,15 @@ private final NestedSet<Artifact> transitiveAssets; private final NestedSet<Artifact> transitiveSymbols; - static AssetDependencies fromRuleDeps(RuleContext ruleContext, boolean neverlink) { + public static AssetDependencies fromRuleDeps(RuleContext ruleContext, boolean neverlink) { return fromProviders( AndroidCommon.getTransitivePrerequisites( ruleContext, Mode.TARGET, AndroidAssetsInfo.PROVIDER), neverlink); } - static AssetDependencies fromProviders(Iterable<AndroidAssetsInfo> providers, boolean neverlink) { + public static AssetDependencies fromProviders( + Iterable<AndroidAssetsInfo> providers, boolean neverlink) { NestedSetBuilder<ParsedAndroidAssets> direct = NestedSetBuilder.naiveLinkOrder(); NestedSetBuilder<ParsedAndroidAssets> transitive = NestedSetBuilder.naiveLinkOrder(); NestedSetBuilder<Artifact> assets = NestedSetBuilder.naiveLinkOrder();
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 8a0d0e6..438f12c 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
@@ -13,6 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; +import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.config.CompilationMode; @@ -52,7 +53,11 @@ /** Processes Android data (assets, resources, and manifest) for android_binary targets. */ public static ProcessedAndroidData processBinaryDataFrom( - RuleContext ruleContext, StampedAndroidManifest manifest, boolean conditionalKeepRules) + RuleContext ruleContext, + StampedAndroidManifest manifest, + boolean conditionalKeepRules, + Map<String, String> manifestValues, + AndroidAaptVersion aaptVersion) throws RuleErrorException, InterruptedException { if (conditionalKeepRules && AndroidAaptVersion.chooseTargetAaptVersion(ruleContext) != AndroidAaptVersion.AAPT2) { @@ -61,7 +66,7 @@ } AndroidResourcesProcessorBuilder builder = - builderForNonIncrementalTopLevelTarget(ruleContext, manifest) + builderForNonIncrementalTopLevelTarget(ruleContext, manifest, manifestValues, aaptVersion) .setUseCompiledResourcesForMerge( AndroidAaptVersion.chooseTargetAaptVersion(ruleContext) == AndroidAaptVersion.AAPT2 && AndroidCommon.getAndroidConfig(ruleContext).skipParsingAction()) @@ -95,11 +100,13 @@ RuleContext ruleContext, StampedAndroidManifest manifest, Artifact apkOut, - String proguardPrefix) + String proguardPrefix, + Map<String, String> manifestValues) throws RuleErrorException { AndroidResourcesProcessorBuilder builder = - builderForTopLevelTarget(ruleContext, manifest, proguardPrefix).setApkOut(apkOut); + builderForTopLevelTarget(ruleContext, manifest, proguardPrefix, manifestValues) + .setApkOut(apkOut); return buildActionForBinary(ruleContext, builder, manifest); } @@ -135,10 +142,14 @@ /** Processes Android data (assets, resources, and manifest) for android_local_test targets. */ public static ProcessedAndroidData processLocalTestDataFrom( - RuleContext ruleContext, StampedAndroidManifest manifest) + RuleContext ruleContext, + StampedAndroidManifest manifest, + Map<String, String> manifestValues, + AndroidAaptVersion aaptVersion) throws RuleErrorException, InterruptedException { - return builderForNonIncrementalTopLevelTarget(ruleContext, manifest) + return builderForNonIncrementalTopLevelTarget( + ruleContext, manifest, manifestValues, aaptVersion) .setUseCompiledResourcesForMerge( AndroidAaptVersion.chooseTargetAaptVersion(ruleContext) == AndroidAaptVersion.AAPT2 && AndroidCommon.getAndroidConfig(ruleContext).skipParsingAction()) @@ -161,27 +172,24 @@ RuleContext ruleContext, StampedAndroidManifest manifest, String packageUnderTest, - boolean hasLocalResourceFiles) - throws InterruptedException, RuleErrorException { + boolean hasLocalResourceFiles, + AndroidAaptVersion aaptVersion, + AndroidResources resources, + ResourceDependencies resourceDeps, + AndroidAssets assets, + AssetDependencies assetDeps) + throws InterruptedException { AndroidResourcesProcessorBuilder builder = - builderForNonIncrementalTopLevelTarget(ruleContext, manifest) + builderForNonIncrementalTopLevelTarget( + ruleContext, manifest, ImmutableMap.of(), aaptVersion) .setMainDexProguardOut(AndroidBinary.createMainDexProguardSpec(ruleContext)) .setPackageUnderTest(packageUnderTest) - .setIsTestWithResources(hasLocalResourceFiles); + .setIsTestWithResources(hasLocalResourceFiles) + .withResourceDependencies(resourceDeps) + .withAssetDependencies(assetDeps); - if (hasLocalResourceFiles) { - builder - .withResourceDependencies( - ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false)) - .withAssetDependencies( - AssetDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false)); - } - - return builder.build( - AndroidResources.from(ruleContext, "local_resource_files"), - AndroidAssets.from(ruleContext), - manifest); + return builder.build(resources, assets, manifest); } /** @@ -190,18 +198,22 @@ * <p>The builder will be populated with commonly-used settings and outputs. */ private static AndroidResourcesProcessorBuilder builderForNonIncrementalTopLevelTarget( - RuleContext ruleContext, StampedAndroidManifest manifest) - throws InterruptedException, RuleErrorException { + RuleContext ruleContext, + StampedAndroidManifest manifest, + Map<String, String> manifestValues, + AndroidAaptVersion aaptVersion) + throws InterruptedException { - return builderForTopLevelTarget(ruleContext, manifest, "") - .targetAaptVersion(AndroidAaptVersion.chooseTargetAaptVersion(ruleContext)) + return builderForTopLevelTarget(ruleContext, manifest, "", manifestValues) + .targetAaptVersion(aaptVersion) // Outputs .setApkOut(ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK)) .setRTxtOut(ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT)) .setSourceJarOut( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_JAVA_SOURCE_JAR)) - .setSymbols(ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_MERGED_SYMBOLS)); + .setSymbols( + ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_MERGED_SYMBOLS)); } /** @@ -210,9 +222,10 @@ * <p>The builder will be populated with commonly-used settings and outputs. */ private static AndroidResourcesProcessorBuilder builderForTopLevelTarget( - RuleContext ruleContext, StampedAndroidManifest manifest, String proguardPrefix) { - Map<String, String> manifestValues = ApplicationManifest.getManifestValues(ruleContext); - + RuleContext ruleContext, + StampedAndroidManifest manifest, + String proguardPrefix, + Map<String, String> manifestValues) { return new AndroidResourcesProcessorBuilder(ruleContext) // Settings .setDebug(ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT) @@ -272,10 +285,10 @@ * <p>Registers an action to run R class generation, the last step needed in resource processing. * Returns the fully processed data, including validated resources, wrapped in a ResourceApk. */ - public ResourceApk generateRClass(RuleContext ruleContext) - throws RuleErrorException, InterruptedException { + public ResourceApk generateRClass(RuleContext ruleContext, AndroidAaptVersion aaptVersion) + throws InterruptedException { return new RClassGeneratorActionBuilder(ruleContext) - .targetAaptVersion(AndroidAaptVersion.chooseTargetAaptVersion(ruleContext)) + .targetAaptVersion(aaptVersion) .withDependencies(resourceDeps) .setClassJarOut( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR))
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java index 324766d..7b128596 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceApk.java
@@ -20,6 +20,7 @@ import com.google.devtools.build.lib.analysis.config.CompilationMode; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import java.util.Optional; import javax.annotation.Nullable; /** @@ -228,35 +229,49 @@ return resourceDeps.toInfo(validatedResources); } + // TODO(b/77574966): Stop returning an Optional once we get rid of ResourceContainer and can + // guarantee that only properly merged assets are passed into this object. + Optional<AndroidAssetsInfo> toAssetsInfo(Label label) { + if (primaryAssets instanceof MergedAndroidAssets) { + MergedAndroidAssets merged = (MergedAndroidAssets) primaryAssets; + AndroidAssetsInfo assetsInfo = merged.toProvider(); + return Optional.of(assetsInfo); + } else if (primaryAssets == null) { + return Optional.of(assetDeps.toInfo(label)); + } else { + return Optional.empty(); + } + } + + // TODO(b/77574966): Remove this cast once we get rid of ResourceContainer and can guarantee + // that only properly merged resources are passed into this object. + Optional<AndroidManifestInfo> toManifestInfo() { + if (validatedResources instanceof ValidatedAndroidResources) { + ValidatedAndroidResources validated = (ValidatedAndroidResources) validatedResources; + + return Optional.of(validated.getStampedManifest().toProvider()); + } + + return Optional.empty(); + } + public void addToConfiguredTargetBuilder( RuleConfiguredTargetBuilder builder, Label label, boolean includeSkylarkApiProvider) { AndroidResourcesInfo resourceInfo = toResourceInfo(label); builder.addNativeDeclaredProvider(resourceInfo); - // TODO(b/77574966): Remove this cast once we get rid of ResourceContainer and can guarantee - // that only properly merged resources are passed into this object. - if (validatedResources instanceof ValidatedAndroidResources) { - ValidatedAndroidResources validated = (ValidatedAndroidResources) validatedResources; + Optional<AndroidManifestInfo> manifestInfo = toManifestInfo(); + manifestInfo.ifPresent(builder::addNativeDeclaredProvider); - builder.addNativeDeclaredProvider(validated.getStampedManifest().toProvider()); - } - - // TODO(b/77574966): Remove this cast once we get rid of ResourceContainer and can guarantee - // that only properly merged resources are passed into this object. - if (primaryAssets instanceof MergedAndroidAssets) { - MergedAndroidAssets merged = (MergedAndroidAssets) primaryAssets; - AndroidAssetsInfo assetsInfo = merged.toProvider(); - builder.addNativeDeclaredProvider(assetsInfo); - - if (assetsInfo.getValidationResult() != null) { - // Asset merging output isn't consumed by anything. Require it to be run by top-level - // targets - // so we can validate there are no asset merging conflicts. - builder.addOutputGroup(OutputGroupInfo.HIDDEN_TOP_LEVEL, assetsInfo.getValidationResult()); + Optional<AndroidAssetsInfo> assetsInfo = toAssetsInfo(label); + if (assetsInfo.isPresent()) { + builder.addNativeDeclaredProvider(assetsInfo.get()); + if (assetsInfo.get().getValidationResult() != null) { + // Asset merging output isn't consumed by anything. Require it to be run by top-level targets + // so we can validate there are no asset merging conflicts. + builder.addOutputGroup( + OutputGroupInfo.HIDDEN_TOP_LEVEL, assetsInfo.get().getValidationResult()); } - - } else if (primaryAssets == null) { - builder.addNativeDeclaredProvider(assetDeps.toInfo(label)); } if (includeSkylarkApiProvider) {
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 db71439..a7bee24 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
@@ -17,6 +17,7 @@ import static com.google.common.truth.Truth.assertWithMessage; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Artifact; @@ -448,7 +449,9 @@ null); ValidatedAndroidData validated = - processedData.generateRClass(ruleContext).getValidatedResources(); + processedData + .generateRClass(ruleContext, AndroidAaptVersion.chooseTargetAaptVersion(ruleContext)) + .getValidatedResources(); // An action to generate the R.class file should be registered. assertActionArtifacts( @@ -462,8 +465,9 @@ RuleContext ruleContext = getRuleContext("android_binary", "manifest='AndroidManifest.xml',"); ResourceApk resourceApk = - ProcessedAndroidData.processBinaryDataFrom(ruleContext, getManifest(), false) - .generateRClass(ruleContext); + ProcessedAndroidData.processBinaryDataFrom( + ruleContext, getManifest(), false, ImmutableMap.of(), AndroidAaptVersion.AUTO) + .generateRClass(ruleContext, AndroidAaptVersion.AUTO); assertThat(resourceApk.getResourceProguardConfig()).isNotNull(); assertThat(resourceApk.getMainDexProguardConfig()).isNotNull();