mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-17 06:12:33 -05:00
refactor: quality audit fixes, honest verification reporting
- batocera_scraper: fix OrderedDict parsing for ast.literal_eval - auto_fetch: fix TypeError when sha1/md5 is None - verify: filter non-ZIP files for zipped_file entries (F2) - verify: distinguish ZIP read errors from hash mismatches (F5) - generate_pack: track seen_destinations with source hash (F7) Batocera ep64/ep128.zip now correctly reported as MISSING instead of false UNTESTED (resolved to .rom instead of .zip)
This commit is contained in:
@@ -345,8 +345,8 @@ def generate_issue_body(missing: list[dict], platform: str) -> str:
|
|||||||
]
|
]
|
||||||
|
|
||||||
for entry in missing:
|
for entry in missing:
|
||||||
sha1 = entry.get("sha1", "N/A")
|
sha1 = entry.get("sha1") or "N/A"
|
||||||
md5 = entry.get("md5", "N/A")
|
md5 = entry.get("md5") or "N/A"
|
||||||
lines.append(f"| `{entry['name']}` | {entry['system']} | `{sha1[:12]}...` | `{md5[:12]}...` |")
|
lines.append(f"| `{entry['name']}` | {entry['system']} | `{sha1[:12]}...` | `{md5[:12]}...` |")
|
||||||
|
|
||||||
lines.extend([
|
lines.extend([
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ def generate_pack(
|
|||||||
missing_files = []
|
missing_files = []
|
||||||
untested_files = []
|
untested_files = []
|
||||||
user_provided = []
|
user_provided = []
|
||||||
seen_destinations = set()
|
seen_destinations = {}
|
||||||
|
|
||||||
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||||
for sys_id, system in sorted(config.get("systems", {}).items()):
|
for sys_id, system in sorted(config.get("systems", {}).items()):
|
||||||
@@ -279,7 +279,7 @@ def generate_pack(
|
|||||||
dedup_key = full_dest
|
dedup_key = full_dest
|
||||||
if dedup_key in seen_destinations:
|
if dedup_key in seen_destinations:
|
||||||
continue
|
continue
|
||||||
seen_destinations.add(dedup_key)
|
seen_destinations[dedup_key] = file_entry.get("sha1") or file_entry.get("md5") or ""
|
||||||
|
|
||||||
storage = file_entry.get("storage", "embedded")
|
storage = file_entry.get("storage", "embedded")
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,9 @@ class Scraper(BaseScraper):
|
|||||||
|
|
||||||
clean_dict_str = "\n".join(lines)
|
clean_dict_str = "\n".join(lines)
|
||||||
|
|
||||||
clean_dict_str = clean_dict_str.replace("OrderedDict(", "dict(")
|
# OrderedDict({...}) -> just the inner dict literal
|
||||||
|
clean_dict_str = re.sub(r'OrderedDict\(\s*\{', '{', clean_dict_str)
|
||||||
|
clean_dict_str = re.sub(r'\}\s*\)', '}', clean_dict_str)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return ast.literal_eval(clean_dict_str)
|
return ast.literal_eval(clean_dict_str)
|
||||||
|
|||||||
@@ -120,13 +120,16 @@ def resolve_to_local_path(file_entry: dict, db: dict) -> str | None:
|
|||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
candidates.append((path, entry.get("md5", "")))
|
candidates.append((path, entry.get("md5", "")))
|
||||||
if candidates:
|
if candidates:
|
||||||
|
if has_zipped_file:
|
||||||
|
candidates = [(p, m) for p, m in candidates if p.endswith(".zip")]
|
||||||
if md5 and not has_zipped_file:
|
if md5 and not has_zipped_file:
|
||||||
md5_lower = md5.lower()
|
md5_lower = md5.lower()
|
||||||
for path, db_md5 in candidates:
|
for path, db_md5 in candidates:
|
||||||
if db_md5.lower() == md5_lower:
|
if db_md5.lower() == md5_lower:
|
||||||
return path
|
return path
|
||||||
primary = [p for p, _ in candidates if "/.variants/" not in p]
|
if candidates:
|
||||||
return primary[0] if primary else candidates[0][0]
|
primary = [p for p, _ in candidates if "/.variants/" not in p]
|
||||||
|
return primary[0] if primary else candidates[0][0]
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -156,17 +159,21 @@ def verify_entry_md5(file_entry: dict, local_path: str | None) -> dict:
|
|||||||
|
|
||||||
if zipped_file:
|
if zipped_file:
|
||||||
found_in_zip = False
|
found_in_zip = False
|
||||||
|
had_error = False
|
||||||
for md5_candidate in md5_list or [""]:
|
for md5_candidate in md5_list or [""]:
|
||||||
result = check_inside_zip(local_path, zipped_file, md5_candidate)
|
result = check_inside_zip(local_path, zipped_file, md5_candidate)
|
||||||
if result == Status.OK:
|
if result == Status.OK:
|
||||||
return {"name": name, "status": Status.OK, "path": local_path}
|
return {"name": name, "status": Status.OK, "path": local_path}
|
||||||
if result != "not_in_zip":
|
if result == "error":
|
||||||
|
had_error = True
|
||||||
|
elif result != "not_in_zip":
|
||||||
found_in_zip = True
|
found_in_zip = True
|
||||||
reason = (
|
if had_error and not found_in_zip:
|
||||||
f"{zipped_file} not found inside ZIP"
|
reason = f"{local_path} is not a valid ZIP or read error"
|
||||||
if not found_in_zip
|
elif not found_in_zip:
|
||||||
else f"{zipped_file} MD5 mismatch inside ZIP"
|
reason = f"{zipped_file} not found inside ZIP"
|
||||||
)
|
else:
|
||||||
|
reason = f"{zipped_file} MD5 mismatch inside ZIP"
|
||||||
return {
|
return {
|
||||||
"name": name, "status": Status.UNTESTED, "path": local_path,
|
"name": name, "status": Status.UNTESTED, "path": local_path,
|
||||||
"reason": reason,
|
"reason": reason,
|
||||||
|
|||||||
Reference in New Issue
Block a user