| # 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, | |
| package_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 = [], | |
| resource_apks = depset(), | |
| nocompress_extensions = [], | |
| proto_format = False, | |
| shrink_resource_cycles = 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. | |
| package_id: An optional integer in [2,255]. This is the prefix byte for | |
| all generated resource IDs, defaults to 0x7F (127). 1 is reserved by the | |
| framework, and some builds are known to crash when given IDs > 127. | |
| Shared libraries are also assigned monotonically increasing IDs in | |
| [2,126], so care should be taken that there is room at the lower end. | |
| 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. | |
| resource_apks: Depset of resource only apk files to link against. | |
| 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. | |
| shrink_resource_cycles: Boolean, flag that enables more shrinking of | |
| code and resources by instructing AAPT2 to emit conditional Proguard keep rules. | |
| 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 package_id: | |
| args.add("--packageId", package_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 shrink_resource_cycles: | |
| args.add("--conditionalKeepRules=yes") | |
| if version_name: | |
| args.add("--versionName", version_name) | |
| if version_code: | |
| args.add("--versionCode", version_code) | |
| if java_package: | |
| args.add("--packageForR", java_package) | |
| args.add_joined( | |
| "--resourceApks", | |
| resource_apks, | |
| join_with = ":", | |
| ) | |
| transitive_input_files.append(resource_apks) | |
| _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, | |
| resource_apks = [], | |
| 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. | |
| resource_apks: List of direct resource only apk files. | |
| 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) | |
| args.add_joined( | |
| "--resourceApks", | |
| resource_apks, | |
| join_with = ":", | |
| ) | |
| input_files.extend(resource_apks) | |
| _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] if manifest else [] | |
| 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("--") | |
| if manifest: | |
| 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) | |
| if java_package: | |
| 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) | |
| if package_for_r: | |
| 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)) | |
| args.use_param_file("@%s") | |
| _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, | |
| ) |