mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-17 17:03:27 -05:00
fix: never prove a file by another emulator's tree
lrps2 names no hash for its GameIndex.yaml, and the only full-tail copy was ARMSX2's: it counted as path proof and replaced the file RetroArch pins on desktop targets, which have no ARMSX2. Upstream PCSX2 took ARMSX2's patches.zip by name the same way. A copy in another emulator's tree now proves nothing at any tail length, and LRPS2's own GameIndex comes from the tree the buildbot publishes.
This commit is contained in:
1 parent
b9a65cd622
commit
6810e8df9a
3 files changed
+100
-13
No files matched your search
+9
-9
@@ -19,6 +19,10 @@ bios_directory: "pcsx2/bios/"
|
||||
resources_directory: "pcsx2/resources/"
|
||||
|
||||
notes: |
|
||||
pcsx2/resources/GameIndex.yaml, the per-game patch, settings override and
|
||||
compatibility database, is the one the buildbot publishes in LRPS2.zip (the
|
||||
lrps2 data directory). An OSD warning is shown if it is missing; some games
|
||||
do not boot without it.
|
||||
Hard fork of PCSX2 (pre-Qt, 1.7-dev era) ported to libretro. x86_64 only.
|
||||
BIOS detection is filename-agnostic: scans pcsx2/bios/ for any file between 4-8 MB
|
||||
with a valid romdir structure (RESET + ROMVER entries). No hash validation.
|
||||
@@ -28,6 +32,11 @@ notes: |
|
||||
.info firmware_count=2 counts the bios folder and GameIndex.yaml.
|
||||
.info description mentions EROM.BIN but no EROM loading path exists in the code.
|
||||
|
||||
data_directories:
|
||||
- ref: lrps2
|
||||
destination: ""
|
||||
source_ref: "pcsx2/GameDatabase.cpp:49, pcsx2/GameDatabase.cpp:979"
|
||||
|
||||
files:
|
||||
- name: "<bios>.bin"
|
||||
path: "pcsx2/bios/<bios>.bin"
|
||||
@@ -85,15 +94,6 @@ files:
|
||||
Mechacon (disc drive controller) version as u32.
|
||||
Auto-created with default 0x00020603 if missing.
|
||||
|
||||
- name: "GameIndex.yaml"
|
||||
path: "pcsx2/resources/GameIndex.yaml"
|
||||
required: false
|
||||
description: "game compatibility database"
|
||||
source_ref: "pcsx2/GameDatabase.cpp:49, pcsx2/GameDatabase.cpp:979"
|
||||
note: >
|
||||
YAML database of per-game patches, settings overrides, and compatibility fixes.
|
||||
OSD warning shown if missing. Some games may not boot or have issues without it.
|
||||
|
||||
- name: "cheats_ws.zip"
|
||||
path: "pcsx2/resources/cheats_ws.zip"
|
||||
required: false
|
||||
|
||||
+14
-4
@@ -644,8 +644,8 @@ def _rank_tail_candidates(
|
||||
) -> list[str]:
|
||||
"""Order the files a destination tail designates, the likeliest first.
|
||||
|
||||
A shortened tail found only in another emulator's tree is that
|
||||
emulator's asset, not evidence about this entry. A full tail claimed
|
||||
A tail found in another emulator's tree is that emulator's asset, not
|
||||
evidence about this entry, whatever its length. A full tail claimed
|
||||
twice goes to the file whose path carries the least on top of the
|
||||
destination, then to the owner's own copy (super3's Games.xml was served
|
||||
to Supermodel-Dojo by index order alone), then to any copy outside
|
||||
@@ -655,8 +655,11 @@ def _rank_tail_candidates(
|
||||
def path_of(sha1: str) -> str:
|
||||
return files_db.get(sha1, {}).get("path", "")
|
||||
|
||||
if start:
|
||||
candidates = [h for h in candidates if not _foreign_tree(path_of(h), owners)]
|
||||
# Another emulator's tree answers that emulator's entry, at any tail
|
||||
# length: lrps2 names no hash for pcsx2/resources/GameIndex.yaml, and the
|
||||
# only full-tail copy was ARMSX2's, which then counted as path proof and
|
||||
# replaced the GameIndex RetroArch pins on every desktop target.
|
||||
candidates = [h for h in candidates if not _foreign_tree(path_of(h), owners)]
|
||||
if len(candidates) < 2:
|
||||
return candidates
|
||||
depth = len(tail.split("/"))
|
||||
@@ -1040,6 +1043,13 @@ def resolve_local_file(
|
||||
if file_entry.get("members"):
|
||||
candidates = _holding_members(candidates, file_entry["members"])
|
||||
candidates = _by_affinity(candidates, file_entry, dest_hint)
|
||||
# A copy outside another emulator's tree comes first: the
|
||||
# affinity read pcsx2 in bios/Other/armsx2/pcsx2/ and served
|
||||
# upstream PCSX2 the patches.zip of ARMSX2.
|
||||
owners = _owner_tokens(file_entry)
|
||||
candidates = [
|
||||
p for p in candidates if not _foreign_tree(p, owners)
|
||||
] or candidates
|
||||
primary = [p for p in candidates if "/.variants/" not in p]
|
||||
if primary or candidates:
|
||||
chosen = primary[0] if primary else candidates[0]
|
||||
|
||||
@@ -2287,6 +2287,83 @@ class ARegionDroppedExtraBlocksNothing(unittest.TestCase):
|
||||
self.assertEqual(report({"foo.rom"}), {})
|
||||
|
||||
|
||||
class AnotherEmulatorsTreeProvesNothing(unittest.TestCase):
|
||||
"""lrps2 names no hash for pcsx2/resources/GameIndex.yaml; the only
|
||||
full-tail copy was ARMSX2's, which counted as path proof and replaced
|
||||
the GameIndex RetroArch pins on desktop targets, where ARMSX2 does not
|
||||
exist. Upstream PCSX2 took ARMSX2's patches.zip by name the same way."""
|
||||
|
||||
def _db(self, root, files):
|
||||
import hashlib
|
||||
|
||||
db = {"files": {}, "indexes": {"by_name": {}, "by_md5": {}, "by_crc32": {},
|
||||
"by_path_suffix": {}}}
|
||||
for relative, payload in files.items():
|
||||
path = root / relative
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_bytes(payload)
|
||||
sha1 = hashlib.sha1(payload).hexdigest()
|
||||
db["files"][sha1] = {"path": relative, "name": path.name, "sha1": sha1,
|
||||
"size": len(payload)}
|
||||
db["indexes"]["by_name"].setdefault(path.name, []).append(sha1)
|
||||
parts = relative.split("/")
|
||||
for start in range(1, len(parts) - 1):
|
||||
db["indexes"]["by_path_suffix"].setdefault(
|
||||
"/".join(parts[start:]), []).append(sha1)
|
||||
return db
|
||||
|
||||
def test_neither_the_full_tail_nor_the_name_lands_in_a_foreign_tree(self):
|
||||
from scripts.common import resolve_local_file
|
||||
|
||||
with tempfile.TemporaryDirectory(dir=TMP_ROOT) as directory:
|
||||
root = Path(directory)
|
||||
# The collection's layout, read relative to its root.
|
||||
previous = os.getcwd()
|
||||
os.chdir(root)
|
||||
self.addCleanup(os.chdir, previous)
|
||||
db = self._db(root, {
|
||||
"bios/Other/armsx2/pcsx2/resources/GameIndex.yaml": b"fork",
|
||||
"bios/Other/armsx2/pcsx2/resources/patches.zip": b"fork patches",
|
||||
"bios/Sony/PlayStation 2/patches.zip": b"upstream patches",
|
||||
})
|
||||
index, status = resolve_local_file(
|
||||
{"name": "GameIndex.yaml", "path": "pcsx2/resources/GameIndex.yaml",
|
||||
"source_profile": "lrps2"},
|
||||
db, dest_hint="pcsx2/resources/GameIndex.yaml",
|
||||
)
|
||||
# Held only in the fork's tree, the file answers by name and
|
||||
# proves nothing about this entry.
|
||||
self.assertEqual(status, "name_exact")
|
||||
patches, _status = resolve_local_file(
|
||||
{"name": "patches.zip", "path": "resources/patches.zip",
|
||||
"source_profile": "pcsx2"},
|
||||
db, dest_hint="resources/patches.zip",
|
||||
)
|
||||
self.assertTrue(patches.endswith("PlayStation 2/patches.zip"))
|
||||
|
||||
def test_no_desktop_retroarch_pack_serves_armsx2s_tree(self):
|
||||
from scripts import slots
|
||||
from scripts.common import (
|
||||
load_data_dir_registry,
|
||||
load_database,
|
||||
load_emulator_profiles,
|
||||
load_platform_config,
|
||||
load_target_config,
|
||||
)
|
||||
|
||||
if not (ROOT / "database.json").exists():
|
||||
self.skipTest("database.json is not generated")
|
||||
db = load_database(str(ROOT / "database.json"))
|
||||
config = load_platform_config("retroarch", str(ROOT / "platforms"))
|
||||
profiles = load_emulator_profiles(str(ROOT / "emulators"))
|
||||
cores = set(load_target_config("retroarch", "x86_64", str(ROOT / "platforms")))
|
||||
overrides = slots.pack_overrides(
|
||||
config, profiles, db, None, load_data_dir_registry(str(ROOT / "platforms")),
|
||||
target_cores=cores,
|
||||
)
|
||||
self.assertFalse([d for d, p in overrides.items() if "/armsx2/" in p])
|
||||
|
||||
|
||||
class TheDatabaseCacheIsWrittenWhole(unittest.TestCase):
|
||||
"""A crash while serializing left a truncated db_cache.json behind, and
|
||||
the next run rehashed the whole collection from scratch."""
|
||||
|
||||
Reference in new issue
Block a user