mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-11 12:33:53 -06:00
feat: give the package command back in hints
Run from the retrobios package, a hint and --help named python3 install.py, a file that user does not have. The package's launcher sets RETROBIOS_BOOTSTRAP=pypi, and the command is read from the environment it runs in: uvx retrobios from uv's cache, pipx run retrobios from pipx's, retrobios once installed.
This commit is contained in:
1 parent
6c14468862
commit
b067d27d53
8 files changed
+75
-13
No files matched your search
+1
-1
@@ -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 = "8dd510a5dbc2468248a74e7bb53b791729b194a6ab97e4cc9d900ffa620fa2ba"
|
||||
$defaultInstallSha256 = "6bd77b283f20cad55d53df8a2e7fe8ef177e821f4dfade37e2d12af2fa3f3852"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+16
@@ -6215,6 +6215,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.
|
||||
|
||||
@@ -6271,6 +6285,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
@@ -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="8dd510a5dbc2468248a74e7bb53b791729b194a6ab97e4cc9d900ffa620fa2ba"
|
||||
DEFAULT_INSTALL_SHA256="6bd77b283f20cad55d53df8a2e7fe8ef177e821f4dfade37e2d12af2fa3f3852"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
{
|
||||
"dest": "roms/ports/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1125340,
|
||||
"sha256": "8dd510a5dbc2468248a74e7bb53b791729b194a6ab97e4cc9d900ffa620fa2ba",
|
||||
"size": 1126086,
|
||||
"sha256": "6bd77b283f20cad55d53df8a2e7fe8ef177e821f4dfade37e2d12af2fa3f3852",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -71,8 +71,8 @@
|
||||
"muos": {
|
||||
"archive": {
|
||||
"dest": "ARCHIVE/RetroBIOS.muxapp",
|
||||
"size": 1178965,
|
||||
"sha256": "beaf9d9caafd8e94953605a78fb878787a811646065764ed325b38223eb6a479"
|
||||
"size": 1179711,
|
||||
"sha256": "184146fc9785a1aee6b69f0fae3fac5100dc8cb5558a6f369a5cc1ad3301377d"
|
||||
},
|
||||
"members": [
|
||||
{
|
||||
@@ -92,8 +92,8 @@
|
||||
{
|
||||
"name": "RetroBIOS/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1125340,
|
||||
"sha256": "8dd510a5dbc2468248a74e7bb53b791729b194a6ab97e4cc9d900ffa620fa2ba",
|
||||
"size": 1126086,
|
||||
"sha256": "6bd77b283f20cad55d53df8a2e7fe8ef177e821f4dfade37e2d12af2fa3f3852",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
@@ -166,8 +166,8 @@
|
||||
{
|
||||
"dest": ".config/modules/retrobios/install.py",
|
||||
"repo_path": "install.py",
|
||||
"size": 1125340,
|
||||
"sha256": "8dd510a5dbc2468248a74e7bb53b791729b194a6ab97e4cc9d900ffa620fa2ba",
|
||||
"size": 1126086,
|
||||
"sha256": "6bd77b283f20cad55d53df8a2e7fe8ef177e821f4dfade37e2d12af2fa3f3852",
|
||||
"executable": false
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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__")
|
||||
'''
|
||||
|
||||
|
||||
@@ -7624,5 +7624,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()
|
||||
@@ -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
@@ -1891,7 +1891,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 |
|
||||
|
||||
Reference in new issue
Block a user