mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-12 21:13:49 -06:00
feat: fill a launcher name from a settled entry
The gap report never offers an entry the platform's list settles, so AmberELEC's amiberry configs, which pass kick34005.A500.rom and kick40068.A1200.rom beside a declared kick34005.A500, got nothing. The launcher layer now reads the entries it was not offered, through the setting or the extended name only: by its own name an entry left out of the report was left out for a reason.
This commit is contained in:
1 parent
13bd4a3698
commit
47ae5aa601
2 files changed
+51
-14
No files matched your search
+33
-14
@@ -490,6 +490,8 @@ class _Candidate:
|
||||
by_content: bool
|
||||
# Matched by the size the code checks, the entry naming no hash.
|
||||
by_shape: bool = False
|
||||
# Matched through the setting the launcher writes or the name it extends.
|
||||
by_setting_or_stem: bool = False
|
||||
|
||||
|
||||
class LauncherLayer:
|
||||
@@ -519,7 +521,7 @@ class LauncherLayer:
|
||||
self._by_name_folded.setdefault(name.lower(), []).extend(sha1s)
|
||||
self._files = db.get("files", {})
|
||||
self._owners: dict[tuple[str, bool], list[LauncherPlace]] = {}
|
||||
self._placeholders: dict[tuple[str, bool], list[tuple[dict, dict]]] = {}
|
||||
self._unoffered: dict[tuple[str, bool], list[tuple[dict, dict]]] = {}
|
||||
relevant = set(relevant)
|
||||
for place in self.places:
|
||||
standalone = place.build == "standalone"
|
||||
@@ -534,14 +536,14 @@ class LauncherLayer:
|
||||
owners = set(setting_readers(place.passes_to, profiles, relevant))
|
||||
for key in sorted(owners):
|
||||
self._owners.setdefault((key, standalone), []).append(place)
|
||||
# A placeholder entry stands for every file a scan finds and
|
||||
# is no gap, so the report never offers it: the setting a
|
||||
# launcher writes still reads one file of it.
|
||||
for entry in profiles[key].get("files") or []:
|
||||
if "<" in str(entry.get("name", "")) and set_by(entry, place.passes_to):
|
||||
self._placeholders.setdefault((key, standalone), []).append(
|
||||
(entry, _placeholder_report(key, profiles[key], entry))
|
||||
)
|
||||
# The report never offers a placeholder, which stands for every
|
||||
# file a scan finds, nor an entry the platform's list settles
|
||||
# (AmberELEC declares kick34005.A500): the launcher still reads
|
||||
# its file under its own name.
|
||||
self._unoffered.setdefault((key, standalone), [
|
||||
(entry, _placeholder_report(key, profiles[key], entry))
|
||||
for entry in profiles[key].get("files") or []
|
||||
])
|
||||
self._db = db
|
||||
|
||||
@staticmethod
|
||||
@@ -582,14 +584,14 @@ class LauncherLayer:
|
||||
# RetroPie runs sdl2trs with -romfile4p $biosdir/level4p.rom: the
|
||||
# file under that name is the one the romfile4p slot reads.
|
||||
if set_by(entry, place.passes_to):
|
||||
return _Candidate(entry, basenames, False)
|
||||
return _Candidate(entry, basenames, False, by_setting_or_stem=True)
|
||||
if place.kind == "fixed_name":
|
||||
stems = {
|
||||
base for base in basenames
|
||||
if (stem := suffixed_stem(base)) is not None and place.fold(stem) in own
|
||||
}
|
||||
if stems:
|
||||
return _Candidate(entry, stems, False)
|
||||
return _Candidate(entry, stems, False, by_setting_or_stem=True)
|
||||
content = {
|
||||
place.fold(path.rsplit("/", 1)[-1])
|
||||
for path in place.paths
|
||||
@@ -654,15 +656,26 @@ class LauncherLayer:
|
||||
by_layout: dict[tuple[str, bool], list[tuple[dict, dict]]] = {}
|
||||
for emulator, standalone, entry, report in candidates:
|
||||
by_layout.setdefault((emulator, standalone), []).append((entry, report))
|
||||
for layout, members in self._placeholders.items():
|
||||
by_layout.setdefault(layout, []).extend(members)
|
||||
offered = {id(entry) for _e, _s, entry, _r in candidates}
|
||||
for layout, members in self._unoffered.items():
|
||||
for entry, report in members:
|
||||
if id(entry) in offered:
|
||||
continue
|
||||
if "<" not in str(entry.get("name", "")):
|
||||
report["in_repo"] = resolve_held(report) is not None
|
||||
report["unoffered"] = True
|
||||
by_layout.setdefault(layout, []).append((entry, report))
|
||||
placed: set[str] = set()
|
||||
for (emulator, standalone), members in sorted(by_layout.items()):
|
||||
for place in self.places_for(emulator, standalone):
|
||||
# An entry the report left out answers only through the
|
||||
# setting or the extended name: by its own name it was left
|
||||
# out for a reason (a region variant, a settled duplicate).
|
||||
matched = [
|
||||
(candidate, report)
|
||||
for entry, report in members
|
||||
if (candidate := self.match(place, entry)) is not None
|
||||
and (candidate.by_setting_or_stem or not report.get("unoffered"))
|
||||
]
|
||||
# A size names one entry only when no other of the core's
|
||||
# entries takes that size too.
|
||||
@@ -798,8 +811,14 @@ class LauncherLayer:
|
||||
|
||||
|
||||
def _placeholder_report(key: str, profile: dict, entry: dict) -> dict:
|
||||
"""The report entry of a placeholder, which the gap report never builds."""
|
||||
"""The report entry of an entry the gap report never builds."""
|
||||
identity = {
|
||||
field: entry[field]
|
||||
for field in ("aliases", "md5", "sha1", "sha256", "crc32", "size", "min_size", "max_size")
|
||||
if entry.get(field) is not None
|
||||
}
|
||||
return {
|
||||
**identity,
|
||||
"profile": key,
|
||||
"emulator": profile.get("emulator", key),
|
||||
"name": entry.get("name", ""),
|
||||
|
||||
@@ -289,6 +289,24 @@ class LauncherLayerTest(unittest.TestCase):
|
||||
self.assertEqual(added["kick.A500.rom"]["md5"], _md5(CONTENT["core.bin"]))
|
||||
self.assertIsNone(suffixed_stem("scph1001.bin"))
|
||||
|
||||
def test_an_entry_the_platform_declares_still_fills_the_launcher_name(self) -> None:
|
||||
"""AmberELEC declares kick34005.A500, so the report never offers
|
||||
Amiberry's entry, and its config still passes kick34005.A500.rom."""
|
||||
profile = {
|
||||
"emulator": "FixEmu", "type": "standalone", "systems": ["test-sys"],
|
||||
"files": [{"name": "core.bin", "aliases": ["kick.A500"], "required": True}],
|
||||
}
|
||||
with open(os.path.join(self.emulators_dir, "fixemu.yml"), "w") as fh:
|
||||
yaml.dump(profile, fh)
|
||||
self.config["launchers"][2]["names"] = ["kick.A500.rom"]
|
||||
self.config["systems"]["test-sys"]["files"].append(
|
||||
{"name": "core.bin", "destination": "core.bin", "required": True}
|
||||
)
|
||||
_emulator_profiles_cache.clear()
|
||||
self.profiles = load_emulator_profiles(self.emulators_dir)
|
||||
added = {u["path"]: u for u in self._report() if u.get("launcher")}
|
||||
self.assertEqual(added["kick.A500.rom"]["md5"], _md5(CONTENT["core.bin"]))
|
||||
|
||||
def test_each_name_of_a_config_takes_its_own_key(self) -> None:
|
||||
"""AmberELEC's atari800.cfg names eight ROMs under eight keys, and
|
||||
one record describes them in order: 5200a.rom is ROM_5200_A's file,
|
||||
|
||||
Reference in new issue
Block a user