From b6331a765a60607124c3b1d129d252be4cbde03f Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Sat, 17 Oct 2026 12:28:27 +0200 Subject: [PATCH] fix: name the platform a typo was meant to be --- scripts/common.py | 18 ++++++++++++++++++ scripts/cross_reference.py | 3 +++ scripts/generate_pack.py | 4 ++++ scripts/verify.py | 3 +++ tests/test_system_selection.py | 21 +++++++++++++++++++++ 5 files changed, 49 insertions(+) diff --git a/scripts/common.py b/scripts/common.py index ad368b2e..d8ff9619 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -350,6 +350,24 @@ def list_registered_platforms( return platforms +def require_platform(name: str, platforms_dir: str = "platforms") -> None: + """Exit with a usable message when no platform answers to a name. + + A typo used to end in a traceback (verify, cross_reference) or in "no + pack for batocra" after the whole build ran (generate_pack). + """ + if os.path.exists(os.path.join(platforms_dir, f"{name}.yml")): + return + import difflib # noqa: PLC0415 + + known = list_registered_platforms(platforms_dir, include_archived=True) + close = difflib.get_close_matches(name, known, n=1) + hint = f" Did you mean '{close[0]}'?" if close else "" + raise SystemExit( + f"ERROR: unknown platform '{name}'.{hint}\nKnown platforms: {', '.join(known)}" + ) + + def _target_overrides(platform_name: str, targets_dir: str) -> dict: overrides_file = os.path.join(targets_dir, "_overrides.yml") if not os.path.exists(overrides_file): diff --git a/scripts/cross_reference.py b/scripts/cross_reference.py index 51a8d7be..b78512af 100644 --- a/scripts/cross_reference.py +++ b/scripts/cross_reference.py @@ -20,6 +20,7 @@ from pathlib import Path sys.path.insert(0, os.path.dirname(__file__)) from common import ( + require_platform, _norm_system_id, directory_members, get_mame_clone_map, @@ -642,6 +643,8 @@ def main(): parser.add_argument("--target", "-t", help="Hardware target (e.g., switch, rpi4)") parser.add_argument("--json", action="store_true", help="JSON output") args = parser.parse_args() + if args.platform: + require_platform(args.platform, args.platforms_dir) profiles = load_emulator_profiles(args.emulators_dir) if args.emulator: diff --git a/scripts/generate_pack.py b/scripts/generate_pack.py index 948b0a6e..aafd2c9f 100644 --- a/scripts/generate_pack.py +++ b/scripts/generate_pack.py @@ -30,6 +30,7 @@ from pathlib import Path sys.path.insert(0, os.path.dirname(__file__)) from common import resolve_platform_cores as _platform_cores from common import ( + require_platform, apply_target_overrides, archive_entry, profiles_for_systems, @@ -2846,6 +2847,9 @@ def main(): ) args = parser.parse_args() packresolve.set_offline(bool(args.offline)) + if args.platform: + for name in args.platform.split(","): + require_platform(name.strip(), args.platforms_dir) _refuse_unapplied_flags(args, parser) if args.target: diff --git a/scripts/verify.py b/scripts/verify.py index 91b3947f..09824202 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -34,6 +34,7 @@ import slots sys.path.insert(0, os.path.dirname(__file__)) from common import ( + require_platform, archive_entry, archive_members, profiles_for_systems, @@ -2064,6 +2065,8 @@ def main(): ) parser.add_argument("--json", action="store_true", help="JSON output") args = parser.parse_args() + if args.platform: + require_platform(args.platform, args.platforms_dir) requested_regions: list[str] = [] if getattr(args, "region", None): diff --git a/tests/test_system_selection.py b/tests/test_system_selection.py index 14a09a9b..49611e6e 100644 --- a/tests/test_system_selection.py +++ b/tests/test_system_selection.py @@ -89,5 +89,26 @@ class ADeclinedBuildIsAFailure(unittest.TestCase): self.assertEqual([p for p in os.listdir(tmp) if p.endswith(".zip")], []) + +class AMistypedPlatformIsNamed(unittest.TestCase): + """verify and cross_reference ended a typo on a traceback; generate_pack + ran its whole build first and then said "no pack for batocra".""" + + def test_every_cli_names_the_platform_it_meant(self): + out = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp")) + out.rmdir() + for script, extra in (("verify.py", []), ("cross_reference.py", []), + ("generate_pack.py", ["--offline", "--output-dir", str(out)])): + with self.subTest(script=script): + proc = subprocess.run( + [sys.executable, f"scripts/{script}", "--platform", "batocra", *extra], + capture_output=True, text=True, cwd=str(REPO_ROOT), timeout=300, + check=False, + ) + self.assertNotEqual(proc.returncode, 0) + self.assertNotIn("Traceback", proc.stderr, proc.stderr) + self.assertIn("Did you mean 'batocera'?", proc.stderr) + self.assertFalse(out.exists()) + if __name__ == "__main__": unittest.main()