chore: merge line mode on shared decisions

This commit is contained in:
Abdessamad Derraz committed 2026-10-27 13:02:52 +01:00
commit 40fca7fb1a
32 files changed
+2303 -422

No files matched your search

+1 -1
View File
@@ -11,7 +11,7 @@
$ErrorActionPreference = "Stop"
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
$defaultInstallSha256 = "cc940a96dea46fb43d3940a13fddb4c9f1c02b8d81d1c810bcbddd5120143ce4"
$defaultInstallSha256 = "71fa422aa38f9710c9aab81ba038cad71df66f574a527dc62e0307c69c30d1b0"
$maximumInstallerBytes = 2MB
$installerExit = 0
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
+1066 -293
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -18,7 +18,7 @@ esac
TEMP_INSTALLER=""
TEMP_DIRECTORY=""
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
DEFAULT_INSTALL_SHA256="cc940a96dea46fb43d3940a13fddb4c9f1c02b8d81d1c810bcbddd5120143ce4"
DEFAULT_INSTALL_SHA256="71fa422aa38f9710c9aab81ba038cad71df66f574a527dc62e0307c69c30d1b0"
MAX_INSTALLER_BYTES=2097152
cleanup() {
+8 -8
View File
@@ -27,8 +27,8 @@
{
"dest": "roms/ports/retrobios/install.py",
"repo_path": "install.py",
"size": 735645,
"sha256": "cc940a96dea46fb43d3940a13fddb4c9f1c02b8d81d1c810bcbddd5120143ce4",
"size": 775811,
"sha256": "71fa422aa38f9710c9aab81ba038cad71df66f574a527dc62e0307c69c30d1b0",
"executable": false
},
{
@@ -71,8 +71,8 @@
"muos": {
"archive": {
"dest": "ARCHIVE/RetroBIOS.muxapp",
"size": 788194,
"sha256": "3a9bc441d4178cc15833dc8a3f28877370b4075a05131d209208186247756cc7"
"size": 828360,
"sha256": "dc3204c1dab8db00fb10e47cb9d2cad8ad6320b9d5c7d8fff9168c238620d5ef"
},
"members": [
{
@@ -92,8 +92,8 @@
{
"name": "RetroBIOS/install.py",
"repo_path": "install.py",
"size": 735645,
"sha256": "cc940a96dea46fb43d3940a13fddb4c9f1c02b8d81d1c810bcbddd5120143ce4",
"size": 775811,
"sha256": "71fa422aa38f9710c9aab81ba038cad71df66f574a527dc62e0307c69c30d1b0",
"executable": false
},
{
@@ -166,8 +166,8 @@
{
"dest": ".config/modules/retrobios/install.py",
"repo_path": "install.py",
"size": 735645,
"sha256": "cc940a96dea46fb43d3940a13fddb4c9f1c02b8d81d1c810bcbddd5120143ce4",
"size": 775811,
"sha256": "71fa422aa38f9710c9aab81ba038cad71df66f574a527dc62e0307c69c30d1b0",
"executable": false
},
{
+27
View File
@@ -15,6 +15,7 @@
"detect",
"error",
"scanned",
"choices",
"file",
"system",
"checking",
@@ -50,6 +51,9 @@
{
"$ref": "#/$defs/scanned"
},
{
"$ref": "#/$defs/choices"
},
{
"$ref": "#/$defs/file"
},
@@ -240,6 +244,29 @@
}
}
},
"choices": {
"type": "object",
"additionalProperties": false,
"required": [
"event",
"platform",
"systems"
],
"properties": {
"event": {
"const": "choices"
},
"platform": {
"type": "string"
},
"systems": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"file": {
"type": "object",
"additionalProperties": false,
+8 -2
View File
@@ -22,7 +22,8 @@
"md5": { "type": "string", "pattern": "^[a-f0-9]{32}$" },
"size": { "type": "integer", "minimum": 0 },
"status": { "enum": ["verified", "verified_md5", "verified_rebuild", "verified_data", "verified_members", "untracked"] },
"name": { "type": "string" }
"name": { "type": "string" },
"systems": { "type": "array", "items": { "type": "string", "minLength": 1 } }
}
}
},
@@ -37,6 +38,11 @@
"errors": { "type": "integer", "minimum": 0 }
}
},
"errors": { "type": "array", "items": { "type": "string" } }
"errors": { "type": "array", "items": { "type": "string" } },
"system_titles": { "type": "object", "additionalProperties": { "type": "string" } },
"system_names": {
"type": "object",
"additionalProperties": { "type": "array", "items": { "type": "string" } }
}
}
}
+2 -1
View File
@@ -170,7 +170,8 @@ def render(page: str) -> str:
if name not in writers:
raise MissingProse(f"no table is written for the marker {name!r}")
seen.append(name)
return f"{match.group('open')}\n{writers[name](match.group('body'))}\n{match.group('close')}"
table = writers[name](match.group("body"))
return f"{match.group('open')}\n{table}\n{match.group('close')}"
text = BLOCK.sub(write, page)
absent = sorted(set(writers) - set(seen))
+55
View File
@@ -2802,6 +2802,10 @@ def _run_platform_packs(
) -> None:
"""Generate ZIP packs for platform groups and verify."""
variants = ALL_VARIANTS if args.all_variants else ((args.source, args.required_only),)
registry_path = os.path.join(args.platforms_dir, "_registry.yml")
# Per pack, the systems each of its files is for, written into its
# manifest.json once the pack is verified (pack_systems).
systems_for: dict[str, dict] = {}
failed: list[str] = []
for source, required_only in variants:
@@ -2902,6 +2906,20 @@ def _run_platform_packs(
# the output directory already held and exit 0.
if not _produced(args.split, zip_path, zip_paths):
failed.append(representative)
elif zip_path and not system_filter:
# The install list of the same choices names each file's
# systems: the pack records them, so a pack alone (a
# handheld without Wi-Fi) can be narrowed by system.
systems_for[os.path.basename(zip_path)] = pack_systems(generate_manifest(
representative, args.platforms_dir, db, args.bios_dir,
registry_path, emulators_dir=args.emulators_dir,
zip_contents=zip_contents, emu_profiles=emu_profiles,
target_cores=tc, source=source,
regions=getattr(args, "regions", None), target_name=named_target,
offline=args.offline, required_only=required_only,
data_registry=data_registry,
no_game_data=getattr(args, "no_game_data", False),
))
print("\nVerifying packs and generating manifests...")
skip_conf = bool(system_filter or args.split)
@@ -2910,6 +2928,7 @@ def _run_platform_packs(
db,
platforms_dir=args.platforms_dir,
emulators_dir=args.emulators_dir,
pack_systems_by_name=systems_for,
skip_conformance=skip_conf,
data_registry=data_registry,
regions=getattr(args, "regions", None),
@@ -4731,6 +4750,37 @@ def _manifest_core_index(
def pack_systems(install_manifest: dict) -> dict:
"""What a pack's manifest.json records of its systems, from the install
list built with the same choices: each file's systems, by its path in
the pack, and the names a person reads for them.
A pack recorded none: the installer refused --system with a pack alone
("the file list comes from an older release") and offered no Choose
systems, the route of a handheld without Wi-Fi.
"""
return {
"files": {entry["dest"]: list(entry.get("systems") or [])
for entry in install_manifest.get("files", []) if "systems" in entry},
"system_titles": dict(install_manifest.get("system_titles") or {}),
"system_names": dict(install_manifest.get("system_names") or {}),
}
def annotate_pack_systems(manifest: dict, systems: dict | None) -> None:
"""Write pack_systems into a pack's manifest: a systems list on each
file the install list names, the titles and names beside."""
if not systems:
return
for entry in manifest.get("files", []):
held = systems["files"].get(entry["path"])
if held is not None:
entry["systems"] = held
for key in ("system_titles", "system_names"):
if systems.get(key):
manifest[key] = systems[key]
def inject_manifest(zip_path: str, manifest: dict) -> None:
"""Inject manifest.json into an existing ZIP pack.
@@ -4952,9 +5002,13 @@ def verify_and_finalize_packs(
target_name: str | None = None,
emulators_dir: str = "emulators",
no_game_data: bool = False,
pack_systems_by_name: dict[str, dict] | None = None,
) -> bool:
"""Verify all packs, inject manifests, generate SHA256SUMS.
pack_systems_by_name gives, per pack file name, the systems its
manifest.json records (pack_systems).
Two-stage verification:
1. Hash check against database.json (integrity)
2. Extract + verify against platform config (conformance)
@@ -4994,6 +5048,7 @@ def verify_and_finalize_packs(
print(f" ERROR: {err}")
all_ok = False
failing.append(name)
annotate_pack_systems(manifest, (pack_systems_by_name or {}).get(name))
inject_manifest(zip_path, manifest)
# Stage 2: platform conformance (extract + verify)
+1 -1
View File
@@ -4,7 +4,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B, Ctrl-C or Start+Select stops. What is done stays done.
B, Ctrl-C or Select+Start stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
+1 -1
View File
@@ -4,7 +4,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B, Ctrl-C or Start+Select stops. What
B, Ctrl-C or Select+Start stops. What
is done stays done.
FAILED scph5500.bin (HTTP 404)
+1 -1
View File
@@ -4,7 +4,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B, Ctrl-C or Start+Select stops. What
B, Ctrl-C or Select+Start stops. What
is done stays done.
FAILED scph5500.bin (HTTP 404)
+1 -1
View File
@@ -4,7 +4,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B, Ctrl-C or Start+Select stops. What is done stays done.
B, Ctrl-C or Select+Start stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
+1 -1
View File
@@ -37,4 +37,4 @@
A/Enter Back Up/Down Scroll
A/Enter Back
+1 -1
View File
@@ -9,4 +9,4 @@
missing 16.0 KB gba_bios.bin
A/Enter Back Up/Down Scroll
A/Enter Back
+1 -1
View File
@@ -12,4 +12,4 @@
A/Enter Back Up/Down Scroll
A/Enter Back
+1 -1
View File
@@ -21,4 +21,4 @@
A/Enter Back Up/Down Scroll
A/Enter Back
+1 -1
View File
@@ -37,4 +37,4 @@
A/Enter Exit Up/Down Scroll
A/Enter Exit
+1 -1
View File
@@ -21,4 +21,4 @@
A/Enter Exit Up/Down Scroll
A/Enter Exit
+6 -6
View File
@@ -766,7 +766,7 @@
missing 16.0 KB gba_bios.bin
A Back Up/Down Scroll
A Back
=== preview 40x15
RetroBIOS: Preview
@@ -782,7 +782,7 @@
A Back Up/Down Scroll
A Back
=== preview 80x24
RetroBIOS: Preview
@@ -807,7 +807,7 @@
A Back Up/Down Scroll
A Back
=== command 40x12
RetroBIOS: Command line
@@ -982,7 +982,7 @@
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit Up/Down Scroll
A Exit
=== result 40x15
RetroBIOS: Finished with errors
@@ -998,7 +998,7 @@
A Exit Up/Down Scroll
A Exit
=== result 80x24
RetroBIOS: Finished with errors
@@ -1023,7 +1023,7 @@
A Exit Up/Down Scroll
A Exit
=== error 40x12
RetroBIOS: Something went wrong
+12 -12
View File
@@ -388,7 +388,7 @@
Start+Select Quit B Quit
Select+Start Quit B Quit
=== checking 40x15
RetroBIOS: Checking
@@ -404,7 +404,7 @@
Start+Select Quit B Quit
Select+Start Quit B Quit
=== checking 80x24
RetroBIOS: Checking
@@ -429,7 +429,7 @@
Start+Select Quit B Quit
Select+Start Quit B Quit
=== plan 40x12
RetroBIOS: RetroArch
@@ -766,7 +766,7 @@
missing 16.0 KB gba_bios.bin
A Back Up/Down Scroll
A Back
=== preview 40x15
RetroBIOS: Preview
@@ -782,7 +782,7 @@
A Back Up/Down Scroll
A Back
=== preview 80x24
RetroBIOS: Preview
@@ -807,7 +807,7 @@
A Back Up/Down Scroll
A Back
=== command 40x12
RetroBIOS: Command line
@@ -923,7 +923,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B or Start+Select stops. What is done
B or Select+Start stops. What is done
stays done.
FAILED scph5500.bin (HTTP 404)
@@ -936,7 +936,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B or Start+Select stops. What is done
B or Select+Start stops. What is done
stays done.
FAILED scph5500.bin (HTTP 404)
@@ -952,7 +952,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B or Start+Select stops. What is done stays done.
B or Select+Start stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -982,7 +982,7 @@
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit Up/Down Scroll
A Exit
=== result 40x15
RetroBIOS: Finished with errors
@@ -998,7 +998,7 @@
A Exit Up/Down Scroll
A Exit
=== result 80x24
RetroBIOS: Finished with errors
@@ -1023,7 +1023,7 @@
A Exit Up/Down Scroll
A Exit
=== error 40x12
RetroBIOS: Something went wrong
+12 -12
View File
@@ -388,7 +388,7 @@
Start+Select Quit B Quit
Select+Start Quit B Quit
=== checking 40x15
RetroBIOS: Checking
@@ -404,7 +404,7 @@
Start+Select Quit B Quit
Select+Start Quit B Quit
=== checking 80x24
RetroBIOS: Checking
@@ -429,7 +429,7 @@
Start+Select Quit B Quit
Select+Start Quit B Quit
=== plan 40x12
RetroBIOS: RetroArch
@@ -766,7 +766,7 @@
missing 16.0 KB gba_bios.bin
A Back Up/Down Scroll
A Back
=== preview 40x15
RetroBIOS: Preview
@@ -782,7 +782,7 @@
A Back Up/Down Scroll
A Back
=== preview 80x24
RetroBIOS: Preview
@@ -807,7 +807,7 @@
A Back Up/Down Scroll
A Back
=== command 40x12
RetroBIOS: Command line
@@ -923,7 +923,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B or Start+Select stops. What is done
B or Select+Start stops. What is done
stays done.
FAILED scph5500.bin (HTTP 404)
@@ -936,7 +936,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B or Start+Select stops. What is done
B or Select+Start stops. What is done
stays done.
FAILED scph5500.bin (HTTP 404)
@@ -952,7 +952,7 @@
528.0 KB of 1.0 MB
128.9 KB/s, 0:04 left
2 of 4 files
B or Start+Select stops. What is done stays done.
B or Select+Start stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -982,7 +982,7 @@
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit Up/Down Scroll
A Exit
=== result 40x15
RetroBIOS: Finished with errors
@@ -998,7 +998,7 @@
A Exit Up/Down Scroll
A Exit
=== result 80x24
RetroBIOS: Finished with errors
@@ -1023,7 +1023,7 @@
A Exit Up/Down Scroll
A Exit
=== error 40x12
RetroBIOS: Something went wrong
+4 -4
View File
@@ -712,7 +712,7 @@
missing 16.0 KB gba_bios.bin
Enter Back Up/Down Scroll
Enter Back
=== preview 40x15
RetroBIOS: Preview
@@ -728,7 +728,7 @@
Enter Back Up/Down Scroll
Enter Back
=== preview 80x24
RetroBIOS: Preview
@@ -753,7 +753,7 @@
Enter Back Up/Down Scroll
Enter Back
=== command 40x12
RetroBIOS: Command line
@@ -969,7 +969,7 @@
Enter Exit Up/Down Scroll
Enter Exit
=== error 40x12
RetroBIOS: Something went wrong
+6 -6
View File
@@ -766,7 +766,7 @@
missing 16.0 KB gba_bios.bin
A Back Up/Down Scroll
A Back
=== preview 40x15
RetroBIOS: Preview
@@ -782,7 +782,7 @@
A Back Up/Down Scroll
A Back
=== preview 80x24
RetroBIOS: Preview
@@ -807,7 +807,7 @@
A Back Up/Down Scroll
A Back
=== command 40x12
RetroBIOS: Command line
@@ -982,7 +982,7 @@
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit Up/Down Scroll
A Exit
=== result 40x15
RetroBIOS: Finished with errors
@@ -998,7 +998,7 @@
A Exit Up/Down Scroll
A Exit
=== result 80x24
RetroBIOS: Finished with errors
@@ -1023,7 +1023,7 @@
A Exit Up/Down Scroll
A Exit
=== error 40x12
RetroBIOS: Something went wrong
+6 -6
View File
@@ -766,7 +766,7 @@
missing 16.0 KB gba_bios.bin
Start Back Up/Down Scroll
Start Back
=== preview 40x15
RetroBIOS: Preview
@@ -782,7 +782,7 @@
Start Back Up/Down Scroll
Start Back
=== preview 80x24
RetroBIOS: Preview
@@ -807,7 +807,7 @@
Start Back Up/Down Scroll
Start Back
=== command 40x12
RetroBIOS: Command line
@@ -982,7 +982,7 @@
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Start Exit Up/Down Scroll
Start Exit
=== result 40x15
RetroBIOS: Finished with errors
@@ -998,7 +998,7 @@
Start Exit Up/Down Scroll
Start Exit
=== result 80x24
RetroBIOS: Finished with errors
@@ -1023,7 +1023,7 @@
Start Exit Up/Down Scroll
Start Exit
=== error 40x12
RetroBIOS: Something went wrong
+5 -2
View File
@@ -3946,8 +3946,8 @@ class PlatformsAreNamedAsTheyNameThemselves(unittest.TestCase):
contextlib.redirect_stdout(out):
install._prompt_platform_choice(
[("misterfpga", Path("/m")), ("retrodeck", Path("/r"))])
self.assertIn("MiSTer FPGA (/m)", out.getvalue())
self.assertIn("RetroDECK (/r)", out.getvalue())
self.assertIn("MiSTer FPGA: /m", out.getvalue())
self.assertIn("RetroDECK: /r", out.getvalue())
self.assertEqual(install.display_name("romm", {"display_name": "RomM"}), "RomM")
self.assertEqual(install.display_name("romm", {"display_name": "\x1b[2J"}), "RomM")
@@ -5177,6 +5177,9 @@ class EventsDescribeTheRun(unittest.TestCase, _SyntheticTree):
{"event": "detect", "os": "linux", "os_name": install._os_name(),
"platforms": [{"platform": "retroarch", "name": "RetroArch",
"bios_dir": str(self.bios)}]},
# The systems Choose systems lists, before the files are read.
{"event": "choices", "platform": "retroarch",
"systems": ["sys-a", "sys-b", "other"]},
# a.bin and b.bin are in place: the first read and the last.
{"event": "checking", "files_done": 1, "files_total": 2},
{"event": "checking", "files_done": 2, "files_total": 2},
+2 -2
View File
@@ -479,12 +479,12 @@ class TheOneLinerReadsInstalledCores(unittest.TestCase):
command = " ".join(shlex.quote(part) for part in repo.command())
proc = subprocess.run(
["script", "-qec", command, "/dev/null"],
input="i\n", env=repo.env(), capture_output=True,
input="i\n\n", env=repo.env(), capture_output=True,
text=True, timeout=60, check=False,
)
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
self.assertIn("i) only what the installed cores read: 2 files", proc.stdout)
self.assertIn("--platform retroarch --installed-cores", proc.stdout)
self.assertRegex(proc.stdout, r"--platform retroarch --dest \S+ --installed-cores")
self.assertEqual(repo.installed(), ["gba_bios.bin", "mgba/extra.bin"])
+3 -3
View File
@@ -421,7 +421,7 @@ class ACoreWithNoFileOfItsOwn(unittest.TestCase):
self.assertIn("1 file, 9 B", self._line(out.getvalue(), "duckstation"))
def test_the_cores_step_says_so_too(self):
answers = iter(["c", "", ""])
answers = iter(["c", "", "", ""])
out = io.StringIO()
with mock.patch("builtins.input", lambda _prompt="": next(answers)), \
contextlib.redirect_stdout(out):
@@ -458,7 +458,7 @@ class FilesSharedBySystemsAreCountedApart(unittest.TestCase):
self.assertTrue(lines["nintendo-gba"].endswith("1 file, 8 B"))
def test_the_systems_step(self):
answers = iter(["c", ""])
answers = iter(["c", "", ""])
out = io.StringIO()
with mock.patch("builtins.input", lambda _prompt="": next(answers)), \
contextlib.redirect_stdout(out):
@@ -680,7 +680,7 @@ class TheOneLinerNarrows(unittest.TestCase):
command = " ".join(shlex.quote(part) for part in repo.command())
proc = subprocess.run(
["script", "-qec", command, "/dev/null"],
input="c\n2\n\n2\n", env=repo.env(), capture_output=True,
input="c\n2\n\n2\n\n", env=repo.env(), capture_output=True,
text=True, timeout=60, check=False,
)
out = proc.stdout
+1042 -36
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -301,7 +301,7 @@ class TroubleshootingLines(unittest.TestCase):
def test_the_installer_names_what_to_run(self):
source = (REPO_ROOT / "install.py").read_text(encoding="utf-8")
advice = source[source.index("def _write_advice"):source.index("def _plural")]
self.assertIn("_INVOCATION.command(plat, path, elevated=True)", advice)
self.assertIn("hint.command(plat, path, elevated=True)", advice)
class DiagramText(unittest.TestCase):
+2 -1
View File
@@ -182,7 +182,8 @@ class FaqInstallsFromWhatYouHold(unittest.TestCase):
with self.subTest(card=name):
self.assertIn(name, known)
source = (REPO_ROOT / "install.py").read_text(encoding="utf-8")
self.assertIn('f"{card[2]} SD card ({_mount_name(mount)})"', source)
self.assertIn('f"{card[2]} {kind} ({_mount_name(mount)})"', source)
self.assertIn('else "SD card"', source)
def test_a_wiped_card_links_the_copy(self):
section = self._section("Lost or wiped card?")
+1 -1
View File
@@ -65,7 +65,7 @@ class NoSetupFoundGivesEachSystemItsFolder(unittest.TestCase):
def test_the_label_is_the_installer_message(self):
self.assertIn("**`No supported platform detected`:**", self.section)
self.assertIn('print(" No supported platform detected.")', INSTALL_PY)
self.assertIn('else " No supported platform detected.")', INSTALL_PY)
def test_the_lead_names_the_menu(self):
self.assertIn("Not sure? Open RetroArch's **Settings > Directory > System/BIOS**",
+23 -14
View File
@@ -177,7 +177,7 @@ install starts.
| Options | `o`, Tab | Y |
| Filter a long list | `/` then type, Enter on a lone match chooses it | muxterm: Select shows a keyboard. Elsewhere none (the setup list puts the SD cards after RetroArch) |
| Keys of the screen | `?`, F1 | |
| Stop an install | Esc, `q`, Ctrl+C | B, Start+Select (B alone with muxterm's own keys) |
| Stop an install | Esc, `q`, Ctrl+C | B, Select+Start (B alone with muxterm's own keys) |
| Quit | `q`, Ctrl+C | B on the first screen |
| Pause, back with `fg` (Linux, macOS) | Ctrl+Z | |
@@ -193,7 +193,7 @@ on a console no launcher named, it gives both spellings (`A/Enter`, `B/Esc`),
and a narrow screen shortens them to `A`, `B` and `X`. On the
regions screen, Left and Right move the region under the cursor up and down the
order of preference. During the download, a stop waits for the files in
progress, and a second one stops at once. Start+Select on a handheld ends the
progress, and a second one stops at once. Select+Start on a handheld ends the
installer with a signal (SIGTERM), which stops it the same way. Either way the
result says how many files were installed, and it stays printed in the terminal
once the screen closes, with the command that repeats the run. A run that failed
@@ -329,7 +329,7 @@ command never writes one.
```
RetroBIOS 8c0e9c762d2f
Detecting platform...
Looking for setups here...
Found Batocera at /userdata/bios
```
@@ -600,9 +600,11 @@ same choice comes as questions after detection:
```
RetroArch: 8069 files, 6.5 GB.
BIOS folder: /home/me/.config/retroarch/system
Enter) install everything
i) only what the installed cores read: 100 files, 44.2 MB
c) choose systems, cores and regions
f) copy from a folder or an old card
q) quit
```
@@ -615,10 +617,12 @@ the rule `--installed-cores` applies.
`c` walks through three numbered lists, each answered with numbers such as
`1,4,7-9`, or Enter to keep everything on that axis.
- **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.
- **Systems.** The consoles and computers the platform declares, titled and
ordered as the full screen's Choose systems lists them, the id `--system`
takes after each title. A last entry, `Other systems and game engines`,
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
kept. This narrows only the extra files each emulator core loads beyond it.
Asked only when the chosen systems have such files.
@@ -626,9 +630,12 @@ the rule `--installed-cores` applies.
numbers give an order of preference: `2,1` keeps the second region where a
file for it exists, and the first one elsewhere.
The run then prints the options that repeat the same choice without
questions, for instance
`--platform retroarch --system sony-playstation --region north-america`.
Nothing is written yet: the menu comes back counted for the choice, as the
full screen's Confirm does, with the command that makes the same choice
without questions, every other option of the run in it, for instance
`python3 install.py --platform retroarch --dest /home/me/.config/retroarch/system
--system sony-playstation --region north-america`. Enter then installs, and
`c` chooses again.
The same choices on the command line:
@@ -742,7 +749,7 @@ what the options name, everything by default.
| <span id="option-no-input"></span>`--no-input` | Never ask a question, even at a terminal. A run whose output goes to a file or a pipe asks nothing either, and says so on stderr |
| <span id="option-check"></span>`--check` | Report and exit without writing |
| <span id="option-dry-run"></span>`--dry-run` | Show what would be downloaded, the totals first, then by system and with sizes, without writing anything. A plan taller than the screen names the ten largest systems, and `--verbose` lists every system and file |
| <span id="option-yes"></span>`--yes`, `-y` | Do not ask before a download of 1 GB or more |
| <span id="option-yes"></span>`--yes`, `-y` | Do not ask before a download of 1 GB or more, nor anything else. Implies `--no-input`, so a run that needs an answer (nothing found here, two setups found) stops on what to name instead |
| <span id="option-quiet"></span>`--quiet`, `-q` | Print only failures and the final summary. Implies `--no-input` |
| <span id="option-events"></span>`--events` | Write the run as JSON events on standard output, one object per line, and the usual text on standard error. Implies `--no-input`. See [Machine-readable events](#machine-readable-events) |
| <span id="option-from"></span>`--from FOLDER` | Copy the BIOS files a folder holds (an old SD card, a backup, a ZIP) instead of downloading them, each one recognised by its hash and copied, never moved. Repeat for several folders. See [Copy from an old card](#copy-from-an-old-card) |
@@ -1212,7 +1219,7 @@ gets the column that names both:
| Options | o, Tab | Y, o, Tab | Y, Tab, o | Y, Tab, o | o, Tab | Y, Tab, o | L2, Tab, o |
| Back, and quit on the first screen | Esc, Backspace | B/Esc, Backspace | B, Select, Esc | B, Select, Esc | B, Esc, Backspace | B, Select, Esc | R2, Esc, Backspace |
| Stop an install | Esc, Ctrl-C | B/Esc, Ctrl-C | B, Esc, Ctrl-C | B, Esc, Ctrl-C | B, Esc, Ctrl-C | B, Esc, Ctrl-C | R2, Esc, Ctrl-C |
| Quit at once | none | Start+Select | Select, then Start | Select, then Start | none | none | none |
| Quit at once | none | Select+Start | Select, then Start | Select, then Start | none | none | none |
| Use the folder typed | Enter | Enter | A, Enter | A, Enter | Start, Enter | A, Enter | Start, Enter |
| Clear a filter, leave the folder typed | Esc | Esc | B, Esc | B, Esc | Esc | B, Esc | Esc |
@@ -1417,7 +1424,7 @@ fields, the installer refuses to narrow rather than install everything.
<!-- /generated: exit-codes -->
The full screen ended by SIGTERM (Start+Select on a handheld) before any
The full screen ended by SIGTERM (Select+Start on a handheld) before any
install exits `143`. During an install it stops the install first, and exits
`130`. Its window or terminal closed (SIGHUP) exits `129`, during an install
too: the install is stopped as Ctrl+C stops it, and the last lines go
@@ -1459,6 +1466,7 @@ other schemas under `api/v1/schemas/`.
| `detect` | `os`, `os_name`, `platforms` | Once the platforms are known. `os_name` comes from `/etc/os-release`. `platforms` lists `{platform, name, bios_dir}`, and is empty when nothing supported was found |
| `error` | `stage`, `reason`, `platform`, `message` | The file list could not be read (`stage` is `manifest`): `reason` is `network`, `not_found` or `invalid`, `clock` when the server's certificate was refused and the system clock reads a date before the installer was written, `no_ca` when the machine holds no list of trusted certificates (`SSL_CERT_FILE` names one), or `offline` when `--offline` forbids the request. A folder named with `--from` cannot be read (`stage` is `from`, `reason` `not_found`, `not_a_folder` for a file that is no ZIP, `unreadable`, or `system` for the root of the system, `/proc`, `/sys` or `/dev`). The BIOS folder sits under a folder this user cannot open (`stage` is `dest`, `reason` `unreadable`), and the run ends with code 1 before anything is written. The BIOS folder cannot be created (`stage` is `dest`, `reason` `not_writable`): a `summary` follows with what the run installed before it. Two systems are detected on one machine and no `--dest` names the folder (`stage` is `detect`, `reason` `conflict`). The platform named with `--platform` is found nowhere and no folder can be assumed for it: a card system with no card named, a portable emulator, Batocera or Recalbox named on a computer (their folder is the `bios` folder of their SHARE drive), or no usual folder on this system or one set aside behind a folder this user cannot open (`stage` is `detect`, `reason` `not_found`). A `--dest` refused as the card of the system named carries the same `stage` and `reason`: another system's card, a folder inside a card, a drive with none of the files its card always has, or a folder that does not exist. `message` says it in words, and is the only thing that tells these cases apart |
| `scanned` | `folder`, `files`, `truncated`, `other_drives` | Each folder named with `--from`, once read and before `detect`. `files` counts the files found, `truncated` is true when the search stopped at 200,000 of them, and `other_drives` lists the folders below it on another drive, which were not entered |
| `choices` | `platform`, `systems` | Before `checking`: the systems the run's list lets one choose among, sorted by id, `other` last for the files no system names. The run's other options apply (`--core`, `--region`, `--no-game-data`, the files left out for an unknown save directory), `--system` does not: these are the systems a screen lists to choose from, and the count a `--system` is out of |
| `file` | `platform`, `dest`, `systems`, `size`, `state` | Each file of the list after the check. `state` is `present` (hash verified), `wrong_hash` or `missing` |
| `system` | `platform`, `system`, `name`, `files`, `present`, `missing`, `wrong_hash`, `bytes_needed` | Each system, sorted by id, and with `--system` only the systems named. Files with no system count under `other`. `name` is the platform's own name for it |
| `checking` | `files_done`, `files_total` | While the files already in the folder are read and hashed, at most every half second and once at the end. `files_total` counts the files found in place |
@@ -1467,7 +1475,7 @@ other schemas under `api/v1/schemas/`.
| `data` | `platform`, `files`, `bytes` | Right after `declared`: the data-tree files to fetch (the `data_missing` of `check`) and the bytes they write once in place |
| `found` | `platform`, `dest`, `folder`, `path`, `member`, `reason` | Each file to install that this machine already holds, after `check` and before anything is written, in `--check` and `--dry-run` too. `folder` is the `--from` folder as given, or the `bios_dir` of the check when the BIOS folder holds the file at another place, and then `reason` says where in words (`nested folder: ...` for a misplaced file, `the same file is at ...` for one the list installs there too). `path` is the file, and `member` the ZIP member holding the bytes when `path` is an archive, an empty string otherwise. Its copy is reported by a `downloaded` event |
| `unreadable` | `platform`, `folder`, `path`, `member`, `reason` | Each file in a `--from` folder that could not be read and may be one the run still needs, right after the `found` events: its size is that of a file no copy was found for, or unknown (a folder that could not be listed, a ZIP that would not open). `member` names the ZIP member, or is empty. `reason` says why in words (`Permission denied`, `it is encrypted, a password is needed`) |
| `saves` | `platform`, `files`, `folder` | After `detect` and before `checking`, when the list holds files read from the frontend's save directory and that directory is known: how many, and the `folder` they go to, where `<system>` and `<core>` stand for one folder per system or per core. When it is not known, the files are counted in the summary's `skipped` instead (`no_save_directory`) |
| `saves` | `platform`, `files`, `folder` | After `choices` and before `checking`, when the files the run installs (once `--system` and the other choices narrowed the list) hold some read from the frontend's save directory and that directory is known: how many, and the `folder` they go to, where `<system>` and `<core>` stand for one folder per system or per core. When it is not known, the files are counted in the summary's `skipped` instead (`no_save_directory`) |
| `download` | `platform`, `files`, `bytes` | Before the downloads start. Counts the files copied from this machine too |
| `progress` | `files_done`, `files_total`, `bytes_done`, `bytes_total` | At most every half second while bytes arrive |
| `transfer` | `bytes_local`, `bytes_network` | Right after each `progress` event, and once when the files of a `download` event are done. It splits `bytes_done`: `bytes_local` came from this machine (a copy found by `--from` or in the BIOS folder, the pack, a partial copy resumed), `bytes_network` from the network. A download speed is `bytes_network` over the time elapsed |
@@ -1509,6 +1517,7 @@ RetroArch folder that holds only `scph5501.bin`, in the order written:
| `RETROBIOS_INSTALL_SHA256` | The SHA-256 the bootstrap requires of that installer, 64 hex characters. When either of these two is set and the fingerprint does not match, the error names the variable instead of suggesting a retry |
| `RETROBIOS_BOOTSTRAP` | Set by `install.sh` (`sh`) and `install.ps1` (`ps1`) for the temporary installer they run, so that its hints give back the one-line command rather than `python3 install.py` |
| `NO_COLOR` | Plain text, no colour, even at a terminal, when set to any value but an empty one. `TERM=dumb`, or no `TERM` outside Windows, also turns the live progress line and the colour off, as does a terminal whose description moves no cursor the ANSI way (`TERM=vt52`). The full screen draws no colour at all: the row in focus is marked with `>` as well as reverse video, and every state is written in words |
| `TERM`, `TERMINFO`, `TERMINFO_DIRS` | Decide whether the full screen opens. `TERM` unset or `dumb` (outside Windows) gives the questions line by line. Otherwise the terminal's description is read where ncurses reads it: `TERMINFO`, then `~/.terminfo`, then each folder of `TERMINFO_DIRS`, then the system's own. A description whose cursor moves are not the ANSI ones the screen writes (`TERM=vt52`) gives the questions too, and `--tui` there stops with the reason |
| `FORCE_COLOR`, `CLICOLOR_FORCE` | Colour even when the output is a pipe or a file, set to any value but `0` or an empty one. `NO_COLOR` wins over both, and the progress line stays one line per file |
| `SSL_CERT_FILE`, `SSL_CERT_DIR` | The trusted certificates to check servers with, for a Python that finds none of its own |
| `RETROBIOS_PLAIN`, `ACCESSIBLE` | Set to anything but `0`: the questions come line by line, as with `--plain`, instead of the full-screen interface |