mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 21:43:23 -05:00
fix: write retrodeck additions beside homonyms
This commit is contained in:
1 parent
0057a82fe1
commit
b5f9095633
2 files changed
+60
-4
No files matched your search
@@ -37,6 +37,14 @@ def _md5_set(value: object) -> set[str]:
|
|||||||
return {m.strip().lower() for m in str(value or "").split(",") if m.strip()}
|
return {m.strip().lower() for m in str(value or "").split(",") if m.strip()}
|
||||||
|
|
||||||
|
|
||||||
|
def _paths_key(entry: dict) -> tuple[str, ...]:
|
||||||
|
"""Where an entry says the file goes: no paths is the BIOS root."""
|
||||||
|
paths = entry.get("paths")
|
||||||
|
if isinstance(paths, list):
|
||||||
|
return tuple(sorted(str(p) for p in paths))
|
||||||
|
return (str(paths),) if paths else ()
|
||||||
|
|
||||||
|
|
||||||
def _matching_keys(
|
def _matching_keys(
|
||||||
entry: dict, by_key: dict[tuple[str, str], OrderedDict]
|
entry: dict, by_key: dict[tuple[str, str], OrderedDict]
|
||||||
) -> list[tuple[str, str]]:
|
) -> list[tuple[str, str]]:
|
||||||
@@ -177,7 +185,12 @@ class Exporter(BaseExporter):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _merge(cls, existing: object, ours: list[OrderedDict]) -> list[OrderedDict]:
|
def _merge(
|
||||||
|
cls,
|
||||||
|
existing: object,
|
||||||
|
ours: list[OrderedDict],
|
||||||
|
additions: list[OrderedDict] | None = None,
|
||||||
|
) -> list[OrderedDict]:
|
||||||
"""Correct the component's own list; never replace it.
|
"""Correct the component's own list; never replace it.
|
||||||
|
|
||||||
Assigning our entries wholesale dropped every file RetroDECK declares
|
Assigning our entries wholesale dropped every file RetroDECK declares
|
||||||
@@ -234,6 +247,21 @@ class Exporter(BaseExporter):
|
|||||||
merged.extend(
|
merged.extend(
|
||||||
entry for key, entry in by_key.items() if key not in corrected
|
entry for key, entry in by_key.items() if key not in corrected
|
||||||
)
|
)
|
||||||
|
# A file the platform does not declare is appended unless the list
|
||||||
|
# already holds that name for that system at that path. The key
|
||||||
|
# above is name and system only, and folded melonDS's SkyEmu/
|
||||||
|
# firmware.bin into the root firmware.bin the platform declares,
|
||||||
|
# while the report counted it added.
|
||||||
|
held = {
|
||||||
|
(str(e.get("filename", "")), system, _paths_key(e))
|
||||||
|
for e in merged
|
||||||
|
for system in (_systems_of(e) or [""])
|
||||||
|
}
|
||||||
|
for entry in additions or []:
|
||||||
|
key = (str(entry.get("filename", "")), str(entry.get("system", "")), _paths_key(entry))
|
||||||
|
if key[0] and key not in held:
|
||||||
|
held.add(key)
|
||||||
|
merged.append(entry)
|
||||||
return merged
|
return merged
|
||||||
|
|
||||||
def render(
|
def render(
|
||||||
@@ -257,16 +285,17 @@ class Exporter(BaseExporter):
|
|||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
entries = [self._entry(fe) for fe in files]
|
entries = [self._entry(fe) for fe in files if fe.platform is not None]
|
||||||
|
additions = [self._entry(fe) for fe in files if fe.platform is None]
|
||||||
for component_value in manifest.values():
|
for component_value in manifest.values():
|
||||||
if not isinstance(component_value, dict):
|
if not isinstance(component_value, dict):
|
||||||
continue
|
continue
|
||||||
holder = self._bios_holder(component_value)
|
holder = self._bios_holder(component_value)
|
||||||
if holder is None:
|
if holder is None:
|
||||||
component_value["bios"] = self._merge(None, entries)
|
component_value["bios"] = self._merge(None, entries, additions)
|
||||||
else:
|
else:
|
||||||
container, key = holder
|
container, key = holder
|
||||||
container[key] = self._merge(container.get(key), entries)
|
container[key] = self._merge(container.get(key), entries, additions)
|
||||||
break
|
break
|
||||||
|
|
||||||
produced[path] = json.dumps(manifest, indent=2, ensure_ascii=False) + "\n"
|
produced[path] = json.dumps(manifest, indent=2, ensure_ascii=False) + "\n"
|
||||||
@@ -293,6 +322,7 @@ class Exporter(BaseExporter):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
declared: set[str] = set()
|
declared: set[str] = set()
|
||||||
|
placed: set[tuple[str, tuple[str, ...]]] = set()
|
||||||
for component_value in manifest.values():
|
for component_value in manifest.values():
|
||||||
if not isinstance(component_value, dict):
|
if not isinstance(component_value, dict):
|
||||||
continue
|
continue
|
||||||
@@ -302,6 +332,7 @@ class Exporter(BaseExporter):
|
|||||||
container, key = holder
|
container, key = holder
|
||||||
for entry in container[key]:
|
for entry in container[key]:
|
||||||
declared.add(entry.get("filename", ""))
|
declared.add(entry.get("filename", ""))
|
||||||
|
placed.add((entry.get("filename", ""), _paths_key(entry)))
|
||||||
if not component_value.get("name") and not component_value.get(
|
if not component_value.get("name") and not component_value.get(
|
||||||
"system"
|
"system"
|
||||||
):
|
):
|
||||||
@@ -310,4 +341,8 @@ class Exporter(BaseExporter):
|
|||||||
for fe in files:
|
for fe in files:
|
||||||
if fe.name not in declared:
|
if fe.name not in declared:
|
||||||
issues.append(f"absent from {path}: {fe.name}")
|
issues.append(f"absent from {path}: {fe.name}")
|
||||||
|
elif fe.platform is None and (
|
||||||
|
fe.name, _paths_key(self._entry(fe))
|
||||||
|
) not in placed:
|
||||||
|
issues.append(f"absent from {path}: {fe.destination or fe.name}")
|
||||||
return issues
|
return issues
|
||||||
@@ -57,6 +57,27 @@ class RetroDeckWritesWhatItCounts(unittest.TestCase):
|
|||||||
merged = RetroDeck._merge(existing, ours)
|
merged = RetroDeck._merge(existing, ours)
|
||||||
self.assertEqual([e["md5"] for e in merged], [f"{A},{C}", B])
|
self.assertEqual([e["md5"] for e in merged], [f"{A},{C}", B])
|
||||||
|
|
||||||
|
def test_an_addition_at_another_path_is_written(self):
|
||||||
|
"""melonDS: RetroDECK declares firmware.bin at the root; the truth adds
|
||||||
|
SkyEmu/firmware.bin. Keyed by name and system, the addition vanished
|
||||||
|
and the report still counted it."""
|
||||||
|
existing = [{"filename": "firmware.bin", "system": "nds", "md5": A}]
|
||||||
|
addition = OrderedDict(filename="firmware.bin", system="nds", md5=B,
|
||||||
|
paths="$bios_path/SkyEmu")
|
||||||
|
merged = RetroDeck._merge(existing, [], [addition])
|
||||||
|
self.assertEqual(
|
||||||
|
[(e["md5"], e.get("paths")) for e in merged],
|
||||||
|
[(A, None), (B, "$bios_path/SkyEmu")],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_an_addition_never_corrects_a_platform_entry(self):
|
||||||
|
existing = [{"filename": "firmware.bin", "system": "nds", "md5": A}]
|
||||||
|
addition = OrderedDict(filename="firmware.bin", system="nds", md5=B,
|
||||||
|
paths="$bios_path/SkyEmu")
|
||||||
|
merged = RetroDeck._merge(existing, [], [addition, addition])
|
||||||
|
self.assertEqual(merged[0]["md5"], A)
|
||||||
|
self.assertEqual(len(merged), 2)
|
||||||
|
|
||||||
def test_a_list_of_systems_is_kept(self):
|
def test_a_list_of_systems_is_kept(self):
|
||||||
existing = [{"filename": "neogeo.zip", "system": ["neogeo", "fbneo"], "md5": A}]
|
existing = [{"filename": "neogeo.zip", "system": ["neogeo", "fbneo"], "md5": A}]
|
||||||
ours = [OrderedDict(filename="neogeo.zip", system="fbneo", md5=B)]
|
ours = [OrderedDict(filename="neogeo.zip", system="fbneo", md5=B)]
|
||||||
|
|||||||
Reference in new issue
Block a user