feat: full screen keeps its notes on Details

The plan, Confirm and the result say what happens, its size, where and
the next step. Their counts, free space, backup and save notes, kinds,
reasons a file is left out, per-file failures and commands move to a
Details screen: d on the plan, Confirm and the result, the Details row
on the plan, Y, o or Tab on the result. Opened on the result, they are
also said in the terminal after Exit. Installing lists the files that
went well only with --verbose, and --verbose draws every line in place.
The log line reads Log: so that Details names one thing.

--check prints its count, the folder and the remedy in both modes, so
that --verbose prints every default line. Each golden screen gets a word
budget per size, and a test proves the screen and its Details together
equal the --verbose screen.
This commit is contained in:
Abdessamad Derraz committed 2026-11-10 01:09:37 +01:00
1 parent 36745abf10
commit fcb64e3857
56 files changed
+1851 -666

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@
# and Invoke-WebRequest throws on a cut transfer before the hash is read:
# the site's build rewrites this line there (scripts/sitebootstrap.py).
$mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
$defaultInstallSha256 = "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e"
$defaultInstallSha256 = "d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637"
# The pin above refuses any changed byte: this cap only stops a body that
# cannot be the installer (a sign-in portal's page) before it is hashed.
$maximumInstallerBytes = 8MB
+221 -84
View File
@@ -6875,12 +6875,15 @@ def _report_outcome(
say(next_step_words(platform_of or {}, paths))
NEXT_ON_CARD = "Next: put the card back in the device and start a game."
def next_step_words(platform_of: dict[Path, str], paths: list[Path]) -> str:
"""The step after an install that ended well: a card goes back in its
device, a setup on this machine is started."""
setups = [(platform_of.get(path, ""), path) for path in paths]
if setups and all(plat and on_its_card(plat, path) for plat, path in setups):
return "Next: put the card back in the device and start a game."
return NEXT_ON_CARD
names = list(dict.fromkeys(detected_os(plat, path) or display_name(plat)
for plat, path in setups if plat))
if len(names) == 1:
@@ -6944,7 +6947,7 @@ def _check_fetch_line(fetch: int, beside: str, lacking: int = 0) -> str:
f"internet, which {offline_named()} does not use. {_offline_remedy()}")
# Why nothing is lost goes with the details: the remedy is the line.
return (" Run the same command without --check to fetch them."
+ (f" A wrong copy is replaced, and the one in place kept in {BACKUP_DIR} "
+ (f"\n A wrong copy is replaced, and the one in place kept in {BACKUP_DIR} "
f"beside {beside}." if OUTPUT.verbose else ""))
@@ -16209,15 +16212,14 @@ def _install(args: argparse.Namespace, real_stdout: TextIO) -> None:
# The count and the folder by default, each file with
# --verbose: 20 paths hid the line saying what to do.
print(f"\n {_plural(len(to_download) + trees_missing, 'file')} "
+ ("not in place" if offline or LOCAL.pack is not None
else "to download") + (":" if OUTPUT.verbose else "."))
+ ("not in place." if offline or LOCAL.pack is not None
else "to download."))
for line in check_lines(missing, mismatched, files, manifest, bios_path,
args.verbose, up_to_date, bios_index, copies):
detail(line)
for line in unreadable_lines(unread, args.verbose):
print(line)
if not OUTPUT.verbose:
print(f" BIOS folder: {shown_path(bios_path)}")
print(f" BIOS folder: {shown_path(bios_path)}")
# The data files need the internet too: offline, "8164 files
# need the internet" stood under "10805 files not in place".
trees_fetched = trees_missing if LOCAL.pack is None else 0
@@ -17196,6 +17198,8 @@ class TuiLine(str):
# Whether the command it holds is typed into PowerShell, from the
# Invocation that made it: its line ends follow its words.
powershell: bool | None = None
# Shown on the Details screen, not on the screen it explains.
detail = False
def _styled(text: str, style: str = "") -> TuiLine:
@@ -17204,6 +17208,30 @@ def _styled(text: str, style: str = "") -> TuiLine:
return line
def _detail(text: str, style: str = "") -> TuiLine:
"""A line of the Details screen: an explanation, a list, a reason."""
line = _styled(text, style)
line.detail = True
return line
def _details(lines: Iterable[str]) -> list[TuiLine]:
"""lines as Details lines, each keeping how it is drawn."""
marked = []
for line in lines:
copy = TuiLine(str(line))
for name in ("style", "mark", "command", "powershell"):
if hasattr(line, name):
setattr(copy, name, getattr(line, name))
copy.detail = True
marked.append(copy)
return marked
def _is_detail(line: object) -> bool:
return bool(getattr(line, "detail", False))
def _command_line(text: str, hint: Invocation) -> TuiLine:
"""A line holding a command hint made, wrapped with hint's shell."""
line = _styled(text, "command")
@@ -17504,6 +17532,9 @@ class TuiState:
self.installed_only: bool = False
self.jobs: int = 8
self.passthrough: list = []
# Whether Details were opened on the result: the terminal keeps
# them after Exit too.
self.details_seen = False
# The install.
self.download: dict | None = None
self.progress: dict | None = None
@@ -18104,7 +18135,7 @@ class TuiRow(NamedTuple):
# Screens that scroll text instead of listing rows.
_PAGERS = ("preview", "command", "result", "misplaced", "unreadable", "games")
_PAGERS = ("preview", "command", "result", "misplaced", "unreadable", "games", "details")
_CHECKLISTS = ("systems", "cores")
@@ -18483,9 +18514,10 @@ def _plan_rows(state: TuiState) -> list[TuiRow]:
rows = [TuiRow("systems", TUI_SYSTEMS_ROW)]
game_data = _game_data_row(state)
return rows + ([game_data] if game_data is not None else []) + [
TuiRow("options", "Options"), TuiRow("quit", "Quit")]
*_details_row(state), TuiRow("options", "Options"), TuiRow("quit", "Quit")]
if not (_needed(check) if check else 0) and not check.get("data_missing"):
return [TuiRow("close", "Close"), *_games_rows(state), TuiRow("options", "Options")]
return [TuiRow("close", "Close"), *_games_rows(state), *_details_row(state),
TuiRow("options", "Options")]
# The size the pack can give: "Install 6.6 GB" from a pack holding
# none of the files.
lacking = set(_tui_pack_lacks(state, [event["dest"] for event in state.files]))
@@ -18542,7 +18574,18 @@ def _plan_rows(state: TuiState) -> list[TuiRow]:
rows.append(TuiRow("misplaced", "Show the files in the wrong place"))
if state.unreadable:
rows.append(TuiRow("unreadable", "Show the files that could not be read"))
return rows + [TuiRow("options", "Options"), TuiRow("quit", "Quit")]
return rows + [*_details_row(state), TuiRow("options", "Options"), TuiRow("quit", "Quit")]
# The plan's explanations, counts and reasons, one press away: a pad has
# no d key.
TUI_DETAILS_ROW = TuiRow("details", "Details")
def _details_row(state: TuiState) -> list[TuiRow]:
"""The Details row, where the plan leaves lines out: --verbose shows
them all on the plan itself."""
return [] if tui_verbose(state) else [TUI_DETAILS_ROW]
def games_where(state: TuiState) -> str:
@@ -18604,11 +18647,11 @@ def games_plan_words(state: TuiState) -> list[str]:
f"{', '.join(region_title(str(r)) for r in row['regions'])}"
for row in games.get("found") or [] if row.get("regions")]
if narrowed:
words.append(f"One region where the games prove it: {'; '.join(narrowed)}.")
words.append(_detail(f"One region where the games prove it: {'; '.join(narrowed)}."))
fallback = len(games.get("fallback") or [])
if fallback:
words.append(f"{agree(fallback, 'game gets', 'games get')} every BIOS of "
f"{'its' if fallback == 1 else 'their'} system: Show the games.")
words.append(_detail(f"{agree(fallback, 'game gets', 'games get')} every BIOS of "
f"{'its' if fallback == 1 else 'their'} system: Show the games."))
return words
@@ -19495,6 +19538,8 @@ def _tui_folder_facts(state: TuiState) -> dict:
def _activate(state: TuiState, row: TuiRow) -> list[tuple]:
screen, action = state.screen, row.action
if action == "details":
return _open_details(state)
if action == "filter":
only = _only_match(state)
if only is not None:
@@ -20438,6 +20483,10 @@ def _pager_key(state: TuiState, key: TuiKey) -> list[tuple]:
elif name in ("enter", "esc", "backspace") or char == " ":
if screen == "result":
return tui_quit(state)
if screen == "details":
# Never _back: a run counting under the plan goes on.
state.stack.pop()
return []
return _back(state)
state.focus[screen] = max(0, min(top, _pager_last(state, _pager_items(state))))
return []
@@ -20517,6 +20566,11 @@ def tui_update(state: TuiState, key: TuiKey) -> list[tuple]:
state.focus["error_text"] = max(0, state.focus.get("error_text", 0)
+ (step if key.name == "pgdn" else -step))
return []
if char == "d" and screen in ("plan", "confirm", "result") and not (
screen == "confirm" and (state.running or state.dry is None)):
return _open_details(state)
if screen == "result" and not rows and (char == "o" or key.name == "tab"):
return _open_details(state)
if screen in _PAGERS and not rows:
return _pager_key(state, key)
if not rows:
@@ -21173,7 +21227,7 @@ _ROW_VERBS = {
"unreadable": "Show", "exit": "Exit", "addapp": "Put it on the card",
"cardsystem": "Choose", "rescan": "Look again", "elsewhere": "Choose", "drive": "Choose",
"recheck": "Check again", "gamedata": "Change", "share": "Choose", "morecores": "Show",
"games": "Change", "startonly": "Change", "gameslist": "Show",
"games": "Change", "startonly": "Change", "gameslist": "Show", "details": "Show",
}
@@ -21564,7 +21618,7 @@ def _plan_lines(check: dict, dest: Path | None, state: TuiState) -> list:
if found_in:
# Right under the folder it names: after the save lines it read as
# naming them.
lines.append(_styled(f"Named by {_short_path(Path(found_in[0]), state.home)}", "path"))
lines.append(_detail(f"Named by {_short_path(Path(found_in[0]), state.home)}", "path"))
if state.facts.get("writable") is False:
# The remedy itself comes below, after the counts.
lines += cannot_write_words(dest, state.platform, tui_hint(state),
@@ -21578,27 +21632,27 @@ def _plan_lines(check: dict, dest: Path | None, state: TuiState) -> list:
counts = (f"{check['present']} in place, {check['missing'] + data} missing, "
f"{_plural(wrong, 'wrong copy')}")
# A first install's missing files are its normal state, not a warning.
lines.append(_styled(counts, "quiet") if not check["present"] and not wrong else counts)
lines.append(_detail(counts, "quiet" if not check["present"] and not wrong else ""))
# The backup line goes right under the count it explains, before the
# pack and copy split: at 40x12 and 40x15 it came after it, and was cut.
count_at = len(lines)
if copied and fetch and LOCAL.pack is not None:
lines.append(f"{fetch} from the pack, {len(copied)} copied from this machine")
lines.append(_detail(f"{fetch} from the pack, {len(copied)} copied from this machine"))
elif copied and fetch and not offline:
# 47 to download above 49 missing and 1 wrong copy: the 3 found on
# this machine are the difference, on a line of its own ("0 wrong
# copies: 2 of them" read as two of the zero). Offline the headline
# says it: "3 downloaded" sat under "3 need the internet".
lines.append(f"{need} to install: {len(copied)} copied from this machine, "
f"{fetch} downloaded")
lines.append(_detail(f"{need} to install: {len(copied)} copied from this machine, "
f"{fetch} downloaded"))
after_counts = len(lines)
saves = (_choice_saves(state) if check is state.check
else state.dry_saves if check is state.dry else None)
saves_lines = _saves_lines(state, saves)
lines += [_styled(line, "path" if index else "") for index, line in enumerate(saves_lines)]
lines += [_detail(line, "path" if index else "") for index, line in enumerate(saves_lines)]
free = state.facts.get("free")
if free is not None:
lines.append(f"Free space: {format_size(free)}")
lines.append(_detail(f"Free space: {format_size(free)}"))
if check["bytes_needed"] > free:
lines.append(space_words(check["bytes_needed"], free, _on_its_card(state)))
# The wrong copies something replaces: offline, those a folder copied
@@ -21612,30 +21666,32 @@ def _plan_lines(check: dict, dest: Path | None, state: TuiState) -> list:
if wrong_dests else wrong)
misplaced = _tui_misplaced(state) if check is state.check else []
if misplaced:
lines.insert(after_counts, f"{_plural(len(misplaced), 'file')} "
f"{'is' if len(misplaced) == 1 else 'are'} in the wrong place, "
f"{'it' if len(misplaced) == 1 else 'they'} will be copied where the "
"emulators read "
f"{'it' if len(misplaced) == 1 else 'them'}, the "
f"{'copy' if len(misplaced) == 1 else 'copies'} left as "
f"{'it is' if len(misplaced) == 1 else 'they are'}.")
lines.insert(after_counts, _detail(
f"{_plural(len(misplaced), 'file')} "
f"{'is' if len(misplaced) == 1 else 'are'} in the wrong place, "
f"{'it' if len(misplaced) == 1 else 'they'} will be copied where the "
"emulators read "
f"{'it' if len(misplaced) == 1 else 'them'}, the "
f"{'copy' if len(misplaced) == 1 else 'copies'} left as "
f"{'it is' if len(misplaced) == 1 else 'they are'}."))
if backup:
# With its subject: "They are replaced" sat lines under the count.
# Not where nothing can be installed: nothing is replaced then.
lines.insert(count_at, (f"The {_plural(wrong, 'wrong copy')} " if backup == wrong
else f"{backup} of the {_plural(wrong, 'wrong copy')} ")
+ f"{'is' if backup == 1 else 'are'} replaced, the old "
f"{'one' if backup == 1 else 'ones'} kept in a backup folder.")
lines.insert(count_at, _detail(
(f"The {_plural(wrong, 'wrong copy')} " if backup == wrong
else f"{backup} of the {_plural(wrong, 'wrong copy')} ")
+ f"{'is' if backup == 1 else 'are'} replaced, the old "
f"{'one' if backup == 1 else 'ones'} kept in a backup folder."))
if state.facts.get("writable") is False and dest is not None:
lines += _commands(state, write_remedy(dest, state.platform, tui_hint(state),
state.pad not in TUI_PAD_ROUTES))
if check is state.check:
lines += _scan_lines(state)
lines += _details(_scan_lines(state))
if check.get("not_installable"):
lines += _unavailable_lines(state)
lines += _details(_unavailable_lines(state))
if check is state.check:
lines += _unplaced_lines(_choice_summary(state), state,
"Choose it in Options, Save folder (--save-dir).")
lines += _details(_unplaced_lines(_choice_summary(state), state,
"Choose it in Options, Save folder (--save-dir)."))
if check is state.check and state.from_folders:
# A folder copied from that holds none of them: the plan came back
# the same, still saying to copy from a folder.
@@ -22014,7 +22070,8 @@ def _choice_line(state: TuiState) -> list[str]:
"count comes before the install."]
def _view_plan(state: TuiState, width: int, height: int) -> tuple:
def _plan_text(state: TuiState) -> list:
"""Every line of the plan, the Details lines among them."""
check = state.check or {}
lines = _plan_lines(check, state.dest, state)
choice = _choice_line(state)
@@ -22126,11 +22183,11 @@ def _view_plan(state: TuiState, width: int, height: int) -> tuple:
if found and parts:
parts = (f"Not in {', '.join(_last_name(str(folder)) for folder in found)}: "
f"{parts}")
lines[at:at] = [*([state.card_note] if state.card_note
lines[at:at] = [*([_detail(state.card_note)] if state.card_note
and state.card_note != state.status else []),
*([f"{said[0].upper()}{said[1:]}."] if said else []),
*([emptied_named] if emptied_named else []), *choice,
*([parts] if parts else []), *games_plan_words(state)]
*([_detail(parts)] if parts else []), *games_plan_words(state)]
if state.version:
# Before the free space, which gives way first: appended last, the
# note was cut from the 40x12 plan with no sign.
@@ -22140,7 +22197,7 @@ def _view_plan(state: TuiState, width: int, height: int) -> tuple:
if state.board:
free = next((index for index, line in enumerate(lines)
if str(line).startswith("Free space:")), len(lines))
lines.insert(free, state.board)
lines.insert(free, _detail(state.board))
if state.status:
lines.append(state.status)
if defined:
@@ -22150,7 +22207,25 @@ def _view_plan(state: TuiState, width: int, height: int) -> tuple:
# where the screen has no room.
saves = next((index for index, line in enumerate(lines)
if "'s save directory" in str(line)), len(lines))
lines.insert(saves, defined)
lines.insert(saves, _detail(defined))
return lines
def tui_verbose(state: TuiState) -> bool:
"""Whether the screen was opened with --verbose: every line is shown
where it belongs, as before the Details screen held them."""
return any(flag == "--verbose" for flag, _value in state.passthrough)
def _shown(state: TuiState, lines: list) -> list:
"""The lines a screen shows: all with --verbose, else all but Details."""
return list(lines) if tui_verbose(state) else [
line for line in lines if not _is_detail(line)]
def _view_plan(state: TuiState, width: int, height: int) -> tuple:
check = state.check or {}
lines = _shown(state, _plan_text(state))
# A folder that does not fit is wrapped, as the first screen wraps it:
# cut in its middle, the plan hid the part being checked before Install.
# At 40 columns too, broken after a separator: cut there, it was spelled
@@ -22442,7 +22517,9 @@ def _pager_items(state: TuiState) -> list:
if state.screen == "games":
return games_pager_lines(state)
if state.screen == "result":
return tui_outcome(state)[1]
return _shown(state, tui_outcome(state)[1])
if state.screen == "details":
return details_lines(state)
if state.screen == "command":
return ["The same choice without questions:", "",
_command_line(tui_command(state), tui_hint(state))]
@@ -22511,18 +22588,7 @@ def _view_confirm(state: TuiState, width: int, height: int) -> tuple:
# Why this screen: the numbers above are counted again for the
# systems and options chosen, the last look before anything is
# written.
lines = _plan_lines(state.dry, state.dest, state)
# The kinds apart, as the plan counts them, under the folder.
data = state.dry.get("data_missing", 0)
parts, _defined = _kinds_lines(state, state.dry_files, data,
state.dry.get("data_bytes") if data else None)
if parts:
at = next((index + 1 for index, line in enumerate(lines)
if str(line).startswith(_FOLDER_LABEL)), len(lines))
lines.insert(at, parts)
if any(row.action == "install" for row in tui_rows(state)):
lines.insert(0, "Counted again for these choices. Nothing is written before "
"Install.")
lines = _shown(state, _confirm_text(state))
if not any(row.action == "install" for row in tui_rows(state)) and state.dry is not None:
# Back alone: one Back on the bar, and no word of an Install. Titled
# for what it is: "Confirm" over nothing to confirm.
@@ -22533,6 +22599,23 @@ def _view_confirm(state: TuiState, width: int, height: int) -> tuple:
("A/Enter Install", "B/Esc Back", "? Help"))
def _confirm_text(state: TuiState) -> list:
"""Every line of Confirm, the Details lines among them."""
lines = _plan_lines(state.dry or {}, state.dest, state)
# The kinds apart, as the plan counts them, under the folder.
data = (state.dry or {}).get("data_missing", 0)
parts, _defined = _kinds_lines(state, state.dry_files, data,
(state.dry or {}).get("data_bytes") if data else None)
if parts:
at = next((index + 1 for index, line in enumerate(lines)
if str(line).startswith(_FOLDER_LABEL)), len(lines))
lines.insert(at, _detail(parts))
if any(row.action == "install" for row in tui_rows(state)):
lines.insert(0, "Counted again for these choices.")
lines.insert(1, _detail("Nothing is written before Install."))
return lines
def _bar(share: float, width: int) -> str:
room = max(4, width - 7)
filled = int(share * room)
@@ -22568,7 +22651,7 @@ def _view_installing(state: TuiState, width: int, height: int) -> tuple:
else f"{stops[1]} stops. What is done stays done.")
room = height - len(lines) - 1
failed = [item for item in reversed(state.finished) if not item[1]]
good = [item for item in reversed(state.finished) if item[1]]
good = [item for item in reversed(state.finished) if item[1]] if tui_verbose(state) else []
shown = (failed + good)[:max(0, room)]
if shown:
lines.append("")
@@ -22778,13 +22861,13 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]:
apart = _tui_tally(state, [{"dest": dest, "size": 0} for dest in missing
if dest not in wrong_dests])
if _tui_categories(state) and apart.bios and apart.games:
lines.append(f"Still missing: {installed_words(apart.bios, apart.games)}.")
lines.append(_detail(f"Still missing: {installed_words(apart.bios, apart.games)}."))
# Each folder spelled in full, as the result names its others.
lines.append(_offline_remedy([shown_path(folder) for folder in state.from_folders]))
ok = {dest for dest, good, _why in state.finished if good}
if any(reason and dest in ok for dest, (_folder, reason) in state.local_dests.items()):
# A fix copies: the misplaced files are the user's, never moved.
lines.append("The copies in the wrong place were left as they are.")
lines.append(_detail("The copies in the wrong place were left as they are."))
if _tui_categories(state) and title != "Stopped" and installed:
# As the plan counted them, and as line mode ends, on every result:
# the old card's said "6 files copied" and no kind. The data tree
@@ -22792,14 +22875,14 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]:
done = _tui_tally(state, [{"dest": dest, "size": 0}
for dest, good, _why in state.finished if good])
if done.files and not (title == "Done" and _one_kind(state, installed)):
lines.append("Installed: " + installed_words(
done.bios, done.games, max(0, installed - done.files)) + ".")
lines.append(_detail("Installed: " + installed_words(
done.bios, done.games, max(0, installed - done.files)) + "."))
# The folder the plan named: MinUI's Bios, not the card's root.
lines.append(f"BIOS folder: {shown_path(_plan_folder(state, state.dest))}")
if installed + up_to_date:
# Spelled as the BIOS folder above it is, whole: "~/" beside a full
# path was two spellings on one screen.
lines += _saves_lines(state, state.done_saves, whole=True)
lines += _details(_saves_lines(state, state.done_saves, whole=True))
if state.version:
# Said again with the result, as line mode ends: the system's own
# BIOS check may mark the files just put in place.
@@ -22813,7 +22896,8 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]:
names = ", ".join(str(item.get("name")) for item in fallback[:3])
more = f" and {len(fallback) - 3} more" if len(fallback) > 3 else ""
their = "its" if len(fallback) == 1 else "their"
lines.append(f"Not recognised, every BIOS of {their} system kept: {names}{more}.")
lines.append(_detail(f"Not recognised, every BIOS of {their} system kept: "
f"{names}{more}."))
if space:
lines.append("Free some space on the card, then run again." if _on_its_card(state)
else "Free some space, or run again and choose another folder.")
@@ -22829,10 +22913,10 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]:
continue
for dest in dests:
if shown < 20:
lines.append(f" failed: {dest}" + (f" ({reason})" if reason else ""))
lines.append(_detail(f" failed: {dest}" + (f" ({reason})" if reason else "")))
shown += 1
if shown > 20:
lines.append(f" ... and {shown - 20} more")
lines.append(_detail(f" ... and {shown - 20} more"))
if title == "Finished with errors":
# What a rerun does, as line mode and the first install page say
# it: the screen never did.
@@ -22848,8 +22932,9 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]:
if expected > landed and not left and title != "Stopped" and summary:
# The data files the plan counted, never named on a result that
# counted the BIOS files alone.
lines.append(f"{_plural(expected - landed, 'data file')} not installed"
+ (f": not in {LOCAL.pack.name}." if LOCAL.pack is not None else "."))
lines.append(_detail(f"{_plural(expected - landed, 'data file')} not installed"
+ (f": not in {LOCAL.pack.name}." if LOCAL.pack is not None
else ".")))
if state.dest is not None and any(failure["reason"] == NOT_WRITABLE
for failure in failed):
# The plan's own advice: the result offered nothing after 22 files
@@ -22869,27 +22954,38 @@ def tui_outcome(state: TuiState) -> tuple[str, list[str]]:
lines.append(f"The files it replaced are kept in {kept['folder']}")
if typed:
# Broken between its words only, never inside one (_wrap).
lines.append(_command_line(f"To put them back: {run.launcher()} --restore "
f"{run.word(str(kept['folder']))}", run))
lines += _details([_command_line(f"To put them back: {run.launcher()} --restore "
f"{run.word(str(kept['folder']))}", run)])
if summary and not summary.get("interrupted") and installed + up_to_date:
lines += _unavailable_lines(state)
lines += _details(_unavailable_lines(state))
for group in summary.get("left_out") or []:
lines.append(f"{left_out_words(group)}.")
lines += _unplaced_lines(summary, state)
lines.append(_detail(f"{left_out_words(group)}."))
lines += _details(_unplaced_lines(summary, state))
lines += _tui_app_lines(state)
if title == "Done" and not (state.platform == "romm" and installed):
# Last of what the result says by default: RomM's scan is its step.
lines.append(tui_next_words(state))
if typed:
lines += ["Same choice without questions:",
_command_line(f" {tui_command(state)}", tui_hint(state))]
lines += _details(["Same choice without questions:",
_command_line(f" {tui_command(state)}", tui_hint(state))])
if tui_keeps_log(state):
lines.append(f"Details: {state.log}")
lines.append(f"Log: {state.log}")
if state.mouse and typed:
# A drag over the command selected nothing: the terminal sends the
# press as a report. Said where it is read.
lines.append(_styled(TUI_RESULT_AGAIN if state.os_type == "android"
lines.append(_detail(TUI_RESULT_AGAIN if state.os_type == "android"
else TUI_RESULT_COPY, "dim"))
return title, lines
def tui_next_words(state: TuiState) -> str:
"""The step after an install the result says went well."""
if _on_its_card(state):
return NEXT_ON_CARD
name = detected_os(state.platform, state.dest) if state.dest is not None else ""
return f"Next: start {name or display_name(state.platform, state.manifest)} and play."
def _dest_error_outcome(state: TuiState, installed: int) -> tuple[str, list[str]]:
"""The result of a run whose BIOS folder could not be created: that
reason for every file, and its remedy. It said "22 files not fetched
@@ -22908,10 +23004,10 @@ def _dest_error_outcome(state: TuiState, installed: int) -> tuple[str, list[str]
lines.append("Run it again and choose another folder.")
lines += _commands(state, remedy)
if state.pad not in TUI_PAD_ROUTES:
lines += ["Same choice without questions:",
_command_line(f" {tui_command(state)}", tui_hint(state))]
lines += _details(["Same choice without questions:",
_command_line(f" {tui_command(state)}", tui_hint(state))])
if tui_keeps_log(state):
lines.append(f"Details: {state.log}")
lines.append(f"Log: {state.log}")
return ("Nothing installed" if not installed else "Finished with errors"), lines
@@ -22957,6 +23053,7 @@ def tui_keeps_log(state: TuiState) -> bool:
def _view_result(state: TuiState, width: int, height: int) -> tuple:
title, lines = tui_outcome(state)
lines = _shown(state, lines)
# The outcome in bold, its counts in their roles: it led a list of
# lines drawn alike.
lines[0] = _styled(lines[0], "title")
@@ -22971,7 +23068,7 @@ def _view_result(state: TuiState, width: int, height: int) -> tuple:
if state.app_running:
return (title, _pager(state, width, height, lines), ("Writing to the card...",))
return (title, _pager(state, width, height, lines),
("A/Enter Exit", *_scroll(state, lines, width, height)))
("A/Enter Exit", "Y/o Details", *_scroll(state, lines, width, height)))
def _view_error(state: TuiState, width: int, height: int) -> tuple:
@@ -23006,6 +23103,36 @@ def _view_quit(state: TuiState, width: int, height: int) -> tuple:
rows), hint)
def details_lines(state: TuiState) -> list:
"""What the screen under Details leaves out: its explanations, lists
and reasons."""
if len(state.stack) < 2:
return ["Nothing more to say here."]
# Read as the screen under it reads itself: its rows, its words.
top = state.stack.pop()
try:
under = state.screen
lines = (_plan_text(state) if under == "plan"
else _confirm_text(state) if under == "confirm"
else tui_outcome(state)[1] if under == "result" else [])
finally:
state.stack.append(top)
return [line for line in lines if _is_detail(line)] or ["Nothing more to say here."]
def _view_details(state: TuiState, width: int, height: int) -> tuple:
items = _pager_items(state)
return ("Details", _pager(state, width, height, items),
("A/Enter Back", *_scroll(state, items, width, height)))
def _open_details(state: TuiState) -> list[tuple]:
if state.screen == "result":
# Looked at, they are said again in the terminal after Exit.
state.details_seen = True
return _push(state, "details")
_TUI_VIEWS: dict[str, Callable[[TuiState, int, int], tuple]] = {
"setup": _view_setup, "platforms": _view_platforms, "folder": _view_folder,
"browse": _view_browse, "path": _view_path, "create": _view_create,
@@ -23014,7 +23141,7 @@ _TUI_VIEWS: dict[str, Callable[[TuiState, int, int], tuple]] = {
"preview": _view_preview, "command": _view_command, "confirm": _view_confirm,
"installing": _view_installing, "result": _view_result, "error": _view_error,
"quit": _view_quit, "cardroot": _view_cardroot, "misplaced": _view_misplaced,
"unreadable": _view_unreadable, "games": _view_games,
"unreadable": _view_unreadable, "games": _view_games, "details": _view_details,
}
@@ -23078,6 +23205,10 @@ def _help_lines(state: TuiState) -> list[tuple[str, str]]:
keys.append(("Left/Right", "Change a value"))
if screen in ("plan", "systems", "confirm"):
keys.append((names["options"], "Options"))
if screen in ("plan", "confirm"):
keys.append(("d", "Details"))
elif screen == "result" and not tui_rows(state):
keys.append((f"{names['options']}, d" if names["options"] else "d", "Details"))
# The result's bar calls B Exit: the help called it Quit.
back = "Exit" if screen == "result" else "Quit" if len(state.stack) == 1 else "Back"
keys += [(names["back"], back), ("q, Ctrl-C", "Quit"), *kill, *_route_extras(state),
@@ -23156,7 +23287,7 @@ def _view_help(state: TuiState, width: int, height: int) -> tuple:
# Cut from its end at 40x12, the help lost Quit and This help with no
# sign: what a list's keys also say elsewhere goes first.
for spare in ("First, last", "All, none", "extra", "Filter by setup or device name",
"Filter", "Options", "This help", "gap", "definitions"):
"Filter", "Options", "Details", "This help", "gap", "definitions"):
if (len(drawn(keys)) + len(extra) + len(defined)
+ len(_text_lines(more, width)) <= height):
break
@@ -23975,15 +24106,15 @@ def _said_lines(state: TuiState) -> list[str]:
def _closing_lines(state: TuiState) -> list[str]:
if state.screen != "result" and state.download is not None:
if state.screen not in ("result", "details") and state.download is not None:
# An install ran: what it wrote is said, whatever ended it.
title, lines = tui_outcome(state)
return [f"RetroBIOS: {title}", *_terminal_words(lines)]
return [f"RetroBIOS: {title}", *_terminal_words(_farewell_shown(state, lines))]
if state.screen == "crashed":
return [f"RetroBIOS stopped on an unexpected error. What it was is in {state.log}."]
if state.screen == "result":
if state.screen == "result" or (state.screen == "details" and "result" in state.stack):
title, lines = tui_outcome(state)
return [f"RetroBIOS: {title}", *_terminal_words(lines)]
return [f"RetroBIOS: {title}", *_terminal_words(_farewell_shown(state, lines))]
if state.screen == "error":
return [f"RetroBIOS: {state.error_title or 'something went wrong'}",
*(line.replace("then choose Try again", "then run the installer again")
@@ -24012,6 +24143,12 @@ TUI_SAVE_REMEDY = "Choose it in Options, Save folder (--save-dir), next time."
LINE_SAVE_REMEDY = "Name it with --save-dir next time."
def _farewell_shown(state: TuiState, lines: list) -> list:
"""The result as the terminal keeps it: Details too once they were
opened, as the result's copy hint says."""
return list(lines) if state.details_seen else _shown(state, lines)
def _terminal_words(lines: list[str]) -> list[str]:
"""The result's lines as the terminal prints them after the screen."""
return [line.replace(TUI_SAVE_REMEDY, LINE_SAVE_REMEDY) for line in lines
+1 -1
View File
@@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins
# curl or wget stop on a cut transfer before the hash is read: the site's
# build rewrites this line there (scripts/sitebootstrap.py).
MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
DEFAULT_INSTALL_SHA256="00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e"
DEFAULT_INSTALL_SHA256="d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637"
# The pin above refuses any changed byte: this cap only stops a body that
# cannot be the installer (a sign-in portal's page) before it is hashed.
MAX_INSTALLER_BYTES=8388608
+8 -8
View File
@@ -27,8 +27,8 @@
{
"dest": "roms/ports/retrobios/install.py",
"repo_path": "install.py",
"size": 1135666,
"sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e",
"size": 1141160,
"sha256": "d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637",
"executable": false
},
{
@@ -71,8 +71,8 @@
"muos": {
"archive": {
"dest": "ARCHIVE/RetroBIOS.muxapp",
"size": 1189291,
"sha256": "c56ce912e436173542905c89c1aee7de025f93bea5df130ab51e589c071f6369"
"size": 1194785,
"sha256": "344b9bb17095fef0ae3dfcee82f7144075b0c388033337552e37a2910f473dc9"
},
"members": [
{
@@ -92,8 +92,8 @@
{
"name": "RetroBIOS/install.py",
"repo_path": "install.py",
"size": 1135666,
"sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e",
"size": 1141160,
"sha256": "d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637",
"executable": false
},
{
@@ -166,8 +166,8 @@
{
"dest": ".config/modules/retrobios/install.py",
"repo_path": "install.py",
"size": 1135666,
"sha256": "00376e0108c51fc9dbd27470080028be84251b1aa8d7bdfe28db3a71b2eae29e",
"size": 1141160,
"sha256": "d07c90a00f5bab9c583c34a9a1413bed5625542e7c88fed7bd9bab0020e9e637",
"executable": false
},
{
+1 -1
View File
@@ -604,7 +604,7 @@ def _refused_lines(text: str) -> list[str]:
"""The files a check flags, each with its reason and where its cores read it."""
lines = text.splitlines()
start = next((i for i, line in enumerate(lines)
if re.fullmatch(r" \d+ files? [a-z ]+:", line)), None)
if re.fullmatch(r" \d+ files? [a-z ]+\.", line)), None)
if start is None:
raise SampleFailed("the check printed no files not in place")
end = max(i for i, line in enumerate(lines) if line.lstrip().startswith("read by "))
+105 -23
View File
@@ -331,13 +331,11 @@
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -363,6 +361,8 @@
@@ -372,11 +372,9 @@
^[[0;1m ^[[0;1;32mEvery file on the list is in place^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m
^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;7;35m > Close^[[0m
Details
Options
@@ -404,6 +402,8 @@
@@ -657,11 +657,9 @@
=== confirm
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Confirm^[[0m
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
^[[0;1m ^[[0;1;35m1^[[0;1m file to download, ^[[0;1;35m16.0 KB^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
Back
@@ -691,6 +689,8 @@
@@ -705,7 +705,7 @@
B, Ctrl-C or Select+Start stops. What is done stays done.
^[[0;1;31mFAILED^[[0m scph5500.bin (HTTP 404)
^[[0;32m ok^[[0m gba_bios.bin
@@ -741,14 +741,9 @@
^[[0;1m ^[[0;1;32m3 installed^[[0;1m, ^[[0;1;31m1 failed^[[0;1m.^[[0m
BIOS folder: ^[[0;1m/home/user/.config/retroarch/system^[[0m
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch --dest /home/user/.config/retroarch/system
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -776,7 +771,12 @@
^[[0;1;35mA/Enter^[[0m Exit
^[[0;1;35mA/Enter^[[0m Exit ^[[0;2mY/o^[[0m Details
=== error
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mSomething went wrong^[[0m
@@ -865,6 +865,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
@@ -896,7 +897,6 @@
Any key closes this help
@@ -906,11 +906,6 @@
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
For the games on this card: yes 412 games
@@ -918,6 +913,7 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -936,6 +932,10 @@
@@ -969,6 +969,88 @@
^[[0;1;35mA/Enter^[[0m Back
=== plan-details
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;1;35mA/Enter^[[0m Back
=== result-details
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch --dest /home/user/.config/retroarch/system
+41 -15
View File
@@ -108,10 +108,10 @@
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
BIOS folder:
^[[0;1m~/.config/retroarch/system^[[0m
^[[0;33m1 wrong copy^[[0m: backed up, replaced.
^[[0;7;35m > Install^[[0m
Choose systems
Copy from an old card or a folder
Details
Options
Quit
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
@@ -121,12 +121,12 @@
^[[0;1m ^[[0;1;32mEvery file on the list is in place^[[0m
BIOS folder:
^[[0;1m~/.config/retroarch/system^[[0m
^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;7;35m > Close^[[0m
Details
Options
^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
=== systems
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
@@ -210,14 +210,14 @@
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Confirm^[[0m
Counted again for these choices.
Nothing is written before Install.
^[[0;1m ^[[0;1;35m1^[[0;1m file to download, ^[[0;1;35m16.0 KB^[[0m
BIOS folder: ^[[0;1m~/.co.../retroarch/system^[[0m
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
Back
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2m?^[[0m Help
=== installing
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Installing^[[0m
@@ -230,7 +230,7 @@
is done stays done.
^[[0;1;31mFAILED^[[0m scph5500.bin (HTTP 404)
^[[0;32m ok^[[0m gba_bios.bin
^[[0;1;35mB^[[0m Stop ^[[0;2m?^[[0m Help
=== result
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mFinished with errors^[[0m
@@ -238,13 +238,13 @@
^[[0;1m ^[[0;1;32m3 installed^[[0;1m, ^[[0;1;31m1 failed^[[0;1m.^[[0m
BIOS folder:
^[[0;1m/home/user/.config/retroarch/system^[[0m
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
^[[0;2m 1-8 of 17^[[0m
^[[0;1;35mA^[[0m Exit ^[[0;2m^v^[[0m Scroll
Log: /tmp/retrobios-x/install.log
^[[0;1;35mA^[[0m Exit ^[[0;2mY^[[0m Details
=== error
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mSomething went wrong^[[0m
@@ -277,12 +277,12 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
BIOS folder:
^[[0;1m/home/user/.config/retroarch/system^[[0m
Any key closes this help
=== plan-games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
@@ -295,7 +295,7 @@
For the games on this card: yes 412
Only what starts: no
Show the games
^[[0;2m 1-4 of 8^[[0m
^[[0;2m 1-4 of 9^[[0m
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
=== games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Games on this card^[[0m
@@ -310,3 +310,29 @@
^[[0;2m 1-5 of 9^[[0m
^[[0;1;35mA^[[0m Back ^[[0;2m^v^[[0m Scroll
=== plan-details
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
The ^[[0;33m1 wrong copy^[[0m is replaced, the old
one kept in a backup folder.
Free space: 50.0 GB
^[[0;1;35mA^[[0m Back
=== result-details
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore .../2026-10-23_1200
^[[0;2m Shortened to fit this window.^[[0m
Same choice without questions:
python3 install.py \
--platform retroarch \
--dest .../retroarch/system
^[[0;2m Shortened to fit this window.^[[0m
^[[0;1;35mA^[[0m Back
+51 -19
View File
@@ -132,15 +132,15 @@
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
BIOS folder:
^[[0;1m~/.config/retroarch/system^[[0m
^[[0;33m1 wrong copy^[[0m: backed up, replaced.
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
Choose systems
Copy from an old card or a folder
Details
Options
Quit
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
=== plan-in-place
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
@@ -148,15 +148,15 @@
^[[0;1m ^[[0;1;32mEvery file on the list is in place^[[0m
BIOS folder:
^[[0;1m~/.config/retroarch/system^[[0m
^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;7;35m > Close^[[0m
Details
Options
^[[0;1;35mA^[[0m Close ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
=== systems
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
@@ -258,17 +258,17 @@
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Confirm^[[0m
Counted again for these choices.
Nothing is written before Install.
^[[0;1m ^[[0;1;35m1^[[0;1m file to download, ^[[0;1;35m16.0 KB^[[0m
BIOS folder: ^[[0;1m~/.co.../retroarch/system^[[0m
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
Back
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2m?^[[0m Help
=== installing
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Installing^[[0m
@@ -281,7 +281,7 @@
is done stays done.
^[[0;1;31mFAILED^[[0m scph5500.bin (HTTP 404)
^[[0;32m ok^[[0m gba_bios.bin
@@ -292,16 +292,16 @@
^[[0;1m ^[[0;1;32m3 installed^[[0;1m, ^[[0;1;31m1 failed^[[0;1m.^[[0m
BIOS folder:
^[[0;1m/home/user/.config/retroarch/system^[[0m
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
To put them back: python3 install.py \
--restore .../2026-10-23_1200
^[[0;2m Shortened to fit this window.^[[0m
^[[0;2m 1-11 of 17^[[0m
^[[0;1;35mA^[[0m Exit ^[[0;2m^v^[[0m Scroll
Log: /tmp/retrobios-x/install.log
^[[0;1;35mA^[[0m Exit ^[[0;2mY^[[0m Details
=== error
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mSomething went wrong^[[0m
@@ -340,6 +340,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
@@ -348,7 +349,6 @@
^[[0;1m/home/user/.config/retroarch/system^[[0m
Any key closes this help
=== plan-games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
@@ -356,13 +356,13 @@
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
BIOS folder:
^[[0;1m~/.config/retroarch/system^[[0m
For the 412 games on this card.
^[[0;7;35m > Install^[[0m
For the games on this card: yes 412
Only what starts: no
Show the games
Choose systems
Copy from an old card or a folder
Details
Options
Quit
^[[0;1;35mA^[[0m Install ^[[0;2mB^[[0m Back ^[[0;2mY^[[0m Options ^[[0;2m?^[[0m Help
@@ -381,4 +381,36 @@
that they start:
GBA/demo.gba: not recognised
GBA/hack.gba: not recognised
^[[0;1;35mA^[[0m Back
=== plan-details
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
The ^[[0;33m1 wrong copy^[[0m is replaced, the old
one kept in a backup folder.
Free space: 50.0 GB
^[[0;1;35mA^[[0m Back
=== result-details
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore .../2026-10-23_1200
^[[0;2m Shortened to fit this window.^[[0m
Same choice without questions:
python3 install.py \
--platform retroarch \
--dest .../retroarch/system
^[[0;2m Shortened to fit this window.^[[0m
^[[0;1;35mA^[[0m Back
+74 -24
View File
@@ -203,13 +203,11 @@
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -222,17 +220,17 @@
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
=== plan-in-place
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
^[[0;1m ^[[0;1;32mEvery file on the list is in place^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m
^[[0;32m5 in place^[[0m, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;7;35m > Close^[[0m
Details
Options
@@ -247,6 +245,8 @@
^[[0;1;35mA/Enter^[[0m Close ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
=== systems
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Choose systems^[[0m
@@ -401,11 +401,9 @@
=== confirm
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Confirm^[[0m
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
^[[0;1m ^[[0;1;35m1^[[0;1m file to download, ^[[0;1;35m16.0 KB^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
Back
@@ -422,6 +420,8 @@
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2m?^[[0m Help
=== installing
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Installing^[[0m
@@ -433,7 +433,7 @@
B, Ctrl-C or Select+Start stops. What is done stays done.
^[[0;1;31mFAILED^[[0m scph5500.bin (HTTP 404)
^[[0;32m ok^[[0m gba_bios.bin
@@ -453,16 +453,10 @@
^[[0;1m ^[[0;1;32m3 installed^[[0;1m, ^[[0;1;31m1 failed^[[0;1m.^[[0m
BIOS folder: ^[[0;1m/home/user/.config/retroarch/system^[[0m
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch \
--dest /home/user/.config/retroarch/system
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -472,7 +466,13 @@
^[[0;1;35mA/Enter^[[0m Exit
^[[0;1;35mA/Enter^[[0m Exit ^[[0;2mY/o^[[0m Details
=== error
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: ^[[0;1;31mSomething went wrong^[[0m
@@ -529,6 +529,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
@@ -546,7 +547,6 @@
Any key closes this help
=== plan-games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: RetroArch^[[0m
@@ -554,11 +554,6 @@
^[[0;1m ^[[0;1;35m4^[[0;1m files to download, ^[[0;1;35m1.0 MB^[[0m
BIOS folder: ^[[0;1m~/.config/retroarch/system^[[0m
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;7;35m > Install^[[0m
For the games on this card: yes 412 games
@@ -566,12 +561,17 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
^[[0;1;35mA/Enter^[[0m Install ^[[0;2mB/Esc^[[0m Back ^[[0;2mY/o^[[0m Options ^[[0;2m?^[[0m Help
=== games
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Games on this card^[[0m
@@ -597,4 +597,54 @@
^[[0;1;35mA/Enter^[[0m Back
=== plan-details
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m
^[[0;32m1 in place^[[0m, ^[[0;33m3 missing^[[0m, ^[[0;33m1 wrong copy^[[0m
The ^[[0;33m1 wrong copy^[[0m is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
^[[0;1;35mA/Enter^[[0m Back
=== result-details
^[[0;1m ^[[0;1;35mRetroBIOS^[[0;1m: Details^[[0m
^[[0;1;31mfailed:^[[0m scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch \
--dest /home/user/.config/retroarch/system
^[[0;1;35mA/Enter^[[0m Back
+3 -3
View File
@@ -1,10 +1,8 @@
RetroBIOS: Confirm
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
1 file to download, 16.0 KB
BIOS folder: ~/.config/retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
@@ -34,6 +32,8 @@
+3 -3
View File
@@ -1,12 +1,12 @@
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install B Back ? Help
+3 -3
View File
@@ -1,15 +1,15 @@
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install B Back ? Help
+3 -3
View File
@@ -1,10 +1,8 @@
RetroBIOS: Confirm
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
1 file to download, 16.0 KB
BIOS folder: ~/.config/retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
@@ -21,4 +19,6 @@
A/Enter Install B/Esc Back ? Help
+1 -1
View File
@@ -3,6 +3,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
@@ -34,7 +35,6 @@
Any key closes this help
+2 -2
View File
@@ -3,10 +3,10 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
BIOS folder:
/home/user/.config/retroarch/system
Any key closes this help
+1 -1
View File
@@ -3,6 +3,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
@@ -11,5 +12,4 @@
/home/user/.config/retroarch/system
Any key closes this help
+1 -1
View File
@@ -3,6 +3,7 @@
Up/Down, k/j Move
A/Enter, Start Install
Y, o, Tab Options
d Details
B/Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
@@ -20,5 +21,4 @@
Any key closes this help
+1 -1
View File
@@ -7,7 +7,7 @@
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
@@ -8,5 +8,5 @@
is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
B Stop ? Help
+1 -1
View File
@@ -8,7 +8,7 @@
is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
+1 -1
View File
@@ -7,7 +7,7 @@
B, Ctrl-C or Select+Start stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
+3 -3
View File
@@ -2,13 +2,11 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -34,6 +32,8 @@
+1 -1
View File
@@ -3,10 +3,10 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options ? Help
+3 -3
View File
@@ -3,13 +3,13 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
1 in place, 3 missing, 1 wrong copy
Free space: 50.0 GB
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options ? Help
+3 -3
View File
@@ -2,13 +2,11 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -21,4 +19,6 @@
A/Enter Install B/Esc Back Y/o Options ? Help
+40
View File
@@ -0,0 +1,40 @@
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
A/Enter Back
+12
View File
@@ -0,0 +1,12 @@
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old
one kept in a backup folder.
Free space: 50.0 GB
A Back
+15
View File
@@ -0,0 +1,15 @@
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old
one kept in a backup folder.
Free space: 50.0 GB
A Back
+24
View File
@@ -0,0 +1,24 @@
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
A/Enter Back
+5 -5
View File
@@ -3,11 +3,6 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
For the games on this card: yes 412 games
@@ -15,6 +10,7 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -33,6 +29,10 @@
+1 -1
View File
@@ -8,5 +8,5 @@
For the games on this card: yes 412
Only what starts: no
Show the games
1-4 of 8
1-4 of 9
A Install B Back Y Options ? Help
+1 -1
View File
@@ -3,13 +3,13 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
For the 412 games on this card.
> Install
For the games on this card: yes 412
Only what starts: no
Show the games
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options ? Help
+5 -5
View File
@@ -3,11 +3,6 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
For the games on this card: yes 412 games
@@ -15,10 +10,15 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
A/Enter Install B/Esc Back Y/o Options ? Help
+3 -3
View File
@@ -2,11 +2,9 @@
Every file on the list is in place
BIOS folder: ~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
@@ -34,6 +32,8 @@
+4 -4
View File
@@ -3,10 +3,10 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close B Back Y Options ? Help
+4 -4
View File
@@ -3,13 +3,13 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close B Back Y Options ? Help
+3 -3
View File
@@ -2,11 +2,9 @@
Every file on the list is in place
BIOS folder: ~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
@@ -21,4 +19,6 @@
A/Enter Close B/Esc Back Y/o Options ? Help
+7 -7
View File
@@ -2,14 +2,9 @@
3 installed, 1 failed.
BIOS folder: /home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch --dest /home/user/.config/retroarch/system
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -37,4 +32,9 @@
A/Enter Exit
A/Enter Exit Y/o Details
+3 -3
View File
@@ -3,10 +3,10 @@
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
1-8 of 17
A Exit ^v Scroll
Log: /tmp/retrobios-x/install.log
A Exit Y Details
+6 -6
View File
@@ -3,13 +3,13 @@
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
To put them back: python3 install.py \
--restore .../2026-10-23_1200
Shortened to fit this window.
1-11 of 17
A Exit ^v Scroll
Log: /tmp/retrobios-x/install.log
A Exit Y Details
+8 -8
View File
@@ -2,16 +2,10 @@
3 installed, 1 failed.
BIOS folder: /home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch \
--dest /home/user/.config/retroarch/system
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -21,4 +15,10 @@
A/Enter Exit
A/Enter Exit Y/o Details
+40
View File
@@ -0,0 +1,40 @@
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch --dest /home/user/.config/retroarch/system
A/Enter Back
+12
View File
@@ -0,0 +1,12 @@
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore .../2026-10-23_1200
Shortened to fit this window.
Same choice without questions:
python3 install.py \
--platform retroarch \
--dest .../retroarch/system
Shortened to fit this window.
A Back
+15
View File
@@ -0,0 +1,15 @@
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore .../2026-10-23_1200
Shortened to fit this window.
Same choice without questions:
python3 install.py \
--platform retroarch \
--dest .../retroarch/system
Shortened to fit this window.
A Back
+24
View File
@@ -0,0 +1,24 @@
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch \
--dest /home/user/.config/retroarch/system
A/Enter Back
+122 -72
View File
@@ -407,10 +407,10 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
@@ -420,28 +420,26 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
1 in place, 3 missing, 1 wrong copy
Free space: 50.0 GB
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
=== plan 80x24
RetroBIOS: RetroArch
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -454,6 +452,8 @@
A Install B Back Y Options
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -461,12 +461,12 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close B Back Y Options
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -474,26 +474,24 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close B Back Y Options
=== plan-in-place 80x24
RetroBIOS: RetroArch
Every file on the list is in place
BIOS folder: ~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
@@ -508,6 +506,8 @@
A Close B Back Y Options
=== systems 40x12
RetroBIOS: Choose systems
@@ -779,39 +779,37 @@
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install B Back
=== confirm 40x15
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install B Back
=== confirm 80x24
RetroBIOS: Confirm
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
1 file to download, 16.0 KB
BIOS folder: ~/.config/retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
@@ -828,6 +826,8 @@
A Install B Back
=== installing 40x12
RetroBIOS: Installing
@@ -839,7 +839,7 @@
B stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
B Stop
=== installing 40x15
@@ -852,7 +852,7 @@
B stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -868,7 +868,7 @@
B stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -883,45 +883,15 @@
B Stop
=== result 40x12
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit
=== result 40x15
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit
=== result 80x24
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder: /home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -936,7 +906,8 @@
A Exit
A Exit Y Details
=== error 40x12
RetroBIOS: Something went wrong
@@ -1006,12 +977,12 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
BIOS folder:
/home/user/.config/retroarch/system
Any key closes this help
=== help 40x15
RetroBIOS: Keys
@@ -1019,6 +990,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -1027,7 +999,6 @@
Any key closes this help
=== help 80x24
RetroBIOS: Keys
@@ -1035,6 +1006,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
@@ -1052,7 +1024,6 @@
Any key closes this help
=== plan-games 40x12
RetroBIOS: RetroArch
@@ -1065,7 +1036,7 @@
For the games on this card: yes 412
Only what starts: no
Show the games
1-4 of 8
1-4 of 9
A Install B Back Y Options
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1073,13 +1044,13 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
For the 412 games on this card.
> Install
For the games on this card: yes 412
Only what starts: no
Show the games
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
@@ -1089,11 +1060,6 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
For the games on this card: yes 412 games
@@ -1101,12 +1067,17 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
=== games 80x24
RetroBIOS: Games on this card
@@ -1132,4 +1103,83 @@
A Back
=== plan-details 80x24
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
A Back
=== result-details 40x12
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
=== result-details 40x15
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
=== result-details 80x24
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
+123 -73
View File
@@ -407,10 +407,10 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
@@ -420,28 +420,26 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
1 in place, 3 missing, 1 wrong copy
Free space: 50.0 GB
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
=== plan 80x24
RetroBIOS: RetroArch
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -454,6 +452,8 @@
A Install B Back Y Options
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -461,12 +461,12 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close B Back Y Options
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -474,26 +474,24 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close B Back Y Options
=== plan-in-place 80x24
RetroBIOS: RetroArch
Every file on the list is in place
BIOS folder: ~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
@@ -508,6 +506,8 @@
A Close B Back Y Options
=== systems 40x12
RetroBIOS: Choose systems
@@ -779,39 +779,37 @@
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install B Back
=== confirm 40x15
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install B Back
=== confirm 80x24
RetroBIOS: Confirm
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
1 file to download, 16.0 KB
BIOS folder: ~/.config/retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
@@ -828,6 +826,8 @@
A Install B Back
=== installing 40x12
RetroBIOS: Installing
@@ -840,7 +840,7 @@
stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
B Stop
=== installing 40x15
RetroBIOS: Installing
@@ -853,7 +853,7 @@
stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -868,7 +868,7 @@
B or Select+Start stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -883,45 +883,15 @@
B Stop
=== result 40x12
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit
=== result 40x15
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit
=== result 80x24
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder: /home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -936,7 +906,8 @@
A Exit
A Exit Y Details
=== error 40x12
RetroBIOS: Something went wrong
@@ -1006,12 +977,12 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
Select, then Start Quit at once
BIOS folder:
/home/user/.config/retroarch/system
Any key closes this help
=== help 40x15
RetroBIOS: Keys
@@ -1019,6 +990,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
Select, then Start Quit at once
@@ -1027,7 +999,6 @@
/home/user/.config/retroarch/system
Any key closes this help
=== help 80x24
RetroBIOS: Keys
@@ -1035,6 +1006,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
Select, then Start Quit at once
@@ -1052,7 +1024,6 @@
Any key closes this help
=== plan-games 40x12
RetroBIOS: RetroArch
@@ -1065,7 +1036,7 @@
For the games on this card: yes 412
Only what starts: no
Show the games
1-4 of 8
1-4 of 9
A Install B Back Y Options
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1073,13 +1044,13 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
For the 412 games on this card.
> Install
For the games on this card: yes 412
Only what starts: no
Show the games
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
@@ -1089,11 +1060,6 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
For the games on this card: yes 412 games
@@ -1101,12 +1067,17 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
=== games 80x24
RetroBIOS: Games on this card
@@ -1132,4 +1103,83 @@
A Back
=== plan-details 80x24
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
A Back
=== result-details 40x12
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
=== result-details 40x15
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
=== result-details 80x24
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
+123 -73
View File
@@ -407,10 +407,10 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
@@ -420,28 +420,26 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
1 in place, 3 missing, 1 wrong copy
Free space: 50.0 GB
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
=== plan 80x24
RetroBIOS: RetroArch
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -454,6 +452,8 @@
A Install B Back Y Options
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -461,12 +461,12 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close B Back Y Options
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -474,26 +474,24 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close B Back Y Options
=== plan-in-place 80x24
RetroBIOS: RetroArch
Every file on the list is in place
BIOS folder: ~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
@@ -508,6 +506,8 @@
A Close B Back Y Options
=== systems 40x12
RetroBIOS: Choose systems
@@ -779,39 +779,37 @@
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install B Back
=== confirm 40x15
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install B Back
=== confirm 80x24
RetroBIOS: Confirm
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
1 file to download, 16.0 KB
BIOS folder: ~/.config/retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
@@ -828,6 +826,8 @@
A Install B Back
=== installing 40x12
RetroBIOS: Installing
@@ -840,7 +840,7 @@
stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
B Stop
=== installing 40x15
RetroBIOS: Installing
@@ -853,7 +853,7 @@
stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -868,7 +868,7 @@
B or Select+Start stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -883,45 +883,15 @@
B Stop
=== result 40x12
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit
=== result 40x15
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit
=== result 80x24
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder: /home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -936,7 +906,8 @@
A Exit
A Exit Y Details
=== error 40x12
RetroBIOS: Something went wrong
@@ -1006,12 +977,12 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
Select, then Start Quit at once
BIOS folder:
/home/user/.config/retroarch/system
Any key closes this help
=== help 40x15
RetroBIOS: Keys
@@ -1019,6 +990,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
Select, then Start Quit at once
@@ -1027,7 +999,6 @@
/home/user/.config/retroarch/system
Any key closes this help
=== help 80x24
RetroBIOS: Keys
@@ -1035,6 +1006,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
Y, Tab, o Options
d Details
B, Select, Esc Back
q, Ctrl-C Quit
Select, then Start Quit at once
@@ -1052,7 +1024,6 @@
Any key closes this help
=== plan-games 40x12
RetroBIOS: RetroArch
@@ -1065,7 +1036,7 @@
For the games on this card: yes 412
Only what starts: no
Show the games
1-4 of 8
1-4 of 9
A Install B Back Y Options
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1073,13 +1044,13 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
For the 412 games on this card.
> Install
For the games on this card: yes 412
Only what starts: no
Show the games
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
@@ -1089,11 +1060,6 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
For the games on this card: yes 412 games
@@ -1101,12 +1067,17 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
A Install B Back Y Options
=== games 80x24
RetroBIOS: Games on this card
@@ -1132,4 +1103,83 @@
A Back
=== plan-details 80x24
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
A Back
=== result-details 40x12
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
=== result-details 40x15
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
=== result-details 80x24
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
+166 -58
View File
@@ -382,10 +382,10 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
Enter Install Esc Back o Options
@@ -395,28 +395,26 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
1 in place, 3 missing, 1 wrong copy
Free space: 50.0 GB
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
Enter Install Esc Back o Options
=== plan 80x24
RetroBIOS: RetroArch
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -429,6 +427,8 @@
Enter Install Esc Back o Options ? Help
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -436,12 +436,12 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
Enter Close Esc Back o Options
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -449,26 +449,24 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
Enter Close Esc Back o Options
=== plan-in-place 80x24
RetroBIOS: RetroArch
Every file on the list is in place
BIOS folder: ~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
@@ -483,6 +481,8 @@
Enter Close Esc Back o Options ? Help
=== systems 40x12
RetroBIOS: Choose systems
@@ -812,39 +812,37 @@
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
Enter Install Esc Back ? Help
=== confirm 40x15
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
Enter Install Esc Back ? Help
=== confirm 80x24
RetroBIOS: Confirm
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
1 file to download, 16.0 KB
BIOS folder: ~/.config/retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
@@ -861,6 +859,8 @@
Enter Install Esc Back ? Help
=== installing 40x12
RetroBIOS: Installing
@@ -873,7 +873,7 @@
stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
Esc Stop ? Help
=== installing 40x15
RetroBIOS: Installing
@@ -886,7 +886,7 @@
stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -901,7 +901,7 @@
Esc or Ctrl-C stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -922,44 +922,38 @@
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
1-8 of 17
Enter Exit ^v Scroll
Log: /tmp/retrobios-x/install.log
Enter Exit o Details
=== result 40x15
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
To put them back: python3 install.py \
--restore .../2026-10-23_1200
Shortened to fit this window.
1-11 of 17
Enter Exit ^v Scroll
Log: /tmp/retrobios-x/install.log
Enter Exit o Details
=== result 80x24
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder: /home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch \
--dest /home/user/.config/retroarch/system
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -969,7 +963,13 @@
Enter Exit
Enter Exit o Details
=== error 40x12
RetroBIOS: Something went wrong
@@ -1084,12 +1084,12 @@
Up/Down, k/j Move
Enter Install
o, Tab Options
d Details
Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
BIOS folder:
/home/user/.config/retroarch/system
Any key closes this help
=== help 40x15
RetroBIOS: Keys
@@ -1097,6 +1097,7 @@
Up/Down, k/j Move
Enter Install
o, Tab Options
d Details
Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
@@ -1105,7 +1106,6 @@
/home/user/.config/retroarch/system
Any key closes this help
=== help 80x24
RetroBIOS: Keys
@@ -1113,6 +1113,7 @@
Up/Down, k/j Move
Enter Install
o, Tab Options
d Details
Esc, Backspace Back
q, Ctrl-C Quit
?, F1 This help
@@ -1130,7 +1131,6 @@
Any key closes this help
=== plan-games 40x12
RetroBIOS: RetroArch
@@ -1143,7 +1143,7 @@
For the games on this card: yes 412
Only what starts: no
Show the games
1-4 of 8
1-4 of 9
Enter Install Esc Back o Options
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1151,13 +1151,13 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
For the 412 games on this card.
> Install
For the games on this card: yes 412
Only what starts: no
Show the games
Choose systems
Copy from an old card or a folder
Details
Options
Quit
Enter Install Esc Back o Options
@@ -1167,11 +1167,6 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
For the games on this card: yes 412 games
@@ -1179,12 +1174,17 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
Enter Install Esc Back o Options ? Help
=== games 40x12
RetroBIOS: Games on this card
@@ -1239,4 +1239,112 @@
Enter Back
=== plan-details 40x12
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old
one kept in a backup folder.
Free space: 50.0 GB
Enter Back
=== plan-details 40x15
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old
one kept in a backup folder.
Free space: 50.0 GB
Enter Back
=== plan-details 80x24
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
Enter Back
=== result-details 40x12
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore .../2026-10-23_1200
Shortened to fit this window.
Same choice without questions:
python3 install.py \
--platform retroarch \
--dest .../retroarch/system
Shortened to fit this window.
Enter Back
=== result-details 40x15
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore .../2026-10-23_1200
Shortened to fit this window.
Same choice without questions:
python3 install.py \
--platform retroarch \
--dest .../retroarch/system
Shortened to fit this window.
Enter Back
=== result-details 80x24
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
To put them back: python3 install.py \
--restore /home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Same choice without questions:
python3 install.py --platform retroarch \
--dest /home/user/.config/retroarch/system
Enter Back
+129 -50
View File
@@ -436,10 +436,10 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install R2 Back L2 Options
@@ -449,28 +449,26 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
1 in place, 3 missing, 1 wrong copy
Free space: 50.0 GB
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install R2 Back L2 Options
=== plan 80x24
RetroBIOS: RetroArch
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -483,6 +481,8 @@
A Install R2 Back L2 Options
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -490,12 +490,12 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close R2 Back L2 Options
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -503,26 +503,24 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
A Close R2 Back L2 Options
=== plan-in-place 80x24
RetroBIOS: RetroArch
Every file on the list is in place
BIOS folder: ~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
@@ -537,6 +535,8 @@
A Close R2 Back L2 Options
=== systems 40x12
RetroBIOS: Choose systems
@@ -808,39 +808,37 @@
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install R2 Back
=== confirm 40x15
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
A Install R2 Back
=== confirm 80x24
RetroBIOS: Confirm
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
1 file to download, 16.0 KB
BIOS folder: ~/.config/retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
@@ -857,6 +855,8 @@
A Install R2 Back
=== installing 40x12
RetroBIOS: Installing
@@ -868,7 +868,7 @@
R2 stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
R2 Stop
=== installing 40x15
@@ -881,7 +881,7 @@
R2 stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -897,7 +897,7 @@
R2 stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -918,39 +918,38 @@
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
A Exit
Log: /tmp/retrobios-x/install.log
A Exit L2 Details
=== result 40x15
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
A Exit
A Exit L2 Details
=== result 80x24
RetroBIOS: Finished with errors
3 installed, 1 failed.
BIOS folder: /home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -965,7 +964,8 @@
A Exit
A Exit L2 Details
=== error 40x12
RetroBIOS: Something went wrong
@@ -1080,12 +1080,12 @@
D-pad, Up/Down Move
A, Start, Enter Install
L2, Tab, o Options
d Details
R2, Esc, Backspace Back
q, Ctrl-C Quit
B Sends no key here
BIOS folder:
/home/user/.config/retroarch/system
Any key closes this help
=== help 40x15
RetroBIOS: Keys
@@ -1093,6 +1093,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
L2, Tab, o Options
d Details
R2, Esc, Backspace Back
q, Ctrl-C Quit
B Sends no key here
@@ -1101,7 +1102,6 @@
/home/user/.config/retroarch/system
Any key closes this help
=== help 80x24
RetroBIOS: Keys
@@ -1109,6 +1109,7 @@
D-pad, Up/Down Move
A, Start, Enter Install
L2, Tab, o Options
d Details
R2, Esc, Backspace Back
q, Ctrl-C Quit
B Sends no key here
@@ -1126,7 +1127,6 @@
Any key closes this help
=== plan-games 40x12
RetroBIOS: RetroArch
@@ -1139,7 +1139,7 @@
For the games on this card: yes 412
Only what starts: no
Show the games
1-4 of 8
1-4 of 9
A Install R2 Back L2 Options
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1147,13 +1147,13 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
For the 412 games on this card.
> Install
For the games on this card: yes 412
Only what starts: no
Show the games
Choose systems
Copy from an old card or a folder
Details
Options
Quit
A Install R2 Back L2 Options
@@ -1163,11 +1163,6 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
For the games on this card: yes 412 games
@@ -1175,12 +1170,17 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
A Install R2 Back L2 Options
=== games 80x24
RetroBIOS: Games on this card
@@ -1206,4 +1206,83 @@
A Back
=== plan-details 80x24
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
A Back
=== result-details 40x12
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
=== result-details 40x15
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
=== result-details 80x24
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
A Back
+154 -46
View File
@@ -436,10 +436,10 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
Start Install B Back
@@ -449,28 +449,26 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
1 wrong copy: backed up, replaced.
1 in place, 3 missing, 1 wrong copy
Free space: 50.0 GB
> Install
Choose systems
Copy from an old card or a folder
Details
Options
Quit
Start Install B Back
=== plan 80x24
RetroBIOS: RetroArch
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
@@ -483,6 +481,8 @@
Start Install B Back
=== plan-in-place 40x12
RetroBIOS: RetroArch
@@ -490,12 +490,12 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
Start Close B Back
=== plan-in-place 40x15
RetroBIOS: RetroArch
@@ -503,26 +503,24 @@
Every file on the list is in place
BIOS folder:
~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced,
the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
Start Close B Back
=== plan-in-place 80x24
RetroBIOS: RetroArch
Every file on the list is in place
BIOS folder: ~/.config/retroarch/system
5 in place, 0 missing, 0 wrong copies
1 of the 0 wrong copies is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Close
Details
Options
@@ -537,6 +535,8 @@
Start Close B Back
=== systems 40x12
RetroBIOS: Choose systems
@@ -866,39 +866,37 @@
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
Start Install B Back
=== confirm 40x15
RetroBIOS: Confirm
Counted again for these choices.
Nothing is written before Install.
1 file to download, 16.0 KB
BIOS folder: ~/.co.../retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
Start Install B Back
=== confirm 80x24
RetroBIOS: Confirm
Counted again for these choices. Nothing is written before Install.
Counted again for these choices.
1 file to download, 16.0 KB
BIOS folder: ~/.config/retroarch/system
0 in place, 1 missing, 0 wrong copies
Free space: 50.0 GB
> Install
Back
@@ -915,6 +913,8 @@
Start Install B Back
=== installing 40x12
RetroBIOS: Installing
@@ -926,7 +926,7 @@
B stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
B Stop
=== installing 40x15
@@ -939,7 +939,7 @@
B stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -955,7 +955,7 @@
B stops. What is done stays done.
FAILED scph5500.bin (HTTP 404)
ok gba_bios.bin
@@ -976,12 +976,12 @@
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
Start Exit
=== result 40x15
RetroBIOS: Finished with errors
@@ -989,12 +989,12 @@
3 installed, 1 failed.
BIOS folder:
/home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/
retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -1004,11 +1004,11 @@
3 installed, 1 failed.
BIOS folder: /home/user/.config/retroarch/system
failed: scph5500.bin (HTTP 404)
Run it again to retry only those.
The files it replaced are kept in
/home/user/.config/retroarch/retrobios-backup/2026-10-23_1200
Details: /tmp/retrobios-x/install.log
Log: /tmp/retrobios-x/install.log
@@ -1138,12 +1138,12 @@
D-pad, Up/Down Move
Start, Enter Install
o, Tab Options
d Details
B, Esc, Backspace Back
q, Ctrl-C Quit
Select Keyboard on or off
Menu Close the terminal
Any key closes this help
=== help 40x15
RetroBIOS: Keys
@@ -1151,6 +1151,7 @@
D-pad, Up/Down Move
Start, Enter Install
o, Tab Options
d Details
B, Esc, Backspace Back
q, Ctrl-C Quit
Select Keyboard on or off
@@ -1159,7 +1160,6 @@
BIOS folder:
/home/user/.config/retroarch/system
Any key closes this help
=== help 80x24
RetroBIOS: Keys
@@ -1167,6 +1167,7 @@
D-pad, Up/Down Move
Start, Enter Install
o, Tab Options
d Details
B, Esc, Backspace Back
q, Ctrl-C Quit
Select Keyboard on or off
@@ -1184,7 +1185,6 @@
Any key closes this help
=== plan-games 40x12
RetroBIOS: RetroArch
@@ -1197,7 +1197,7 @@
For the games on this card: yes 412
Only what starts: no
Show the games
1-4 of 8
1-4 of 9
Start Install B Back
=== plan-games 40x15
RetroBIOS: RetroArch
@@ -1205,13 +1205,13 @@
4 files to download, 1.0 MB
BIOS folder:
~/.config/retroarch/system
For the 412 games on this card.
> Install
For the games on this card: yes 412
Only what starts: no
Show the games
Choose systems
Copy from an old card or a folder
Details
Options
Quit
Start Install B Back
@@ -1221,11 +1221,6 @@
4 files to download, 1.0 MB
BIOS folder: ~/.config/retroarch/system
For the 412 games on this card.
One region where the games prove it: nintendo-gba Europe.
2 games get every BIOS of their system: Show the games.
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
> Install
For the games on this card: yes 412 games
@@ -1233,12 +1228,17 @@
Show the games
Choose systems
Copy the BIOS files from an old card or a folder
Details
Options
Quit
Start Install B Back
=== games 40x12
RetroBIOS: Games on this card
@@ -1293,4 +1293,112 @@
Start Back
=== plan-details 40x12
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old
one kept in a backup folder.
Free space: 50.0 GB
Start Back
=== plan-details 40x15
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old
one kept in a backup folder.
Free space: 50.0 GB
Start Back
=== plan-details 80x24
RetroBIOS: Details
1 in place, 3 missing, 1 wrong copy
The 1 wrong copy is replaced, the old one kept in a backup folder.
Free space: 50.0 GB
Start Back
=== result-details 40x12
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
Start Back
=== result-details 40x15
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
Start Back
=== result-details 80x24
RetroBIOS: Details
failed: scph5500.bin (HTTP 404)
Start Back
+1 -1
View File
@@ -187,7 +187,7 @@ class InstallerSamplesSayWhatTheCodePrints(unittest.TestCase):
page = _page("installer.md")
refused = _generated(page, "check-refused")
self.assertRegex(refused, r"\n \d+ files? [a-z ]+:\n")
self.assertRegex(refused, r"\n \d+ files? [a-z ]+\.\n")
self.assertIn("read by beetle_psx, pcsx_rearmed at", refused)
self.assertNotRegex(page, r"opened at /\S+ by ")
self.assertIn('"read by ', inspect.getsource(install.opened_line))
+2 -2
View File
@@ -5668,7 +5668,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
proc = _install_run(self.env, "--platform", "retroarch", "--dest", str(dest),
"--check", "--no-input", "--verbose")
self.assertEqual(proc.returncode, 3, proc.stderr)
listing = proc.stdout.split("to download:\n", 1)[1].splitlines()
listing = proc.stdout.split("to download.\n", 1)[1].splitlines()
self.assertEqual(listing[0].strip(), "wrong copy: scph5501.bin")
def test_a_dry_run_counts_the_data_trees_and_ends_on_its_last_line(self):
@@ -5716,7 +5716,7 @@ class RunsAgainstTheRealLists(unittest.TestCase, _LoopbackRun):
"--manifest", str(REPO_ROOT / "install" / "retroarch.json"))
self.assertEqual(proc.returncode, 3, proc.stdout + proc.stderr)
missing = re.search(r"0 in place, (\d+) missing", proc.stdout).group(1)
self.assertIn(f"\n {missing} files not in place:\n", proc.stdout)
self.assertIn(f"\n {missing} files not in place.\n", proc.stdout)
self.assertIn(f" {missing} files need the internet", proc.stdout)
def test_a_cores_folder_can_be_named(self):
+248 -21
View File
@@ -83,6 +83,11 @@ def keys(*names: str) -> list:
return [Key("char", name[5:]) if name.startswith("char:") else Key(name) for name in names]
# The screens as --verbose draws them, every Details line where it belongs:
# the findings marked with it read lines the default leaves to Details.
in_full = mock.patch.object(install, "tui_verbose", lambda _state: True)
def _args(**given) -> argparse.Namespace:
"""The namespace main() parses, every option at its default."""
values = dict(
@@ -1002,19 +1007,7 @@ def golden_states() -> dict:
"bytes_total": 1064964}
installing.finished = [("gba_bios.bin", True, ""), ("scph5500.bin", False, "HTTP 404")]
states["installing"] = installing
result = checked_state()
result.stack.append("result")
result.code = 1
result.log = "/tmp/retrobios-x/install.log"
result.download = installing.download
result.summary = {
"event": "summary", "mode": "install", "installed": 3, "up_to_date": 1, "pending": 1,
"failed": [{"dest": "scph5500.bin", "reason": "HTTP 404"}],
"skipped": [{"reason": "not_found", "label": "not found", "files": 2, "required": 1}],
"left_out": [], "kept": [{"folder": str(HOME / ".config/retroarch/retrobios-backup/"
"2026-10-23_1200"), "files": 1, "bytes": 4}],
"interrupted": False}
states["result"] = result
states["result"] = golden_states_result()
error = fresh_state()
error.stack, error.run = ["setup", "error"], "check"
error.error = [" Could not fetch the file list for retroarch after 3 attempts: "
@@ -1032,9 +1025,33 @@ def golden_states() -> dict:
listed = games_state()
listed.stack.append("games")
states["games"] = listed
# What the plan and the result leave out by default, one press away.
details = checked_state()
details.stack.append("details")
states["plan-details"] = details
told = golden_states_result()
told.stack.append("details")
states["result-details"] = told
return states
def golden_states_result() -> install.TuiState:
"""The result golden_states draws, a file failed and one kept."""
result = checked_state()
result.stack.append("result")
result.code = 1
result.log = "/tmp/retrobios-x/install.log"
result.download = {"event": "download", "files": 4, "bytes": 1064964}
result.summary = {
"event": "summary", "mode": "install", "installed": 3, "up_to_date": 1, "pending": 1,
"failed": [{"dest": "scph5500.bin", "reason": "HTTP 404"}],
"skipped": [{"reason": "not_found", "label": "not found", "files": 2, "required": 1}],
"left_out": [], "kept": [{"folder": str(HOME / ".config/retroarch/retrobios-backup/"
"2026-10-23_1200"), "files": 1, "bytes": 4}],
"interrupted": False}
return result
def result_states() -> dict:
"""The result of a run that installed everything, of one with a file
failed, of one --offline left files out of, and of one stopped."""
@@ -1159,8 +1176,11 @@ class Views(unittest.TestCase):
def test_each_role_paints_a_status_word_on_the_result_screens(self):
"""Done, a part done, files left offline, a stop: between them the
result screens use every role, each on a word that says it."""
# The failed files are listed on the result's Details.
told = result_states()["partial"]
told.stack.append("details")
drawn = "\n".join(install.tui_paint(str(line), line.style, True)
for state in result_states().values()
for state in [*result_states().values(), told]
for line in install.tui_view(state, 80, 24))
for role, word in (("accent", "RetroBIOS"), ("strong+success", "4 files installed"),
("strong+success", "Done"), ("failure", "1 failed"),
@@ -1573,6 +1593,7 @@ class SmallFixes(unittest.TestCase):
self.assertTrue(state.installed_only)
self.assertNotIn("--installed-cores", [f for f, _v in install.tui_flags(state)])
@in_full
def test_the_end_of_a_wrapped_pager_is_reachable(self):
state = checked_state()
state.stack.append("result")
@@ -2081,7 +2102,7 @@ class WorkFolders(unittest.TestCase):
def test_a_failure_keeps_the_log_it_names(self):
work, out = self.run_to(1)
self.assertTrue(work.exists())
self.assertIn(f"Details: {work / 'install.log'}", out)
self.assertIn(f"Log: {work / 'install.log'}", out)
def test_a_stop_leaves_nothing(self):
work, out = self.run_to(130)
@@ -2238,6 +2259,7 @@ class CopyFromAnOldCard(unittest.TestCase):
self.assertEqual(state.from_folders, [Path("/media/old")])
self.assertIn(("--from", "/media/old"), install.tui_flags(state))
@in_full
def test_files_in_the_wrong_place_are_said_and_listed(self):
state = checked_state()
state.platform, state.dest = "retroarch", SYSTEM_DIR
@@ -2778,6 +2800,7 @@ class CardsSpaceAndConfirm(unittest.TestCase):
if row.action == "game_data")
self.assertEqual(label, "Game data: left out")
@in_full
def test_the_plan_says_which_config_named_the_folder(self):
config = HOME / ".config/retroarch/retroarch.cfg"
with mock.patch.dict(install._RETROARCH_CONFIGS, {SYSTEM_DIR: (config, config.parent)}):
@@ -2803,6 +2826,7 @@ class CardsSpaceAndConfirm(unittest.TestCase):
# 1 MB from the network in 2 s, whatever came from the old card.
self.assertIn("512.0 KB/s, 0:02 left", text)
@in_full
def test_the_plan_says_what_the_scan_left_out(self):
state = checked_state()
state.from_folders = [Path("E:\\")]
@@ -3009,6 +3033,7 @@ class SaveDirectoryLeftOut(unittest.TestCase):
install.tui_receive(state, ("ended", state.run_id, 1, []))
return state, summary
@in_full
def test_a_list_that_holds_none_of_them_offers_no_folder(self):
"""RetroPie's list leaves its save files out with no hash or address:
--save-dir installs none of them, and was advised again each run."""
@@ -3024,6 +3049,7 @@ class SaveDirectoryLeftOut(unittest.TestCase):
self.assertEqual([text for text in install.tui_outcome(state)[1] if "save" in text],
[line])
@in_full
def test_files_left_out_of_the_save_directory_are_said(self):
state = fresh_state()
state.stack = ["setup"]
@@ -3673,6 +3699,7 @@ class DataFilesHaveASize(unittest.TestCase):
""""8179 files to download, 6.6 GB, and 2636 data
files", the data files with no size."""
@in_full
def test_the_plan_gives_the_data_files_size(self):
state = fresh_state()
state.stack = ["setup"]
@@ -3720,6 +3747,7 @@ class ThePagerCountsLines(unittest.TestCase):
self.assertTrue(any(re.fullmatch(rf" \d+-{len(wrapped)} of {len(wrapped)}",
line) for line in body), body)
@in_full
def test_the_counter_moves_one_line_per_press(self):
state = self.result_state(40, 12)
first = [line for line in install.tui_view(state, 40, 12) if " of " in line][-1]
@@ -3862,6 +3890,7 @@ class BackTicksAndSaveFolder(unittest.TestCase):
state = install.TuiState()
self.assertLess(abs(state.now - time.monotonic()), 5)
@in_full
def test_a_pack_installs_from_the_pack(self):
state = checked_state()
state.found = [{"event": "found", "platform": "retroarch", "dest": FILES[0]["dest"],
@@ -4152,6 +4181,7 @@ class TheSaveFolderLineFollowsTheChoice(unittest.TestCase):
self.assertEqual(state.screen, "result")
self.assertNotIn("save directory", self.said(install.tui_outcome(state)[1]))
@in_full
def test_kept_the_confirm_screen_and_the_result_name_it(self):
state = self.run_to_result(confirm_saves=True, install_saves=True)
self.assertIn(self.LINE, self.confirm)
@@ -4882,6 +4912,11 @@ class EndToEnd(unittest.TestCase):
screen = term.wait("RetroBIOS is on the KNULLI card")
self.assertIn("start RetroBIOS from Ports", screen)
self.assertNotIn(install.APP_OFFER, screen)
# The command, a Details line, is said after Exit once they were opened.
term.send("d")
term.wait("RetroBIOS: Details")
term.send("\x1b")
term.wait("RetroBIOS is on the KNULLI card")
term.send("\r")
self.assertEqual(term.close(), 0)
self.assertAppOnCard(root, "KNULLI")
@@ -4904,7 +4939,9 @@ class EndToEnd(unittest.TestCase):
after = term.after()
self.assertIn("RetroBIOS: Done", after)
self.assertIn("5 files installed.", after)
self.assertIn("--platform retroarch --dest", after)
# The command is a Details line: said after Exit once they were opened.
self.assertIn("Next: start RetroArch and play.", after)
self.assertNotIn("--platform retroarch --dest", after)
# The cursor and the main screen come back before the result is printed.
self.assertIn(b"\x1b[?25h\x1b[?1049l", term.raw)
@@ -4943,15 +4980,24 @@ class EndToEnd(unittest.TestCase):
term.send("\r")
screen = term.wait("files to download")
self.assertIn("6 files to download", screen)
# The second folder the run writes to, named before
# anything is written, and again on the result.
# The second folder the run writes to, named on the
# plan's Details before anything is written, and on the
# result's.
term.send("d")
screen = term.wait("RetroBIOS: Details")
self.assertIn("1 file read from RetroArch's save directory goes to a "
"folder per core under:\n ~/MySaves", screen)
term.send("\x1b")
term.wait("files to download")
term.send("\r")
screen = term.wait("6 files installed.")
term.wait("6 files installed.")
term.send("d")
screen = term.wait("RetroBIOS: Details")
# Spelled in full on the result, as its other folders.
joined = "".join(line.strip() for line in screen.splitlines())
self.assertIn("folder per core under:" + str(saves), joined)
term.send("\x1b")
term.wait("6 files installed.")
term.send("\r")
self.assertEqual(term.close(), 0)
results.append(written(repo, saves))
@@ -4978,6 +5024,10 @@ class EndToEnd(unittest.TestCase):
self.assertIn("3 files to download", screen)
term.send("\r")
term.wait("3 files installed.")
term.send("d")
term.wait("RetroBIOS: Details")
term.send("\x1b")
term.wait("3 files installed.")
term.send("\r")
self.assertEqual(term.close(), 0)
self.assertEqual(repo.installed(), ["pcsx/extra.bin", "scph5500.bin", "scph5501.bin"])
@@ -4999,9 +5049,13 @@ class EndToEnd(unittest.TestCase):
screen = term.wait("4 files to download")
self.assertIn("> Install", screen)
term.send("\r")
screen = term.wait("installed.")
term.wait("installed.")
term.send("o")
screen = term.wait("RetroBIOS: Details")
self.assertIn("1 game data file left out.", screen)
term.send("\r")
term.wait("installed.")
term.send("\r")
self.assertEqual(term.close(), 0)
self.assertEqual(repo.installed(), ["gba_bios.bin", "mgba/extra.bin",
"pcsx/extra.bin", "scph5501.bin"])
@@ -5090,6 +5144,10 @@ class EndToEnd(unittest.TestCase):
self.assertIn("5 files installed.", screen)
self.assertIn("3 files copied from", screen)
self.assertIn("2 downloaded.", screen)
term.send("o")
term.wait("RetroBIOS: Details")
term.send("\r")
term.wait("files installed.")
term.send("\r")
self.assertEqual(term.close(), 0)
self.assertEqual(len(repo.installed()), 5)
@@ -5808,6 +5866,7 @@ class ThePlanNumbersAddUp(unittest.TestCase):
""""47 files to download" sat above "49 missing, 1 wrong copy": the 3
found on this machine were the difference, left to the reader."""
@in_full
def test_the_copied_files_are_the_difference(self):
state = checked_state()
state.found = [found("scph5500.bin", str(SYSTEM_DIR), "one folder too deep")]
@@ -6441,6 +6500,7 @@ class ConfirmRefusalsAndCardRows(unittest.TestCase):
if row.action == "platform"}
self.assertEqual(labels["knulli"], "KNULLI")
@in_full
def test_offline_plan_counts_agree(self):
""""3 downloaded" under "3 need the internet";
the data files read as if on hand."""
@@ -6871,6 +6931,7 @@ class WhatEachScreenOffers(unittest.TestCase):
rows = install.tui_rows(state)
self.assertEqual(rows[state.focus["browse"]].value, stick)
@in_full
def test_offline_plan_names_the_folder_already_copied_from(self):
state = checked_state()
state.from_folders = [self.root / "from1"]
@@ -6979,6 +7040,7 @@ class WhatEachScreenOffers(unittest.TestCase):
"not known. Name it with --save-dir next time.", text)
self.assertNotIn("the collection does not hold", text)
@in_full
def test_plural_game_data_and_the_backup_line_at_40x12(self):
state = checked_state()
games = [{"dest": f"g{index}.dat", "system": "", "category": install.GAME_DATA}
@@ -7759,6 +7821,7 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings,
self.assertIn("1 game data file left out (--no-game-data)", after)
self.assertNotIn("doom1.wad would", after)
@in_full
def test_the_plan_counts_game_data_apart_and_one_press_leaves_it_out(self):
state = checked_state()
manifest = json.loads(json.dumps(state.manifest))
@@ -7890,6 +7953,7 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings,
if split:
self.assertEqual(int(split[1]) + int(split[2]), int(head[1]))
@in_full
def test_the_screen_divides_the_count_it_shows(self):
state = checked_state()
manifest = json.loads(json.dumps(state.manifest))
@@ -9017,6 +9081,7 @@ class PacksWordingAndDocs(unittest.TestCase):
install.LOCAL.pack = mock.Mock(name="pack")
self.assertIn("to install from the pack", install._pager_items(state)[0])
@in_full
def test_scroll_is_named_only_where_the_text_scrolls(self):
""""Up/Down Scroll" over nine lines that fit."""
state = checked_state()
@@ -10082,6 +10147,7 @@ class CardNamesAndHelp(_CardFixtures, unittest.TestCase):
self.assertNotIn("A/Enter", bar)
self.assertNotIn("B/Esc", bar)
@in_full
def test_the_folder_its_config_named_is_said_under_it(self):
state = checked_state()
long_dest = Path("/home/user/" + "a-long-folder-name/" * 5 + "system")
@@ -10227,6 +10293,7 @@ class TheAndroidResultReadsWhole(unittest.TestCase):
state.cols, state.rows = cols, 40
return install.tui_view(state, cols, 40)
@in_full
def test_a_path_or_a_command_is_never_split_inside_a_word(self):
full = "/sdcard/RetroArch/retrobios-backup/20261027-223524"
for cols in (40, 50, 80):
@@ -10948,6 +11015,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase):
plain.help = True
self.assertNotIn("Tap", " ".join(install.tui_view(plain, 80, 24)))
@in_full
def test_the_result_is_left_by_a_tap(self):
"""The result gave the mouse back, and on Termux
leaving it took the keyboard. A tap on its Exit closes it, and its
@@ -10964,6 +11032,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase):
# Root cause 2: one narrowed list drives every count.
@in_full
def test_the_game_data_row_and_the_save_line_follow_the_choice(self):
"""With only the GBA ticked, the plan said 1 game
data file and a save file of the PlayStation."""
@@ -11001,6 +11070,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase):
word = "left out" if left else "kept"
self.assertRegex(line, rf"^ Game data: {word} +51(, | files, )2\.4 GB$")
@in_full
def test_data_files_are_named_apart(self):
"""Data files beside BIOS files and game data, the
parts adding up to the count above, each kind said once."""
@@ -11013,6 +11083,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase):
"other cores. Data files: the files an emulator reads from a data "
"folder of its own, such as Dolphin's Sys and PPSSPP's assets.", text)
@in_full
def test_confirm_counts_the_kinds_apart(self):
"""Extra criteria: the plan split BIOS files and game
data, Confirm did not."""
@@ -11292,6 +11363,7 @@ class TapsGameDataAndExitCodes(_CardFixtures, unittest.TestCase):
rows = install.tui_rows(state)
self.assertIn(sides[0][1], [row.value for row in rows if row.action == "drive"])
@in_full
def test_named_by_sits_under_its_folder(self):
"""The offline remedy and the narrowing came
between the folder and what named it."""
@@ -11421,7 +11493,7 @@ class TapsOnAPty(unittest.TestCase):
bar = term.screen.display[-1]
self.click(term, bar.index("Exit"), len(term.screen.display) - 1)
self.assertEqual(term.close(), 0)
self.assertIn("Same choice without questions:", term.after())
self.assertIn("Next: start RetroArch and play.", term.after())
self.assertGreater(term.raw.rfind(b"\x1b[?1000l"), mark)
@@ -11742,6 +11814,7 @@ class OneChoicePerRun(unittest.TestCase):
state.exit_code, state.quit_asked = install.QUIT_CODE, True
self.assertIn(note, install.tui_farewell(state))
@in_full
def test_the_help_defines_game_data_at_40_columns(self):
"""The row was a choice nothing explained on the
Miyoo's screen."""
@@ -11807,6 +11880,7 @@ class OneChoicePerRun(unittest.TestCase):
whole="command")
self.assertIn(f" --from-pack {path}", lines)
@in_full
def test_the_definition_is_said_once_and_never_spliced(self):
state = checked_state()
state.systems = []
@@ -11819,6 +11893,7 @@ class OneChoicePerRun(unittest.TestCase):
self.assertIn("Not available here: jazz2/Source/Anims.j2a (Jazz Jackrabbit 2), game "
"data its game reads.", text)
@in_full
def test_the_headline_counts_every_file_once(self):
""""8358 files and 2636 data files", and the
definition dropped at 80 columns."""
@@ -11830,6 +11905,7 @@ class OneChoicePerRun(unittest.TestCase):
self.assertNotIn("and 7 data files", lines[2])
self.assertIn("Data files: the files an emulator reads", text)
@in_full
def test_the_save_line_never_ends_on_its_colon(self):
""""...goes to a folder per core under:" with no
folder at 60x20."""
@@ -11927,6 +12003,7 @@ class OneChoicePerRun(unittest.TestCase):
said = " ".join(install._needed_lines(entries, "Needed"))
self.assertIn("... and 1 more system (--check --verbose lists them all)", said)
@in_full
def test_the_farewell_names_the_option_not_the_screen(self):
state = _installed_state(SYSTEM_DIR)
state.manifest = {**state.manifest, "save_directory": {"folder": "saves",
@@ -12674,6 +12751,7 @@ class ChoiceStateInBothModes(unittest.TestCase):
_title, lines = install.tui_outcome(state)
self.assertIn("7 data files not installed: not in RetroArch_BIOS_Pack.zip.", lines)
@in_full
def test_a_command_at_40_columns_breaks_between_shell_words(self):
"""The terminal folded commands inside a word,
"--platform" ended a line with its value on the next."""
@@ -12707,6 +12785,7 @@ class ChoiceStateInBothModes(unittest.TestCase):
farewell = "\n".join(install.tui_farewell(state))
self.assertIn("/home/moi/retroarch_system/tmp/tui_audit14/sb/a/b/bios", farewell)
@in_full
def test_a_folder_on_its_own_line_has_one_indent(self):
"""The save folder at the label's indent, the
BIOS folder under it, a path's last piece without its indent."""
@@ -13341,6 +13420,7 @@ class OneVocabularyOneCount(unittest.TestCase):
self.assertIn("1 in place, 3 missing, 0 wrong copies", text)
self.assertIn("Nothing installed: 3 files need the internet", text)
@in_full
def test_a_pack_holding_none_offers_no_install(self):
"""A data tree whose folder is the BIOS folder
itself (blueMSX) made any pack hold a data file: Install focused,
@@ -13533,6 +13613,7 @@ class TheFromPlanSaysItsKinds(unittest.TestCase):
"""Every file found in the folder, the plan named
the Game data row and said neither the kinds nor what game data is."""
@in_full
def test_the_kinds_and_the_definition_stay(self):
audit = OneChoicePerRun()
state = audit.game_plan()
@@ -14542,6 +14623,7 @@ class CoresListAndFolderFailures(unittest.TestCase):
# Root cause 6: every other item.
@in_full
def test_offline_the_plan_promises_no_replacement_it_cannot_make(self):
"""Offline, the plan said a wrong copy no folder
holds "is replaced"."""
@@ -14668,6 +14750,7 @@ class GamesOnTheCard(unittest.TestCase):
"""For the games on this card: the first choice where the card holds
games, the whole list one press away (--for-games)."""
@in_full
def test_a_card_with_games_opens_on_them(self):
state = games_state()
self.assertTrue(state.for_games)
@@ -14845,5 +14928,149 @@ class GamesEndToEnd(unittest.TestCase):
written = sorted(p.name for p in card.bios.rglob("*") if p.is_file())
self.assertEqual(written, ["bios_CD_E.bin", "cd_extra.bin"])
# The most words each screen may show by default, one count per size of
# SIZES (owner, 2026-11-09: a beginner lost the important line in text). A
# path is no word. The plan, Confirm and the result say what happens, where
# and what next; their counts, notes and commands wait on Details. A list
# shows more rows on a taller window. A change that adds words to a screen
# raises its numbers here and says why.
SCREEN_WORDS = {
"setup": (29, 36, 34, 34), "platforms": (23, 27, 89, 225), "folder": (27, 27, 25, 25),
"folder-card": (52, 52, 50, 50), "browse": (17, 17, 15, 15), "path": (23, 23, 25, 25),
"create": (23, 23, 21, 21), "checking": (18, 18, 17, 17), "plan": (31, 31, 31, 31),
"plan-in-place": (22, 22, 19, 19), "systems": (36, 37, 36, 36),
"options": (40, 42, 59, 59), "regions": (45, 44, 42, 42), "cores": (47, 47, 45, 45),
"preview": (29, 29, 28, 28), "command": (22, 22, 16, 16), "confirm": (22, 22, 20, 20),
"installing": (32, 32, 31, 31), "result": (29, 29, 27, 27), "error": (37, 34, 32, 31),
"quit": (14, 14, 12, 12), "help": (24, 26, 26, 26), "plan-games": (36, 46, 54, 54),
"games": (36, 45, 44, 44), "plan-details": (30, 30, 29, 29),
"result-details": (34, 34, 23, 23),
}
def screen_words(lines: list) -> int:
"""Words of a drawn screen, its title and bar included, a path left out."""
return sum(1 for line in lines for token in str(line).split()
if re.search(r"[A-Za-z0-9]", token) and "/" not in token)
class ScreenWordBudgets(unittest.TestCase):
def setUp(self):
patcher = mock.patch.object(install, "_mounted_cards", return_value=[])
patcher.start()
self.addCleanup(patcher.stop)
def test_every_screen_keeps_to_its_budget(self):
states = golden_states()
self.assertEqual(sorted(states), sorted(SCREEN_WORDS),
"a screen without a word budget, or a budget without its screen")
for name, state in states.items():
for (cols, rows), budget in zip(SIZES, SCREEN_WORDS[name]):
with self.subTest(screen=name, size=f"{cols}x{rows}"):
state.cols, state.rows = cols, rows
words = screen_words(install.tui_view(state, cols, rows))
self.assertLessEqual(words, budget)
def test_the_default_path_says_what_where_and_next_first(self):
"""The plan opens on what it installs and where, the result on what
happened, where and the next step: nothing between them."""
plan = [str(line).strip() for line in install.tui_view(checked_state(), 80, 24)]
self.assertEqual(plan[2:4], ["4 files to download, 1.0 MB",
"BIOS folder: ~/.config/retroarch/system"])
self.assertEqual(plan[4], "")
done = result_states()["done"]
lines = [str(line).strip() for line in install.tui_view(done, 80, 24)]
self.assertEqual(lines[2:5], ["4 files installed. 1 file already in place.",
f"BIOS folder: {SYSTEM_DIR}",
"Next: start RetroArch and play."])
class DetailsScreen(unittest.TestCase):
"""What the plan, Confirm and the result leave out by default, one key
or one row away, and every line of --verbose in one place or the other."""
def setUp(self):
patcher = mock.patch.object(install, "_mounted_cards", return_value=[])
patcher.start()
self.addCleanup(patcher.stop)
def text(self, state: install.TuiState, cols: int = 80, rows: int = 24) -> str:
return "\n".join(str(line) for line in install.tui_view(state, cols, rows))
def test_d_opens_the_plans_details_and_b_comes_back(self):
state = checked_state()
self.assertNotIn("Free space", self.text(state))
press(state, "d")
self.assertEqual(state.screen, "details")
shown = self.text(state)
for line in ("1 in place, 3 missing, 1 wrong copy", "Free space: 50.0 GB",
"The 1 wrong copy is replaced"):
self.assertIn(line, shown)
press(state, "esc")
self.assertEqual(state.screen, "plan")
def test_a_controller_reaches_them_by_the_row(self):
state = checked_state()
rows = install.tui_rows(state)
state.focus["plan"] = [row.action for row in rows].index("details")
self.assertIn("A/Enter Show", self.text(state))
press(state, "enter")
self.assertEqual(state.screen, "details")
press(state, "enter")
self.assertEqual(state.screen, "plan")
def test_the_results_details_are_said_after_exit_once_opened(self):
state = golden_states_result()
self.assertIn("Y/o Details", self.text(state))
self.assertNotIn("Same choice without questions", "\n".join(install.tui_farewell(state)))
press(state, "o")
self.assertEqual(state.screen, "details")
self.assertIn("Same choice without questions:", self.text(state))
press(state, "esc")
self.assertEqual(state.screen, "result")
press(state, "enter")
farewell = "\n".join(install.tui_farewell(state))
self.assertIn("Same choice without questions:", farewell)
self.assertIn("failed: scph5500.bin (HTTP 404)", farewell)
def test_confirm_has_its_details_too(self):
state = golden_states()["confirm"]
self.assertNotIn("Free space", self.text(state))
press(state, "d")
self.assertEqual(state.screen, "details")
self.assertIn("Nothing is written before Install.", self.text(state))
self.assertIn("Free space: 50.0 GB", self.text(state))
def test_every_line_is_on_the_screen_or_its_details(self):
"""The screen and its Details together say what --verbose says on
the screen alone: no line is lost."""
for name in ("plan", "plan-games", "plan-in-place", "confirm", "result"):
with self.subTest(screen=name):
state = golden_states()[name]
whole = (install._plan_text(state) if state.screen == "plan"
else install._confirm_text(state) if state.screen == "confirm"
else install.tui_outcome(state)[1])
shown = install._shown(state, whole)
state.stack.append("details")
told = install.details_lines(state)
self.assertEqual(sorted(map(str, whole)),
sorted(map(str, [*shown, *[line for line in told
if install._is_detail(line)]])))
def test_verbose_draws_them_in_place_and_offers_no_row(self):
state = checked_state()
state.passthrough = [("--verbose", None)]
text = self.text(state)
self.assertIn("Free space: 50.0 GB", text)
self.assertNotIn("details", [row.action for row in install.tui_rows(state)])
def test_installing_lists_the_files_that_went_well_with_verbose(self):
state = golden_states()["installing"]
self.assertNotIn("gba_bios.bin", self.text(state))
self.assertIn("FAILED scph5500.bin (HTTP 404)", self.text(state))
state.passthrough = [("--verbose", None)]
self.assertIn("ok gba_bios.bin", self.text(state))
if __name__ == "__main__":
unittest.main()
+3 -3
View File
@@ -287,7 +287,7 @@ class InstallerLeavesGameDataOut(unittest.TestCase):
def test_install_leaves_it_out_and_names_it(self):
self.serve()
proc = self.run_installer("--no-game-data")
proc = self.run_installer("--no-game-data", "--verbose")
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
self.assertTrue((self.bios / "a.bin").exists())
self.assertFalse((self.bios / "game.wad").exists())
@@ -297,10 +297,10 @@ class InstallerLeavesGameDataOut(unittest.TestCase):
def test_check_and_dry_run_leave_it_out(self):
self.serve()
for mode, listed in (("--check", "1 file to download:"),
for mode, listed in (("--check", "1 file to download."),
("--dry-run", "Would download 1 file")):
with self.subTest(mode=mode):
proc = self.run_installer("--no-game-data", mode)
proc = self.run_installer("--no-game-data", mode, "--verbose")
self.assertIn(
"2 game data files left out (--no-game-data), 1 of them not installable: "
"game.wad, level.dat",
+14 -10
View File
@@ -171,8 +171,9 @@ Enter checks the BIOS folder when nothing can be copied.
Run at a terminal, the installer opens a full screen that a keyboard or a
controller drives. Three presses of A or Enter install everything the setup
reads: the setup found here, the plan, then the result. The plan screen says
how many files are missing, how much they weigh, how many are in place and how
much space is free, before anything is written.
what it installs, its size and where, before anything is written. **Details**
(`d`) adds the rest: how many files are in place, the free space, the files
left out and why.
The other choices sit one press away. **Choose systems** ticks the consoles to
keep, with the total to download under the list. It opens on its first system,
@@ -207,6 +208,7 @@ install starts.
| Tick, untick | Space, Right, Left | X, D-pad Right and Left (X alone inside muxterm, Y with muxterm's own keys) |
| Back | Esc, Backspace | B, Select (B alone with muxterm's own keys, where Select shows its keyboard) |
| Options | `o`, Tab | Y |
| Details | `d`, and `o` or Tab on the result | the Details row, Y on the result |
| 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 (F1 alone while typing a filter, where the help lists the keys that do not type) | |
| Stop an install | Esc, `q`, Ctrl+C | B, Select+Start (B alone with muxterm's own keys) |
@@ -229,11 +231,12 @@ 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. 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
keeps its log and names it, and every other run leaves nothing behind. A path
on the result is never split inside a word: one longer than the window takes
a line of its own, which the terminal folds. A command breaks only between its
result says how many files were installed and the next step, and it stays
printed in the terminal once the screen closes. Its **Details** hold the
command that repeats the run, printed in the terminal too once they were
opened. A run that failed keeps its log and names it, and every other run
leaves nothing behind. A path on the result is never split inside a word: one
longer than the window takes a line of its own, which the terminal folds. A command breaks only between its
arguments, an option kept with its value, each line but the last ending with
the continuation its shell reads (a backslash in sh, a backtick in PowerShell), so
the lines copied run as one command. Where an option and its path do not fit
@@ -315,8 +318,9 @@ them back on every way out, a stop with Ctrl+Z included. On the command line
screen, any screen showing a command and the screen where a path is typed,
the terminal keeps the mouse, so text is selected, copied and pasted as usual.
The result takes taps, so a touch screen can leave it: it is printed again in
the terminal once the screen closes, its commands with it, and its last line
says so. Elsewhere, and on the result, hold Shift while selecting. `--plain`
the terminal once the screen closes, with its commands when its Details were
opened, and the last line of the Details says so. Elsewhere, and on the
result, hold Shift while selecting. `--plain`
never asks for clicks. Clicks and taps were checked on 2026-10-27 in xterm,
tmux, GNU screen 4.09, Windows Terminal (WSL) and Termux
on Android 17. macOS Terminal and iTerm2 are not checked yet, nor the key
@@ -618,7 +622,7 @@ against a list of four files:
<!-- generated: check-refused -->
```
3 files to download:
3 files to download.
2 of these files are in the BIOS folder in the wrong place: a run without --check copies them where the cores open them, and leaves the copies found as they are.
wrong copy: scph5501.bin
another region: the contents of scph5500.bin (japan)