chore: merge round 4 fixes (profiles)

This commit is contained in:
Abdessamad Derraz committed 2026-10-21 13:17:10 +02:00
commit 43fe5a7b15
15 files changed
+354 -29

No files matched your search

File renamed without changes.
-3
View File
@@ -131,7 +131,6 @@ notes: |
files:
- name: nds_bios_arm9.bin
aliases: [NDS_Bios9.bin, bios9.bin, biosnds9.rom]
path: system/nds_bios_arm9.bin
system: nintendo-ds
required: false
@@ -154,7 +153,6 @@ files:
source_ref: "drastic r2.5.2.2 initialize_memory 0x1c4b0-0x1c4d4, libdrastic_arm64.so 0x2b6f0-0x2b708, DraSticActivity.smali:4084-4090, drastic_bios_readme.txt:1-31"
- name: nds_bios_arm7.bin
aliases: [NDS_Bios7.bin, bios7.bin, biosnds7.rom]
path: system/nds_bios_arm7.bin
system: nintendo-ds
required: false
@@ -177,7 +175,6 @@ files:
source_ref: "drastic r2.5.2.2 initialize_memory 0x1c508-0x1c52c, libdrastic_arm64.so 0x2b740-0x2b758, DraSticActivity.smali:4078-4083"
- name: nds_firmware.bin
aliases: [NDS_Lite_Firmware.bin, dsfirmware.bin, firmware.bin]
path: system/nds_firmware.bin
system: nintendo-ds
required: false
+10 -9
View File
@@ -8,8 +8,9 @@ core_classification: community_fork
bios_mode: agnostic
source: "https://github.com/libretro/ps2"
upstream: "https://github.com/PCSX2/pcsx2"
profiled_date: "2026-03-25"
source_commit: "6eabf2242d451ee2e6d52b1e3f10efb77143ed05"
profiled_date: "2026-10-21"
source_commit: "6664c60294ee05fe5e8c7645ab7da546dae78ed2"
upstream_commit: "a81f1aa39fc56ef60dbc913637c74c49c1792033"
core_version: "Git"
display_name: "Sony - PlayStation 2 (LRPS2)"
cores: [lrps2, pcsx2, "ps2"]
@@ -46,7 +47,7 @@ files:
min_size: 4194304
max_size: 8388608
validation: [size]
source_ref: "source pcsx2/ps2/BiosTools.cpp:33-34, 63-180, 249-274, 286-348"
source_ref: "source pcsx2/ps2/BiosTools.cpp:33-34, 63-180, 250-275, 287-349"
note: >
Scans pcsx2/bios/ for any file between 4 MB and 8 MB. Validates via romdir
structure parsing (RESET + ROMVER entries). User selects BIOS via core option
@@ -57,7 +58,7 @@ files:
required: false
max_size: 4194304
description: "DVD player ROM"
source_ref: "source pcsx2/ps2/BiosTools.cpp:189-229, 339"
source_ref: "source pcsx2/ps2/BiosTools.cpp:189-230, 340"
note: >
DVD player ROM. Tries <biospath>.rom1 (appended) then <biosbase>.rom1
(extension replaced). Silently skipped if not found.
@@ -67,7 +68,7 @@ files:
required: false
max_size: 524288
description: "Chinese ROM extension"
source_ref: "source pcsx2/ps2/BiosTools.cpp:189-229, 340"
source_ref: "source pcsx2/ps2/BiosTools.cpp:189-230, 341"
note: >
Chinese region ROM extension. Same naming convention as rom1.
Only present on Chinese region consoles.
@@ -78,7 +79,7 @@ files:
hle_fallback: true
size: 1024
description: "NVRAM / EEPROM data"
source_ref: "source pcsx2/CDVD/CDVD.cpp:196-227"
source_ref: "source pcsx2/CDVD/CDVD.cpp:194-226"
note: >
Console EEPROM data (language, timezone, region, iLink ID, OSD settings).
Path derived from BIOS path with extension replaced to .nvm.
@@ -90,7 +91,7 @@ files:
hle_fallback: true
size: 4
description: "Mechacon version"
source_ref: "source pcsx2/CDVD/CDVD.cpp:229-245"
source_ref: "source pcsx2/CDVD/CDVD.cpp:228-243"
note: >
Mechacon (disc drive controller) version as u32.
Auto-created with default 0x00020603 if missing.
@@ -99,7 +100,7 @@ files:
path: "pcsx2/resources/cheats_ws.zip"
required: false
description: "widescreen patches archive"
source_ref: "source pcsx2/VMManager.cpp:383-396"
source_ref: "source pcsx2/VMManager.cpp:382-395"
note: >
ZIP archive of per-game widescreen (16:9) patches in pnach format.
Only loaded when widescreen patches are enabled via core options.
@@ -109,7 +110,7 @@ files:
path: "pcsx2/resources/cheats_ni.zip"
required: false
description: "no-interlacing patches archive"
source_ref: "source pcsx2/VMManager.cpp:418-431"
source_ref: "source pcsx2/VMManager.cpp:417-430"
note: >
ZIP archive of per-game no-interlacing patches in pnach format.
Only loaded when no-interlacing patches are enabled via core options.
+44 -2
View File
@@ -59,14 +59,56 @@ files:
- name: "sega_101.bin"
system: sega-saturn
required: true
mode: standalone
size: 524288
validation: [size]
aliases: [mpr-17933.bin, saturn_bios.bin]
description: "Saturn IPL ROM (BIOS). Any region accepted."
note: "The libretro port reads sega_101.bin, mpr-17933.bin and saturn_bios.bin from its system directory (kBiosFilenames)."
source_ref:
standalone: "apps/ymir-sdl3/src/util/rom_loader.cpp:9-22, apps/ymir-sdl3/src/app/rom_manager.cpp:14-53, libs/ymir-core/include/ymir/sys/memory_defs.hpp:9"
libretro: "apps/ymir-libretro/src/libretro.cpp:305-309, apps/ymir-libretro/src/libretro.cpp:651-690, apps/ymir-libretro/src/libretro.cpp:692-703"
# The libretro build reads three names in its system directory. The md5 of
# the first two is that of the image whose XXH128 is the kLocalBiosHashes
# row the port gives a region to.
- name: "sega_101.bin"
system: sega-saturn
region: [japan]
priority: 1
required: true
mode: libretro
size: 524288
validation: [size]
md5: "85ec9ca47d8f6807718151cbcca8b964"
description: "Saturn IPL ROM 1.01 (1994-12-28), Japan."
note: "First name read. The port gives this image the Japan region, so it is loaded when ymir_region is japan and kept or switched to for a disc whose area code is J. Any other 512 KiB file under this name is read with the region the IPL database gives it, or none."
source_ref:
libretro: "apps/ymir-libretro/src/libretro.cpp:305-309, apps/ymir-libretro/src/libretro.cpp:596-606, apps/ymir-libretro/src/libretro.cpp:627-648, apps/ymir-libretro/src/libretro.cpp:651-702, apps/ymir-libretro/src/libretro.cpp:1231-1238, apps/ymir-libretro/src/libretro.cpp:1290-1306"
- name: "mpr-17933.bin"
system: sega-saturn
region: [north-america, europe, asia-ntsc, asia-pal, brazil, latin-america]
priority: 2
required: true
mode: libretro
size: 524288
validation: [size]
md5: "3240872c70984b6cbfda1586cab68dbe"
description: "Saturn IPL ROM 1.01a (1994-11-15), North America and Europe."
note: "Second name read. The port gives this image the US_EU region, loaded when ymir_region is north_america or europe and for a disc whose area code is any of T, U, B, A, E and L. Area K maps to the KR region, which neither image carries, so a Korean disc keeps the image already loaded."
source_ref:
libretro: "apps/ymir-libretro/src/libretro.cpp:305-309, apps/ymir-libretro/src/libretro.cpp:596-606, apps/ymir-libretro/src/libretro.cpp:627-648, apps/ymir-libretro/src/libretro.cpp:651-702, apps/ymir-libretro/src/libretro.cpp:1231-1238, apps/ymir-libretro/src/libretro.cpp:1290-1306, libs/ymir-core/include/ymir/media/media_defs.hpp:17-29"
- name: "saturn_bios.bin"
system: sega-saturn
priority: 3
required: false
mode: libretro
size: 524288
validation: [size]
description: "Saturn IPL ROM, any revision"
note: "Third name read. No region comes with the name: the image gets the one the IPL database gives its hash, or none, and is loaded when it is the first candidate found or its region is the one asked for."
source_ref:
libretro: "apps/ymir-libretro/src/libretro.cpp:305-309, apps/ymir-libretro/src/libretro.cpp:651-702, apps/ymir-libretro/src/libretro.cpp:1231-1238"
# IPL images named by the standalone XXH128 database. The md5 is that of
# the image whose seeded XXH128 matches the database row.
+9
View File
@@ -506,6 +506,15 @@ launchers:
kind: package
names: []
source_ref: "scriptmodules/emulators/drastic.sh:12, 40"
- emulator: drastic
package: drastic
build: standalone
kind: passes_path
names: []
search_dir: $md_conf_root/nds/drastic
passes_to: working directory of $md_inst/drastic.sh
fails_when_missing: false
source_ref: "scriptmodules/emulators/drastic.sh:48"
- emulator: fbzx
package: fbzx
repo: "git https://github.com/rastersoft/fbzx :_get_branch_fbzx"
+6 -3
View File
@@ -614,9 +614,12 @@ def _collect_all_aliases(files: dict) -> dict:
["sgb2_bios.bin", "sgb2_boot.bin", "sgb2.boot.rom"],
["sgb1.program.rom", "SGB1.sfc/program.rom"],
["sgb2.program.rom", "SGB2.sfc/program.rom"],
# Nintendo DS
["bios7.bin", "nds7.bin"],
["bios9.bin", "nds9.bin"],
# Nintendo DS. DraStic opens nds_bios_arm9.bin, nds_bios_arm7.bin
# and nds_firmware.bin and checks their size only: the collection
# answers those names with its DS dumps.
["NDS_Bios7.bin", "bios7.bin", "nds7.bin", "nds_bios_arm7.bin"],
["NDS_Bios9.bin", "bios9.bin", "nds9.bin", "nds_bios_arm9.bin"],
["NDS_Lite_Firmware.bin", "nds_firmware.bin"],
["dsi_sd_card.bin", "nds_sd_card.bin"],
# MSX
["MSX.ROM", "MSX.rom", "Machines/Shared Roms/MSX.rom"],
+31 -6
View File
@@ -22,10 +22,23 @@ from dataclasses import dataclass
from common import declared_root, name_match_size_ok, sanitize_pack_path
# The kinds whose names say which file the launcher opens. The others hand
# over a directory, copy a file the platform already names, or let the
# The kinds whose names say which file the launcher opens. A link of a named
# file is one too: ROCKNIX links /storage/roms/bios/nds_bios_arm9.bin into
# DraStic's system folder, so that is the path the emulator reads. The others
# hand over a directory, copy a file the platform already names, or let the
# emulator choose.
PLACE_KINDS = ("names_searched", "fixed_name", "core_option")
PLACE_KINDS = ("names_searched", "fixed_name", "core_option", "links")
# How each launcher extractor spells the BIOS directory in search_dir, as the
# platform's own scripts name it: RetroPie's scriptmodules ($biosdir,
# retropie_launchers.BIOSDIR), EmuDeck's EmuScripts (${biosPath},
# emudeck_launchers.BIOS) and RetroDECK's framework ($bios_path,
# retrodeck_launchers.BIOS).
BIOS_ROOT_TOKENS = ("$biosdir", "${biosdir}", "${biosPath}", "$bios_path", "${bios_path}")
# A path spelled from a home or filesystem root names the BIOS directory by
# its base name: /userdata/bios, ~/roms/bios, $HOME/RetroPie/BIOS.
_ROOTED = ("/", "~/", "$HOME/", "$home/", "${HOME}/")
_LABELLED = re.compile(r"^([^\s()]+\.[A-Za-z0-9]+) \([^()]*\)$")
_PLACEHOLDER = re.compile(r"\{(\w+)\}")
@@ -68,19 +81,22 @@ class LauncherPlace:
option or a system leaves that default in use elsewhere, and a core
option offers a file the user may choose without ever choosing it.
"""
return self.kind in ("names_searched", "fixed_name") and not self.conditional
return (
self.kind in ("names_searched", "fixed_name", "links")
and not self.conditional
)
def _bios_relative(directory: str, base: str) -> str | None:
"""A launcher directory relative to the BIOS root, None when it is not one."""
directory = directory.strip().rstrip("/")
roots = {base, "<system_directory>"}
roots = {base, "<system_directory>", *BIOS_ROOT_TOKENS}
head, _, rest = directory.partition("/")
if directory in roots:
return ""
if head in roots:
relative = rest
elif directory.startswith("/") and base and f"/{base}/" in f"{directory}/":
elif directory.startswith(_ROOTED) and base and f"/{base}/" in f"{directory}/":
relative = f"{directory}/".split(f"/{base}/", 1)[1].rstrip("/")
else:
return None
@@ -390,9 +406,18 @@ class LauncherLayer:
if isinstance(filled, dict):
added.append(filled)
if place.stands_for_default:
# The emulator opens the launcher's file instead of its
# own name, so a copy under that name is read by nobody:
# EmuDeck passes Complex_4627v1.03.bin to xemu, which then
# never opens Complex_4627.bin. A held file sitting on one
# of the place's own paths is what fills it.
own = {place.fold(p) for p in place.paths}
settled.update(
id(report) for _candidate, report in matched
if not report.get("in_repo")
or place.fold(sanitize_pack_path(
report.get("path") or report.get("name", "")
)) not in own
)
return added, settled
+32
View File
@@ -48,6 +48,11 @@ OUTSIDE_BIOS: dict[str, tuple[str, ...]] = {
"gngeopi": ("-B",), # gngeo -B/--biospath <directory of neogeo.zip>
}
# Packages whose emulator reads its system files below the working directory
# the generated launch script enters with pushd, a folder outside $biosdir:
# DraStic opens system/<name> under it. Each must still pushd.
WORKING_DIRECTORY: tuple[str, ...] = ("drastic",)
_FUNCTION = re.compile(r"^function\s+([\w.+-]+)\s*\(\)\s*\{\s*$")
_ASSIGN = re.compile(r"^(?:local\s+)?([A-Za-z_]\w*)=(.*)$")
_DECLARE = re.compile(r"^local\s+([A-Za-z_]\w*(?:\s+[A-Za-z_]\w*)*)\s*$")
@@ -518,6 +523,7 @@ class PackageReader:
if links:
self._links(links)
self._outside_bios(events)
self._working_directory(events)
return self.records
@staticmethod
@@ -821,6 +827,32 @@ class PackageReader:
)
def _working_directory(self, events: list[Event]) -> None:
"""The folder a generated launch script enters before it runs the emulator."""
if self.package.id not in WORKING_DIRECTORY:
return
found = False
for event in events:
if not event.heredoc or not event.words or event.words[0] != ["pushd"]:
continue
script = _redirect_target(event.opener)
if script is None or len(event.words) != 2 or len(event.words[1]) != 1:
raise LauncherPatternMissing(
f"{event.path}:{event.line}", f"pushd outside a launch script: {event.raw}"
)
found = True
self.record(
"passes_path", [], [(event.path, event.line)],
search_dir=event.words[1][0].strip("\"'"),
passes_to=f"working directory of {script}",
fails_when_missing=False, depends_on_option=self._depends(event),
)
if not found:
raise LauncherPatternMissing(
self.package.path, "the launch script no longer enters a working directory"
)
def _redirect_target(words: list[list[str]]) -> str | None:
"""The file a `cat > FILE << EOF` or `cat << EOF >> FILE` line writes."""
flat = [w[0] for w in words if w]
+38
View File
@@ -153,5 +153,43 @@ class AnUnreadableSourceStopsTheRun(unittest.TestCase):
self.assertIn("broken.yml", str(caught.exception))
class DrasticNamesTheDSDumps(unittest.TestCase):
"""DraStic opens nds_bios_arm9.bin, nds_bios_arm7.bin and nds_firmware.bin
and checks their size only. Its profile listed nine other names none of
its binaries contains, which were the only way the collection answered
its own three names."""
def _aliases(self, files: dict) -> dict:
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp:
previous = os.getcwd()
os.chdir(tmp)
try:
Path("emulators").mkdir()
return generate_db._collect_all_aliases(files)
finally:
os.chdir(previous)
def test_the_collection_answers_drastic_names(self):
files = {
"a9": {"name": "NDS_Bios9.bin", "path": "bios/Nintendo/DS/NDS_Bios9.bin", "md5": "m9"},
"a7": {"name": "NDS_Bios7.bin", "path": "bios/Nintendo/DS/NDS_Bios7.bin", "md5": "m7"},
"fw": {"name": "NDS_Lite_Firmware.bin",
"path": "bios/Nintendo/DS/NDS_Lite_Firmware.bin", "md5": "mf"},
}
aliases = self._aliases(files)
named = {sha: {a["name"] for a in entries} for sha, entries in aliases.items()}
self.assertIn("nds_bios_arm9.bin", named["a9"])
self.assertIn("nds_bios_arm7.bin", named["a7"])
self.assertIn("nds_firmware.bin", named["fw"])
def test_the_profile_carries_no_name_drastic_never_opens(self):
import yaml
profile = yaml.safe_load((REPO_ROOT / "emulators" / "drastic.yml").read_text())
self.assertEqual(
[e["name"] for e in profile["files"] if e.get("aliases")], [],
)
if __name__ == "__main__":
unittest.main()
+44
View File
@@ -250,6 +250,50 @@ class LauncherLayerTest(unittest.TestCase):
self.assertNotIn("core.bin", {u["name"] for u in self._report()})
self.assertNotIn("core.bin", self._pack_names())
def test_the_default_name_a_launcher_replaces_is_not_packed(self) -> None:
"""EmuDeck passes Complex_4627v1.03.bin to xemu, which then never
opens Complex_4627.bin: the pack carried both, one read by nobody."""
report = {u["path"]: u for u in self._report()}
self.assertIn("sub/fix.bin", report)
self.assertNotIn("core.bin", report)
self.assertNotIn("core.bin", self._pack_names())
def test_a_link_of_a_named_file_is_a_place(self) -> None:
"""ROCKNIX links /storage/roms/bios/nds_bios_arm9.bin into DraStic's
system folder (start_drastic.sh:37-41): the file goes where the
link reads it, not under the emulator's own folder."""
self.config["launchers"][2].update(
kind="links", names=["fix.bin"], search_dir="/storage/roms/bios",
)
places = [p for p in launcher_places(self.config) if p.kind == "links"]
self.assertEqual([p.paths for p in places], [("fix.bin",)])
self.assertTrue(places[0].stands_for_default)
report = {u["path"]: u for u in self._report()}
self.assertIn("fix.bin", report)
self.assertNotIn("core.bin", report)
def test_a_link_of_a_directory_is_no_place(self) -> None:
self.config["launchers"][2].update(
kind="links", names=[], search_dir="/userdata/bios/sub",
)
self.assertFalse([p for p in launcher_places(self.config) if p.kind == "links"])
def test_the_platform_spelling_of_the_bios_folder_is_a_root(self) -> None:
"""RetroPie names $biosdir, EmuDeck ${biosPath}, RetroDECK $bios_path:
read as no folder at all, every place of those platforms was dropped."""
for spelling in ("$biosdir", "${biosPath}", "$bios_path", "$HOME/RetroPie/bios"):
self.config["launchers"][2]["search_dir"] = f"{spelling}/sub"
with self.subTest(spelling=spelling):
self.assertEqual(launcher_places(self.config)[2].paths, ("sub/sub/fix.bin",))
def test_every_extractor_spelling_of_the_bios_folder_is_known(self) -> None:
import launchers
from scraper import emudeck_launchers, retrodeck_launchers, retropie_launchers
for token in (emudeck_launchers.BIOS, retrodeck_launchers.BIOS,
retropie_launchers.BIOSDIR):
self.assertIn(token, launchers.BIOS_ROOT_TOKENS)
def test_no_place_is_filled_twice(self) -> None:
added = [u["path"] for u in self._report() if u.get("launcher")]
self.assertEqual(sorted(added), ["e.bin", "sub/fix.bin"])
+41
View File
@@ -269,6 +269,47 @@ class CommandLines(unittest.TestCase):
rl.extract_launchers(files)
DRASTIC = module("drastic", """
function configure_drastic() {
mkRomDir "nds"
addEmulator 1 "$md_id" "nds" "$md_inst/drastic.sh %ROM%"
addSystem "nds"
[[ "$md_mode" == "remove" ]] && return
isPlatform "kms" && ! isPlatform "x11" && setBackend "$md_id" "x11"
cat > "$md_inst/drastic.sh" << _EOF_
#!/bin/bash
pushd "$md_conf_root/nds/drastic"
$md_inst/drastic "\\$1"
popd
_EOF_
chmod +x "$md_inst/drastic.sh"
}
""", 36)
class WorkingDirectory(unittest.TestCase):
def test_drastic_reads_below_the_folder_its_script_enters(self):
found = records({f"{EMULATORS}/drastic.sh": DRASTIC}, "drastic")
entered = [r for r in found if r["kind"] == "passes_path"]
self.assertEqual(
[(r["search_dir"], r["passes_to"], r["source_ref"]) for r in entered],
[(
"$md_conf_root/nds/drastic",
"working directory of $md_inst/drastic.sh",
f"{EMULATORS}/drastic.sh:48",
)],
)
def test_a_launch_script_that_no_longer_enters_a_folder_raises(self):
files = {f"{EMULATORS}/drastic.sh": DRASTIC.replace('pushd "', 'echo "')}
with self.assertRaises(rl.LauncherPatternMissing):
rl.extract_launchers(files)
class LaunchScripts(unittest.TestCase):
def test_fs_uae_refuses_to_start_without_kick13(self):
files = {f"{EMULATORS}/fs-uae.sh": FS_UAE, f"{EMULATORS}/fs-uae/fs-uae.sh": FS_UAE_LAUNCHER}
+32
View File
@@ -1347,5 +1347,37 @@ class ARefusedRegionalFileHoldsNoSlot(unittest.TestCase):
self.assertIn("rg_jp.bin", report["pack_destinations"])
class YmirLibretroRegions(unittest.TestCase):
"""ymir's libretro port gives sega_101.bin the Japan region and
mpr-17933.bin US_EU (apps/ymir-libretro/src/libretro.cpp:596-606) and
loads the candidate a region asks for (627-648, 1290-1306). One entry for
all three names put no region on any of them."""
def test_each_name_carries_the_region_the_port_gives_it(self):
import yaml
profile = yaml.safe_load(
(Path(__file__).resolve().parents[1] / "emulators" / "ymir.yml").read_text()
)
libretro = {
entry["name"]: entry for entry in profile["files"]
if entry.get("mode") == "libretro"
and entry["name"] in ("sega_101.bin", "mpr-17933.bin", "saturn_bios.bin")
}
self.assertEqual(sorted(libretro), ["mpr-17933.bin", "saturn_bios.bin", "sega_101.bin"])
self.assertEqual(libretro["sega_101.bin"]["region"], ["japan"])
self.assertTrue(
{"north-america", "europe"} <= set(libretro["mpr-17933.bin"]["region"])
)
self.assertNotIn("japan", libretro["mpr-17933.bin"]["region"])
self.assertNotIn("region", libretro["saturn_bios.bin"])
self.assertEqual(
[libretro[n]["priority"] for n in ("sega_101.bin", "mpr-17933.bin", "saturn_bios.bin")],
[1, 2, 3],
)
self.assertFalse(any(e.get("aliases") for e in profile["files"]
if e["name"] == "sega_101.bin"))
if __name__ == "__main__":
unittest.main()
+49
View File
@@ -0,0 +1,49 @@
"""Sega ROMs live under bios/Sega.
The SF-7000 disk unit ROM, which only the sega-sf7000 entries read, sat in
bios/Microsoft/MSX because blueMSX keeps its machine folders together. The
collection files a dump under the maker of the machine it belongs to, and
the blueMSX layout is a destination the pack writes, not a storage rule.
Reads the repository.
"""
from __future__ import annotations
import sys
import unittest
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "scripts"))
class SegaFilesStayUnderSega(unittest.TestCase):
def test_no_sega_only_file_under_msx(self):
folder = REPO_ROOT / "bios" / "Microsoft" / "MSX"
if not folder.is_dir():
self.skipTest("bios/Microsoft/MSX is absent")
from common import load_emulator_profiles
systems: dict[str, set[str]] = {}
for profile in load_emulator_profiles(str(REPO_ROOT / "emulators")).values():
for entry in profile.get("files") or []:
if not isinstance(entry, dict) or not entry.get("system"):
continue
for name in [entry.get("name", ""), *(entry.get("aliases") or [])]:
key = Path(str(name)).name.lower()
systems.setdefault(key, set()).add(str(entry["system"]))
misfiled = sorted(
str(path.relative_to(folder))
for path in folder.rglob("*")
if path.is_file()
and systems.get(path.name.lower())
and all(s.startswith("sega-") for s in systems[path.name.lower()])
)
self.assertEqual(misfiled, [])
def test_sf7000_rom_is_filed_under_sega(self):
self.assertTrue((REPO_ROOT / "bios" / "Sega" / "SF-7000" / "sf7000.rom").is_file())
if __name__ == "__main__":
unittest.main()
+17 -5
View File
@@ -326,6 +326,10 @@ Each package also gets one `kind: package` record, and that record is what
maps a package to the profile of the build it compiles: `repo` names the
project (`minivmac` builds github.com/minivmac/minivmac, Mini vMac 37, not the
libretro port), so the mapping never rests on stripping `lr-` from a name.
DraStic reads its BIOS below the folder its generated launch script enters
(`pushd "$md_conf_root/nds/drastic"`, `drastic.sh:48`), outside `$biosdir`:
that folder is a `passes_path` record, and the scrape stops if the script no
longer enters one.
RetroDECK's records come from each component's `component_prepare.sh`,
`component_launcher.sh` and `component_functions.sh`, and from the presets
they copy, with `$bios_path` as the framework names it. In both, every line
@@ -337,17 +341,25 @@ stops with `LauncherPatternMissing`.
cross-reference both of them consume. A `names_searched` list is one place:
the names are tried in order and one held file fills it, so a core file the
launcher would never open once another name of the list is there is not
reported missing. A `fixed_name` or `core_option` name is a place of its own.
reported missing. A `fixed_name` or `core_option` name is a place of its own,
and so is a `links` name: ROCKNIX links `/storage/roms/bios/nds_bios_arm9.bin`
into DraStic's system folder, so that path is the one DraStic reads.
Only a record that applies without condition settles the core's own name: a
core option the user may never set, or a record tied to one system, leaves
the core's default in use elsewhere.
the core's default in use elsewhere. Settled, the core's own name is neither
reported nor packed, held or not: EmuDeck passes `Complex_4627v1.03.bin` to
xemu, which then never opens `Complex_4627.bin`.
A place that no declared file and no packed core file fills receives, under
the launcher's name, a file the core accepts: the file the collection knows
under that name when the core takes its content, otherwise the copy held for
the core entry read under that name. Records that only hand over a directory
(`passes_path`, `scans_dir`) or copy a file the platform already names
(`links`, `copies`) place nothing, and a `search_dir` the code describes
rather than names ("directory of the Chihiro BIOS found") is skipped.
(`passes_path`, `scans_dir`, a `links` record with no names) or copy a file
the platform already names (`copies`) place nothing, and a `search_dir` the
code describes rather than names ("directory of the Chihiro BIOS found") is
skipped. `$biosdir`, `${biosPath}` and `$bios_path` are the BIOS directory as
RetroPie, EmuDeck and RetroDECK spell it, and a path from a root
(`/userdata/bios`, `$HOME/RetroPie/BIOS/dc`) is placed by the platform's
`base_destination`.
### Inheritance
+1 -1
View File
@@ -38,7 +38,7 @@ Every module in `tests/`, by the area it guards.
| Area | Fixtures | Modules |
|------|----------|---------|
| 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_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_shipped_content`, `test_twin_declarations`, `test_validated_choice`, `test_variant_choice`, `test_variant_identity`, `test_zipped_member` |
| 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_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_crypto_aes`, `test_crypto_unique_data`, `test_crypto_verify`, `test_case_insensitive_platforms`, `test_checks_have_values`, `test_core_file_fills_declaration`, `test_core_size_refusal`, `test_cross_reference_sources`, `test_file_consumers`, `test_fileless_audit`, `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_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_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_required_only_archives`, `test_required_only_twins`, `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` |