fix: scope slot labels to system and region

slots reads content_alternatives too, so a content-found label is settled only by a dump of its own system and region slot.
This commit is contained in:
Abdessamad Derraz committed 2026-11-06 08:16:08 +01:00
1 parent 807ffa0ca9
commit 6695efeebe
2 files changed
+19 -20

No files matched your search

+7 -18
View File
@@ -44,7 +44,7 @@ from common import (
)
from packresolve import preferred_entries
from validation import (
opens_by_name,
content_alternatives,
outside_gap_scope,
read_from_save_dir,
with_archive_members,
@@ -91,7 +91,7 @@ class Claim:
local_path: str | None = None
status: str = ""
# A core that identifies its firmware by content reads no file by this
# name: any dump it accepts for the system answers for it.
# name: any dump it takes for the same system and region answers for it.
accepts: tuple[dict, ...] = ()
@property
@@ -218,12 +218,6 @@ def profile_claims(
zip_contents, data_dir_registry,
)
)
labels = [
f for f in profile.get("files") or []
if isinstance(f, dict)
and not opens_by_name(f, profile, is_standalone)
and _lists_hashes(f)
]
for entry in profile.get("files") or []:
if not isinstance(entry, dict):
continue
@@ -274,13 +268,7 @@ def profile_claims(
)
if status == "name_exact" and _size_the_code_reads(entry, local):
status = SIZE_EXACT
accepts: tuple[dict, ...] = ()
if not opens_by_name(entry, profile, is_standalone):
systems = set(entry_system_ids(entry, profile))
accepts = tuple(
f for f in labels
if not systems or systems & set(entry_system_ids(f, profile))
)
accepts = tuple(content_alternatives(entry, profile))
claims.append(
Claim(
origin="profile",
@@ -769,8 +757,8 @@ def _satisfies(profile: Claim, platform: Claim, db: dict) -> bool:
hash list accepts the profile's file, or when the profile's accepts the
platform's. A contradiction needs both lists to reject the other side.
A core found by content (found_by: content) reads no file by the
destination's name, so any dump it accepts for the system settles the
slot: DuckStation takes Batocera's scph1001.bin v2.0, which its profile
destination's name, so any dump it takes for the same system and region
settles the slot: DuckStation takes Batocera's scph1001.bin v2.0, which its profile
labels scph1001_v20.bin.
"""
if profile.local_path == platform.local_path:
@@ -791,7 +779,8 @@ def _satisfies(profile: Claim, platform: Claim, db: dict) -> bool:
):
return True
if platform.local_path and any(
_accepted_by_all(platform.local_path, [label], db) for label in profile.accepts
_lists_hashes(label) and _accepted_by_all(platform.local_path, [label], db)
for label in profile.accepts
):
return True
return bool(
+12 -2
View File
@@ -116,8 +116,9 @@ class TestConflicts(unittest.TestCase):
scph1001.bin entry is a label. Batocera ships the v2.0 dump there,
which the profile accepts under scph1001_v20.bin: no conflict."""
files = [
{"name": "IPL.bin", "path": "GC/JAP/IPL.bin", "md5": "n" * 32},
{"name": "IPL_usa.bin", "md5": "m" * 32},
{"name": "IPL.bin", "path": "GC/JAP/IPL.bin", "md5": "n" * 32,
"region": ["japan"]},
{"name": "IPL_alt.bin", "md5": "m" * 32, "region": ["japan"]},
]
by_name = slots.find_conflicts(
self._config("m" * 32), {"dolphin": {"files": files}}, REGIONS_DB
@@ -129,6 +130,15 @@ class TestConflicts(unittest.TestCase):
REGIONS_DB,
)
self.assertEqual(by_content, [])
# Another region is another slot: openMSX finds each ROM by sha1 too,
# and one machine's ROM never stands for another's.
files[1]["region"] = ["north-america"]
other_slot = slots.find_conflicts(
self._config("m" * 32),
{"dolphin": {"found_by": "content", "files": files}},
REGIONS_DB,
)
self.assertEqual(len(other_slot), 1)
def test_wrong_region_under_a_region_slot_is_reported(self):
conflicts = slots.find_conflicts(