fix: exporters keep what the maintainer wrote

This commit is contained in:
Abdessamad Derraz committed 2026-10-09 22:45:57 +02:00
1 parent 3baec1794b
commit 8fb65b8e97
4 files changed
+133 -20

No files matched your search

+43 -10
View File
@@ -62,10 +62,29 @@ class Exporter(BaseExporter):
# The data block is a fraction of the file; the rest is the checker.
return True
def _bios_files(self, files: list[NativeFile]) -> str:
return ", ".join(self._bios_items(files))
def _bios_files(self, files: list[NativeFile], before: dict | None = None) -> str:
return ", ".join(self._bios_items(files, before))
def _bios_items(self, files: list[NativeFile]) -> list[str]:
@staticmethod
def _runner_keys(item: dict | None) -> list[str]:
"""The emulator and core checkBios reads through coreExists().
Not in our model, so they travel from the maintainer's own entry: a
rewritten item without them made the checker treat the BIOS as
wanted by every build (vectrex, tvc, macintosh, bk).
"""
return [
f'"{key}": "{item[key]}"'
for key in ("emulator", "core")
if item and isinstance(item.get(key), str)
]
def _bios_items(self, files: list[NativeFile], before: dict | None = None) -> list[str]:
originals = {
str(item.get("file", "")): item
for item in (before or {}).get("biosFiles", [])
if isinstance(item, dict)
}
parts: list[str] = []
for fe in files:
# The platform states an unhashed file as an empty md5 rather
@@ -80,14 +99,25 @@ class Exporter(BaseExporter):
zipped = fe.native("zipped_file", "")
if zipped:
item.append(f'"zippedFile": "{zipped}"')
item.extend(self._runner_keys(originals.get(path)))
parts.append("{ " + ", ".join(item) + " }")
return parts
def _entry_line(self, system: NativeSystem, files: list[NativeFile]) -> str:
@staticmethod
def _own_entry(system: NativeSystem, before: dict | None) -> dict:
"""The maintainer's entry for this system, out of the parsed pair."""
inner = (before or {}).get(system.native_id)
return inner if isinstance(inner, dict) else {}
def _entry_line(
self, system: NativeSystem, files: list[NativeFile], before: dict | None = None
) -> str:
own = self._own_entry(system, before)
runner = "".join(f"{key}, " for key in self._runner_keys(own))
return (
f'{_INDENT}"{system.native_id}": '
f'{{ "name": "{self.display_name(system)}", '
f'"biosFiles": [ {self._bios_files(files)} ] }},'
f'{{ "name": "{self.display_name(system)}", {runner}'
f'"biosFiles": [ {self._bios_files(files, own)} ] }},'
)
@staticmethod
@@ -127,14 +157,17 @@ class Exporter(BaseExporter):
) -> list[str]:
"""One entry, keeping the layout and the notes it was written with."""
trailing, leading = self._item_notes(original)
items = self._bios_items(files)
before = self._parse_entry(original)
own = self._own_entry(system, before)
items = self._bios_items(files, own)
one_line = len(original) == 1 and not trailing and not leading
if one_line:
return [self._entry_line(system, files)]
return [self._entry_line(system, files, before)]
runner = "".join(f"{key}, " for key in self._runner_keys(own))
head = (
f'{_INDENT}"{system.native_id}": '
f'{{ "name": "{self.display_name(system)}", "biosFiles": ['
f'{{ "name": "{self.display_name(system)}", {runner}"biosFiles": ['
)
pad = " " * (len(_INDENT) + 4)
lines = [head]
@@ -244,8 +277,8 @@ class Exporter(BaseExporter):
continue
written.add(key)
original_lines = body[start:end + 1]
replacement = self._entry_line(*pair)
before = self._parse_entry(original_lines)
replacement = self._entry_line(*pair, before)
after = self._parse_entry([replacement])
if before is not None and before == after:
# Nothing changed: keep the maintainer's own lines, comments
+9 -2
View File
@@ -82,8 +82,15 @@ class Exporter(BaseExporter):
for fe in system.files:
# A SHA1 BizHawk declares is BizHawk's own code, the authority
# for its cores: the truth's MSX.rom came from FBNeo and would
# have made MSXHawk refuse the dump it accepts.
if fe.hash("sha1") and not _hash_values(fe.platform or {}, "sha1"):
# have made MSXHawk refuse the dump it accepts. An entry the
# database never declared (can_add refuses it) names no call
# of its own either: by name it would rewrite the homonym of
# another system.
if (
fe.platform is not None
and fe.hash("sha1")
and not _hash_values(fe.platform, "sha1")
):
seen.setdefault(fe.name.casefold(), []).append(fe)
resolved: dict[str, NativeFile] = {}
for name, entries in seen.items():
+10 -8
View File
@@ -176,8 +176,8 @@ class Exporter(BaseExporter):
return nested, "bios"
return None
@staticmethod
def _merge(existing: object, ours: list[OrderedDict]) -> list[OrderedDict]:
@classmethod
def _merge(cls, existing: object, ours: list[OrderedDict]) -> list[OrderedDict]:
"""Correct the component's own list; never replace it.
Assigning our entries wholesale dropped every file RetroDECK declares
@@ -206,6 +206,9 @@ class Exporter(BaseExporter):
for system in _systems_of(entry):
key = (str(entry.get("filename", "")), system)
seen_keys[key] = seen_keys.get(key, 0) + 1
# A hash no revision shares is a revision the platform does not
# know: appended, not counted corrected against entries kept as
# they were (the 64DD IPL declared twice, both contradicted).
for entry in entries:
keys = _matching_keys(entry, by_key)
other_revision = (
@@ -213,18 +216,17 @@ class Exporter(BaseExporter):
and seen_keys.get(keys[0], 0) > 1
and not _md5_set(entry.get("md5")) & _md5_set(by_key[keys[0]].get("md5"))
)
if other_revision:
merged.append(OrderedDict(entry))
corrected.update(keys)
continue
if not keys:
if other_revision or not keys:
merged.append(OrderedDict(entry))
continue
declared = entry.get("system")
combined = OrderedDict(entry)
# Only what the format says it corrects: the maintainer's
# description and search paths are theirs (neogeo.zip lost its
# four roms directories to a path that does not exist).
combined.update(
(field, value) for field, value in by_key[keys[0]].items()
if not (field == "system" and declared)
if field in cls.carries() and not (field == "system" and declared)
)
merged.append(combined)
corrected.update(keys)