mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-04-17 22:32:31 -05:00
feat: allow --platform + --system combination
This commit is contained in:
@@ -1068,3 +1068,14 @@ def list_system_ids(emulators_dir: str) -> None:
|
|||||||
for sys_id in sorted(system_emus):
|
for sys_id in sorted(system_emus):
|
||||||
count = len(system_emus[sys_id])
|
count = len(system_emus[sys_id])
|
||||||
print(f" {sys_id:35s} ({count} emulator{'s' if count > 1 else ''})")
|
print(f" {sys_id:35s} ({count} emulator{'s' if count > 1 else ''})")
|
||||||
|
|
||||||
|
|
||||||
|
def list_platform_system_ids(platform_name: str, platforms_dir: str) -> None:
|
||||||
|
"""Print system IDs from a platform's YAML config."""
|
||||||
|
config = load_platform_config(platform_name, platforms_dir)
|
||||||
|
systems = config.get("systems", {})
|
||||||
|
for sys_id in sorted(systems):
|
||||||
|
file_count = len(systems[sys_id].get("files", []))
|
||||||
|
mfr = systems[sys_id].get("manufacturer", "")
|
||||||
|
mfr_display = f" [{mfr.split('|')[0]}]" if mfr else ""
|
||||||
|
print(f" {sys_id:35s} ({file_count} file{'s' if file_count != 1 else ''}){mfr_display}")
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ sys.path.insert(0, os.path.dirname(__file__))
|
|||||||
from common import (
|
from common import (
|
||||||
_build_validation_index, build_zip_contents_index, check_file_validation,
|
_build_validation_index, build_zip_contents_index, check_file_validation,
|
||||||
check_inside_zip, compute_hashes, fetch_large_file, filter_files_by_mode,
|
check_inside_zip, compute_hashes, fetch_large_file, filter_files_by_mode,
|
||||||
group_identical_platforms, list_emulator_profiles, list_registered_platforms,
|
group_identical_platforms, list_emulator_profiles, list_platform_system_ids,
|
||||||
|
list_registered_platforms,
|
||||||
filter_systems_by_target, list_system_ids, load_database,
|
filter_systems_by_target, list_system_ids, load_database,
|
||||||
load_data_dir_registry, load_emulator_profiles, load_platform_config,
|
load_data_dir_registry, load_emulator_profiles, load_platform_config,
|
||||||
md5_composite, resolve_local_file,
|
md5_composite, resolve_local_file,
|
||||||
@@ -232,6 +233,7 @@ def generate_pack(
|
|||||||
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,
|
||||||
|
system_filter: list[str] | None = None,
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
"""Generate a ZIP pack for a platform.
|
"""Generate a ZIP pack for a platform.
|
||||||
|
|
||||||
@@ -248,7 +250,25 @@ def generate_pack(
|
|||||||
version = config.get("version", config.get("dat_version", ""))
|
version = config.get("version", config.get("dat_version", ""))
|
||||||
version_tag = f"_{version.replace(' ', '')}" if version else ""
|
version_tag = f"_{version.replace(' ', '')}" if version else ""
|
||||||
req_tag = "_Required" if required_only else ""
|
req_tag = "_Required" if required_only else ""
|
||||||
zip_name = f"{platform_display.replace(' ', '_')}{version_tag}{req_tag}_BIOS_Pack.zip"
|
|
||||||
|
sys_tag = ""
|
||||||
|
if system_filter:
|
||||||
|
display_parts = []
|
||||||
|
for sid in system_filter:
|
||||||
|
s = sid.lower().replace("_", "-")
|
||||||
|
for prefix in ("microsoft-", "nintendo-", "sony-", "sega-", "snk-",
|
||||||
|
"panasonic-", "nec-", "epoch-", "mattel-", "fairchild-",
|
||||||
|
"hartung-", "tiger-", "magnavox-", "philips-", "bandai-",
|
||||||
|
"casio-", "coleco-", "commodore-", "sharp-", "sinclair-",
|
||||||
|
"atari-"):
|
||||||
|
if s.startswith(prefix):
|
||||||
|
s = s[len(prefix):]
|
||||||
|
break
|
||||||
|
parts = s.split("-")
|
||||||
|
display_parts.append("_".join(p.title() for p in parts if p))
|
||||||
|
sys_tag = "_" + "_".join(display_parts)
|
||||||
|
|
||||||
|
zip_name = f"{platform_display.replace(' ', '_')}{version_tag}{req_tag}_BIOS_Pack{sys_tag}.zip"
|
||||||
zip_path = os.path.join(output_dir, zip_name)
|
zip_path = os.path.join(output_dir, zip_name)
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
|
||||||
@@ -281,6 +301,18 @@ def generate_pack(
|
|||||||
platform_cores=plat_cores,
|
platform_cores=plat_cores,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if system_filter:
|
||||||
|
from common import _norm_system_id
|
||||||
|
norm_filter = {_norm_system_id(s) for s in system_filter}
|
||||||
|
filtered = {sid: sys_data for sid, sys_data in pack_systems.items()
|
||||||
|
if sid in system_filter or _norm_system_id(sid) in norm_filter}
|
||||||
|
if not filtered:
|
||||||
|
available = sorted(pack_systems.keys())[:10]
|
||||||
|
print(f" WARNING: no systems matched filter {system_filter} "
|
||||||
|
f"(available: {', '.join(available)})")
|
||||||
|
return None
|
||||||
|
pack_systems = filtered
|
||||||
|
|
||||||
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
||||||
for sys_id, system in sorted(pack_systems.items()):
|
for sys_id, system in sorted(pack_systems.items()):
|
||||||
for file_entry in system.get("files", []):
|
for file_entry in system.get("files", []):
|
||||||
@@ -899,7 +931,10 @@ def main():
|
|||||||
list_emulator_profiles(args.emulators_dir)
|
list_emulator_profiles(args.emulators_dir)
|
||||||
return
|
return
|
||||||
if args.list_systems:
|
if args.list_systems:
|
||||||
list_system_ids(args.emulators_dir)
|
if args.platform:
|
||||||
|
list_platform_system_ids(args.platform, args.platforms_dir)
|
||||||
|
else:
|
||||||
|
list_system_ids(args.emulators_dir)
|
||||||
return
|
return
|
||||||
if args.list_targets:
|
if args.list_targets:
|
||||||
if not args.platform:
|
if not args.platform:
|
||||||
@@ -914,18 +949,26 @@ def main():
|
|||||||
print(f" {t['name']:30s} {t['architecture']:10s} {t['core_count']:>4d} cores{aliases}")
|
print(f" {t['name']:30s} {t['architecture']:10s} {t['core_count']:>4d} cores{aliases}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Mutual exclusion
|
# Mode validation
|
||||||
modes = sum(1 for x in (args.platform, args.all, args.emulator, args.system) if x)
|
has_platform = bool(args.platform)
|
||||||
if modes == 0:
|
has_all = args.all
|
||||||
|
has_emulator = bool(args.emulator)
|
||||||
|
has_system = bool(args.system)
|
||||||
|
|
||||||
|
# --platform/--all and --system can combine (system filters within platform)
|
||||||
|
# --emulator is exclusive with everything else
|
||||||
|
if has_emulator and (has_platform or has_all or has_system):
|
||||||
|
parser.error("--emulator is mutually exclusive with --platform, --all, and --system")
|
||||||
|
if has_platform and has_all:
|
||||||
|
parser.error("--platform and --all are mutually exclusive")
|
||||||
|
if not (has_platform or has_all or has_emulator or has_system):
|
||||||
parser.error("Specify --platform, --all, --emulator, or --system")
|
parser.error("Specify --platform, --all, --emulator, or --system")
|
||||||
if modes > 1:
|
if args.standalone and not (has_emulator or (has_system and not has_platform and not has_all)):
|
||||||
parser.error("--platform, --all, --emulator, and --system are mutually exclusive")
|
parser.error("--standalone requires --emulator or --system (without --platform)")
|
||||||
if args.standalone and not (args.emulator or args.system):
|
if args.target and not (has_platform or has_all):
|
||||||
parser.error("--standalone requires --emulator or --system")
|
|
||||||
if args.target and not (args.platform or args.all):
|
|
||||||
parser.error("--target requires --platform or --all")
|
parser.error("--target requires --platform or --all")
|
||||||
if args.target and (args.emulator or args.system):
|
if args.target and has_emulator:
|
||||||
parser.error("--target is incompatible with --emulator and --system")
|
parser.error("--target is incompatible with --emulator")
|
||||||
|
|
||||||
db = load_database(args.db)
|
db = load_database(args.db)
|
||||||
zip_contents = build_zip_contents_index(db)
|
zip_contents = build_zip_contents_index(db)
|
||||||
@@ -941,8 +984,8 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return
|
return
|
||||||
|
|
||||||
# System mode
|
# System mode (standalone, without platform context)
|
||||||
if args.system:
|
if has_system and not has_platform and not has_all:
|
||||||
system_ids = [s.strip() for s in args.system.split(",") if s.strip()]
|
system_ids = [s.strip() for s in args.system.split(",") if s.strip()]
|
||||||
result = generate_system_pack(
|
result = generate_system_pack(
|
||||||
system_ids, args.emulators_dir, db, args.bios_dir, args.output_dir,
|
system_ids, args.emulators_dir, db, args.bios_dir, args.output_dir,
|
||||||
@@ -952,6 +995,10 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
system_filter = None
|
||||||
|
if args.system:
|
||||||
|
system_filter = [s.strip() for s in args.system.split(",") if s.strip()]
|
||||||
|
|
||||||
# Platform mode (existing)
|
# Platform mode (existing)
|
||||||
if args.all:
|
if args.all:
|
||||||
platforms = list_registered_platforms(
|
platforms = list_registered_platforms(
|
||||||
@@ -1016,6 +1063,7 @@ def main():
|
|||||||
zip_contents=zip_contents, data_registry=data_registry,
|
zip_contents=zip_contents, data_registry=data_registry,
|
||||||
emu_profiles=emu_profiles, target_cores=tc,
|
emu_profiles=emu_profiles, target_cores=tc,
|
||||||
required_only=args.required_only,
|
required_only=args.required_only,
|
||||||
|
system_filter=system_filter,
|
||||||
)
|
)
|
||||||
if zip_path and variants:
|
if zip_path and variants:
|
||||||
rep_cfg = load_platform_config(representative, args.platforms_dir)
|
rep_cfg = load_platform_config(representative, args.platforms_dir)
|
||||||
|
|||||||
@@ -1602,5 +1602,84 @@ class TestE2E(unittest.TestCase):
|
|||||||
self.assertTrue(any("present_req.bin" in n for n in names))
|
self.assertTrue(any("present_req.bin" in n for n in names))
|
||||||
|
|
||||||
|
|
||||||
|
def test_132_platform_system_filter(self):
|
||||||
|
"""--platform + --system filters systems within a platform pack."""
|
||||||
|
from generate_pack import generate_pack
|
||||||
|
output_dir = os.path.join(self.root, "pack_sysfilter")
|
||||||
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
config = {
|
||||||
|
"platform": "SysFilterTest",
|
||||||
|
"verification_mode": "existence",
|
||||||
|
"base_destination": "system",
|
||||||
|
"systems": {
|
||||||
|
"system-a": {
|
||||||
|
"files": [
|
||||||
|
{"name": "present_req.bin", "destination": "present_req.bin"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"system-b": {
|
||||||
|
"files": [
|
||||||
|
{"name": "present_opt.bin", "destination": "present_opt.bin"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
with open(os.path.join(self.platforms_dir, "test_sysfilter.yml"), "w") as fh:
|
||||||
|
yaml.dump(config, fh)
|
||||||
|
zip_path = generate_pack(
|
||||||
|
"test_sysfilter", self.platforms_dir, self.db, self.bios_dir, output_dir,
|
||||||
|
system_filter=["system-a"],
|
||||||
|
)
|
||||||
|
self.assertIsNotNone(zip_path)
|
||||||
|
with zipfile.ZipFile(zip_path) as zf:
|
||||||
|
names = zf.namelist()
|
||||||
|
self.assertTrue(any("present_req.bin" in n for n in names))
|
||||||
|
self.assertFalse(any("present_opt.bin" in n for n in names))
|
||||||
|
|
||||||
|
def test_133_platform_system_filter_normalized(self):
|
||||||
|
"""_norm_system_id normalization matches with manufacturer prefix."""
|
||||||
|
from common import _norm_system_id
|
||||||
|
self.assertEqual(
|
||||||
|
_norm_system_id("sony-playstation"),
|
||||||
|
_norm_system_id("playstation"),
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_134_list_systems_platform_context(self):
|
||||||
|
"""list_platform_system_ids lists systems from a platform YAML."""
|
||||||
|
from common import list_platform_system_ids
|
||||||
|
import io
|
||||||
|
config = {
|
||||||
|
"platform": "ListSysTest",
|
||||||
|
"verification_mode": "existence",
|
||||||
|
"systems": {
|
||||||
|
"alpha-sys": {
|
||||||
|
"files": [
|
||||||
|
{"name": "a.bin", "destination": "a.bin"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"beta-sys": {
|
||||||
|
"files": [
|
||||||
|
{"name": "b1.bin", "destination": "b1.bin"},
|
||||||
|
{"name": "b2.bin", "destination": "b2.bin"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
with open(os.path.join(self.platforms_dir, "test_listsys.yml"), "w") as fh:
|
||||||
|
yaml.dump(config, fh)
|
||||||
|
captured = io.StringIO()
|
||||||
|
old_stdout = sys.stdout
|
||||||
|
sys.stdout = captured
|
||||||
|
try:
|
||||||
|
list_platform_system_ids("test_listsys", self.platforms_dir)
|
||||||
|
finally:
|
||||||
|
sys.stdout = old_stdout
|
||||||
|
output = captured.getvalue()
|
||||||
|
self.assertIn("alpha-sys", output)
|
||||||
|
self.assertIn("beta-sys", output)
|
||||||
|
self.assertIn("1 file", output)
|
||||||
|
self.assertIn("2 files", output)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user