mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-13 12:22:33 -05:00
fix: cross-reference checks data/ directories for false positives
_find_in_repo and _name_in_index now scan data/ in addition to bios/ via database.json. Eliminates 129 false positives from game data migrated to data/ (OpenTyrian, ScummVM, SDLPAL, Cave Story, Syobon Action). True missing: 782 -> 653.
This commit is contained in:
@@ -50,7 +50,21 @@ def load_platform_files(platforms_dir: str) -> tuple[dict[str, set[str]], dict[s
|
||||
return declared, platform_data_dirs
|
||||
|
||||
|
||||
def _find_in_repo(fname: str, by_name: dict[str, list], by_name_lower: dict[str, str]) -> bool:
|
||||
def _build_data_dir_index(data_root: str = "data") -> set[str]:
|
||||
"""Build a set of filenames available in data/ directories."""
|
||||
names: set[str] = set()
|
||||
root_path = Path(data_root)
|
||||
if not root_path.is_dir():
|
||||
return names
|
||||
for fpath in root_path.rglob("*"):
|
||||
if fpath.is_file() and not fpath.name.startswith("."):
|
||||
names.add(fpath.name)
|
||||
names.add(fpath.name.lower())
|
||||
return names
|
||||
|
||||
|
||||
def _find_in_repo(fname: str, by_name: dict[str, list], by_name_lower: dict[str, str],
|
||||
data_names: set[str] | None = None) -> bool:
|
||||
if fname in by_name:
|
||||
return True
|
||||
basename = fname.rsplit("/", 1)[-1] if "/" in fname else None
|
||||
@@ -63,6 +77,11 @@ def _find_in_repo(fname: str, by_name: dict[str, list], by_name_lower: dict[str,
|
||||
key = basename.lower()
|
||||
if key in by_name_lower:
|
||||
return True
|
||||
if data_names:
|
||||
if fname in data_names or key in data_names:
|
||||
return True
|
||||
if basename and (basename in data_names or basename.lower() in data_names):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -71,12 +90,14 @@ def cross_reference(
|
||||
declared: dict[str, set[str]],
|
||||
db: dict,
|
||||
platform_data_dirs: dict[str, set[str]] | None = None,
|
||||
data_names: set[str] | None = None,
|
||||
) -> dict:
|
||||
"""Compare emulator profiles against platform declarations.
|
||||
|
||||
Returns a report with gaps (files emulators need but platforms don't list)
|
||||
and coverage stats. Files covered by matching data_directories between
|
||||
emulator profile and platform config are not reported as gaps.
|
||||
Checks both bios/ (via database) and data/ (via data_names index).
|
||||
"""
|
||||
platform_data_dirs = platform_data_dirs or {}
|
||||
by_name = db.get("indexes", {}).get("by_name", {})
|
||||
@@ -106,7 +127,7 @@ def cross_reference(
|
||||
continue
|
||||
|
||||
in_platform = fname in platform_names
|
||||
in_repo = _find_in_repo(fname, by_name, by_name_lower)
|
||||
in_repo = _find_in_repo(fname, by_name, by_name_lower, data_names)
|
||||
|
||||
entry = {
|
||||
"name": fname,
|
||||
@@ -205,7 +226,8 @@ def main():
|
||||
|
||||
declared, plat_data_dirs = load_platform_files(args.platforms_dir)
|
||||
db = load_database(args.db)
|
||||
report = cross_reference(profiles, declared, db, plat_data_dirs)
|
||||
data_names = _build_data_dir_index()
|
||||
report = cross_reference(profiles, declared, db, plat_data_dirs, data_names)
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(report, indent=2))
|
||||
|
||||
@@ -246,8 +246,9 @@ def _build_expected(file_entry: dict, checks: list[str]) -> dict:
|
||||
expected["adler32"] = adler_val
|
||||
return expected
|
||||
|
||||
def _name_in_index(name: str, by_name: dict, by_path_suffix: dict | None = None) -> bool:
|
||||
"""Check if a name is resolvable in the database indexes."""
|
||||
def _name_in_index(name: str, by_name: dict, by_path_suffix: dict | None = None,
|
||||
data_names: set[str] | None = None) -> bool:
|
||||
"""Check if a name is resolvable in the database indexes or data directories."""
|
||||
if name in by_name:
|
||||
return True
|
||||
basename = name.rsplit("/", 1)[-1]
|
||||
@@ -255,6 +256,11 @@ def _name_in_index(name: str, by_name: dict, by_path_suffix: dict | None = None)
|
||||
return True
|
||||
if by_path_suffix and name in by_path_suffix:
|
||||
return True
|
||||
if data_names:
|
||||
if name in data_names or name.lower() in data_names:
|
||||
return True
|
||||
if basename != name and (basename in data_names or basename.lower() in data_names):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@@ -264,6 +270,7 @@ def find_undeclared_files(
|
||||
db: dict,
|
||||
emu_profiles: dict | None = None,
|
||||
target_cores: set[str] | None = None,
|
||||
data_names: set[str] | None = None,
|
||||
) -> list[dict]:
|
||||
"""Find files needed by cores but not declared in platform config."""
|
||||
# Collect all filenames declared by this platform
|
||||
@@ -333,7 +340,7 @@ def find_undeclared_files(
|
||||
# Archived files are grouped by archive
|
||||
if archive:
|
||||
if archive not in archive_entries:
|
||||
in_repo = _name_in_index(archive, by_name, by_path_suffix)
|
||||
in_repo = _name_in_index(archive, by_name, by_path_suffix, data_names)
|
||||
archive_entries[archive] = {
|
||||
"emulator": profile.get("emulator", emu_name),
|
||||
"name": archive,
|
||||
@@ -364,10 +371,10 @@ def find_undeclared_files(
|
||||
dest = f.get("path") or fname
|
||||
|
||||
# Resolution: try name, then path basename, then path_suffix
|
||||
in_repo = _name_in_index(fname, by_name, by_path_suffix)
|
||||
in_repo = _name_in_index(fname, by_name, by_path_suffix, data_names)
|
||||
if not in_repo and dest != fname:
|
||||
path_base = dest.rsplit("/", 1)[-1]
|
||||
in_repo = _name_in_index(path_base, by_name, by_path_suffix)
|
||||
in_repo = _name_in_index(path_base, by_name, by_path_suffix, data_names)
|
||||
|
||||
checks = _parse_validation(f.get("validation"))
|
||||
undeclared.append({
|
||||
@@ -587,7 +594,10 @@ def verify_platform(
|
||||
status_counts[s] = status_counts.get(s, 0) + 1
|
||||
|
||||
# Cross-reference undeclared files
|
||||
undeclared = find_undeclared_files(config, emulators_dir, db, emu_profiles, target_cores=target_cores)
|
||||
from cross_reference import _build_data_dir_index
|
||||
data_names = _build_data_dir_index()
|
||||
undeclared = find_undeclared_files(config, emulators_dir, db, emu_profiles,
|
||||
target_cores=target_cores, data_names=data_names)
|
||||
exclusions = find_exclusion_notes(config, emulators_dir, emu_profiles, target_cores=target_cores)
|
||||
|
||||
# Ground truth coverage
|
||||
|
||||
Reference in New Issue
Block a user