mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-20 10:23:16 -05:00
feat: install one emulator's files in one command
install.py --emulator NAME keeps what the named emulators read on the detected platform: their own files and the platform's files of the systems they run, as a pack built for them carries, without the systems no core is mapped to. Each emulator page now gives that command for Linux, macOS and Windows, beside the per-file links.
This commit is contained in:
1 parent
7c94a58825
commit
e424a35aee
7 files changed
+141
-2
No files matched your search
+1
-1
@@ -8,7 +8,7 @@ param(
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "300fcfd077c970a6807b2414b19cbae87b330664f3f7092d8275f5da2fe6e022"
|
||||
$defaultInstallSha256 = "6245355aa8a65872b761229f2429ca6e0953573f0b75f6f30286a2f067c83afd"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+55
@@ -3505,6 +3505,49 @@ def _older_list_advice() -> str:
|
||||
"installer again to fetch the current one.")
|
||||
|
||||
|
||||
def _narrow_to_emulators(
|
||||
names: list[str], manifest: dict, plat: str,
|
||||
files: list[dict], omitted: list[dict],
|
||||
) -> tuple[list[dict], list[dict]]:
|
||||
"""Keep what the named emulators read, as the pack built for them.
|
||||
|
||||
An emulator page offers this as one command, so a name the platform
|
||||
does not run is refused rather than read as nothing to install.
|
||||
"""
|
||||
if "system_cores" not in manifest:
|
||||
print(f"Error: the {plat} file list does not say which emulators read "
|
||||
"which systems, which --emulator needs.", file=sys.stderr)
|
||||
print(_older_list_advice(), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
known = sorted({
|
||||
name
|
||||
for profile, aliases in (manifest.get("core_names") or {}).items()
|
||||
for name in [profile, *aliases]
|
||||
} | set(available_choices(files, omitted)["cores"]))
|
||||
try:
|
||||
chosen = resolve_choices(names, known, "emulator")
|
||||
except ValueError as exc:
|
||||
print(f"Error: {plat}: {exc}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
before = len(files)
|
||||
files, omitted = narrow_to_cores(manifest, chosen, files, omitted)
|
||||
# A whole-platform install keeps the platform's files of a system no
|
||||
# core is mapped to. Here only the named emulators' systems are wanted.
|
||||
cores = designated_cores(manifest, chosen)
|
||||
reached = {
|
||||
system for system, readers in (manifest.get("system_cores") or {}).items()
|
||||
if cores.intersection(readers)
|
||||
}
|
||||
|
||||
def theirs(entry: dict) -> bool:
|
||||
return entry.get("cores") is not None or bool(reached.intersection(entry_systems(entry)))
|
||||
|
||||
files = [entry for entry in files if theirs(entry)]
|
||||
omitted = [entry for entry in omitted if theirs(entry)]
|
||||
print(f" Narrowed {before} -> {len(files)} files to {', '.join(chosen)}")
|
||||
return files, omitted
|
||||
|
||||
|
||||
def _requested_narrowing(
|
||||
args: argparse.Namespace, plat: str, files: list[dict], omitted: list[dict]
|
||||
) -> tuple[list[str], list[str], list[str]] | None:
|
||||
@@ -3588,6 +3631,13 @@ def main() -> None:
|
||||
action="store_true",
|
||||
help="opt in to copies into detected standalone-emulator directories",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--emulator",
|
||||
action="append",
|
||||
metavar="NAME",
|
||||
help="install what these emulators read on the platform, as a pack "
|
||||
"built for them carries (names: --list-cores)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--installed-cores",
|
||||
action="store_true",
|
||||
@@ -3946,6 +3996,11 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
|
||||
)
|
||||
print(f" Narrowed {before} -> {len(files)} files to the installed cores")
|
||||
|
||||
if args.emulator:
|
||||
files, omitted_files = _narrow_to_emulators(
|
||||
args.emulator, manifest, plat_name, files, omitted_files
|
||||
)
|
||||
|
||||
selection = _requested_narrowing(args, plat_name, files, omitted_files)
|
||||
if (
|
||||
selection is None
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ esac
|
||||
TEMP_INSTALLER=""
|
||||
TEMP_DIRECTORY=""
|
||||
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
DEFAULT_INSTALL_SHA256="300fcfd077c970a6807b2414b19cbae87b330664f3f7092d8275f5da2fe6e022"
|
||||
DEFAULT_INSTALL_SHA256="6245355aa8a65872b761229f2429ca6e0953573f0b75f6f30286a2f067c83afd"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -2969,6 +2969,37 @@ def _render_metadata_rows(profile: dict) -> list[str]:
|
||||
return lines
|
||||
|
||||
|
||||
def _install_block(name: str, profile: dict) -> list[str]:
|
||||
"""One command that installs this emulator's files where it reads them.
|
||||
|
||||
The installer finds the platform and its BIOS folder, then keeps what
|
||||
this emulator reads there: its own files and the platform's files of
|
||||
the systems it runs. Each file is also linked one by one below.
|
||||
"""
|
||||
if profile.get("type") in ("alias", "launcher", "test"):
|
||||
return []
|
||||
base = "https://raw.githubusercontent.com/Abdess/retrobios/main"
|
||||
return [
|
||||
'??? tip "Install this emulator\'s files"',
|
||||
"",
|
||||
" The installer finds your platform and its BIOS folder, then downloads "
|
||||
"only the files this emulator reads there and checks each one.",
|
||||
"",
|
||||
" Linux, macOS, Steam Deck:",
|
||||
"",
|
||||
" ```sh",
|
||||
f" curl -fsSL {base}/install.sh | sh -s -- --emulator {name}",
|
||||
" ```",
|
||||
"",
|
||||
" Windows (PowerShell):",
|
||||
"",
|
||||
" ```powershell",
|
||||
f" &([scriptblock]::Create((irm {base}/install.ps1))) --emulator {name}",
|
||||
" ```",
|
||||
"",
|
||||
]
|
||||
|
||||
|
||||
def _render_platform_details(profile: dict) -> list[str]:
|
||||
"""The per-platform block, one level of nesting deep."""
|
||||
lines: list[str] = []
|
||||
@@ -3287,6 +3318,8 @@ def generate_emulator_page(
|
||||
lines.append("</div>")
|
||||
lines.append("")
|
||||
|
||||
lines.extend(_install_block(name, profile))
|
||||
|
||||
lines.extend(_render_platform_details(profile))
|
||||
|
||||
lines.extend(_render_structured_blocks(profile))
|
||||
|
||||
@@ -2902,6 +2902,39 @@ class ARefusedStandaloneCopyIsNamed(unittest.TestCase):
|
||||
|
||||
|
||||
|
||||
class OneEmulatorsFilesInOneCommand(unittest.TestCase):
|
||||
"""An emulator page offers one command for that emulator's files.
|
||||
--core kept the platform's whole list, and narrowing to cores kept the
|
||||
platform files of every system no core is mapped to."""
|
||||
|
||||
MANIFEST = {
|
||||
"system_cores": {"ibm-pc": ["pcem"], "nintendo-nes": ["fceumm"]},
|
||||
"core_names": {"pcem": ["pcem"], "fceumm": ["fceumm"]},
|
||||
"files": [],
|
||||
}
|
||||
|
||||
def test_only_its_files_and_its_systems(self):
|
||||
import contextlib # noqa: PLC0415
|
||||
|
||||
files = [
|
||||
{"dest": "pcem/ibmpc.bin", "cores": ["pcem"], "systems": ["ibm-pc"]},
|
||||
{"dest": "disksys.rom", "cores": None, "systems": ["nintendo-nes"]},
|
||||
{"dest": "ep128emu/exos.rom", "cores": None, "systems": ["enterprise"]},
|
||||
{"dest": "ibm.rom", "cores": None, "systems": ["ibm-pc"]},
|
||||
]
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
kept, _omitted = install._narrow_to_emulators(
|
||||
["PCem"], self.MANIFEST, "retroarch", files, [])
|
||||
self.assertEqual(sorted(e["dest"] for e in kept), ["ibm.rom", "pcem/ibmpc.bin"])
|
||||
|
||||
def test_an_unknown_name_is_refused(self):
|
||||
import contextlib # noqa: PLC0415
|
||||
|
||||
with contextlib.redirect_stderr(io.StringIO()), self.assertRaises(SystemExit):
|
||||
install._narrow_to_emulators(["nope"], self.MANIFEST, "retroarch", [], [])
|
||||
|
||||
|
||||
|
||||
class ThePagesQuoteTheBootstrapsOwnWords(unittest.TestCase):
|
||||
"""The installer page and the FAQ quoted "install.py SHA-256 mismatch",
|
||||
a message the bootstraps no longer print."""
|
||||
|
||||
@@ -818,5 +818,22 @@ class ACardSaysWhyAFileIsLeftOut(unittest.TestCase):
|
||||
self.assertIn("installed with the standalone emulator", badges)
|
||||
|
||||
|
||||
class AnEmulatorPageOffersItsInstall(unittest.TestCase):
|
||||
"""An emulator page linked each file one by one and offered no way to
|
||||
install them together."""
|
||||
|
||||
def test_the_command_names_the_emulator(self):
|
||||
from generate_site import _install_block
|
||||
|
||||
text = "\n".join(_install_block("pcem", {"type": "libretro"}))
|
||||
self.assertIn("install.sh | sh -s -- --emulator pcem", text)
|
||||
self.assertIn("install.ps1))) --emulator pcem", text)
|
||||
self.assertEqual(_install_block("x", {"type": "alias"}), [])
|
||||
|
||||
def test_the_installer_takes_the_option(self):
|
||||
source = (ROOT / "install.py").read_text(encoding="utf-8")
|
||||
self.assertIn('"--emulator"', source)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -219,6 +219,7 @@ what the options name, everything by default.
|
||||
| `--installed-cores` | Keep only what the cores already installed read (RetroArch, Lakka, RetroPie). See [Installed cores](#installed-cores) |
|
||||
| `--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 |
|
||||
| `--emulator NAMES` | Install what these emulators read on the detected platform, and nothing else: their own files and the platform's files of the systems they run. Each emulator page on the site gives this command. `--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` |
|
||||
| `--list-systems` | Print a platform's systems with the files and size each holds |
|
||||
| `--list-cores` | Print the cores whose extra files a platform installs |
|
||||
|
||||
Reference in new issue
Block a user