From 8128b47aeb6714f00dc70253d9e0826d6d4dac2e Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sun, 6 Sep 2026 23:06:00 +0200 Subject: [PATCH] fix: skip full conformance on a targeted pack --- scripts/generate_pack.py | 62 +++++++++++++++++++++++++++++++++++++--- tests/test_e2e.py | 22 ++++++++++++++ 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/scripts/generate_pack.py b/scripts/generate_pack.py index 839e3845..97bbac07 100644 --- a/scripts/generate_pack.py +++ b/scripts/generate_pack.py @@ -3087,17 +3087,71 @@ def inject_manifest(zip_path: str, manifest: dict) -> None: +_TARGET_TAGS_CACHE: set[str] | None = None + + +def _known_target_tags(platforms_dir: str = "platforms") -> set[str]: + """Every filename tag a hardware target can put in a pack name. + + A target tag is derived from the target's own name, so unlike the other + narrowings it cannot be a literal list. + """ + global _TARGET_TAGS_CACHE + if _TARGET_TAGS_CACHE is not None: + return _TARGET_TAGS_CACHE + tags: set[str] = set() + targets_dir = os.path.join(platforms_dir, "targets") + if os.path.isdir(targets_dir): + for entry in sorted(os.listdir(targets_dir)): + if not entry.endswith(".yml") or entry.startswith("_"): + continue + try: + with open(os.path.join(targets_dir, entry)) as fh: + data = yaml_load(fh) or {} + except OSError as exc: + print(f"warning: cannot read {entry}: {exc}", file=sys.stderr) + continue + for name in (data.get("targets") or {}): + tags.add(f"_{_target_tag(str(name))}") + # A pack is named after what the caller typed, and an alias is a name a + # caller may type: --target switch names the pack _Switch while the target + # file only knows nintendo-switch. + overrides_path = os.path.join(targets_dir, "_overrides.yml") + if os.path.exists(overrides_path): + try: + with open(overrides_path) as fh: + overrides = yaml_load(fh) or {} + except OSError as exc: + print(f"warning: cannot read _overrides.yml: {exc}", file=sys.stderr) + overrides = {} + for platform in overrides.values(): + if not isinstance(platform, dict): + continue + for target in (platform.get("targets") or {}).values(): + if not isinstance(target, dict): + continue + for alias in target.get("aliases") or []: + tags.add(f"_{_target_tag(str(alias))}") + _TARGET_TAGS_CACHE = tags + return tags + + def _narrows_contents(pack_name: str) -> bool: """True when a pack holds fewer files than the platform declares. - A source-restricted or required-only build is narrower by design, so the - full platform expectation does not apply to it and conformance is skipped. + A source-restricted, required-only or target-filtered build is narrower by + design, so the full platform expectation does not apply to it and + conformance is skipped. Without the target tag here, every targeted pack + was checked against the platform's whole system list and reported the + systems the target itself had removed as missing. Region is not listed: the region filter is passed to the check itself. """ - return any( + if any( tag in pack_name for tag in ("_Platform_", "_Truth_", "_Required", "_OnePerSlot") - ) + ): + return True + return any(f"{tag}_" in pack_name for tag in _known_target_tags()) def verify_and_finalize_packs( diff --git a/tests/test_e2e.py b/tests/test_e2e.py index 8380c38e..2b6bd722 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -5842,6 +5842,28 @@ struct BurnDriver BurnDrvneogeo = { ) self.assertIn("error:", combined) + def test_a_targeted_pack_skips_full_platform_conformance(self): + """A target-filtered pack is narrower, so the full expectation is off. + + The tag was missing from the skip list, so every targeted pack was + checked against the platform's whole system list and reported the + systems the target itself had removed as missing: a correct build + exited non-zero on hundreds of files it was never asked to carry. + """ + from generate_pack import _narrowings, _narrows_contents + + for target in ("nintendo-switch", "switch", "rpi4"): + with self.subTest(target=target): + applied = _narrowings("full", None, target, False, False) + self.assertEqual(len(applied), 1, target) + tag = applied[0][0] + self.assertTrue( + _narrows_contents(f"Platform_1.0{tag}_BIOS_Pack.zip"), + f"a pack built for {target} would be held to the full list", + ) + + self.assertFalse(_narrows_contents("Platform_1.0_BIOS_Pack.zip")) + def test_standalone_mode_names_itself(self): """--emulator --standalone ships a different file set; without a tag it overwrote the pack built without it."""