aboutsummaryrefslogtreecommitdiff
path: root/rules/aar_import/impl.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'rules/aar_import/impl.bzl')
-rw-r--r--rules/aar_import/impl.bzl547
1 files changed, 547 insertions, 0 deletions
diff --git a/rules/aar_import/impl.bzl b/rules/aar_import/impl.bzl
new file mode 100644
index 0000000..96baa2b
--- /dev/null
+++ b/rules/aar_import/impl.bzl
@@ -0,0 +1,547 @@
+# 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.
+
+"""Implementation."""
+
+load(
+ "@rules_android//rules:acls.bzl",
+ _acls = "acls",
+)
+load(
+ "@rules_android//rules:common.bzl",
+ _common = "common",
+)
+load("@rules_android//rules:intellij.bzl", "intellij")
+load(
+ "@rules_android//rules:java.bzl",
+ _java = "java",
+)
+load("@rules_android//rules:providers.bzl", "AndroidLintRulesInfo")
+load(
+ "@rules_android//rules:resources.bzl",
+ _resources = "resources",
+)
+load(
+ "@rules_android//rules:utils.bzl",
+ _get_android_toolchain = "get_android_toolchain",
+ _utils = "utils",
+)
+
+RULE_PREFIX = "_aar"
+ANDROID_MANIFEST = "AndroidManifest.xml"
+LINT_JAR = "lint.jar"
+_UNEXPECTED_LINT_JAR_ERROR = (
+ "In target %s, has_lint_jar attribute is required when the aar contains " +
+ "a lint.jar file."
+)
+
+def _create_aar_artifact(ctx, name):
+ return ctx.actions.declare_file("%s/%s/%s" % (RULE_PREFIX, ctx.label.name, name))
+
+def _create_aar_tree_artifact(ctx, name):
+ return ctx.actions.declare_directory("%s/unzipped/%s/%s" % (RULE_PREFIX, name, ctx.label.name))
+
+# Create an action to extract a file (specified by the parameter filename) from an AAR file.
+def _extract_single_file(
+ ctx,
+ out_file,
+ aar,
+ filename,
+ unzip_tool):
+ args = ctx.actions.args()
+ args.add(aar)
+ args.add(filename)
+ args.add("-d", out_file.dirname)
+
+ ctx.actions.run(
+ executable = unzip_tool,
+ arguments = [args],
+ inputs = [aar],
+ outputs = [out_file],
+ mnemonic = "AarFileExtractor",
+ progress_message = "Extracting %s from %s" % (filename, aar.basename),
+ )
+
+def _extract_resources(
+ ctx,
+ out_resources_dir,
+ out_assets_dir,
+ aar,
+ aar_resources_extractor_tool):
+ args = ctx.actions.args()
+ args.add("--input_aar", aar)
+ args.add("--output_res_dir", out_resources_dir.path)
+ args.add("--output_assets_dir", out_assets_dir.path)
+ ctx.actions.run(
+ executable = aar_resources_extractor_tool,
+ arguments = [args],
+ inputs = [aar],
+ outputs = [out_resources_dir, out_assets_dir],
+ mnemonic = "AarResourcesExtractor",
+ progress_message = "Extracting resources and assets from %s" % aar.basename,
+ )
+
+def _extract_native_libs(
+ ctx,
+ output_zip,
+ aar,
+ android_cpu,
+ aar_native_libs_zip_creator_tool):
+ args = ctx.actions.args()
+ args.add("--input_aar", aar)
+ args.add("--cpu", android_cpu)
+ args.add("--output_zip", output_zip)
+ ctx.actions.run(
+ executable = aar_native_libs_zip_creator_tool,
+ arguments = [args],
+ inputs = [aar],
+ outputs = [output_zip],
+ mnemonic = "AarNativeLibsFilter",
+ progress_message = "Filtering AAR native libs by architecture",
+ )
+
+def _process_resources(
+ ctx,
+ aar,
+ manifest,
+ deps,
+ aar_resources_extractor_tool,
+ unzip_tool):
+ # Extract resources and assets, if they exist.
+ resources = _create_aar_tree_artifact(ctx, "resources")
+ assets = _create_aar_tree_artifact(ctx, "assets")
+ _extract_resources(
+ ctx,
+ resources,
+ assets,
+ aar,
+ aar_resources_extractor_tool,
+ )
+
+ resources_ctx = _resources.process_starlark(
+ ctx,
+ manifest = manifest,
+ assets = [assets],
+ assets_dir = assets.path,
+ resource_files = [resources],
+ stamp_manifest = False,
+ deps = ctx.attr.deps,
+ exports = ctx.attr.exports,
+ exports_manifest = getattr(ctx.attr, "exports_manifest", True),
+
+ # Tool and Processing related inputs
+ aapt = _get_android_toolchain(ctx).aapt2.files_to_run,
+ android_jar = ctx.attr._android_sdk[AndroidSdkInfo].android_jar,
+ android_kit = _get_android_toolchain(ctx).android_kit.files_to_run,
+ busybox = _get_android_toolchain(ctx).android_resources_busybox.files_to_run,
+ java_toolchain = _common.get_java_toolchain(ctx),
+ host_javabase = _common.get_host_javabase(ctx),
+ instrument_xslt = _utils.only(_get_android_toolchain(ctx).add_g3itr_xslt.files.to_list()),
+ xsltproc = _get_android_toolchain(ctx).xsltproc_tool.files_to_run,
+ )
+
+ # TODO: replace android_data
+ # data_ctx = android_data.make_context(ctx.actions, ctx.attr)
+ # resource_apk = android_data.process_aar_import_data(
+ # data_ctx,
+ # resources,
+ # assets,
+ # manifest,
+ # deps = deps,
+ # )
+ # resources_ctx["validation_results"].append(
+ # _utils.only(resource_apk[AndroidResourcesInfo].direct_android_resources.to_list()).java_class_jar,
+ # )
+ # resources_ctx["providers"].append(resource_apk[AndroidResourcesInfo])
+ # resources_ctx["providers"].append(resource_apk[AndroidAssetsInfo])
+
+ if not _acls.in_aar_propagate_resources(str(ctx.label)):
+ resources_ctx["providers"] = []
+
+ return struct(**resources_ctx)
+
+def _extract_jars(
+ ctx,
+ out_jars_tree_artifact,
+ out_jars_params_file,
+ aar,
+ aar_embedded_jars_extractor_tool):
+ args = ctx.actions.args()
+ args.add("--input_aar", aar)
+ args.add("--output_dir", out_jars_tree_artifact.path)
+ args.add("--output_singlejar_param_file", out_jars_params_file)
+ ctx.actions.run(
+ executable = aar_embedded_jars_extractor_tool,
+ arguments = [args],
+ inputs = [aar],
+ outputs = [out_jars_tree_artifact, out_jars_params_file],
+ mnemonic = "AarEmbeddedJarsExtractor",
+ progress_message = "Extracting classes.jar and libs/*.jar from %s" % aar.basename,
+ )
+
+def _merge_jars(
+ ctx,
+ out_jar,
+ jars_tree_artifact,
+ jars_param_file,
+ single_jar_tool):
+ args = ctx.actions.args()
+ args.add("--output", out_jar)
+ args.add("--dont_change_compression")
+ args.add("--normalize")
+ args.add("@" + jars_param_file.path)
+ ctx.actions.run(
+ executable = single_jar_tool,
+ arguments = [args],
+ inputs = [jars_tree_artifact, jars_param_file],
+ outputs = [out_jar],
+ mnemonic = "AarJarsMerger",
+ progress_message = "Merging AAR embedded jars",
+ )
+
+def _extract_and_merge_jars(
+ ctx,
+ out_jar,
+ aar,
+ aar_embedded_jars_extractor_tool,
+ single_jar_tool):
+ """Extracts all the Jars within the AAR and produces a single jar.
+
+ An AAR may have multiple Jar files embedded within it. This method
+ extracts and merges all Jars.
+ """
+ jars_tree_artifact = _create_aar_tree_artifact(ctx, "jars")
+ jars_params_file = _create_aar_artifact(ctx, "jar_merging_params")
+ _extract_jars(
+ ctx,
+ jars_tree_artifact,
+ jars_params_file,
+ aar,
+ aar_embedded_jars_extractor_tool,
+ )
+ _merge_jars(
+ ctx,
+ out_jar,
+ jars_tree_artifact,
+ jars_params_file,
+ single_jar_tool,
+ )
+
+def _create_import_deps_check(
+ ctx,
+ jars_to_check,
+ declared_deps,
+ transitive_deps,
+ bootclasspath,
+ jdeps_output,
+ import_deps_checker_tool,
+ host_javabase):
+ args = ctx.actions.args()
+ args.add_all(jars_to_check, before_each = "--input")
+ args.add_all(declared_deps, before_each = "--directdep")
+ args.add_all(transitive_deps, before_each = "--classpath_entry")
+ args.add_all(bootclasspath, before_each = "--bootclasspath_entry")
+ args.add("--checking_mode=error")
+ args.add("--jdeps_output", jdeps_output)
+ args.add("--rule_label", ctx.label)
+
+ _java.run(
+ ctx = ctx,
+ host_javabase = host_javabase,
+ executable = import_deps_checker_tool,
+ arguments = [args],
+ inputs = depset(
+ jars_to_check,
+ transitive = [
+ declared_deps,
+ transitive_deps,
+ bootclasspath,
+ ],
+ ),
+ outputs = [jdeps_output],
+ mnemonic = "ImportDepsChecker",
+ progress_message = "Checking the completeness of the deps for %s" % jars_to_check,
+ )
+
+def _process_jars(
+ ctx,
+ out_jar,
+ aar,
+ source_jar,
+ r_java,
+ deps,
+ exports,
+ enable_desugar_java8,
+ enable_imports_deps_check,
+ bootclasspath,
+ desugar_java8_extra_bootclasspath,
+ aar_embedded_jars_extractor_tool,
+ import_deps_checker_tool,
+ single_jar_tool,
+ java_toolchain,
+ host_javabase):
+ providers = []
+ validation_results = []
+ r_java_info = [r_java] if r_java else []
+
+ # An aar may have multple Jar files, extract and merge into a single jar.
+ _extract_and_merge_jars(
+ ctx,
+ out_jar,
+ aar,
+ aar_embedded_jars_extractor_tool,
+ single_jar_tool,
+ )
+
+ java_infos = deps + exports
+
+ if enable_desugar_java8:
+ bootclasspath = depset(transitive = [
+ desugar_java8_extra_bootclasspath,
+ bootclasspath,
+ ])
+
+ merged_java_info = java_common.merge(java_infos + r_java_info)
+ jdeps_artifact = _create_aar_artifact(ctx, "jdeps.proto")
+ _create_import_deps_check(
+ ctx,
+ [out_jar],
+ merged_java_info.compile_jars,
+ merged_java_info.transitive_compile_time_jars,
+ bootclasspath,
+ jdeps_artifact,
+ import_deps_checker_tool,
+ host_javabase,
+ )
+ if enable_imports_deps_check:
+ validation_results.append(jdeps_artifact)
+
+ java_info = JavaInfo(
+ out_jar,
+ compile_jar = java_common.stamp_jar(
+ actions = ctx.actions,
+ jar = out_jar,
+ target_label = ctx.label,
+ java_toolchain = java_toolchain,
+ ),
+ source_jar = source_jar,
+ neverlink = False,
+ deps = r_java_info + java_infos, # TODO(djwhang): Exports are not deps.
+ exports =
+ (r_java_info if _acls.in_aar_import_exports_r_java(str(ctx.label)) else []) +
+ java_infos, # TODO(djwhang): Deps are not exports.
+ # TODO(djwhang): AarImportTest is not expecting jdeps, enable or remove it completely
+ # jdeps = jdeps_artifact,
+ )
+ providers.append(java_info)
+
+ return struct(
+ java_info = java_info,
+ providers = providers,
+ validation_results = validation_results,
+ )
+
+def _validate_rule(
+ ctx,
+ aar,
+ manifest,
+ checks):
+ package = _java.resolve_package_from_label(ctx.label, ctx.attr.package)
+ validation_output = ctx.actions.declare_file("%s_validation_output" % ctx.label.name)
+
+ args = ctx.actions.args()
+ args.add("-aar", aar)
+ inputs = [aar]
+ args.add("-label", str(ctx.label))
+ if _acls.in_aar_import_pkg_check(str(ctx.label)):
+ args.add("-pkg", package)
+ args.add("-manifest", manifest)
+ inputs.append(manifest)
+ if ctx.attr.has_lint_jar:
+ args.add("-has_lint_jar")
+ args.add("-output", validation_output)
+
+ ctx.actions.run(
+ executable = checks,
+ arguments = [args],
+ inputs = inputs,
+ outputs = [validation_output],
+ mnemonic = "ValidateAAR",
+ progress_message = "Validating aar_import %s" % str(ctx.label),
+ )
+ return validation_output
+
+def _process_lint_rules(
+ ctx,
+ aar,
+ unzip_tool):
+ providers = []
+
+ if ctx.attr.has_lint_jar:
+ lint_jar = _create_aar_artifact(ctx, LINT_JAR)
+ _extract_single_file(
+ ctx,
+ lint_jar,
+ aar,
+ LINT_JAR,
+ unzip_tool,
+ )
+ providers.append(AndroidLintRulesInfo(
+ lint_jar = lint_jar,
+ ))
+
+ providers.extend(_utils.collect_providers(
+ AndroidLintRulesInfo,
+ ctx.attr.exports,
+ ))
+ return providers
+
+def impl(ctx):
+ """The rule implementation.
+
+ Args:
+ ctx: The context.
+
+ Returns:
+ A list of providers.
+ """
+ providers = []
+ validation_outputs = []
+
+ aar = _utils.only(ctx.files.aar)
+ unzip_tool = _get_android_toolchain(ctx).unzip_tool.files_to_run
+
+ # Extract the AndroidManifest.xml from the AAR.
+ android_manifest = _create_aar_artifact(ctx, ANDROID_MANIFEST)
+ _extract_single_file(
+ ctx,
+ android_manifest,
+ aar,
+ ANDROID_MANIFEST,
+ unzip_tool,
+ )
+
+ resources_ctx = _process_resources(
+ ctx,
+ aar = aar,
+ manifest = android_manifest,
+ deps = ctx.attr.deps,
+ aar_resources_extractor_tool =
+ _get_android_toolchain(ctx).aar_resources_extractor.files_to_run,
+ unzip_tool = unzip_tool,
+ )
+ providers.extend(resources_ctx.providers)
+
+ merged_jar = _create_aar_artifact(ctx, "classes_and_libs_merged.jar")
+ jvm_ctx = _process_jars(
+ ctx,
+ out_jar = merged_jar,
+ aar = aar,
+ source_jar = ctx.file.srcjar,
+ deps = _utils.collect_providers(JavaInfo, ctx.attr.deps),
+ r_java = resources_ctx.r_java,
+ exports = _utils.collect_providers(JavaInfo, ctx.attr.exports),
+ enable_desugar_java8 = ctx.fragments.android.desugar_java8,
+ enable_imports_deps_check =
+ _acls.in_aar_import_deps_checker(str(ctx.label)),
+ aar_embedded_jars_extractor_tool =
+ _get_android_toolchain(ctx).aar_embedded_jars_extractor.files_to_run,
+ bootclasspath =
+ ctx.attr._java_toolchain[java_common.JavaToolchainInfo].bootclasspath,
+ desugar_java8_extra_bootclasspath =
+ _get_android_toolchain(ctx).desugar_java8_extra_bootclasspath.files,
+ import_deps_checker_tool =
+ _get_android_toolchain(ctx).import_deps_checker.files_to_run,
+ single_jar_tool =
+ ctx.attr._java_toolchain[java_common.JavaToolchainInfo].single_jar,
+ java_toolchain =
+ ctx.attr._java_toolchain[java_common.JavaToolchainInfo],
+ host_javabase = ctx.attr._host_javabase,
+ )
+ providers.extend(jvm_ctx.providers)
+ validation_outputs.extend(jvm_ctx.validation_results)
+
+ native_libs = _create_aar_artifact(ctx, "native_libs.zip")
+ _extract_native_libs(
+ ctx,
+ native_libs,
+ aar = aar,
+ android_cpu = ctx.fragments.android.android_cpu,
+ aar_native_libs_zip_creator_tool =
+ _get_android_toolchain(ctx).aar_native_libs_zip_creator.files_to_run,
+ )
+ native_libs_infos = _utils.collect_providers(
+ AndroidNativeLibsInfo,
+ ctx.attr.deps,
+ ctx.attr.exports,
+ )
+ providers.append(
+ AndroidNativeLibsInfo(
+ depset(
+ [native_libs],
+ transitive = [info.native_libs for info in native_libs_infos],
+ ),
+ ),
+ )
+
+ lint_providers = _process_lint_rules(
+ ctx,
+ aar = aar,
+ unzip_tool = unzip_tool,
+ )
+ providers.extend(lint_providers)
+
+ validation_outputs.append(_validate_rule(
+ ctx,
+ aar = aar,
+ manifest = android_manifest,
+ checks = _get_android_toolchain(ctx).aar_import_checks.files_to_run,
+ ))
+
+ providers.append(
+ intellij.make_android_ide_info(
+ ctx,
+ java_package = _java.resolve_package_from_label(ctx.label, ctx.attr.package),
+ manifest = resources_ctx.merged_manifest,
+ defines_resources = resources_ctx.defines_resources,
+ merged_manifest = resources_ctx.merged_manifest,
+ resources_apk = resources_ctx.resources_apk,
+ r_jar = _utils.only(resources_ctx.r_java.outputs.jars) if resources_ctx.r_java else None,
+ java_info = jvm_ctx.java_info,
+ signed_apk = None, # signed_apk, always empty for aar_import
+ apks_under_test = [], # apks_under_test, always empty for aar_import
+ native_libs = dict(), # nativelibs, always empty for aar_import
+ idlclass = _get_android_toolchain(ctx).idlclass.files_to_run,
+ host_javabase = _common.get_host_javabase(ctx),
+ ),
+ )
+
+ providers.append(OutputGroupInfo(_validation = depset(validation_outputs)))
+
+ # There isn't really any use case for building an aar_import target on its own, so the files to
+ # build could be empty. The R class JAR and merged JARs are added here as a sanity check for
+ # Bazel developers so that `bazel build java/com/my_aar_import` will fail if the resource
+ # processing or JAR merging steps fail.
+ files_to_build = []
+ files_to_build.extend(resources_ctx.validation_results) # TODO(djwhang): This should be validation.
+ files_to_build.append(merged_jar)
+
+ providers.append(
+ DefaultInfo(
+ files = depset(files_to_build),
+ runfiles = ctx.runfiles(),
+ ),
+ )
+
+ return providers