diff --git a/install.ps1 b/install.ps1 index 087b4755c..5d08082f3 100644 --- a/install.ps1 +++ b/install.ps1 @@ -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 diff --git a/install.py b/install.py index 5d50497f8..6f1431495 100644 --- a/install.py +++ b/install.py @@ -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 diff --git a/install.sh b/install.sh index 36aaf3311..4c22d6cb4 100755 --- a/install.sh +++ b/install.sh @@ -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 diff --git a/install/launchers/index.json b/install/launchers/index.json index c056dc24c..4b00af4b4 100644 --- a/install/launchers/index.json +++ b/install/launchers/index.json @@ -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 }, { diff --git a/scripts/generate_installer_doc.py b/scripts/generate_installer_doc.py index 7baf85733..5a1b795e8 100644 --- a/scripts/generate_installer_doc.py +++ b/scripts/generate_installer_doc.py @@ -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 ")) diff --git a/tests/fixtures/tui/colour-120x40.txt b/tests/fixtures/tui/colour-120x40.txt index 536322f7f..66389a8c2 100644 --- a/tests/fixtures/tui/colour-120x40.txt +++ b/tests/fixtures/tui/colour-120x40.txt @@ -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 + + + + + + + + + + + + + + + + + + + + diff --git a/tests/fixtures/tui/colour-40x12.txt b/tests/fixtures/tui/colour-40x12.txt index ce9ed9559..cfdbdf301 100644 --- a/tests/fixtures/tui/colour-40x12.txt +++ b/tests/fixtures/tui/colour-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/colour-40x15.txt b/tests/fixtures/tui/colour-40x15.txt index 8b56ed9b5..4772e545b 100644 --- a/tests/fixtures/tui/colour-40x15.txt +++ b/tests/fixtures/tui/colour-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/colour-80x24.txt b/tests/fixtures/tui/colour-80x24.txt index 1fbde9a63..f86488285 100644 --- a/tests/fixtures/tui/colour-80x24.txt +++ b/tests/fixtures/tui/colour-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/confirm-120x40.txt b/tests/fixtures/tui/confirm-120x40.txt index c870132df..733790008 100644 --- a/tests/fixtures/tui/confirm-120x40.txt +++ b/tests/fixtures/tui/confirm-120x40.txt @@ -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 @@ + + diff --git a/tests/fixtures/tui/confirm-40x12.txt b/tests/fixtures/tui/confirm-40x12.txt index 9e57bb545..22629b910 100644 --- a/tests/fixtures/tui/confirm-40x12.txt +++ b/tests/fixtures/tui/confirm-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/confirm-40x15.txt b/tests/fixtures/tui/confirm-40x15.txt index d18f06885..572a2678f 100644 --- a/tests/fixtures/tui/confirm-40x15.txt +++ b/tests/fixtures/tui/confirm-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/confirm-80x24.txt b/tests/fixtures/tui/confirm-80x24.txt index a44f71b14..ba06ca00a 100644 --- a/tests/fixtures/tui/confirm-80x24.txt +++ b/tests/fixtures/tui/confirm-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/help-120x40.txt b/tests/fixtures/tui/help-120x40.txt index 71ba78093..edf48ff0f 100644 --- a/tests/fixtures/tui/help-120x40.txt +++ b/tests/fixtures/tui/help-120x40.txt @@ -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 diff --git a/tests/fixtures/tui/help-40x12.txt b/tests/fixtures/tui/help-40x12.txt index 09b22304d..5362abd16 100644 --- a/tests/fixtures/tui/help-40x12.txt +++ b/tests/fixtures/tui/help-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/help-40x15.txt b/tests/fixtures/tui/help-40x15.txt index 830acb87b..4ee7e371c 100644 --- a/tests/fixtures/tui/help-40x15.txt +++ b/tests/fixtures/tui/help-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/help-80x24.txt b/tests/fixtures/tui/help-80x24.txt index 557dd2178..b22ec4987 100644 --- a/tests/fixtures/tui/help-80x24.txt +++ b/tests/fixtures/tui/help-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/installing-120x40.txt b/tests/fixtures/tui/installing-120x40.txt index ff7651b12..3660aebba 100644 --- a/tests/fixtures/tui/installing-120x40.txt +++ b/tests/fixtures/tui/installing-120x40.txt @@ -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 + diff --git a/tests/fixtures/tui/installing-40x12.txt b/tests/fixtures/tui/installing-40x12.txt index d56a30bbd..e92b7c2f3 100644 --- a/tests/fixtures/tui/installing-40x12.txt +++ b/tests/fixtures/tui/installing-40x12.txt @@ -8,5 +8,5 @@ is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + B Stop ? Help diff --git a/tests/fixtures/tui/installing-40x15.txt b/tests/fixtures/tui/installing-40x15.txt index 950ad6515..011e1dce2 100644 --- a/tests/fixtures/tui/installing-40x15.txt +++ b/tests/fixtures/tui/installing-40x15.txt @@ -8,7 +8,7 @@ is done stays done. FAILED scph5500.bin (HTTP 404) - ok gba_bios.bin + diff --git a/tests/fixtures/tui/installing-80x24.txt b/tests/fixtures/tui/installing-80x24.txt index fdd275588..338c47ec9 100644 --- a/tests/fixtures/tui/installing-80x24.txt +++ b/tests/fixtures/tui/installing-80x24.txt @@ -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 + diff --git a/tests/fixtures/tui/plan-120x40.txt b/tests/fixtures/tui/plan-120x40.txt index 3ca54cb75..ca67ddd86 100644 --- a/tests/fixtures/tui/plan-120x40.txt +++ b/tests/fixtures/tui/plan-120x40.txt @@ -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 @@ + + diff --git a/tests/fixtures/tui/plan-40x12.txt b/tests/fixtures/tui/plan-40x12.txt index ef7c55353..26f08e468 100644 --- a/tests/fixtures/tui/plan-40x12.txt +++ b/tests/fixtures/tui/plan-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/plan-40x15.txt b/tests/fixtures/tui/plan-40x15.txt index bf4817eda..5e2e6a6ea 100644 --- a/tests/fixtures/tui/plan-40x15.txt +++ b/tests/fixtures/tui/plan-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/plan-80x24.txt b/tests/fixtures/tui/plan-80x24.txt index 112f7c53a..09a860db6 100644 --- a/tests/fixtures/tui/plan-80x24.txt +++ b/tests/fixtures/tui/plan-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/plan-details-120x40.txt b/tests/fixtures/tui/plan-details-120x40.txt new file mode 100644 index 000000000..a875ed363 --- /dev/null +++ b/tests/fixtures/tui/plan-details-120x40.txt @@ -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 diff --git a/tests/fixtures/tui/plan-details-40x12.txt b/tests/fixtures/tui/plan-details-40x12.txt new file mode 100644 index 000000000..01c228e8e --- /dev/null +++ b/tests/fixtures/tui/plan-details-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/plan-details-40x15.txt b/tests/fixtures/tui/plan-details-40x15.txt new file mode 100644 index 000000000..04d3cb149 --- /dev/null +++ b/tests/fixtures/tui/plan-details-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/plan-details-80x24.txt b/tests/fixtures/tui/plan-details-80x24.txt new file mode 100644 index 000000000..5e33341d1 --- /dev/null +++ b/tests/fixtures/tui/plan-details-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/plan-games-120x40.txt b/tests/fixtures/tui/plan-games-120x40.txt index 14b9e837a..157d4e6e9 100644 --- a/tests/fixtures/tui/plan-games-120x40.txt +++ b/tests/fixtures/tui/plan-games-120x40.txt @@ -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 @@ + + + + diff --git a/tests/fixtures/tui/plan-games-40x12.txt b/tests/fixtures/tui/plan-games-40x12.txt index 34dfd18a2..800da31b1 100644 --- a/tests/fixtures/tui/plan-games-40x12.txt +++ b/tests/fixtures/tui/plan-games-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/plan-games-40x15.txt b/tests/fixtures/tui/plan-games-40x15.txt index b8573927e..2d208f0e1 100644 --- a/tests/fixtures/tui/plan-games-40x15.txt +++ b/tests/fixtures/tui/plan-games-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/plan-games-80x24.txt b/tests/fixtures/tui/plan-games-80x24.txt index a6389d14b..81c89f428 100644 --- a/tests/fixtures/tui/plan-games-80x24.txt +++ b/tests/fixtures/tui/plan-games-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/plan-in-place-120x40.txt b/tests/fixtures/tui/plan-in-place-120x40.txt index 0e5b41f91..7001d8a90 100644 --- a/tests/fixtures/tui/plan-in-place-120x40.txt +++ b/tests/fixtures/tui/plan-in-place-120x40.txt @@ -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 @@ + + diff --git a/tests/fixtures/tui/plan-in-place-40x12.txt b/tests/fixtures/tui/plan-in-place-40x12.txt index 83ce5207e..7b46aabc7 100644 --- a/tests/fixtures/tui/plan-in-place-40x12.txt +++ b/tests/fixtures/tui/plan-in-place-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/plan-in-place-40x15.txt b/tests/fixtures/tui/plan-in-place-40x15.txt index f5f2d9033..182af92d6 100644 --- a/tests/fixtures/tui/plan-in-place-40x15.txt +++ b/tests/fixtures/tui/plan-in-place-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/plan-in-place-80x24.txt b/tests/fixtures/tui/plan-in-place-80x24.txt index da0702005..36673c825 100644 --- a/tests/fixtures/tui/plan-in-place-80x24.txt +++ b/tests/fixtures/tui/plan-in-place-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/result-120x40.txt b/tests/fixtures/tui/result-120x40.txt index 550ec7724..628078bd4 100644 --- a/tests/fixtures/tui/result-120x40.txt +++ b/tests/fixtures/tui/result-120x40.txt @@ -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 diff --git a/tests/fixtures/tui/result-40x12.txt b/tests/fixtures/tui/result-40x12.txt index 12339e200..d0c87bb72 100644 --- a/tests/fixtures/tui/result-40x12.txt +++ b/tests/fixtures/tui/result-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/result-40x15.txt b/tests/fixtures/tui/result-40x15.txt index 61db5344b..395f4cf8e 100644 --- a/tests/fixtures/tui/result-40x15.txt +++ b/tests/fixtures/tui/result-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/result-80x24.txt b/tests/fixtures/tui/result-80x24.txt index ab4770376..ca5097819 100644 --- a/tests/fixtures/tui/result-80x24.txt +++ b/tests/fixtures/tui/result-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/result-details-120x40.txt b/tests/fixtures/tui/result-details-120x40.txt new file mode 100644 index 000000000..1896a865d --- /dev/null +++ b/tests/fixtures/tui/result-details-120x40.txt @@ -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 diff --git a/tests/fixtures/tui/result-details-40x12.txt b/tests/fixtures/tui/result-details-40x12.txt new file mode 100644 index 000000000..063668de9 --- /dev/null +++ b/tests/fixtures/tui/result-details-40x12.txt @@ -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 diff --git a/tests/fixtures/tui/result-details-40x15.txt b/tests/fixtures/tui/result-details-40x15.txt new file mode 100644 index 000000000..efd9f6523 --- /dev/null +++ b/tests/fixtures/tui/result-details-40x15.txt @@ -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 diff --git a/tests/fixtures/tui/result-details-80x24.txt b/tests/fixtures/tui/result-details-80x24.txt new file mode 100644 index 000000000..9d05dd8aa --- /dev/null +++ b/tests/fixtures/tui/result-details-80x24.txt @@ -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 diff --git a/tests/fixtures/tui/route-evmapy.txt b/tests/fixtures/tui/route-evmapy.txt index 5f3beed24..b8a915afb 100644 --- a/tests/fixtures/tui/route-evmapy.txt +++ b/tests/fixtures/tui/route-evmapy.txt @@ -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 diff --git a/tests/fixtures/tui/route-gptokeyb.txt b/tests/fixtures/tui/route-gptokeyb.txt index 13e24690f..f1179b688 100644 --- a/tests/fixtures/tui/route-gptokeyb.txt +++ b/tests/fixtures/tui/route-gptokeyb.txt @@ -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 diff --git a/tests/fixtures/tui/route-gptokeyb_muxterm.txt b/tests/fixtures/tui/route-gptokeyb_muxterm.txt index 9342b9667..c285fd3d9 100644 --- a/tests/fixtures/tui/route-gptokeyb_muxterm.txt +++ b/tests/fixtures/tui/route-gptokeyb_muxterm.txt @@ -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 diff --git a/tests/fixtures/tui/route-keys.txt b/tests/fixtures/tui/route-keys.txt index 4d2e586eb..557245079 100644 --- a/tests/fixtures/tui/route-keys.txt +++ b/tests/fixtures/tui/route-keys.txt @@ -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 diff --git a/tests/fixtures/tui/route-miyoo.txt b/tests/fixtures/tui/route-miyoo.txt index ab456df22..9c0dc475a 100644 --- a/tests/fixtures/tui/route-miyoo.txt +++ b/tests/fixtures/tui/route-miyoo.txt @@ -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 diff --git a/tests/fixtures/tui/route-muxterm.txt b/tests/fixtures/tui/route-muxterm.txt index 2f19f13e7..f118e37e6 100644 --- a/tests/fixtures/tui/route-muxterm.txt +++ b/tests/fixtures/tui/route-muxterm.txt @@ -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 diff --git a/tests/test_doc_pages.py b/tests/test_doc_pages.py index bcfda2ef0..d8a558358 100644 --- a/tests/test_doc_pages.py +++ b/tests/test_doc_pages.py @@ -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)) diff --git a/tests/test_install.py b/tests/test_install.py index eba661cfa..41e7aab15 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -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): diff --git a/tests/test_install_tui.py b/tests/test_install_tui.py index 785e379f8..b0aaa73ce 100644 --- a/tests/test_install_tui.py +++ b/tests/test_install_tui.py @@ -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() diff --git a/tests/test_no_game_data.py b/tests/test_no_game_data.py index 2bb59c2fc..42a9d571f 100644 --- a/tests/test_no_game_data.py +++ b/tests/test_no_game_data.py @@ -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", diff --git a/wiki/installer.md b/wiki/installer.md index 5ce100f68..55c2899a9 100644 --- a/wiki/installer.md +++ b/wiki/installer.md @@ -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: ``` - 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)