feat: add source param to manifest and split packs

This commit is contained in:
Abdessamad Derraz
2026-04-01 14:44:39 +02:00
parent 2c1c2a7bfe
commit 5f579d1851

View File

@@ -1936,11 +1936,13 @@ def generate_split_packs(
emu_profiles: dict | None = None, emu_profiles: dict | None = None,
target_cores: set[str] | None = None, target_cores: set[str] | None = None,
required_only: bool = False, required_only: bool = False,
source: str = "full",
) -> list[str]: ) -> list[str]:
"""Generate split packs (one ZIP per system or manufacturer).""" """Generate split packs (one ZIP per system or manufacturer)."""
config = load_platform_config(platform_name, platforms_dir) config = load_platform_config(platform_name, platforms_dir)
platform_display = config.get("platform", platform_name) platform_display = config.get("platform", platform_name)
split_dir = os.path.join(output_dir, f"{platform_display.replace(' ', '_')}_Split") source_tag = {"platform": "_Platform", "truth": "_Truth"}.get(source, "")
split_dir = os.path.join(output_dir, f"{platform_display.replace(' ', '_')}{source_tag}_Split")
os.makedirs(split_dir, exist_ok=True) os.makedirs(split_dir, exist_ok=True)
systems = config.get("systems", {}) systems = config.get("systems", {})
@@ -1955,15 +1957,12 @@ def generate_split_packs(
if emu_profiles is None: if emu_profiles is None:
emu_profiles = load_emulator_profiles(emulators_dir) emu_profiles = load_emulator_profiles(emulators_dir)
base_dest = config.get("base_destination", "") base_dest = config.get("base_destination", "")
if emu_profiles: if source == "platform":
all_extras = []
elif emu_profiles:
all_extras = _collect_emulator_extras( all_extras = _collect_emulator_extras(
config, config, emulators_dir, db, set(), base_dest, emu_profiles,
emulators_dir, target_cores=target_cores, include_all=(source == "truth"),
db,
set(),
base_dest,
emu_profiles,
target_cores=target_cores,
) )
else: else:
all_extras = [] all_extras = []
@@ -2007,13 +2006,14 @@ def generate_split_packs(
required_only=required_only, required_only=required_only,
system_filter=group_system_ids, system_filter=group_system_ids,
precomputed_extras=group_extras, precomputed_extras=group_extras,
source=source,
) )
if zip_path: if zip_path:
version = config.get("version", config.get("dat_version", "")) version = config.get("version", config.get("dat_version", ""))
ver_tag = f"_{version.replace(' ', '')}" if version else "" ver_tag = f"_{version.replace(' ', '')}" if version else ""
req_tag = "_Required" if required_only else "" req_tag = "_Required" if required_only else ""
safe_group = group_name.replace(" ", "_") safe_group = group_name.replace(" ", "_")
new_name = f"{platform_display.replace(' ', '_')}{ver_tag}{req_tag}_{safe_group}_BIOS_Pack.zip" new_name = f"{platform_display.replace(' ', '_')}{ver_tag}{source_tag}{req_tag}_{safe_group}_BIOS_Pack.zip"
new_path = os.path.join(split_dir, new_name) new_path = os.path.join(split_dir, new_name)
if new_path != zip_path: if new_path != zip_path:
os.rename(zip_path, new_path) os.rename(zip_path, new_path)
@@ -2859,6 +2859,7 @@ def generate_manifest(
zip_contents: dict | None = None, zip_contents: dict | None = None,
emu_profiles: dict | None = None, emu_profiles: dict | None = None,
target_cores: set[str] | None = None, target_cores: set[str] | None = None,
source: str = "full",
) -> dict: ) -> dict:
"""Generate a JSON manifest for a platform (same resolution as generate_pack). """Generate a JSON manifest for a platform (same resolution as generate_pack).
@@ -2905,71 +2906,76 @@ def generate_manifest(
total_size = 0 total_size = 0
# Phase 1: baseline files # Phase 1: baseline files
for sys_id, system in sorted(pack_systems.items()): if source != "truth":
for file_entry in system.get("files", []): for sys_id, system in sorted(pack_systems.items()):
dest = _sanitize_path(file_entry.get("destination", file_entry["name"])) for file_entry in system.get("files", []):
if not dest: dest = _sanitize_path(file_entry.get("destination", file_entry["name"]))
continue if not dest:
full_dest = f"{base_dest}/{dest}" if base_dest else dest continue
full_dest = f"{base_dest}/{dest}" if base_dest else dest
dedup_key = full_dest dedup_key = full_dest
if dedup_key in seen_destinations: if dedup_key in seen_destinations:
continue continue
if case_insensitive and dedup_key.lower() in seen_lower: if case_insensitive and dedup_key.lower() in seen_lower:
continue continue
if _has_path_conflict(full_dest, seen_destinations, seen_parents): if _has_path_conflict(full_dest, seen_destinations, seen_parents):
continue continue
storage = file_entry.get("storage", "embedded") storage = file_entry.get("storage", "embedded")
if storage == "user_provided": if storage == "user_provided":
continue continue
local_path, status = resolve_file(file_entry, db, bios_dir, zip_contents) local_path, status = resolve_file(file_entry, db, bios_dir, zip_contents)
if status in ("not_found", "external"): if status in ("not_found", "external"):
continue continue
# Get SHA1 and size # Get SHA1 and size
sha1 = file_entry.get("sha1", "") sha1 = file_entry.get("sha1", "")
file_size = 0 file_size = 0
if local_path and os.path.exists(local_path): if local_path and os.path.exists(local_path):
file_size = os.path.getsize(local_path) file_size = os.path.getsize(local_path)
if not sha1: if not sha1:
hashes = compute_hashes(local_path) hashes = compute_hashes(local_path)
sha1 = hashes["sha1"] sha1 = hashes["sha1"]
repo_path = _get_repo_path(sha1, db) if sha1 else "" repo_path = _get_repo_path(sha1, db) if sha1 else ""
entry: dict = { entry: dict = {
"dest": dest, "dest": dest,
"sha1": sha1, "sha1": sha1,
"size": file_size, "size": file_size,
"repo_path": repo_path, "repo_path": repo_path,
"cores": None, "cores": None,
} }
if _is_large_file(local_path or "", repo_root): if _is_large_file(local_path or "", repo_root):
entry["storage"] = "release" entry["storage"] = "release"
entry["release_asset"] = ( entry["release_asset"] = (
os.path.basename(local_path) if local_path else file_entry["name"] os.path.basename(local_path) if local_path else file_entry["name"]
) )
manifest_files.append(entry) manifest_files.append(entry)
total_size += file_size total_size += file_size
seen_destinations.add(dedup_key) seen_destinations.add(dedup_key)
_register_path(dedup_key, seen_destinations, seen_parents) _register_path(dedup_key, seen_destinations, seen_parents)
if case_insensitive: if case_insensitive:
seen_lower.add(dedup_key.lower()) seen_lower.add(dedup_key.lower())
# Phase 2: core complement (emulator extras) # Phase 2: core complement (emulator extras)
core_files = _collect_emulator_extras( if source != "platform":
config, core_files = _collect_emulator_extras(
emulators_dir, config,
db, emulators_dir,
seen_destinations, db,
base_dest, seen_destinations,
emu_profiles, base_dest,
target_cores=target_cores, emu_profiles,
) target_cores=target_cores,
include_all=(source == "truth"),
)
else:
core_files = []
extras_pfx = _detect_extras_prefix(config, base_dest) extras_pfx = _detect_extras_prefix(config, base_dest)
for fe in core_files: for fe in core_files:
dest = _sanitize_path(fe.get("destination", fe["name"])) dest = _sanitize_path(fe.get("destination", fe["name"]))
@@ -3038,6 +3044,7 @@ def generate_manifest(
result: dict = { result: dict = {
"manifest_version": 1, "manifest_version": 1,
"source": source,
"platform": platform_name, "platform": platform_name,
"display_name": platform_display, "display_name": platform_display,
"version": "1.0", "version": "1.0",