1414
1515"""Low-level bundling name helpers."""
1616
17+ load (
18+ "@bazel_skylib//lib:new_sets.bzl" ,
19+ "sets" ,
20+ )
1721load (
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+
251276def _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
368377def _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):
393402bundling_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)
0 commit comments