mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-06 01:53:56 -06:00
fix: gap report reads the launcher layer
cross_reference --platform listed core files the platform's launcher already settles, as Batocera's DuckStation scph1002a.bin while the PAL slot holds scph5502.bin. It now hands the launcher layer the same entries verify does, and counts what it settles as set aside.
This commit is contained in:
1 parent
9808936975
commit
8f7dbb1b31
4 files changed
+119
-20
No files matched your search
@@ -48,6 +48,7 @@ from common import (
|
||||
select_emulator_profiles,
|
||||
)
|
||||
from hashing import parse_hash_list
|
||||
from launchers import LauncherLayer, declared_destinations, held_record
|
||||
from validation import (
|
||||
case_folded_slots,
|
||||
declaration_settles,
|
||||
@@ -692,6 +693,7 @@ SET_ASIDE = {
|
||||
"other_versions": "other versions of a slot",
|
||||
"not_read": "not read on this platform",
|
||||
"outside_scope": "outside the pack",
|
||||
"launcher": "filled by the platform's launcher",
|
||||
}
|
||||
|
||||
|
||||
@@ -923,6 +925,19 @@ def _cross_reference_profile(
|
||||
}
|
||||
if save_root:
|
||||
entry["root"] = "save"
|
||||
elif index.get("launcher_candidates") is not None:
|
||||
# What verify hands the launcher layer for the same entry.
|
||||
probe = {
|
||||
**f,
|
||||
"profile": emu_name,
|
||||
"emulator": profile.get("emulator", emu_name),
|
||||
"path": effective_path,
|
||||
"in_repo": in_repo,
|
||||
"bundled": entry["bundled"],
|
||||
}
|
||||
index["launcher_candidates"].append(
|
||||
(emu_name, is_standalone, f, probe, entry)
|
||||
)
|
||||
gaps.append(entry)
|
||||
|
||||
for ag in sorted(archive_gaps.values(), key=lambda e: e["name"]):
|
||||
@@ -934,12 +949,7 @@ def _cross_reference_profile(
|
||||
"systems": systems,
|
||||
"total_files": len(emu_files),
|
||||
"platform_covered": len(covered),
|
||||
"gaps": len(gaps),
|
||||
"gap_in_repo": sum(1 for g in gaps if g["in_repo"]),
|
||||
"gap_missing": sum(1 for g in gaps if g["source"] == "missing"),
|
||||
"gap_bios": sum(1 for g in gaps if g["source"] == "bios"),
|
||||
"gap_data": sum(1 for g in gaps if g["source"] == "data"),
|
||||
"gap_large_file": sum(1 for g in gaps if g["source"] == "large_file"),
|
||||
**_gap_counts(gaps),
|
||||
"gap_details": gaps,
|
||||
"unsourceable": unsourceable_list,
|
||||
# Entries, not rows: an archive's members are one gap row.
|
||||
@@ -950,6 +960,61 @@ def _cross_reference_profile(
|
||||
}
|
||||
|
||||
|
||||
def _gap_counts(gaps: list[dict]) -> dict[str, int]:
|
||||
"""The per-source tallies of a profile's gap rows."""
|
||||
return {
|
||||
"gaps": len(gaps),
|
||||
"gap_in_repo": sum(1 for g in gaps if g["in_repo"]),
|
||||
"gap_missing": sum(1 for g in gaps if g["source"] == "missing"),
|
||||
"gap_bios": sum(1 for g in gaps if g["source"] == "bios"),
|
||||
"gap_data": sum(1 for g in gaps if g["source"] == "data"),
|
||||
"gap_large_file": sum(1 for g in gaps if g["source"] == "large_file"),
|
||||
}
|
||||
|
||||
|
||||
def _settle_launcher_places(
|
||||
report: dict,
|
||||
candidates: list[tuple[str, bool, dict, dict, dict]],
|
||||
layer: LauncherLayer,
|
||||
db: dict,
|
||||
) -> None:
|
||||
"""Apply the platform's launcher places as find_undeclared_files does.
|
||||
|
||||
Batocera's DuckStation generator fills the PAL slot with scph5502.bin,
|
||||
yet the report listed duckstation's scph1002a.bin as a file the pack
|
||||
carries, which neither the pack nor the manifest does.
|
||||
"""
|
||||
added, settled = layer.settle(
|
||||
[(emu, standalone, f, probe) for emu, standalone, f, probe, _ in candidates],
|
||||
lambda probe: held_record(probe, db),
|
||||
)
|
||||
for emu, _standalone, _f, probe, gap in candidates:
|
||||
if id(probe) not in settled:
|
||||
continue
|
||||
data = report[emu]
|
||||
data["gap_details"] = [g for g in data["gap_details"] if g is not gap]
|
||||
data["undeclared_files"] -= 1
|
||||
data["set_aside"]["launcher"] += 1
|
||||
for entry in added:
|
||||
data = report[entry["profile"]]
|
||||
data["gap_details"].append({
|
||||
"name": entry["name"],
|
||||
"path": entry["path"],
|
||||
"required": entry.get("required", False),
|
||||
"bundled": False,
|
||||
"note": "",
|
||||
"source_ref": "",
|
||||
"in_platform": False,
|
||||
"in_repo": True,
|
||||
"source": "bios",
|
||||
"identity": entry.get("sha1") or "",
|
||||
"launcher": entry["launcher"],
|
||||
"launcher_of": entry["launcher_of"],
|
||||
})
|
||||
for data in report.values():
|
||||
data.update(_gap_counts(data["gap_details"]))
|
||||
|
||||
|
||||
def cross_reference(
|
||||
profiles: dict[str, dict],
|
||||
declared: dict[str, set[str]],
|
||||
@@ -960,6 +1025,7 @@ def cross_reference(
|
||||
standalone_cores: set[str] | None = None,
|
||||
folded_slots: frozenset[str] = frozenset(),
|
||||
platform: str = "",
|
||||
launcher_layer: LauncherLayer | None = None,
|
||||
) -> dict:
|
||||
"""Compare emulator profiles against platform declarations.
|
||||
|
||||
@@ -998,12 +1064,15 @@ def cross_reference(
|
||||
"all_declared": all_declared,
|
||||
"folded_slots": folded_slots,
|
||||
"bios_dir": db.get("bios_dir"),
|
||||
"launcher_candidates": [] if launcher_layer else None,
|
||||
}
|
||||
for emu_name, profile in profiles.items():
|
||||
_cross_reference_profile(
|
||||
emu_name, profile, declared, report, index, standalone_cores,
|
||||
platform,
|
||||
)
|
||||
if launcher_layer:
|
||||
_settle_launcher_places(report, index["launcher_candidates"], launcher_layer, db)
|
||||
|
||||
return report
|
||||
|
||||
@@ -1195,6 +1264,10 @@ def main() -> None:
|
||||
standalone_cores=standalone_cores,
|
||||
folded_slots=folded_declared_slots(args.platforms_dir, selected, db),
|
||||
platform=config.get("_key", args.platform) if args.platform else "",
|
||||
# What the platform's launchers open, as verify and the builder read it.
|
||||
launcher_layer=LauncherLayer(
|
||||
config, profiles, relevant, db, declared_destinations(config)
|
||||
) if args.platform else None,
|
||||
)
|
||||
|
||||
if args.json:
|
||||
|
||||
+12
-1
@@ -20,7 +20,7 @@ import re
|
||||
from collections.abc import Callable, Iterable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from common import declared_root, name_match_size_ok, sanitize_pack_path
|
||||
from common import declared_root, name_match_size_ok, resolve_local_file, sanitize_pack_path
|
||||
|
||||
# The kinds whose names say which file the launcher opens. A link of a named
|
||||
# file is one too: ROCKNIX links /storage/roms/bios/nds_bios_arm9.bin into
|
||||
@@ -330,6 +330,17 @@ def standalone_root(
|
||||
return next(iter(folders)) if len(folders) == 1 else None
|
||||
|
||||
|
||||
def held_record(report: dict, db: dict) -> dict | None:
|
||||
"""The database record of the file the collection holds for a report entry."""
|
||||
local, status = resolve_local_file(report, db, dest_hint=report.get("path") or "")
|
||||
if local is None or status in ("not_found", "hash_mismatch"):
|
||||
return None
|
||||
for record in db.get("files", {}).values():
|
||||
if record.get("path") == local:
|
||||
return record
|
||||
return None
|
||||
|
||||
|
||||
def declared_destinations(config: dict) -> set[str]:
|
||||
"""Each destination the platform declares, relative to the core file directory.
|
||||
|
||||
|
||||
+2
-13
@@ -84,7 +84,7 @@ from common import (
|
||||
|
||||
yaml = require_yaml()
|
||||
from exporter.candidates import BIOS, EntryCategories
|
||||
from launchers import LauncherLayer, declared_destinations
|
||||
from launchers import LauncherLayer, declared_destinations, held_record
|
||||
from nativemode import (
|
||||
SIZE_AND_ANY_HASH,
|
||||
digest_algorithm,
|
||||
@@ -489,17 +489,6 @@ def _identity_of(entry: dict) -> dict:
|
||||
}
|
||||
|
||||
|
||||
def _held_record(report: dict, db: dict) -> dict | None:
|
||||
"""The database record of the file the collection holds for a report entry."""
|
||||
local, status = resolve_local_file(report, db, dest_hint=report.get("path") or "")
|
||||
if local is None or status in ("not_found", "hash_mismatch"):
|
||||
return None
|
||||
for record in db.get("files", {}).values():
|
||||
if record.get("path") == local:
|
||||
return record
|
||||
return None
|
||||
|
||||
|
||||
def find_undeclared_files(
|
||||
config: dict,
|
||||
emulators_dir: str,
|
||||
@@ -778,7 +767,7 @@ def find_undeclared_files(
|
||||
|
||||
if launcher_layer:
|
||||
added, settled = launcher_layer.settle(
|
||||
launcher_candidates, lambda report: _held_record(report, db)
|
||||
launcher_candidates, lambda report: held_record(report, db)
|
||||
)
|
||||
undeclared = [u for u in undeclared if id(u) not in settled]
|
||||
undeclared.extend(added)
|
||||
|
||||
Reference in new issue
Block a user