fix: count only the hash changes an export writes

RomM kept hashes the truth contradicts beside the corrected one, RetroDECK kept a cleared md5, Recalbox counted changes on an element it writes back whole, and two record formats counted fills no record could hold.
This commit is contained in:
Abdessamad Derraz committed 2026-10-18 20:36:47 +02:00
1 parent a913fbf539
commit eac2eaec83
7 files changed
+116 -3

No files matched your search

+14
View File
@@ -179,6 +179,20 @@ class BaseExporter(ABC):
"""
return field_name in self.carries()
def fills(self, fe: NativeFile, field_name: str) -> bool:
"""Whether a hash only the truth names lands in the written entry."""
return self.states(fe, field_name)
def clears(self, fe: NativeFile, field_name: str) -> bool:
"""Whether a platform hash the truth contradicts leaves the entry."""
return self.states(fe, field_name)
@staticmethod
def record_fills(fe: NativeFile, field_name: str) -> bool:
"""A record format writes a filled hash only when record_hash names
one: two values the truth accepts make no single record."""
return bool(fe.record_hash(field_name))
def withheld(self) -> list[str]:
"""Corrections the render proved and still did not write, named.
+11
View File
@@ -98,6 +98,17 @@ class Exporter(BaseExporter):
return f" <bios {' '.join(attrs)} />"
def states(self, fe: NativeFile, field_name: str) -> bool:
"""An element it cannot rewrite is written back as Recalbox wrote it.
es_bios.xsd makes md5 required: an entry whose md5 the truth
contradicts without naming another keeps its element whole, and
counting the md5 cleared announced a change absent from the file.
"""
if fe.platform is not None and not self.writable(fe):
return False
return super().states(fe, field_name)
@classmethod
def writable(cls, fe: NativeFile, require: str = "") -> bool:
"""es_bios.xsd makes md5 and core required; without them, no element.
+6
View File
@@ -247,6 +247,12 @@ class Exporter(BaseExporter):
(field, value) for field, value in by_key[keys[0]].items()
if field in cls.carries() and not (field == "system" and declared)
)
# A hash of theirs that ours no longer carries is one the truth
# contradicts: kept, it went on rejecting the dump the emulator
# loads while the summary counted it cleared.
for field in ("md5", "sha256"):
if field in cls.carries() and field not in by_key[keys[0]]:
combined.pop(field, None)
if _md5_set(entry.get("md5")) == _md5_set(combined.get("md5")):
combined["md5"] = entry.get("md5")
elif isinstance(entry.get("md5"), list) and isinstance(combined.get("md5"), str):
+15 -1
View File
@@ -18,7 +18,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from scraper.romm_scraper import SLUG_MAP
from .base_exporter import BaseExporter
from .baseline import NativeFile, NativeSystem, Report
from .baseline import NativeFile, NativeSystem, Report, _hash_values
SOURCE_URL = (
"https://raw.githubusercontent.com/rommapp/romm/master/backend/models"
@@ -143,11 +143,25 @@ class Exporter(BaseExporter):
value = fe.record_hash(hash_name)
if value:
self._write(entry, field, value, fe, hash_name)
elif self._contradicted(fe, hash_name):
# RomM accepts any one hash: a value the truth
# rejects, left beside the corrected md5, still
# passes the dump it describes.
entry.pop(field, None)
output[key] = entry
text = json.dumps(output, indent=2, ensure_ascii=False) + "\n"
return {self.native_filename(): text}
@staticmethod
def _contradicted(fe: NativeFile, name: str) -> bool:
"""A hash the platform states and the truth, taking the entry over,
does not keep."""
return bool(_hash_values(fe.platform or {}, name)) and not fe.hashes(name)
def fills(self, fe: NativeFile, field_name: str) -> bool:
return self.states(fe, field_name) and self.record_fills(fe, field_name)
def _write(
self, entry: dict, field: str, value: str, fe: NativeFile, name: str
) -> None:
+3
View File
@@ -134,6 +134,9 @@ class Exporter(BaseExporter):
)
return lines
def fills(self, fe: NativeFile, field_name: str) -> bool:
return self.states(fe, field_name) and self.record_fills(fe, field_name)
def render(
self,
systems: dict[str, NativeSystem],