fix: credit a core the archive it reads members in

FBNeo reads sm1.sm1 inside neogeo.zip. The site resolved each member entry by its crc32, credited loose copies FBNeo never opens, and no neogeo.zip card named FBNeo. A member entry now resolves through archive_entry as the pack does, and its card names the archive.
This commit is contained in:
Abdessamad Derraz committed 2026-11-05 19:29:02 +01:00
1 parent f24b34c1ef
commit 1b388e3cdc
3 files changed
+51 -8

No files matched your search

+16 -6
View File
@@ -27,6 +27,7 @@ from common import (
platform_arg,
ProfileSelectionError,
_norm_system_id,
archive_entry,
directory_members,
expand_directory_entries,
get_mame_clone_map,
@@ -545,6 +546,20 @@ class FileConsumers:
if member is not entry
}
@staticmethod
def entry_target(entry: dict, files: list[dict]) -> tuple[dict, str]:
"""The entry a profile entry resolves through, and its destination.
A ROM read inside an archive is the archive: FBNeo opens sm1.sm1 in
neogeo.zip, and resolved by its crc32 it credited a loose copy FBNeo
never opens, while no neogeo.zip card named FBNeo. The archive
members the profile reads decide between same-named copies, as in
the emulator pack and verify.
"""
if entry.get("archive"):
return archive_entry(entry["archive"], files), ""
return with_archive_members(entry, files), entry.get("path") or ""
def add_emulators(self, profiles: dict[str, dict]) -> None:
"""Each file a profile entry resolves to, a directory's members included.
@@ -573,12 +588,7 @@ class FileConsumers:
for dest, sha1 in members.items()
]
else:
# The archive members the profile reads decide between
# same-named copies, as in the emulator pack and verify.
found = [self.sha1_of(
with_archive_members(entry, files), entry.get("path") or "",
owner=name,
)]
found = [self.sha1_of(*self.entry_target(entry, files), owner=name)]
for sha1 in found:
if sha1:
self.emulators.setdefault(sha1, set()).add(name)
+5 -2
View File
@@ -8182,10 +8182,13 @@ def _render_emulator_file(
if consumers and f.get("type") == "directory":
details.extend(_directory_copies(f, consumers))
if consumers:
sha1 = consumers.sha1_of(f, f.get("path") or "", owner=owner)
sha1 = consumers.sha1_of(
*consumers.entry_target(f, profile.get("files") or []), owner=owner)
held = consumers.path_of(sha1) if sha1 and in_repo else ""
parts = held.split("/")
if len(parts) >= 3 and parts[0] == "bios":
if len(parts) >= 3 and parts[0] == "bios" and f.get("archive"):
details.append(_held_copy_line((held, f["name"]), consumers))
elif len(parts) >= 3 and parts[0] == "bios":
# Which copy answers this entry, linked to its collection card
# (provenance, every hash, download): an entry declaring no hash
# said "in repo" without naming the file.
+30
View File
@@ -454,3 +454,33 @@ class OneDefinitionPerName(unittest.TestCase):
self.assertNotIn(name, seen, f"{path.name}:{node.lineno} binds {name} "
f"again, first at line {seen.get(name)}")
seen[name] = node.lineno
@unittest.skipUnless((REPO_ROOT / "database.json").is_file(), "database.json is not built")
class AMemberIsReadInItsArchive(unittest.TestCase):
"""FBNeo reads sm1.sm1 inside neogeo.zip. Resolved by its crc32, the
entry credited a loose sm1.sm1 FBNeo never opens, and no neogeo.zip card
named FBNeo, while the pack ships it one."""
def test_the_archive_is_credited_and_named_on_the_card(self):
import json
import generate_site as gs
from common import archive_entry, resolve_local_file
from cross_reference import FileConsumers
db = json.loads((REPO_ROOT / "database.json").read_text(encoding="utf-8"))
profile = yaml.safe_load((REPO_ROOT / "emulators" / "fbneo.yml").read_text(encoding="utf-8"))
files = profile["files"]
consumers = FileConsumers(db)
consumers.add_emulators({"fbneo": profile})
credited = {consumers.path_of(sha1) for sha1 in consumers.emulators}
shipped, _status = resolve_local_file(
{**archive_entry("neogeo.zip", files), "source_profile": "fbneo"}, db)
self.assertIn(shipped, credited)
self.assertFalse([p for p in credited if p.endswith("/sm1.sm1")])
sm1 = next(f for f in files if f["name"] == "sm1.sm1")
rows = "\n".join(gs._render_emulator_file(sm1, profile, consumers, files,
lambda _f: True, owner="fbneo"))
self.assertIn("Collection copy: member `sm1.sm1` of", rows)
self.assertIn(shipped, rows)