mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
fix: keep pack order outside contested paths
Ranking contested core claims sorted the whole gap report, which reordered every manifest. Only the claims on one contested path move now, grouped where the first of them stood, and two spellings of a path are one group where the filesystem folds case (RetroBat's 64DD_IPL_DEV.bin). An entry without a destination (EmuDeck's system:md5 whitelist) no longer counts as a pack path in verify, and step 5 prints one status for counts and paths together. A full offline run compared all 12 archives and 930 emulator packs path by path, every one equal.
This commit is contained in:
1 parent
aa36ec544d
commit
4ba935374e
4 files changed
+51
-11
No files matched your search
+29
-9
@@ -869,10 +869,11 @@ def _collect_emulator_extras(
|
||||
# BIOS root before Solarus, which pins its own by sha1, and fbalpha2012's
|
||||
# hashless hiscore.dat took RetroDECK's over mame2015's sha1. Profile
|
||||
# order decides only between claims of equal proof.
|
||||
rank = _ClaimRanks(undeclared, placement, db)
|
||||
undeclared = sorted(
|
||||
undeclared, key=lambda u: (-rank.of_entry(u), not _names_content(u))
|
||||
undeclared = sorted(undeclared, key=lambda u: not _names_content(u))
|
||||
rank = _ClaimRanks(
|
||||
undeclared, placement, db, bool(config.get("case_insensitive_fs", False))
|
||||
)
|
||||
undeclared = rank.ordered(undeclared)
|
||||
extras = []
|
||||
seen_dests: set[str] = set(seen)
|
||||
# Destination -> the extra that took it, to record later claimants on.
|
||||
@@ -1056,8 +1057,12 @@ class _ClaimRanks:
|
||||
where two claims meet: a destination one core asks for has no contest.
|
||||
"""
|
||||
|
||||
def __init__(self, undeclared: list[dict], placement: ExtraPlacement, db: dict) -> None:
|
||||
def __init__(
|
||||
self, undeclared: list[dict], placement: ExtraPlacement, db: dict, fold: bool,
|
||||
) -> None:
|
||||
self._db = db
|
||||
# Two spellings of one path are one file where the filesystem folds case.
|
||||
self._key = (lambda dest: dest.lower()) if fold else (lambda dest: dest)
|
||||
self._placed: dict[int, tuple[str, str] | None] = {}
|
||||
counts: dict[str, int] = {}
|
||||
for u in undeclared:
|
||||
@@ -1067,14 +1072,13 @@ class _ClaimRanks:
|
||||
)
|
||||
self._placed[id(u)] = placed
|
||||
if placed is not None:
|
||||
counts[placed[1]] = counts.get(placed[1], 0) + 1 + len(
|
||||
u.get("other_claims", [])
|
||||
)
|
||||
key = self._key(placed[1])
|
||||
counts[key] = counts.get(key, 0) + 1 + len(u.get("other_claims", []))
|
||||
self._contested = {dest for dest, n in counts.items() if n > 1}
|
||||
self._cache: dict[tuple, int] = {}
|
||||
|
||||
def of_extra(self, extra: dict, full_dest: str) -> int:
|
||||
if full_dest not in self._contested:
|
||||
if self._key(full_dest) not in self._contested:
|
||||
return 0
|
||||
key = (extra.get("source_profile"), extra.get("source_name"),
|
||||
extra.get("source_path"), full_dest)
|
||||
@@ -1093,9 +1097,25 @@ class _ClaimRanks:
|
||||
)
|
||||
return self._cache[key]
|
||||
|
||||
def ordered(self, undeclared: list[dict]) -> list[dict]:
|
||||
"""The entries in their order, the claims on one contested path
|
||||
reordered among themselves by proof. Nothing else moves, so the
|
||||
pack and the manifest keep their order."""
|
||||
first: dict[str, int] = {}
|
||||
keys: list[tuple[int, int, int]] = []
|
||||
for position, u in enumerate(undeclared):
|
||||
placed = self._placed.get(id(u))
|
||||
if placed is None or self._key(placed[1]) not in self._contested:
|
||||
keys.append((position, 0, position))
|
||||
continue
|
||||
group = first.setdefault(self._key(placed[1]), position)
|
||||
keys.append((group, -self.of_entry(u), position))
|
||||
order = sorted(range(len(undeclared)), key=keys.__getitem__)
|
||||
return [undeclared[i] for i in order]
|
||||
|
||||
def of_entry(self, u: dict) -> int:
|
||||
placed = self._placed.get(id(u))
|
||||
if placed is None or placed[1] not in self._contested:
|
||||
if placed is None or self._key(placed[1]) not in self._contested:
|
||||
return 0
|
||||
name = u.get("archive") or u["name"]
|
||||
return max(
|
||||
|
||||
@@ -919,6 +919,7 @@ def main() -> None:
|
||||
# Counts can agree while the paths differ, both ways at once.
|
||||
ok = check_pack_destinations(destinations_file, pack_output) and ok
|
||||
ok = check_emulator_packs() and ok
|
||||
print(f"--- 5/8 consistency check, counts and paths: {'OK' if ok else 'FAILED'} ---")
|
||||
results["consistency"] = ok
|
||||
all_ok = all_ok and ok
|
||||
else:
|
||||
|
||||
+7
-2
@@ -904,8 +904,10 @@ def _builder_placement(
|
||||
The builder walks the systems in name order and skips a path that a
|
||||
written file blocks as a directory, or the reverse: RetroArch declares
|
||||
SGB1.sfc and SGB1.sfc/program.rom, and only the first is in the pack.
|
||||
Returns (path -> local copy written there, path -> copy or None for each
|
||||
slot kept, a user_provided or external one included).
|
||||
An entry without a destination (EmuDeck's system:md5 whitelist) is
|
||||
judged but takes no path. Returns (path -> local copy written there,
|
||||
path -> copy or None for each slot kept, a user_provided or external one
|
||||
included).
|
||||
"""
|
||||
from packpaths import _has_path_conflict, _register_path
|
||||
|
||||
@@ -915,6 +917,9 @@ def _builder_placement(
|
||||
folded: set[str] = set()
|
||||
parents: set[str] = set()
|
||||
for _sys_id, full, local in sorted(packed_order, key=lambda item: item[0]):
|
||||
# EmuDeck's system:md5 entries name no file: the builder writes none.
|
||||
if not full or full.endswith("/"):
|
||||
continue
|
||||
if (
|
||||
full in occupied
|
||||
or (case_insensitive and full.lower() in folded)
|
||||
|
||||
@@ -108,6 +108,20 @@ class AUserProvidedSlot(_Fixture):
|
||||
self.assertEqual(report["pack_destinations"], [])
|
||||
|
||||
|
||||
class AnEntryWithoutAFileTakesNoPath(unittest.TestCase):
|
||||
"""EmuDeck's system:md5 entries name no file. verify credited the bare
|
||||
base destination as a pack path, and the comparison failed on ''."""
|
||||
|
||||
def test_it_is_left_out(self):
|
||||
from verify import _builder_placement
|
||||
|
||||
shipped, occupied = _builder_placement(
|
||||
[("s", "bios/", None), ("s", "", "x"), ("s", "bios/a.bin", "bios/a.bin")], False
|
||||
)
|
||||
self.assertEqual(shipped, {"bios/a.bin": "bios/a.bin"})
|
||||
self.assertEqual(set(occupied), {"bios/a.bin"})
|
||||
|
||||
|
||||
class ThePipelineComparesPaths(unittest.TestCase):
|
||||
"""Equal counts, other paths: the comparison fails and names both sides."""
|
||||
|
||||
|
||||
Reference in new issue
Block a user