mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-14 05:53:47 -06:00
fix: take an unchecked version as a match in packs
Raze lists three sized BLOOD.RFF versions and a fourth it takes without a check, the shareware RFF the collection holds. The Batocera pack printed two DISCREPANCY lines for it that verify never showed. A slot with an unchecked sibling now accepts any copy for that core, in the validation rules and in _matches_an_alternative. When every version refuses a copy, the message names all accepted values instead of the first.
This commit is contained in:
1 parent
3d0ee19bcb
commit
0d21566183
3 files changed
+84
-1
No files matched your search
+29
-1
@@ -8,6 +8,7 @@ truth data for reporting.
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import zipfile
|
||||
from collections.abc import Callable, Iterator, Mapping, Sequence
|
||||
|
||||
@@ -161,6 +162,11 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
Raises ValueError if two profiles declare conflicting values.
|
||||
"""
|
||||
index: dict[str, dict] = {}
|
||||
# A slot where one version is taken without any check (Raze's "BLOOD:
|
||||
# Unknown Version", which holds the shareware RFF) accepts every copy for
|
||||
# that core: its validated siblings are alternatives, not requirements.
|
||||
unchecked: set[tuple[str, str, str]] = set()
|
||||
checked: set[tuple[str, str, str]] = set()
|
||||
for emu_name, profile in profiles.items():
|
||||
if profile.get("type") in ("launcher", "alias"):
|
||||
continue
|
||||
@@ -169,8 +175,11 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
if not fname:
|
||||
continue
|
||||
checks = _parse_validation(f.get("validation"))
|
||||
slot = (fname, emu_name, f.get("path") or fname)
|
||||
if not checks:
|
||||
unchecked.add(slot)
|
||||
continue
|
||||
checked.add(slot)
|
||||
if fname not in index:
|
||||
index[fname] = {
|
||||
"checks": set(),
|
||||
@@ -276,6 +285,8 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
existing["source_ref"] = pe_entry["source_ref"]
|
||||
else:
|
||||
pe[emu_name] = pe_entry
|
||||
for fname, emu_name, _path in sorted(checked & unchecked):
|
||||
index[fname]["rules"].append(_entry_rule(emu_name, {}, set()))
|
||||
# Convert sets to sorted tuples/lists for determinism
|
||||
for v in index.values():
|
||||
v["checks"] = sorted(v["checks"])
|
||||
@@ -324,6 +335,23 @@ def _emulators_for_check(
|
||||
return sorted(result)
|
||||
|
||||
|
||||
_REASON = re.compile(r"^(\w+ mismatch): got (\S+), accepted \[(.*)\]$")
|
||||
|
||||
|
||||
def _merged_reason(reasons: list[str]) -> str:
|
||||
"""One reason for every entry of a core that turned the copy away.
|
||||
|
||||
Raze lists three BLOOD.RFF sizes and the message named the first one
|
||||
alone. Reasons of one kind are merged into a single accepted list.
|
||||
"""
|
||||
parsed = [_REASON.match(reason) for reason in reasons]
|
||||
if all(parsed) and len({(m.group(1), m.group(2)) for m in parsed}) == 1:
|
||||
accepted = sorted({v for m in parsed for v in m.group(3).split(",") if v},
|
||||
key=lambda v: (len(v), v))
|
||||
return f"{parsed[0].group(1)}: got {parsed[0].group(2)}, accepted [{','.join(accepted)}]"
|
||||
return reasons[0]
|
||||
|
||||
|
||||
def check_file_validation(
|
||||
local_path: str,
|
||||
filename: str,
|
||||
@@ -363,7 +391,7 @@ def check_file_validation(
|
||||
for rule in rules
|
||||
]
|
||||
if all(reasons):
|
||||
failures[emu] = reasons[0]
|
||||
failures[emu] = _merged_reason(reasons)
|
||||
if not failures:
|
||||
return None
|
||||
first = sorted(failures)[0]
|
||||
|
||||
Reference in new issue
Block a user