mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 21:43:23 -05:00
fix: never pair files whose contents or dirs differ
This commit is contained in:
1 parent
22f018995e
commit
6380a92e6c
4 files changed
+75
-3
No files matched your search
@@ -323,13 +323,21 @@ def build_native_model(
|
||||
]
|
||||
|
||||
def by_destination(candidate: NativeFile) -> bool:
|
||||
# Dolphin writes dolphin-emu/Sys/GC/USA/IPL.bin for the truth's
|
||||
# GC/USA/IPL.bin: a destination ending in the path is the file.
|
||||
theirs = _match_key(candidate.platform or {})[0]
|
||||
return bool(t_dest) and theirs == t_dest
|
||||
return bool(t_dest) and (theirs == t_dest or theirs.endswith("/" + t_dest))
|
||||
|
||||
def by_name(candidate: NativeFile) -> bool:
|
||||
theirs = _match_key(candidate.platform or {})[1]
|
||||
theirs_dest, theirs = _match_key(candidate.platform or {})
|
||||
if not t_name or theirs != t_name:
|
||||
return False
|
||||
# Two declared directories that differ name two files: the
|
||||
# truth's BeebFile/BIOS.rom is not Recalbox's np2kai/bios.rom.
|
||||
if "/" in t_dest and "/" in theirs_dest and not theirs_dest.endswith(
|
||||
"/" + t_dest.rsplit("/", 1)[0].rsplit("/", 1)[-1] + "/" + t_name
|
||||
):
|
||||
return False
|
||||
# A shared name with two declared sizes is two files: fbneo's
|
||||
# 480-byte boot.bin is not RomM's 2 MB Dreamcast boot.bin.
|
||||
t_size = truth_entry.get("size")
|
||||
|
||||
+19
-1
@@ -165,12 +165,30 @@ def _same_file(files: list[dict], file_entry: dict, emu_name: str) -> dict | Non
|
||||
same_name = [f for f in files if f["name"].lower() == name_lower]
|
||||
return (
|
||||
next((f for f in same_name if path and other_path(f) == path), None)
|
||||
or next((f for f in same_name if emu_name not in f.get("_cores", ())), None)
|
||||
# Another core's file of the same name is the same file unless their
|
||||
# contents disagree: beebem's 16 KB BBC BIOS.rom and np2kai's PC-98
|
||||
# bios.rom merged, and the export wrote the BBC md5 over Recalbox's.
|
||||
or next(
|
||||
(f for f in same_name
|
||||
if emu_name not in f.get("_cores", ()) and not _contents_disagree(f, file_entry)),
|
||||
None,
|
||||
)
|
||||
# Revisions accepted under one name and no path fill one slot.
|
||||
or next((f for f in same_name if not path or not other_path(f)), None)
|
||||
)
|
||||
|
||||
|
||||
def _contents_disagree(a: dict, b: dict) -> bool:
|
||||
"""A hash both declare without a value in common, or two declared sizes."""
|
||||
for field in ("sha1", "md5", "sha256", "crc32"):
|
||||
ours = {str(v).lower() for v in (a.get(field) if isinstance(a.get(field), list) else [a.get(field)]) if v}
|
||||
theirs = {str(v).lower() for v in (b.get(field) if isinstance(b.get(field), list) else [b.get(field)]) if v}
|
||||
if ours and theirs and not ours & theirs:
|
||||
return True
|
||||
size_a, size_b = a.get("size"), b.get("size")
|
||||
return isinstance(size_a, int) and isinstance(size_b, int) and size_a != size_b
|
||||
|
||||
|
||||
def _fold_into(existing: dict, file_entry: dict, emu_name: str) -> None:
|
||||
"""Add one core's declaration to the entry that already stands for it."""
|
||||
existing["_cores"] = existing.get("_cores", set()) | {emu_name}
|
||||
|
||||
@@ -195,6 +195,16 @@ class MisterCountsWhatItWrites(unittest.TestCase):
|
||||
self.assertFalse(exporter.states(absent, "md5"))
|
||||
|
||||
|
||||
class OneMd5FormatsAddWhole(unittest.TestCase):
|
||||
def test_an_addition_with_several_md5_is_refused(self):
|
||||
from exporter.batocera_exporter import Exporter as Batocera # noqa: PLC0415
|
||||
|
||||
several = NativeFile("boot.bin", "boot.bin", "dc", truth={"md5": [A, B, C]})
|
||||
single = NativeFile("boot2.bin", "boot2.bin", "dc", truth={"md5": A})
|
||||
self.assertFalse(Batocera.writable(several))
|
||||
self.assertTrue(Batocera.writable(single))
|
||||
|
||||
|
||||
class ModelKeepsOneFileOneEntry(unittest.TestCase):
|
||||
def test_a_list_of_sizes_is_not_one_size(self):
|
||||
"""A profile may accept several revisions; int() on the list crashed."""
|
||||
@@ -275,6 +285,31 @@ class RommKeepsItsOwnKeys(unittest.TestCase):
|
||||
self.assertEqual(written["dc:boot.bin"]["size"], "2097152")
|
||||
self.assertFalse(exporter.writable(ours))
|
||||
|
||||
class NamesInAnotherDirectory(unittest.TestCase):
|
||||
def test_a_truth_path_in_another_directory_does_not_match(self):
|
||||
scraped = {"systems": {"pc98": {"files": [
|
||||
{"name": "bios.rom", "destination": "np2kai/bios.rom", "md5": A},
|
||||
]}}}
|
||||
truth = {"systems": {"pc98": {"files": [
|
||||
{"name": "bios.rom", "path": "BeebFile/BIOS.rom", "md5": B},
|
||||
]}}}
|
||||
systems, _report = build_native_model(truth, scraped)
|
||||
declared = next(f for f in systems["pc98"].files if f.platform is not None)
|
||||
self.assertIsNone(declared.truth)
|
||||
|
||||
def test_a_destination_ending_in_the_path_matches(self):
|
||||
scraped = {"systems": {"gc": {"files": [
|
||||
{"name": "IPL.bin", "destination": "dolphin-emu/Sys/GC/USA/IPL.bin", "md5": A},
|
||||
{"name": "IPL.bin", "destination": "dolphin-emu/Sys/GC/EUR/IPL.bin", "md5": B},
|
||||
]}}}
|
||||
truth = {"systems": {"gc": {"files": [
|
||||
{"name": "IPL.bin", "path": "GC/EUR/IPL.bin", "md5": B},
|
||||
{"name": "IPL.bin", "path": "GC/USA/IPL.bin", "md5": A},
|
||||
]}}}
|
||||
systems, report = build_native_model(truth, scraped)
|
||||
self.assertEqual(report.hashes_corrected, [])
|
||||
|
||||
|
||||
class RecalboxKeepsItsOwnNotes(unittest.TestCase):
|
||||
def test_no_profile_prose_reaches_a_note(self):
|
||||
fe = NativeFile("bios.bin", "bios.bin", "psx", platform={"md5": A},
|
||||
|
||||
@@ -115,6 +115,17 @@ class OneNameSeveralFiles(unittest.TestCase):
|
||||
self.assertEqual(_diff_system(self._system(), scraped), {})
|
||||
|
||||
|
||||
class DifferentContentsStayApart(unittest.TestCase):
|
||||
def test_two_cores_same_name_different_contents(self):
|
||||
"""beebem's BBC BIOS.rom and np2kai's PC-98 bios.rom merged into one."""
|
||||
system: dict = {}
|
||||
_merge_file_into_system(system, {"name": "bios.rom", "path": "np2kai/bios.rom",
|
||||
"md5": "a" * 32}, "np2kai", None)
|
||||
_merge_file_into_system(system, {"name": "bios.rom", "path": "BeebFile/BIOS.rom",
|
||||
"md5": "b" * 32, "size": 16384}, "beebem", None)
|
||||
self.assertEqual(len(system["files"]), 2)
|
||||
|
||||
|
||||
class RenameMatching(unittest.TestCase):
|
||||
def test_a_shared_sha1_pairs_the_two_names(self):
|
||||
truth = [_entry("bios_CD_U.bin", sha1="a" * 40)]
|
||||
|
||||
Reference in new issue
Block a user