chore: merge origin/main

This commit is contained in:
Abdessamad Derraz committed 2026-11-09 20:01:25 +01:00
commit 7b90d94ebe
8 files changed
+75 -13

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@
# and Invoke-WebRequest throws on a cut transfer before the hash is read:
# the site's build rewrites this line there (scripts/sitebootstrap.py).
$mismatchAdvice = "The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
$defaultInstallSha256 = "e076488b9766904d7f859e0463e55214fed9386dcaaca362b04a371a820c6c7c"
$defaultInstallSha256 = "28316d79b6f4f846f8091bc27e59655894aee48905be686b7971554c2fe17dbc"
$maximumInstallerBytes = 2MB
$installerExit = 0
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
+16
View File
@@ -6559,6 +6559,20 @@ def _command_rank(option: tuple[str, str | None]) -> int:
return _COMMAND_ORDER.index(flag) if flag in _COMMAND_ORDER else len(_COMMAND_ORDER)
def package_command(prefix: str) -> str:
"""The command that ran the retrobios package, read from the environment
it runs in. uvx runs it from uv's cache (~/.cache/uv/archive-v0/<id>
with uv 0.12.9) and pipx run from pipx's (~/.cache/pipx/<id> with
pipx 1.4.3), and neither leaves a retrobios command behind. pip, pipx
install (pipx's venvs/) and uv tool install do."""
parts = re.split(r"[\\/]", prefix)
if "archive-v0" in parts:
return "uvx retrobios"
if any(part in ("pipx", ".pipx") for part in parts) and "venvs" not in parts:
return "pipx run retrobios"
return "retrobios"
class Invocation:
"""How this run was started, so that a hint gives the command back whole.
@@ -6615,6 +6629,8 @@ class Invocation:
return f"&([scriptblock]::Create((irm {BOOTSTRAP_URL}.ps1)))"
if bootstrap == "sh":
return f"curl -fsSL {BOOTSTRAP_URL} | {'sudo ' if elevated else ''}sh -s --"
if bootstrap == "pypi":
return f"{'sudo ' if elevated else ''}{package_command(sys.prefix)}"
python = "python" if self.os_type == "windows" else "python3"
return f"{'sudo ' if elevated else ''}{python} install.py"
+1 -1
View File
@@ -23,7 +23,7 @@ DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/ins
# curl or wget stop on a cut transfer before the hash is read: the site's
# build rewrites this line there (scripts/sitebootstrap.py).
MISMATCH_ADVICE="The download was most likely cut short: try again. Within minutes of an update of this project the two files can come from caches of different ages. Waiting five minutes settles that."
DEFAULT_INSTALL_SHA256="e076488b9766904d7f859e0463e55214fed9386dcaaca362b04a371a820c6c7c"
DEFAULT_INSTALL_SHA256="28316d79b6f4f846f8091bc27e59655894aee48905be686b7971554c2fe17dbc"
MAX_INSTALLER_BYTES=2097152
cleanup() {
+8 -8
View File
@@ -27,8 +27,8 @@
{
"dest": "roms/ports/retrobios/install.py",
"repo_path": "install.py",
"size": 1142840,
"sha256": "e076488b9766904d7f859e0463e55214fed9386dcaaca362b04a371a820c6c7c",
"size": 1143586,
"sha256": "28316d79b6f4f846f8091bc27e59655894aee48905be686b7971554c2fe17dbc",
"executable": false
},
{
@@ -71,8 +71,8 @@
"muos": {
"archive": {
"dest": "ARCHIVE/RetroBIOS.muxapp",
"size": 1196465,
"sha256": "7ef6e947618ffe51b95823b28ce2a064c6eddf2b7fb77e2066f9c2d279176f03"
"size": 1197211,
"sha256": "c66dc01820e1610e7e476b417a44fc3c9007886d574aef81bcdb41441f1e1a8c"
},
"members": [
{
@@ -92,8 +92,8 @@
{
"name": "RetroBIOS/install.py",
"repo_path": "install.py",
"size": 1142840,
"sha256": "e076488b9766904d7f859e0463e55214fed9386dcaaca362b04a371a820c6c7c",
"size": 1143586,
"sha256": "28316d79b6f4f846f8091bc27e59655894aee48905be686b7971554c2fe17dbc",
"executable": false
},
{
@@ -166,8 +166,8 @@
{
"dest": ".config/modules/retrobios/install.py",
"repo_path": "install.py",
"size": 1142840,
"sha256": "e076488b9766904d7f859e0463e55214fed9386dcaaca362b04a371a820c6c7c",
"size": 1143586,
"sha256": "28316d79b6f4f846f8091bc27e59655894aee48905be686b7971554c2fe17dbc",
"executable": false
},
{
+3
View File
@@ -44,6 +44,7 @@ MODULE = "retrobios"
# keeps the exit codes it gives a reader that left (141) and Ctrl+C (130).
LAUNCHER = '''"""The RetroBIOS installer, install.py, run as the retrobios command."""
import os
import runpy
from pathlib import Path
@@ -51,6 +52,8 @@ __version__ = "{version}"
def main() -> None:
# The hints give back the command that ran this, not python3 install.py.
os.environ["RETROBIOS_BOOTSTRAP"] = "pypi"
runpy.run_path(str(Path(__file__).with_name("install.py")), run_name="__main__")
'''
+27
View File
@@ -7721,5 +7721,32 @@ class TheListVersionIsSaidBeforeAndAfter(unittest.TestCase):
self.assertNotIn("This list was built for", proc.stdout)
class APackageHintNamesThePackageCommand(unittest.TestCase):
"""Run from the retrobios package, a hint said `python3 install.py`,
a file the user does not have."""
def test_the_environment_names_the_command(self):
for prefix, command in (
("/home/me/.cache/uv/archive-v0/UwL4i3xOlCEYSTnw", "uvx retrobios"),
("C:\\Users\\me\\AppData\\Local\\uv\\cache\\archive-v0\\x1", "uvx retrobios"),
("/home/me/.cache/pipx/539b8243c11ee7c", "pipx run retrobios"),
("/home/me/.local/pipx/.cache/539b8243c11ee7c", "pipx run retrobios"),
("/home/me/.local/share/pipx/venvs/retrobios", "retrobios"),
("/home/me/.local/share/uv/tools/retrobios", "retrobios"),
("/home/me/venv", "retrobios"),
):
with self.subTest(prefix=prefix):
self.assertEqual(install.package_command(prefix), command)
def test_the_launcher_is_the_package_command(self):
hint = install.Invocation()
with unittest.mock.patch.dict(os.environ, {"RETROBIOS_BOOTSTRAP": "pypi"}), \
unittest.mock.patch.object(install.sys, "prefix", "/home/me/.cache/uv/archive-v0/a"):
self.assertEqual(hint.launcher(), "uvx retrobios")
self.assertEqual(hint.launcher(elevated=True), "sudo uvx retrobios")
self.assertTrue(hint.command("retroarch", "DIR").startswith(
"uvx retrobios --platform retroarch --dest DIR"))
if __name__ == "__main__":
unittest.main()
+18 -2
View File
@@ -186,8 +186,10 @@ class TheInstalledCommandIsTheInstaller(Built):
def _same_answers(self, python: str, name: str) -> None:
command = self._installed(python, name)
# `retrobios` and `python -m retrobios` both run install.py.
# `retrobios` and `python -m retrobios` both run install.py, whose
# examples then name the package command.
launchers = ([str(command)], [str(command.with_name("python")), "-m", "retrobios"])
as_package = {**os.environ, "RETROBIOS_BOOTSTRAP": "pypi"}
for launcher in launchers:
for args in (["--help"], ["--version"], ["--no-such-option"]):
with self.subTest(python=name, launcher=launcher[-1], args=args):
@@ -195,7 +197,7 @@ class TheInstalledCommandIsTheInstaller(Built):
text=True, check=False, cwd=self.scratch)
script = subprocess.run([python, str(REPO_ROOT / "install.py"), *args],
capture_output=True, text=True, check=False,
cwd=self.scratch)
cwd=self.scratch, env=as_package)
self.assertEqual(
(packaged.returncode, packaged.stdout, packaged.stderr),
(script.returncode, script.stdout, script.stderr))
@@ -203,6 +205,20 @@ class TheInstalledCommandIsTheInstaller(Built):
def test_this_python(self):
self._same_answers(sys.executable, "venv-current")
def test_a_hint_gives_back_the_package_command(self):
"""Nothing detected, the example said `python3 install.py`."""
command = self._installed(sys.executable, "venv-hint")
home = self.scratch / "empty-home"
home.mkdir()
env = {**os.environ, "HOME": str(home), "USERPROFILE": str(home),
"RETROBIOS_INSTALL_OFFLINE": "1"}
env.pop("RETROBIOS_BOOTSTRAP", None)
run = subprocess.run([str(command), "--yes"], capture_output=True, text=True,
check=False, cwd=self.scratch, env=env)
out = run.stdout + run.stderr
self.assertIn("retrobios --platform retroarch --dest", out)
self.assertNotIn("install.py --platform", out)
def test_python_38(self):
python = _python38()
if python is None:
+1 -1
View File
@@ -1886,7 +1886,7 @@ RetroArch folder that holds only `scph5501.bin`, in the order written:
| `EXTERNAL_STORAGE` | Android only, the shared storage root RetroArch builds its default directories from. Defaults to `/storage/emulated/0` |
| `RETROBIOS_INSTALL_URL` | Where the bootstrap fetches `install.py`. HTTPS only |
| `RETROBIOS_INSTALL_SHA256` | The SHA-256 the bootstrap requires of that installer, 64 hex characters. When either of these two is set and the fingerprint does not match, the error names the variable instead of suggesting a retry |
| `RETROBIOS_BOOTSTRAP` | Set by `install.sh` (`sh`) and `install.ps1` (`ps1`) for the temporary installer they run, so that its hints give back the one-line command rather than `python3 install.py` |
| `RETROBIOS_BOOTSTRAP` | Set by `install.sh` (`sh`) and `install.ps1` (`ps1`) for the temporary installer they run, and by the `retrobios` package (`pypi`), so that its hints give back the command that ran it (the one-liner, `uvx retrobios`, `pipx run retrobios` or `retrobios`) rather than `python3 install.py` |
| `NO_COLOR` | Set to any value but an empty one: no colour, even at a terminal. The full screen then marks the row in focus with `>` as well as reverse video. What else turns colour off is under [The full-screen interface](#the-full-screen-interface) |
| `TERM`, `TERMINFO`, `TERMINFO_DIRS` | Decide whether the full screen opens, as [The full-screen interface](#the-full-screen-interface) says. The terminal's description is read where ncurses reads it: `TERMINFO`, then `~/.terminfo`, then each folder of `TERMINFO_DIRS`, then the system's own |
| `FORCE_COLOR`, `CLICOLOR_FORCE` | Colour even when the output is a pipe or a file, set to any value but `0` or an empty one. `NO_COLOR` wins over both, and the progress line stays one line per file |