From 8cf70b6afb2db356a74bfd6cd9e4648060a0422c Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:48:02 +0200 Subject: [PATCH 1/6] docs: name emulator errors in troubleshooting --- wiki/troubleshooting.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/wiki/troubleshooting.md b/wiki/troubleshooting.md index af29ce2ab..bba8e39dd 100644 --- a/wiki/troubleshooting.md +++ b/wiki/troubleshooting.md @@ -1,6 +1,7 @@ --- level: start order: 40 +terms: bios not found, bios missing, firmware missing, bios error --- # When a game does not start @@ -11,7 +12,13 @@ Most often a BIOS file is missing or wrong. -Run the command with `--check`. It changes nothing. + + +Your emulator says **BIOS not found**, **BIOS missing** or **firmware +missing**? Run the command with `--check`. It changes nothing. ```sh @@ -37,13 +44,17 @@ Run it without `--check`. It adds missing files and replaces wrong ones. - **Right folder?** [Get your files](../which-pack.md) names it. - **Exact name?** `scph5501.bin` and `SCPH-5501.BIN` differ. On Linux, - capitals count too. + capitals count too. The command adds names that differ by capitals. - **A `bios` folder inside your BIOS folder?** Move its files up one level. -- **Unzipped by hand on Linux?** The command adds names that differ by - capitals. +- **BIOS setting on a subfolder, like `system/dc`?** Point it at the BIOS + folder itself. Some emulators add their own, like `dc/` for Flycast, and + the command puts the files there. - **A ZIP in parts, like `Pack.part1of2.zip`?** Unzip every part into one folder. + + ## An arcade game does not start It needs its BIOS set, like `neogeo.zip`, and a game set for the same emulator @@ -51,7 +62,7 @@ version. - Keep `neogeo.zip` zipped. - A game set for another MAME version often fails. - Details: [the version of each emulator](../emulators/index.md). + Details: [the version of each emulator](technical-faq.md#which-mame-version-do-the-arcade-bios-sets-match). - Run the command once. It installs the BIOS sets your emulators read. ## The BIOS is fine, the game still fails @@ -59,7 +70,12 @@ version. - **Another emulator?** Each reads its own files, listed on its page. - **A BIOS setting?** Some emulators can skip the BIOS. In PCSX ReARMed, set **BIOS Selection** to **Auto**. -- **A disc in several files?** Open its `.cue` or `.m3u`, not a `.bin`. +- **The screen says "Please insert PlayStation CD-ROM"?** The BIOS works. + The game did not load: open its `.cue` or `.m3u` file, not a `.bin`. A + disc from another region shows it too. + + ## If the command fails { #installation-script-fails } From 34b3a9a9c6fd5348d4b43c3c3d266faeca057883 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:48:02 +0200 Subject: [PATCH 2/6] docs: arcade version table in technical faq --- wiki/faq.md | 16 +++++++++++----- wiki/glossary.md | 4 ++-- wiki/technical-faq.md | 24 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/wiki/faq.md b/wiki/faq.md index bd5c0b6ff..0c880f997 100644 --- a/wiki/faq.md +++ b/wiki/faq.md @@ -40,10 +40,10 @@ the ZIPs inside zipped, like `neogeo.zip`. Usually. The command installs each setup's own version, like its `neogeo.zip`. -## My arcade game does not start +## My arcade game fails (which MAME version?) { #my-arcade-game-does-not-start } The game set must match the emulator's version, and `neogeo.zip` stays zipped. -Reference: [Which version each emulator reads](technical-faq.md#which-mame-version-do-the-arcade-bios-sets-match). +Which version each emulator reads: [the list](technical-faq.md#which-mame-version-do-the-arcade-bios-sets-match). ## Keys, firmware or BIOS? @@ -80,8 +80,8 @@ setup's files and checks each one. `--dry-run` shows the list first. ## Fill an SD card from a computer? -Yes. Name your setup and the card's BIOS folder. For RetroArch on a Switch -card in drive `E:`: +Yes. Name your setup and the card's BIOS folder. For RetroArch on a Switch, +with the card in drive `E:`, run: ```sh @@ -98,7 +98,7 @@ Fill its folder from a computer, as above, or unzip your ZIP and check it with - Name your emulator's BIOS folder with `--dest`. - ES-DE, LaunchBox: the command fills the folders of the emulators they start. -- iPhone, iPad: no terminal. Use the ZIP. +- iPhone, iPad (iOS): no terminal. Use the ZIP. ## Why is a file missing from the ZIP? @@ -108,6 +108,12 @@ Some come with the emulator, so the ZIP skips them. Often a missing BIOS: [When a game does not start](troubleshooting.md). +## Can I copy my own console's BIOS? { #copy-your-own-bios } + +Yes. The emulators explain how: [PCSX2](https://pcsx2.net/docs/setup/bios/) +for PlayStation 2, [melonDS](https://melonds.kuribo64.net/faq.php) for DS and +DSi. + ## Is this legal? Laws differ by country. [Is it legal?](legal.md) diff --git a/wiki/glossary.md b/wiki/glossary.md index 6acb9644e..504b64897 100644 --- a/wiki/glossary.md +++ b/wiki/glossary.md @@ -22,8 +22,8 @@ order: 60 : The folder where your setup looks for BIOS files. **Pack** -: The ZIP file with every BIOS file for one setup. Made for the setups most - people download. +: The ZIP, sometimes in parts, with one setup's BIOS files. Made for the + setups most people download. **Platform** : A setup, as the project's data calls it. diff --git a/wiki/technical-faq.md b/wiki/technical-faq.md index 6a6b70022..c03bd9393 100644 --- a/wiki/technical-faq.md +++ b/wiki/technical-faq.md @@ -1,6 +1,7 @@ --- level: reference order: 120 +terms: mame version, romset version, which mame --- # Technical questions @@ -120,6 +121,29 @@ per catalog and the full list of catalogued dumps still missing. ## Which MAME version do the arcade BIOS sets match? +Your game sets and BIOS sets must come from the same version as your arcade +emulator. + +| Emulator, as RetroArch names it | Sets from | +|---|---| +| MAME 2000 | MAME 0.37b5 | +| MAME 2003, MAME 2003 Midway | MAME 0.78 | +| MAME 2003-Plus | MAME 0.78, with later fixes | +| MAME 2009 | MAME 0.135u4 | +| MAME 2010 | MAME 0.139 | +| MAME 2014, MAME 2015 | MAME 0.160 | +| MAME 2016 | MAME 0.174 | +| MAME/MESS | MAME 0.287 | +| MAME, MAME/Arcade | MAME 0.289 | +| FB Alpha 2012 CPS-1, FB Alpha 2012 CPS-2 | FB Alpha 0.2.97.28 | +| FB Alpha 2012, FB Alpha 2012 CPS-3, FB Alpha 2012 Neo Geo | FB Alpha 0.2.97.29 | +| FB Alpha 2019 | FB Alpha 0.2.97.44 | +| FinalBurn Neo, FinalBurn Neo (Neo-Geo), FinalBurn Neo (CPS-1 / CPS-2) | FinalBurn Neo 1.0.0.2 | + +Each emulator's page names its version too. + +### How this is known + Arcade BIOS sets are coupled to the romset version, so there is one profile per MAME core generation: MAME 2000 (0.37b5), MAME 2003 (0.78), MAME 2003-Plus, MAME 2009 (0.135u4), MAME 2010 (0.139), MAME 2015 From 6e7047b3fcd441a12d02c416fdb4e0726a55f010 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:48:02 +0200 Subject: [PATCH 3/6] feat: attach the installer to each release --- scripts/check_release.py | 23 ++++++++++++++++++++--- wiki/release-process.md | 11 +++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/scripts/check_release.py b/scripts/check_release.py index 92dda8697..e53e5b560 100644 --- a/scripts/check_release.py +++ b/scripts/check_release.py @@ -7,7 +7,9 @@ SHA256SUMS.txt lists for it, as must each handheld launcher (RetroBIOS.zip and the others build_port.py writes) the list names, the parts of a pack must add up to the download size the README prints, and nothing else may be attached. The record holds one pack for each platform the registry marks release_pack, and no other -pack. An upload that +pack. The installer (install.py, install.sh, install.ps1) and every file +list of install/ are listed and attached too, so a package can pin one +release. An upload that failed in the loop, or a part re-uploaded from an older build, otherwise publishes a release that `sha256sum --check` rejects for every user. @@ -37,6 +39,12 @@ from release_record import RECORD, load_record SUMS = "SHA256SUMS.txt" SIGNATURE = SUMS + ".sig" +INSTALLER = ("install.py", "install.sh", "install.ps1") + + +def installer_files(install_dir: str | Path = "install") -> list[str]: + """The release files a package pins: the installer and each file list.""" + return [*INSTALLER, *sorted(p.name for p in Path(install_dir).glob("*.json"))] @dataclass(frozen=True) @@ -73,6 +81,7 @@ def compare_release( tag: str, local_files: dict[str, str] | None = None, released: set[str] | None = None, + installer: list[str] | None = None, ) -> list[Finding]: """Every way the release can differ from what was built. @@ -80,6 +89,7 @@ def compare_release( signature) to its local sha256: the copy on the release must be that one. *released* names the platforms the registry marks release_pack: each one has a recorded pack, and no recorded pack serves only other platforms. + *installer* names the installer files each release lists and carries. """ findings: list[Finding] = [] if record.get("tag") != tag: @@ -112,9 +122,11 @@ def compare_release( findings.append(Finding("extra", name, "attached but neither recorded nor listed")) for name in sorted(set(recorded) - set(sums)): findings.append(Finding("unlisted", name, f"absent from {SUMS}")) + for name in sorted(set(installer or ()) - set(sums)): + findings.append(Finding("no-installer", name, f"absent from {SUMS}")) # The handheld launchers are release files but no packs: release.json # records packs, and the checksum list alone vouches for the launchers. - for name in sorted(set(sums) - set(recorded) - set(ARCHIVES)): + for name in sorted(set(sums) - set(recorded) - set(ARCHIVES) - set(installer or ())): findings.append(Finding("unrecorded", name, f"listed in {SUMS}, absent from release.json")) wanted = {**sums, **(local_files or {})} @@ -190,6 +202,10 @@ def main() -> int: "--platforms-dir", default="platforms", help="registry whose release_pack platforms each need a pack (default: %(default)s)", ) + parser.add_argument( + "--install-dir", default="install", + help="file lists the release must carry beside the installer (default: %(default)s)", + ) parser.add_argument("--json", action="store_true", help="JSON output") args = parser.parse_args() @@ -223,7 +239,8 @@ def main() -> int: return 2 released = set(list_release_pack_platforms(args.platforms_dir, include_archived=True)) - findings = compare_release(record, sums, assets, tag, local_files, released) + findings = compare_release(record, sums, assets, tag, local_files, released, + installer_files(args.install_dir)) if args.json: print(json.dumps( {"tag": tag, "draft": draft, "assets": len(assets), diff --git a/wiki/release-process.md b/wiki/release-process.md index 923da6247..f3c73dd90 100644 --- a/wiki/release-process.md +++ b/wiki/release-process.md @@ -227,11 +227,17 @@ python scripts/split_pack.py dist/ # check_release.py compares each asset with its line there. python scripts/build_port.py +# 2c. The installer and the file lists step 1 wrote, so a package can pin +# one release (installer page, "For packagers"). check_release.py +# refuses a release that lacks one of them. +cp install.py install.sh install.ps1 install/*.json dist/ + # 3. Checksums of the files as published, then sign the list. The checksums # answer corruption, and the signature answers a rewritten release, which is # the one thing a checksum published beside its own artifacts cannot # answer. -(cd dist && sha256sum *.zip RetroBIOS.muxapp > SHA256SUMS.txt) +(cd dist && sha256sum *.zip RetroBIOS.muxapp install.py install.sh install.ps1 \ + $(cd ../install && ls *.json) > SHA256SUMS.txt) ssh-keygen -Y sign -f ~/.ssh/retrobios_signing -n file dist/SHA256SUMS.txt # 4. Record what each pack holds, read from the archives just checked: @@ -253,7 +259,8 @@ python scripts/release_notes.py --whats-new tmp/whats-new.md --output tmp/notes. # A public release with half its assets is a broken download for everyone # during the whole upload. gh release create "v${DATE}" --draft --title "BIOS Pack v${DATE}" --notes-file tmp/notes.md -for f in dist/SHA256SUMS.txt dist/SHA256SUMS.txt.sig dist/*.zip dist/RetroBIOS.muxapp; do +for f in dist/SHA256SUMS.txt dist/SHA256SUMS.txt.sig dist/*.zip dist/RetroBIOS.muxapp \ + dist/install.py dist/install.sh dist/install.ps1 $(ls install/*.json | sed 's|^install/|dist/|'); do [ -f "$f" ] && gh release upload "v${DATE}" "$f#$(basename "$f")" --clobber done # A count does not see a failed upload beside a stray file, nor a part From 2c756eac86e1143f38b4d2e346219e8766b626b8 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:48:02 +0200 Subject: [PATCH 4/6] docs: link each installer option to its row --- wiki/installer.md | 178 ++++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 76 deletions(-) diff --git a/wiki/installer.md b/wiki/installer.md index ea072e166..c11fc5000 100644 --- a/wiki/installer.md +++ b/wiki/installer.md @@ -1,6 +1,7 @@ --- level: setup order: 100 +terms: manifest, events, exit code, schema --- # All installer options @@ -22,10 +23,13 @@ How the command protects your machine is under ## Options at a glance -Read from the installer's own option list, the one `--help` prints. The -[Options](#options) table below gives each one in full. +Each links to its row in the [Options](#options) table. - +- **Where and for what**: [`--platform`](#option-platform), [`--dest`](#option-dest), [`--target`](#option-target), [`--every-board`](#option-every-board), [`--save-dir`](#option-save-dir), [`--romm-firmware`](#option-romm-firmware), [`--standalone-copies`](#option-standalone-copies) +- **Fewer files**: [`--system`](#option-system), [`--core`](#option-core), [`--emulator`](#option-emulator), [`--region`](#option-region), [`--no-game-data`](#option-no-game-data), [`--installed-cores`](#option-installed-cores), [`--cores-dir`](#option-cores-dir) +- **Look first**: [`--check`](#option-check), [`--dry-run`](#option-dry-run), [`--list-platforms`](#option-list-platforms), [`--list-targets`](#option-list-targets), [`--list-systems`](#option-list-systems), [`--list-cores`](#option-list-cores), [`--list-emulators`](#option-list-emulators) +- **From files you have**: [`--from`](#option-from), [`--from-pack`](#option-from-pack), [`--manifest`](#option-manifest), [`--restore`](#option-restore) +- **How the run talks**: [`--tui`](#option-tui), [`--plain`](#option-plain), [`--no-input`](#option-no-input), [`--yes`](#option-yes), [`--quiet`](#option-quiet), [`--verbose`](#option-verbose), [`--events`](#option-events), [`--jobs`](#option-jobs), [`--version`](#option-version), [`--help`](#option-help) ## One line @@ -46,16 +50,27 @@ needed, and Python 3.8 is the floor both bootstraps enforce before handing over: python install.py ``` -A package that must not change under its users pins the installer to a -release tag, and the file lists to the same tag with `RETROBIOS_REF`: +### For packagers { #for-packagers } + +A package that must not change under its users takes the installer and its +file list from one release. Each release carries `install.py`, `install.sh`, +`install.ps1` and the file list of every platform (`retroarch.json` and the +others from `install/`), all listed in the signed `SHA256SUMS.txt`: ```bash -curl -fsSLO https://raw.githubusercontent.com/Abdess/retrobios//install.py -RETROBIOS_REF= python3 install.py +base=https://github.com/Abdess/retrobios/releases/download/ +curl -fsSLO "$base/install.py" -O "$base/retroarch.json" -O "$base/SHA256SUMS.txt" +sha256sum --check --ignore-missing SHA256SUMS.txt +RETROBIOS_REF= python3 install.py --manifest retroarch.json ``` -A tag lasts until the next release deletes it. What `RETROBIOS_REF` does not -pin is listed under [Environment overrides](#environment-overrides). +For contributors: [Verifying a release](release-process.md#verifying-a-release) +checks the signature of the list. Each release deletes the previous tag and its assets, +so `releases/latest/download/install.py` and the other files under +`releases/latest/download/` are the stable addresses: they serve the latest +release, whose `SHA256SUMS.txt` names the bytes. v2026.10.10 and the releases +before it carry neither the installer nor the file lists. What `RETROBIOS_REF` +does not pin is listed under [Environment overrides](#environment-overrides). ## Passing options @@ -79,6 +94,36 @@ from the text and calling it passes the arguments through: --platform retroarch --dest D:\bios ``` +## Without a network (offline install) { #without-a-network-offline-install } + + + +A pack downloaded once installs again with no network, on this machine or on +one that has none: + +```bash +python install.py --from-pack ~/Downloads/RetroArch_v1.22.2_BIOS_Pack.zip +python install.py --from-pack ~/Downloads/RetroArch_v1.22.2_BIOS_Pack.part1of3.zip +python install.py --from-pack ~/Downloads --dest /media/card/retroarch/system +``` + +One part is enough to name a split pack: the others are taken from the same +folder, and a part that is not there is named before anything is written. +The platform is read from the pack's name when `--platform` is not given. The +file list is the one the pack carries (`manifest.json`), with each file's +SHA-1 and size, and every file is checked against it before it takes its +place. A data tree (Dolphin's `Sys/`, PPSSPP's assets) comes from the pack +too, not from its source archive. `--target` reads a core list from the +network and is refused with `--from-pack`. A board found on the device is not +applied either: every board's files are installed. + +`--manifest FILE` reads the file list from a copy of `install/.json` +instead of downloading it. Alone, the files still come from the repository. +With `--from-pack`, the run reads that list and takes every file from the +pack: `--system`, `--core`, `--region` and `--no-game-data` then apply as +they do online, and a file of the list the pack does not hold fails as +`not in the pack`. The list's platform has to be the one installed for. + ## The full-screen interface { #the-full-screen-interface } Run at a terminal, the installer opens a full screen that a keyboard or a @@ -623,41 +668,41 @@ what the options name, everything by default. | Option | Effect | |--------|--------| -| `--platform NAME` | Install for this platform instead of the detected one. A system `--list-platforms` names under its own files (`muos`, `arkos`) stands for the file list it gets, and the run says which. Unknown names are refused with the closest ones | -| `--dest PATH` | Destination directory, overriding detection. Without `--platform`, the file list is the platform detected here: at a terminal the installer asks, Enter taking the one found, and otherwise it uses the one found, RetroArch's when nothing is found, and refuses when several are. The run prints whose list it is. A folder that does not exist is named with the nearest one that does, then created. When more than its last level is missing (a mistyped path), a run at a terminal asks first, and the answer defaults to no | -| `--target NAME` | Keep only the files the cores of that hardware target need, and the systems they emulate. An unknown target is refused rather than ignored, since carrying on would install everything. On Batocera, Recalbox, ROCKNIX and Lakka the board is read from the system (`batocera.arch`, `recalbox.arch`, `HW_DEVICE`, `LIBREELEC_DEVICE` or `LIBREELEC_PROJECT`) and applied when no `--target` is given | -| `--every-board` | Install the files of every board instead of the one the system names, for a card that moves between devices | -| `--installed-cores` | Keep only what the cores already installed read (RetroArch, Lakka, RetroPie). See [Installed cores](#installed-cores) | -| `--cores-dir PATH` | The folder RetroArch loads its cores from, for `--installed-cores` when it is not found. Implies `--installed-cores` | -| `--save-dir PATH` | The frontend's save directory (RetroArch's `savefile_directory`), for the files some cores read there, when the run cannot find it. The core's own folder is still added below it when the frontend sorts saves by core | -| `--system NAMES` | Install only these systems. Comma-separated or repeated. `--list-systems` prints the names, `other` included. A short name the platform does not use (`gba`, `psx`) is refused with the ids it may stand for, never taken in their place | -| `--core NAMES` | Keep the platform's own list and only the extra files these cores load. `--list-cores` prints the names | -| `--emulator NAMES` | Install what these emulators read on the detected platform, and nothing else: their own files and the platform's files of the systems they run. Each emulator page on the site gives this command. `--list-emulators` prints the names, buildbot names such as `mednafen_psx` included | -| `--region LIST` | Preferred regions, best first (`us,eu,jp`): keep one BIOS per region where a system has several. Accepts the names and aliases of `generate_pack.py --region` | -| `--no-game-data` | Leave out game data (a game's own files, not firmware) and install the firmware only. What it leaves out is named. See [Firmware without game data](#firmware-without-game-data) | -| `--list-systems` | Print a platform's systems with the files and size each holds, the files other systems share too counted apart | -| `--list-cores` | Print the cores whose extra files a platform installs | -| `--list-emulators` | Print every name `--emulator` accepts, each buildbot name beside the emulator it stands for | -| `--romm-firmware TEMPLATE` | RomM: where each platform's firmware goes in the library, as `filesystem.structure.firmware` in RomM's `config.yml` says (`{platform}/bios` for a library laid out as `{platform}/roms`). Read from `config.yml` beside the library when it is there. See [RomM firmware layout](#romm-firmware-layout) | -| `--no-input` | Never ask a question, even at a terminal | -| `--check` | Report and exit without writing | -| `--dry-run` | Show what would be downloaded, by system and with sizes, without writing anything | -| `--yes`, `-y` | Do not ask before a download of 1 GB or more | -| `--quiet`, `-q` | Print only failures and the final summary. Implies `--no-input` | -| `--events` | Write the run as JSON events on standard output, one object per line, and the usual text on standard error. Implies `--no-input`. See [Machine-readable events](#machine-readable-events) | -| `--from FOLDER` | Copy the BIOS files a folder holds (an old SD card, a backup, a ZIP) instead of downloading them, each one recognised by its hash and copied, never moved. Repeat for several folders. See [Copy from an old card](#copy-from-an-old-card) | -| `--from-pack PATH` | Install from a pack already downloaded: its ZIP, one of its parts (the others are found in the same folder), or the folder holding them. Makes no network request and checks every file's hash. See [Without a network](#without-a-network-offline-install) | -| `--manifest FILE` | Read the file list from FILE, a copy of `install/.json`, instead of downloading it. See [Without a network](#without-a-network-offline-install) | -| `--restore FOLDER` | Put back the files a run replaced and kept in FOLDER, a dated folder inside `retrobios-backup`. Takes no other option but `--dry-run` and `--no-input`. See [Files you already had](#files-you-already-had) | -| `--tui` | Open the full-screen interface, or stop with the reason it cannot open here (code 2) instead of falling back to the questions. Wins over `RETROBIOS_PLAIN` and `ACCESSIBLE`. See [The full-screen interface](#the-full-screen-interface) | -| `--plain` | Ask the questions line by line instead of the full-screen interface, the mode for a screen reader. See [The full-screen interface](#the-full-screen-interface) | -| `--version` | Print the installer's identity, the first 12 hex digits of the SHA-256 the bootstraps pin | -| `--list-platforms` | Print the supported platforms and what was detected here | -| `--list-targets` | Print the hardware targets a platform publishes, with the core count each carries | -| `--jobs N`, `-j N` | Parallel downloads, 1 to 32, default 8 | -| `--verbose`, `-v` | Print per-attempt failures and hash mismatches | -| `--standalone-copies` | Also copy into detected standalone emulator directories | -| `--help`, `-h` | Print the option list, a few examples in the form the run was started with, and the address of this page | +| `--platform NAME` | Install for this platform instead of the detected one. A system `--list-platforms` names under its own files (`muos`, `arkos`) stands for the file list it gets, and the run says which. Unknown names are refused with the closest ones | +| `--dest PATH` | Destination directory, overriding detection. Without `--platform`, the file list is the platform detected here: at a terminal the installer asks, Enter taking the one found, and otherwise it uses the one found, RetroArch's when nothing is found, and refuses when several are. The run prints whose list it is. A folder that does not exist is named with the nearest one that does, then created. When more than its last level is missing (a mistyped path), a run at a terminal asks first, and the answer defaults to no | +| `--target NAME` | Keep only the files the cores of that hardware target need, and the systems they emulate. An unknown target is refused rather than ignored, since carrying on would install everything. On Batocera, Recalbox, ROCKNIX and Lakka the board is read from the system (`batocera.arch`, `recalbox.arch`, `HW_DEVICE`, `LIBREELEC_DEVICE` or `LIBREELEC_PROJECT`) and applied when no `--target` is given | +| `--every-board` | Install the files of every board instead of the one the system names, for a card that moves between devices | +| `--installed-cores` | Keep only what the cores already installed read (RetroArch, Lakka, RetroPie). See [Installed cores](#installed-cores) | +| `--cores-dir PATH` | The folder RetroArch loads its cores from, for `--installed-cores` when it is not found. Implies `--installed-cores` | +| `--save-dir PATH` | The frontend's save directory (RetroArch's `savefile_directory`), for the files some cores read there, when the run cannot find it. The core's own folder is still added below it when the frontend sorts saves by core | +| `--system NAMES` | Install only these systems. Comma-separated or repeated. `--list-systems` prints the names, `other` included. A short name the platform does not use (`gba`, `psx`) is refused with the ids it may stand for, never taken in their place | +| `--core NAMES` | Keep the platform's own list and only the extra files these cores load. `--list-cores` prints the names | +| `--emulator NAMES` | Install what these emulators read on the detected platform, and nothing else: their own files and the platform's files of the systems they run. Each emulator page on the site gives this command. `--list-emulators` prints the names, buildbot names such as `mednafen_psx` included | +| `--region LIST` | Preferred regions, best first (`us,eu,jp`): keep one BIOS per region where a system has several. Accepts the names and aliases of `generate_pack.py --region` | +| `--no-game-data` | Leave out game data (a game's own files, not firmware) and install the firmware only. What it leaves out is named. See [Firmware without game data](#firmware-without-game-data) | +| `--list-systems` | Print a platform's systems with the files and size each holds, the files other systems share too counted apart | +| `--list-cores` | Print the cores whose extra files a platform installs | +| `--list-emulators` | Print every name `--emulator` accepts, each buildbot name beside the emulator it stands for | +| `--romm-firmware TEMPLATE` | RomM: where each platform's firmware goes in the library, as `filesystem.structure.firmware` in RomM's `config.yml` says (`{platform}/bios` for a library laid out as `{platform}/roms`). Read from `config.yml` beside the library when it is there. See [RomM firmware layout](#romm-firmware-layout) | +| `--no-input` | Never ask a question, even at a terminal | +| `--check` | Report and exit without writing | +| `--dry-run` | Show what would be downloaded, by system and with sizes, without writing anything | +| `--yes`, `-y` | Do not ask before a download of 1 GB or more | +| `--quiet`, `-q` | Print only failures and the final summary. Implies `--no-input` | +| `--events` | Write the run as JSON events on standard output, one object per line, and the usual text on standard error. Implies `--no-input`. See [Machine-readable events](#machine-readable-events) | +| `--from FOLDER` | Copy the BIOS files a folder holds (an old SD card, a backup, a ZIP) instead of downloading them, each one recognised by its hash and copied, never moved. Repeat for several folders. See [Copy from an old card](#copy-from-an-old-card) | +| `--from-pack PATH` | Install from a pack already downloaded: its ZIP, one of its parts (the others are found in the same folder), or the folder holding them. Makes no network request and checks every file's hash. See [Without a network](#without-a-network-offline-install) | +| `--manifest FILE` | Read the file list from FILE, a copy of `install/.json`, instead of downloading it. See [Without a network](#without-a-network-offline-install) | +| `--restore FOLDER` | Put back the files a run replaced and kept in FOLDER, a dated folder inside `retrobios-backup`. Takes no other option but `--dry-run` and `--no-input`. See [Files you already had](#files-you-already-had) | +| `--tui` | Open the full-screen interface, or stop with the reason it cannot open here (code 2) instead of falling back to the questions. Wins over `RETROBIOS_PLAIN` and `ACCESSIBLE`. See [The full-screen interface](#the-full-screen-interface) | +| `--plain` | Ask the questions line by line instead of the full-screen interface, the mode for a screen reader. See [The full-screen interface](#the-full-screen-interface) | +| `--version` | Print the installer's identity, the first 12 hex digits of the SHA-256 the bootstraps pin | +| `--list-platforms` | Print the supported platforms and what was detected here | +| `--list-targets` | Print the hardware targets a platform publishes, with the core count each carries | +| `--jobs N`, `-j N` | Parallel downloads, 1 to 32, default 8 | +| `--verbose`, `-v` | Print per-attempt failures and hash mismatches | +| `--standalone-copies` | Also copy into detected standalone emulator directories | +| `--help`, `-h` | Print the option list, a few examples in the form the run was started with, and the address of this page | `--check` reads the same file list, hashes the destination and exits, with code 1 when a file is missing or does not match and 0 when every one does. Files @@ -1024,36 +1069,6 @@ file lists come from `main`. The launchers in `ports/` start it with `--tui`, and read it through [Machine-readable events](#machine-readable-events) for the rest. -## Without a network (offline install) { #without-a-network-offline-install } - - - -A pack downloaded once installs again with no network, on this machine or on -one that has none: - -```bash -python install.py --from-pack ~/Downloads/RetroArch_v1.22.2_BIOS_Pack.zip -python install.py --from-pack ~/Downloads/RetroArch_v1.22.2_BIOS_Pack.part1of3.zip -python install.py --from-pack ~/Downloads --dest /media/card/retroarch/system -``` - -One part is enough to name a split pack: the others are taken from the same -folder, and a part that is not there is named before anything is written. -The platform is read from the pack's name when `--platform` is not given. The -file list is the one the pack carries (`manifest.json`), with each file's -SHA-1 and size, and every file is checked against it before it takes its -place. A data tree (Dolphin's `Sys/`, PPSSPP's assets) comes from the pack -too, not from its source archive. `--target` reads a core list from the -network and is refused with `--from-pack`. A board found on the device is not -applied either: every board's files are installed. - -`--manifest FILE` reads the file list from a copy of `install/.json` -instead of downloading it. Alone, the files still come from the repository. -With `--from-pack`, the run reads that list and takes every file from the -pack: `--system`, `--core`, `--region` and `--no-game-data` then apply as -they do online, and a file of the list the pack does not hold fails as -`not in the pack`. The list's platform has to be the one installed for. - ## Where the files come from Each manifest entry names either `repo_path`, served from the repository at the @@ -1165,11 +1180,11 @@ fields, the installer refuses to narrow rather than install everything. | `141` | the output was piped to a reader that closed early (`--list-platforms \| head`) | `install.ps1` passes the installer's code on unchanged: run as a file it exits -with it, run through `irm \| iex` it sets `$LASTEXITCODE` (an `exit` there +with it, run through `irm | iex` it sets `$LASTEXITCODE` (an `exit` there would close the PowerShell window). It declares no parameter of its own, so every argument reaches `install.py` as typed, short forms such as `-v` included. Its body runs in a script block of its own, -so `irm \| iex` leaves neither its variables nor its `$ErrorActionPreference` +so `irm | iex` leaves neither its variables nor its `$ErrorActionPreference` in the session. Failures that are per-file, such as a download exhausting its three attempts, @@ -1212,6 +1227,17 @@ existing kind: a reader skips a kind it does not know. An option refused before the run starts (`install.py: error:`, code 2) writes no event at all. A program reads a missing `end` as that case. +Five lines of a run of `--check --events --system sony-playstation` on a +RetroArch folder that holds only `scph5501.bin`, in the order written: + +```json +{"event": "start", "schema": 1, "installer": "c90676dcc433", "mode": "check"} +{"event": "file", "platform": "retroarch", "dest": "scph5501.bin", "systems": ["sony-playstation"], "size": 524288, "state": "present"} +{"event": "check", "platform": "retroarch", "name": "RetroArch", "bios_dir": "system", "files": 118, "present": 1, "missing": 117, "wrong_hash": 0, "bytes_needed": 344457216, "data_missing": 0, "not_installable": 0} +{"event": "summary", "mode": "check", "installed": 0, "up_to_date": 1, "pending": 117, "failed": [], "skipped": [], "left_out": [], "kept": [], "interrupted": false} +{"event": "end", "code": 1} +``` + ## Environment overrides | Variable | Effect | From b305167a95f7fbbad35810a54b5ae964bdb0ecf3 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Fri, 23 Oct 2026 18:48:02 +0200 Subject: [PATCH 5/6] chore: test the round 4 wiki copy --- tests/test_site_copy.py | 4 +- tests/test_site_funnel.py | 7 + tests/test_site_r2_wiki.py | 12 +- tests/test_site_r3_wiki.py | 10 +- tests/test_site_r4_wiki.py | 352 +++++++++++++++++++++++++++++++++++++ wiki/testing-guide.md | 2 +- 6 files changed, 376 insertions(+), 11 deletions(-) create mode 100644 tests/test_site_r4_wiki.py diff --git a/tests/test_site_copy.py b/tests/test_site_copy.py index ebf809516..3f7dff44b 100644 --- a/tests/test_site_copy.py +++ b/tests/test_site_copy.py @@ -32,8 +32,8 @@ START_PAGES = { "which-pack.md": 400, "wiki/what-are-bios-files.md": 300, "wiki/first-install.md": 400, - "wiki/troubleshooting.md": 300, - "wiki/faq.md": 450, + "wiki/troubleshooting.md": 345, + "wiki/faq.md": 480, "wiki/glossary.md": 200, } # Level 1: the guide part of each setup page, above its Reference heading. diff --git a/tests/test_site_funnel.py b/tests/test_site_funnel.py index d9ff2b25f..099c721e1 100644 --- a/tests/test_site_funnel.py +++ b/tests/test_site_funnel.py @@ -201,6 +201,11 @@ class DeepLinksCarryALabel(unittest.TestCase): more says what it leads to, with that page's level label before it on its line, or in the heading of its section ("## Reference: ...").""" + # Answers a start page sends its reader to on purpose: the arcade + # version table opens on one plain sentence, and "Reference:" before + # its link read as a broken crumb (round 4, C4 and C9). + ANSWERS = ("/retrobios/wiki/technical-faq/#which-mame-version-do-the-arcade-bios-sets-match",) + def test_start_and_setup_pages(self): import sitestarlight # noqa: PLC0415 @@ -228,6 +233,8 @@ class DeepLinksCarryALabel(unittest.TestCase): deeper = levels[target] if ORDER.index(deeper) - ORDER.index(level) < 2: continue + if any(f"]({answer})" in match.group(0) for answer in self.ANSWERS): + continue label = f"{generate_site.LEVELS[deeper]}:" if label not in line[: match.start()] and not any( heading.startswith(label) for heading in headings.values()): diff --git a/tests/test_site_r2_wiki.py b/tests/test_site_r2_wiki.py index 361114bd9..f3c58db0f 100644 --- a/tests/test_site_r2_wiki.py +++ b/tests/test_site_r2_wiki.py @@ -360,11 +360,15 @@ class InstallerOptionsAtAGlance(unittest.TestCase): listed = {usage.split()[0].rstrip(",") for usage, _ in sitediagrams.installer_options()} self.assertEqual(declared | {"--help"}, listed) - def test_the_built_page_opens_on_the_table(self): + def test_the_built_page_opens_on_a_link_per_option(self): text = _built("wiki/installer.md") - table = text.index("| Option | What it does | More |") - self.assertLess(table, text.index("## One line")) - self.assertIn("| `--check` |", text) + glance = text.index("## Options at a glance") + self.assertLess(glance, text.index("## One line")) + listed = text[glance:text.index("## One line")] + for usage, _ in sitediagrams.installer_options(): + flag = usage.split()[0].rstrip(",") + with self.subTest(option=flag): + self.assertIn(f"[`{flag}`](#option-{flag.lstrip('-')})", listed) self.assertNotIn(" @@ -97,7 +96,7 @@ Fill its folder from a computer, as above, or unzip your ZIP and check it with ## My setup is not in the list - Name your emulator's BIOS folder with `--dest`. -- ES-DE, LaunchBox: the command fills the folders of the emulators they start. +- ES-DE, LaunchBox: the command fills their emulators' folders. - iPhone, iPad (iOS): no terminal. Use the ZIP. ## Why is a file missing from the ZIP? @@ -110,9 +109,8 @@ Often a missing BIOS: [When a game does not start](troubleshooting.md). ## Can I copy my own console's BIOS? { #copy-your-own-bios } -Yes. The emulators explain how: [PCSX2](https://pcsx2.net/docs/setup/bios/) -for PlayStation 2, [melonDS](https://melonds.kuribo64.net/faq.php) for DS and -DSi. +Yes: [PCSX2](https://pcsx2.net/docs/setup/bios/) for PlayStation 2, +[melonDS](https://melonds.kuribo64.net/faq.php) for DS and DSi. ## Is this legal? diff --git a/wiki/troubleshooting.md b/wiki/troubleshooting.md index bba8e39dd..2be073a2f 100644 --- a/wiki/troubleshooting.md +++ b/wiki/troubleshooting.md @@ -43,14 +43,11 @@ Run it without `--check`. It adds missing files and replaces wrong ones. ## 3. Check the folder and the names - **Right folder?** [Get your files](../which-pack.md) names it. -- **Exact name?** `scph5501.bin` and `SCPH-5501.BIN` differ. On Linux, - capitals count too. The command adds names that differ by capitals. +- **Exact name?** `scph5501.bin` and `SCPH-5501.BIN` differ. - **A `bios` folder inside your BIOS folder?** Move its files up one level. - **BIOS setting on a subfolder, like `system/dc`?** Point it at the BIOS - folder itself. Some emulators add their own, like `dc/` for Flycast, and - the command puts the files there. -- **A ZIP in parts, like `Pack.part1of2.zip`?** Unzip every part into one - folder. + folder. Emulators add their own, like `dc/` for Flycast. +- **A ZIP in parts?** Unzip every part into one folder. @@ -60,10 +57,9 @@ shell/libretro/libretro.cpp:2252-2253, emulators/flycast.yml. --> It needs its BIOS set, like `neogeo.zip`, and a game set for the same emulator version. -- Keep `neogeo.zip` zipped. -- A game set for another MAME version often fails. +- Another MAME version's game set often fails. Details: [the version of each emulator](technical-faq.md#which-mame-version-do-the-arcade-bios-sets-match). -- Run the command once. It installs the BIOS sets your emulators read. +- Run the command once. It installs the BIOS sets. ## The BIOS is fine, the game still fails @@ -71,17 +67,13 @@ version. - **A BIOS setting?** Some emulators can skip the BIOS. In PCSX ReARMed, set **BIOS Selection** to **Auto**. - **The screen says "Please insert PlayStation CD-ROM"?** The BIOS works. - The game did not load: open its `.cue` or `.m3u` file, not a `.bin`. A - disc from another region shows it too. - - + The game did not load: open its `.cue` or `.m3u` file, not a `.bin`. ## If the command fails { #installation-script-fails } - **Network error:** try again later. - **`The clock reads ...`:** set the right date. -- **Permission denied:** do what the message says. It names what to run. +- **Permission denied:** do what the message says. - **No setup found:** name it and its folder: