mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 12:19:13 -05:00
fix: scope gap report entries by platform
cross_reference --platform read bundled from the profile alone and never read unread_on. It now calls validation.installed_with_emulator and unread_on with the platform key, as verify does, and a file installed with its emulator is reported as bundled whether held or not.
This commit is contained in:
1 parent
0242dc77ee
commit
3545c1b333
2 files changed
+83
-13
No files matched your search
+28
-13
@@ -45,7 +45,13 @@ from common import (
|
||||
select_emulator_profiles,
|
||||
)
|
||||
from hashing import parse_hash_list
|
||||
from validation import case_folded_slots, declaration_settles, outside_gap_scope
|
||||
from validation import (
|
||||
case_folded_slots,
|
||||
declaration_settles,
|
||||
installed_with_emulator,
|
||||
outside_gap_scope,
|
||||
unread_on,
|
||||
)
|
||||
|
||||
yaml = require_yaml()
|
||||
|
||||
@@ -606,9 +612,15 @@ def _cross_reference_profile(
|
||||
report: dict,
|
||||
index: dict,
|
||||
standalone_cores: set[str] | None = None,
|
||||
platform: str = "",
|
||||
) -> None:
|
||||
"""Compare one emulator profile against what the platforms declare.
|
||||
|
||||
*platform* is the platform key under --platform, empty for the whole
|
||||
tree. It decides, through the functions verify reads, which entries the
|
||||
platform's launcher never opens and which ones its emulator package
|
||||
already installs.
|
||||
|
||||
Split out of cross_reference, where it was a 200-line loop body that
|
||||
carried the whole function's branching: every file is resolved by name,
|
||||
by path, by hash and by archive membership before it can be called a
|
||||
@@ -667,7 +679,7 @@ def _cross_reference_profile(
|
||||
if len(layouts) > 1:
|
||||
# One file read at one path by both builds counts once.
|
||||
seen_key = (effective_path.casefold(), seen_key)
|
||||
if not fname or seen_key in seen_files:
|
||||
if not fname or seen_key in seen_files or unread_on(f, platform):
|
||||
continue
|
||||
|
||||
# Collect unsourceable files separately (documented, not a gap)
|
||||
@@ -760,7 +772,7 @@ def _cross_reference_profile(
|
||||
"name": fname,
|
||||
"path": effective_path,
|
||||
"required": f.get("required", False),
|
||||
"bundled": bool(f.get("bundled")),
|
||||
"bundled": installed_with_emulator(f, platform),
|
||||
"note": f.get("note", ""),
|
||||
"source_ref": f.get("source_ref", ""),
|
||||
"in_platform": False,
|
||||
@@ -800,6 +812,7 @@ def cross_reference(
|
||||
all_declared: dict[str, list[tuple[int | None, str]]] | None = None,
|
||||
standalone_cores: set[str] | None = None,
|
||||
folded_slots: frozenset[str] = frozenset(),
|
||||
platform: str = "",
|
||||
) -> dict:
|
||||
"""Compare emulator profiles against platform declarations.
|
||||
|
||||
@@ -841,7 +854,8 @@ def cross_reference(
|
||||
}
|
||||
for emu_name, profile in profiles.items():
|
||||
_cross_reference_profile(
|
||||
emu_name, profile, declared, report, index, standalone_cores
|
||||
emu_name, profile, declared, report, index, standalone_cores,
|
||||
platform,
|
||||
)
|
||||
|
||||
return report
|
||||
@@ -872,14 +886,14 @@ def print_report(
|
||||
if gaps == 0 and not show_clean:
|
||||
continue
|
||||
|
||||
# Counted once, for the heading and the total alike: a file bundled
|
||||
# with its emulator is not one to source.
|
||||
emulator_bundled = sum(
|
||||
1 for g in data["gap_details"]
|
||||
if g.get("bundled") and g.get("source") == "missing"
|
||||
)
|
||||
# Counted once, for the heading and the total alike: a file installed
|
||||
# with its emulator is neither one to source nor one the pack brings,
|
||||
# held or not (validation.deliverable leaves it out of every pack).
|
||||
bundled_gaps = [g for g in data["gap_details"] if g.get("bundled")]
|
||||
emulator_bundled = len(bundled_gaps)
|
||||
counts = {key: data.get(f"gap_{key}", 0) for key in totals}
|
||||
counts["missing"] -= emulator_bundled
|
||||
for g in bundled_gaps:
|
||||
counts[g.get("source", "missing")] -= 1
|
||||
counts["bundled"] = emulator_bundled
|
||||
parts = [f"{count} {key}" for key, count in counts.items() if count]
|
||||
status = ", ".join(parts) if parts else "OK"
|
||||
@@ -896,7 +910,7 @@ def print_report(
|
||||
for g in data["gap_details"]:
|
||||
req = "*" if g["required"] else " "
|
||||
src = g.get("source", "missing").upper()
|
||||
if g.get("bundled") and g.get("source") == "missing":
|
||||
if g.get("bundled"):
|
||||
src = "BUNDLED"
|
||||
# One line per file: a note spanning lines fell to column 0
|
||||
# between entries and read as an emulator heading.
|
||||
@@ -920,7 +934,7 @@ def print_report(
|
||||
f"large_file: {totals['large_file']})")
|
||||
print(f" {totals['missing']} missing (need to be sourced)")
|
||||
if bundled:
|
||||
print(f" {bundled} bundled with their emulator, not collected")
|
||||
print(f" {bundled} bundled with their emulator, not packed")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
@@ -1023,6 +1037,7 @@ def main() -> None:
|
||||
all_declared=declared_names(args.platforms_dir, selected, db),
|
||||
standalone_cores=standalone_cores,
|
||||
folded_slots=folded_declared_slots(args.platforms_dir, selected, db),
|
||||
platform=config.get("_key", args.platform) if args.platform else "",
|
||||
)
|
||||
|
||||
if args.json:
|
||||
|
||||
@@ -110,5 +110,60 @@ class GapReportSources(unittest.TestCase):
|
||||
)
|
||||
|
||||
|
||||
class PlatformScopedEntries(unittest.TestCase):
|
||||
"""Under --platform the report reads the platform's scoping fields
|
||||
through the functions verify and the builder call: blastem's cdbios.bin
|
||||
is never opened by RetroBat (unread_on), touchHLE's fonts are not in
|
||||
ROCKNIX's package (not_bundled_on), fMSX's fonts come with Recalbox's
|
||||
(installed_on)."""
|
||||
|
||||
PROFILES = {"emu": {"emulator": "Emu", "systems": ["sys"], "files": [
|
||||
{"name": "skipped.bin", "required": True, "unread_on": ["plat"]},
|
||||
{"name": "font.ttf", "required": True, "bundled": True,
|
||||
"not_bundled_on": ["plat"]},
|
||||
{"name": "held.fnt", "installed_on": ["plat"]},
|
||||
]}}
|
||||
DB = {"files": {"a" * 40: {"path": "bios/held.fnt", "name": "held.fnt"}},
|
||||
"indexes": {"by_name": {"held.fnt": ["a" * 40]}, "by_md5": {},
|
||||
"by_crc32": {}, "by_sha256": {}, "by_path_suffix": {}}}
|
||||
|
||||
def _gaps(self, platform: str) -> dict[str, dict]:
|
||||
report = cross_reference(self.PROFILES, {}, self.DB, platform=platform)
|
||||
return {g["name"]: g for g in report["emu"]["gap_details"]}
|
||||
|
||||
def test_an_entry_the_platform_never_opens_is_not_a_gap(self):
|
||||
self.assertNotIn("skipped.bin", self._gaps("plat"))
|
||||
self.assertIn("skipped.bin", self._gaps("other"))
|
||||
self.assertIn("skipped.bin", self._gaps(""))
|
||||
|
||||
def test_bundled_follows_the_platform_package(self):
|
||||
gaps = self._gaps("plat")
|
||||
self.assertFalse(gaps["font.ttf"]["bundled"])
|
||||
self.assertTrue(gaps["held.fnt"]["bundled"])
|
||||
gaps = self._gaps("other")
|
||||
self.assertTrue(gaps["font.ttf"]["bundled"])
|
||||
self.assertFalse(gaps["held.fnt"]["bundled"])
|
||||
|
||||
def test_a_held_bundled_file_is_not_announced_as_available(self):
|
||||
import contextlib
|
||||
import io
|
||||
|
||||
report = cross_reference(self.PROFILES, {}, self.DB, platform="plat")
|
||||
with contextlib.redirect_stdout(io.StringIO()) as out:
|
||||
print_report(report)
|
||||
text = out.getvalue()
|
||||
self.assertIn("held.fnt [BUNDLED]", text)
|
||||
self.assertIn("0 available", text)
|
||||
self.assertIn("1 missing (need to be sourced)", text)
|
||||
|
||||
def test_the_report_reads_the_shared_rules(self):
|
||||
"""One rule, one function: a local `bool(f.get("bundled"))` answered
|
||||
differently from verify for every installed_on/not_bundled_on entry."""
|
||||
source = (REPO_ROOT / "scripts" / "cross_reference.py").read_text()
|
||||
self.assertNotIn('bool(f.get("bundled"))', source)
|
||||
self.assertIn("installed_with_emulator(f, platform)", source)
|
||||
self.assertIn("unread_on(f, platform)", source)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user