chore: merge round 5 wiki fixes

This commit is contained in:
Abdessamad Derraz committed 2026-10-24 01:30:33 +02:00
commit 6936302133
11 files changed
+298 -48

No files matched your search

+14 -4
View File
@@ -739,11 +739,12 @@ def localize_images(markdown: str, page: Path) -> str:
# system, the Windows form written by the same function as the setup pages'.
OS_TABS = re.compile(
r"(?m)^(?P<indent>[ \t]*)<!--\s*os-tabs(?:\s+windows:\s*(?P<windows>.*?))?\s*-->[ \t]*\n"
r"(?m)^(?P<indent>[ \t]*)<!--\s*os-tabs(?P<own>(?:\s+[^\n]*?)?)\s*-->[ \t]*\n"
r"(?P=indent)```(?:sh|bash)[^\n]*\n(?P<body>.*?)\n(?P=indent)```[ \t]*$",
re.S,
)
OS_TAB_KEYS = ("windows", "macos", "linux", "steamdeck")
_OWN_ARGS = re.compile(r"(?:^|\s)(" + "|".join(OS_TAB_KEYS) + r"):\s*")
FENCE_TITLES = {"sh": "Terminal", "powershell": "PowerShell"}
@@ -758,10 +759,18 @@ def _installer_args(body: str) -> str:
return match.group(1) or ""
def _own_args(text: str) -> dict[str, str]:
"""`windows: ARGS macos: ARGS` -> the options each named tab uses."""
parts = _OWN_ARGS.split(text.strip())
if parts[0].strip():
raise ValueError(f"an os-tabs marker names no system: {text.strip()!r}")
return {key: value.strip() for key, value in zip(parts[1::2], parts[2::2])}
def expand_commands(markdown: str) -> str:
"""Each install command marked `<!-- os-tabs -->` as Windows, macOS,
Linux and Steam Deck tabs. `<!-- os-tabs windows: ARGS -->` gives the
Windows tab its own options, for a path written another way there."""
Linux and Steam Deck tabs. `<!-- os-tabs windows: ARGS macos: ARGS -->`
gives a tab its own options, for a folder that differs there."""
if "os-tabs" not in markdown:
return markdown
from siteguides import TERMINALS, install_command
@@ -769,10 +778,11 @@ def expand_commands(markdown: str) -> str:
def replace(match: re.Match[str]) -> str:
indent = match.group("indent")
args = _installer_args(match.group("body"))
own_args = _own_args(match.group("own"))
items = []
for key in OS_TAB_KEYS:
label, _how, shell = TERMINALS[key]
own = match.group("windows") if key == "windows" and match.group("windows") else args
own = own_args.get(key) or args
items.append((label, [f'```{shell} title="{FENCE_TITLES[shell]}"',
install_command(shell, own), "```"]))
return "\n".join(markup.tabs(items, indent)).rstrip("\n")
+7 -5
View File
@@ -198,8 +198,9 @@ class SetupsWithoutAPage(unittest.TestCase):
for words in ("--dest", "ES-DE", "LaunchBox", "iPhone"):
with self.subTest(words=words):
self.assertIn(words, section)
# No folder is written: the copy names none it cannot cite.
self.assertNotRegex(section, r"[~/\\][A-Za-z]")
# No folder is written: the copy names none it cannot cite. Link
# targets are pages of this site, not folders.
self.assertNotRegex(re.sub(r"\]\([^)]*\)", "]", section), r"[~/\\][A-Za-z]")
def test_the_installer_fills_the_emulators_a_launcher_starts(self):
installer = _flat(_wiki("installer.md"))
@@ -234,11 +235,12 @@ class ExitStatusAndPinnedInstaller(unittest.TestCase):
with self.subTest(field=field):
self.assertIn(f'"{field}"', fields)
def test_a_packager_pins_installer_and_lists_to_one_tag(self):
def test_a_packager_pins_installer_and_lists_to_one_commit(self):
# No release carries the installer yet: the section pins a commit.
section = _section(self.text, "One line")
self.assertIn("releases/download/<tag>", section)
self.assertIn("raw.githubusercontent.com/Abdess/retrobios/$commit", section)
self.assertIn("$base/install.py", section)
self.assertIn("RETROBIOS_REF=<tag>", section)
self.assertIn("RETROBIOS_REF=$commit", section)
self.assertIn('os.environ.get("RETROBIOS_REF"', self.source)
+8 -5
View File
@@ -262,15 +262,18 @@ class PinnedInstaller(unittest.TestCase):
self.assertIn(f"dist/{name}", upload)
self.assertIn("install/*.json", upload)
def test_the_installer_page_names_the_release_addresses(self):
def test_the_installer_page_pins_one_commit(self):
# v2026.10.10 carries no install.py: until a release does, the
# section pins a commit, never a release address.
text = _wiki("installer.md")
section = _flat(_section(text, "For packagers"))
for words in ("releases/download/<tag>", "--manifest retroarch.json",
"sha256sum --check", "SHA256SUMS.txt", "releases/latest/download/",
"release-process.md#verifying-a-release"):
for words in ("raw.githubusercontent.com/Abdess/retrobios/$commit",
'"$base/install/retroarch.json"', "--manifest retroarch.json",
"sha256sum --check", "RETROBIOS_REF=$commit"):
with self.subTest(words=words):
self.assertIn(words, section)
self.assertNotIn("raw.githubusercontent.com/Abdess/retrobios/<tag>/install.py", text)
self.assertNotIn("releases/download/", section)
self.assertNotIn("releases/latest/download/", section)
terms = _front(text)["terms"]
for word in ("manifest", "events", "exit code", "schema"):
with self.subTest(term=word):
+225
View File
@@ -0,0 +1,225 @@
"""Wiki (round 5, package 5).
Each class names the finding it holds: a "no setup" command that sent
macOS and Steam Deck files where RetroArch never reads, a level 0 rule that
every emulator needs one exact name, FAQ answers that ended at a ZIP most
setups lack, a packager section pointing at release assets that do not
exist, and two copy fixes. Every claim is held against install.py, the
setup guides or the generator that writes the page a link opens.
"""
from __future__ import annotations
import re
import sys
import unittest
from pathlib import Path
import yaml
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT))
sys.path.insert(0, str(REPO_ROOT / "scripts"))
import sitediagrams # noqa: E402
from siteguides import INSTALL_BASE # noqa: E402
from tests import sitepages # noqa: E402
WIKI = REPO_ROOT / "wiki"
FENCED = re.compile(r"^```.*?^```", re.S | re.M)
INSTALL_PY = (REPO_ROOT / "install.py").read_text(encoding="utf-8")
def _wiki(name: str) -> str:
return (WIKI / name).read_text(encoding="utf-8")
def _front(text: str) -> dict:
return yaml.safe_load(text.split("---", 2)[1])
def _section(text: str, heading: str) -> str:
start = re.search(rf"(?m)^#+ {re.escape(heading)}(?:\s*\{{[^}}]*\}})?\n", text)
if start is None:
raise AssertionError(f"no section {heading!r}")
rest = text[start.end():]
blank = FENCED.sub(lambda m: re.sub(r"[^\n]", " ", m.group(0)), rest)
end = re.search(r"(?m)^#{1,2} ", blank)
return rest[: end.start()] if end else rest
def _flat(text: str) -> str:
return " ".join(text.split())
def _guide_folders(name: str) -> dict[str, str]:
guides = yaml.safe_load((REPO_ROOT / "platforms" / "_guides.yml").read_text(encoding="utf-8"))
return {row["where"]: row["path"] for row in guides["guides"][name]["folders"]}
class NoSetupFoundGivesEachSystemItsFolder(unittest.TestCase):
"""C3: macOS, Linux and Steam Deck shared `~/.config/retroarch/system`."""
def setUp(self):
self.section = _section(_wiki("troubleshooting.md"), "If the command fails")
def test_the_label_is_the_installer_message(self):
self.assertIn("**`No supported platform detected`:**", self.section)
self.assertIn('print(" No supported platform detected.")', INSTALL_PY)
def test_the_lead_names_the_menu(self):
self.assertIn("Not sure? Open RetroArch's **Settings > Directory > System/BIOS**",
_flat(self.section))
def test_each_tab_carries_the_folder_retroarch_reads_there(self):
expected = {
# install.py's Windows default and the hint it prints.
"Windows": "C:\\RetroArch-Win64\\system",
"macOS": "~/Documents/RetroArch/system",
"Linux": "~/.config/retroarch/system",
"Steam Deck": "~/.var/app/org.libretro.RetroArch/config/retroarch/system",
}
self.assertIn('_host_path("C:/RetroArch-Win64/system")', INSTALL_PY)
self.assertIn('"windows": "C:\\\\RetroArch-Win64\\\\system"', INSTALL_PY)
self.assertIn('return Path.home() / "Documents" / "RetroArch"', INSTALL_PY)
folders = _guide_folders("retroarch")
self.assertEqual(folders["macOS"], f"`{expected['macOS']}/`")
self.assertEqual(folders["Linux"], f"`{expected['Linux']}/`")
self.assertEqual(folders["Steam Deck and Linux Flatpak"], f"`{expected['Steam Deck']}/`")
tabs = sitediagrams.expand_commands(self.section)
parts = re.split(r'<TabItem label="([^"]+)">', tabs)
bodies = dict(zip(parts[1::2], parts[2::2]))
self.assertEqual(set(bodies), set(expected))
for label, folder in expected.items():
with self.subTest(tab=label):
self.assertIn(f"--platform retroarch --dest {folder}\n", bodies[label])
others = {f for key, f in expected.items() if key != label}
for other in others:
self.assertNotIn(f"--dest {other}\n", bodies[label])
def test_the_built_page_shows_four_folders(self):
sitepages.require()
built = sitepages.page("wiki/troubleshooting.md").read_text(encoding="utf-8")
self.assertNotIn("os-tabs", built)
for folder in ("C:\\RetroArch-Win64\\system", "~/Documents/RetroArch/system",
"~/.config/retroarch/system",
"~/.var/app/org.libretro.RetroArch/config/retroarch/system"):
with self.subTest(folder=folder):
self.assertIn(f"--dest {folder}", built)
class OsTabsTakeOptionsPerSystem(unittest.TestCase):
"""The marker gives any tab its own options, and refuses words it cannot read."""
PAGE = ("<!-- os-tabs windows: --dest E:\\x macos: --dest /m steamdeck: --dest /d -->\n"
f"```sh\ncurl -fsSL {INSTALL_BASE}/install.sh | sh -s -- --dest /l\n```\n")
def test_each_named_tab_uses_its_own(self):
parts = re.split(r'<TabItem label="([^"]+)">', sitediagrams.expand_commands(self.PAGE))
bodies = dict(zip(parts[1::2], parts[2::2]))
self.assertIn("--dest E:\\x\n", bodies["Windows"])
self.assertIn("--dest /m\n", bodies["macOS"])
self.assertIn("--dest /l\n", bodies["Linux"])
self.assertIn("--dest /d\n", bodies["Steam Deck"])
def test_text_before_a_system_name_fails_the_build(self):
page = self.PAGE.replace("os-tabs windows:", "os-tabs typo windows:")
with self.assertRaises(ValueError):
sitediagrams.expand_commands(page)
class MostEmulatorsNotEvery(unittest.TestCase):
"""C8: level 0 said every emulator needs one exact name."""
def test_the_rule_names_its_exception(self):
section = _flat(_section(_wiki("what-are-bios-files.md"), "The name must match"))
self.assertIn("Most emulators look for one exact name, like `scph5501.bin`.", section)
self.assertIn("A few, like DuckStation, read any name and check what the file holds.",
section)
profile = yaml.safe_load((REPO_ROOT / "emulators" / "duckstation.yml").read_text(
encoding="utf-8"))
self.assertEqual(profile["found_by"], "content")
class FaqAnswersLeadSomewhere(unittest.TestCase):
"""C9: "Use the ZIP" for iOS, and a dead end for 12 setups without one."""
def setUp(self):
self.text = _wiki("faq.md")
self.generator = (REPO_ROOT / "scripts" / "generate_site.py").read_text(encoding="utf-8")
def test_ios_goes_to_the_iphone_section(self):
section = _flat(_section(self.text, "My setup is not in the list"))
self.assertIn("iPhone, iPad (iOS): no terminal. [Pick your consoles and copy them "
"to the app](../which-pack.md#iphone-and-ipad).", section)
self.assertNotIn("Use the ZIP", section)
self.assertIn('"## iPhone and iPad { #iphone-and-ipad }"', self.generator)
def test_antivirus_answer_covers_setups_without_a_zip(self):
section = _flat(_section(self.text, "Windows or my antivirus blocks the command"))
self.assertIn("Use your setup's ZIP. None? [Pick your consoles]"
"(../which-pack.md#only-some-consoles) and download their files.",
section)
self.assertNotIn("if any", section)
self.assertIn('"## Only some consoles?"', self.generator)
class PackagersPinACommit(unittest.TestCase):
"""J4: the section fetched install.py from a release that carries none."""
def setUp(self):
self.section = _section(_wiki("installer.md"), "For packagers")
def test_the_pin_read_is_the_one_install_sh_writes(self):
sed = re.search(r"sed -n '(s/\^DEFAULT_INSTALL_SHA256=.*?/p)'", self.section)
self.assertIsNotNone(sed)
bootstrap = (REPO_ROOT / "install.sh").read_text(encoding="utf-8")
lines = re.findall(r'(?m)^DEFAULT_INSTALL_SHA256="([0-9a-f]{64})"$', bootstrap)
self.assertEqual(len(lines), 1)
def test_the_manifest_comes_from_the_same_commit(self):
self.assertIn('-O "$base/install/retroarch.json"', self.section)
self.assertTrue((REPO_ROOT / "install" / "retroarch.json").is_file())
self.assertIn("RETROBIOS_REF=$commit python3 install.py --manifest retroarch.json",
self.section)
self.assertIn('"--manifest",', INSTALL_PY)
self.assertIn('"https://raw.githubusercontent.com/Abdess/retrobios/"', INSTALL_PY)
def test_search_words(self):
terms = _front(_wiki("installer.md"))["terms"]
for word in ("packager", "pin", "reproducible"):
with self.subTest(word=word):
self.assertIn(word, terms)
class SearchWords(unittest.TestCase):
"""Contract with the search gate: each page carries its own words."""
def test_troubleshooting(self):
terms = _front(_wiki("troubleshooting.md"))["terms"]
for word in ("check my bios folder", "check bios folder"):
with self.subTest(word=word):
self.assertIn(word, terms)
def test_legal(self):
self.assertIn("license", _front(_wiki("legal.md"))["terms"])
class SmallCopyFixes(unittest.TestCase):
"""C-other: the RetroPie share had no name, and Mega CD two spellings."""
def test_retropie_share_is_named_with_its_source(self):
section = _section(_wiki("first-install.md"), "Error: Python 3.8 or newer is required.")
self.assertIn("share open, `\\\\RETROPIE\\bios` from Windows:", section)
self.assertIn("samba.sh:49-52", section)
self.assertIn("Transferring-Roms.md:29", section)
def test_mega_cd_is_spelled_once(self):
for path in sorted(WIKI.glob("*.md")):
with self.subTest(page=path.name):
self.assertNotIn("Mega-CD", path.read_text(encoding="utf-8"))
if __name__ == "__main__":
unittest.main()
+6 -4
View File
@@ -67,12 +67,13 @@ Read them first: [install.sh](https://github.com/Abdess/retrobios/blob/main/inst
## Windows or my antivirus blocks the command
Use your setup's ZIP, if any: [Get your files](../which-pack.md).
Use your setup's ZIP. None? [Pick your consoles](../which-pack.md#only-some-consoles)
and download their files.
## Why is there no ZIP for my setup?
ZIPs are made for the setups most people download. The command installs every
setup's files and checks each one. `--dry-run` shows the list first.
ZIPs exist for the most downloaded setups. The command installs and checks
every setup's files.
## Fill an SD card from a computer?
@@ -99,7 +100,8 @@ Fill it from a computer, as above, or point `--from-pack` at your ZIP: [Without
- Name your emulator's BIOS folder with `--dest`.
- ES-DE, LaunchBox: the command fills their emulators' folders.
- iPhone, iPad (iOS): no terminal. Use the ZIP.
- iPhone, iPad (iOS): no terminal.
[Pick your consoles and copy them to the app](../which-pack.md#iphone-and-ipad).
## Why is a file missing from the ZIP?
+6 -2
View File
@@ -141,8 +141,12 @@ Choose **Another setup or folder**, then your setup and its folder.
The message shows the command that installs Python. Run it, then run the
installer again.
A RetroPie 4.8 image has Python 3.7.3, and its update command finds nothing
newer. Run it on a computer, the `bios` share open:
RetroPie 4.8 has Python 3.7.3, and its update finds nothing newer. Run it on
a computer, with RetroPie's `bios` share open, `\\RETROPIE\bios` from Windows:
<!-- RetroPie-Setup scriptmodules/supplementary/samba.sh:49-52 (46128cd2) shares
$home/RetroPie/BIOS as "bios", and RetroPie docs/Transferring-Roms.md:29 names
\\RETROPIE. -->
<!-- os-tabs windows: --platform retropie --dest \\RETROPIE\bios\ -->
```sh
+12 -15
View File
@@ -1,7 +1,7 @@
---
level: setup
order: 100
terms: manifest, events, exit code, schema
terms: manifest, events, exit code, schema, packager, pin, reproducible
---
# All installer options
@@ -47,24 +47,21 @@ python install.py
### 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`:
file list from one commit. `install.sh` of that commit pins the SHA-256 of its
`install.py`, and `RETROBIOS_REF` makes the installer download every file from
the same commit:
```bash
base=https://github.com/Abdess/retrobios/releases/download/<tag>
curl -fsSLO "$base/install.py" -O "$base/retroarch.json" -O "$base/SHA256SUMS.txt"
sha256sum --check --ignore-missing SHA256SUMS.txt
RETROBIOS_REF=<tag> python3 install.py --manifest retroarch.json
commit=<commit>
base=https://raw.githubusercontent.com/Abdess/retrobios/$commit
curl -fsSLO "$base/install.py" -O "$base/install/retroarch.json"
pin=$(curl -fsSL "$base/install.sh" | sed -n 's/^DEFAULT_INSTALL_SHA256="\(.*\)"$/\1/p')
echo "$pin install.py" | sha256sum --check
RETROBIOS_REF=$commit python3 install.py --manifest retroarch.json
```
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).
What `RETROBIOS_REF` does not pin is listed under
[Environment overrides](#environment-overrides).
## Passing options
+1
View File
@@ -1,6 +1,7 @@
---
level: start
order: 55
terms: license
---
# Is it legal?
+2 -2
View File
@@ -50,14 +50,14 @@ Every module in `tests/`, by the area it guards.
|------|----------|---------|
| Core regression suites | synthetic | `test_e2e`, `test_audit_regressions`, `test_tool_messages` |
| File resolution and identity | synthetic + collection | `test_adler32_resolution`, `test_agnostic_scan`, `test_agnostic_scan_mode`, `test_agnostic_scope`, `test_agnostic_substitute`, `test_archive_choice`, `test_archive_recipes`, `test_bios_companions`, `test_bundled_identity`, `test_casefold_cache`, `test_db_aliases`, `test_declared_names`, `test_derivations`, `test_directory_entries`, `test_extra_identity`, `test_foreign_tree`, `test_foreign_tree_names`, `test_frontend_digest`, `test_game_data_homonyms`, `test_hashing`, `test_identity`, `test_md5_pack_context`, `test_name_tiebreak`, `test_nec_filing`, `test_owner_resolution`, `test_path_suffix`, `test_resolution_evidence`, `test_sega_filing`, `test_shipped_content`, `test_twin_declarations`, `test_validated_choice`, `test_variant_choice`, `test_variant_identity`, `test_zipped_member` |
| Verification, cross-reference and profile checks | synthetic + profiles | `test_bios_layout`, `test_cache_independent_counts`, `test_case_insensitive_platforms`, `test_checks_have_values`, `test_core_file_fills_declaration`, `test_core_size_refusal`, `test_cross_reference_sources`, `test_crypto_aes`, `test_crypto_unique_data`, `test_crypto_verify`, `test_entry_categories`, `test_file_consumers`, `test_fileless_audit`, `test_flycast_layout`, `test_gap_settlement`, `test_hidden_extras`, `test_launcher_aliases`, `test_launcher_layer`, `test_native_mode`, `test_no_case_collisions`, `test_path_conflict_status`, `test_path_null_copies`, `test_profile_checks`, `test_profile_repositories`, `test_romm_hash_rule`, `test_shared_groups`, `test_standalone_links`, `test_standalone_mode`, `test_undeclared_dedup`, `test_unplaced_extras`, `test_validation_scope`, `test_verify_all_dir`, `test_verify_emulator_evidence`, `test_verify_listing`, `test_verify_pack_choice`, `test_verify_release_asset` |
| Verification, cross-reference and profile checks | synthetic + profiles | `test_bios_layout`, `test_cache_independent_counts`, `test_case_insensitive_platforms`, `test_checks_have_values`, `test_core_file_fills_declaration`, `test_core_size_refusal`, `test_cross_reference_sources`, `test_crypto_aes`, `test_crypto_unique_data`, `test_crypto_verify`, `test_entry_categories`, `test_file_consumers`, `test_fileless_audit`, `test_flycast_layout`, `test_gap_settlement`, `test_hidden_extras`, `test_launcher_aliases`, `test_launcher_layer`, `test_native_mode`, `test_no_case_collisions`, `test_path_conflict_status`, `test_path_null_copies`, `test_profile_checks`, `test_profile_names`, `test_profile_paths`, `test_profile_repositories`, `test_romm_hash_rule`, `test_shared_groups`, `test_standalone_links`, `test_standalone_mode`, `test_undeclared_dedup`, `test_unplaced_extras`, `test_validation_scope`, `test_verify_all_dir`, `test_verify_emulator_evidence`, `test_verify_listing`, `test_verify_pack_choice`, `test_verify_release_asset` |
| Packs and manifests | synthetic + real packs | `test_artifact_lock`, `test_atomic_artifacts`, `test_batocera_cores`, `test_deterministic_zip`, `test_emulator_pack_counts`, `test_finalize_pack_names`, `test_large_file_cache`, `test_libretro_layout`, `test_manifest_entry`, `test_minui_platform`, `test_no_game_data`, `test_pack_conformance_dirs`, `test_pack_core_extras`, `test_pack_counts`, `test_pack_destinations`, `test_pack_failures`, `test_pack_file_names`, `test_pack_grouping`, `test_pack_integrity`, `test_pack_member_identity`, `test_pack_readme`, `test_platform_inheritance`, `test_platform_keys`, `test_release_packs`, `test_required_only_archives`, `test_required_only_twins`, `test_save_root`, `test_split_extras`, `test_split_names`, `test_split_pack`, `test_system_pack_extras`, `test_system_pack_parity`, `test_torrentzip`, `test_which_pack` |
| Slots and regions | synthetic + profiles | `test_region`, `test_region_agnostic_scan`, `test_region_groups`, `test_region_held`, `test_region_platform_index`, `test_region_required_only`, `test_slot`, `test_slots`, `test_slots_shipped_file` |
| Hardware targets and systems | synthetic + target files | `test_extract_targets`, `test_lakka_targets`, `test_libretro_slugs`, `test_system_ids`, `test_system_selection`, `test_target_names`, `test_target_scrapers`, `test_target_systems`, `test_target_verify` |
| Installer and downloads | loopback server | `test_check_release`, `test_download`, `test_install`, `test_install_cores`, `test_install_experience`, `test_install_from`, `test_install_offline`, `test_install_selection`, `test_install_tui` |
| Handheld launchers | a pty as the console, fake installer and firmware tools, stubbed PortMaster dialogs | `test_handheld_launchers`, `test_port` |
| Truth and native export | synthetic + cached originals | `test_export_counts`, `test_export_native_layer`, `test_export_report`, `test_exporters`, `test_truth_data_dir_readers`, `test_truth_diff`, `test_truth_layout` |
| Scrapers, upstream and provenance | inline sources, synthetic | `test_batocera_md5_list`, `test_check_freshness`, `test_contributing_text`, `test_coverage_cache`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_dedup`, `test_doc_pages`, `test_doc_surfaces`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_optional_dependencies`, `test_profile_sync`, `test_prose_style`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_romset_recipes`, `test_schema_semantic_gate`, `test_scraper_contract`, `test_site_availability`, `test_site_content_data`, `test_site_copy`, `test_site_cores`, `test_site_emulator_page`, `test_site_exports`, `test_site_funnel`, `test_site_images`, `test_site_picker`, `test_site_platform_hashes`, `test_site_r2_components`, `test_site_r2_css`, `test_site_r2_emulators`, `test_site_r2_entry`, `test_site_r2_gate`, `test_site_r2_nav`, `test_site_r2_p0`, `test_site_r2_reference`, `test_site_r2_systems`, `test_site_r2_wiki`, `test_site_r3_collection`, `test_site_r3_components`, `test_site_r3_css`, `test_site_r3_emulators`, `test_site_r3_entry`, `test_site_r3_nav`, `test_site_r3_p0`, `test_site_r3_reference`, `test_site_r3_systems`, `test_site_r3_wiki`, `test_site_r4_components`, `test_site_r4_css`, `test_site_r4_emulators`, `test_site_r4_entry`, `test_site_r4_merge`, `test_site_r4_p0`, `test_site_r4_reference`, `test_site_r4_search`, `test_site_r4_systems`, `test_site_r4_wiki`, `test_site_r5_components`, `test_site_r5_reference`, `test_site_render`, `test_site_system_links`, `test_site_validation`, `test_site_weight`, `test_site_write`, `test_source_ref_targets`, `test_upstream`, `test_upstream_index`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_workflow_paths` |
| Scrapers, upstream and provenance | inline sources, synthetic | `test_batocera_md5_list`, `test_check_freshness`, `test_contributing_text`, `test_coverage_cache`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_dedup`, `test_doc_pages`, `test_doc_surfaces`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_optional_dependencies`, `test_profile_sync`, `test_prose_style`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_romset_recipes`, `test_schema_semantic_gate`, `test_scraper_contract`, `test_site_availability`, `test_site_content_data`, `test_site_copy`, `test_site_cores`, `test_site_emulator_page`, `test_site_exports`, `test_site_funnel`, `test_site_images`, `test_site_picker`, `test_site_platform_hashes`, `test_site_r2_components`, `test_site_r2_css`, `test_site_r2_emulators`, `test_site_r2_entry`, `test_site_r2_gate`, `test_site_r2_nav`, `test_site_r2_p0`, `test_site_r2_reference`, `test_site_r2_systems`, `test_site_r2_wiki`, `test_site_r3_collection`, `test_site_r3_components`, `test_site_r3_css`, `test_site_r3_emulators`, `test_site_r3_entry`, `test_site_r3_nav`, `test_site_r3_p0`, `test_site_r3_reference`, `test_site_r3_systems`, `test_site_r3_wiki`, `test_site_r4_components`, `test_site_r4_css`, `test_site_r4_emulators`, `test_site_r4_entry`, `test_site_r4_merge`, `test_site_r4_p0`, `test_site_r4_reference`, `test_site_r4_search`, `test_site_r4_systems`, `test_site_r4_wiki`, `test_site_r5_components`, `test_site_r5_reference`, `test_site_r5_wiki`, `test_site_render`, `test_site_system_links`, `test_site_validation`, `test_site_weight`, `test_site_write`, `test_source_ref_targets`, `test_upstream`, `test_upstream_index`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_workflow_paths` |
## Test architecture
+13 -8
View File
@@ -1,7 +1,7 @@
---
level: start
order: 40
terms: bios not found, bios missing, firmware missing, bios error
terms: bios not found, bios missing, firmware missing, bios error, check my bios folder, check bios folder
---
# When a game does not start
@@ -33,7 +33,7 @@ Read the count line:
- **`wrong hash`**: another region or model, or damaged.
- **Fewer present than the total**: files are missing.
- **A line under a file**, like `still zipped`, says what to fix.
- **A line under a file**, like `still zipped`, says the fix.
- **`0 wrong hash`, all present**: go to step 3.
## 2. Fix the files
@@ -44,11 +44,11 @@ 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.
- **A `bios` folder inside your BIOS folder?** Run the installer: it copies
those files up one level.
- **A `bios` folder inside your BIOS folder?** The installer copies those
files up one level.
- **BIOS setting on a subfolder, like `system/dc`?** Point it at the BIOS
folder. Emulators add their own, like `dc/` for Flycast.
- **A ZIP in parts, like `Pack.part1of2.zip`?** Unzip every part into one
- **A ZIP in parts, like `Pack.part1of2.zip`?** Unzip all parts into one
folder.
<!-- Flycast's libretro port appends "dc/" to the system directory:
@@ -65,7 +65,7 @@ version.
## The BIOS is fine, the game still fails
- **Another emulator?** Each reads its own files, listed on its page.
- **Another emulator?** Each reads the files listed on its page.
- **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.
@@ -76,9 +76,14 @@ version.
- **Network error:** try again later.
- **`The clock reads ...`:** set the right date.
- **Permission denied:** do what the message says.
- **No setup found:** name it and its folder:
- **`No supported platform detected`:** name the folder. Not sure? Open
RetroArch's **Settings > Directory > System/BIOS**.
<!-- os-tabs windows: --platform retroarch --dest C:\path\to\RetroArch\system -->
<!-- The folders RetroArch reads by default, as install.py writes them
(_os_default_dests, _macos_retroarch_base) and the RetroArch setup page
cites them. Steam Deck: the Flatpak build. -->
<!-- os-tabs windows: --platform retroarch --dest C:\RetroArch-Win64\system macos: --platform retroarch --dest ~/Documents/RetroArch/system steamdeck: --platform retroarch --dest ~/.var/app/org.libretro.RetroArch/config/retroarch/system -->
```sh
curl -fsSL https://raw.githubusercontent.com/Abdess/retrobios/main/install.sh | sh -s -- --platform retroarch --dest ~/.config/retroarch/system
```
+4 -3
View File
@@ -31,14 +31,15 @@ If step 3 fails, you see "BIOS missing" or a black screen.
- **Better with it:** Dreamcast. Some games need it.
- **Usually not:** NES, Super Nintendo, Mega Drive, Game Boy and Game Boy
Advance.
- **Add-ons need their own:** the Famicom Disk System and the Mega-CD.
- **Add-ons need their own:** the Famicom Disk System and the Mega CD.
Details: [Every console, one by one](../systems/index.md)
## The name must match
An emulator looks for one exact name. A PlayStation emulator looks for
`scph5501.bin`. A file with another name is not found.
Most emulators look for one exact name, like `scph5501.bin`. A file with
another name is not found. A few, like DuckStation, read any name and check
what the file holds.
## The version must match