aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar asteinb <asteinb@google.com>2018-08-08 11:01:16 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-08-08 11:03:17 -0700
commit8264972b4aa708710653e02da842902040ffabf7 (patch)
tree26e7b7890fefa430b19937e748a9e84a3ea57571
parentf2a07a7336445b9b427c144c95663c2f2649a307 (diff)
Remove ApplicationManifest
This class just contains methods used elsewhere; move them to appropriate places (generally AndroidManifest or StampedAndroidManifest). Also, somewhat reduce code duplication by having more stuff use the existing AndroidManifest.from() method, which automatically handles unspecified manifests and packages. RELNOTES: none PiperOrigin-RevId: 207913410
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java11
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinaryMobileInstall.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifest.java159
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSkylarkData.java28
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java272
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java119
9 files changed, 257 insertions, 350 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 3c723466f0..5d95ce9a50 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
@@ -17,6 +17,7 @@ package com.google.devtools.build.lib.rules.android;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.devtools.build.lib.syntax.Type.STRING;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import com.google.auto.value.AutoValue;
@@ -183,15 +184,19 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
AndroidResources.validateRuleContext(ruleContext);
final AndroidDataContext dataContext = androidSemantics.makeContextForNative(ruleContext);
+ Map<String, String> manifestValues = StampedAndroidManifest.getManifestValues(ruleContext);
StampedAndroidManifest manifest =
AndroidManifest.fromAttributes(ruleContext, dataContext, androidSemantics)
.mergeWithDeps(
dataContext,
androidSemantics,
+ ruleContext,
resourceDeps,
- ApplicationManifest.getManifestValues(ruleContext),
- ApplicationManifest.useLegacyMerging(ruleContext));
+ manifestValues,
+ ruleContext.getRule().isAttrDefined("manifest_merger", STRING)
+ ? ruleContext.attributes().get("manifest_merger", STRING)
+ : null);
AndroidAaptVersion aaptVersion = AndroidAaptVersion.chooseTargetAaptVersion(ruleContext);
final ResourceApk resourceApk =
@@ -201,7 +206,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
manifest,
/* conditionalKeepRules = */ shouldShrinkResourceCycles(
dataContext.getAndroidConfig(), ruleContext, shrinkResources),
- ApplicationManifest.getManifestValues(ruleContext),
+ manifestValues,
aaptVersion,
AndroidResources.from(ruleContext, "resource_files"),
AndroidAssets.from(ruleContext),
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 29529bbfc0..0669f0bad3 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
@@ -62,7 +62,7 @@ public final class AndroidBinaryMobileInstall {
final ResourceApk incrementalResourceApk;
final ResourceApk splitResourceApk;
- Map<String, String> manifestValues = ApplicationManifest.getManifestValues(ruleContext);
+ Map<String, String> manifestValues = StampedAndroidManifest.getManifestValues(ruleContext);
incrementalResourceApk =
ProcessedAndroidData.processIncrementalBinaryDataFrom(
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 98ec4dafde..f7657ed8b2 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
@@ -221,7 +221,7 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment
}
}
- // TODO(corysmith): Move to ApplicationManifest when no longer needed as a public function.
+ // TODO(corysmith): Move to an appropriate place when no longer needed as a public function.
@Nullable
public static AndroidAaptVersion chooseTargetAaptVersion(RuleContext ruleContext)
throws RuleErrorException {
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 b484479169..8ee5a16afc 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.NestedSet;
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.packages.RuleErrorConsumer;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
import com.google.devtools.build.lib.rules.android.DataBinding.DataBindingContext;
import com.google.devtools.build.lib.rules.java.ClasspathConfiguredFragment;
@@ -97,13 +98,14 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
buildResourceApk(
dataContext,
androidSemantics,
+ ruleContext,
DataBinding.contextFrom(ruleContext, dataContext.getAndroidConfig()),
AndroidManifest.fromAttributes(ruleContext, dataContext),
AndroidResources.from(ruleContext, "resource_files"),
AndroidAssets.from(ruleContext),
ResourceDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
AssetDependencies.fromRuleDeps(ruleContext, /* neverlink = */ false),
- ApplicationManifest.getManifestValues(ruleContext),
+ StampedAndroidManifest.getManifestValues(ruleContext),
AndroidAaptVersion.chooseTargetAaptVersion(ruleContext));
attributesBuilder.addRuntimeClassPathEntry(resourceApk.getResourceJavaClassJar());
@@ -492,6 +494,7 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
static ResourceApk buildResourceApk(
AndroidDataContext dataContext,
AndroidSemantics androidSemantics,
+ RuleErrorConsumer errorConsumer,
DataBindingContext dataBindingContext,
AndroidManifest manifest,
AndroidResources resources,
@@ -506,9 +509,10 @@ public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactor
manifest.mergeWithDeps(
dataContext,
androidSemantics,
+ errorConsumer,
resourceDeps,
manifestValues,
- /* useLegacyMerger = */ false);
+ /* manifestMerger = */ null);
return ProcessedAndroidData.processLocalTestDataFrom(
dataContext,
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 160ccb3980..6a552b8c7b 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,13 +13,19 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.android;
+import static com.google.common.base.Strings.isNullOrEmpty;
+
+import com.google.common.collect.ImmutableSortedMap;
import com.google.devtools.build.lib.actions.Artifact;
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.SymlinkAction;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
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.AndroidManifestMerger;
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;
@@ -74,7 +80,7 @@ public class AndroidManifest {
Artifact rawManifest = null;
if (AndroidResources.definesAndroidResources(ruleContext.attributes())) {
AndroidResources.validateRuleContext(ruleContext);
- rawManifest = ApplicationManifest.getManifestFromAttributes(ruleContext);
+ rawManifest = ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET);
}
return from(
@@ -110,9 +116,16 @@ public class AndroidManifest {
/**
* Inner method to create an AndroidManifest.
*
- * <p>AndroidSemantics-specific processing will be used if a non-null AndroidSemantics is passed.
+ * @param rawManifest If non-null, the returned object will wrap this manifest. Otherwise, the
+ * returned object will wrap a generated dummy manifest.
+ * @param androidSemantics If non-null, will invoke
+ * AndroidSemantics#renameManifest(AndroidDataContext, AndroidManifest)} to do
+ * platform-specific processing on the manifest.
+ * @param pkg If non-null, this Android package will be used for the manifest, and the manifest
+ * will be stamped with it when the {@link #stamp(AndroidDataContext)} method is called.
+ * Otherwise, the default package, based on the current target's Bazel package, will be used.
*/
- static AndroidManifest from(
+ public static AndroidManifest from(
AndroidDataContext dataContext,
RuleErrorConsumer errorConsumer,
@Nullable Artifact rawManifest,
@@ -129,21 +142,40 @@ public class AndroidManifest {
if (rawManifest == null) {
// Generate a dummy manifest
return StampedAndroidManifest.createEmpty(
- dataContext.getActionConstructionContext(), pkg, /* exported = */ false);
+ dataContext.getActionConstructionContext(), pkg, exportsManifest);
}
- Artifact renamedManifest;
+ AndroidManifest raw = new AndroidManifest(rawManifest, pkg, exportsManifest);
+
if (androidSemantics != null) {
- renamedManifest = androidSemantics.renameManifest(dataContext, rawManifest);
- } else {
- renamedManifest = ApplicationManifest.renameManifestIfNeeded(dataContext, rawManifest);
+ return androidSemantics.renameManifest(dataContext, raw);
}
+ return raw.renameManifestIfNeeded(dataContext);
+ }
- return new AndroidManifest(renamedManifest, pkg, exportsManifest);
+ AndroidManifest renameManifestIfNeeded(AndroidDataContext dataContext)
+ throws InterruptedException {
+ if (manifest.getFilename().equals("AndroidManifest.xml")) {
+ return this;
+ } else {
+ /*
+ * If the manifest file is not named AndroidManifest.xml, we create a symlink named
+ * AndroidManifest.xml to it. aapt requires the manifest to be named as such.
+ */
+ Artifact manifestSymlink =
+ dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_SYMLINKED_MANIFEST);
+ dataContext.registerAction(
+ new SymlinkAction(
+ dataContext.getActionConstructionContext().getActionOwner(),
+ manifest,
+ manifestSymlink,
+ "Renaming Android manifest for " + dataContext.getLabel()));
+ return updateManifest(manifestSymlink);
+ }
}
- AndroidManifest(AndroidManifest other, Artifact manifest) {
- this(manifest, other.pkg, other.exported);
+ public AndroidManifest updateManifest(Artifact manifest) {
+ return new AndroidManifest(manifest, pkg, exported);
}
/**
@@ -158,25 +190,18 @@ public class AndroidManifest {
/** If needed, stamps the manifest with the correct Java package */
public StampedAndroidManifest stamp(AndroidDataContext dataContext) {
- return new StampedAndroidManifest(
- ApplicationManifest.maybeSetManifestPackage(dataContext, manifest, pkg).orElse(manifest),
- pkg,
- exported);
- }
+ Artifact outputManifest = getManifest();
+ if (!isNullOrEmpty(pkg)) {
+ outputManifest = dataContext.getUniqueDirectoryArtifact("_renamed", "AndroidManifest.xml");
+ new ManifestMergerActionBuilder()
+ .setManifest(manifest)
+ .setLibrary(true)
+ .setCustomPackage(pkg)
+ .setManifestOutput(outputManifest)
+ .build(dataContext);
+ }
- /**
- * Stamps the manifest with values from the "manifest_values" attributes.
- *
- * <p>If no manifest values are specified, the manifest will remain unstamped.
- */
- public StampedAndroidManifest stampWithManifestValues(
- RuleContext ruleContext, AndroidDataContext dataContext, AndroidSemantics androidSemantics) {
- return mergeWithDeps(
- dataContext,
- androidSemantics,
- ResourceDependencies.empty(),
- ApplicationManifest.getManifestValues(ruleContext),
- ApplicationManifest.useLegacyMerging(ruleContext));
+ return new StampedAndroidManifest(outputManifest, pkg, exported);
}
/**
@@ -186,27 +211,79 @@ public class AndroidManifest {
*
* <p>If there is no merging to be done and no manifest values are specified, the manifest will
* remain unstamped.
+ *
+ * @param manifestMerger if not null, a string dictating which manifest merger to use
*/
public StampedAndroidManifest mergeWithDeps(
AndroidDataContext dataContext,
AndroidSemantics androidSemantics,
+ RuleErrorConsumer errorConsumer,
ResourceDependencies resourceDeps,
Map<String, String> manifestValues,
- boolean useLegacyMerger) {
- Artifact newManifest =
- ApplicationManifest.maybeMergeWith(
- dataContext,
- androidSemantics,
- manifest,
- resourceDeps,
- manifestValues,
- useLegacyMerger,
- pkg)
- .orElse(manifest);
+ @Nullable String manifestMerger) {
+ Map<Artifact, Label> mergeeManifests = getMergeeManifests(resourceDeps.getResourceContainers());
+
+ Artifact newManifest;
+ if (useLegacyMerging(errorConsumer, dataContext.getAndroidConfig(), manifestMerger)) {
+ newManifest =
+ androidSemantics
+ .maybeDoLegacyManifestMerging(mergeeManifests, dataContext, manifest)
+ .orElse(manifest);
+
+ } else if (!mergeeManifests.isEmpty() || !manifestValues.isEmpty()) {
+ newManifest = dataContext.getUniqueDirectoryArtifact("_merged", "AndroidManifest.xml");
+
+ new ManifestMergerActionBuilder()
+ .setManifest(manifest)
+ .setMergeeManifests(mergeeManifests)
+ .setLibrary(false)
+ .setManifestValues(manifestValues)
+ .setCustomPackage(pkg)
+ .setManifestOutput(newManifest)
+ .setLogOut(dataContext.getUniqueDirectoryArtifact("_merged", "manifest_merger_log.txt"))
+ .build(dataContext);
+
+ } else {
+ newManifest = manifest;
+ }
return new StampedAndroidManifest(newManifest, pkg, exported);
}
+ /**
+ * Checks if the legacy manifest merger should be used, based on an optional string specifying the
+ * merger to use.
+ */
+ private static boolean useLegacyMerging(
+ RuleErrorConsumer errorConsumer,
+ AndroidConfiguration androidConfig,
+ @Nullable String mergerString) {
+ AndroidManifestMerger merger = AndroidManifestMerger.fromString(mergerString);
+ if (merger == null) {
+ merger = androidConfig.getManifestMerger();
+ }
+ if (merger == AndroidManifestMerger.LEGACY) {
+ errorConsumer.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(
+ Iterable<ValidatedAndroidResources> transitiveData) {
+ ImmutableSortedMap.Builder<Artifact, Label> builder =
+ ImmutableSortedMap.orderedBy(Artifact.EXEC_PATH_COMPARATOR);
+ for (ValidatedAndroidResources d : transitiveData) {
+ if (d.isManifestExported()) {
+ builder.put(d.getManifest(), d.getLabel());
+ }
+ }
+ return builder.build();
+ }
+
public Artifact getManifest() {
return manifest;
}
@@ -283,7 +360,7 @@ public class AndroidManifest {
@Override
public boolean equals(Object object) {
- if (object == null || getClass() != object.getClass()) {
+ if (!(object instanceof AndroidManifest)) {
return false;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
index 9e06e3750f..b7d2b7d4fb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSemantics.java
@@ -36,9 +36,9 @@ import java.util.Optional;
*/
public interface AndroidSemantics {
- default Artifact renameManifest(AndroidDataContext dataContext, Artifact rawManifest)
- throws InterruptedException {
- return ApplicationManifest.renameManifestIfNeeded(dataContext, rawManifest);
+ default AndroidManifest renameManifest(
+ AndroidDataContext dataContext, AndroidManifest rawManifest) throws InterruptedException {
+ return rawManifest.renameManifestIfNeeded(dataContext);
}
default Optional<Artifact> maybeDoLegacyManifestMerging(
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 e23d77156e..023b95b89c 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
@@ -109,23 +109,16 @@ public abstract class AndroidSkylarkData
String pkg = fromNoneable(customPackage, String.class);
try (SkylarkErrorReporter errorReporter =
SkylarkErrorReporter.from(ctx.getActionConstructionContext(), location, env)) {
- if (pkg == null) {
- pkg =
- AndroidManifest.getDefaultPackage(
- env.getCallerLabel(), ctx.getActionConstructionContext(), errorReporter);
- }
- }
-
- Artifact primaryManifest = fromNoneable(manifest, Artifact.class);
- if (primaryManifest == null) {
- return StampedAndroidManifest.createEmpty(ctx.getActionConstructionContext(), pkg, exported)
+ return AndroidManifest.from(
+ ctx,
+ errorReporter,
+ fromNoneable(manifest, Artifact.class),
+ getAndroidSemantics(),
+ pkg,
+ exported)
+ .stamp(ctx)
.toProvider();
}
-
- // If needed, rename the manifest to "AndroidManifest.xml", which aapt expects.
- Artifact renamedManifest = getAndroidSemantics().renameManifest(ctx, primaryManifest);
-
- return new AndroidManifest(renamedManifest, pkg, exported).stamp(ctx).toProvider();
}
@Override
@@ -419,6 +412,7 @@ public abstract class AndroidSkylarkData
AndroidLocalTestBase.buildResourceApk(
ctx,
getAndroidSemantics(),
+ errorReporter,
DataBinding.asDisabledDataBindingContext(),
rawManifest,
AndroidResources.from(errorReporter, getFileProviders(resources), "resource_files"),
@@ -548,10 +542,10 @@ public abstract class AndroidSkylarkData
rawManifest.mergeWithDeps(
ctx,
getAndroidSemantics(),
+ errorReporter,
resourceDeps,
manifestValues,
- ApplicationManifest.useLegacyMerging(
- errorReporter, ctx.getAndroidConfig(), manifestMerger));
+ manifestMerger);
ResourceApk resourceApk =
ProcessedAndroidData.processBinaryDataFrom(
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
deleted file mode 100644
index 3b4f239a1a..0000000000
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ApplicationManifest.java
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2015 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 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.ImmutableMap;
-import com.google.common.collect.ImmutableSortedMap;
-import com.google.devtools.build.lib.actions.Artifact;
-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.FileWriteAction;
-import com.google.devtools.build.lib.analysis.actions.SpawnAction;
-import com.google.devtools.build.lib.analysis.actions.SymlinkAction;
-import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.packages.RuleErrorConsumer;
-import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidManifestMerger;
-import com.google.devtools.build.lib.syntax.Type;
-import java.util.Map;
-import java.util.Optional;
-import java.util.TreeMap;
-import javax.annotation.Nullable;
-
-/** Represents a AndroidManifest, that may have been merged from dependencies. */
-public final class ApplicationManifest {
-
- static Artifact createSplitManifest(
- RuleContext ruleContext, Artifact manifest, String splitName, boolean hasCode) {
- // aapt insists that manifests be called AndroidManifest.xml, even though they have to be
- // explicitly designated as manifests on the command line
- Artifact result =
- AndroidBinary.getDxArtifact(ruleContext, "split_" + splitName + "/AndroidManifest.xml");
- SpawnAction.Builder builder =
- new SpawnAction.Builder()
- .setExecutable(
- ruleContext.getExecutablePrerequisite("$build_split_manifest", Mode.HOST))
- .setProgressMessage("Creating manifest for split %s", splitName)
- .setMnemonic("AndroidBuildSplitManifest")
- .addInput(manifest)
- .addOutput(result);
- CustomCommandLine.Builder commandLine =
- CustomCommandLine.builder()
- .addExecPath("--main_manifest", manifest)
- .addExecPath("--split_manifest", result)
- .add("--split", splitName);
- if (hasCode) {
- commandLine.add("--hascode");
- } else {
- commandLine.add("--nohascode");
- }
-
- String overridePackage = getManifestValues(ruleContext).get("applicationId");
- if (overridePackage != null) {
- commandLine.add("--override_package", overridePackage);
- }
-
- builder.addCommandLine(commandLine.build());
- ruleContext.registerAction(builder.build(ruleContext));
- return result;
- }
-
- static Artifact addMobileInstallStubApplication(RuleContext ruleContext, Artifact manifest)
- throws InterruptedException {
-
- Artifact stubManifest =
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_MANIFEST);
- Artifact stubData =
- ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_DATA);
-
- SpawnAction.Builder builder =
- new SpawnAction.Builder()
- .setExecutable(ruleContext.getExecutablePrerequisite("$stubify_manifest", Mode.HOST))
- .setProgressMessage("Injecting mobile install stub application")
- .setMnemonic("InjectMobileInstallStubApplication")
- .addInput(manifest)
- .addOutput(stubManifest)
- .addOutput(stubData);
- CustomCommandLine.Builder commandLine =
- CustomCommandLine.builder()
- .add("--mode=mobile_install")
- .addExecPath("--input_manifest", manifest)
- .addExecPath("--output_manifest", stubManifest)
- .addExecPath("--output_datafile", stubData);
-
- String overridePackage = getManifestValues(ruleContext).get("applicationId");
- if (overridePackage != null) {
- commandLine.add("--override_package", overridePackage);
- }
-
- builder.addCommandLine(commandLine.build());
- ruleContext.registerAction(builder.build(ruleContext));
-
- return stubManifest;
- }
-
- public static Artifact getManifestFromAttributes(RuleContext ruleContext) {
- return ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET);
- }
-
- static Artifact renameManifestIfNeeded(AndroidDataContext dataContext, Artifact manifest)
- throws InterruptedException {
- if (manifest.getFilename().equals("AndroidManifest.xml")) {
- return manifest;
- } else {
- /*
- * If the manifest file is not named AndroidManifest.xml, we create a symlink named
- * AndroidManifest.xml to it. aapt requires the manifest to be named as such.
- */
- Artifact manifestSymlink =
- dataContext.createOutputArtifact(AndroidRuleClasses.ANDROID_SYMLINKED_MANIFEST);
- dataContext.registerAction(
- new SymlinkAction(
- dataContext.getActionConstructionContext().getActionOwner(),
- manifest,
- manifestSymlink,
- "Renaming Android manifest for " + dataContext.getLabel()));
- return manifestSymlink;
- }
- }
-
- /**
- * Creates an action to generate an empty manifest file with a specific package name.
- *
- * @return an artifact for the generated manifest
- */
- public static Artifact generateManifest(
- ActionConstructionContext context, String manifestPackage) {
- Artifact generatedManifest =
- context.getUniqueDirectoryArtifact("_generated", "AndroidManifest.xml");
-
- String contents =
- Joiner.on("\n")
- .join(
- "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
- "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"",
- " package=\"" + manifestPackage + "\">",
- " <application>",
- " </application>",
- "</manifest>");
- context.registerAction(
- FileWriteAction.create(context, generatedManifest, contents, /*makeExecutable=*/ false));
- return generatedManifest;
- }
-
- /** Gets a map of manifest values from this rule's 'manifest_values' attribute */
- public static ImmutableMap<String, String> getManifestValues(RuleContext context) {
- Map<String, String> manifestValues = new TreeMap<>();
- 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.getExpander().expand("manifest_values", manifestValues.get(variable)));
- }
- return ImmutableMap.copyOf(manifestValues);
- }
-
- private ApplicationManifest() {}
-
- static Optional<Artifact> maybeMergeWith(
- AndroidDataContext dataContext,
- AndroidSemantics androidSemantics,
- Artifact primaryManifest,
- ResourceDependencies resourceDeps,
- Map<String, String> manifestValues,
- boolean useLegacyMerging,
- String customPackage) {
- Map<Artifact, Label> mergeeManifests = getMergeeManifests(resourceDeps.getResourceContainers());
-
- if (useLegacyMerging) {
- return androidSemantics.maybeDoLegacyManifestMerging(
- mergeeManifests, dataContext, primaryManifest);
- } else {
- if (!mergeeManifests.isEmpty() || !manifestValues.isEmpty()) {
- Artifact outputManifest =
- dataContext.getUniqueDirectoryArtifact("_merged", "AndroidManifest.xml");
- Artifact mergeLog =
- dataContext.getUniqueDirectoryArtifact("_merged", "manifest_merger_log.txt");
- new ManifestMergerActionBuilder()
- .setManifest(primaryManifest)
- .setMergeeManifests(mergeeManifests)
- .setLibrary(false)
- .setManifestValues(manifestValues)
- .setCustomPackage(customPackage)
- .setManifestOutput(outputManifest)
- .setLogOut(mergeLog)
- .build(dataContext);
- return Optional.of(outputManifest);
- }
- }
- return Optional.empty();
- }
-
- /** Checks if the legacy manifest merger should be used, based on a rule attribute */
- public static boolean useLegacyMerging(RuleContext ruleContext) {
- return ruleContext.isLegalFragment(AndroidConfiguration.class)
- && ruleContext.getRule().isAttrDefined("manifest_merger", STRING)
- && useLegacyMerging(
- ruleContext,
- AndroidCommon.getAndroidConfig(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(
- RuleErrorConsumer errorConsumer,
- AndroidConfiguration androidConfig,
- @Nullable String mergerString) {
- AndroidManifestMerger merger = AndroidManifestMerger.fromString(mergerString);
- if (merger == null) {
- merger = androidConfig.getManifestMerger();
- }
- if (merger == AndroidManifestMerger.LEGACY) {
- errorConsumer.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(
- Iterable<ValidatedAndroidResources> transitiveData) {
- ImmutableSortedMap.Builder<Artifact, Label> builder =
- ImmutableSortedMap.orderedBy(Artifact.EXEC_PATH_COMPARATOR);
- for (ValidatedAndroidResources d : transitiveData) {
- if (d.isManifestExported()) {
- builder.put(d.getManifest(), d.getLabel());
- }
- }
- return builder.build();
- }
-
- static Optional<Artifact> maybeSetManifestPackage(
- AndroidDataContext dataContext, Artifact manifest, String customPackage) {
- if (isNullOrEmpty(customPackage)) {
- return Optional.empty();
- }
- Artifact outputManifest =
- dataContext.getUniqueDirectoryArtifact("_renamed", "AndroidManifest.xml");
- new ManifestMergerActionBuilder()
- .setManifest(manifest)
- .setLibrary(true)
- .setCustomPackage(customPackage)
- .setManifestOutput(outputManifest)
- .build(dataContext);
-
- return Optional.of(outputManifest);
- }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java b/src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java
index a0ef0dd9d7..5cb4dd1df0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/StampedAndroidManifest.java
@@ -13,10 +13,19 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.android;
+import com.google.common.base.Joiner;
+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.actions.ActionConstructionContext;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+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.configuredtargets.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.syntax.Type;
+import java.util.Map;
+import java.util.TreeMap;
import javax.annotation.Nullable;
/** An {@link AndroidManifest} stamped with the correct package. */
@@ -55,27 +64,117 @@ public class StampedAndroidManifest extends AndroidManifest {
/** Creates an empty manifest stamped with a specified package. */
public static StampedAndroidManifest createEmpty(
ActionConstructionContext context, String pkg, boolean exported) {
- return new StampedAndroidManifest(
- ApplicationManifest.generateManifest(context, pkg), pkg, exported);
+ Artifact generatedManifest =
+ context.getUniqueDirectoryArtifact("_generated", "AndroidManifest.xml");
+
+ String contents =
+ Joiner.on("\n")
+ .join(
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>",
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"",
+ " package=\"" + pkg + "\">",
+ " <application>",
+ " </application>",
+ "</manifest>");
+ context.registerAction(
+ FileWriteAction.create(context, generatedManifest, contents, /*makeExecutable=*/ false));
+ return new StampedAndroidManifest(generatedManifest, pkg, exported);
}
public StampedAndroidManifest addMobileInstallStubApplication(RuleContext ruleContext)
throws InterruptedException {
- return new StampedAndroidManifest(
- ApplicationManifest.addMobileInstallStubApplication(ruleContext, getManifest()),
- getPackage(),
- isExported());
+
+ Artifact stubManifest =
+ ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_MANIFEST);
+ Artifact stubData =
+ ruleContext.getImplicitOutputArtifact(
+ AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_DATA);
+
+ SpawnAction.Builder builder =
+ new SpawnAction.Builder()
+ .setExecutable(ruleContext.getExecutablePrerequisite("$stubify_manifest", Mode.HOST))
+ .setProgressMessage("Injecting mobile install stub application")
+ .setMnemonic("InjectMobileInstallStubApplication")
+ .addInput(getManifest())
+ .addOutput(stubManifest)
+ .addOutput(stubData);
+ CustomCommandLine.Builder commandLine =
+ CustomCommandLine.builder()
+ .add("--mode=mobile_install")
+ .addExecPath("--input_manifest", getManifest())
+ .addExecPath("--output_manifest", stubManifest)
+ .addExecPath("--output_datafile", stubData);
+
+ String overridePackage = getManifestValues(ruleContext).get("applicationId");
+ if (overridePackage != null) {
+ commandLine.add("--override_package", overridePackage);
+ }
+
+ builder.addCommandLine(commandLine.build());
+ ruleContext.registerAction(builder.build(ruleContext));
+
+ return new StampedAndroidManifest(stubManifest, getPackage(), isExported());
+ }
+
+ public static Map<String, String> getManifestValues(RuleContext context) {
+ if (!context.attributes().isAttributeValueExplicitlySpecified("manifest_values")) {
+ return ImmutableMap.of();
+ }
+
+ Map<String, String> manifestValues =
+ new TreeMap<>(context.attributes().get("manifest_values", Type.STRING_DICT));
+
+ for (String variable : manifestValues.keySet()) {
+ manifestValues.put(
+ variable, context.getExpander().expand("manifest_values", manifestValues.get(variable)));
+ }
+ return ImmutableMap.copyOf(manifestValues);
}
public StampedAndroidManifest createSplitManifest(
RuleContext ruleContext, String splitName, boolean hasCode) {
- return new StampedAndroidManifest(
- ApplicationManifest.createSplitManifest(ruleContext, getManifest(), splitName, hasCode),
- getPackage(),
- isExported());
+ // aapt insists that manifests be called AndroidManifest.xml, even though they have to be
+ // explicitly designated as manifests on the command line
+ Artifact splitManifest =
+ AndroidBinary.getDxArtifact(ruleContext, "split_" + splitName + "/AndroidManifest.xml");
+ SpawnAction.Builder builder =
+ new SpawnAction.Builder()
+ .setExecutable(
+ ruleContext.getExecutablePrerequisite("$build_split_manifest", Mode.HOST))
+ .setProgressMessage("Creating manifest for split %s", splitName)
+ .setMnemonic("AndroidBuildSplitManifest")
+ .addInput(getManifest())
+ .addOutput(splitManifest);
+ CustomCommandLine.Builder commandLine =
+ CustomCommandLine.builder()
+ .addExecPath("--main_manifest", getManifest())
+ .addExecPath("--split_manifest", splitManifest)
+ .add("--split", splitName);
+ if (hasCode) {
+ commandLine.add("--hascode");
+ } else {
+ commandLine.add("--nohascode");
+ }
+
+ String overridePackage = getManifestValues(ruleContext).get("applicationId");
+
+ if (overridePackage != null) {
+ commandLine.add("--override_package", overridePackage);
+ }
+
+ builder.addCommandLine(commandLine.build());
+ ruleContext.registerAction(builder.build(ruleContext));
+
+ return new StampedAndroidManifest(splitManifest, getPackage(), isExported());
}
public AndroidManifestInfo toProvider() {
return AndroidManifestInfo.of(getManifest(), getPackage(), isExported());
}
+
+ @Override
+ public boolean equals(Object object) {
+ return (object instanceof StampedAndroidManifest && super.equals(object));
+ }
}