fix: give a suffixed release its emulator's tree

_foreign_tree compared owner tokens by equality, so cxbx-reloaded-2023
read bios/Other/cxbx-reloaded/ as another emulator's tree and the
case-folded fallback served xemu's encrypted EEPROM. The leading whole
words of a profile key now name its own tree too. Across every profile
entry this moves cxbx-reloaded-2023's EEPROM.bin to the decrypted dump,
turns eight name matches on the same files into path matches, and gives
solarus-2.0.0 the Solarus tree's gamecontrollerdb.txt.
This commit is contained in:
Abdessamad Derraz committed 2026-10-21 10:09:57 +02:00
1 parent 236f30860e
commit 604ab3371b
2 files changed
+56 -1

No files matched your search

+11 -1
View File
@@ -934,11 +934,21 @@ def _affinity_tokens(text: str) -> set[str]:
def _owner_tokens(file_entry: dict) -> set[str]:
"""Tokens naming the profile that asks for the file."""
"""Tokens naming the profile that asks for the file.
A profile named after another with a suffix (cxbx-reloaded-2023,
mame4droid-2024) is a release of that emulator, and the tree named by
the shorter name is its own: cxbx-reloaded-2023 was served xemu's
encrypted EEPROM because bios/Other/cxbx-reloaded/ read as foreign.
Only whole leading words count, so dolphin-mmjr2 is not dolphin-mmjr.
"""
tokens: set[str] = set()
for owner in (file_entry.get("source_profile"), file_entry.get("source_emulator")):
if owner:
tokens |= _affinity_tokens(str(owner).replace(" ", ""))
profile = str(file_entry.get("source_profile") or "").casefold()
words = [word for word in re.split(r"[^0-9a-z]+", profile) if word]
tokens |= {"".join(words[:end]) for end in range(1, len(words))}
return tokens
+45
View File
@@ -68,5 +68,50 @@ class ForeignTree(unittest.TestCase):
self.assertNotEqual(status, "path_exact")
class AReleaseNamedAfterTheTree(unittest.TestCase):
"""cxbx-reloaded-2023 asks for EEPROM.bin. Its emulator's tree holds the
decrypted dump Cxbx reads, xemu's aliases name the encrypted retail one
eeprom.bin. The tree read as foreign to the suffixed profile, so the
case-folded fallback served the encrypted dump."""
def setUp(self):
self._tmp = tempfile.TemporaryDirectory()
self._cwd = os.getcwd()
os.chdir(self._tmp.name)
files = {}
for rel, payload in (
("bios/Other/cxbx-reloaded/EEPROM.bin", b"decrypted"),
("bios/Microsoft/Xbox/eeprom.bin", b"encrypted"),
):
path = Path(rel)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(payload)
sha1 = hashlib.sha1(payload).hexdigest()
files[sha1] = {"path": rel, "name": path.name, "size": len(payload),
"sha1": sha1, "md5": hashlib.md5(payload).hexdigest(),
"sha256": hashlib.sha256(payload).hexdigest(),
"crc32": f"{len(files) + 1:08x}"}
self.db = {"files": files, "indexes": generate_db.build_indexes(files, {})}
def tearDown(self):
os.chdir(self._cwd)
self._tmp.cleanup()
def _resolve(self, owner: str, name: str):
entry = {"name": name, "source_profile": owner}
return resolve_local_file(entry, self.db, {})
def test_the_suffixed_release_reads_its_emulator_tree(self):
local, _status = self._resolve("cxbx-reloaded-2023", "EEPROM.bin")
self.assertEqual(local, "bios/Other/cxbx-reloaded/EEPROM.bin")
def test_only_whole_leading_words_name_the_tree(self):
"""dolphin-mmjr2 is not a release of dolphin-mmjr: mmjr2 is one word."""
from common import _owner_tokens
self.assertNotIn("dolphinmmjr", _owner_tokens({"source_profile": "dolphin-mmjr2"}))
self.assertIn("cxbxreloaded", _owner_tokens({"source_profile": "cxbx-reloaded-2023"}))
if __name__ == "__main__":
unittest.main()