Skip to content

Commit d240302

Browse files
authored
Align actool with upstream (#2804)
1 parent 1387ba3 commit d240302

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+946
-417
lines changed

apple/internal/bundling_support.bzl

Lines changed: 66 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
"""Low-level bundling name helpers."""
1616

17+
load(
18+
"@bazel_skylib//lib:new_sets.bzl",
19+
"sets",
20+
)
1721
load(
1822
"//apple:providers.bzl",
1923
"AppleBaseBundleIdInfo",
@@ -248,24 +252,37 @@ See https://github.com/bazelbuild/rules_apple/blob/master/doc/shared_capabilitie
248252
suffix_default = suffix_default,
249253
)
250254

255+
def _ensure_asset_catalog_files_not_in_xcassets(
256+
*,
257+
extension,
258+
files,
259+
message = None):
260+
"""Validates that a subset of asset catalog files are not within an xcassets directory.
261+
262+
Args:
263+
extension: The extension that should be used for the this particular asset that should never
264+
be found within the xcassets directory.
265+
files: An iterable of files to use.
266+
message: A custom error message to use, the list of found files that were found in xcassets
267+
directories will be printed afterwards.
268+
"""
269+
_ensure_path_format(
270+
files = files,
271+
allowed_path_fragments = [],
272+
denied_path_fragments = ["xcassets", extension],
273+
message = message,
274+
)
275+
251276
def _ensure_single_xcassets_type(
252277
*,
253-
additional_path_fragments = [],
254-
attr,
255278
extension,
256279
files,
257280
message = None):
258-
"""Helper for when an xcassets catalog should have a single sub type.
281+
"""Validates that asset catalog files are nested within an xcassets directory.
259282
260283
Args:
261-
additional_path_fragments: Additional path fragments to check for in the path (in order), used
262-
to handle actool inputs that don't use the `xcassets` directory, such as Xcode 26 `icon`
263-
bundles generated by the Icon Composer tool.
264-
attr: The attribute to associate with the build failure if the list of
265-
files has an element that is not in a directory with the given
266-
extension.
267-
extension: The extension that should be used for the different asset
268-
type witin the catalog.
284+
extension: The extension that should be used for the this particular asset within the xcassets
285+
directory.
269286
files: An iterable of files to use.
270287
message: A custom error message to use, the list of found files that
271288
didn't match will be printed afterwards.
@@ -274,9 +291,9 @@ def _ensure_single_xcassets_type(
274291
message = ("Expected the xcassets directory to only contain files " +
275292
"are in sub-directories with the extension %s") % extension
276293
_ensure_path_format(
277-
attr = attr,
278294
files = files,
279-
path_fragments_list = [["xcassets", extension], additional_path_fragments],
295+
allowed_path_fragments = ["xcassets", extension],
296+
denied_path_fragments = [],
280297
message = message,
281298
)
282299

@@ -307,63 +324,55 @@ def _path_is_under_fragments(path, path_fragments):
307324

308325
return True
309326

310-
def _ensure_path_format(*, attr, files, path_fragments_list, message = None):
327+
def _ensure_path_format(
328+
*,
329+
files,
330+
allowed_path_fragments,
331+
denied_path_fragments,
332+
message = None):
311333
"""Ensure the files match the required path fragments.
312334
313-
TODO(b/77804841): The places calling this should go away and these types of
314-
checks should be done during the resource processing. Right now these checks
315-
are being wedged in at the attribute collection steps, and they then get
316-
combined into a single list of resources; the bundling then resplits them
317-
up in groups to process they by type. So the more validation/splitting done
318-
here the slower things get (as double work is done). The bug is to revisit
319-
all of this and instead pass through individual things in a structured way
320-
so they don't have to be resplit. That would allow the validation to be
321-
done while processing (in a single pass) instead.
322-
323335
Args:
324-
attr: The attribute to associate with the build failure if the list of
325-
files has an element that is not in a directory with the given
326-
extension.
327336
files: An iterable of files to use.
328-
path_fragments_list: A list of lists, each inner lists is a sequence of
329-
extensions that must be on the paths passed in (to ensure proper
330-
nesting).
337+
allowed_path_fragments: A list representing a sequence of extensions where each file path
338+
passed in MUST MATCH the sequence to ensure proper nesting. If this is provided,
339+
denied_path_fragments must be empty.
340+
denied_path_fragments: A list representing a sequence of extensions where each file path
341+
passed in MUST NOT MATCH the sequence to ensure proper nesting. If this is provided,
342+
allowed_path_fragments must be empty.
331343
message: A custom error message to use, the list of found files that
332344
didn't match will be printed afterwards.
333345
"""
334346

335-
formatted_path_fragments_list = []
336-
for x in path_fragments_list:
337-
formatted_path_fragments_list.append([".%s/" % y for y in x])
347+
if allowed_path_fragments and denied_path_fragments:
348+
fail("""
349+
Internal Error: Both allowed_path_fragments and denied_path_fragments were provided, but only one \
350+
of them should be provided.
338351
339-
# Just check that the paths include the expected nesting. More complete
340-
# checks would likely be the number of outer directories with that suffix,
341-
# the number of inner ones, extra directories segments where not expected,
342-
# etc.
343-
bad_paths = {}
344-
for f in files:
345-
path = f.path
352+
Please file an issue on the Apple BUILD Rules.
353+
""")
346354

347-
was_good = False
348-
for path_fragments in formatted_path_fragments_list:
349-
if _path_is_under_fragments(path, path_fragments):
350-
was_good = True
351-
break # No need to check other fragments
355+
formatted_path_fragments = []
356+
for x in allowed_path_fragments + denied_path_fragments:
357+
formatted_path_fragments.append(".%s/" % x)
358+
allow_path_under_fragments = bool(allowed_path_fragments)
352359

353-
if not was_good:
354-
bad_paths[path] = None
360+
bad_paths = sets.make()
361+
for f in files:
362+
path = f.path
363+
if _path_is_under_fragments(path, formatted_path_fragments) != allow_path_under_fragments:
364+
sets.insert(bad_paths, path)
355365

356-
if len(bad_paths):
366+
if sets.length(bad_paths):
357367
if not message:
358-
as_paths = [
359-
("*" + "*".join(x) + "...")
360-
for x in formatted_path_fragments_list
361-
]
362-
message = "Expected only files inside directories named '*.%s'" % (
363-
", ".join(as_paths)
368+
message_prefix = (
369+
"Expected only " if allow_path_under_fragments else "Did not expect any "
364370
)
365-
formatted_paths = "[\n %s\n]" % ",\n ".join(bad_paths.keys())
366-
fail("%s, but found the following: %s" % (message, formatted_paths), attr)
371+
as_path = "*" + "*".join(formatted_path_fragments) + "..."
372+
message = message_prefix + "files inside directories named '*.%s'" % (as_path)
373+
374+
formatted_paths = "[\n %s\n]" % ",\n ".join(sets.to_list(bad_paths))
375+
fail("%s, but found the following: %s" % (message, formatted_paths))
367376

368377
def _validate_bundle_id(bundle_id):
369378
"""Ensure the value is a valid bundle it or fail the build.
@@ -393,7 +402,7 @@ def _validate_bundle_id(bundle_id):
393402
bundling_support = struct(
394403
bundle_full_name = _bundle_full_name,
395404
bundle_full_id = _bundle_full_id,
396-
ensure_path_format = _ensure_path_format,
405+
ensure_asset_catalog_files_not_in_xcassets = _ensure_asset_catalog_files_not_in_xcassets,
397406
ensure_single_xcassets_type = _ensure_single_xcassets_type,
398407
validate_bundle_id = _validate_bundle_id,
399408
)

apple/internal/partials/BUILD

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ bzl_library(
1515
],
1616
deps = [
1717
"//apple/internal:apple_product_type",
18-
"//apple/internal:bundling_support",
1918
"@bazel_skylib//lib:partial",
2019
],
2120
)

apple/internal/partials/app_assets_validation.bzl

Lines changed: 59 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,26 @@ load(
2222
"//apple/internal:apple_product_type.bzl",
2323
"apple_product_type",
2424
)
25-
load(
26-
"//apple/internal:bundling_support.bzl",
27-
"bundling_support",
28-
)
2925

30-
_supports_visionos = hasattr(apple_common.platform_type, "visionos")
26+
# Standard icon extensions as of Xcode 26 for most Apple platforms (iOS, macOS, watchOS).
27+
_STANDARD_ICONS = [".appiconset/", ".icon/"]
28+
29+
# Valid icon extensions for specific product types that have exceptional requirements, independent
30+
# of platform.
31+
_VALID_ICON_EXTENSIONS_FOR_PRODUCT_TYPE = {
32+
apple_product_type.messages_extension: [".stickersiconset/"],
33+
apple_product_type.messages_sticker_pack_extension: [".stickersiconset/", ".stickerpack/", ".sticker/", ".stickersequence/"],
34+
}
35+
36+
# Comprehensive list of all valid icon extensions for each platform. These cover apps, extensions,
37+
# app clips, and bundle types that can use icons.
38+
_VALID_ICON_EXTENSIONS_FOR_PLATFORM = {
39+
"ios": _STANDARD_ICONS,
40+
"macos": _STANDARD_ICONS,
41+
"tvos": [".brandassets/"],
42+
"watchos": _STANDARD_ICONS,
43+
"visionos": [".solidimagestack/"],
44+
}
3145

3246
def _app_assets_validation_partial_impl(
3347
*,
@@ -37,74 +51,49 @@ def _app_assets_validation_partial_impl(
3751
product_type):
3852
"""Implementation for the app assets processing partial."""
3953

54+
# actool.bzl has the most comprehensive validations since it evaluates the final set of files
55+
# before they are sent to actool. We only check here that the user is sending files that look
56+
# like they could be app icons via an attribute named `app_icons`, and likewise for launch
57+
# images.
58+
4059
if app_icons:
41-
if product_type == apple_product_type.messages_extension:
42-
message = ("Message extensions must use Messages Extensions Icon Sets " +
43-
"(named .stickersiconset), not traditional App Icon Sets")
44-
bundling_support.ensure_single_xcassets_type(
45-
attr = "app_icons",
46-
extension = "stickersiconset",
47-
files = app_icons,
48-
message = message,
49-
)
50-
elif product_type == apple_product_type.messages_sticker_pack_extension:
51-
path_fragments = [
52-
# Replacement for appiconset.
53-
["xcstickers", "stickersiconset"],
54-
# The stickers.
55-
["xcstickers", "stickerpack", "sticker"],
56-
["xcstickers", "stickerpack", "stickersequence"],
57-
]
58-
message = (
59-
"Message StickerPack extensions use an asset catalog named " +
60-
"*.xcstickers. Their main icons use *.stickersiconset; and then " +
61-
"under the Sticker Pack (*.stickerpack) goes the Stickers " +
62-
"(named *.sticker) and/or Sticker Sequences (named " +
63-
"*.stickersequence)"
64-
)
65-
bundling_support.ensure_path_format(
66-
attr = "app_icons",
67-
files = app_icons,
68-
path_fragments_list = path_fragments,
69-
message = message,
70-
)
71-
elif platform_prerequisites.platform_type == apple_common.platform_type.tvos:
72-
bundling_support.ensure_single_xcassets_type(
73-
attr = "app_icons",
74-
extension = "brandassets",
75-
files = app_icons,
76-
)
77-
elif (_supports_visionos and
78-
platform_prerequisites.platform_type == apple_common.platform_type.visionos):
79-
message = ("visionOS apps must use visionOS app icon layers grouped in " +
80-
".solidimagestack bundles, not traditional App Icon Sets")
81-
bundling_support.ensure_single_xcassets_type(
82-
attr = "app_icons",
83-
extension = "solidimagestack",
84-
files = app_icons,
85-
message = message,
86-
)
87-
else:
88-
# For Xcode 26, appiconset-s can live alongside iOS/macOS/watchOS .icon bundle contents
89-
# to ensure rendering is correct for pre-26 Apple OSes, so we need to make that
90-
# exception here.
91-
additional_path_fragments = []
92-
xcode_version = platform_prerequisites.xcode_version_config.xcode_version()
93-
if xcode_version >= apple_common.dotted_version("26.0"):
94-
additional_path_fragments.append("icon")
95-
bundling_support.ensure_single_xcassets_type(
96-
additional_path_fragments = additional_path_fragments,
97-
attr = "app_icons",
98-
extension = "appiconset",
99-
files = app_icons,
100-
)
60+
valid_icon_extensions = (
61+
_VALID_ICON_EXTENSIONS_FOR_PRODUCT_TYPE.get(product_type, None) or
62+
_VALID_ICON_EXTENSIONS_FOR_PLATFORM[str(platform_prerequisites.platform_type)]
63+
)
64+
for resource in app_icons:
65+
resource_short_path = resource.short_path
66+
possible_valid_icon = False
67+
for valid_icon_extension in valid_icon_extensions:
68+
if valid_icon_extension in resource_short_path:
69+
possible_valid_icon = True
70+
break
71+
if (not possible_valid_icon and
72+
not resource_short_path.endswith(".xcassets/Contents.json") and
73+
not resource_short_path.endswith(".xcstickers/Contents.json")):
74+
fail("""
75+
Found in app_icons a file that cannot be used as an app icon:
76+
{resource_short_path}
77+
78+
Valid icon bundles for this target have the following extensions: {valid_icon_extensions}
79+
""".format(
80+
resource_short_path = resource_short_path,
81+
valid_icon_extensions = valid_icon_extensions,
82+
))
10183

10284
if launch_images:
103-
bundling_support.ensure_single_xcassets_type(
104-
attr = "launch_images",
105-
extension = "launchimage",
106-
files = launch_images,
107-
)
85+
for resource in launch_images:
86+
resource_short_path = resource.short_path
87+
if (not ".launchimage/" in resource_short_path and
88+
not resource_short_path.endswith(".xcassets/Contents.json")):
89+
fail("""
90+
Found in launch_images a file that cannot be used as a launch image:
91+
{resource_short_path}
92+
93+
All launch images must be in a directory named '*.launchimage' within an '*.xcassets' directory.
94+
""".format(
95+
resource_short_path = resource_short_path,
96+
))
10897

10998
return struct()
11099

apple/internal/resource_actions/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ bzl_library(
1616
deps = [
1717
"//apple:utils",
1818
"//apple/internal:apple_product_type",
19+
"//apple/internal:bundling_support",
1920
"//apple/internal/utils:xctoolrunner",
2021
"@bazel_skylib//lib:paths",
21-
"@bazel_skylib//lib:sets",
2222
"@build_bazel_apple_support//lib:apple_support",
2323
],
2424
)

0 commit comments

Comments
 (0)