1# Copyright 2019 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Bazel ResourcesBusyBox Commands.""" 16 17load(":java.bzl", _java = "java") 18 19_ANDROID_RESOURCES_STRICT_DEPS = "android_resources_strict_deps" 20 21def _sanitize_assets_dir(assets_dir): 22 sanitized_assets_dir = "/".join( 23 [ 24 part 25 for part in assets_dir.split("/") 26 if part != "" and part != "." 27 ], 28 ) 29 30 return "/" + sanitized_assets_dir if assets_dir.startswith("/") else sanitized_assets_dir 31 32def _get_unique_assets_dirs(assets, assets_dir): 33 """Find the unique assets directories, partitioned by assets_dir. 34 35 Args: 36 assets: A list of Files. List of asset files to process. 37 assets_dir: String. String giving the path to the files in assets. 38 39 Returns: 40 A list of short_paths representing unique asset dirs. 41 """ 42 if not assets: 43 return [] 44 45 dirs = dict() 46 47 assets_dir = _sanitize_assets_dir(assets_dir) 48 if assets_dir: 49 partition_by = "/%s/" % assets_dir.strip("/") 50 for f in assets: 51 if f.is_directory and f.path.endswith(partition_by[:-1]): 52 # If f is a directory, check if its path ends with the assets_dir. 53 dirs[f.path] = True 54 elif f.is_directory and "_aar/unzipped" in f.path: 55 # Assets from an aar_import rule are extracted in a 56 # "assets" subdirectory of the given path 57 dirs["%s/assets" % f.path] = True 58 else: 59 # Partition to remove subdirectories beneath assets_dir 60 # Also removes the trailing / 61 dirs["".join(f.path.rpartition(partition_by)[:2])[:-1]] = True 62 else: 63 # Use the dirname of the generating target if no assets_dir. 64 for f in assets: 65 if f.is_source: 66 dirs[f.owner.package] = True 67 else: 68 # Prepend the root path for generated files. 69 dirs[f.root.path + "/" + f.owner.package] = True 70 return dirs.keys() 71 72def _get_unique_res_dirs(resource_files): 73 """Find the unique res dirs. 74 75 Args: 76 resource_files: A list of Files. A list of resource_files. 77 78 Returns: 79 A list of short_paths representing unique res dirs from the given resource files. 80 """ 81 dirs = dict() 82 for f in resource_files: 83 if f.is_directory: 84 dirs[f.path] = True 85 else: 86 dirs[f.dirname.rpartition("/" + f.dirname.split("/")[-1])[0]] = True 87 return dirs.keys() 88 89def _make_serialized_resources_flag( 90 assets = [], 91 assets_dir = None, 92 resource_files = [], 93 label = "", 94 symbols = None): 95 return ";".join( 96 [ 97 "#".join(_get_unique_res_dirs(resource_files)), 98 "#".join(_get_unique_assets_dirs(assets, assets_dir)), 99 label, 100 symbols.path if symbols else "", 101 ], 102 ).rstrip(":") 103 104def _make_resources_flag( 105 assets = [], 106 assets_dir = None, 107 resource_files = [], 108 manifest = None, 109 r_txt = None, 110 symbols = None): 111 return ":".join( 112 [ 113 "#".join(_get_unique_res_dirs(resource_files)), 114 "#".join(_get_unique_assets_dirs(assets, assets_dir)), 115 manifest.path if manifest else "", 116 r_txt.path if r_txt else "", 117 symbols.path if symbols else "", 118 ], 119 ) 120 121def _path(f): 122 return f.path 123 124def _make_package_resources_flags(resources_node): 125 if not (resources_node.manifest and resources_node.r_txt and resources_node.compiled_resources): 126 return None 127 flag = _make_resources_flag( 128 resource_files = resources_node.resource_files.to_list(), 129 assets = resources_node.assets.to_list(), 130 assets_dir = resources_node.assets_dir, 131 manifest = resources_node.manifest, 132 r_txt = resources_node.r_txt, 133 symbols = resources_node.compiled_resources, 134 ) 135 return flag 136 137def _make_package_assets_flags(resources_node): 138 assets = resources_node.assets.to_list() 139 if not assets: 140 return None 141 return _make_serialized_resources_flag( 142 assets = assets, 143 assets_dir = resources_node.assets_dir, 144 label = str(resources_node.label), 145 symbols = resources_node.compiled_assets, 146 ) 147 148def _extract_filters( 149 raw_list): 150 """Extract densities and resource_configuration filters from raw string lists. 151 152 In BUILD files, string lists can be represented as a list of strings, a single comma-separated 153 string, or a combination of both. This method outputs a single list of individual string values, 154 which can then be passed directly to resource processing actions. Empty strings are removed and 155 the final list is sorted. 156 157 Args: 158 raw_list: List of strings. The raw densities or resource configuration filters. 159 160 Returns: 161 List of strings extracted from the raw list. 162 """ 163 out_filters = [] 164 for item in raw_list: 165 if "," in item: 166 item_list = item.split(",") 167 for entry in item_list: 168 stripped_entry = entry.strip() 169 if stripped_entry: 170 out_filters.append(stripped_entry) 171 elif item: 172 out_filters.append(item) 173 return sorted(out_filters) 174 175def _package( 176 ctx, 177 out_r_src_jar = None, 178 out_r_txt = None, 179 out_symbols = None, 180 out_manifest = None, 181 out_proguard_cfg = None, 182 out_main_dex_proguard_cfg = None, 183 out_resource_files_zip = None, 184 out_file = None, 185 package_type = None, 186 java_package = None, 187 manifest = None, 188 assets = [], 189 assets_dir = None, 190 resource_files = [], 191 resource_configs = None, 192 densities = [], 193 application_id = None, 194 direct_resources_nodes = [], 195 transitive_resources_nodes = [], 196 transitive_manifests = [], 197 transitive_assets = [], 198 transitive_compiled_assets = [], 199 transitive_resource_files = [], 200 transitive_compiled_resources = [], 201 transitive_r_txts = [], 202 additional_apks_to_link_against = [], 203 nocompress_extensions = [], 204 proto_format = False, 205 version_name = None, 206 version_code = None, 207 android_jar = None, 208 aapt = None, 209 busybox = None, 210 host_javabase = None, 211 should_throw_on_conflict = True, # TODO: read this from allowlist at caller 212 debug = True): # TODO: we will set this to false in prod builds 213 """Packages the compiled Android Resources with AAPT. 214 215 Args: 216 ctx: The context. 217 out_r_src_jar: A File. The R.java outputted by linking resources in a srcjar. 218 out_r_txt: A File. The resource IDs outputted by linking resources in text. 219 out_symbols: A File. The output zip containing compiled resources. 220 out_manifest: A File. The output processed manifest. 221 out_proguard_cfg: A File. The proguard config to be generated. 222 out_main_dex_proguard_cfg: A File. The main dex proguard config to be generated. 223 out_resource_files_zip: A File. The resource files zipped by linking resources. 224 out_file: A File. The Resource APK outputted by linking resources. 225 package_type: A string. The configuration type to use when packaging. 226 java_package: A string. The Java package for the generated R.java. 227 manifest: A File. The AndroidManifest.xml. 228 assets: sequence of Files. A list of Android assets files to be processed. 229 assets_dir: String. The name of the assets directory. 230 resource_files: A list of Files. The resource files. 231 resource_configs: A list of strings. The list of resource configuration 232 filters. 233 densities: A list of strings. The list of screen densities to filter for when 234 building the apk. 235 application_id: An optional string. The applicationId set in manifest values. 236 direct_resources_nodes: Depset of ResourcesNodeInfo providers. The set of 237 ResourcesNodeInfo from direct dependencies. 238 transitive_resources_nodes: Depset of ResourcesNodeInfo providers. The set 239 of ResourcesNodeInfo from transitive dependencies (not including directs). 240 transitive_manifests: List of Depsets. Depsets contain all transitive manifests. 241 transitive_assets: List of Depsets. Depsets contain all transitive assets. 242 transitive_compiled_assets: List of Depsets. Depsets contain all transitive 243 compiled_assets. 244 transitive_resource_files: List of Depsets. Depsets contain all transitive 245 resource files. 246 transitive_compiled_resources: List of Depsets. Depsets contain all transitive 247 compiled_resources. 248 transitive_r_txts: List of Depsets. Depsets contain all transitive R txt files. 249 additional_apks_to_link_against: A list of Files. Additional APKs to link 250 against. Optional. 251 nocompress_extensions: A list of strings. File extension to leave uncompressed 252 in the apk. 253 proto_format: Boolean, whether to generate the resource table in proto format. 254 version_name: A string. The version name to stamp the generated manifest with. Optional. 255 version_code: A string. The version code to stamp the generated manifest with. Optional. 256 android_jar: A File. The Android Jar. 257 aapt: A FilesToRunProvider. The AAPT executable. 258 busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. 259 host_javabase: Target. The host javabase. 260 should_throw_on_conflict: A boolean. Determines whether an error should be thrown 261 when a resource conflict occurs. 262 debug: A boolean. Determines whether to enable debugging. 263 """ 264 if not manifest: 265 fail("No manifest given, the manifest is mandatory.") 266 267 direct_data_flag = [] 268 direct_compiled_resources = [] 269 270 output_files = [] 271 input_files = [] 272 transitive_input_files = [] 273 274 args = ctx.actions.args() 275 args.use_param_file("@%s") 276 args.add("--tool", "AAPT2_PACKAGE") 277 args.add("--") 278 args.add("--aapt2", aapt.executable) 279 args.add_joined( 280 "--data", 281 transitive_resources_nodes, 282 map_each = _make_package_resources_flags, 283 join_with = ",", 284 ) 285 args.add_joined( 286 "--directData", 287 direct_resources_nodes, 288 map_each = _make_package_resources_flags, 289 join_with = ",", 290 ) 291 args.add_joined( 292 "--directAssets", 293 direct_resources_nodes, 294 map_each = _make_package_assets_flags, 295 join_with = "&", 296 omit_if_empty = True, 297 ) 298 args.add_joined( 299 "--assets", 300 transitive_resources_nodes, 301 map_each = _make_package_assets_flags, 302 join_with = "&", 303 omit_if_empty = True, 304 ) 305 transitive_input_files.extend(transitive_resource_files) 306 transitive_input_files.extend(transitive_assets) 307 transitive_input_files.extend(transitive_compiled_assets) 308 transitive_input_files.extend(transitive_compiled_resources) 309 transitive_input_files.extend(transitive_manifests) 310 transitive_input_files.extend(transitive_r_txts) 311 args.add( 312 "--primaryData", 313 _make_resources_flag( 314 manifest = manifest, 315 assets = assets, 316 assets_dir = assets_dir, 317 resource_files = resource_files, 318 ), 319 ) 320 input_files.append(manifest) 321 input_files.extend(resource_files) 322 input_files.extend(assets) 323 args.add("--androidJar", android_jar) 324 input_files.append(android_jar) 325 args.add("--rOutput", out_r_txt) 326 output_files.append(out_r_txt) 327 if out_symbols: 328 args.add("--symbolsOut", out_symbols) 329 output_files.append(out_symbols) 330 args.add("--srcJarOutput", out_r_src_jar) 331 output_files.append(out_r_src_jar) 332 if out_proguard_cfg: 333 args.add("--proguardOutput", out_proguard_cfg) 334 output_files.append(out_proguard_cfg) 335 if out_main_dex_proguard_cfg: 336 args.add("--mainDexProguardOutput", out_main_dex_proguard_cfg) 337 output_files.append(out_main_dex_proguard_cfg) 338 args.add("--manifestOutput", out_manifest) 339 output_files.append(out_manifest) 340 if out_resource_files_zip: 341 args.add("--resourcesOutput", out_resource_files_zip) 342 output_files.append(out_resource_files_zip) 343 if out_file: 344 args.add("--packagePath", out_file) 345 output_files.append(out_file) 346 args.add("--useAaptCruncher=no") # Unnecessary, used for AAPT1 only but added here to minimize diffs. 347 if package_type: 348 args.add("--packageType", package_type) 349 if debug: 350 args.add("--debug") 351 if should_throw_on_conflict: 352 args.add("--throwOnResourceConflict") 353 if resource_configs: 354 args.add_joined("--resourceConfigs", _extract_filters(resource_configs), join_with = ",") 355 if densities: 356 args.add_joined("--densities", _extract_filters(densities), join_with = ",") 357 if application_id: 358 args.add("--applicationId", application_id) 359 if additional_apks_to_link_against: 360 args.add_joined( 361 "--additionalApksToLinkAgainst", 362 additional_apks_to_link_against, 363 join_with = ",", 364 map_each = _path, 365 ) 366 input_files.extend(additional_apks_to_link_against) 367 if nocompress_extensions: 368 args.add_joined("--uncompressedExtensions", nocompress_extensions, join_with = ",") 369 if proto_format: 370 args.add("--resourceTableAsProto") 371 if version_name: 372 args.add("--versionName", version_name) 373 if version_code: 374 args.add("--versionCode", version_code) 375 args.add("--packageForR", java_package) 376 377 _java.run( 378 ctx = ctx, 379 host_javabase = host_javabase, 380 executable = busybox, 381 tools = [aapt], 382 arguments = [args], 383 inputs = depset(input_files, transitive = transitive_input_files), 384 outputs = output_files, 385 mnemonic = "PackageAndroidResources", 386 progress_message = "Packaging Android Resources in %s" % ctx.label, 387 ) 388 389def _parse( 390 ctx, 391 out_symbols = None, 392 assets = [], 393 assets_dir = None, 394 busybox = None, 395 host_javabase = None): 396 """Parses Android assets. 397 398 Args: 399 ctx: The context. 400 out_symbols: A File. The output bin containing parsed assets. 401 assets: sequence of Files. A list of Android assets files to be processed. 402 assets_dir: String. The name of the assets directory. 403 busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. 404 host_javabase: Target. The host javabase. 405 """ 406 args = ctx.actions.args() 407 args.use_param_file("@%s") 408 args.add("--tool", "PARSE") 409 args.add("--") 410 args.add( 411 "--primaryData", 412 _make_resources_flag( 413 assets = assets, 414 assets_dir = assets_dir, 415 ), 416 ) 417 args.add("--output", out_symbols) 418 419 _java.run( 420 ctx = ctx, 421 host_javabase = host_javabase, 422 executable = busybox, 423 arguments = [args], 424 inputs = assets, 425 outputs = [out_symbols], 426 mnemonic = "ParseAndroidResources", 427 progress_message = "Parsing Android Resources in %s" % out_symbols.short_path, 428 ) 429 430def _make_merge_assets_flags(resources_node): 431 assets = resources_node.assets.to_list() 432 if not (assets or resources_node.assets_dir): 433 return None 434 return _make_serialized_resources_flag( 435 assets = assets, 436 assets_dir = resources_node.assets_dir, 437 label = str(resources_node.label), 438 symbols = resources_node.assets_symbols, 439 ) 440 441def _merge_assets( 442 ctx, 443 out_assets_zip = None, 444 assets = [], 445 assets_dir = None, 446 symbols = None, 447 transitive_assets = [], 448 transitive_assets_symbols = [], 449 direct_resources_nodes = [], 450 transitive_resources_nodes = [], 451 busybox = None, 452 host_javabase = None): 453 """Merges Android assets. 454 455 Args: 456 ctx: The context. 457 out_assets_zip: A File. 458 assets: sequence of Files. A list of Android assets files to be processed. 459 assets_dir: String. The name of the assets directory. 460 symbols: A File. The parsed assets. 461 transitive_assets: Sequence of Depsets. The list of transitive 462 assets from deps. 463 transitive_assets_symbols: Sequence of Depsets. The list of 464 transitive assets_symbols files from deps. 465 direct_resources_nodes: Sequence of ResourcesNodeInfo providers. The list 466 of ResourcesNodeInfo providers that are direct depencies. 467 transitive_resources_nodes: Sequence of ResourcesNodeInfo providers. The 468 list of ResourcesNodeInfo providers that are transitive depencies. 469 busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. 470 host_javabase: Target. The host javabase. 471 """ 472 args = ctx.actions.args() 473 args.use_param_file("@%s") 474 args.add("--tool", "MERGE_ASSETS") 475 args.add("--") 476 args.add("--assetsOutput", out_assets_zip) 477 args.add( 478 "--primaryData", 479 _make_serialized_resources_flag( 480 assets = assets, 481 assets_dir = assets_dir, 482 label = str(ctx.label), 483 symbols = symbols, 484 ), 485 ) 486 args.add_joined( 487 "--directData", 488 direct_resources_nodes, 489 map_each = _make_merge_assets_flags, 490 join_with = "&", 491 ) 492 args.add_joined( 493 "--data", 494 transitive_resources_nodes, 495 map_each = _make_merge_assets_flags, 496 join_with = "&", 497 ) 498 499 _java.run( 500 ctx = ctx, 501 host_javabase = host_javabase, 502 executable = busybox, 503 arguments = [args], 504 inputs = depset( 505 assets + [symbols], 506 transitive = transitive_assets + transitive_assets_symbols, 507 ), 508 outputs = [out_assets_zip], 509 mnemonic = "MergeAndroidAssets", 510 progress_message = 511 "Merging Android Assets in %s" % out_assets_zip.short_path, 512 ) 513 514def _validate_and_link( 515 ctx, 516 out_r_src_jar = None, 517 out_r_txt = None, 518 out_file = None, 519 compiled_resources = None, 520 transitive_compiled_resources = depset(), 521 java_package = None, 522 manifest = None, 523 android_jar = None, 524 busybox = None, 525 host_javabase = None, 526 aapt = None): 527 """Links compiled Android Resources with AAPT. 528 529 Args: 530 ctx: The context. 531 out_r_src_jar: A File. The R.java outputted by linking resources in a srcjar. 532 out_r_txt: A File. The resource IDs outputted by linking resources in text. 533 out_file: A File. The Resource APK outputted by linking resources. 534 compiled_resources: A File. The symbols.zip of compiled resources for 535 this target. 536 transitive_compiled_resources: Depset of Files. The symbols.zip of the 537 compiled resources from the transitive dependencies of this target. 538 java_package: A string. The Java package for the generated R.java. 539 manifest: A File. The AndroidManifest.xml. 540 android_jar: A File. The Android Jar. 541 busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. 542 host_javabase: Target. The host javabase. 543 aapt: A FilesToRunProvider. The AAPT executable. 544 """ 545 output_files = [] 546 input_files = [android_jar] 547 transitive_input_files = [] 548 549 # Retrieves the list of files at runtime when a directory is passed. 550 args = ctx.actions.args() 551 args.use_param_file("@%s") 552 args.add("--tool", "LINK_STATIC_LIBRARY") 553 args.add("--") 554 args.add("--aapt2", aapt.executable) 555 args.add("--libraries", android_jar) 556 if compiled_resources: 557 args.add("--compiled", compiled_resources) 558 input_files.append(compiled_resources) 559 args.add_joined( 560 "--compiledDep", 561 transitive_compiled_resources, 562 join_with = ":", 563 ) 564 transitive_input_files.append(transitive_compiled_resources) 565 args.add("--manifest", manifest) 566 input_files.append(manifest) 567 if java_package: 568 args.add("--packageForR", java_package) 569 args.add("--sourceJarOut", out_r_src_jar) 570 output_files.append(out_r_src_jar) 571 args.add("--rTxtOut", out_r_txt) 572 output_files.append(out_r_txt) 573 args.add("--staticLibraryOut", out_file) 574 output_files.append(out_file) 575 576 _java.run( 577 ctx = ctx, 578 host_javabase = host_javabase, 579 executable = busybox, 580 tools = [aapt], 581 arguments = [args], 582 inputs = depset(input_files, transitive = transitive_input_files), 583 outputs = output_files, 584 mnemonic = "LinkAndroidResources", 585 progress_message = 586 "Linking Android Resources in " + out_file.short_path, 587 ) 588 589def _compile( 590 ctx, 591 out_file = None, 592 assets = [], 593 assets_dir = None, 594 resource_files = [], 595 busybox = None, 596 aapt = None, 597 host_javabase = None): 598 """Compile and store resources in a single archive. 599 600 Args: 601 ctx: The context. 602 out_file: File. The output zip containing compiled resources. 603 resource_files: A list of Files. The list of resource files or directories 604 assets: A list of Files. The list of assets files or directories 605 to process. 606 assets_dir: String. The name of the assets directory. 607 busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. 608 aapt: AAPT. Tool for compiling resources. 609 host_javabase: Target. The host javabase. 610 """ 611 if not out_file: 612 fail("No output directory specified.") 613 614 # Retrieves the list of files at runtime when a directory is passed. 615 args = ctx.actions.args() 616 args.use_param_file("@%s") 617 args.add("--tool", "COMPILE_LIBRARY_RESOURCES") 618 args.add("--") 619 args.add("--aapt2", aapt.executable) 620 args.add( 621 "--resources", 622 _make_resources_flag( 623 resource_files = resource_files, 624 assets = assets, 625 assets_dir = assets_dir, 626 ), 627 ) 628 args.add("--output", out_file) 629 630 _java.run( 631 ctx = ctx, 632 host_javabase = host_javabase, 633 executable = busybox, 634 tools = [aapt], 635 arguments = [args], 636 inputs = resource_files + assets, 637 outputs = [out_file], 638 mnemonic = "CompileAndroidResources", 639 progress_message = "Compiling Android Resources in %s" % out_file.short_path, 640 ) 641 642def _make_merge_compiled_flags(resources_node_info): 643 if not resources_node_info.compiled_resources: 644 return None 645 return _make_serialized_resources_flag( 646 label = str(resources_node_info.label), 647 symbols = resources_node_info.compiled_resources, 648 ) 649 650def _merge_compiled( 651 ctx, 652 out_class_jar = None, 653 out_manifest = None, 654 out_aapt2_r_txt = None, 655 java_package = None, 656 manifest = None, 657 compiled_resources = None, 658 direct_resources_nodes = [], 659 transitive_resources_nodes = [], 660 direct_compiled_resources = depset(), 661 transitive_compiled_resources = depset(), 662 android_jar = None, 663 busybox = None, 664 host_javabase = None): 665 """Merges the compile resources. 666 667 Args: 668 ctx: The context. 669 out_class_jar: A File. The compiled R.java outputted by linking resources. 670 out_manifest: A File. The list of resource files or directories 671 out_aapt2_r_txt: A File. The resource IDs outputted by linking resources in text. 672 java_package: A string. The Java package for the generated R.java. 673 manifest: A File. The AndroidManifest.xml. 674 compiled_resources: A File. The symbols.zip of compiled resources for this target. 675 direct_resources_nodes: Sequence of ResourcesNodeInfo providers. The list 676 of ResourcesNodeInfo providers that are direct depencies. 677 transitive_resources_nodes: Sequence of ResourcesNodeInfo providers. The 678 list of ResourcesNodeInfo providers that are transitive depencies. 679 direct_compiled_resources: Depset of Files. A depset of symbols.zip of 680 compiled resources from direct dependencies. 681 transitive_compiled_resources: Depset of Files. A depset of symbols.zip of 682 compiled resources from transitive dependencies. 683 android_jar: A File. The Android Jar. 684 busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. 685 host_javabase: Target. The host javabase. 686 """ 687 output_files = [] 688 input_files = [android_jar] 689 transitive_input_files = [] 690 691 args = ctx.actions.args() 692 args.use_param_file("@%s") 693 args.add("--tool", "MERGE_COMPILED") 694 args.add("--") 695 args.add("--classJarOutput", out_class_jar) 696 output_files.append(out_class_jar) 697 args.add("--targetLabel", ctx.label) 698 args.add("--manifestOutput", out_manifest) 699 output_files.append(out_manifest) 700 args.add("--rTxtOut", out_aapt2_r_txt) 701 output_files.append(out_aapt2_r_txt) 702 args.add("--androidJar", android_jar) 703 args.add("--primaryManifest", manifest) 704 input_files.append(manifest) 705 if java_package: 706 args.add("--packageForR", java_package) 707 args.add( 708 "--primaryData", 709 _make_serialized_resources_flag( 710 label = str(ctx.label), 711 symbols = compiled_resources, 712 ), 713 ) 714 input_files.append(compiled_resources) 715 args.add_joined( 716 "--directData", 717 direct_resources_nodes, 718 map_each = _make_merge_compiled_flags, 719 join_with = "&", 720 ) 721 transitive_input_files.append(direct_compiled_resources) 722 if _ANDROID_RESOURCES_STRICT_DEPS in ctx.disabled_features: 723 args.add_joined( 724 "--data", 725 transitive_resources_nodes, 726 map_each = _make_merge_compiled_flags, 727 join_with = "&", 728 ) 729 transitive_input_files.append(transitive_compiled_resources) 730 731 _java.run( 732 ctx = ctx, 733 host_javabase = host_javabase, 734 executable = busybox, 735 arguments = [args], 736 inputs = depset(input_files, transitive = transitive_input_files), 737 outputs = output_files, 738 mnemonic = "StarlarkMergeCompiledAndroidResources", 739 progress_message = 740 "Merging compiled Android Resources in " + out_class_jar.short_path, 741 ) 742 743def _escape_mv(s): 744 """Escapes `:` and `,` in manifest values so they can be used as a busybox flag.""" 745 return s.replace(":", "\\:").replace(",", "\\,") 746 747def _owner_label(file): 748 return "//" + file.owner.package + ":" + file.owner.name 749 750# We need to remove the "/_migrated/" path segment from file paths in order for sorting to 751# match the order of the native manifest merging action. 752def _manifest_short_path(manifest): 753 return manifest.short_path.replace("/_migrated/", "/") 754 755def _mergee_manifests_flag(manifests): 756 ordered_manifests = sorted(manifests.to_list(), key = _manifest_short_path) 757 entries = [] 758 for manifest in ordered_manifests: 759 label = _owner_label(manifest).replace(":", "\\:") 760 entries.append((manifest.path + ":" + label).replace(",", "\\,")) 761 flag_entry = ",".join(entries) 762 if not flag_entry: 763 return None 764 return flag_entry 765 766def _merge_manifests( 767 ctx, 768 out_file = None, 769 out_log_file = None, 770 merge_type = "APPLICATION", 771 manifest = None, 772 mergee_manifests = depset(), 773 manifest_values = None, 774 java_package = None, 775 busybox = None, 776 host_javabase = None): 777 """Merge multiple AndroidManifest.xml files into a single one. 778 779 Args: 780 ctx: The context. 781 out_file: A File. The output merged manifest. 782 out_log_file: A File. The output log from the merge tool. 783 merge_type: A string, either APPLICATION or LIBRARY. Type of merging. 784 manifest: A File. The primary AndroidManifest.xml. 785 mergee_manifests: A depset of Files. All transitive manifests to be merged. 786 manifest_values: A dictionary. Manifest values to substitute. 787 java_package: A string. Custom java package to insert in manifest package attribute. 788 busybox: A FilesToRunProvider. The ResourceProcessorBusyBox executable. 789 host_javabase: Target. The host javabase. 790 """ 791 if merge_type not in ["APPLICATION", "LIBRARY"]: 792 fail("Unexpected manifest merge type: " + merge_type) 793 794 outputs = [out_file] 795 directs = [manifest] 796 transitives = [mergee_manifests] 797 798 # Args for busybox 799 args = ctx.actions.args() 800 args.use_param_file("@%s", use_always = True) 801 args.add("--tool", "MERGE_MANIFEST") 802 args.add("--") 803 args.add("--manifest", manifest) 804 args.add_all( 805 "--mergeeManifests", 806 [mergee_manifests], 807 map_each = _mergee_manifests_flag, 808 ) 809 if manifest_values: 810 args.add( 811 "--manifestValues", 812 ",".join(["%s:%s" % (_escape_mv(k), _escape_mv(v)) for k, v in manifest_values.items()]), 813 ) 814 args.add("--mergeType", merge_type) 815 args.add("--customPackage", java_package) 816 args.add("--manifestOutput", out_file) 817 if out_log_file: 818 args.add("--log", out_log_file) 819 outputs.append(out_log_file) 820 821 _java.run( 822 ctx = ctx, 823 host_javabase = host_javabase, 824 executable = busybox, 825 arguments = [args], 826 inputs = depset(directs, transitive = transitives), 827 outputs = outputs, 828 mnemonic = "MergeManifests", 829 progress_message = "Merging Android Manifests in %s" % out_file.short_path, 830 ) 831 832def _process_databinding( 833 ctx, 834 out_databinding_info = None, 835 out_databinding_processed_resources = None, 836 databinding_resources_dirname = None, 837 resource_files = None, 838 java_package = None, 839 busybox = None, 840 host_javabase = None): 841 """Processes databinding for android_binary. 842 843 Processes databinding declarations over resources, populates the databinding layout 844 info file, and generates new resources with databinding expressions stripped out. 845 846 Args: 847 ctx: The context. 848 out_databinding_info: File. The output databinding layout info zip file. 849 out_databinding_processed_resources: List of Files. The generated databinding 850 processed resource files. 851 databinding_resources_dirname: String. The execution path to the directory where 852 the out_databinding_processed_resources are generated. 853 resource_files: List of Files. The resource files to be processed. 854 java_package: String. Java package for which java sources will be 855 generated. By default the package is inferred from the directory where 856 the BUILD file containing the rule is. 857 busybox: FilesToRunProvider. The ResourceBusyBox executable or 858 FilesToRunprovider 859 host_javabase: A Target. The host javabase. 860 """ 861 res_dirs = _get_unique_res_dirs(resource_files) 862 863 args = ctx.actions.args() 864 args.add("--tool", "PROCESS_DATABINDING") 865 args.add("--") 866 args.add("--output_resource_directory", databinding_resources_dirname) 867 args.add_all(res_dirs, before_each = "--resource_root") 868 args.add("--dataBindingInfoOut", out_databinding_info) 869 args.add("--appId", java_package) 870 871 _java.run( 872 ctx = ctx, 873 host_javabase = host_javabase, 874 executable = busybox, 875 arguments = [args], 876 inputs = resource_files, 877 outputs = [out_databinding_info] + out_databinding_processed_resources, 878 mnemonic = "StarlarkProcessDatabinding", 879 progress_message = "Processing data binding", 880 ) 881 882def _make_generate_binay_r_flags(resources_node): 883 if not (resources_node.r_txt or resources_node.manifest): 884 return None 885 return ",".join( 886 [ 887 resources_node.r_txt.path if resources_node.r_txt else "", 888 resources_node.manifest.path if resources_node.manifest else "", 889 ], 890 ) 891 892def _generate_binary_r( 893 ctx, 894 out_class_jar = None, 895 r_txt = None, 896 manifest = None, 897 package_for_r = None, 898 final_fields = None, 899 resources_nodes = depset(), 900 transitive_r_txts = [], 901 transitive_manifests = [], 902 busybox = None, 903 host_javabase = None): 904 """Generate compiled resources class jar. 905 906 Args: 907 ctx: The context. 908 out_class_jar: File. The output class jar file. 909 r_txt: File. The resource IDs outputted by linking resources in text. 910 manifest: File. The primary AndroidManifest.xml. 911 package_for_r: String. The Java package for the generated R class files. 912 final_fields: Bool. Whether fields get declared as final. 913 busybox: FilesToRunProvider. The ResourceBusyBox executable or 914 FilesToRunprovider 915 host_javabase: A Target. The host javabase. 916 """ 917 args = ctx.actions.args() 918 args.add("--tool", "GENERATE_BINARY_R") 919 args.add("--") 920 args.add("--primaryRTxt", r_txt) 921 args.add("--primaryManifest", manifest) 922 args.add("--packageForR", package_for_r) 923 args.add_all( 924 resources_nodes, 925 map_each = _make_generate_binay_r_flags, 926 before_each = "--library", 927 ) 928 if final_fields: 929 args.add("--finalFields") 930 else: 931 args.add("--nofinalFields") 932 933 # TODO(b/154003916): support transitive "--library transitive_r_txt_path,transitive_manifest_path" flags 934 args.add("--classJarOutput", out_class_jar) 935 args.add("--targetLabel", str(ctx.label)) 936 937 _java.run( 938 ctx = ctx, 939 host_javabase = host_javabase, 940 executable = busybox, 941 arguments = [args], 942 inputs = depset([r_txt, manifest], transitive = transitive_r_txts + transitive_manifests), 943 outputs = [out_class_jar], 944 mnemonic = "StarlarkRClassGenerator", 945 progress_message = "Generating R classes", 946 ) 947 948def _make_aar( 949 ctx, 950 out_aar = None, 951 assets = [], 952 assets_dir = None, 953 resource_files = [], 954 class_jar = None, 955 r_txt = None, 956 manifest = None, 957 proguard_specs = [], 958 should_throw_on_conflict = False, 959 busybox = None, 960 host_javabase = None): 961 """Generate an android archive file. 962 963 Args: 964 ctx: The context. 965 out_aar: File. The output AAR file. 966 assets: sequence of Files. A list of Android assets files to be processed. 967 assets_dir: String. The name of the assets directory. 968 resource_files: A list of Files. The resource files. 969 class_jar: File. The class jar file. 970 r_txt: File. The resource IDs outputted by linking resources in text. 971 manifest: File. The primary AndroidManifest.xml. 972 proguard_specs: List of File. The proguard spec files. 973 busybox: FilesToRunProvider. The ResourceBusyBox executable or 974 FilesToRunprovider 975 host_javabase: A Target. The host javabase. 976 should_throw_on_conflict: A boolean. Determines whether an error should be thrown 977 when a resource conflict occurs. 978 """ 979 args = ctx.actions.args() 980 args.add("--tool", "GENERATE_AAR") 981 args.add("--") 982 args.add( 983 "--mainData", 984 _make_resources_flag( 985 manifest = manifest, 986 assets = assets, 987 assets_dir = assets_dir, 988 resource_files = resource_files, 989 ), 990 ) 991 args.add("--manifest", manifest) 992 args.add("--rtxt", r_txt) 993 args.add("--classes", class_jar) 994 args.add("--aarOutput", out_aar) 995 args.add_all(proguard_specs, before_each = "--proguardSpec") 996 if should_throw_on_conflict: 997 args.add("--throwOnResourceConflict") 998 999 _java.run( 1000 ctx = ctx, 1001 host_javabase = host_javabase, 1002 executable = busybox, 1003 arguments = [args], 1004 inputs = ( 1005 resource_files + 1006 assets + 1007 proguard_specs + 1008 [r_txt, manifest, class_jar] 1009 ), 1010 outputs = [out_aar], 1011 mnemonic = "StarlarkAARGenerator", 1012 progress_message = "Generating AAR package for %s" % ctx.label, 1013 ) 1014 1015busybox = struct( 1016 compile = _compile, 1017 merge_compiled = _merge_compiled, 1018 validate_and_link = _validate_and_link, 1019 merge_manifests = _merge_manifests, 1020 package = _package, 1021 parse = _parse, 1022 merge_assets = _merge_assets, 1023 make_resources_flag = _make_resources_flag, 1024 process_databinding = _process_databinding, 1025 generate_binary_r = _generate_binary_r, 1026 make_aar = _make_aar, 1027 1028 # Exposed for testing 1029 mergee_manifests_flag = _mergee_manifests_flag, 1030 get_unique_res_dirs = _get_unique_res_dirs, 1031 sanitize_assets_dir = _sanitize_assets_dir, 1032 extract_filters = _extract_filters, 1033) 1034