# Copyright 2019 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. """Bazel ResourcesBusyBox Commands.""" load(":java.bzl", _java = "java") _ANDROID_RESOURCES_STRICT_DEPS = "android_resources_strict_deps" def _sanitize_assets_dir(assets_dir): sanitized_assets_dir = "/".join( [ part for part in assets_dir.split("/") if part != "" and part != "." ], ) return "/" + sanitized_assets_dir if assets_dir.startswith("/") else sanitized_assets_dir def _get_unique_assets_dirs(assets, assets_dir): """Find the unique assets directories, partitioned by assets_dir. Args: assets: A list of Files. List of asset files to process. assets_dir: String. String giving the path to the files in assets. Returns: A list of short_paths representing unique asset dirs. """ if not assets: return [] dirs = dict() assets_dir = _sanitize_assets_dir(assets_dir) if assets_dir: partition_by = "/%s/" % assets_dir.strip("/") for f in assets: if f.is_directory and f.path.endswith(partition_by[:-1]): # If f is a directory, check if its path ends with the assets_dir. dirs[f.path] = True elif f.is_directory and "_aar/unzipped" in f.path: # Assets from an aar_import rule are extracted in a # "assets" subdirectory of the given path dirs["%s/assets" % f.path] = True else: # Partition to remove subdirectories beneath assets_dir # Also removes the trailing / dirs["".join(f.path.rpartition(partition_by)[:2])[:-1]] = True else: # Use the dirname of the generating target if no assets_dir. for f in assets: if f.is_source: dirs[f.owner.package] = True else: # Prepend the root path for generated files. dirs[f.root.path + "/" + f.owner.package] = True return dirs.keys() def _get_unique_res_dirs(resource_files): """Find the unique res dirs. Args: resource_files: A list of Files. A list of resource_files. Returns: A list of short_paths representing unique res dirs from the given resource files. """ dirs = dict() for f in resource_files: if f.is_directory: dirs[f.path] = True else: dirs[f.dirname.rpartition("/" + f.dirname.split("/")[-1])[0]] = True return dirs.keys() def _make_serialized_resources_flag( assets = [], assets_dir = None, resource_files = [], label = "", symbols = None): return ";".join( [ "#".join(_get_unique_res_dirs(resource_files)), "#".join(_get_unique_assets_dirs(assets, assets_dir)), label, symbols.path if symbols else "", ], ).rstrip(":") def _make_resources_flag( assets = [], assets_dir = None, resource_files = [], manifest = None, r_txt = None, symbols = None): return ":".join( [ "#".join(_get_unique_res_dirs(resource_files)), "#".join(_get_unique_assets_dirs(assets, assets_dir)), manifest.path if manifest else "", r_txt.path if r_txt else "", symbols.path if symbols else "", ], ) def _path(f): return f.path def _make_package_resources_flags(resources_node): if not (resources_node.manifest and resources_node.r_txt and resources_node.compiled_resources): return None flag = _make_resources_flag( resource_files = resources_node.resource_files.to_list(), assets = resources_node.assets.to_list(), assets_dir = resources_node.assets_dir, manifest = resources_node.manifest, r_txt = resources_node.r_txt, symbols = resources_node.compiled_resources, ) return flag def _make_package_assets_flags(resources_node): assets = resources_node.assets.to_list() if not assets: return None return _make_serialized_resources_flag( assets = assets, assets_dir = resources_node.assets_dir, label = str(resources_node.label), symbols = resources_node.compiled_assets, ) def _extract_filters( raw_list): """Extract densities and resource_configuration filters from raw string lists. In BUILD files, string lists can be represented as a list of strings, a single comma-separated string, or a combination of both. This method outputs a single list of individual string values, which can then be passed directly to resource processing actions. Empty strings are removed and the final list is sorted. Args: raw_list: List of strings. The raw densities or resource configuration filters. Returns: List of strings extracted from the raw list. """ out_filters = [] for item in raw_list: if "," in item: item_list = item.split(",") for entry in item_list: stripped_entry = entry.strip() if stripped_entry: out_filters.append(stripped_entry) elif item: out_filters.append(item) return sorted(out_filters) def _package( ctx, out_r_src_jar = None, out_r_txt = None, out_symbols = None, out_manifest = None, out_proguard_cfg = None, out_main_dex_proguard_cfg = None, out_resource_files_zip = None, out_file = None, package_type = None, java_package = None, manifest = None, assets = [], assets_dir = None, resource_files = [], resource_configs = None, densities = [], application_id = None, direct_resources_nodes = [], transitive_resources_nodes = [], transitive_manifests = [], transitive_assets = [], transitive_compiled_assets = [], transitive_resource_files = [], transitive_compiled_resources = [], transitive_r_txts = [], additional_apks_to_link_against = [], nocompress_extensions = [], proto_format = False, version_name = None, version_code = None, android_jar = None, aapt = None, busybox = None, host_javabase = None, should_throw_on_conflict = True, # TODO: read this from allowlist at caller debug = True): # TODO: we will set this to false in prod builds """Packages the compiled Android Resources with AAPT. Args: ctx: The context. out_r_src_jar: A File. The R.java outputted by linking resources in a srcjar. out_r_txt: A File. The resource IDs outputted by linking resources in text. out_symbols: A File. The output zip containing compiled resources. out_manifest: A File. The output processed manifest. out_proguard_cfg: A File. The proguard config to be generated. out_main_dex_proguard_cfg: A File. The main dex proguard config to be generated. out_resource_files_zip: A File. The resource files zipped by linking resources. out_file: A File. The Resource APK outputted by linking resources. package_type: A string. The configuration type to use when packaging. java_package: A string. The Java package for the generated R.java. manifest: A File. The AndroidManifest.xml. assets: sequence of Files. A list of Android assets files to be processed. assets_dir: String. The name of the assets directory. resource_files: A list of Files. The resource files. resource_configs: A list of strings. The list of resource configuration filters. densities: A list of strings. The list of screen densities to filter for when building the apk. application_id: An optional string. The applicationId set in manifest values. direct_resources_nodes: Depset of ResourcesNodeInfo providers. The set of ResourcesNodeInfo from direct dependencies. transitive_resources_nodes: Depset of ResourcesNodeInfo providers. The set of ResourcesNodeInfo from transitive dependencies (not including directs). transitive_manifests: List of Depsets. Depsets contain all transitive manifests. transitive_assets: List of Depsets. Depsets contain all transitive assets. transitive_compiled_assets: List of Depsets. Depsets contain all transitive compiled_assets. transitive_resource_files: List of Depsets. Depsets contain all transitive resource files. transitive_compiled_resources: List of Depsets. Depsets contain all transitive compiled_resources. transitive_r_txts: List of Depsets. Depsets contain all transitive R txt files. additional_apks_to_link_against: A list of Files. Additional APKs to link against. Optional. nocompress_extensions: A list of strings. File extension to leave uncompressed in the apk. proto_format: Boolean, whether to generate the resource table in proto format. version_name: A string. The version name to stamp the generated manifest with. Optional. version_code: A string. The version code to stamp the generated manifest with. Optional. android_jar: A File. The Android Jar. aapt: A FilesToRunProvider. The AAPT executable. busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. host_javabase: Target. The host javabase. should_throw_on_conflict: A boolean. Determines whether an error should be thrown when a resource conflict occurs. debug: A boolean. Determines whether to enable debugging. """ if not manifest: fail("No manifest given, the manifest is mandatory.") direct_data_flag = [] direct_compiled_resources = [] output_files = [] input_files = [] transitive_input_files = [] args = ctx.actions.args() args.use_param_file("@%s") args.add("--tool", "AAPT2_PACKAGE") args.add("--") args.add("--aapt2", aapt.executable) args.add_joined( "--data", transitive_resources_nodes, map_each = _make_package_resources_flags, join_with = ",", ) args.add_joined( "--directData", direct_resources_nodes, map_each = _make_package_resources_flags, join_with = ",", ) args.add_joined( "--directAssets", direct_resources_nodes, map_each = _make_package_assets_flags, join_with = "&", omit_if_empty = True, ) args.add_joined( "--assets", transitive_resources_nodes, map_each = _make_package_assets_flags, join_with = "&", omit_if_empty = True, ) transitive_input_files.extend(transitive_resource_files) transitive_input_files.extend(transitive_assets) transitive_input_files.extend(transitive_compiled_assets) transitive_input_files.extend(transitive_compiled_resources) transitive_input_files.extend(transitive_manifests) transitive_input_files.extend(transitive_r_txts) args.add( "--primaryData", _make_resources_flag( manifest = manifest, assets = assets, assets_dir = assets_dir, resource_files = resource_files, ), ) input_files.append(manifest) input_files.extend(resource_files) input_files.extend(assets) args.add("--androidJar", android_jar) input_files.append(android_jar) args.add("--rOutput", out_r_txt) output_files.append(out_r_txt) if out_symbols: args.add("--symbolsOut", out_symbols) output_files.append(out_symbols) args.add("--srcJarOutput", out_r_src_jar) output_files.append(out_r_src_jar) if out_proguard_cfg: args.add("--proguardOutput", out_proguard_cfg) output_files.append(out_proguard_cfg) if out_main_dex_proguard_cfg: args.add("--mainDexProguardOutput", out_main_dex_proguard_cfg) output_files.append(out_main_dex_proguard_cfg) args.add("--manifestOutput", out_manifest) output_files.append(out_manifest) if out_resource_files_zip: args.add("--resourcesOutput", out_resource_files_zip) output_files.append(out_resource_files_zip) if out_file: args.add("--packagePath", out_file) output_files.append(out_file) args.add("--useAaptCruncher=no") # Unnecessary, used for AAPT1 only but added here to minimize diffs. if package_type: args.add("--packageType", package_type) if debug: args.add("--debug") if should_throw_on_conflict: args.add("--throwOnResourceConflict") if resource_configs: args.add_joined("--resourceConfigs", _extract_filters(resource_configs), join_with = ",") if densities: args.add_joined("--densities", _extract_filters(densities), join_with = ",") if application_id: args.add("--applicationId", application_id) if additional_apks_to_link_against: args.add_joined( "--additionalApksToLinkAgainst", additional_apks_to_link_against, join_with = ",", map_each = _path, ) input_files.extend(additional_apks_to_link_against) if nocompress_extensions: args.add_joined("--uncompressedExtensions", nocompress_extensions, join_with = ",") if proto_format: args.add("--resourceTableAsProto") if version_name: args.add("--versionName", version_name) if version_code: args.add("--versionCode", version_code) args.add("--packageForR", java_package) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, tools = [aapt], arguments = [args], inputs = depset(input_files, transitive = transitive_input_files), outputs = output_files, mnemonic = "PackageAndroidResources", progress_message = "Packaging Android Resources in %s" % ctx.label, ) def _parse( ctx, out_symbols = None, assets = [], assets_dir = None, busybox = None, host_javabase = None): """Parses Android assets. Args: ctx: The context. out_symbols: A File. The output bin containing parsed assets. assets: sequence of Files. A list of Android assets files to be processed. assets_dir: String. The name of the assets directory. busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. host_javabase: Target. The host javabase. """ args = ctx.actions.args() args.use_param_file("@%s") args.add("--tool", "PARSE") args.add("--") args.add( "--primaryData", _make_resources_flag( assets = assets, assets_dir = assets_dir, ), ) args.add("--output", out_symbols) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, arguments = [args], inputs = assets, outputs = [out_symbols], mnemonic = "ParseAndroidResources", progress_message = "Parsing Android Resources in %s" % out_symbols.short_path, ) def _make_merge_assets_flags(resources_node): assets = resources_node.assets.to_list() if not (assets or resources_node.assets_dir): return None return _make_serialized_resources_flag( assets = assets, assets_dir = resources_node.assets_dir, label = str(resources_node.label), symbols = resources_node.assets_symbols, ) def _merge_assets( ctx, out_assets_zip = None, assets = [], assets_dir = None, symbols = None, transitive_assets = [], transitive_assets_symbols = [], direct_resources_nodes = [], transitive_resources_nodes = [], busybox = None, host_javabase = None): """Merges Android assets. Args: ctx: The context. out_assets_zip: A File. assets: sequence of Files. A list of Android assets files to be processed. assets_dir: String. The name of the assets directory. symbols: A File. The parsed assets. transitive_assets: Sequence of Depsets. The list of transitive assets from deps. transitive_assets_symbols: Sequence of Depsets. The list of transitive assets_symbols files from deps. direct_resources_nodes: Sequence of ResourcesNodeInfo providers. The list of ResourcesNodeInfo providers that are direct depencies. transitive_resources_nodes: Sequence of ResourcesNodeInfo providers. The list of ResourcesNodeInfo providers that are transitive depencies. busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. host_javabase: Target. The host javabase. """ args = ctx.actions.args() args.use_param_file("@%s") args.add("--tool", "MERGE_ASSETS") args.add("--") args.add("--assetsOutput", out_assets_zip) args.add( "--primaryData", _make_serialized_resources_flag( assets = assets, assets_dir = assets_dir, label = str(ctx.label), symbols = symbols, ), ) args.add_joined( "--directData", direct_resources_nodes, map_each = _make_merge_assets_flags, join_with = "&", ) args.add_joined( "--data", transitive_resources_nodes, map_each = _make_merge_assets_flags, join_with = "&", ) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, arguments = [args], inputs = depset( assets + [symbols], transitive = transitive_assets + transitive_assets_symbols, ), outputs = [out_assets_zip], mnemonic = "MergeAndroidAssets", progress_message = "Merging Android Assets in %s" % out_assets_zip.short_path, ) def _validate_and_link( ctx, out_r_src_jar = None, out_r_txt = None, out_file = None, compiled_resources = None, transitive_compiled_resources = depset(), java_package = None, manifest = None, android_jar = None, busybox = None, host_javabase = None, aapt = None): """Links compiled Android Resources with AAPT. Args: ctx: The context. out_r_src_jar: A File. The R.java outputted by linking resources in a srcjar. out_r_txt: A File. The resource IDs outputted by linking resources in text. out_file: A File. The Resource APK outputted by linking resources. compiled_resources: A File. The symbols.zip of compiled resources for this target. transitive_compiled_resources: Depset of Files. The symbols.zip of the compiled resources from the transitive dependencies of this target. java_package: A string. The Java package for the generated R.java. manifest: A File. The AndroidManifest.xml. android_jar: A File. The Android Jar. busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. host_javabase: Target. The host javabase. aapt: A FilesToRunProvider. The AAPT executable. """ output_files = [] input_files = [android_jar] transitive_input_files = [] # Retrieves the list of files at runtime when a directory is passed. args = ctx.actions.args() args.use_param_file("@%s") args.add("--tool", "LINK_STATIC_LIBRARY") args.add("--") args.add("--aapt2", aapt.executable) args.add("--libraries", android_jar) if compiled_resources: args.add("--compiled", compiled_resources) input_files.append(compiled_resources) args.add_joined( "--compiledDep", transitive_compiled_resources, join_with = ":", ) transitive_input_files.append(transitive_compiled_resources) args.add("--manifest", manifest) input_files.append(manifest) if java_package: args.add("--packageForR", java_package) args.add("--sourceJarOut", out_r_src_jar) output_files.append(out_r_src_jar) args.add("--rTxtOut", out_r_txt) output_files.append(out_r_txt) args.add("--staticLibraryOut", out_file) output_files.append(out_file) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, tools = [aapt], arguments = [args], inputs = depset(input_files, transitive = transitive_input_files), outputs = output_files, mnemonic = "LinkAndroidResources", progress_message = "Linking Android Resources in " + out_file.short_path, ) def _compile( ctx, out_file = None, assets = [], assets_dir = None, resource_files = [], busybox = None, aapt = None, host_javabase = None): """Compile and store resources in a single archive. Args: ctx: The context. out_file: File. The output zip containing compiled resources. resource_files: A list of Files. The list of resource files or directories assets: A list of Files. The list of assets files or directories to process. assets_dir: String. The name of the assets directory. busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. aapt: AAPT. Tool for compiling resources. host_javabase: Target. The host javabase. """ if not out_file: fail("No output directory specified.") # Retrieves the list of files at runtime when a directory is passed. args = ctx.actions.args() args.use_param_file("@%s") args.add("--tool", "COMPILE_LIBRARY_RESOURCES") args.add("--") args.add("--aapt2", aapt.executable) args.add( "--resources", _make_resources_flag( resource_files = resource_files, assets = assets, assets_dir = assets_dir, ), ) args.add("--output", out_file) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, tools = [aapt], arguments = [args], inputs = resource_files + assets, outputs = [out_file], mnemonic = "CompileAndroidResources", progress_message = "Compiling Android Resources in %s" % out_file.short_path, ) def _make_merge_compiled_flags(resources_node_info): if not resources_node_info.compiled_resources: return None return _make_serialized_resources_flag( label = str(resources_node_info.label), symbols = resources_node_info.compiled_resources, ) def _merge_compiled( ctx, out_class_jar = None, out_manifest = None, out_aapt2_r_txt = None, java_package = None, manifest = None, compiled_resources = None, direct_resources_nodes = [], transitive_resources_nodes = [], direct_compiled_resources = depset(), transitive_compiled_resources = depset(), android_jar = None, busybox = None, host_javabase = None): """Merges the compile resources. Args: ctx: The context. out_class_jar: A File. The compiled R.java outputted by linking resources. out_manifest: A File. The list of resource files or directories out_aapt2_r_txt: A File. The resource IDs outputted by linking resources in text. java_package: A string. The Java package for the generated R.java. manifest: A File. The AndroidManifest.xml. compiled_resources: A File. The symbols.zip of compiled resources for this target. direct_resources_nodes: Sequence of ResourcesNodeInfo providers. The list of ResourcesNodeInfo providers that are direct depencies. transitive_resources_nodes: Sequence of ResourcesNodeInfo providers. The list of ResourcesNodeInfo providers that are transitive depencies. direct_compiled_resources: Depset of Files. A depset of symbols.zip of compiled resources from direct dependencies. transitive_compiled_resources: Depset of Files. A depset of symbols.zip of compiled resources from transitive dependencies. android_jar: A File. The Android Jar. busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. host_javabase: Target. The host javabase. """ output_files = [] input_files = [android_jar] transitive_input_files = [] args = ctx.actions.args() args.use_param_file("@%s") args.add("--tool", "MERGE_COMPILED") args.add("--") args.add("--classJarOutput", out_class_jar) output_files.append(out_class_jar) args.add("--targetLabel", ctx.label) args.add("--manifestOutput", out_manifest) output_files.append(out_manifest) args.add("--rTxtOut", out_aapt2_r_txt) output_files.append(out_aapt2_r_txt) args.add("--androidJar", android_jar) args.add("--primaryManifest", manifest) input_files.append(manifest) if java_package: args.add("--packageForR", java_package) args.add( "--primaryData", _make_serialized_resources_flag( label = str(ctx.label), symbols = compiled_resources, ), ) input_files.append(compiled_resources) args.add_joined( "--directData", direct_resources_nodes, map_each = _make_merge_compiled_flags, join_with = "&", ) transitive_input_files.append(direct_compiled_resources) if _ANDROID_RESOURCES_STRICT_DEPS in ctx.disabled_features: args.add_joined( "--data", transitive_resources_nodes, map_each = _make_merge_compiled_flags, join_with = "&", ) transitive_input_files.append(transitive_compiled_resources) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, arguments = [args], inputs = depset(input_files, transitive = transitive_input_files), outputs = output_files, mnemonic = "StarlarkMergeCompiledAndroidResources", progress_message = "Merging compiled Android Resources in " + out_class_jar.short_path, ) def _escape_mv(s): """Escapes `:` and `,` in manifest values so they can be used as a busybox flag.""" return s.replace(":", "\\:").replace(",", "\\,") def _owner_label(file): return "//" + file.owner.package + ":" + file.owner.name # We need to remove the "/_migrated/" path segment from file paths in order for sorting to # match the order of the native manifest merging action. def _manifest_short_path(manifest): return manifest.short_path.replace("/_migrated/", "/") def _mergee_manifests_flag(manifests): ordered_manifests = sorted(manifests.to_list(), key = _manifest_short_path) entries = [] for manifest in ordered_manifests: label = _owner_label(manifest).replace(":", "\\:") entries.append((manifest.path + ":" + label).replace(",", "\\,")) flag_entry = ",".join(entries) if not flag_entry: return None return flag_entry def _merge_manifests( ctx, out_file = None, out_log_file = None, merge_type = "APPLICATION", manifest = None, mergee_manifests = depset(), manifest_values = None, java_package = None, busybox = None, host_javabase = None): """Merge multiple AndroidManifest.xml files into a single one. Args: ctx: The context. out_file: A File. The output merged manifest. out_log_file: A File. The output log from the merge tool. merge_type: A string, either APPLICATION or LIBRARY. Type of merging. manifest: A File. The primary AndroidManifest.xml. mergee_manifests: A depset of Files. All transitive manifests to be merged. manifest_values: A dictionary. Manifest values to substitute. java_package: A string. Custom java package to insert in manifest package attribute. busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. host_javabase: Target. The host javabase. """ if merge_type not in ["APPLICATION", "LIBRARY"]: fail("Unexpected manifest merge type: " + merge_type) outputs = [out_file] directs = [manifest] transitives = [mergee_manifests] # Args for busybox args = ctx.actions.args() args.use_param_file("@%s", use_always = True) args.add("--tool", "MERGE_MANIFEST") args.add("--") args.add("--manifest", manifest) args.add_all( "--mergeeManifests", [mergee_manifests], map_each = _mergee_manifests_flag, ) if manifest_values: args.add( "--manifestValues", ",".join(["%s:%s" % (_escape_mv(k), _escape_mv(v)) for k, v in manifest_values.items()]), ) args.add("--mergeType", merge_type) args.add("--customPackage", java_package) args.add("--manifestOutput", out_file) if out_log_file: args.add("--log", out_log_file) outputs.append(out_log_file) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, arguments = [args], inputs = depset(directs, transitive = transitives), outputs = outputs, mnemonic = "MergeManifests", progress_message = "Merging Android Manifests in %s" % out_file.short_path, ) def _process_databinding( ctx, out_databinding_info = None, out_databinding_processed_resources = None, databinding_resources_dirname = None, resource_files = None, java_package = None, busybox = None, host_javabase = None): """Processes databinding for android_binary. Processes databinding declarations over resources, populates the databinding layout info file, and generates new resources with databinding expressions stripped out. Args: ctx: The context. out_databinding_info: File. The output databinding layout info zip file. out_databinding_processed_resources: List of Files. The generated databinding processed resource files. databinding_resources_dirname: String. The execution path to the directory where the out_databinding_processed_resources are generated. resource_files: List of Files. The resource files to be processed. java_package: String. Java package for which java sources will be generated. By default the package is inferred from the directory where the BUILD file containing the rule is. busybox: FilesToRunProvider. The ResourceBusyBox executable or FilesToRunprovider host_javabase: A Target. The host javabase. """ res_dirs = _get_unique_res_dirs(resource_files) args = ctx.actions.args() args.add("--tool", "PROCESS_DATABINDING") args.add("--") args.add("--output_resource_directory", databinding_resources_dirname) args.add_all(res_dirs, before_each = "--resource_root") args.add("--dataBindingInfoOut", out_databinding_info) args.add("--appId", java_package) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, arguments = [args], inputs = resource_files, outputs = [out_databinding_info] + out_databinding_processed_resources, mnemonic = "StarlarkProcessDatabinding", progress_message = "Processing data binding", ) def _make_generate_binay_r_flags(resources_node): if not (resources_node.r_txt or resources_node.manifest): return None return ",".join( [ resources_node.r_txt.path if resources_node.r_txt else "", resources_node.manifest.path if resources_node.manifest else "", ], ) def _generate_binary_r( ctx, out_class_jar = None, r_txt = None, manifest = None, package_for_r = None, final_fields = None, resources_nodes = depset(), transitive_r_txts = [], transitive_manifests = [], busybox = None, host_javabase = None): """Generate compiled resources class jar. Args: ctx: The context. out_class_jar: File. The output class jar file. r_txt: File. The resource IDs outputted by linking resources in text. manifest: File. The primary AndroidManifest.xml. package_for_r: String. The Java package for the generated R class files. final_fields: Bool. Whether fields get declared as final. busybox: FilesToRunProvider. The ResourceBusyBox executable or FilesToRunprovider host_javabase: A Target. The host javabase. """ args = ctx.actions.args() args.add("--tool", "GENERATE_BINARY_R") args.add("--") args.add("--primaryRTxt", r_txt) args.add("--primaryManifest", manifest) args.add("--packageForR", package_for_r) args.add_all( resources_nodes, map_each = _make_generate_binay_r_flags, before_each = "--library", ) if final_fields: args.add("--finalFields") else: args.add("--nofinalFields") # TODO(b/154003916): support transitive "--library transitive_r_txt_path,transitive_manifest_path" flags args.add("--classJarOutput", out_class_jar) args.add("--targetLabel", str(ctx.label)) _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, arguments = [args], inputs = depset([r_txt, manifest], transitive = transitive_r_txts + transitive_manifests), outputs = [out_class_jar], mnemonic = "StarlarkRClassGenerator", progress_message = "Generating R classes", ) def _make_aar( ctx, out_aar = None, assets = [], assets_dir = None, resource_files = [], class_jar = None, r_txt = None, manifest = None, proguard_specs = [], should_throw_on_conflict = False, busybox = None, host_javabase = None): """Generate an android archive file. Args: ctx: The context. out_aar: File. The output AAR file. assets: sequence of Files. A list of Android assets files to be processed. assets_dir: String. The name of the assets directory. resource_files: A list of Files. The resource files. class_jar: File. The class jar file. r_txt: File. The resource IDs outputted by linking resources in text. manifest: File. The primary AndroidManifest.xml. proguard_specs: List of File. The proguard spec files. busybox: FilesToRunProvider. The ResourceBusyBox executable or FilesToRunprovider host_javabase: A Target. The host javabase. should_throw_on_conflict: A boolean. Determines whether an error should be thrown when a resource conflict occurs. """ args = ctx.actions.args() args.add("--tool", "GENERATE_AAR") args.add("--") args.add( "--mainData", _make_resources_flag( manifest = manifest, assets = assets, assets_dir = assets_dir, resource_files = resource_files, ), ) args.add("--manifest", manifest) args.add("--rtxt", r_txt) args.add("--classes", class_jar) args.add("--aarOutput", out_aar) args.add_all(proguard_specs, before_each = "--proguardSpec") if should_throw_on_conflict: args.add("--throwOnResourceConflict") _java.run( ctx = ctx, host_javabase = host_javabase, executable = busybox, arguments = [args], inputs = ( resource_files + assets + proguard_specs + [r_txt, manifest, class_jar] ), outputs = [out_aar], mnemonic = "StarlarkAARGenerator", progress_message = "Generating AAR package for %s" % ctx.label, ) busybox = struct( compile = _compile, merge_compiled = _merge_compiled, validate_and_link = _validate_and_link, merge_manifests = _merge_manifests, package = _package, parse = _parse, merge_assets = _merge_assets, make_resources_flag = _make_resources_flag, process_databinding = _process_databinding, generate_binary_r = _generate_binary_r, make_aar = _make_aar, # Exposed for testing mergee_manifests_flag = _mergee_manifests_flag, get_unique_res_dirs = _get_unique_res_dirs, sanitize_assets_dir = _sanitize_assets_dir, extract_filters = _extract_filters, )