feat: offer the files no platform system owns

This commit is contained in:
Abdessamad Derraz committed 2026-10-10 04:42:11 +02:00
1 parent 788a6dd4df
commit 6fca4149f5
5 files changed
+49 -14

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ param(
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" $defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
$defaultInstallSha256 = "a1bae5feab3e85224526eaab7ed99ae0d711081c925aa520d3768532cd11a797" $defaultInstallSha256 = "edc57fe82a964b271bdae9d20985421f7a6ba88859f9c6926f323c909ec2d651"
$maximumInstallerBytes = 2MB $maximumInstallerBytes = 2MB
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
$temporary = $null $temporary = $null
+28 -10
View File
@@ -130,6 +130,10 @@ _REGION_PARENT = {
REGIONS = frozenset({WORLD_REGION} | set(REGION_TREE) | set(_REGION_PARENT)) REGIONS = frozenset({WORLD_REGION} | set(REGION_TREE) | set(_REGION_PARENT))
MAX_SELECTION_TAGS = 1000 MAX_SELECTION_TAGS = 1000
SELECTION_FIELDS = ("systems", "regions", "region_groups", "region_system_groups") SELECTION_FIELDS = ("systems", "regions", "region_groups", "region_system_groups")
# The files cores load for systems the platform does not list (game engines,
# computers): no system of the platform owns them, and choosing systems
# leaves them out unless this name is chosen too.
OTHER_SYSTEMS = "other"
# Platforms with a manifest in install/. Manifest URLs are case sensitive, # Platforms with a manifest in install/. Manifest URLs are case sensitive,
# so user input is normalized against this list before any fetch. # so user input is normalized against this list before any fetch.
@@ -1153,11 +1157,12 @@ def region_drops(
def entry_systems(entry: dict) -> list[str]: def entry_systems(entry: dict) -> list[str]:
"""The systems a file serves: a list on files, one name on omissions.""" """The platform systems a file or an omission belongs to.
systems = entry.get("systems")
if systems: An omission's `system` is spelled the way its profile spells it; only
return list(systems) `systems` names the platform's own, the ones --system accepts.
return [entry["system"]] if entry.get("system") else [] """
return list(entry.get("systems") or [])
def narrow( def narrow(
@@ -1183,11 +1188,18 @@ def narrow(
omitted = [o for o in omitted if o["dest"] not in dropped] omitted = [o for o in omitted if o["dest"] not in dropped]
if systems: if systems:
wanted = set(systems) wanted = set(systems)
files = [f for f in files if wanted & set(entry_systems(f))] files = [f for f in files if _chosen(f, wanted)]
omitted = [o for o in omitted if wanted & set(entry_systems(o))] omitted = [o for o in omitted if _chosen(o, wanted)]
return files, omitted return files, omitted
def _chosen(entry: dict, wanted: set[str]) -> bool:
systems = entry_systems(entry)
if not systems:
return OTHER_SYSTEMS in wanted
return bool(wanted & set(systems))
def records_selection(files: list[dict]) -> bool: def records_selection(files: list[dict]) -> bool:
"""Whether a manifest carries what narrowing reads; older ones do not.""" """Whether a manifest carries what narrowing reads; older ones do not."""
return any("systems" in entry for entry in files) return any("systems" in entry for entry in files)
@@ -1196,13 +1208,16 @@ def records_selection(files: list[dict]) -> bool:
def available_choices(files: list[dict], omitted: list[dict]) -> dict[str, list[str]]: def available_choices(files: list[dict], omitted: list[dict]) -> dict[str, list[str]]:
"""The systems, cores and regions a manifest lets one narrow to.""" """The systems, cores and regions a manifest lets one narrow to."""
systems = {s for e in files + omitted for s in entry_systems(e)} systems = {s for e in files + omitted for s in entry_systems(e)}
ordered = sorted(systems)
if any(not entry_systems(f) for f in files):
ordered.append(OTHER_SYSTEMS)
cores = {c for f in files for c in (f.get("cores") or [])} cores = {c for f in files for c in (f.get("cores") or [])}
regions = { regions = {
r for e in files + omitted for r in (e.get("regions") or []) r for e in files + omitted for r in (e.get("regions") or [])
if r != WORLD_REGION if r != WORLD_REGION
} }
return { return {
"systems": sorted(systems), "systems": ordered,
"cores": sorted(cores), "cores": sorted(cores),
"regions": sorted(regions), "regions": sorted(regions),
} }
@@ -1812,8 +1827,11 @@ def _prompt_custom_selection(
break break
choices = available_choices(files, omitted) choices = available_choices(files, omitted)
if OTHER_SYSTEMS in choices["systems"]:
print(f"\n'{OTHER_SYSTEMS}' holds what cores load for systems this platform")
print("does not list, such as game engines and extra computers.")
systems = _pick("Systems:", [ systems = _pick("Systems:", [
(name, [f for f in files if name in entry_systems(f)]) (name, [f for f in files if _chosen(f, {name})])
for name in choices["systems"] for name in choices["systems"]
]) ])
kept, kept_omitted = narrow(files, omitted, systems, [], []) kept, kept_omitted = narrow(files, omitted, systems, [], [])
@@ -1866,7 +1884,7 @@ def _print_choices(
width = min(max(len(name) for name in names), 40) width = min(max(len(name) for name in names), 40)
for name in names: for name in names:
held = ( held = (
[f for f in files if name in entry_systems(f)] [f for f in files if _chosen(f, {name})]
if systems if systems
else [f for f in files if name in (f.get("cores") or [])] else [f for f in files if name in (f.get("cores") or [])]
) )
+1 -1
View File
@@ -18,7 +18,7 @@ esac
TEMP_INSTALLER="" TEMP_INSTALLER=""
TEMP_DIRECTORY="" TEMP_DIRECTORY=""
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
DEFAULT_INSTALL_SHA256="a1bae5feab3e85224526eaab7ed99ae0d711081c925aa520d3768532cd11a797" DEFAULT_INSTALL_SHA256="edc57fe82a964b271bdae9d20985421f7a6ba88859f9c6926f323c909ec2d651"
MAX_INSTALLER_BYTES=2097152 MAX_INSTALLER_BYTES=2097152
cleanup() { cleanup() {
+14
View File
@@ -106,6 +106,7 @@ class Narrowing(unittest.TestCase):
] ]
OMITTED = [ OMITTED = [
{"dest": "scph5502.bin", "name": "scph5502.bin", "system": "sony-playstation", {"dest": "scph5502.bin", "name": "scph5502.bin", "system": "sony-playstation",
"systems": ["sony-playstation"],
"required": True, "reason": "not_found", "cores": None, "required": True, "reason": "not_found", "cores": None,
"regions": ["europe"], "region_system_groups": ["sony-playstation"]}, "regions": ["europe"], "region_system_groups": ["sony-playstation"]},
] ]
@@ -143,6 +144,19 @@ class Narrowing(unittest.TestCase):
self.assertIn("scph5500.bin", files) self.assertIn("scph5500.bin", files)
self.assertIn("scph5501.bin", files) self.assertIn("scph5501.bin", files)
def test_other_holds_what_no_platform_system_owns(self):
files = [
{"dest": "pak0.pak", "size": 1, "cores": ["tyrquake"]},
{"dest": "gba_bios.bin", "size": 1, "cores": None,
"systems": ["nintendo-gba"]},
]
self.assertEqual(install.available_choices(files, [])["systems"],
["nintendo-gba", "other"])
kept, _ = install.narrow(files, [], ["nintendo-gba"], [], [])
self.assertEqual([f["dest"] for f in kept], ["gba_bios.bin"])
kept, _ = install.narrow(files, [], ["other"], [], [])
self.assertEqual([f["dest"] for f in kept], ["pak0.pak"])
def test_a_core_variant_competes_across_systems(self): def test_a_core_variant_competes_across_systems(self):
"""PicoDrive files its US Mega CD BIOS under sega-segacd and the EU """PicoDrive files its US Mega CD BIOS under sega-segacd and the EU
one under sega-mega-cd, one variant group. The pack groups every core one under sega-mega-cd, one variant group. The pack groups every core
+5 -2
View File
@@ -118,7 +118,10 @@ Retroarch: 5861 files, 6.0 GB.
`c` walks through three numbered lists, each answered with numbers such as `c` walks through three numbered lists, each answered with numbers such as
`1,4,7-9`, or Enter to keep everything on that axis. `1,4,7-9`, or Enter to keep everything on that axis.
- **Systems.** The consoles and computers the platform declares. - **Systems.** The consoles and computers the platform declares. A last
entry, `other`, holds what cores load for systems the platform does not
list, such as game engines and extra computers. Choosing systems leaves it
out unless it is chosen too, as `generate_pack.py --system` does.
- **Cores.** The platform's own BIOS list for the chosen systems is always - **Cores.** The platform's own BIOS list for the chosen systems is always
kept; this narrows only the extra files each emulator core loads beyond it. kept; this narrows only the extra files each emulator core loads beyond it.
Asked only when the chosen systems have such files. Asked only when the chosen systems have such files.
@@ -164,7 +167,7 @@ what the options name, everything by default.
| `--platform NAME` | Install for this platform instead of the detected one. Unknown names are refused with the available list | | `--platform NAME` | Install for this platform instead of the detected one. Unknown names are refused with the available list |
| `--dest PATH` | Destination directory, overriding detection. With `--dest` alone the file list is RetroArch's | | `--dest PATH` | Destination directory, overriding detection. With `--dest` alone the file list is RetroArch's |
| `--target NAME` | Keep only the files the cores of that hardware target need. An unknown target is refused rather than ignored, since carrying on would install everything | | `--target NAME` | Keep only the files the cores of that hardware target need. An unknown target is refused rather than ignored, since carrying on would install everything |
| `--system NAMES` | Install only these systems. Comma-separated or repeated; `--list-systems` prints the names | | `--system NAMES` | Install only these systems. Comma-separated or repeated; `--list-systems` prints the names, `other` included |
| `--core NAMES` | Keep the platform's own list and only the extra files these cores load; `--list-cores` prints the names | | `--core NAMES` | Keep the platform's own list and only the extra files these cores load; `--list-cores` prints the names |
| `--region LIST` | Preferred regions, best first (`us,eu,jp`): keep one BIOS per region where a system has several. Accepts the names and aliases of `generate_pack.py --region` | | `--region LIST` | Preferred regions, best first (`us,eu,jp`): keep one BIOS per region where a system has several. Accepts the names and aliases of `generate_pack.py --region` |
| `--list-systems` | Print a platform's systems with the files and size each holds | | `--list-systems` | Print a platform's systems with the files and size each holds |