diff options
author | 2016-06-22 20:46:21 +0000 | |
---|---|---|
committer | 2016-06-23 11:10:23 +0000 | |
commit | e1a4a812971f604d51bdf098b6117d9ba03da1c8 (patch) | |
tree | d53b64a6f80fb82cfa43d65c9b3f2f73b9084cdf /src/main/java/com/google/devtools/build/lib/rules | |
parent | 6105e2415faa0f36ec6ae3399d90e1a173ef7f58 (diff) |
Adds the Android manifest merger as an option for android_binary rules. The merger that is used (legacy or android) is controlled by the manifest_merger attribute on android_binary and the default is controlled by the --android_manifest_merger flag.
RELNOTES: The Android manifest merger is now available as an option for android_binary rules. The merger will honor tools annotations in AndroidManifest.xml and will perform placeholder substitutions using the values specified in android_binary.manifest_values. The merger may be selected by setting the manifest_merger attribute on android_binary.
--
MOS_MIGRATED_REVID=125603954
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules')
8 files changed, 339 insertions, 123 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 500c60165d..c9530a6c69 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 @@ -191,25 +191,6 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { LocalResourceContainer.validateRuleContext(ruleContext); ApplicationManifest ruleManifest = androidSemantics.getManifestForRule(ruleContext); - String applicationId = null; - String versionCode = null; - String versionName = null; - Map<String, String> manifestValues = - ruleContext.attributes().get("manifest_values", Type.STRING_DICT); - if (manifestValues != null) { - if (manifestValues.containsKey("applicationId")) { - applicationId = manifestValues.get("applicationId"); - } - if (manifestValues.containsKey("versionCode")) { - versionCode = ruleContext.expandMakeVariables("manifest_values", - manifestValues.get("versionCode")); - } - if (manifestValues.containsKey("versionName")) { - versionName = ruleContext.expandMakeVariables("manifest_values", - manifestValues.get("versionName")); - } - } - applicationManifest = ruleManifest.mergeWith(ruleContext, resourceDeps); resourceApk = applicationManifest.packWithDataAndResources( @@ -223,9 +204,6 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext.getTokenizedStringListAttr("nocompress_extensions"), ruleContext.attributes().get("crunch_png", Type.BOOLEAN), ruleContext.getTokenizedStringListAttr("densities"), - applicationId, - versionCode, - versionName, false, /* incremental */ ProguardHelper.getProguardConfigArtifact(ruleContext, ""), createMainDexProguardSpec(ruleContext), @@ -247,9 +225,6 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext.getTokenizedStringListAttr("nocompress_extensions"), ruleContext.attributes().get("crunch_png", Type.BOOLEAN), ruleContext.getTokenizedStringListAttr("densities"), - applicationId, - versionCode, - versionName, true, /* incremental */ ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental"), null, /* mainDexProguardCfg */ @@ -270,9 +245,6 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext.getTokenizedStringListAttr("nocompress_extensions"), ruleContext.attributes().get("crunch_png", Type.BOOLEAN), ruleContext.getTokenizedStringListAttr("densities"), - applicationId, - versionCode, - versionName, true, /* incremental */ ProguardHelper.getProguardConfigArtifact(ruleContext, "instant_run"), null, /* mainDexProguardCfg */ @@ -293,9 +265,6 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { ruleContext.getTokenizedStringListAttr("nocompress_extensions"), ruleContext.attributes().get("crunch_png", Type.BOOLEAN), ruleContext.getTokenizedStringListAttr("densities"), - applicationId, - versionCode, - versionName, true, /* incremental */ ProguardHelper.getProguardConfigArtifact(ruleContext, "incremental_split"), null, /* mainDexProguardCfg */ diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryOnlyRule.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryOnlyRule.java index a558b05664..e6e116d888 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryOnlyRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryOnlyRule.java @@ -26,6 +26,7 @@ import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet; import com.google.devtools.build.lib.packages.RuleClass; import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType; +import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidManifestMerger; import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode; /** @@ -35,15 +36,40 @@ public final class AndroidBinaryOnlyRule implements RuleDefinition { @Override public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) { return builder -// /* <!-- #BLAZE_RULE(android_binary).ATTRIBUTE(manifest_values) --> -// A dictionary of values to be overridden in the manifest. Any instance of ${name} in the -// manifest will be replaced with the value corresponding to name in this dictionary. -// applicationId, versionCode, versionName, minSdkVersion, targetSdkVersion and -// maxSdkVersion will also override the corresponding attributes of the manifest and -// uses-sdk tags. packageName will be ignored and will be set from either applicationId if -// specified or the package in manifest. -// <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ - .add(attr("manifest_values", STRING_DICT).undocumented("not ready for production use")) + /* <!-- #BLAZE_RULE(android_binary).ATTRIBUTE(manifest_merger) --> + Select the manifest merger to use for this rule.<br/> + Possible values: + <ul> + <li><code>manifest_merger = "legacy"</code>: Use the legacy manifest merger. Does not + allow features of the android merger like placeholder substitution and tools + attributes for defining merge behavior. Removes all + <code><uses-permission></code> and <code><uses-permission-sdk-23></code> + tags. Performs a tag-level merge.</li> + <li><code>manifest_merger = "android"</code>: Use the android manifest merger. Allows + features like placeholder substitution and tools attributes for defining merge + behavior. Follows the semantics from + <a href="http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger"> + the documentation</a> except it has been modified to also remove all + <code><uses-permission></code> and <code><uses-permission-sdk-23></code> + tags. Performs an attribute-level merge.</li> + <li><code>manifest_merger = "auto"</code>: Merger is controlled by the + <a href="../blaze-user-manual.html#flag--android_manifest_merger"> + --android_manifest_merger</a> flag.</li> + </ul> + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("manifest_merger", STRING) + .allowedValues(new AllowedValueSet(AndroidManifestMerger.getAttributeValues())) + .value(AndroidManifestMerger.getRuleAttributeDefault())) + /* <!-- #BLAZE_RULE(android_binary).ATTRIBUTE(manifest_values) --> + A dictionary of values to be overridden in the manifest. Any instance of ${name} in the + manifest will be replaced with the value corresponding to name in this dictionary. + applicationId, versionCode, versionName, minSdkVersion, targetSdkVersion and + maxSdkVersion will also override the corresponding attributes of the manifest and + uses-sdk tags. packageName will be ignored and will be set from either applicationId if + specified or the package in manifest. When manifest_merger is set to legacy, only + applicationId, versionCode and versionName will have any effect. + <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ + .add(attr("manifest_values", STRING_DICT)) /* <!-- #BLAZE_RULE(android_binary).ATTRIBUTE(nocompress_extensions) --> A list of file extension to leave uncompressed in apk. <!-- #END_BLAZE_RULE.ATTRIBUTE --> */ diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java index cdc30bf39f..d8f7cbb724 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java @@ -98,6 +98,16 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment { } /** + * Converter for {@link AndroidManifestMerger} + */ + public static final class AndroidManifestMergerConverter + extends EnumConverter<AndroidManifestMerger> { + public AndroidManifestMergerConverter() { + super(AndroidManifestMerger.class, "android manifest merger"); + } + } + + /** * Value used to avoid multiple configurations from conflicting. * * <p>This is set to {@code ANDROID} in Android configurations and to {@code MAIN} otherwise. This @@ -139,6 +149,30 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment { } } + /** Types of android manifest mergers. */ + public enum AndroidManifestMerger { + LEGACY, + ANDROID; + + public static List<String> getAttributeValues() { + return ImmutableList.of(LEGACY.name().toLowerCase(), ANDROID.name().toLowerCase(), + getRuleAttributeDefault()); + } + + public static String getRuleAttributeDefault() { + return "auto"; + } + + public static AndroidManifestMerger fromString(String value) { + for (AndroidManifestMerger merger : AndroidManifestMerger.values()) { + if (merger.name().equalsIgnoreCase(value)) { + return merger; + } + } + return null; + } + } + /** * Android configuration options. */ @@ -296,6 +330,14 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment { help = "Enables the use of an obfuscation map when generating the main dex jar file") public boolean useProguardPreviousObfuscationMap; + @Option(name = "android_manifest_merger", + defaultValue = "legacy", + category = "semantics", + converter = AndroidManifestMergerConverter.class, + help = "Selects the manifest merger to use for android_binary rules. Flag to help the" + + "transition to the Android manifest merger from the legacy merger.") + public AndroidManifestMerger manifestMerger; + @Override public void addAllLabels(Multimap<String, Label> labelMap) { if (androidCrosstoolTop != null) { @@ -366,6 +408,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment { private final boolean allowAndroidLibraryDepsWithoutSrcs; private final boolean useAndroidResourceShrinking; private final boolean useProguardPreviousObfuscationMap; + private final AndroidManifestMerger manifestMerger; AndroidConfiguration(Options options, Label androidSdk) { this.sdk = androidSdk; @@ -389,6 +432,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment { this.allowAndroidLibraryDepsWithoutSrcs = options.allowAndroidLibraryDepsWithoutSrcs; this.useAndroidResourceShrinking = options.useAndroidResourceShrinking; this.useProguardPreviousObfuscationMap = options.useProguardPreviousObfuscationMap; + this.manifestMerger = options.manifestMerger; } public String getCpu() { @@ -465,6 +509,10 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment { return useProguardPreviousObfuscationMap; } + public AndroidManifestMerger getManifestMerger() { + return manifestMerger; + } + @Override public void addGlobalMakeVariables(ImmutableMap.Builder<String, String> globalMakeEnvBuilder) { globalMakeEnvBuilder.put("ANDROID_CPU", cpu); diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java index 8630825550..964db8ae54 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java @@ -25,7 +25,6 @@ import com.google.devtools.build.lib.analysis.config.CompilationMode; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.packages.BuildType; -import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; import com.google.devtools.build.lib.rules.android.AndroidLibraryAarProvider.Aar; import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer; @@ -78,7 +77,8 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { final ResourceApk resourceApk; if (definesLocalResources) { - ApplicationManifest applicationManifest = androidSemantics.getManifestForRule(ruleContext); + ApplicationManifest applicationManifest = androidSemantics.getManifestForRule(ruleContext) + .renamePackage(ruleContext, AndroidCommon.getJavaPackage(ruleContext)); resourceApk = applicationManifest.packWithDataAndResources( null, /* resourceApk -- not needed for library */ ruleContext, @@ -90,11 +90,8 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { ImmutableList.<String>of(), /* uncompressedExtensions */ false, /* crunchPng */ ImmutableList.<String>of(), /* densities */ - null /* applicationId */, - null /* versionCode */, - null /* versionName */, - false, - null /* proguardCfgOut */, + false, /* incremental */ + null, /* proguardCfgOut */ null, /* mainDexProguardCfg */ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_PROCESSED_MANIFEST), null /* mergedResourcesOut */); @@ -145,7 +142,8 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { } else { // there are no local resources and resources attribute was not specified either aar = null; - ApplicationManifest applicationManifest = ApplicationManifest.generatedManifest(ruleContext); + ApplicationManifest applicationManifest = ApplicationManifest.generatedManifest(ruleContext) + .renamePackage(ruleContext, AndroidCommon.getJavaPackage(ruleContext)); String javaPackage = AndroidCommon.getJavaPackage(ruleContext); @@ -200,7 +198,7 @@ public abstract class AndroidLibrary implements RuleConfiguredTargetFactory { .add(ProguardSpecProvider.class, new ProguardSpecProvider(transitiveProguardConfigs)) .addOutputGroup(OutputGroupProvider.HIDDEN_TOP_LEVEL, transitiveProguardConfigs) .add(AndroidLibraryAarProvider.class, new AndroidLibraryAarProvider( - aar, transitiveAars.build())) + aar, transitiveAars.build())) .build(); } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java index 306a922bce..0f2008b569 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java @@ -165,11 +165,10 @@ public final class AndroidRuleClasses { "//tools/android:incremental_stub_application"; public static final String DEFAULT_INCREMENTAL_SPLIT_STUB_APPLICATION = "//tools/android:incremental_split_stub_application"; - public static final String DEFAULT_RESOURCES_PROCESSOR = - "//tools/android:resources_processor"; - public static final String DEFAULT_RESOURCE_SHRINKER = - "//tools/android:resource_shrinker"; public static final String DEFAULT_AAR_GENERATOR = "//tools/android:aar_generator"; + public static final String DEFAULT_MANIFEST_MERGER = "//tools/android:manifest_merger"; + public static final String DEFAULT_RESOURCES_PROCESSOR = "//tools/android:resources_processor"; + public static final String DEFAULT_RESOURCE_SHRINKER = "//tools/android:resource_shrinker"; public static final String DEFAULT_SDK = "//tools/android:sdk"; /** @@ -398,12 +397,14 @@ public final class AndroidRuleClasses { @Override public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment env) { return builder + .add(attr("$android_aar_generator", LABEL).cfg(HOST).exec().value( + env.getToolsLabel(DEFAULT_AAR_GENERATOR))) + .add(attr("$android_manifest_merger", LABEL).cfg(HOST).exec().value( + env.getToolsLabel(DEFAULT_MANIFEST_MERGER))) .add(attr("$android_resources_processor", LABEL).cfg(HOST).exec().value( env.getToolsLabel(DEFAULT_RESOURCES_PROCESSOR))) .add(attr("$android_resource_shrinker", LABEL).cfg(HOST).exec().value( env.getToolsLabel(DEFAULT_RESOURCE_SHRINKER))) - .add(attr("$android_aar_generator", LABEL).cfg(HOST).exec().value( - env.getToolsLabel(DEFAULT_AAR_GENERATOR))) .build(); } 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 296f4aff14..8992776ec2 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 @@ -13,8 +13,12 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; +import static com.google.common.base.Strings.isNullOrEmpty; +import static com.google.devtools.build.lib.syntax.Type.STRING; + import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; @@ -26,6 +30,7 @@ import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; import com.google.devtools.build.lib.analysis.actions.FileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.config.CompilationMode; +import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidManifestMerger; import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer; import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceType; import com.google.devtools.build.lib.syntax.Type; @@ -33,6 +38,7 @@ import com.google.devtools.build.lib.vfs.PathFragment; import java.util.List; import java.util.Map; +import java.util.TreeMap; import javax.annotation.Nullable; @@ -44,9 +50,8 @@ public final class ApplicationManifest { ruleContext.attributeError("manifest", "a resources or manifest attribute is mandatory."); return null; } - return new ApplicationManifest(Iterables.getOnlyElement( - resources.getDirectAndroidResources()) - .getManifest()); + return new ApplicationManifest( + ruleContext, Iterables.getOnlyElement(resources.getDirectAndroidResources()).getManifest()); } public ApplicationManifest createSplitManifest( @@ -67,7 +72,7 @@ public final class ApplicationManifest { .addArgument(splitName) .addArgument(hasCode ? "--hascode" : "--nohascode"); - String overridePackage = getOverridePackage(ruleContext); + String overridePackage = manifestValues.get("applicationId"); if (overridePackage != null) { builder .addArgument("--override_package") @@ -75,31 +80,7 @@ public final class ApplicationManifest { } ruleContext.registerAction(builder.build(ruleContext)); - return new ApplicationManifest(result); - } - - private String getOverridePackage(RuleContext ruleContext) { - // It seems that we sometimes rename the app for God-knows-what reason. If that is the case, - // pass this information to the stubifier script. - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("manifest_values")) { - Map<String, String> manifestValues = - ruleContext.attributes().get("manifest_values", Type.STRING_DICT); - if (manifestValues.containsKey("applicationId")) { - return manifestValues.get("applicationId"); - } - } - if (ruleContext.attributes().isAttributeValueExplicitlySpecified("application_id")) { - return ruleContext.attributes().get("application_id", Type.STRING); - } - - AndroidResourcesProvider resourcesProvider = AndroidCommon.getAndroidResources(ruleContext); - if (resourcesProvider != null) { - ResourceContainer resourceContainer = Iterables.getOnlyElement( - resourcesProvider.getDirectAndroidResources()); - return resourceContainer.getRenameManifestPackage(); - } else { - return null; - } + return new ApplicationManifest(ruleContext, result); } public ApplicationManifest addMobileInstallStubApplication(RuleContext ruleContext) @@ -121,7 +102,7 @@ public final class ApplicationManifest { .addOutputArgument(ruleContext.getImplicitOutputArtifact( AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_DATA)); - String overridePackage = getOverridePackage(ruleContext); + String overridePackage = manifestValues.get("applicationId"); if (overridePackage != null) { builder.addArgument("--override_package"); builder.addArgument(overridePackage); @@ -129,7 +110,7 @@ public final class ApplicationManifest { ruleContext.registerAction(builder.build(ruleContext)); - return new ApplicationManifest(stubManifest); + return new ApplicationManifest(ruleContext, stubManifest); } public ApplicationManifest addInstantRunStubApplication(RuleContext ruleContext) @@ -150,15 +131,17 @@ public final class ApplicationManifest { ruleContext.registerAction(builder.build(ruleContext)); - return new ApplicationManifest(stubManifest); + return new ApplicationManifest(ruleContext, stubManifest); } - + public static ApplicationManifest fromRule(RuleContext ruleContext) { - return new ApplicationManifest(ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET)); + return new ApplicationManifest( + ruleContext, ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET)); } - public static ApplicationManifest fromExplicitManifest(Artifact manifest) { - return new ApplicationManifest(manifest); + public static ApplicationManifest fromExplicitManifest( + RuleContext ruleContext, Artifact manifest) { + return new ApplicationManifest(ruleContext, manifest); } /** @@ -184,26 +167,78 @@ public final class ApplicationManifest { "</manifest>"); ruleContext.getAnalysisEnvironment().registerAction(new FileWriteAction( ruleContext.getActionOwner(), generatedManifest, contents, false /* makeExecutable */)); - return new ApplicationManifest(generatedManifest); + return new ApplicationManifest(ruleContext, generatedManifest); + } + + private static ImmutableMap<String, String> getManifestValues(RuleContext context) { + Map<String, String> manifestValues = new TreeMap<>(); + // applicationId is set from manifest_values or android_resources.rename_manifest_package + // with descending priority. + AndroidResourcesProvider resourcesProvider = AndroidCommon.getAndroidResources(context); + if (resourcesProvider != null) { + ResourceContainer resourceContainer = Iterables.getOnlyElement( + resourcesProvider.getDirectAndroidResources()); + if (resourceContainer.getRenameManifestPackage() != null) { + manifestValues.put("applicationId", resourceContainer.getRenameManifestPackage()); + } + } + if (context.attributes().isAttributeValueExplicitlySpecified("manifest_values")) { + manifestValues.putAll(context.attributes().get("manifest_values", Type.STRING_DICT)); + } + + for (String variable : manifestValues.keySet()) { + manifestValues.put( + variable, context.expandMakeVariables("manifest_values", manifestValues.get(variable))); + } + return ImmutableMap.copyOf(manifestValues); } private final Artifact manifest; + private final ImmutableMap<String, String> manifestValues; - private ApplicationManifest(Artifact manifest) { + private ApplicationManifest(RuleContext ruleContext, Artifact manifest) { this.manifest = manifest; + this.manifestValues = getManifestValues(ruleContext); } - public ApplicationManifest mergeWith(RuleContext ruleContext, - ResourceDependencies resourceDeps) { + public ApplicationManifest mergeWith(RuleContext ruleContext, ResourceDependencies resourceDeps) { Iterable<Artifact> mergeeManifests = getMergeeManifests(resourceDeps.getResources()); - if (!Iterables.isEmpty(mergeeManifests)) { - Iterable<Artifact> exportedManifests = mergeeManifests; - Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact( - ruleContext.getRule().getName() + "_merged", "AndroidManifest.xml", - ruleContext.getBinOrGenfilesDirectory()); - AndroidManifestMergeHelper.createMergeManifestAction(ruleContext, getManifest(), - exportedManifests, ImmutableList.of("all"), outputManifest); - return new ApplicationManifest(outputManifest); + + boolean legacy = true; + 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(); + } + legacy = merger == AndroidManifestMerger.LEGACY; + } + + if (legacy) { + if (!Iterables.isEmpty(mergeeManifests)) { + Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact( + ruleContext.getRule().getName() + "_merged", "AndroidManifest.xml", + ruleContext.getBinOrGenfilesDirectory()); + AndroidManifestMergeHelper.createMergeManifestAction(ruleContext, getManifest(), + mergeeManifests, ImmutableList.of("all"), outputManifest); + return new ApplicationManifest(ruleContext, outputManifest); + } + } else { + if (!Iterables.isEmpty(mergeeManifests) || !manifestValues.isEmpty()) { + Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact( + ruleContext.getRule().getName() + "_merged", "AndroidManifest.xml", + ruleContext.getBinOrGenfilesDirectory()); + new ManifestMergerActionBuilder(ruleContext) + .setManifest(getManifest()) + .setMergeeManifests(mergeeManifests) + .setLibrary(false) + .setManifestValues(manifestValues) + .setCustomPackage(AndroidCommon.getJavaPackage(ruleContext)) + .setManifestOutput(outputManifest) + .build(ruleContext); + return new ApplicationManifest(ruleContext, outputManifest); + } } return this; } @@ -220,6 +255,22 @@ public final class ApplicationManifest { return builder.build(); } + public ApplicationManifest renamePackage(RuleContext ruleContext, String customPackage) { + if (isNullOrEmpty(customPackage)) { + return this; + } + Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact( + ruleContext.getRule().getName() + "_renamed", "AndroidManifest.xml", + ruleContext.getBinOrGenfilesDirectory()); + new ManifestMergerActionBuilder(ruleContext) + .setManifest(getManifest()) + .setLibrary(true) + .setCustomPackage(customPackage) + .setManifestOutput(outputManifest) + .build(ruleContext); + return new ApplicationManifest(ruleContext, outputManifest); + } + /** Packages up the manifest with assets from the rule and dependent resources. * @throws InterruptedException */ public ResourceApk packWithAssets( @@ -244,14 +295,11 @@ public final class ApplicationManifest { false, /* isLibrary */ resourceDeps, rTxt, - null, /* symbolsTxt */ + null, /* Artifact symbolsTxt */ ImmutableList.<String>of(), /* configurationFilters */ ImmutableList.<String>of(), /* uncompressedExtensions */ true, /* crunchPng */ ImmutableList.<String>of(), /* densities */ - null, /* String applicationId */ - null, /* String versionCode */ - null, /* String versionName */ incremental, data, proguardCfg, @@ -272,9 +320,6 @@ public final class ApplicationManifest { List<String> uncompressedExtensions, boolean crunchPng, List<String> densities, - String applicationId, - String versionCode, - String versionName, boolean incremental, Artifact proguardCfg, @Nullable Artifact mainDexProguardCfg, @@ -307,9 +352,6 @@ public final class ApplicationManifest { uncompressedExtensions, crunchPng, densities, - applicationId, - versionCode, - versionName, incremental, data, proguardCfg, @@ -329,9 +371,6 @@ public final class ApplicationManifest { List<String> uncompressedExtensions, boolean crunchPng, List<String> densities, - String applicationId, - String versionCode, - String versionName, boolean incremental, LocalResourceContainer data, Artifact proguardCfg, @@ -370,9 +409,9 @@ public final class ApplicationManifest { .setDensities(densities) .setProguardOut(proguardCfg) .setMainDexProguardOut(mainDexProguardCfg) - .setApplicationId(applicationId) - .setVersionCode(versionCode) - .setVersionName(versionName); + .setApplicationId(manifestValues.get("applicationId")) + .setVersionCode(manifestValues.get("versionCode")) + .setVersionName(manifestValues.get("versionName")); if (!incremental) { builder diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/LocalResourceContainer.java b/src/main/java/com/google/devtools/build/lib/rules/android/LocalResourceContainer.java index acd5cf1aa3..971ccf7dfb 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/LocalResourceContainer.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/LocalResourceContainer.java @@ -45,10 +45,7 @@ public final class LocalResourceContainer { "assets", "assets_dir", "inline_constants", - "exports_manifest", - "application_id", - "version_name", - "version_code" + "exports_manifest" }; /** diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java new file mode 100644 index 0000000000..21174401a0 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ManifestMergerActionBuilder.java @@ -0,0 +1,138 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.devtools.build.lib.rules.android; + +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Builder for creating manifest merger actions. + */ +public class ManifestMergerActionBuilder { + private final RuleContext ruleContext; + private final SpawnAction.Builder spawnActionBuilder; + + private Artifact manifest; + private List<Artifact> mergeeManifests; + private boolean isLibrary; + private Map<String, String> manifestValues; + private String customPackage; + private Artifact manifestOutput; + + public ManifestMergerActionBuilder(RuleContext ruleContext) { + this.ruleContext = ruleContext; + this.spawnActionBuilder = new SpawnAction.Builder(); + } + + public ManifestMergerActionBuilder setManifest(Artifact manifest) { + this.manifest = manifest; + return this; + } + + public ManifestMergerActionBuilder setMergeeManifests(Iterable<Artifact> mergeeManifests) { + this.mergeeManifests = ImmutableList.copyOf(mergeeManifests); + return this; + } + + public ManifestMergerActionBuilder setLibrary(boolean isLibrary) { + this.isLibrary = isLibrary; + return this; + } + + public ManifestMergerActionBuilder setManifestValues(Map<String, String> manifestValues) { + this.manifestValues = manifestValues; + return this; + } + + public ManifestMergerActionBuilder setCustomPackage(String customPackage) { + this.customPackage = customPackage; + return this; + } + + public ManifestMergerActionBuilder setManifestOutput(Artifact manifestOutput) { + this.manifestOutput = manifestOutput; + return this; + } + + public void build(ActionConstructionContext context) { + NestedSetBuilder<Artifact> inputs = NestedSetBuilder.naiveLinkOrder(); + ImmutableList.Builder<Artifact> outputs = ImmutableList.builder(); + CustomCommandLine.Builder builder = new CustomCommandLine.Builder(); + + inputs.addAll(ruleContext.getExecutablePrerequisite("$android_manifest_merger", Mode.HOST) + .getRunfilesSupport() + .getRunfilesArtifactsWithoutMiddlemen()); + + builder.addExecPath("--manifest", manifest); + inputs.add(manifest); + + if (mergeeManifests != null && !mergeeManifests.isEmpty()) { + builder.addJoinExecPaths("--mergeeManifests", ":", mergeeManifests); + inputs.addAll(mergeeManifests); + } + + if (isLibrary) { + builder.add("--mergeType").add("LIBRARY"); + } + + if (manifestValues != null && !manifestValues.isEmpty()) { + builder.add("--manifestValues").add(mapToDictionaryString(manifestValues)); + } + + if (customPackage != null && !customPackage.isEmpty()) { + builder.add("--customPackage").add(customPackage); + } + + builder.addExecPath("--manifestOutput", manifestOutput); + outputs.add(manifestOutput); + + ruleContext.registerAction( + this.spawnActionBuilder + .addTransitiveInputs(inputs.build()) + .addOutputs(outputs.build()) + .setCommandLine(builder.build()) + .setExecutable( + ruleContext.getExecutablePrerequisite("$android_manifest_merger", Mode.HOST)) + .setProgressMessage("Merging manifest") + .setMnemonic("ManifestMerger") + .build(context)); + } + + private <K, V> String mapToDictionaryString(Map<K, V> map) { + StringBuilder sb = new StringBuilder(); + Iterator<Entry<K, V>> iter = map.entrySet().iterator(); + while (iter.hasNext()) { + Entry<K, V> entry = iter.next(); + sb.append(entry.getKey().toString().replace(":", "\\:").replace(",", "\\,")); + sb.append(':'); + sb.append(entry.getValue().toString().replace(":", "\\:").replace(",", "\\,")); + if (iter.hasNext()) { + sb.append(','); + } + } + return sb.toString(); + } +} + |