From f2e25aeea2fff5e9e177e010829747394d517870 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Thu, 5 Nov 2026 11:52:26 +0100 Subject: [PATCH] feat: list platforms with --list-platforms install.py took --list-platforms, generate_pack.py --list and verify.py nothing. Both tools now take --list-platforms and print the same list from common.py. generate_pack.py keeps --list (finding 80). --- scripts/common.py | 16 ++++++++++++++++ scripts/generate_pack.py | 27 ++++++++++----------------- scripts/verify.py | 13 ++++++++++--- tests/test_tool_messages.py | 25 +++++++++++++++++++++++++ wiki/tools.md | 3 ++- 5 files changed, 63 insertions(+), 21 deletions(-) diff --git a/scripts/common.py b/scripts/common.py index 3ae9c8add..47d53833d 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -3192,6 +3192,22 @@ def list_system_ids(emulators_dir: str) -> None: print(f" {spelling:35s} ({count} emulator{'s' if count > 1 else ''})") +def print_platform_listing(platforms_dir: str) -> None: + """Every registered platform, one per line, marked when archived or + served by the installer only. + + Every platform takes --platform. --all covers the active ones, and the + pack builder's --all the release packs. Printed by --list-platforms in + verify.py and generate_pack.py, the name install.py gives it. + """ + active = set(list_registered_platforms(platforms_dir)) + released = set(list_release_pack_platforms(platforms_dir, include_archived=True)) + for name in list_registered_platforms(platforms_dir, include_archived=True): + marks = [m for m, on in (("archived", name not in active), + ("installer only", name not in released)) if on] + print(f"{name} ({', '.join(marks)})" if marks else name) + + def list_platform_system_ids(platform_name: str, platforms_dir: str) -> None: """Print system IDs from a platform's YAML config, with the platform's own names for them, which --system also accepts.""" diff --git a/scripts/generate_pack.py b/scripts/generate_pack.py index 8d9ba9a7e..1bed3b5e3 100644 --- a/scripts/generate_pack.py +++ b/scripts/generate_pack.py @@ -53,6 +53,7 @@ from common import ( list_platform_system_ids, platform_system_names, resolve_system_arg, + print_platform_listing, select_systems, platform_scope_systems, system_scope_error, @@ -1866,11 +1867,6 @@ def generate_system_pack( shutil.rmtree(scratch, ignore_errors=True) -def list_platforms(platforms_dir: str) -> list[str]: - """List available platform names from registry.""" - return list_registered_platforms(platforms_dir, include_archived=True) - - def _system_display_name(system_id: str) -> str: """Convert system ID to display name for ZIP naming.""" s = system_id.lower().replace("_", "-") @@ -3097,7 +3093,7 @@ def _refuse_unapplied_flags(args: argparse.Namespace, parser: argparse.ArgumentP name for name, on in ( ("--manifest-targets", args.manifest_targets), ("--verify-packs", args.verify_packs and not args.all_variants), - ("--list", args.list), + ("--list-platforms", args.list), ("--list-emulators", args.list_emulators), ("--list-systems", args.list_systems), ("--list-targets", args.list_targets), @@ -3123,7 +3119,7 @@ QUICK_MODE_FLAGS: dict[str, set[str]] = { }, # One manifest per hardware target, from the target files themselves. "--manifest-targets": set(), - "--list": set(), + "--list-platforms": set(), "--list-emulators": set(), "--list-systems": {"--platform"}, "--list-targets": {"--platform"}, @@ -3152,7 +3148,7 @@ def _given_flags(args: argparse.Namespace) -> set[str]: "--target": args.target, "--region": args.region, "--one-per-slot": args.one_per_slot, - "--list": args.list, + "--list-platforms": args.list, "--list-emulators": args.list_emulators, "--list-systems": args.list_systems, "--list-targets": args.list_targets, @@ -3249,7 +3245,11 @@ def _main(held: contextlib.ExitStack) -> None: action="store_true", help="Pack the data directories as cached, still fetching release assets", ) - parser.add_argument("--list", action="store_true", help="List available platforms") + # install.py's name. --list stays for the scripts that already type it. + parser.add_argument( + "--list-platforms", "--list", dest="list", action="store_true", + help="List available platforms", + ) parser.add_argument( "--required-only", action="store_true", @@ -3351,14 +3351,7 @@ def _main(held: contextlib.ExitStack) -> None: ) return if args.list: - # Every platform builds with --platform. --all builds the release - # packs only, the others are served by the installer. - active = set(list_registered_platforms(args.platforms_dir)) - released = set(list_release_pack_platforms(args.platforms_dir, include_archived=True)) - for p in list_platforms(args.platforms_dir): - marks = [m for m, on in (("archived", p not in active), - ("installer only", p not in released)) if on] - print(f"{p} ({', '.join(marks)})" if marks else p) + print_platform_listing(args.platforms_dir) return if args.list_emulators: list_emulator_profiles(args.emulators_dir) diff --git a/scripts/verify.py b/scripts/verify.py index bede4c9d2..4e486caf7 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -63,6 +63,7 @@ from common import ( load_emulator_profiles, load_platform_config, resolve_system_arg, + print_platform_listing, select_systems, platform_scope_systems, system_scope_error, @@ -2620,6 +2621,7 @@ def _refuse_listing_narrowings( """ listing = next( (flag for flag, on in ( + ("--list-platforms", args.list_platforms), ("--list-emulators", args.list_emulators), ("--list-systems", args.list_systems), ("--list-targets", args.list_targets), @@ -2628,7 +2630,7 @@ def _refuse_listing_narrowings( ) if not listing: return - reads_platform = listing != "--list-emulators" + reads_platform = listing not in ("--list-emulators", "--list-platforms") for flag, on in ( ("--platform", args.platform and not reads_platform), ("--all", args.all), @@ -2678,7 +2680,9 @@ def _refuse_mode_flags(args: argparse.Namespace, parser: argparse.ArgumentParser def _run_listing(args: argparse.Namespace, parser: argparse.ArgumentParser) -> None: - if args.list_emulators: + if args.list_platforms: + print_platform_listing(args.platforms_dir) + elif args.list_emulators: list_emulator_profiles(args.emulators_dir) elif args.list_systems and args.platform: list_platform_system_ids(args.platform, args.platforms_dir) @@ -2717,6 +2721,9 @@ def _main(held: contextlib.ExitStack) -> None: parser.add_argument( "--list-systems", action="store_true", help="List available systems" ) + parser.add_argument( + "--list-platforms", action="store_true", help="List available platforms" + ) parser.add_argument( "--include-archived", action="store_true", help="With --all, also verify the archived platforms (RetroPie)", @@ -2790,7 +2797,7 @@ def _main(held: contextlib.ExitStack) -> None: parser.error(str(exc)) _refuse_listing_narrowings(args, parser) - if args.list_emulators or args.list_systems or args.list_targets: + if args.list_platforms or args.list_emulators or args.list_systems or args.list_targets: _run_listing(args, parser) return diff --git a/tests/test_tool_messages.py b/tests/test_tool_messages.py index ccbf9ddc7..3d782366f 100644 --- a/tests/test_tool_messages.py +++ b/tests/test_tool_messages.py @@ -235,6 +235,31 @@ class APlatformWithoutTargetsSaysSo(unittest.TestCase): ) +class OneNameListsThePlatforms(unittest.TestCase): + """install.py --list-platforms, generate_pack.py --list, and no listing + at all in verify.py: three scripts, three answers to one question.""" + + def _run(self, script: str, flag: str) -> subprocess.CompletedProcess: + return subprocess.run( + [sys.executable, f"scripts/{script}", flag], capture_output=True, text=True, + cwd=str(REPO_ROOT), timeout=120, check=False, + ) + + def test_both_tools_take_it_and_agree(self): + verify_out = self._run("verify.py", "--list-platforms") + pack_out = self._run("generate_pack.py", "--list-platforms") + self.assertEqual(verify_out.returncode, 0, verify_out.stderr) + self.assertEqual(pack_out.returncode, 0, pack_out.stderr) + self.assertEqual(verify_out.stdout, pack_out.stdout) + self.assertIn("retroarch", verify_out.stdout.split()) + self.assertIn("--list-platforms", (REPO_ROOT / "install.py").read_text()) + + def test_the_installer_name_is_the_one_documented(self): + tools = (REPO_ROOT / "wiki" / "tools.md").read_text() + self.assertIn("generate_pack.py --list-platforms", tools) + self.assertIn("verify.py --list-platforms", tools) + + class OneSpellingPerOption(unittest.TestCase): """verify.py -p batocera worked and slots.py -p batocera was refused.""" diff --git a/wiki/tools.md b/wiki/tools.md index 1aa6aef87..ed20d0bff 100644 --- a/wiki/tools.md +++ b/wiki/tools.md @@ -134,6 +134,7 @@ python scripts/verify.py --platform recalbox --region us # regional priority l python scripts/verify.py --platform emuelec --no-game-data # the firmware-only pack, game data named python scripts/verify.py --all --destinations tmp/paths.json # also write the paths each pack holds python scripts/verify.py --all --offline # a release asset the cache lacks counts missing, as in an offline build +python scripts/verify.py --list-platforms # list all platforms python scripts/verify.py --list-emulators # list all emulators python scripts/verify.py --list-systems # list all systems python scripts/verify.py --platform retroarch --list-targets # list available targets @@ -208,7 +209,7 @@ python scripts/generate_pack.py --all --all-variants --output-dir dist/ # all 6 python scripts/generate_pack.py --all --all-variants --verify-packs --output-dir dist/ # Listing and integrity -python scripts/generate_pack.py --list # list available platforms +python scripts/generate_pack.py --list-platforms # list available platforms python scripts/generate_pack.py --list-emulators python scripts/generate_pack.py --list-systems python scripts/generate_pack.py --platform retroarch --list-targets