mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 13:33:24 -05:00
fix: never serve a homonym for an absent file
This commit is contained in:
1 parent
1cc2d48f2f
commit
a090e64336
2 files changed
+60
-1
No files matched your search
+10
-1
@@ -642,6 +642,7 @@ def resolve_local_file(
|
|||||||
# 2b. Path suffix lookup is useful for same-named regional files, but it
|
# 2b. Path suffix lookup is useful for same-named regional files, but it
|
||||||
# is identity evidence only when no content hash was declared. A stale
|
# is identity evidence only when no content hash was declared. A stale
|
||||||
# or incorrect destination can therefore never mask a hash mismatch.
|
# or incorrect destination can therefore never mask a hash mismatch.
|
||||||
|
own_file_absent = False
|
||||||
if dest_hint and by_path_suffix:
|
if dest_hint and by_path_suffix:
|
||||||
# A destination is written from the emulator's point of view
|
# A destination is written from the emulator's point of view
|
||||||
# ("pcsx2/resources/GameIndex.yaml") and the index from the repo's
|
# ("pcsx2/resources/GameIndex.yaml") and the index from the repo's
|
||||||
@@ -665,6 +666,14 @@ def resolve_local_file(
|
|||||||
candidates = by_path_suffix.get(tail, [])
|
candidates = by_path_suffix.get(tail, [])
|
||||||
if start and len(candidates) > 1:
|
if start and len(candidates) > 1:
|
||||||
continue
|
continue
|
||||||
|
# The index names the file this destination designates. Not on
|
||||||
|
# disk, it is a release asset the checkout does not hold, and no
|
||||||
|
# other file of that name is it.
|
||||||
|
if not start and candidates and not any(
|
||||||
|
os.path.exists(files_db.get(h, {}).get("path", ""))
|
||||||
|
for h in candidates
|
||||||
|
):
|
||||||
|
own_file_absent = True
|
||||||
if len(candidates) > 1:
|
if len(candidates) > 1:
|
||||||
depth = len(tail.split("/"))
|
depth = len(tail.split("/"))
|
||||||
candidates = sorted(
|
candidates = sorted(
|
||||||
@@ -699,7 +708,7 @@ def resolve_local_file(
|
|||||||
# an FPseNG font, an openMSX one and a 3DO ROM. Content still decides: the
|
# an FPseNG font, an openMSX one and a 3DO ROM. Content still decides: the
|
||||||
# hash and path steps above run first, so collecting the real bytes makes
|
# hash and path steps above run first, so collecting the real bytes makes
|
||||||
# the entry resolve.
|
# the entry resolve.
|
||||||
unsourceable = bool(file_entry.get("unsourceable"))
|
unsourceable = bool(file_entry.get("unsourceable")) or own_file_absent
|
||||||
|
|
||||||
if not has_strong_hash and not unsourceable:
|
if not has_strong_hash and not unsourceable:
|
||||||
candidates = []
|
candidates = []
|
||||||
|
|||||||
@@ -81,6 +81,56 @@ class HomonymRule(unittest.TestCase):
|
|||||||
self.assertEqual(homonyms(claims), [])
|
self.assertEqual(homonyms(claims), [])
|
||||||
|
|
||||||
|
|
||||||
|
class AbsentFileIsNotReplacedByAHomonym(unittest.TestCase):
|
||||||
|
"""The database names the file a destination designates. When that file
|
||||||
|
is a release asset the checkout does not hold, the name step answered
|
||||||
|
with whatever else carried the name: Enemy Territory's `etmain/pak0.pk3`
|
||||||
|
resolved to the Quake III demo pak on a clone without the large files."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
import hashlib
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import generate_db
|
||||||
|
|
||||||
|
self._tmp = tempfile.TemporaryDirectory()
|
||||||
|
root = Path(self._tmp.name)
|
||||||
|
files = {}
|
||||||
|
for relative, payload in (
|
||||||
|
("bios/ET/etmain/pak0.pk3", b"enemy territory"),
|
||||||
|
("bios/Q3/demoq3/pak0.pk3", b"quake iii demo"),
|
||||||
|
):
|
||||||
|
target = root / relative
|
||||||
|
target.parent.mkdir(parents=True)
|
||||||
|
target.write_bytes(payload)
|
||||||
|
sha1 = hashlib.sha1(payload).hexdigest()
|
||||||
|
files[sha1] = {
|
||||||
|
"path": str(target), "name": "pak0.pk3", "size": len(payload),
|
||||||
|
"sha1": sha1, "md5": hashlib.md5(payload).hexdigest(),
|
||||||
|
"sha256": hashlib.sha256(payload).hexdigest(), "crc32": "0",
|
||||||
|
}
|
||||||
|
indexes = generate_db.build_indexes(
|
||||||
|
{s: {**r, "path": r["path"][len(str(root)) + 1:]} for s, r in files.items()},
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
self.db = {"files": files, "indexes": indexes}
|
||||||
|
self.own = root / "bios/ET/etmain/pak0.pk3"
|
||||||
|
self.entry = {"name": "pak0.pk3", "path": "etmain/pak0.pk3"}
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self._tmp.cleanup()
|
||||||
|
|
||||||
|
def _resolve(self):
|
||||||
|
return resolve_local_file(self.entry, self.db, {}, dest_hint="etmain/pak0.pk3")
|
||||||
|
|
||||||
|
def test_present_it_resolves_by_its_path(self):
|
||||||
|
self.assertEqual(self._resolve(), (str(self.own), "path_exact"))
|
||||||
|
|
||||||
|
def test_absent_it_is_not_found_rather_than_another_game(self):
|
||||||
|
self.own.unlink()
|
||||||
|
self.assertEqual(self._resolve(), (None, "not_found"))
|
||||||
|
|
||||||
|
|
||||||
class CollectionCarriesNoGameDataHomonym(unittest.TestCase):
|
class CollectionCarriesNoGameDataHomonym(unittest.TestCase):
|
||||||
def test_the_profiles_resolve_no_game_data_to_another_game(self):
|
def test_the_profiles_resolve_no_game_data_to_another_game(self):
|
||||||
database = REPO_ROOT / "database.json"
|
database = REPO_ROOT / "database.json"
|
||||||
|
|||||||
Reference in new issue
Block a user