mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-16 08:23:28 -05:00
feat: let a core check warn instead of reject
This commit is contained in:
1 parent
33ae27ebcf
commit
7cb4b926a3
5 files changed
+120
-52
No files matched your search
@@ -85,9 +85,7 @@ from validation import (
|
||||
agnostic_substitute,
|
||||
frontend_digest_matches,
|
||||
_build_validation_index,
|
||||
check_file_validation,
|
||||
filter_files_by_mode,
|
||||
find_validated_variant,
|
||||
)
|
||||
|
||||
yaml = require_yaml()
|
||||
@@ -1531,17 +1529,15 @@ def generate_emulator_pack(
|
||||
# The file verify --emulator credits is the one shipped:
|
||||
# a dump the core's own check rejects gives way to a held
|
||||
# one it accepts (azahar's otp.bin, dolphin's dsp_rom.bin).
|
||||
refused = check_file_validation(
|
||||
local_path, fe["name"], validation_index, bios_dir, {emu_name}
|
||||
better, disagreement = validated_choice(
|
||||
fe, local_path, db, validation_index, bios_dir, None,
|
||||
emulators={emu_name},
|
||||
)
|
||||
if refused:
|
||||
better = find_validated_variant(
|
||||
fe, db, local_path, validation_index, bios_dir,
|
||||
emulators={emu_name},
|
||||
)
|
||||
if not better:
|
||||
refusal = refusal or f"{fe['name']} -{refused[0]}"
|
||||
continue
|
||||
if disagreement:
|
||||
reason = disagreement.split(" says ", 1)[-1]
|
||||
refusal = refusal or f"{fe['name']} -{reason}"
|
||||
continue
|
||||
if better != local_path:
|
||||
chosen = (fe, better, None)
|
||||
break
|
||||
if status == "hash_mismatch":
|
||||
|
||||
+38
-15
@@ -95,6 +95,8 @@ def _entry_rule(emu_name: str, f: dict, checks: set[str]) -> dict:
|
||||
},
|
||||
"adler32_byteswap": bool(f.get("adler32_byteswap")),
|
||||
"crypto": {c for c in checks if c in _CRYPTO_CHECKS},
|
||||
# A failed check the code only warns about: the file still runs.
|
||||
"warn": f.get("on_mismatch") == "warn",
|
||||
}
|
||||
|
||||
|
||||
@@ -180,6 +182,9 @@ def _build_validation_index(profiles: dict) -> dict[str, dict]:
|
||||
}
|
||||
index[fname]["rules"].append(_entry_rule(emu_name, f, checks))
|
||||
index[fname]["emulators"].add(emu_name)
|
||||
if f.get("on_mismatch") == "warn":
|
||||
# Never a rejection, so not part of the merged rejection rules.
|
||||
continue
|
||||
index[fname]["checks"].update(checks)
|
||||
# Track non-reproducible crypto checks
|
||||
index[fname]["crypto_only"].update(c for c in checks if c in _CRYPTO_CHECKS)
|
||||
@@ -314,6 +319,7 @@ def check_file_validation(
|
||||
validation_index: dict[str, dict],
|
||||
bios_dir: str = "bios",
|
||||
emulators: set[str] | None = None,
|
||||
strict: bool = False,
|
||||
) -> tuple[str, list[str]] | None:
|
||||
"""Check emulator-level validation on a resolved file.
|
||||
|
||||
@@ -323,7 +329,9 @@ def check_file_validation(
|
||||
With ``emulators``, the cores that read the file's destination, each of
|
||||
them must accept it through one of its own entries for the name, the
|
||||
way each runs its own check. Without, the checks of every core naming
|
||||
the file are merged.
|
||||
the file are merged. A check declared `on_mismatch: warn` rejects
|
||||
nothing, since the core runs with the file; ``strict`` counts it, to
|
||||
prefer a file that passes it too.
|
||||
|
||||
Returns None if all checks pass or no validation applies.
|
||||
Returns (reason, emulators) tuple on failure, where *emulators*
|
||||
@@ -340,7 +348,8 @@ def check_file_validation(
|
||||
if not rules:
|
||||
continue
|
||||
reasons = [
|
||||
_rule_failure(rule, local_path, filename, bios_dir, hashes)
|
||||
None if rule["warn"] and not strict
|
||||
else _rule_failure(rule, local_path, filename, bios_dir, hashes)
|
||||
for rule in rules
|
||||
]
|
||||
if all(reasons):
|
||||
@@ -470,6 +479,7 @@ def find_validated_variant(
|
||||
bios_dir: str = "bios",
|
||||
platform_digest: str | None = None,
|
||||
emulators: set[str] | None = None,
|
||||
strict: bool = False,
|
||||
) -> str | None:
|
||||
"""A held file the emulator's own checks accept, in place of current_path.
|
||||
|
||||
@@ -529,7 +539,7 @@ def find_validated_variant(
|
||||
if accepted and str(entry.get(platform_digest, "")).lower() not in accepted:
|
||||
continue
|
||||
if check_file_validation(
|
||||
path, fname, validation_index, bios_dir, emulators
|
||||
path, fname, validation_index, bios_dir, emulators, strict
|
||||
) is None:
|
||||
return path
|
||||
return None
|
||||
@@ -668,6 +678,7 @@ def validated_choice(
|
||||
platform_digest: str | None,
|
||||
destination: str = "",
|
||||
owners: dict | None = None,
|
||||
emulators: set[str] | None = None,
|
||||
) -> tuple[str | None, str | None]:
|
||||
"""The file a platform destination ships, and the disagreement if any.
|
||||
|
||||
@@ -681,8 +692,8 @@ def validated_choice(
|
||||
return local_path, None
|
||||
name = file_entry.get("name", "")
|
||||
rules = validation_index.get(name)
|
||||
judges: set[str] | None = None
|
||||
if rules and owners and destination:
|
||||
judges: set[str] | None = emulators
|
||||
if rules and judges is None and owners and destination:
|
||||
owning = _owners_of(destination, name, owners)
|
||||
if not owning & set(rules["emulators"]):
|
||||
# No core that checks this name reads this destination: PC-98's
|
||||
@@ -691,19 +702,31 @@ def validated_choice(
|
||||
# The cores that read this destination judge it, each by its own
|
||||
# entries.
|
||||
judges = owning & set(rules["emulators"])
|
||||
check = check_file_validation(
|
||||
local_path, file_entry.get("name", ""), validation_index, bios_dir, judges
|
||||
)
|
||||
if not check:
|
||||
def check(path: str, strict: bool):
|
||||
return check_file_validation(path, name, validation_index, bios_dir, judges, strict)
|
||||
|
||||
def variant(strict: bool):
|
||||
return find_validated_variant(
|
||||
file_entry, db, local_path, validation_index, bios_dir,
|
||||
platform_digest=platform_digest, emulators=judges, strict=strict,
|
||||
)
|
||||
|
||||
if not check(local_path, True):
|
||||
return local_path, None
|
||||
better = find_validated_variant(
|
||||
file_entry, db, local_path, validation_index, bios_dir,
|
||||
platform_digest=platform_digest, emulators=judges,
|
||||
)
|
||||
# A held file every check passes, warn-level ones included, comes first;
|
||||
# then the file itself when only a warning fails (the core runs it);
|
||||
# then a held file the core at least runs.
|
||||
better = variant(True)
|
||||
if better:
|
||||
return better, None
|
||||
reason, emulators = check
|
||||
return local_path, f"{', '.join(emulators)} says {reason}"
|
||||
failed = check(local_path, False)
|
||||
if not failed:
|
||||
return local_path, None
|
||||
better = variant(False)
|
||||
if better:
|
||||
return better, None
|
||||
reason, failing = failed
|
||||
return local_path, f"{', '.join(failing)} says {reason}"
|
||||
|
||||
|
||||
def existence_discrepancy(file_entry: dict, local_path: str, platform_display: str) -> str:
|
||||
|
||||
+20
-25
@@ -81,7 +81,6 @@ from validation import (
|
||||
build_ground_truth,
|
||||
check_file_validation,
|
||||
filter_files_by_mode,
|
||||
find_validated_variant,
|
||||
outside_gap_scope,
|
||||
)
|
||||
|
||||
@@ -1585,31 +1584,27 @@ def verify_emulator(
|
||||
)
|
||||
else:
|
||||
# Apply emulator validation
|
||||
# Judged by this emulator's own entries, as it runs its check.
|
||||
check = check_file_validation(
|
||||
local_path, name, validation_index, emulators={emu_name}
|
||||
# Judged by this emulator's own entries, as it runs its check,
|
||||
# through the selection the emulator pack makes.
|
||||
chosen, disagreement = validated_choice(
|
||||
file_entry, local_path, db, validation_index, DEFAULT_BIOS_DIR,
|
||||
None, emulators={emu_name},
|
||||
)
|
||||
if check:
|
||||
reason, _emus = check
|
||||
better = find_validated_variant(
|
||||
file_entry, db, local_path, validation_index,
|
||||
emulators={emu_name},
|
||||
)
|
||||
if better:
|
||||
result = {
|
||||
"name": name,
|
||||
"status": Status.OK,
|
||||
"required": required,
|
||||
"path": better,
|
||||
}
|
||||
else:
|
||||
result = {
|
||||
"name": name,
|
||||
"status": Status.UNTESTED,
|
||||
"required": required,
|
||||
"path": local_path,
|
||||
"reason": reason,
|
||||
}
|
||||
if disagreement:
|
||||
result = {
|
||||
"name": name,
|
||||
"status": Status.UNTESTED,
|
||||
"required": required,
|
||||
"path": local_path,
|
||||
"reason": disagreement.split(" says ", 1)[-1],
|
||||
}
|
||||
elif chosen != local_path:
|
||||
result = {
|
||||
"name": name,
|
||||
"status": Status.OK,
|
||||
"required": required,
|
||||
"path": chosen,
|
||||
}
|
||||
elif resolve_status == "hash_mismatch":
|
||||
# Nothing in validation: caught it, but the name matched
|
||||
# while the bytes contradict the hash the profile
|
||||
|
||||
Reference in new issue
Block a user