mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-18 23:02:33 -05:00
fix: align status terminology with Batocera source code
Batocera uses exactly 2 statuses (batocera-systems:967-969): - MISSING: file not found on disk - UNTESTED: file present but hash not confirmed Removed the wrong_hash/untested split — both are UNTESTED per Batocera's design (file accepted by emulator, just not guaranteed correct). Fixed duplicate count bug from rename. Reason detail (MD5 mismatch vs inner file not found) preserved in the message. Verified against Batocera source: checkBios() lines 1062-1091, checkInsideZip() lines 978-1009, BiosStatus class lines 967-969.
This commit is contained in:
@@ -291,7 +291,7 @@ def generate_pack(
|
|||||||
missing_files = []
|
missing_files = []
|
||||||
user_provided = []
|
user_provided = []
|
||||||
seen_destinations = set()
|
seen_destinations = set()
|
||||||
# Per-file status: worst status wins (missing > wrong_hash > ok)
|
# Per-file status: worst status wins (missing > untested > ok)
|
||||||
file_status: dict[str, str] = {}
|
file_status: dict[str, str] = {}
|
||||||
file_reasons: dict[str, str] = {}
|
file_reasons: dict[str, str] = {}
|
||||||
|
|
||||||
@@ -365,15 +365,20 @@ def generate_pack(
|
|||||||
from verify import check_inside_zip
|
from verify import check_inside_zip
|
||||||
inner_md5 = file_entry.get("md5", "")
|
inner_md5 = file_entry.get("md5", "")
|
||||||
inner_result = check_inside_zip(local_path, zf_name, inner_md5)
|
inner_result = check_inside_zip(local_path, zf_name, inner_md5)
|
||||||
if inner_result != "ok":
|
if inner_result == "ok":
|
||||||
file_status[dedup_key] = "wrong_hash"
|
|
||||||
reason = f"{zf_name} hash mismatch inside ZIP"
|
|
||||||
file_reasons[dedup_key] = reason
|
|
||||||
else:
|
|
||||||
file_status.setdefault(dedup_key, "ok")
|
file_status.setdefault(dedup_key, "ok")
|
||||||
|
elif inner_result == "not_in_zip":
|
||||||
|
file_status[dedup_key] = "untested"
|
||||||
|
file_reasons[dedup_key] = f"{zf_name} not found inside ZIP"
|
||||||
|
elif inner_result == "error":
|
||||||
|
file_status[dedup_key] = "untested"
|
||||||
|
file_reasons[dedup_key] = f"cannot read ZIP"
|
||||||
|
else:
|
||||||
|
file_status[dedup_key] = "untested"
|
||||||
|
file_reasons[dedup_key] = f"{zf_name} MD5 mismatch inside ZIP"
|
||||||
else:
|
else:
|
||||||
file_status[dedup_key] = "wrong_hash"
|
file_status[dedup_key] = "untested"
|
||||||
file_reasons[dedup_key] = "container hash mismatch"
|
file_reasons[dedup_key] = "hash mismatch"
|
||||||
else:
|
else:
|
||||||
file_status.setdefault(dedup_key, "ok")
|
file_status.setdefault(dedup_key, "ok")
|
||||||
|
|
||||||
@@ -440,22 +445,24 @@ def generate_pack(
|
|||||||
total_files += 1
|
total_files += 1
|
||||||
|
|
||||||
files_ok = sum(1 for s in file_status.values() if s == "ok")
|
files_ok = sum(1 for s in file_status.values() if s == "ok")
|
||||||
files_wrong = sum(1 for s in file_status.values() if s == "wrong_hash")
|
files_untested = sum(1 for s in file_status.values() if s == "untested")
|
||||||
files_miss = sum(1 for s in file_status.values() if s == "missing")
|
files_miss = sum(1 for s in file_status.values() if s == "missing")
|
||||||
total_checked = len(file_status)
|
total_checked = len(file_status)
|
||||||
|
|
||||||
parts = [f"{files_ok}/{total_checked} files OK"]
|
parts = [f"{files_ok}/{total_checked} files OK"]
|
||||||
if files_wrong:
|
if files_untested:
|
||||||
parts.append(f"{files_wrong} wrong hash")
|
parts.append(f"{files_untested} untested")
|
||||||
if files_miss:
|
if files_miss:
|
||||||
parts.append(f"{files_miss} missing")
|
parts.append(f"{files_miss} missing")
|
||||||
extras_msg = f", {extra_count} extras" if extra_count else ""
|
extras_msg = f", {extra_count} extras" if extra_count else ""
|
||||||
print(f" {zip_path}: {total_files} files packed{extras_msg}, {', '.join(parts)} [{verification_mode}]")
|
print(f" {zip_path}: {total_files} files packed{extras_msg}, {', '.join(parts)} [{verification_mode}]")
|
||||||
|
|
||||||
for key, reason in file_reasons.items():
|
for key, reason in sorted(file_reasons.items()):
|
||||||
print(f" WRONG HASH: {key} — {reason}")
|
status = file_status.get(key, "")
|
||||||
|
label = "UNTESTED"
|
||||||
|
print(f" {label}: {key} — {reason}")
|
||||||
for name in missing_files:
|
for name in missing_files:
|
||||||
print(f" MISSING: {name}")
|
print(f" MISSING: {name}")
|
||||||
return zip_path
|
return zip_path
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ DEFAULT_PLATFORMS_DIR = "platforms"
|
|||||||
|
|
||||||
|
|
||||||
class Status:
|
class Status:
|
||||||
OK = "ok" # Verified - hash matches (or existence for existence-only platforms)
|
OK = "ok" # hash matches (or exists for existence-only)
|
||||||
UNTESTED = "untested" # File present but hash mismatch (Batocera term)
|
UNTESTED = "untested" # file present, hash not confirmed (Batocera terminology)
|
||||||
MISSING = "missing" # File not found at all
|
MISSING = "missing" # file not found at all
|
||||||
|
|
||||||
|
|
||||||
def check_inside_zip(container: str, file_name: str, expected_md5: str) -> str:
|
def check_inside_zip(container: str, file_name: str, expected_md5: str) -> str:
|
||||||
@@ -114,15 +114,16 @@ def verify_entry_md5(
|
|||||||
elif result != "not_in_zip":
|
elif result != "not_in_zip":
|
||||||
found_in_zip = True
|
found_in_zip = True
|
||||||
if had_error and not found_in_zip:
|
if had_error and not found_in_zip:
|
||||||
reason = f"{local_path} is not a valid ZIP or read error"
|
# Can't read the ZIP at all
|
||||||
elif not found_in_zip:
|
return {"name": name, "status": Status.UNTESTED, "path": local_path,
|
||||||
reason = f"{zipped_file} not found inside ZIP"
|
"reason": f"{local_path} is not a valid ZIP or read error"}
|
||||||
else:
|
if not found_in_zip:
|
||||||
reason = f"{zipped_file} MD5 mismatch inside ZIP"
|
# Inner file not in the ZIP — can't verify
|
||||||
return {
|
return {"name": name, "status": Status.UNTESTED, "path": local_path,
|
||||||
"name": name, "status": Status.UNTESTED, "path": local_path,
|
"reason": f"{zipped_file} not found inside ZIP"}
|
||||||
"reason": reason,
|
# Inner file found but MD5 doesn't match — wrong version
|
||||||
}
|
return {"name": name, "status": Status.UNTESTED, "path": local_path,
|
||||||
|
"reason": f"{zipped_file} MD5 mismatch inside ZIP"}
|
||||||
|
|
||||||
if not md5_list:
|
if not md5_list:
|
||||||
return {"name": name, "status": Status.OK, "path": local_path}
|
return {"name": name, "status": Status.OK, "path": local_path}
|
||||||
@@ -154,7 +155,7 @@ def verify_entry_md5(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
"name": name, "status": Status.UNTESTED, "path": local_path,
|
"name": name, "status": Status.UNTESTED, "path": local_path,
|
||||||
"expected_md5": md5_list[0] if md5_list else "", "actual_md5": actual_md5,
|
"reason": f"expected {md5_list[0][:12]}… got {actual_md5[:12]}…",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -220,17 +221,15 @@ def verify_platform(config: dict, db: dict) -> dict:
|
|||||||
dest = file_entry.get("destination", file_entry.get("name", ""))
|
dest = file_entry.get("destination", file_entry.get("name", ""))
|
||||||
if not dest:
|
if not dest:
|
||||||
dest = f"{sys_id}/{file_entry.get('name', '')}"
|
dest = f"{sys_id}/{file_entry.get('name', '')}"
|
||||||
|
# Worst status wins: missing > untested > ok
|
||||||
cur = result["status"]
|
cur = result["status"]
|
||||||
prev = file_status.get(dest)
|
prev = file_status.get(dest)
|
||||||
if prev is None:
|
severity = {Status.OK: 0, Status.UNTESTED: 1, Status.MISSING: 2}
|
||||||
|
if prev is None or severity.get(cur, 0) > severity.get(prev, 0):
|
||||||
file_status[dest] = cur
|
file_status[dest] = cur
|
||||||
elif cur == Status.MISSING:
|
|
||||||
file_status[dest] = Status.MISSING
|
|
||||||
elif cur == Status.UNTESTED and prev != Status.MISSING:
|
|
||||||
file_status[dest] = Status.UNTESTED
|
|
||||||
|
|
||||||
files_ok = sum(1 for s in file_status.values() if s == Status.OK)
|
files_ok = sum(1 for s in file_status.values() if s == Status.OK)
|
||||||
files_mismatch = sum(1 for s in file_status.values() if s == Status.UNTESTED)
|
files_untested = sum(1 for s in file_status.values() if s == Status.UNTESTED)
|
||||||
files_missing = sum(1 for s in file_status.values() if s == Status.MISSING)
|
files_missing = sum(1 for s in file_status.values() if s == Status.MISSING)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -238,7 +237,7 @@ def verify_platform(config: dict, db: dict) -> dict:
|
|||||||
"verification_mode": mode,
|
"verification_mode": mode,
|
||||||
"total_files": len(file_status),
|
"total_files": len(file_status),
|
||||||
"files_ok": files_ok,
|
"files_ok": files_ok,
|
||||||
"files_mismatch": files_mismatch,
|
"files_untested": files_untested,
|
||||||
"files_missing": files_missing,
|
"files_missing": files_missing,
|
||||||
"details": results,
|
"details": results,
|
||||||
}
|
}
|
||||||
@@ -303,13 +302,13 @@ def main():
|
|||||||
mode = result["verification_mode"]
|
mode = result["verification_mode"]
|
||||||
total = result["total_files"]
|
total = result["total_files"]
|
||||||
ok = result["files_ok"]
|
ok = result["files_ok"]
|
||||||
mismatch = result["files_mismatch"]
|
untested = result["files_untested"]
|
||||||
miss = result["files_missing"]
|
miss = result["files_missing"]
|
||||||
label = " / ".join(group)
|
label = " / ".join(group)
|
||||||
|
|
||||||
parts = [f"{ok}/{total} files OK"]
|
parts = [f"{ok}/{total} files OK"]
|
||||||
if mismatch:
|
if untested:
|
||||||
parts.append(f"{mismatch} wrong hash")
|
parts.append(f"{untested} untested")
|
||||||
if miss:
|
if miss:
|
||||||
parts.append(f"{miss} missing")
|
parts.append(f"{miss} missing")
|
||||||
print(f"{label}: {', '.join(parts)} [{mode}]")
|
print(f"{label}: {', '.join(parts)} [{mode}]")
|
||||||
@@ -317,9 +316,7 @@ def main():
|
|||||||
for d in result["details"]:
|
for d in result["details"]:
|
||||||
if d["status"] == Status.UNTESTED:
|
if d["status"] == Status.UNTESTED:
|
||||||
reason = d.get("reason", "")
|
reason = d.get("reason", "")
|
||||||
if not reason and "expected_md5" in d:
|
print(f" UNTESTED: {d['system']}/{d['name']} — {reason}")
|
||||||
reason = f"expected {d['expected_md5'][:12]}… got {d['actual_md5'][:12]}…"
|
|
||||||
print(f" WRONG HASH: {d['system']}/{d['name']} — {reason}")
|
|
||||||
|
|
||||||
for d in result["details"]:
|
for d in result["details"]:
|
||||||
if d["status"] == Status.MISSING:
|
if d["status"] == Status.MISSING:
|
||||||
|
|||||||
Reference in New Issue
Block a user