diff --git a/install.ps1 b/install.ps1 index 6ad5678a..dc685b85 100644 --- a/install.ps1 +++ b/install.ps1 @@ -8,7 +8,7 @@ param( $ErrorActionPreference = "Stop" $defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" -$defaultInstallSha256 = "f2a35f8df5956bb8b7ff1d697c0c204688d911a8942477b6d084882a92349a3b" +$defaultInstallSha256 = "974ecc9fd5fc23433ebd50488629abc20aa861a21389cf31044643ddd6e62418" $maximumInstallerBytes = 2MB $installerExit = 0 $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } diff --git a/install.py b/install.py index be342a2c..5b424eba 100644 --- a/install.py +++ b/install.py @@ -2599,6 +2599,9 @@ def _prompt_manual_platform(os_type: str) -> list[tuple[str, Path]]: plat = AVAILABLE_PLATFORMS[int(choice) - 1] elif choice in AVAILABLE_PLATFORMS: plat = choice + else: + print(f" Type a number from 1 to {len(AVAILABLE_PLATFORMS)}, a platform name, " + "or q to quit.") default_dest = _default_dest(os_type, plat) try: raw = input(f"BIOS directory [{default_dest}]: ").strip() @@ -2652,26 +2655,24 @@ def _prompt_platform_choice( print("\nInstall for:") for i, (name, path) in enumerate(platforms, 1): print(f" {i}) {name.capitalize()} ({path})") + last = len(platforms) + (1 if len(platforms) > 1 else 0) if len(platforms) > 1: - print(f" {len(platforms) + 1}) All") + print(f" {last}) All") + print(" q) quit") print() while True: - try: - choice = input("> ").strip() - except (EOFError, KeyboardInterrupt): - print() + choice = _ask("> ").lower() + if choice == "q": sys.exit(0) - if not choice: - continue - try: - idx = int(choice) - except ValueError: - continue + idx = int(choice) if choice.isdigit() else 0 if 1 <= idx <= len(platforms): return [platforms[idx - 1]] - if idx == len(platforms) + 1 and len(platforms) > 1: + if idx == last and len(platforms) > 1: return platforms + # A wrong answer used to bring back a bare prompt, and nothing said + # how to leave it. + print(f" Type a number from 1 to {last}, or q to quit.") def _ask(prompt: str) -> str: @@ -2741,6 +2742,8 @@ def _prompt_custom_selection( return INSTALLED_ONLY if answer == "c": break + keys = "Enter, i, c or q" if installed is not None else "Enter, c or q" + print(f" Type {keys}.") choices = available_choices(files, omitted) if OTHER_SYSTEMS in choices["systems"]: diff --git a/install.sh b/install.sh index f4be7c18..5441786c 100755 --- a/install.sh +++ b/install.sh @@ -18,7 +18,7 @@ esac TEMP_INSTALLER="" TEMP_DIRECTORY="" DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" -DEFAULT_INSTALL_SHA256="f2a35f8df5956bb8b7ff1d697c0c204688d911a8942477b6d084882a92349a3b" +DEFAULT_INSTALL_SHA256="974ecc9fd5fc23433ebd50488629abc20aa861a21389cf31044643ddd6e62418" MAX_INSTALLER_BYTES=2097152 cleanup() { diff --git a/tests/test_install.py b/tests/test_install.py index 101295d8..35e3cf10 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -1514,6 +1514,39 @@ class TestDestinationFollowsUserLinks(unittest.TestCase): install._destination_path(bios, "/etc/passwd") +class TestDetectedPlatformPrompt(unittest.TestCase): + """With two platforms detected the menu had no quit entry, and q or any + wrong answer brought back a bare prompt.""" + + PLATFORMS = [("emudeck", Path("/e")), ("retroarch", Path("/r"))] + + def _answer(self, *answers: str): + replies = iter(answers) + out = io.StringIO() + with unittest.mock.patch("builtins.input", lambda _prompt="": next(replies)), \ + contextlib.redirect_stdout(out): + try: + result = install._prompt_platform_choice(self.PLATFORMS) + except SystemExit as exc: + result = exc + return result, out.getvalue() + + def test_q_quits_and_the_menu_says_so(self): + result, out = self._answer("q") + self.assertIsInstance(result, SystemExit) + self.assertEqual(result.code, 0) + self.assertIn("q) quit", out) + + def test_a_wrong_answer_names_the_choices(self): + result, out = self._answer("x", "2") + self.assertEqual(result, [self.PLATFORMS[1]]) + self.assertIn("Type a number from 1 to 3, or q to quit.", out) + + def test_all_installs_every_platform(self): + result, _ = self._answer("3") + self.assertEqual(result, self.PLATFORMS) + + class TestManualPlatformPrompt(unittest.TestCase): """With nothing detected, an interactive run asks instead of exiting.""" @@ -1543,6 +1576,14 @@ class TestManualPlatformPrompt(unittest.TestCase): install._prompt_manual_platform("linux") self.assertEqual(raised.exception.code, 0) + def test_a_wrong_answer_says_what_to_type(self): + answers = iter(["99", "1", ""]) + out = io.StringIO() + with unittest.mock.patch("builtins.input", lambda _prompt="": next(answers)), \ + contextlib.redirect_stdout(out): + install._prompt_manual_platform("linux") + self.assertIn("or q to quit", out.getvalue()) + def test_windows_hint_shows_the_one_liner_with_arguments(self): hint = "\n".join(install._manual_usage_hint("windows")) self.assertIn("--platform retroarch --dest", hint)