fix: name a missing folder in the folder check

This commit is contained in:
Abdessamad Derraz committed 2026-11-06 14:44:31 +01:00
1 parent 2d1c889d41
commit 3b137cd266
3 files changed
+35 -10

No files matched your search

+9 -9
View File
@@ -1,22 +1,19 @@
"""Check a BIOS folder against one platform's list, from the published data only:
python check_platform_folder.py batocera path/to/bios. Exit 1 on a file wrong or missing."""
"""Usage: python check_platform_folder.py batocera path/to/bios. Exit 1 on a file wrong or missing."""
from __future__ import annotations
import hashlib
import json
import sys
import urllib.error
import urllib.request
import zipfile
from pathlib import Path
API = "https://abdess.github.io/retrobios/api/v1/platforms/"
DIGESTS = {"md5": "md5", "sha1": "sha1"} # without one (existence), presence passes
def accepts(entry: dict, path: Path, mode: str) -> bool:
"""Whether the platform's own check passes the file at path."""
digest, raw = DIGESTS.get(mode), entry.get(mode) or ""
digest, raw = mode if mode in ("md5", "sha1") else None, entry.get(mode) or "" # existence: no digest
values = [v.strip().lower() for v in (raw if isinstance(raw, list) else str(raw).split(",")) if v.strip()]
if digest is None or not values:
return path.is_file() # nothing to compare: the platform checks presence
@@ -29,7 +26,7 @@ def accepts(entry: dict, path: Path, mode: str) -> bool:
actual = hashlib.new(digest, path.read_bytes()).hexdigest()
if entry.get("zip_digest") != "composite" and any(actual.startswith(v) for v in values):
return True # a truncated md5 (Batocera) compares by its prefix
if digest == DIGESTS["md5"] and path.suffix.lower() == ".zip": # Recalbox: members in name order
if digest == "md5" and path.suffix.lower() == ".zip": # Recalbox: members in name order
with zipfile.ZipFile(path) as archive:
names = sorted(name for name in archive.namelist() if not name.endswith("/"))
return hashlib.md5(b"".join(map(archive.read, names))).hexdigest() in values
@@ -42,8 +39,7 @@ def check(platform: str, root: Path, api: str = API) -> list[tuple[str, str]]:
"""(destination, ok | wrong | missing) per entry. With no destination (EmuDeck), any file with its hash passes."""
with urllib.request.urlopen(f"{api}{platform}.json") as response:
contract = json.load(response)["items"][0]["contract"]
mode, results = contract["verification_mode"], []
loose = [path for path in root.iterdir() if path.is_file()] if root.is_dir() else []
mode, results, loose = contract["verification_mode"], [], [p for p in root.iterdir() if p.is_file()]
for system_id, system in contract["systems"].items():
listed = [e for e in system.get("files") or [] if not e.get("destination")]
for entry in (e for e in system.get("files") or [] if e.get("destination")):
@@ -57,12 +53,16 @@ def check(platform: str, root: Path, api: str = API) -> list[tuple[str, str]]:
if __name__ == "__main__":
if len(sys.argv) != 3:
sys.exit(__doc__)
try:
found = check(sys.argv[1], Path(sys.argv[2]))
except urllib.error.HTTPError as error: # a 404: no platform has that name
except urllib.request.HTTPError as error: # a 404: no platform has that name
with urllib.request.urlopen(API.replace("platforms/", "catalog.json")) as response:
known = sorted(i["url"][10:-5] for i in json.load(response)["items"] if i["url"].startswith("manifests/"))
sys.exit(f"unknown platform: {sys.argv[1]}. Known: {', '.join(known)}" if error.code == 404 else error)
except OSError as error: # no such folder, or no network (URLError)
sys.exit(f"error: {error}")
for verdict in ("ok", "wrong", "missing"):
names = sorted({dest for dest, seen in found if seen == verdict})
print(f"{verdict}: {len(names)}" + "".join(f"\n {name}" for name in names if verdict != "ok"))