fix: lay a hash pack out as its emulator does

This commit is contained in:
Abdessamad Derraz committed 2026-10-10 07:59:18 +02:00
1 parent e8bdcb405d
commit 9002a4a4bb
2 files changed
+50 -6

No files matched your search

+38 -6
View File
@@ -1826,6 +1826,33 @@ def generate_split_packs(
return results
def _entry_for_file(candidates: list[dict], held: dict) -> dict:
"""The declaration a held file answers when several share its name.
BBKEmu declares 8.BIN once per model; the last one won, and the A4980
dump went to the A4988 folder. The declared hash decides, then the
destination the collection's own path ends with, then the last one.
"""
def declared(fe: dict, key: str) -> set[str]:
value = fe.get(key)
values = value if isinstance(value, list) else str(value or "").split(",")
return {str(v).strip().lower() for v in values if str(v).strip()}
for fe in candidates:
if any(
str(held.get(key, "")).lower() in declared(fe, key)
for key in ("sha1", "md5", "sha256", "crc32")
if held.get(key)
):
return fe
held_paths = [str(held.get("path", ""))] + [str(p) for p in held.get("paths") or []]
for fe in candidates:
tail = str(fe.get("path") or fe.get("destination") or "").lower()
if tail and any(path.lower().endswith("/" + tail) for path in held_paths):
return fe
return candidates[-1]
def generate_md5_pack(
hashes: list[tuple[str, str]],
db: dict,
@@ -1845,7 +1872,7 @@ def generate_md5_pack(
if zip_contents is None:
zip_contents = {}
plat_file_index: dict[str, dict] = {}
plat_file_index: dict[str, list[dict]] = {}
base_dest = ""
plat_display = "Custom"
if platform_name and platforms_dir:
@@ -1854,7 +1881,7 @@ def generate_md5_pack(
plat_display = config.get("platform", platform_name)
for _sys_id, system in config.get("systems", {}).items():
for fe in system.get("files", []):
plat_file_index[fe.get("name", "").lower()] = fe
plat_file_index.setdefault(fe.get("name", "").lower(), []).append(fe)
emu_pack_structure = None
emu_display = ""
@@ -1873,9 +1900,9 @@ def generate_md5_pack(
emu_display = profile.get("emulator", emulator_name)
emu_pack_structure = profile.get("pack_structure")
for fe in profile.get("files", []):
plat_file_index[fe.get("name", "").lower()] = fe
plat_file_index.setdefault(fe.get("name", "").lower(), []).append(fe)
for alias in fe.get("aliases", []):
plat_file_index[alias.lower()] = fe
plat_file_index.setdefault(alias.lower(), []).append(fe)
context_name = plat_display if platform_name else (emu_display or "Custom")
# --standalone changes the destination layout, so a run with it must not
@@ -1920,11 +1947,16 @@ def generate_md5_pack(
matched_fe = None
for lookup_name in [name] + aliases:
if lookup_name.lower() in plat_file_index:
matched_fe = plat_file_index[lookup_name.lower()]
matched_fe = _entry_for_file(
plat_file_index[lookup_name.lower()], entry
)
break
if matched_fe:
if emulator_name and emu_pack_structure is not None:
if emulator_name:
# Laid out as the emulator pack lays it out: a profile
# without pack_structure still names its path and its
# standalone_path, and --standalone has to reach them.
dest = _resolve_destination(
matched_fe, emu_pack_structure, standalone
)
+12
View File
@@ -50,5 +50,17 @@ class TheEmulatorContextIsChecked(unittest.TestCase):
self.assertEqual(names, [])
def test_the_standalone_layout_reaches_a_profile_without_structure(self):
"""BBKEmu has no pack_structure; its A4980 8.BIN goes to
system/BBKEmu/A4980/ standalone. The hash pack kept the bare name,
then, once laid out, sent it to the A4988 folder whose entry shares
the name."""
md5 = "ddfc001a6859d63ed46368ea7fe9f20c"
if not any(record.get("md5") == md5 for record in self.db["files"].values()):
self.skipTest("the A4980 8.BIN is not collected")
proc, names = _pack("--from-md5", md5, "--emulator", "bbkemu", "--standalone")
self.assertEqual(proc.returncode, 0, proc.stderr)
self.assertEqual(names, ["system/BBKEmu/A4980/8.BIN"])
if __name__ == "__main__":
unittest.main()