mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-16 08:23:28 -05:00
fix: report core files the platform pack displaces
This commit is contained in:
1 parent
a41648292e
commit
d049270515
5 files changed
+238
-12
No files matched your search
+12
-12
@@ -966,13 +966,13 @@ def generate_pack(
|
||||
full_dest = dest
|
||||
else:
|
||||
full_dest = dest
|
||||
if full_dest in seen_destinations:
|
||||
continue
|
||||
# Skip case-insensitive duplicates (Windows/macOS FS safety)
|
||||
if full_dest.lower() in seen_lower and case_insensitive:
|
||||
continue
|
||||
# Skip file/directory path conflicts (e.g., SGB1.sfc file vs SGB1.sfc/ dir)
|
||||
if _has_path_conflict(full_dest, seen_destinations, seen_parents):
|
||||
# Taken, a case twin on a case-insensitive filesystem, or a
|
||||
# file/directory conflict (SGB1.sfc vs SGB1.sfc/): verify replays
|
||||
# the same rule (packextras.hidden_extras).
|
||||
if placement_block(
|
||||
full_dest, seen_destinations, seen_lower, seen_parents,
|
||||
case_insensitive,
|
||||
):
|
||||
continue
|
||||
|
||||
dest_hint = fe.get("destination", "")
|
||||
@@ -3213,11 +3213,10 @@ def _manifest_core_entries(
|
||||
else:
|
||||
full_dest = dest
|
||||
|
||||
if full_dest in seen_destinations:
|
||||
continue
|
||||
if case_insensitive and full_dest.lower() in seen_lower:
|
||||
continue
|
||||
if _has_path_conflict(full_dest, seen_destinations, seen_parents):
|
||||
if placement_block(
|
||||
full_dest, seen_destinations, seen_lower, seen_parents,
|
||||
case_insensitive,
|
||||
):
|
||||
continue
|
||||
|
||||
dest_hint = fe.get("destination", "")
|
||||
@@ -3989,6 +3988,7 @@ from packpaths import ( # noqa: E402,F401
|
||||
_register_path,
|
||||
_flat,
|
||||
_resolve_destination,
|
||||
placement_block,
|
||||
)
|
||||
from packextras import ( # noqa: E402,F401
|
||||
_detect_extras_prefix,
|
||||
|
||||
@@ -128,6 +128,74 @@ def _slug_for(
|
||||
return _map_emulator_to_slug(profile, platform_systems, norm_map, sys_to_slug)
|
||||
|
||||
|
||||
def hidden_extras(
|
||||
config: dict,
|
||||
emulators_dir: str,
|
||||
db: dict,
|
||||
profiles: dict,
|
||||
shipped: dict[str, str],
|
||||
target_cores: set[str] | None = None,
|
||||
) -> dict[tuple[str, str, str], str]:
|
||||
"""Report entries the builder holds and still leaves out, with the reason.
|
||||
|
||||
The builder walks the core extras after the platform's own files and
|
||||
skips a destination that a case-insensitive filesystem folds onto one
|
||||
already packed, or that a packed file blocks as a directory. RetroPie's
|
||||
openmsx fmpac.rom gave way to the platform's FMPAC.ROM, other bytes,
|
||||
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.
|
||||
"""
|
||||
from packpaths import _register_path, placement_block
|
||||
|
||||
sha1_by_path = {
|
||||
entry.get("path"): sha1 for sha1, entry in db.get("files", {}).items()
|
||||
}
|
||||
base_dest = config.get("base_destination", "")
|
||||
case_insensitive = bool(config.get("case_insensitive_fs", False))
|
||||
seen: set[str] = set()
|
||||
parents: set[str] = set()
|
||||
content: dict[str, str | None] = {}
|
||||
for dest, local in shipped.items():
|
||||
_register_path(dest, seen, parents)
|
||||
content[dest.lower()] = sha1_by_path.get(local)
|
||||
lower = set(content) if case_insensitive else set()
|
||||
prefix = _detect_extras_prefix(config, base_dest)
|
||||
hidden: dict[tuple[str, str, str], str] = {}
|
||||
for fe in _collect_emulator_extras(
|
||||
config, emulators_dir, db, set(shipped), base_dest, profiles,
|
||||
target_cores=target_cores,
|
||||
):
|
||||
dest = sanitize_pack_path(fe.get("destination", fe.get("name", "")))
|
||||
if not dest:
|
||||
continue
|
||||
full = dest if not prefix or dest.startswith(f"{prefix}/") else f"{prefix}/{dest}"
|
||||
reason = placement_block(full, seen, lower, parents, case_insensitive)
|
||||
if reason == "taken":
|
||||
# Another core's claim on the same path, settled by the claims
|
||||
# the collector records: not a file left out.
|
||||
continue
|
||||
local, _status = resolve_local_file(
|
||||
fe, db, dest_hint=fe.get("destination", "")
|
||||
)
|
||||
held = sha1_by_path.get(local) if local else None
|
||||
if reason == "case_twin" and held and content.get(full.lower()) == held:
|
||||
continue
|
||||
if reason is not None:
|
||||
key = (
|
||||
fe.get("source_emulator", ""), fe.get("source_name", ""),
|
||||
fe.get("source_path", ""),
|
||||
)
|
||||
hidden.setdefault(key, reason)
|
||||
continue
|
||||
_register_path(full, seen, parents)
|
||||
content[full.lower()] = held
|
||||
if case_insensitive:
|
||||
lower.add(full.lower())
|
||||
return hidden
|
||||
|
||||
|
||||
def unplaceable_extras(config: dict, undeclared: list[dict], profiles: dict) -> set:
|
||||
"""Keys of the report entries a slug-based platform cannot place.
|
||||
|
||||
|
||||
@@ -26,6 +26,27 @@ def _has_path_conflict(dest: str, seen_files: set[str], seen_parents: set[str])
|
||||
return True
|
||||
return False
|
||||
|
||||
def placement_block(
|
||||
dest: str,
|
||||
seen_files: set[str],
|
||||
seen_lower: set[str],
|
||||
seen_parents: set[str],
|
||||
case_insensitive: bool,
|
||||
) -> str | None:
|
||||
"""Why a destination cannot take a file in this pack, or None.
|
||||
|
||||
The one rule the builder applies to a core extra and the report replays:
|
||||
counted apart, the report called a skipped file packed.
|
||||
"""
|
||||
if dest in seen_files:
|
||||
return "taken"
|
||||
if case_insensitive and dest.lower() in seen_lower:
|
||||
return "case_twin"
|
||||
if _has_path_conflict(dest, seen_files, seen_parents):
|
||||
return "path_conflict"
|
||||
return None
|
||||
|
||||
|
||||
def _register_path(dest: str, seen_files: set[str], seen_parents: set[str]) -> None:
|
||||
"""Track a file path and its parent directories."""
|
||||
seen_files.add(dest)
|
||||
|
||||
@@ -785,6 +785,39 @@ def _mark_unplaced(config: dict, undeclared: list[dict], profiles: dict) -> None
|
||||
u["omitted"] = "no platform slug for its system"
|
||||
|
||||
|
||||
_HIDDEN_REASONS = {
|
||||
"case_twin": "a packed file of the same name in another case takes its place",
|
||||
"path_conflict": "a packed file occupies its directory",
|
||||
}
|
||||
|
||||
|
||||
def _mark_hidden(
|
||||
config: dict,
|
||||
undeclared: list[dict],
|
||||
emulators_dir: str,
|
||||
db: dict,
|
||||
emu_profiles: dict | None,
|
||||
shipped: dict[str, str],
|
||||
target_cores: set[str] | None,
|
||||
) -> None:
|
||||
"""What the builder holds but cannot place beside the files it packed."""
|
||||
from packextras import hidden_extras
|
||||
|
||||
hidden = hidden_extras(
|
||||
config, emulators_dir, db,
|
||||
emu_profiles if emu_profiles is not None
|
||||
else load_emulator_profiles(emulators_dir),
|
||||
shipped, target_cores,
|
||||
)
|
||||
for u in undeclared:
|
||||
reason = hidden.get(
|
||||
(u.get("emulator", ""), u.get("name", ""), u.get("path") or "")
|
||||
)
|
||||
if reason and u.get("in_repo") and u.get("in_pack", True):
|
||||
u["in_pack"] = False
|
||||
u["omitted"] = _HIDDEN_REASONS[reason]
|
||||
|
||||
|
||||
def _twin_index(
|
||||
verify_systems: dict, db: dict, base_dest: str, zip_contents: dict,
|
||||
) -> tuple[dict[str, int], dict[int, tuple[str, dict]]]:
|
||||
@@ -981,6 +1014,7 @@ def verify_platform(
|
||||
verify_systems, db, base_dest, zip_contents
|
||||
)
|
||||
|
||||
shipped: dict[str, str] = {}
|
||||
for sys_id, system in verify_systems.items():
|
||||
for file_entry in system.get("files", []):
|
||||
if region_drops and (
|
||||
@@ -1030,6 +1064,11 @@ def verify_platform(
|
||||
validation_index,
|
||||
)
|
||||
details.append(result)
|
||||
if local_path and result["status"] != Status.MISSING:
|
||||
shipped.setdefault(
|
||||
f"{base_dest}/{destination}" if base_dest else destination,
|
||||
local_path,
|
||||
)
|
||||
if _twin_unmet(result, held_by):
|
||||
continue
|
||||
|
||||
@@ -1089,6 +1128,9 @@ def verify_platform(
|
||||
not in region_drops
|
||||
]
|
||||
_mark_unplaced(config, undeclared, profiles)
|
||||
_mark_hidden(
|
||||
config, undeclared, emulators_dir, db, emu_profiles, shipped, target_cores
|
||||
)
|
||||
exclusions = find_exclusion_notes(
|
||||
config, emulators_dir, emu_profiles, target_cores=target_cores
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user