fix: read each named core's own entry in recalbox

An element's mandatory flag came from the one truth entry its md5 paired
with. saturn/saturn_bios.bin names yabause, yabasanshiro and kronos,
which require it, and was paired with the beetle_saturn entry, which
does not. Each named core's entries for the file, found by name, now
decide, except a namesake elsewhere in the same tree (bluemsx KANJI.rom
under Shared Roms is not the one under MSX2+ - European).
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 05:39:17 +02:00
1 parent 79d3a86db7
commit 28435230a7
6 files changed
+138 -29

No files matched your search

+3 -2
View File
@@ -535,9 +535,10 @@ def landed_changes(exporter: object, systems: dict) -> LandedChanges:
"added", entry, None, None, _added_fields(exporter, entry)
))
continue
# Asked of the exporter: a format that names each entry's cores
# reads every entry of those cores, not only the paired one.
if (
(entry.truth or {}).get("required") is not None
and entry.platform.get("required") is not None
entry.platform.get("required") is not None
and exporter.states(entry, "required")
and exporter.required_value(entry) != bool(entry.platform["required"])
):
+14
View File
@@ -122,6 +122,10 @@ class NativeFile:
# (Recalbox on a .zip): the truth's md5 describes the container and
# can be neither compared with it nor written in its place.
composite_md5: bool = False
# Every truth entry of the system that answers to this platform entry's
# name, whichever one the pairing took: the element names its cores, and
# each core's own entry for the file says whether that core needs it.
namesakes: list[dict] = field(default_factory=list)
@property
def origin(self) -> str:
@@ -563,6 +567,16 @@ def build_native_model(
if candidate.truth is None
]
pairs = pair_entries(truth_files, [c.platform or {} for c in candidates])
for candidate in (
c
for native_id in target_ids
for c in systems.get(native_id, NativeSystem(native_id)).files
if c.platform is not None
):
own = str(candidate.name).casefold()
candidate.namesakes.extend(
entry for entry in truth_files if own in _names(entry)
)
for t_index, truth_entry in enumerate(truth_files):
name = str(truth_entry["name"])
+47 -13
View File
@@ -23,7 +23,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from common import load_emulator_profiles, parse_untrusted_xml
from .base_exporter import BaseExporter
from .baseline import NativeFile, NativeSystem, Report
from .baseline import NativeFile, NativeSystem, Report, by_destination, by_name
SOURCE_URL = (
"https://gitlab.com/recalbox/recalbox/-/raw/master/board/recalbox/fsoverlay"
@@ -165,27 +165,61 @@ class Exporter(BaseExporter):
def required_value(self, fe: NativeFile) -> bool:
"""Whether the cores the element names need the file.
An element lists its cores, and the merged flag is true when any
core needs the file: cdi/cdibios.zip names libretro/same_cdi, whose
driver declares no such set, and became mandatory because MAME
requires it. Where none of the element's cores reads the file, the
truth says nothing about it and the platform's value stands.
The element lists its cores, and each core's own entry for the file,
found by name, says whether that core needs it. The md5 pairing
takes one entry only: saturn/saturn_bios.bin names yabause,
yabasanshiro and kronos, which require it, and its md5 paired it
with the beetle_saturn entry. The merged flag is true when any core
needs the file: cdi/cdibios.zip names same_cdi, which declares no
such set, and became mandatory because MAME requires it. Where none
of the element's cores declares the file, the platform's value
stands.
"""
truth = fe.truth or {}
required_by = truth.get("_required_by")
readers = truth.get("_cores")
if required_by is None or not readers:
entries = [fe.truth] if fe.truth else []
entries += [
e for e in fe.namesakes
if e is not fe.truth and self._same_file(e, fe.platform or {})
]
if not entries:
return fe.required
index = self._profile_keys()
named = {
index.get(core.rsplit("/", 1)[-1].replace("-", "_").lower(), "")
for core in fe.cores()
} & set(readers)
if not named:
} - {""}
readers: set[str] = set()
requirers: set[str] = set()
for entry in entries:
cores = set(entry.get("_cores") or ()) & named
readers |= cores
required_by = entry.get("_required_by")
if required_by is None:
if entry.get("required") is not False:
requirers |= cores
else:
requirers |= cores & set(required_by)
if not readers:
if fe.platform is not None and fe.platform.get("required") is not None:
return bool(fe.platform["required"])
return fe.required
return bool(named & set(required_by))
return bool(requirers)
@staticmethod
def _same_file(entry: dict, declared: dict) -> bool:
"""Whether a truth entry of that name describes this element's file.
Its path or its name in the same directory does. A name under an
unrelated directory does too: kronos reads kronos/saturn_bios.bin,
and Recalbox files the same BIOS under saturn/. A name in another
directory of the same tree does not: bluemsx reads
Machines/Shared Roms/KANJI.rom, which is not Recalbox's
Machines/MSX2+ - European/KANJI.rom.
"""
if by_destination(entry, declared) or by_name(entry, declared):
return True
theirs = str(declared.get("destination") or declared.get("name", "")).split("/")[:-1]
ours = str(entry.get("path") or entry.get("name", "")).split("/")[:-1]
return not {d.casefold() for d in theirs} & {d.casefold() for d in ours}
def _bios_element(self, fe: NativeFile, native_id: str) -> str:
attrs = [f"path={quoteattr(self._path(fe))}"]