diff --git a/scripts/generate_db.py b/scripts/generate_db.py index 537871b1..f5ddba5b 100644 --- a/scripts/generate_db.py +++ b/scripts/generate_db.py @@ -395,6 +395,14 @@ def main(): return 0 +def _as_list(value: object) -> list[str]: + """A hash field as lowercase values, whether written alone or as a list.""" + if not value: + return [] + values = value if isinstance(value, list) else str(value).split(",") + return [str(v).strip().lower() for v in values if str(v).strip()] + + def _collect_all_aliases(files: dict) -> dict: """Collect alternate filenames from platform YAMLs, core-info, and known aliases. @@ -483,27 +491,31 @@ def _collect_all_aliases(files: dict) -> dict: for file_entry in emu_config.get("files", []): entry_aliases = list(file_entry.get("aliases") or []) entry_name = file_entry.get("name", "") - sha1 = file_entry.get("sha1", "") - md5 = file_entry.get("md5", "") - matched = None - if sha1 and sha1 in files: - matched = sha1 + # A profile may accept several revisions: each held one + # is designated by the entry, none of them by guess. + matched: set[str] = { + value for value in _as_list(file_entry.get("sha1")) + if value in files + } + matched |= { + md5_to_sha1[value] + for value in _as_list(file_entry.get("md5")) + if value in md5_to_sha1 + } + if matched: # Proven by content, the profile's own name designates # the file whatever the collection calls it. entry_aliases.insert(0, entry_name) - elif md5 and md5 in md5_to_sha1: - matched = md5_to_sha1[md5] - entry_aliases.insert(0, entry_name) if not entry_aliases: continue if not matched and entry_name and name_count.get(entry_name) == 1: # A name carried by several files names none of them: # quasi88's disk.rom aliases went to whichever # disk.rom the scan met last, a Tandy CoCo ROM. - matched = name_to_sha1[entry_name] - if matched: + matched = {name_to_sha1[entry_name]} + for sha in sorted(matched): for alias_name in entry_aliases: - _add_alias(alias_name, matched) + _add_alias(alias_name, sha) except ImportError: pass diff --git a/tests/test_db_aliases.py b/tests/test_db_aliases.py index 2268a3a2..25263709 100644 --- a/tests/test_db_aliases.py +++ b/tests/test_db_aliases.py @@ -88,5 +88,28 @@ class NoNetworkInTheBuild(unittest.TestCase): os.chdir(previous) self.assertEqual([a["name"] for a in aliases.get("s1", [])], ["writer.rom"]) +class AcceptedRevisionLists(unittest.TestCase): + def test_a_list_of_sha1_names_every_held_revision(self): + """A profile accepting several revisions writes sha1 as a list.""" + import generate_db + + with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp: + previous = os.getcwd() + os.chdir(tmp) + try: + Path("emulators").mkdir() + Path("emulators/m.yml").write_text( + 'files:\n - name: "MT32_CONTROL.ROM"\n' + ' sha1: ["s1", "s2", "absent"]\n' + ) + aliases = generate_db._collect_all_aliases({ + "s1": {"name": "ctrl_1_04.rom", "path": "a", "md5": "m1"}, + "s2": {"name": "ctrl_1_05.rom", "path": "b", "md5": "m2"}, + }) + finally: + os.chdir(previous) + for sha in ("s1", "s2"): + self.assertEqual([a["name"] for a in aliases.get(sha, [])], ["MT32_CONTROL.ROM"]) + if __name__ == "__main__": unittest.main()