diff --git a/install.ps1 b/install.ps1 index 3aee95a74..fb834c753 100644 --- a/install.ps1 +++ b/install.ps1 @@ -53,8 +53,19 @@ "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." + $downloaded = (Get-Item -LiteralPath $temporary).Length + if ($downloaded -gt $maximumInstallerBytes) { + # A page served in place of the file says the network + # answered, not this project: the one cause a user can act on. + $tooLarge = ("The downloaded installer is {0} bytes, more than the {1} this script accepts. " + + "Nothing was run and nothing was written. A network that answers with a page of its own " + + "(a sign-in portal, a proxy) gives this: open any web page to sign in, then run the same " + + "command again.") -f $downloaded, $maximumInstallerBytes + if ([Environment]::GetEnvironmentVariable("RETROBIOS_INSTALL_URL")) { + $tooLarge += " RETROBIOS_INSTALL_URL is set in this session and names another installer: " + + "remove it to use the installer this script names." + } + throw $tooLarge } $actual = (Get-FileHash -LiteralPath $temporary -Algorithm SHA256).Hash.ToLowerInvariant() if ($actual -ne $expected.ToLowerInvariant()) { diff --git a/install.sh b/install.sh index 133806530..afb8f61e7 100755 --- a/install.sh +++ b/install.sh @@ -94,7 +94,16 @@ if [ -z "$INSTALLER" ] || [ ! -f "$INSTALLER" ]; then 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 + # A page served in place of the file says the network answered, not this + # project: the one cause a user can act on. + echo "Error: the downloaded installer is $actual_size bytes, more than the $MAX_INSTALLER_BYTES this script accepts." >&2 + echo " Nothing was run and nothing was written. A network that answers with a page of" >&2 + echo " its own (a sign-in portal, a proxy) gives this: open any web page to sign in," >&2 + echo " then run the same command again." >&2 + if [ -n "${RETROBIOS_INSTALL_URL:-}" ]; then + echo " RETROBIOS_INSTALL_URL is set in this environment and names another installer:" >&2 + echo " unset it to use the installer this script names." >&2 + fi exit 1 fi if command -v sha256sum >/dev/null 2>&1; then diff --git a/tests/test_install.py b/tests/test_install.py index 1f90be871..90008eab2 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -4764,6 +4764,38 @@ class TheBoardSystemsAreNamedFromTheCode(unittest.TestCase): self.assertIn(name, paragraph) +class TheInstallerFitsTheOneLiners(unittest.TestCase): + """install.sh and install.ps1 refuse an installer over 2 MiB, and + install.py grew from 596 KB to 1.1 MB in twelve days with nothing + holding it under that: past it, every one-line install would stop.""" + + def _caps(self) -> dict[str, int]: + import re + + shell = (REPO_ROOT / "install.sh").read_text(encoding="utf-8") + ps1 = (REPO_ROOT / "install.ps1").read_text(encoding="utf-8") + units = {"": 1, "KB": 1024, "MB": 1024 ** 2} + number, unit = re.search(r"\$maximumInstallerBytes = (\d+)(KB|MB)?", ps1).groups() + return {"install.sh": int(re.search(r"^MAX_INSTALLER_BYTES=(\d+)$", shell, re.M)[1]), + "install.ps1": int(number) * units[unit or ""]} + + def test_a_quarter_of_each_cap_stays_free(self): + size = (REPO_ROOT / "install.py").stat().st_size + for script, cap in self._caps().items(): + with self.subTest(script=script): + self.assertLessEqual( + size, cap * 3 // 4, + f"install.py is {size} bytes, past three quarters of the {cap} {script} " + "accepts: shrink it or raise the cap in both one-liners") + + def test_the_refusal_names_a_cause_and_a_way_out(self): + for script in ("install.sh", "install.ps1"): + text = " ".join((REPO_ROOT / script).read_text(encoding="utf-8").split()) + with self.subTest(script=script): + self.assertIn("this script accepts", text) + self.assertIn("open any web page to sign in", text) + + class RetroArchAppImageIsPortable(unittest.TestCase): """The buildbot's Linux RetroArch is an AppImage beside a .home folder the AppImage runtime makes its HOME: the run found nothing and offered