diff options
Diffstat (limited to 'src/main/java/com/google')
6 files changed, 233 insertions, 5 deletions
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 5cbb11ad57..12dae484b6 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 @@ -116,7 +116,7 @@ public class AndroidManifest { } /** Gets the default Java package */ - private static String getDefaultPackage(RuleContext ruleContext) { + 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/AndroidManifestInfo.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifestInfo.java new file mode 100644 index 0000000000..1e44f46ab4 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidManifestInfo.java @@ -0,0 +1,101 @@ +// Copyright 2018 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.events.Location; +import com.google.devtools.build.lib.packages.NativeInfo; +import com.google.devtools.build.lib.packages.NativeProvider; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; +import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; +import com.google.devtools.build.lib.skylarkinterface.SkylarkModuleCategory; +import com.google.devtools.build.lib.syntax.Environment; +import com.google.devtools.build.lib.syntax.FunctionSignature; +import com.google.devtools.build.lib.syntax.SkylarkType; + +/** A provider of information about this target's manifest. */ +@SkylarkModule( + name = "AndroidManifestInfo", + doc = + "Information about the Android manifest provided by a rule. Note that, as of now, the" + + " information exposed in this object is not directly consumed by Android rules -" + + " instead, use an AndroidResourcesInfo.", + category = SkylarkModuleCategory.PROVIDER) +public class AndroidManifestInfo extends NativeInfo { + private static final String SKYLARK_NAME = "AndroidManifestInfo"; + + private static final FunctionSignature.WithValues<Object, SkylarkType> SIGNATURE = + FunctionSignature.WithValues.create( + FunctionSignature.of( + /* numMandatoryPositionals = */ 2, // Manifest file and package + /* numOptionalPositionals = */ 1, // exports_manifest + /* numMandatoryNamedOnly = */ 0, + /* starArg = */ false, + /* kwArg = */ false, + /* names = */ "manifest", + "package", + "exports_manifest"), + /* defaultValues = */ ImmutableList.of(false), // is_dummy + /* types = */ ImmutableList.of( + SkylarkType.of(Artifact.class), // manifest + SkylarkType.STRING, // package + SkylarkType.BOOL)); // exports_manifest + + public static final NativeProvider<AndroidManifestInfo> PROVIDER = + new NativeProvider<AndroidManifestInfo>(AndroidManifestInfo.class, SKYLARK_NAME, SIGNATURE) { + @Override + public AndroidManifestInfo createInstanceFromSkylark( + Object[] args, Environment env, Location loc) { + // Skylark support code puts positional inputs in the correct order and validates types. + return of((Artifact) args[0], (String) args[1], (boolean) args[2]); + } + }; + + private final Artifact manifest; + private final String pkg; + private final boolean exportsManifest; + + static AndroidManifestInfo of(Artifact manifest, String pkg, boolean exportsManifest) { + return new AndroidManifestInfo(manifest, pkg, exportsManifest); + } + + private AndroidManifestInfo(Artifact manifest, String pkg, boolean exportsManifest) { + super(PROVIDER); + this.manifest = manifest; + this.pkg = pkg; + this.exportsManifest = exportsManifest; + } + + @SkylarkCallable( + name = "manifest", + doc = "This target's manifest, merged with manifests from dependencies", + structField = true) + public Artifact getManifest() { + return manifest; + } + + @SkylarkCallable(name = "package", doc = "This target's package", structField = true) + public String getPackage() { + return pkg; + } + + @SkylarkCallable( + name = "exports_manifest", + doc = "If this manifest should be exported to targets that depend on it", + structField = true) + public boolean exportsManifest() { + return exportsManifest; + } +} 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 ffcb299a6a..a6b8466a73 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 @@ -13,13 +13,101 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext; +import com.google.devtools.build.lib.skylarkinterface.Param; +import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable; import com.google.devtools.build.lib.skylarkinterface.SkylarkModule; +import com.google.devtools.build.lib.syntax.Runtime; +import javax.annotation.Nullable; /** Skylark-visible methods for working with Android data (manifests, resources, and assets). */ @SkylarkModule( - name = "android_data", - doc = "Utilities for working with Android data (manifests, resources, and assets)" -) + name = "android_data", + doc = + "Utilities for working with Android data (manifests, resources, and assets). " + + "This API is non-final and subject to change without warning; do not rely on it.") public class AndroidSkylarkData { + /** + * Skylark API for stamping an Android manifest + * + * <p>TODO(b/79159379): Stop passing SkylarkRuleContext here + * + * @param ctx the SkylarkRuleContext. We will soon change to using an ActionConstructionContext + * instead. See b/79159379 + */ + @SkylarkCallable( + name = "stamp_manifest", + mandatoryPositionals = 1, // SkylarkRuleContext ctx is mandatory + parameters = { + @Param( + name = "manifest", + positional = false, + defaultValue = "None", + type = Artifact.class, + noneable = true, + named = true, + doc = "The manifest to stamp. If not passed, a dummy manifest will be generated"), + @Param( + name = "custom_package", + positional = false, + defaultValue = "None", + type = String.class, + noneable = true, + named = true, + doc = + "The Android application package to stamp the manifest with. If not provided, the" + + " current Java package, derived from the location of this target's BUILD" + + " file, will be used. For example, given a BUILD file in" + + " 'java/com/foo/bar/BUILD', the package would be 'com.foo.bar'."), + @Param( + name = "exports_manifest", + positional = false, + defaultValue = "False", + type = Boolean.class, + named = true, + doc = + "Defaults to False. If passed as True, this manifest will be exported to and" + + " eventually merged into targets that depend on it. Otherwise, it won't be" + + " inherited."), + }, + doc = "Stamps a manifest with package information.") + public AndroidManifestInfo stampAndroidManifest( + SkylarkRuleContext ctx, Object manifest, Object customPackage, boolean exported) { + String pkg = fromNoneable(customPackage, String.class); + if (pkg == null) { + pkg = AndroidManifest.getDefaultPackage(ctx.getRuleContext()); + } + + Artifact primaryManifest = fromNoneable(manifest, Artifact.class); + if (primaryManifest == null) { + return StampedAndroidManifest.createEmpty(ctx.getRuleContext(), pkg, exported).toProvider(); + } + + return new AndroidManifest(primaryManifest, pkg, exported) + .stamp(ctx.getRuleContext()) + .toProvider(); + } + + /** + * Converts a "Noneable" Object passed by Skylark to an nullable object of the appropriate type. + * + * <p>Skylark "Noneable" types are passed in as an Object that may be either the correct type or a + * Runtime.NONE object. Skylark will handle type checking, based on the appropriate @param + * annotation, but we still need to do the actual cast (or conversion to null) ourselves. + * + * @param object the Noneable object + * @param clazz the correct class, as defined in the @Param annotation + * @param <T> the type to cast to + * @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) { + if (object == Runtime.NONE) { + return null; + } + + return clazz.cast(object); + } } 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 ec54de473c..11c63df827 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 @@ -226,6 +226,14 @@ public final class ResourceApk { // 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; + + 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; builder.addNativeDeclaredProvider(merged.toProvider()); diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java index 27bba1bd4d..43b8ba0345 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/ResourceDependencies.java @@ -132,6 +132,28 @@ public final class ResourceDependencies { transitiveRTxt.build()); } + static ResourceDependencies wrapManifestInfo(Label label, AndroidManifestInfo manifestInfo) { + return new ResourceDependencies( + false, + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), + NestedSetBuilder.create( + Order.NAIVE_LINK_ORDER, + ResourceContainer.builder() + .setManifest(manifestInfo.getManifest()) + .setJavaPackage(manifestInfo.getPackage()) + .setManifestExported(manifestInfo.exportsManifest()) + .setLabel(label) + .build()), + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), + NestedSetBuilder.create(Order.NAIVE_LINK_ORDER, manifestInfo.getManifest()), + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER), + NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER)); + } + @Override public String toString() { return MoreObjects.toStringHelper(this) 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 9ba17bb533..10e6ff4bab 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 @@ -48,7 +48,12 @@ public class StampedAndroidManifest extends AndroidManifest { /** Creates an empty manifest stamped with the default Java package for this target. */ public static StampedAndroidManifest createEmpty(RuleContext ruleContext, boolean exported) { - String pkg = AndroidCommon.getJavaPackage(ruleContext); + return createEmpty(ruleContext, AndroidCommon.getJavaPackage(ruleContext), exported); + } + + /** Creates an empty manifest stamped with a specified package. */ + public static StampedAndroidManifest createEmpty( + RuleContext ruleContext, String pkg, boolean exported) { return new StampedAndroidManifest( ApplicationManifest.generateManifest(ruleContext, pkg), pkg, exported); } @@ -68,4 +73,8 @@ public class StampedAndroidManifest extends AndroidManifest { getPackage(), isExported()); } + + public AndroidManifestInfo toProvider() { + return AndroidManifestInfo.of(getManifest(), getPackage(), isExported()); + } } |