mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-18 17:33:30 -05:00
fix: report a failed bootstrap download plainly
This commit is contained in:
1 parent
0f52c18eca
commit
dedcf32192
4 files changed
+72
-7
No files matched your search
+19
-3
@@ -33,7 +33,14 @@ try {
|
||||
[Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
|
||||
}
|
||||
$temporary = Join-Path ([IO.Path]::GetTempPath()) ("retrobios-install-{0}.py" -f [Guid]::NewGuid())
|
||||
Invoke-WebRequest -Uri $uri -OutFile $temporary -UseBasicParsing
|
||||
try {
|
||||
Invoke-WebRequest -Uri $uri -OutFile $temporary -UseBasicParsing
|
||||
} catch {
|
||||
# The raw WebException read as a crash and named no next step.
|
||||
throw ("The installer could not be downloaded from {0}: {1} " +
|
||||
"Check the network connection and any proxy, then run the same command again. " +
|
||||
"Nothing was run and nothing was written.") -f $url, $_.Exception.Message
|
||||
}
|
||||
if ((Get-Item -LiteralPath $temporary).Length -gt $maximumInstallerBytes) {
|
||||
throw "Downloaded installer exceeds the size limit."
|
||||
}
|
||||
@@ -54,11 +61,14 @@ try {
|
||||
$python = Get-Command python -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
$needPython = "Python 3.8 or newer is required. Install it with " +
|
||||
"'winget install Python.Python.3.12' or from https://www.python.org/downloads/ " +
|
||||
"(tick 'Add python.exe to PATH'), then open a new PowerShell window and run this command again."
|
||||
if (-not $python) {
|
||||
throw "Python 3.8 or newer is required."
|
||||
throw $needPython
|
||||
}
|
||||
& $python.Source @launcher -c "import sys; raise SystemExit(sys.version_info < (3, 8))"
|
||||
if ($LASTEXITCODE -ne 0) { throw "Python 3.8 or newer is required." }
|
||||
if ($LASTEXITCODE -ne 0) { throw $needPython }
|
||||
& $python.Source @launcher $installer @InstallerArguments
|
||||
# The installer has already said what happened: its status is passed on
|
||||
# as it is (1 for files left to fetch under --check, 2 when nothing was
|
||||
@@ -66,6 +76,12 @@ try {
|
||||
# as a crash and flattens every code to one.
|
||||
$installerExit = $LASTEXITCODE
|
||||
}
|
||||
catch {
|
||||
# One line saying what failed and what to do, rather than the red
|
||||
# exception block PowerShell prints for an uncaught throw.
|
||||
[Console]::Error.WriteLine("Error: " + $_.Exception.Message)
|
||||
$installerExit = 1
|
||||
}
|
||||
finally {
|
||||
if ($temporary -and (Test-Path -LiteralPath $temporary)) {
|
||||
Remove-Item -LiteralPath $temporary -Force
|
||||
|
||||
+17
-3
@@ -50,16 +50,30 @@ if [ -z "$INSTALLER" ] || [ ! -f "$INSTALLER" ]; then
|
||||
fi
|
||||
TEMP_DIRECTORY=$(mktemp -d)
|
||||
TEMP_INSTALLER="$TEMP_DIRECTORY/install.py"
|
||||
# Quiet but for the error line: a progress table followed by
|
||||
# "curl: (6) ..." and curl's own exit code told nobody what failed.
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl --fail --location --proto '=https' --tlsv1.2 \
|
||||
"$install_url" --output "$TEMP_INSTALLER"
|
||||
fetch() {
|
||||
curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \
|
||||
--connect-timeout 30 --retry 2 "$install_url" --output "$TEMP_INSTALLER"
|
||||
}
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget --https-only --output-document="$TEMP_INSTALLER" "$install_url"
|
||||
fetch() {
|
||||
wget --quiet --https-only --timeout=30 --tries=3 \
|
||||
--output-document="$TEMP_INSTALLER" "$install_url"
|
||||
}
|
||||
else
|
||||
echo "Error: curl or wget is required to download the installer." >&2
|
||||
echo " On Debian or Ubuntu: sudo apt install curl" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! fetch_error=$(fetch 2>&1); then
|
||||
echo "Error: the installer could not be downloaded from $install_url" >&2
|
||||
echo " $(printf '%s\n' "$fetch_error" | tail -n 1)" >&2
|
||||
echo " Check the network connection, and HTTPS_PROXY if this network needs a proxy," >&2
|
||||
echo " then run the same command again. Nothing was run and nothing was written." >&2
|
||||
exit 1
|
||||
fi
|
||||
actual_size=$(wc -c < "$TEMP_INSTALLER" | tr -d ' ')
|
||||
if [ "$actual_size" -gt "$MAX_INSTALLER_BYTES" ]; then
|
||||
echo "Error: downloaded installer exceeds the size limit." >&2
|
||||
|
||||
@@ -1895,6 +1895,41 @@ class TestAvailablePlatforms(unittest.TestCase):
|
||||
self.assertTrue(marker.is_file(), "piped bootstrap did not download install.py")
|
||||
self.assertIn("retroarch", proc.stdout)
|
||||
|
||||
def test_a_failed_download_says_so_in_one_message(self):
|
||||
"""Offline, the one-liner printed curl's progress table and
|
||||
"curl: (6) ...", then exited 6, a code the table does not list."""
|
||||
scratch = REPO_ROOT / "tmp" / "tests"
|
||||
scratch.mkdir(parents=True, exist_ok=True)
|
||||
with tempfile.TemporaryDirectory(dir=scratch) as directory:
|
||||
root = Path(directory)
|
||||
fake_bin = root / "bin"
|
||||
fake_bin.mkdir()
|
||||
(fake_bin / "curl").write_text(
|
||||
"#!/bin/sh\necho 'curl: (6) Could not resolve host: x' >&2\nexit 6\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
(fake_bin / "curl").chmod(0o755)
|
||||
env = os.environ.copy()
|
||||
env.update(
|
||||
PATH=f"{fake_bin}{os.pathsep}{env['PATH']}",
|
||||
TMPDIR=str(root),
|
||||
RETROBIOS_INSTALL_URL="https://example.invalid/install.py",
|
||||
)
|
||||
proc = subprocess.run(
|
||||
["sh", "-s"], cwd=root, env=env,
|
||||
input=(REPO_ROOT / "install.sh").read_text(encoding="utf-8"),
|
||||
capture_output=True, text=True, timeout=30, check=False,
|
||||
)
|
||||
self.assertEqual(proc.returncode, 1, proc.stderr)
|
||||
self.assertIn("could not be downloaded", proc.stderr)
|
||||
self.assertIn("Nothing was run and nothing was written", proc.stderr)
|
||||
self.assertEqual(proc.stderr.count("curl: (6)"), 1)
|
||||
|
||||
def test_powershell_turns_a_failure_into_one_line(self):
|
||||
source = (REPO_ROOT / "install.ps1").read_text(encoding="utf-8")
|
||||
self.assertIn('[Console]::Error.WriteLine("Error: "', source)
|
||||
self.assertIn("winget install Python", source)
|
||||
|
||||
@unittest.skipUnless(shutil.which("script"), "script(1) provides the terminal")
|
||||
def test_piped_one_liner_hands_the_terminal_to_the_installer(self):
|
||||
"""curl | sh gives the installer the script as stdin, so isatty()
|
||||
|
||||
+1
-1
@@ -420,7 +420,7 @@ followed.
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| `0` | everything asked for is installed or already up to date |
|
||||
| `1` | a failure: an unusable base URL, an unknown platform or target, `--installed-cores` with no core found, a manifest that fails validation, a fetch that never succeeded, no platform to install for in a non-interactive run, some files failed while others installed, or `--check` found files to fetch |
|
||||
| `1` | a failure: the one-liner could not download or verify `install.py`, or found no Python 3.8 (nothing was run), an unusable base URL, an unknown platform or target, `--installed-cores` with no core found, a manifest that fails validation, a fetch that never succeeded, no platform to install for in a non-interactive run, some files failed while others installed, or `--check` found files to fetch |
|
||||
| `2` | nothing was installed: every file the run tried failed (a BIOS folder that cannot be written, for one) |
|
||||
| `130` | stopped with Ctrl+C; run the same command again to carry on |
|
||||
| `141` | the output was piped to a reader that closed early (`--list \| head`) |
|
||||
|
||||
Reference in new issue
Block a user