From 8a779818758fbd7eaf813a66d62aaaba5a01ca3a Mon Sep 17 00:00:00 2001 From: Brentley Jones Date: Wed, 23 Oct 2024 17:06:17 -0500 Subject: [PATCH] Fix `apple_precompiled_resource_bundle` to process all types (#2567) Signed-off-by: Brentley Jones --- apple/internal/partials/resources.bzl | 23 +--- .../partials/support/resources_support.bzl | 127 +++++++++++++----- .../apple_precompiled_resource_bundle.bzl | 14 ++ apple/internal/resources.bzl | 69 ++++++---- doc/rules-resources.md | 17 ++- 5 files changed, 165 insertions(+), 85 deletions(-) diff --git a/apple/internal/partials/resources.bzl b/apple/internal/partials/resources.bzl index 2793132829..03468d7c78 100644 --- a/apple/internal/partials/resources.bzl +++ b/apple/internal/partials/resources.bzl @@ -55,7 +55,7 @@ load( ) load( "@build_bazel_rules_apple//apple/internal/partials/support:resources_support.bzl", - "resources_support", + "PROVIDER_TO_FIELD_ACTION", ) load( "@build_bazel_rules_apple//apple/internal/utils:bundle_paths.bzl", @@ -242,25 +242,6 @@ def _resources_partial_impl( if AppleResourceInfo in x ] - # Map of resource provider fields to a tuple that contains the method to use to process those - # resources and a boolean indicating whether the Swift module is required for that processing. - provider_field_to_action = { - "asset_catalogs": (resources_support.asset_catalogs, False), - "datamodels": (resources_support.datamodels, True), - "framework": (resources_support.apple_bundle(processor.location.framework), False), - "infoplists": (resources_support.infoplists, False), - "metals": (resources_support.metals, False), - "mlmodels": (resources_support.mlmodels, False), - "plists": (resources_support.plists_and_strings, False), - "pngs": (resources_support.pngs, False), - "processed": (resources_support.noop, False), - "storyboards": (resources_support.storyboards, True), - "strings": (resources_support.plists_and_strings, False), - "texture_atlases": (resources_support.texture_atlases, False), - "unprocessed": (resources_support.noop, False), - "xibs": (resources_support.xibs, True), - } - # List containing all the files that the processor will bundle in their # configured location. bundle_files = [] @@ -274,7 +255,7 @@ def _resources_partial_impl( locales_dropped = sets.make() def _deduplicated_field_handler(field, deduplicated): - processing_func, requires_swift_module = provider_field_to_action[field] + processing_func, requires_swift_module = PROVIDER_TO_FIELD_ACTION[field] for parent_dir, module_name, files in deduplicated: if locales_requested: locale = bundle_paths.locale_for_path(parent_dir) diff --git a/apple/internal/partials/support/resources_support.bzl b/apple/internal/partials/support/resources_support.bzl index 236f6aa0e1..9543ed6c39 100644 --- a/apple/internal/partials/support/resources_support.bzl +++ b/apple/internal/partials/support/resources_support.bzl @@ -68,10 +68,12 @@ def _compile_datamodels( xctoolrunner): "Compiles datamodels into mom files." output_files = [] + processed_origins = {} module_name = swift_module or label_name for datamodel_path, files in datamodel_groups.items(): - datamodel_name = paths.replace_extension(paths.basename(datamodel_path), "") + input_files = files.to_list() + datamodel_name = paths.replace_extension(paths.basename(datamodel_path), "") datamodel_parent = parent_dir if datamodel_path.endswith(".xcdatamodeld"): basename = datamodel_name + ".momd" @@ -90,10 +92,12 @@ def _compile_datamodels( file_name = datamodel_name + ".mom", ) + processed_origins[output_file.short_path] = [f.short_path for f in input_files] + resource_actions.compile_datamodels( actions = actions, datamodel_path = datamodel_path, - input_files = files.to_list(), + input_files = input_files, module_name = module_name, output_file = output_file, platform_prerequisites = platform_prerequisites, @@ -103,7 +107,7 @@ def _compile_datamodels( (processor.location.resource, datamodel_parent, depset(direct = [output_file])), ) - return output_files + return (output_files, processed_origins) def _compile_mappingmodels( *, @@ -116,7 +120,10 @@ def _compile_mappingmodels( xctoolrunner): """Compiles mapping models into cdm files.""" output_files = [] - for mappingmodel_path, input_files in mappingmodel_groups.items(): + processed_origins = {} + for mappingmodel_path, files in mappingmodel_groups.items(): + input_files = files.to_list() + compiled_model_name = paths.replace_extension(paths.basename(mappingmodel_path), ".cdm") output_file = intermediates.file( actions = actions, @@ -124,10 +131,11 @@ def _compile_mappingmodels( output_discriminator = output_discriminator, file_name = paths.join(parent_dir or "", compiled_model_name), ) + processed_origins[output_file.short_path] = [f.short_path for f in input_files] resource_actions.compile_mappingmodel( actions = actions, - input_files = input_files.to_list(), + input_files = input_files, mappingmodel_path = mappingmodel_path, output_file = output_file, platform_prerequisites = platform_prerequisites, @@ -138,7 +146,7 @@ def _compile_mappingmodels( (processor.location.resource, parent_dir, depset(direct = [output_file])), ) - return output_files + return (output_files, processed_origins) def _asset_catalogs( *, @@ -154,6 +162,7 @@ def _asset_catalogs( rule_label, **_kwargs): """Processes asset catalog files.""" + processed_origins = {} # Only merge the resulting plist for the top level bundle. For resource # bundles, skip generating the plist. @@ -192,6 +201,7 @@ def _asset_catalogs( output_discriminator = None, target_name = rule_label.name, ) + processed_origins[png_file.short_path] = f.short_path resource_actions.copy_png( actions = actions, input_file = f, @@ -217,9 +227,21 @@ def _asset_catalogs( xctoolrunner = apple_mac_toolchain_info.xctoolrunner, ) + asset_origin_short_paths = [f.short_path for f in asset_files] + processed_origins[assets_dir.short_path] = asset_origin_short_paths + if assets_plist: + processed_origins[assets_plist.short_path] = asset_origin_short_paths + return struct( - files = [(processor.location.resource, parent_dir, depset(direct = [assets_dir] + alternate_icons))], + files = [ + ( + processor.location.resource, + parent_dir, + depset(direct = [assets_dir] + alternate_icons), + ), + ], infoplists = infoplists, + processed_origins = processed_origins, ) def _datamodels( @@ -270,7 +292,11 @@ def _datamodels( attr = "resources", ) - output_files = list(_compile_datamodels( + output_files = [] + ( + compiled_datamodels, + datamodels_processed_origins, + ) = _compile_datamodels( actions = actions, datamodel_groups = datamodel_groups, label_name = rule_label.name, @@ -279,8 +305,12 @@ def _datamodels( platform_prerequisites = platform_prerequisites, swift_module = swift_module, xctoolrunner = apple_mac_toolchain_info.xctoolrunner, - )) - output_files.extend(_compile_mappingmodels( + ) + output_files.extend(compiled_datamodels) + ( + compiled_mappingmodels, + mappingmodels_processed_origins, + ) = _compile_mappingmodels( actions = actions, label_name = rule_label.name, output_discriminator = output_discriminator, @@ -288,9 +318,15 @@ def _datamodels( mappingmodel_groups = mappingmodel_groups, platform_prerequisites = platform_prerequisites, xctoolrunner = apple_mac_toolchain_info.xctoolrunner, - )) + ) + output_files.extend(compiled_mappingmodels) - return struct(files = output_files) + return struct( + files = output_files, + processed_origins = ( + datamodels_processed_origins | mappingmodels_processed_origins + ), + ) def _infoplists( *, @@ -326,9 +362,9 @@ def _infoplists( A struct containing a `files` field with tuples as described in processor.bzl, and an `infoplists` field with the plists that need to be merged for the root Info.plist """ + processed_origins = {} if parent_dir: input_files = files.to_list() - processed_origins = {} out_plist = intermediates.file( actions = actions, target_name = rule_label.name, @@ -354,7 +390,11 @@ def _infoplists( processed_origins = processed_origins, ) else: - return struct(files = [], infoplists = files.to_list()) + return struct( + files = [], + infoplists = files.to_list(), + processed_origins = processed_origins, + ) def _metals( *, @@ -381,6 +421,8 @@ def _metals( Returns: A struct containing a `files` field with tuples as described in processor.bzl. """ + input_files = files.to_list() + processed_origins = {} metallib_path = paths.join(parent_dir or "", output_filename) metallib_file = intermediates.file( actions = actions, @@ -388,9 +430,10 @@ def _metals( output_discriminator = None, target_name = rule_label.name, ) + processed_origins[metallib_file.short_path] = [f.short_path for f in input_files] resource_actions.compile_metals( actions = actions, - input_files = files.to_list(), + input_files = input_files, output_file = metallib_file, platform_prerequisites = platform_prerequisites, ) @@ -401,6 +444,7 @@ def _metals( parent_dir, depset(direct = [metallib_file]), )], + processed_origins = processed_origins, ) def _mlmodels( @@ -417,6 +461,7 @@ def _mlmodels( mlmodel_bundles = [] infoplists = [] + processed_origins = {} for file in files.to_list(): basename = file.basename @@ -432,6 +477,7 @@ def _mlmodels( output_discriminator = output_discriminator, file_name = paths.join(parent_dir or "", paths.replace_extension(basename, ".plist")), ) + processed_origins[output_plist.short_path] = [file.short_path] resource_actions.compile_mlmodel( actions = actions, @@ -454,6 +500,7 @@ def _mlmodels( return struct( files = mlmodel_bundles, infoplists = infoplists, + processed_origins = processed_origins, ) def _plists_and_strings( @@ -588,6 +635,7 @@ def _storyboards( # First, compile all the storyboard files and collect the output folders. compiled_storyboardcs = [] + processed_origins = {} for storyboard in files.to_list(): storyboardc_path = paths.join( # We append something at the end of the name to avoid having X.lproj names in the path. @@ -604,6 +652,7 @@ def _storyboards( output_discriminator = output_discriminator, dir_name = storyboardc_path, ) + processed_origins[storyboardc_dir.short_path] = [storyboard.short_path] resource_actions.compile_storyboard( actions = actions, input_file = storyboard, @@ -633,6 +682,7 @@ def _storyboards( files = [ (processor.location.resource, parent_dir, depset(direct = [linked_storyboard_dir])), ], + processed_origins = processed_origins, ) def _texture_atlases( @@ -652,7 +702,9 @@ def _texture_atlases( ) atlasc_files = [] + processed_origins = {} for atlas_path, files in atlases_groups.items(): + input_files = files.to_list() atlasc_path = paths.join( parent_dir or "", paths.replace_extension(paths.basename(atlas_path), ".atlasc"), @@ -663,9 +715,10 @@ def _texture_atlases( output_discriminator = output_discriminator, dir_name = atlasc_path, ) + processed_origins[atlasc_dir.short_path] = [f.short_path for f in input_files] resource_actions.compile_texture_atlas( actions = actions, - input_files = files, + input_files = input_files, input_path = atlas_path, output_dir = atlasc_dir, platform_prerequisites = platform_prerequisites, @@ -676,6 +729,7 @@ def _texture_atlases( files = [ (processor.location.resource, parent_dir, depset(direct = atlasc_files)), ], + processed_origins = processed_origins, ) def _xibs( @@ -692,6 +746,7 @@ def _xibs( """Processes Xib files.""" swift_module = swift_module or rule_label.name nib_files = [] + processed_origins = {} for file in files.to_list(): basename = paths.replace_extension(file.basename, "") out_path = paths.join("nibs", parent_dir or "", basename) @@ -701,6 +756,7 @@ def _xibs( output_discriminator = output_discriminator, dir_name = out_path, ) + processed_origins[out_dir.short_path] = [file.short_path] resource_actions.compile_xib( actions = actions, input_file = file, @@ -711,7 +767,10 @@ def _xibs( ) nib_files.append(out_dir) - return struct(files = [(processor.location.resource, parent_dir, depset(direct = nib_files))]) + return struct( + files = [(processor.location.resource, parent_dir, depset(direct = nib_files))], + processed_origins = processed_origins, + ) def _noop( *, @@ -732,6 +791,7 @@ def _apple_bundle(bundle_type): Args: bundle_type: The Apple bundle type to bundle for. + Returns: A function to register bundling of an Apple bundle. """ @@ -755,17 +815,22 @@ def _apple_bundle(bundle_type): return _bundle_at_location -resources_support = struct( - apple_bundle = _apple_bundle, - asset_catalogs = _asset_catalogs, - datamodels = _datamodels, - infoplists = _infoplists, - metals = _metals, - mlmodels = _mlmodels, - noop = _noop, - plists_and_strings = _plists_and_strings, - pngs = _pngs, - storyboards = _storyboards, - texture_atlases = _texture_atlases, - xibs = _xibs, -) +# Map of resource provider fields to a tuple that contains the method to use +# to process those resources and a boolean indicating whether the Swift +# module is required for that processing. +PROVIDER_TO_FIELD_ACTION = { + "asset_catalogs": (_asset_catalogs, False), + "datamodels": (_datamodels, True), + "framework": (_apple_bundle(processor.location.framework), False), + "infoplists": (_infoplists, False), + "metals": (_metals, False), + "mlmodels": (_mlmodels, False), + "plists": (_plists_and_strings, False), + "pngs": (_pngs, False), + "processed": (_noop, False), + "storyboards": (_storyboards, True), + "strings": (_plists_and_strings, False), + "texture_atlases": (_texture_atlases, False), + "unprocessed": (_noop, False), + "xibs": (_xibs, True), +} diff --git a/apple/internal/resource_rules/apple_precompiled_resource_bundle.bzl b/apple/internal/resource_rules/apple_precompiled_resource_bundle.bzl index 0ec2355bc5..77d62f64af 100644 --- a/apple/internal/resource_rules/apple_precompiled_resource_bundle.bzl +++ b/apple/internal/resource_rules/apple_precompiled_resource_bundle.bzl @@ -117,6 +117,18 @@ def _apple_precompiled_resource_bundle_impl(ctx): buckets = buckets, platform_prerequisites = platform_prerequisites, processing_owner = owner, + resource_types_to_process = [ + "asset_catalogs", + "datamodels", + "metals", + "mlmodels", + "plists", + "pngs", + "storyboards", + "strings", + "texture_atlases", + "xibs", + ], unowned_resources = unowned_resources, **process_args ), @@ -147,6 +159,7 @@ def _apple_precompiled_resource_bundle_impl(ctx): buckets = buckets, platform_prerequisites = platform_prerequisites, processing_owner = owner, + resource_types_to_process = ["strings", "plists"], unowned_resources = unowned_resources, **process_args ), @@ -177,6 +190,7 @@ def _apple_precompiled_resource_bundle_impl(ctx): buckets = buckets, platform_prerequisites = platform_prerequisites, processing_owner = owner, + resource_types_to_process = ["infoplists"], unowned_resources = unowned_resources, **process_args ), diff --git a/apple/internal/resources.bzl b/apple/internal/resources.bzl index ec07d7ef8c..a9e9ac57a6 100644 --- a/apple/internal/resources.bzl +++ b/apple/internal/resources.bzl @@ -85,21 +85,19 @@ load( ) load( "@build_bazel_rules_apple//apple/internal/partials/support:resources_support.bzl", - "resources_support", + "PROVIDER_TO_FIELD_ACTION", ) load( "@build_bazel_rules_apple//apple/internal/utils:bundle_paths.bzl", "bundle_paths", ) -_CACHEABLE_PROVIDER_FIELD_TO_ACTION = { - "infoplists": (resources_support.infoplists, False), - "plists": (resources_support.plists_and_strings, False), - "pngs": (resources_support.pngs, False), - "strings": (resources_support.plists_and_strings, False), -} - -_PROCESSED_FIELDS = _CACHEABLE_PROVIDER_FIELD_TO_ACTION.keys() +_CACHEABLE_PROVIDER_FIELDS = [ + "infoplists", + "plists", + "pngs", + "strings", +] def _get_attr_using_list(*, attr, nested_attr, split_attr_key = None): """Helper method to always get an attribute as a list within an existing list. @@ -446,38 +444,54 @@ def _process_bucketized_data( platform_prerequisites, processing_owner = None, product_type, + resource_types_to_process = _CACHEABLE_PROVIDER_FIELDS, rule_label, unowned_resources = []): - """Registers actions for cacheable resource types, given bucketized groupings of data. + """Registers actions for select resource types, given bucketized groupings of data. - This method performs the same actions as bucketize_data, and further iterates through a subset - of supported resource types to register actions to process them as necessary before returning an - AppleResourceInfo. This AppleResourceInfo has an additional field, called "processed", featuring - the expected outputs for each of the actions declared in this method. + This method performs the same actions as bucketize_data, and further + iterates through a subset of resource types to register actions to process + them as necessary before returning an AppleResourceInfo. This + AppleResourceInfo has an additional field, called "processed", featuring the + expected outputs for each of the actions declared in this method. Args: actions: The actions provider from `ctx.actions`. - apple_mac_toolchain_info: `struct` of tools from the shared Apple toolchain. - bucketized_owners: A list of tuples indicating the owner of each bucketized resource. - buckets: A dictionary with bucketized resources organized by resource type. + apple_mac_toolchain_info: `struct` of tools from the shared Apple + toolchain. + bucketized_owners: A list of tuples indicating the owner of each + bucketized resource. + buckets: A dictionary with bucketized resources organized by resource + type. bundle_id: The bundle ID to configure for this target. - output_discriminator: A string to differentiate between different target intermediate files - or `None`. - platform_prerequisites: Struct containing information on the platform being targeted. - processing_owner: An optional string that has a unique identifier to the target that should - own the resources. If an owner should be passed, it's usually equal to `str(ctx.label)`. - product_type: The product type identifier used to describe the current bundle type. + output_discriminator: A string to differentiate between different target + intermediate files or `None`. + platform_prerequisites: Struct containing information on the platform + being targeted. + processing_owner: An optional string that has a unique identifier to the + target that should own the resources. If an owner should be passed, + it's usually equal to `str(ctx.label)`. + product_type: The product type identifier used to describe the current + bundle type. + resource_types_to_process: A list of bucket types to process. rule_label: The label of the target being analyzed. unowned_resources: A list of "unowned" resources. Returns: - An AppleResourceInfo provider with resources bucketized according to type. + An AppleResourceInfo provider with resources bucketized according to + type. """ # Keep a list to reference what the processed files are based from. processed_origins = [] - for bucket_name, bucket_action in _CACHEABLE_PROVIDER_FIELD_TO_ACTION.items(): + field_to_action_map = {} + for field in resource_types_to_process: + action = PROVIDER_TO_FIELD_ACTION.get(field) + if action: + field_to_action_map[field] = action + + for bucket_name, bucket_action in field_to_action_map.items(): processed_field = buckets.pop(bucket_name, default = None) if not processed_field: continue @@ -492,6 +506,9 @@ def _process_bucketized_data( "output_discriminator": output_discriminator, "parent_dir": parent_dir, "platform_prerequisites": platform_prerequisites, + # If asset catalogs are being processed, it's not the top-level + # target, so we don't support setting the primary icon name. + "primary_icon_name": None, "product_type": product_type, "rule_label": rule_label, } @@ -910,7 +927,7 @@ def _deduplicate_field( if path_origins in processed_deduplication_list: continue processed_deduplication_list.append(path_origins) - elif field in _PROCESSED_FIELDS: + elif field in _CACHEABLE_PROVIDER_FIELDS: # Check for duplicates across fields that can be processed by a resource aspect, to # avoid dupes between top-level fields and fields processed by the resource aspect. all_path_origins = [ diff --git a/doc/rules-resources.md b/doc/rules-resources.md index 50472359cf..8473a11644 100644 --- a/doc/rules-resources.md +++ b/doc/rules-resources.md @@ -544,15 +544,16 @@ Returns a list of field names of the provider's resource buckets that are non em resources_common.process_bucketized_data(actions, apple_mac_toolchain_info, bucketized_owners, buckets, bundle_id, output_discriminator, platform_prerequisites, processing_owner, product_type, - rule_label, unowned_resources) + resource_types_to_process, rule_label, unowned_resources) -Registers actions for cacheable resource types, given bucketized groupings of data. +Registers actions for select resource types, given bucketized groupings of data. -This method performs the same actions as bucketize_data, and further iterates through a subset -of supported resource types to register actions to process them as necessary before returning an -AppleResourceInfo. This AppleResourceInfo has an additional field, called "processed", featuring -the expected outputs for each of the actions declared in this method. +This method performs the same actions as bucketize_data, and further +iterates through a subset of resource types to register actions to process +them as necessary before returning an AppleResourceInfo. This +AppleResourceInfo has an additional field, called "processed", featuring the +expected outputs for each of the actions declared in this method. **PARAMETERS** @@ -569,12 +570,14 @@ the expected outputs for each of the actions declared in this method. | platform_prerequisites | Struct containing information on the platform being targeted. | none | | processing_owner | An optional string that has a unique identifier to the target that should own the resources. If an owner should be passed, it's usually equal to `str(ctx.label)`. | `None` | | product_type | The product type identifier used to describe the current bundle type. | none | +| resource_types_to_process | A list of bucket types to process. | `["infoplists", "plists", "pngs", "strings"]` | | rule_label | The label of the target being analyzed. | none | | unowned_resources | A list of "unowned" resources. | `[]` | **RETURNS** -An AppleResourceInfo provider with resources bucketized according to type. +An AppleResourceInfo provider with resources bucketized according to + type.