mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-21 03:09:08 -05:00
fix: count a shared destination once, filled
verify kept the worst verdict on the raw destination, the builder the first one it read. Both now key on the sanitized path and let a declaration that holds a file fill one that finds nothing.
This commit is contained in:
1 parent
c63a7e45b1
commit
34c8b925d7
3 files changed
+76
-10
No files matched your search
@@ -964,6 +964,11 @@ def generate_pack(
|
|||||||
dedup_key,
|
dedup_key,
|
||||||
existence_discrepancy(file_entry, local_path, platform_display),
|
existence_discrepancy(file_entry, local_path, platform_display),
|
||||||
)
|
)
|
||||||
|
if file_status.get(dedup_key) == "missing":
|
||||||
|
# An earlier declaration of this path found nothing; this
|
||||||
|
# one fills it, as verify counts it.
|
||||||
|
del file_status[dedup_key]
|
||||||
|
file_reasons.pop(dedup_key, None)
|
||||||
file_status.setdefault(dedup_key, "ok")
|
file_status.setdefault(dedup_key, "ok")
|
||||||
|
|
||||||
# Emulator-level validation: informational only for platform packs.
|
# Emulator-level validation: informational only for platform packs.
|
||||||
|
|||||||
+19
-10
@@ -814,6 +814,12 @@ def _mark_hidden(
|
|||||||
return placed
|
return placed
|
||||||
|
|
||||||
|
|
||||||
|
def _dest_key(file_entry: dict, sys_id: str) -> str:
|
||||||
|
"""The path a declaration occupies, as the builder keys its pack."""
|
||||||
|
dest = sanitize_pack_path(file_entry.get("destination", file_entry.get("name", "")))
|
||||||
|
return dest or f"{sys_id}/{file_entry.get('name', '')}"
|
||||||
|
|
||||||
|
|
||||||
def _twin_index(
|
def _twin_index(
|
||||||
verify_systems: dict, db: dict, base_dest: str, zip_contents: dict,
|
verify_systems: dict, db: dict, base_dest: str, zip_contents: dict,
|
||||||
) -> tuple[dict[str, int], dict[int, tuple[str, dict]]]:
|
) -> tuple[dict[str, int], dict[int, tuple[str, dict]]]:
|
||||||
@@ -1098,19 +1104,25 @@ def verify_platform(
|
|||||||
if _twin_unmet(result, held_by):
|
if _twin_unmet(result, held_by):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Aggregate by destination
|
# Aggregate by destination, keyed as the builder keys its pack.
|
||||||
dest = file_entry.get("destination", file_entry.get("name", ""))
|
# A declaration that finds nothing leaves the path to one that
|
||||||
if not dest:
|
# holds a file: the builder packs that file there, whatever the
|
||||||
dest = f"{sys_id}/{file_entry.get('name', '')}"
|
# order the two are read in.
|
||||||
|
dest = _dest_key(file_entry, sys_id)
|
||||||
results_at.setdefault(dest, []).append(result)
|
results_at.setdefault(dest, []).append(result)
|
||||||
required = file_entry.get("required", True)
|
required = file_entry.get("required", True)
|
||||||
cur = result["status"]
|
cur = result["status"]
|
||||||
prev = file_status.get(dest)
|
prev = file_status.get(dest)
|
||||||
|
hle = hle_index.get(file_entry.get("name", ""), False)
|
||||||
|
sev = compute_severity(cur, required, mode, hle)
|
||||||
|
if prev is not None and (cur == Status.MISSING) != (prev == Status.MISSING):
|
||||||
|
if cur == Status.MISSING:
|
||||||
|
continue
|
||||||
|
del file_status[dest], file_severity[dest]
|
||||||
|
prev = None
|
||||||
if prev is None or _STATUS_ORDER.get(cur, 0) > _STATUS_ORDER.get(prev, 0):
|
if prev is None or _STATUS_ORDER.get(cur, 0) > _STATUS_ORDER.get(prev, 0):
|
||||||
file_status[dest] = cur
|
file_status[dest] = cur
|
||||||
file_required[dest] = required
|
file_required[dest] = required
|
||||||
hle = hle_index.get(file_entry.get("name", ""), False)
|
|
||||||
sev = compute_severity(cur, required, mode, hle)
|
|
||||||
prev_sev = file_severity.get(dest)
|
prev_sev = file_severity.get(dest)
|
||||||
if prev_sev is None or _SEVERITY_ORDER.get(sev, 0) > _SEVERITY_ORDER.get(
|
if prev_sev is None or _SEVERITY_ORDER.get(sev, 0) > _SEVERITY_ORDER.get(
|
||||||
prev_sev, 0
|
prev_sev, 0
|
||||||
@@ -1192,10 +1204,7 @@ def verify_platform(
|
|||||||
dest_to_name: dict[str, str] = {}
|
dest_to_name: dict[str, str] = {}
|
||||||
for sys_id, system in verify_systems.items():
|
for sys_id, system in verify_systems.items():
|
||||||
for fe in system.get("files", []):
|
for fe in system.get("files", []):
|
||||||
dest = fe.get("destination", fe.get("name", ""))
|
dest_to_name.setdefault(_dest_key(fe, sys_id), fe.get("name", ""))
|
||||||
if not dest:
|
|
||||||
dest = f"{sys_id}/{fe.get('name', '')}"
|
|
||||||
dest_to_name.setdefault(dest, fe.get("name", ""))
|
|
||||||
with_validation = sum(
|
with_validation = sum(
|
||||||
1 for dest in file_status if dest_to_name.get(dest, "") in gt_filenames
|
1 for dest in file_status if dest_to_name.get(dest, "") in gt_filenames
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -258,5 +258,57 @@ class AMemberNameIsNotALooseFile(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TwoDeclarationsOfOnePath(unittest.TestCase):
|
||||||
|
"""Two systems declare one destination under two names, no hash, one
|
||||||
|
held. The builder packed the held file and kept the first verdict it
|
||||||
|
read; verify kept the worst, on the raw destination. Read either way
|
||||||
|
round, both must count the path once and met."""
|
||||||
|
|
||||||
|
def _run(self, first: str, second: str, spelling: str):
|
||||||
|
_emulator_profiles_cache.clear()
|
||||||
|
root = Path(tempfile.mkdtemp(dir=REPO_ROOT / "tmp"))
|
||||||
|
self.addCleanup(shutil.rmtree, root, True)
|
||||||
|
bios = root / "bios" / "Maker" / "Console"
|
||||||
|
bios.mkdir(parents=True)
|
||||||
|
data = b"SHARED BOOT ROM"
|
||||||
|
(bios / "boot.bin").write_bytes(data)
|
||||||
|
sha1, md5 = hashlib.sha1(data).hexdigest(), hashlib.md5(data).hexdigest()
|
||||||
|
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": {}},
|
||||||
|
}
|
||||||
|
for folder in ("platforms", "emulators"):
|
||||||
|
(root / folder).mkdir()
|
||||||
|
(root / "platforms" / "fakeplat.yml").write_text(yaml.safe_dump({
|
||||||
|
"platform": "FakePlat", "verification_mode": "existence",
|
||||||
|
"base_destination": "system", "cores": [],
|
||||||
|
"systems": {
|
||||||
|
"a-system": {"files": [{"name": first, "destination": "shared.bin"}]},
|
||||||
|
"b-system": {"files": [{"name": second, "destination": spelling}]},
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
config = load_platform_config("fakeplat", str(root / "platforms"))
|
||||||
|
result = verify_platform(config, db, str(root / "emulators"))
|
||||||
|
out = io.StringIO()
|
||||||
|
with redirect_stdout(out):
|
||||||
|
zip_path = generate_pack(
|
||||||
|
"fakeplat", str(root / "platforms"), db, str(root / "bios"),
|
||||||
|
str(root / "out"), emulators_dir=str(root / "emulators"), offline=True,
|
||||||
|
)
|
||||||
|
with zipfile.ZipFile(zip_path) as zf:
|
||||||
|
self.assertIn("shared.bin", zf.namelist())
|
||||||
|
return result["status_counts"], out.getvalue()
|
||||||
|
|
||||||
|
def test_either_order_counts_one_met_path(self):
|
||||||
|
for first, second in (("boot.bin", "absent.bin"), ("absent.bin", "boot.bin")):
|
||||||
|
for spelling in ("shared.bin", "./shared.bin"):
|
||||||
|
with self.subTest(first=first, spelling=spelling):
|
||||||
|
counts, printed = self._run(first, second, spelling)
|
||||||
|
self.assertEqual(counts, {"ok": 1})
|
||||||
|
self.assertIn("1/1 files OK", printed)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
Reference in new issue
Block a user