fix: count a core file filling a declaration

In existence mode the builder packs a core's file at a destination the
platform declares and does not hold, and counts the declaration met.
verify now reads the same placement and reports it OK, so both sides
agree on the platform's count.
This commit is contained in:
Abdessamad Derraz committed 2026-10-17 18:14:26 +02:00
1 parent 2e52f06896
commit a58b65754b
3 files changed
+139 -20

No files matched your search

+5 -1
View File
@@ -137,6 +137,7 @@ def hidden_extras(
shipped: dict[str, str],
target_cores: set[str] | None = None,
region_drops: set[str] | None = None,
placed: set[str] | None = None,
) -> dict[tuple[str, str, str], str]:
"""Report entries the builder holds and still leaves out, with the reason.
@@ -150,7 +151,8 @@ def hidden_extras(
while the report counted it in the pack. A twin carrying the same bytes
serves the core on the filesystem that folds the names, so it is not a
file left out. ``shipped`` maps the full destination of each platform
file the pack carries to its local copy.
file the pack carries to its local copy. ``placed``, when given,
receives the full destination of each held extra the pack carries.
"""
from packpaths import _register_path, placement_block
@@ -198,6 +200,8 @@ def hidden_extras(
content[full.lower()] = held
if case_insensitive:
lower.add(full.lower())
if placed is not None and local:
placed.add(full)
return hidden
+37 -19
View File
@@ -763,15 +763,19 @@ def _mark_hidden(
shipped: dict[str, str],
target_cores: set[str] | None,
region_drops: set[str] | None = None,
) -> None:
"""What the builder holds but cannot place beside the files it packed."""
) -> set[str]:
"""What the builder holds but cannot place beside the files it packed.
Returns the full destinations the builder fills with a core's file.
"""
from packextras import hidden_extras
placed: set[str] = set()
hidden = hidden_extras(
config, emulators_dir, db,
emu_profiles if emu_profiles is not None
else load_emulator_profiles(emulators_dir),
shipped, target_cores, region_drops,
shipped, target_cores, region_drops, placed,
)
for u in undeclared:
reason = hidden.get(
@@ -780,6 +784,7 @@ def _mark_hidden(
if reason and u.get("in_repo") and u.get("in_pack", True):
u["in_pack"] = False
u["omitted"] = _HIDDEN_REASONS[reason]
return placed
def _twin_index(
@@ -987,6 +992,7 @@ def verify_platform(
)
shipped: dict[str, str] = {}
results_at: dict[str, list[dict]] = {}
for sys_id, system in verify_systems.items():
for file_entry in system.get("files", []):
if region_drops and (
@@ -1055,6 +1061,7 @@ def verify_platform(
dest = file_entry.get("destination", file_entry.get("name", ""))
if not dest:
dest = f"{sys_id}/{file_entry.get('name', '')}"
results_at.setdefault(dest, []).append(result)
required = file_entry.get("required", True)
cur = result["status"]
prev = file_status.get(dest)
@@ -1069,21 +1076,6 @@ def verify_platform(
):
file_severity[dest] = sev
# Count by severity
counts = {
Severity.OK: 0,
Severity.INFO: 0,
Severity.WARNING: 0,
Severity.CRITICAL: 0,
}
for s in file_severity.values():
counts[s] = counts.get(s, 0) + 1
# Count by file status (ok/untested/missing)
status_counts: dict[str, int] = {}
for s in file_status.values():
status_counts[s] = status_counts.get(s, 0) + 1
# Cross-reference undeclared files
if supplemental_names is None:
from cross_reference import _build_supplemental_index
@@ -1107,10 +1099,36 @@ def verify_platform(
not in region_drops
]
_mark_unplaced(config, undeclared, profiles)
_mark_hidden(
placed = _mark_hidden(
config, undeclared, emulators_dir, db, emu_profiles, shipped, target_cores,
region_drops,
)
if not reads_file_contents(mode):
# An existence frontend is satisfied by any file at the path, and the
# builder fills a free platform destination with a core's file.
for dest, status in file_status.items():
full = f"{base_dest}/{dest}" if base_dest else dest
if status == Status.MISSING and full in placed:
file_status[dest] = Status.OK
file_severity[dest] = Severity.OK
for result in results_at.get(dest, []):
result["status"] = Status.OK
# Count by severity
counts = {
Severity.OK: 0,
Severity.INFO: 0,
Severity.WARNING: 0,
Severity.CRITICAL: 0,
}
for s in file_severity.values():
counts[s] = counts.get(s, 0) + 1
# Count by file status (ok/untested/missing)
status_counts: dict[str, int] = {}
for s in file_status.values():
status_counts[s] = status_counts.get(s, 0) + 1
exclusions = find_exclusion_notes(
config, emulators_dir, emu_profiles, target_cores=target_cores
)
+97
View File
@@ -0,0 +1,97 @@
"""A core's file at a free platform destination answers an existence check.
The builder packs a core extra at a destination the platform declares and
does not hold, and in existence mode counts the declaration met: the
frontend sees a file at the path. verify kept it MISSING, so the pack said
1/1 OK and verify 0/1 for the same platform.
"""
from __future__ import annotations
import hashlib
import io
import os
import shutil
import sys
import tempfile
import unittest
import zipfile
from contextlib import redirect_stdout
from pathlib import Path
import yaml
REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "scripts"))
from common import _emulator_profiles_cache, load_platform_config # noqa: E402
from generate_pack import generate_pack # noqa: E402
from verify import verify_platform # noqa: E402
class ACoreFileFillsAFreeDeclaration(unittest.TestCase):
def setUp(self):
_emulator_profiles_cache.clear()
(REPO_ROOT / "tmp").mkdir(exist_ok=True)
self.root = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
self.addCleanup(shutil.rmtree, self.root, True)
bios = self.root / "bios" / "Maker" / "Console"
bios.mkdir(parents=True)
data = b"HELD BOOT ROM"
(bios / "boot.bin").write_bytes(data)
sha1 = hashlib.sha1(data).hexdigest()
md5 = hashlib.md5(data).hexdigest()
self.db = {
"files": {sha1: {
"path": str(bios / "boot.bin"), "name": "boot.bin",
"md5": md5, "crc32": "", "size": len(data),
}},
"indexes": {
"by_md5": {md5: sha1}, "by_name": {"boot.bin": [sha1]},
"by_crc32": {}, "by_path_suffix": {},
},
}
self.platforms = self.root / "platforms"
self.emulators = self.root / "emulators"
self.platforms.mkdir()
self.emulators.mkdir()
(self.platforms / "fakeplat.yml").write_text(yaml.safe_dump({
"platform": "FakePlat",
"verification_mode": "existence",
"base_destination": "system",
"cores": ["fakecore"],
"systems": {"console-a": {"files": [
{"name": "zzz_absent.bin", "destination": "zzz_absent.bin",
"required": True},
]}},
}))
# The entry's name differs from the destination it fills, as
# descriptive names do ("MDA font ROM" at mda.rom).
(self.emulators / "fakecore.yml").write_text(yaml.safe_dump({
"emulator": "FakeCore", "type": "libretro", "cores": ["fakecore"],
"systems": ["console-a"],
"files": [{"name": "Fake boot ROM", "path": "zzz_absent.bin",
"sha1": sha1, "required": True}],
}))
self.config = load_platform_config("fakeplat", str(self.platforms))
def test_verify_counts_what_the_pack_counts(self):
result = verify_platform(
self.config, self.db, str(self.emulators), supplemental_names=set(),
)
out = self.root / "out"
with redirect_stdout(io.StringIO()):
zip_path = generate_pack(
"fakeplat", str(self.platforms), self.db, str(self.root / "bios"),
str(out), emulators_dir=str(self.emulators), offline=True,
)
with zipfile.ZipFile(zip_path) as zf:
self.assertIn("zzz_absent.bin", zf.namelist())
self.assertEqual(result["status_counts"], {"ok": 1})
self.assertEqual(
[d["status"] for d in result["details"]], ["ok"],
)
if __name__ == "__main__":
unittest.main()