fix: derive pack install guides from the registry

The pack README's one-line install was written per platform: ROCKNIX and MiSTer had none, EmuDeck's Windows edition was told to open Konsole, and RomM users were sent to library/bios/ whatever their firmware template. The automatic section now follows each platform's install.detect systems, the EmuDeck and RomM manual steps name every layout, and the download page lists EmuDeck under Windows and macOS.
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 10:10:15 +02:00
1 parent 26a0717601
commit de8ab51d6e
6 files changed
+311 -206

No files matched your search

+6 -6
View File
@@ -1229,12 +1229,12 @@ def generate_pack(
undecidable_slots=slot_undecidable,
narrowings=narrowings,
system_filter=system_filter,
bios_paths=[
str(detect.get("bios_path", ""))
for detect in (
_pack_registry.get(platform_name, {}).get("install", {}) or {}
).get("detect", [])
],
detect=(
_pack_registry.get(platform_name, {}).get("install", {}) or {}
).get("detect", []),
standalone_copies=(
_pack_registry.get(platform_name, {}).get("install", {}) or {}
).get("standalone_copies", []),
)
_write_generated_member(zf, "README.txt", readme_text)
+3 -1
View File
@@ -4735,6 +4735,7 @@ ZIP: extract them all into the same folder.
| [RetroBat](https://www.retrobat.org/) | Windows frontend with EmulationStation, includes RetroArch and standalone emulators | [RetroBat]({rel}) | The `bios` folder inside the RetroBat installation |
| [BizHawk](https://tasvideos.org/BizHawk) | Accuracy-focused multi-system emulator, popular for speedruns and TAS | [BizHawk]({rel}) | The `Firmware` folder inside the BizHawk installation |
| [LaunchBox](https://www.launchbox-app.com/) | Game library manager and launcher, uses RetroArch or standalone emulators behind the scenes | [RetroArch]({rel}) | Open RetroArch (via LaunchBox) > Settings > Directory > System |
| [EmuDeck](https://www.emudeck.com/) | Installs and configures multiple emulators with ES-DE | [EmuDeck]({rel}) | `bios` in the Emulation folder chosen in EmuDeck, `C:\\Emulation\\bios\\` by default |
### Linux
@@ -4750,6 +4751,7 @@ ZIP: extract them all into the same folder.
| Setup | What it is | Pack | Extract to |
|-------|-----------|------|-----------|
| [RetroArch](https://www.retroarch.com/) | Multi-system emulator | [RetroArch]({rel}) | `~/Library/Application Support/RetroArch/system/` |
| [EmuDeck](https://www.emudeck.com/) | Installs and configures multiple emulators with ES-DE | [EmuDeck]({rel}) | `~/Emulation/bios/` |
### Raspberry Pi and single-board computers
@@ -4778,7 +4780,7 @@ ZIP: extract them all into the same folder.
| Setup | What it is | Pack | Extract to |
|-------|-----------|------|-----------|
| [RomM](https://github.com/rommapp/romm) | Web-based ROM manager, plays games in the browser via EmulatorJS | [RomM]({rel}) | The `bios` folder in the RomM library, one subfolder per system |
| [RomM](https://github.com/rommapp/romm) | Web-based ROM manager, plays games in the browser via EmulatorJS | [RomM]({rel}) | `bios/` in the RomM library, one subfolder per platform. With `firmware: "{{platform}}/bios"` in `config.yml`, each subfolder goes to `<platform>/bios/` instead |
---
+221 -190
View File
@@ -5,6 +5,219 @@ goes, and which ones the user has to rename."""
from __future__ import annotations
INSTALL_SH = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh"
INSTALL_PS1 = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.ps1"
def _detect_systems(detect: list[dict]) -> list[str]:
"""The operating systems the registry's detection rules cover, in order."""
order = ("linux", "darwin", "windows")
seen = {str(rule.get("os", "")) for rule in detect}
return [name for name in order if name in seen]
def _automatic_section(
display: str, detect: list[dict], standalone_copies: list[dict] | None,
) -> str:
"""The one-line install, for every system the registry detects the
platform on. Written per platform by hand, it left ROCKNIX and MiSTer
without it and told EmuDeck's Windows edition to open Konsole."""
systems = _detect_systems(detect)
if not systems:
return ""
# A platform detected on Linux only is a system of its own (Batocera,
# ROCKNIX, MiSTer) or runs on one machine (RetroDECK, a RomM server):
# the command runs there.
on_device = systems == ["linux"]
lines = [
" Option A: Automatic (recommended)",
" ---------------------------------",
]
posix = [name for name in systems if name != "windows"]
if posix:
if on_device:
where = f"On the machine running {display} (its terminal, or SSH), run:"
else:
labels = {"linux": "Linux", "darwin": "macOS"}
where = f"{' and '.join(labels[name] for name in posix)}: run this in a terminal:"
lines += [f" {where}", "", f" curl -fsSL {INSTALL_SH} | sh", ""]
if "windows" in systems:
lines += [" Windows: run this in PowerShell:", "", f" irm {INSTALL_PS1} | iex", ""]
lines += [
f" The installer finds the {display} BIOS folder on this machine and",
" installs there, checking every file. --dest names another folder.",
"",
]
# On a desktop: an emulator folder under the home of a console's own
# system is not one its frontend reads.
if standalone_copies and not on_device:
lines += [
" Standalone emulators read some files from folders of their own",
" (Switch and 3DS keys, PlayStation and GameCube BIOS). To copy them",
" into the emulator folders the installer finds, add --standalone-copies:",
"",
]
if posix:
lines.append(f" curl -fsSL {INSTALL_SH} | sh -s -- --standalone-copies")
if "windows" in systems:
lines.append(f" &([scriptblock]::Create((irm {INSTALL_PS1}))) --standalone-copies")
lines.append("")
return "\n".join(lines) + "\n"
def _generic_manual(bios_paths: list[str]) -> str:
"""Where the files go, from the registry's paths, for a platform with no
manual guide of its own."""
targets = [path for path in bios_paths if path]
where = " or ".join(f"{path}/" for path in dict.fromkeys(targets)) or "your BIOS directory"
return (
" Option B: Manual\n"
" ----------------\n"
f" 1. Extract all files from this archive directly into {where}\n"
" 2. Overwrite if asked\n\n"
)
# What a manual install needs on each platform: its shares, cards and folders.
MANUAL_GUIDES: dict[str, str] = {
"retroarch": (
" Option B: Manual (PC)\n"
" ---------------------\n"
" 1. Find your RetroArch system directory:\n"
" - RetroArch > Settings > Directory > System/BIOS\n"
" - Default: retroarch/system/\n"
" 2. Extract all files from this archive directly into your system directory\n"
" 3. Overwrite if asked\n\n"
" Option C: Manual (handheld / SD card)\n"
" -------------------------------------\n"
" Anbernic, Retroid, Miyoo, Trimui, etc.:\n"
" 1. Connect your SD card to your PC\n"
" 2. Find the BIOS folder (usually BIOS/ or system/)\n"
" 3. Extract all files from this archive directly into that folder\n"
" 4. Eject SD card and reboot your device\n\n"
" Common paths by device:\n"
" Anbernic (ArkOS/JELOS): BIOS/\n"
" Retroid (RetroArch): RetroArch/system/\n"
" Miyoo Mini (Onion OS): BIOS/\n"
" Steam Deck (RetroArch): ~/.config/retroarch/system/\n\n"
),
"batocera": (
" The terminal is F1 from the Batocera menu, or SSH.\n\n"
" Option B: Manual (network share)\n"
" --------------------------------\n"
" 1. On your PC, open the Batocera network share:\n"
" - Windows: \\\\BATOCERA\\share\\bios\\\n"
" - Mac/Linux: smb://batocera/share/bios/\n"
" 2. Extract all files from this archive directly into the share\n"
" 3. Overwrite if asked\n\n"
" Option C: Manual (SD card)\n"
" --------------------------\n"
" 1. Put the SD card in your PC\n"
" 2. Navigate to /userdata/bios/ on the SHARE partition\n"
" 3. Extract all files from this archive directly into that folder\n\n"
" NOTE: Dreamcast flash memory is named dc_nvmem.bin\n"
" (if your setup asks for dc_flash.bin, same file).\n\n"
),
"recalbox": (
" Option B: Manual (network share)\n"
" --------------------------------\n"
" 1. On your PC, open the Recalbox network share:\n"
" - Windows: \\\\RECALBOX\\share\\bios\\\n"
" - Mac/Linux: smb://recalbox/share/bios/\n"
" 2. Extract all files from this archive directly into the share\n\n"
" Option C: Manual (SD card)\n"
" --------------------------\n"
" 1. Put the SD card in your PC\n"
" 2. Navigate to /recalbox/share/bios/\n"
" 3. Extract all files from this archive directly into that folder\n\n"
),
"emudeck": (
" Option B: Manual\n"
" ----------------\n"
" Extract all files from this archive directly into EmuDeck's bios\n"
" folder, inside the Emulation folder chosen in EmuDeck:\n"
" Steam Deck, Linux and macOS: ~/Emulation/bios/ by default\n"
" Windows: C:\\Emulation\\bios\\ by default\n\n"
),
"retrodeck": (
" Option B: Manual\n"
" ----------------\n"
" 1. Open Dolphin file manager\n"
" 2. Show hidden files (Ctrl+H)\n"
" 3. Navigate to ~/retrodeck/\n"
" 4. Extract all files from this archive directly into ~/retrodeck/\n"
" (the archive already holds the bios/ and roms/ folders)\n\n"
" NOTE: RetroDECK uses its own BIOS checker. After\n"
" copying, open RetroDECK > Tools > BIOS Checker to\n"
" verify everything is detected.\n\n"
),
"retrobat": (
" Option B: Manual\n"
" ----------------\n"
" 1. Open your RetroBat installation folder\n"
" 2. Navigate to the bios\\ subfolder\n"
" (default: C:\\RetroBat\\bios\\)\n"
" 3. Extract all files from this archive directly into your bios\\ folder\n"
" 4. Overwrite if asked\n\n"
),
"bizhawk": (
" Option B: Manual\n"
" ----------------\n"
" 1. Open the folder you extracted BizHawk to, the one holding\n"
" EmuHawk.exe (Windows) or EmuHawkMono.sh (Linux)\n"
" 2. Navigate to its Firmware subfolder\n"
" 3. Extract all files from this archive directly into your Firmware folder\n"
" 4. In BizHawk: Config > Paths > Firmware should\n"
" point to this folder\n\n"
),
# RomM 5.4 places firmware by filesystem.structure.firmware in config.yml,
# bios/{platform} by default, and suggests {platform}/bios for a library
# laid out as {platform}/roms (rommapp/romm 68f71259,
# backend/config/config_manager.py:58,101-109,1105-1124).
"romm": (
" Option B: Manual\n"
" ----------------\n"
" The archive holds one folder per RomM platform (psx/, gba/, ...).\n"
" Where they go depends on filesystem.structure.firmware in RomM's\n"
" config.yml, read relative to the library folder:\n\n"
" - Not set, or \"bios/{platform}\" (the default): extract all files\n"
" from this archive directly into library/bios/\n"
" - \"{platform}/bios\" (the layout RomM suggests for a library kept as\n"
" {platform}/roms): each folder goes under its platform, psx/ into\n"
" library/psx/bios/, gba/ into library/gba/bios/, and so on.\n"
" The installer reads config.yml and does this itself. Run from\n"
" the host of a container, --romm-firmware \"{platform}/bios\" says it.\n\n"
" Then restart the RomM service to detect new files.\n\n"
),
"retropie": (
" Option B: Via network share\n"
" --------------------------\n"
" 1. On your PC, open: \\\\RETROPIE\\bios\\\n"
" 2. Extract all files from this archive directly into that folder\n\n"
" Option C: Via SSH\n"
" -----------------\n"
" 1. SSH into your Pi: ssh pi@retropie\n"
" 2. Copy files to ~/RetroPie/BIOS/\n\n"
" NOTE: the BIOS folder is on the card's Linux partition,\n"
" which Windows and macOS cannot open: copying through the\n"
" card works from a Linux computer only\n"
" (<rootfs>/home/pi/RetroPie/BIOS/).\n\n"
),
"lakka": (
" Lakka reads its BIOS files from /storage/system/.\n\n"
" Option B: Via network share\n"
" --------------------------\n"
" 1. On Lakka: Settings > Services > Samba Enable\n"
" 2. On your PC, open the System share: \\\\LAKKA\\System\\\n"
" (macOS and Linux: smb://lakka/System)\n"
" 3. Extract all files from this archive directly into that share\n\n"
" Option C: Via SSH\n"
" -----------------\n"
" 1. On Lakka: Settings > Services > SSH Enable\n"
" 2. Copy the files to /storage/system/ (scp -r * root@lakka:/storage/system/)\n\n"
),
}
def _build_readme(
platform_name: str,
platform_display: str,
@@ -19,7 +232,8 @@ def _build_readme(
undecidable_slots: list[str] | None = None,
narrowings: list[tuple[str, str]] | None = None,
system_filter: list[str] | None = None,
bios_paths: list[str] | None = None,
detect: list[dict] | None = None,
standalone_copies: list[dict] | None = None,
) -> str:
"""Build a personalized step-by-step README for each platform pack."""
narrowings = narrowings or []
@@ -31,195 +245,12 @@ def _build_readme(
f"{sep}\n\n"
)
guides: dict[str, str] = {
"retroarch": (
"INSTALLATION GUIDE\n\n"
" Option A: Automatic (recommended)\n"
" ---------------------------------\n"
" Linux, macOS, Steam Deck: run this in a terminal:\n\n"
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
" Windows: run this in PowerShell:\n\n"
" irm https://raw.githubusercontent.com/Abdess/retrobios/main/install.ps1 | iex\n\n"
" The script auto-detects your RetroArch install and copies\n"
" files to the correct location.\n\n"
" Option B: Manual (PC)\n"
" ---------------------\n"
" 1. Find your RetroArch system directory:\n"
" - RetroArch > Settings > Directory > System/BIOS\n"
" - Default: retroarch/system/\n"
" 2. Extract all files from this archive directly into your system directory\n"
" 3. Overwrite if asked\n\n"
" Option C: Manual (handheld / SD card)\n"
" -------------------------------------\n"
" Anbernic, Retroid, Miyoo, Trimui, etc.:\n"
" 1. Connect your SD card to your PC\n"
" 2. Find the BIOS folder (usually BIOS/ or system/)\n"
" 3. Extract all files from this archive directly into that folder\n"
" 4. Eject SD card and reboot your device\n\n"
" Common paths by device:\n"
" Anbernic (ArkOS/JELOS): BIOS/\n"
" Retroid (RetroArch): RetroArch/system/\n"
" Miyoo Mini (Onion OS): BIOS/\n"
" Steam Deck (RetroArch): ~/.config/retroarch/system/\n\n"
),
"batocera": (
"INSTALLATION GUIDE\n\n"
" Option A: Automatic (recommended)\n"
" ---------------------------------\n"
" Open a terminal (F1 from Batocera menu) and run:\n\n"
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
" Option B: Manual (network share)\n"
" --------------------------------\n"
" 1. On your PC, open the Batocera network share:\n"
" - Windows: \\\\BATOCERA\\share\\bios\\\n"
" - Mac/Linux: smb://batocera/share/bios/\n"
" 2. Extract all files from this archive directly into the share\n"
" 3. Overwrite if asked\n\n"
" Option C: Manual (SD card)\n"
" --------------------------\n"
" 1. Put the SD card in your PC\n"
" 2. Navigate to /userdata/bios/ on the SHARE partition\n"
" 3. Extract all files from this archive directly into that folder\n\n"
" NOTE: Dreamcast flash memory is named dc_nvmem.bin\n"
" (if your setup asks for dc_flash.bin, same file).\n\n"
),
"recalbox": (
"INSTALLATION GUIDE\n\n"
" Option A: Automatic\n"
" -------------------\n"
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
" Option B: Manual (network share)\n"
" --------------------------------\n"
" 1. On your PC, open the Recalbox network share:\n"
" - Windows: \\\\RECALBOX\\share\\bios\\\n"
" - Mac/Linux: smb://recalbox/share/bios/\n"
" 2. Extract all files from this archive directly into the share\n\n"
" Option C: Manual (SD card)\n"
" --------------------------\n"
" 1. Put the SD card in your PC\n"
" 2. Navigate to /recalbox/share/bios/\n"
" 3. Extract all files from this archive directly into that folder\n\n"
),
"emudeck": (
"INSTALLATION GUIDE (Steam Deck / Linux)\n\n"
" Option A: Automatic (recommended)\n"
" ---------------------------------\n"
" Open Konsole (or any terminal) and run:\n\n"
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
" The script places the BIOS files. To also copy the keys\n"
" into the standalone emulators it finds, run:\n\n"
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --standalone-copies\n\n"
" Option B: Manual\n"
" ----------------\n"
" 1. Open Dolphin file manager\n"
" 2. Navigate to ~/Emulation/bios/\n"
" 3. Extract all files from this archive directly into ~/Emulation/bios/\n\n"
" STANDALONE EMULATORS (extra step)\n"
" Switch and 3DS emulators need keys in their own folders:\n"
" prod.keys -> ~/.local/share/yuzu/keys/\n"
" prod.keys -> ~/.local/share/eden/keys/\n"
" prod.keys -> ~/.config/Ryujinx/system/\n"
" aes_keys.txt -> ~/.local/share/azahar-emu/sysdata/\n"
" The installer copies them with --standalone-copies.\n\n"
),
"retrodeck": (
"INSTALLATION GUIDE (Steam Deck / Linux)\n\n"
" Option A: Automatic (recommended)\n"
" ---------------------------------\n"
" Open Konsole (or any terminal) and run:\n\n"
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
" Option B: Manual\n"
" ----------------\n"
" 1. Open Dolphin file manager\n"
" 2. Show hidden files (Ctrl+H)\n"
" 3. Navigate to ~/retrodeck/\n"
" 4. Extract all files from this archive directly into ~/retrodeck/\n"
" (the archive already holds the bios/ and roms/ folders)\n\n"
" NOTE: RetroDECK uses its own BIOS checker. After\n"
" copying, open RetroDECK > Tools > BIOS Checker to\n"
" verify everything is detected.\n\n"
),
"retrobat": (
"INSTALLATION GUIDE (Windows)\n\n"
" Option A: Automatic (recommended)\n"
" ---------------------------------\n"
" Open PowerShell and run:\n\n"
" irm https://raw.githubusercontent.com/Abdess/retrobios/main/install.ps1 | iex\n\n"
" Option B: Manual\n"
" ----------------\n"
" 1. Open your RetroBat installation folder\n"
" 2. Navigate to the bios\\ subfolder\n"
" (default: C:\\RetroBat\\bios\\)\n"
" 3. Extract all files from this archive directly into your bios\\ folder\n"
" 4. Overwrite if asked\n\n"
),
"bizhawk": (
"INSTALLATION GUIDE\n\n"
" 1. Open the folder you extracted BizHawk to, the one holding\n"
" EmuHawk.exe (Windows) or EmuHawkMono.sh (Linux)\n"
" 2. Navigate to its Firmware subfolder\n"
" 3. Extract all files from this archive directly into your Firmware folder\n"
" 4. In BizHawk: Config > Paths > Firmware should\n"
" point to this folder\n\n"
),
"romm": (
"INSTALLATION GUIDE (RomM server)\n\n"
" 1. Locate your RomM library folder\n"
" 2. Navigate to its bios/ folder (library/bios/)\n"
" 3. Extract all files from this archive directly into that folder\n"
" 4. Restart the RomM service to detect new files\n\n"
),
"retropie": (
"INSTALLATION GUIDE (Raspberry Pi)\n\n"
" Option A: Automatic\n"
" -------------------\n"
" On the Pi (F4 from EmulationStation, or over SSH), run:\n\n"
" curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh\n\n"
" Option B: Via network share\n"
" --------------------------\n"
" 1. On your PC, open: \\\\RETROPIE\\bios\\\n"
" 2. Extract all files from this archive directly into that folder\n\n"
" Option C: Via SSH\n"
" -----------------\n"
" 1. SSH into your Pi: ssh pi@retropie\n"
" 2. Copy files to ~/RetroPie/BIOS/\n\n"
" NOTE: the BIOS folder is on the card's Linux partition,\n"
" which Windows and macOS cannot open: copying through the\n"
" card works from a Linux computer only\n"
" (<rootfs>/home/pi/RetroPie/BIOS/).\n\n"
),
}
guides["lakka"] = (
"INSTALLATION GUIDE (Lakka)\n\n"
" Lakka reads its BIOS files from /storage/system/.\n\n"
" Option A: Via network share\n"
" --------------------------\n"
" 1. On Lakka: Settings > Services > Samba Enable\n"
" 2. On your PC, open the System share: \\\\LAKKA\\System\\\n"
" (macOS and Linux: smb://lakka/System)\n"
" 3. Extract all files from this archive directly into that share\n\n"
" Option B: Via SSH\n"
" -----------------\n"
" 1. On Lakka: Settings > Services > SSH Enable\n"
" 2. Copy the files to /storage/system/ (scp -r * root@lakka:/storage/system/)\n\n"
)
# A platform without a written guide is told where its files go by the
# registry, which the installer reads too: "your BIOS directory" sent
# MiSTer users looking for a folder MiSTer does not have.
targets = [path for path in bios_paths or [] if path]
where = (
" or ".join(f"{path}/" for path in targets)
if targets else "your BIOS directory"
)
guide = guides.get(
platform_name,
(
f"INSTALLATION\n\n"
f" 1. Extract all files from this archive directly into {where}\n"
f" 2. Overwrite if asked\n\n"
),
detect = list(detect or [])
bios_paths = [str(rule.get("bios_path", "")) for rule in detect]
guide = (
"INSTALLATION GUIDE\n\n"
+ _automatic_section(platform_display, detect, standalone_copies)
+ MANUAL_GUIDES.get(platform_name, _generic_manual(bios_paths))
)
if regions:
+7 -3
View File
@@ -617,7 +617,11 @@ class PackReadmesSayWhatTheInstallerDoes(unittest.TestCase):
def _guide(self, platform: str) -> str:
from packreadme import _build_readme
text = _build_readme(platform, platform, "", 1, 1)
registry = yaml.safe_load((ROOT / "platforms" / "_registry.yml").read_text())
install = registry["platforms"][platform].get("install") or {}
text = _build_readme(platform, platform, "", 1, 1,
detect=install.get("detect", []),
standalone_copies=install.get("standalone_copies", []))
return text[text.index("INSTALLATION"):text.index("TROUBLESHOOTING")]
def test_retroarch_offers_the_windows_installer(self):
@@ -642,7 +646,6 @@ class PackReadmesSayWhatTheInstallerDoes(unittest.TestCase):
named = {
path.rstrip("/") for path in re.findall(r"-> (~/\S+)", guide)
}
self.assertTrue(named)
self.assertEqual(sorted(named - targets), [])
def test_retropie_never_sends_a_pc_to_the_linux_partition(self):
@@ -3832,7 +3835,8 @@ class EveryReadmeNamesItsFolder(unittest.TestCase):
if not folder:
continue
with self.subTest(platform=name):
text = _build_readme(name, name, "", 1, 1, bios_paths=[folder])
text = _build_readme(name, name, "", 1, 1,
detect=[{"os": "linux", "bios_path": folder}])
self.assertIn(folder, text)
lakka = _build_readme("lakka", "Lakka", "", 1, 1)
self.assertNotIn("retroarch/system", lakka)
+20
View File
@@ -71,6 +71,26 @@ def _which_pack() -> str:
return generate_site.generate_which_pack()
class TheDownloadTablesFollowTheRegistry(unittest.TestCase):
"""EmuDeck has a Windows edition the installer detects, and the Windows
table of the download page left it out."""
def test_every_detected_system_lists_the_platform(self):
import yaml # noqa: PLC0415
registry = yaml.safe_load(_read("platforms/_registry.yml"))
names = {"retroarch": "RetroArch", "retrobat": "RetroBat", "emudeck": "EmuDeck",
"bizhawk": "BizHawk"}
page = _which_pack()
for os_name, heading in (("windows", "### Windows"), ("darwin", "### macOS")):
table = _section(page, heading)
for platform, entry in registry["platforms"].items():
systems = {rule["os"] for rule in (entry.get("install") or {}).get("detect", [])}
if os_name in systems:
with self.subTest(os=os_name, platform=platform):
self.assertIn(f"[{names[platform]}](", table)
class DownloadLinksNameTheFile(unittest.TestCase):
def test_a_whole_pack_links_its_asset(self):
self.assertEqual(
+54 -6
View File
@@ -34,13 +34,10 @@ class GuidesPointAtTheReadPath(unittest.TestCase):
def test_unguided_platforms_name_the_registry_path(self):
registry = yaml.safe_load((REPO_ROOT / "platforms" / "_registry.yml").read_text())
for name, data in registry["platforms"].items():
paths = [
str(d.get("bios_path", ""))
for d in (data.get("install", {}) or {}).get("detect", [])
]
if not any(paths):
detect = (data.get("install", {}) or {}).get("detect", [])
if not any(d.get("bios_path") for d in detect):
continue
text = _build_readme(name, name, "", 1, 1, bios_paths=paths)
text = _build_readme(name, name, "", 1, 1, detect=detect)
with self.subTest(platform=name):
self.assertFalse(
any("your BIOS directory" in line for line in _extract_lines(text))
@@ -55,5 +52,56 @@ class GuidesNameShippedInstallers(unittest.TestCase):
with self.subTest(installer=name):
self.assertTrue((REPO_ROOT / name).is_file())
def _registry() -> dict:
return yaml.safe_load((REPO_ROOT / "platforms" / "_registry.yml").read_text())
def _guide(name: str) -> str:
install = _registry()["platforms"][name].get("install") or {}
return _build_readme(name, name, "", 1, 1, detect=install.get("detect", []),
standalone_copies=install.get("standalone_copies", []))
class TheOneLinerFollowsTheRegistry(unittest.TestCase):
"""The guides were written per platform by hand: ROCKNIX and MiSTer,
which the installer detects, had no one-line install, EmuDeck's
Windows edition was told to open Konsole, and every RomM user was sent
to library/bios/ whatever its firmware template."""
def test_every_detected_system_gets_its_command(self):
for name, data in _registry()["platforms"].items():
systems = {rule["os"] for rule in (data.get("install") or {}).get("detect", [])}
if not systems:
continue
text = _guide(name)
with self.subTest(platform=name):
self.assertEqual("install.sh | sh" in text, bool(systems - {"windows"}))
self.assertEqual("install.ps1 | iex" in text, "windows" in systems)
def test_rocknix_and_mister_run_it_on_the_device(self):
for name in ("rocknix", "misterfpga"):
with self.subTest(platform=name):
self.assertIn(f"On the machine running {name}", _guide(name))
def test_emudeck_is_not_steam_deck_only(self):
text = _guide("emudeck")
self.assertNotIn("Steam Deck / Linux", text)
self.assertNotIn("Konsole", text)
self.assertIn("install.ps1 | iex", text)
self.assertIn("C:\\Emulation\\bios", text)
self.assertIn("--standalone-copies", text)
def test_romm_names_both_firmware_layouts(self):
text = _guide("romm")
self.assertIn("library/bios/", text)
self.assertIn("library/psx/bios/", text)
self.assertIn("--romm-firmware", text)
def test_the_commands_are_written_once(self):
source = (REPO_ROOT / "scripts" / "packreadme.py").read_text(encoding="utf-8")
self.assertEqual(source.count("main/install.sh"), 1)
self.assertEqual(source.count("main/install.ps1"), 1)
if __name__ == "__main__":
unittest.main()