From df5de91b3790b2e8dd3ea4f2f3b9dc05047db5c5 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Thu, 5 Nov 2026 11:41:00 +0100 Subject: [PATCH] fix: clean download.sh staging on a failed part --- scripts/download.sh | 14 ++++++++++++-- tests/test_download.py | 13 +++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/scripts/download.sh b/scripts/download.sh index ce2ba8190..92f40bd3f 100755 --- a/scripts/download.sh +++ b/scripts/download.sh @@ -29,6 +29,15 @@ case "$API_BASE" in esac API="${API_BASE%/}/repos/${REPO}/releases/latest" +# Global, not local to download_pack: the EXIT trap runs once that function's +# scope is gone, and under set -u a local would be unbound there. +STAGING="" +cleanup_staging() { + if [ -n "$STAGING" ]; then + rm -rf "$STAGING" + fi +} + usage() { echo "Usage: $0 " echo " $0 --list" @@ -148,7 +157,8 @@ EOF local staging="${dest%/}/.retrobios-download" rm -rf "$staging" mkdir -p "$staging" - trap 'rm -rf "$staging"' EXIT + STAGING="$staging" + trap cleanup_staging EXIT local index=0 local url name @@ -184,7 +194,7 @@ EOF unzip -o -q "$file" -d "$dest" done - rm -rf "$staging" + cleanup_staging trap - EXIT echo "Done! BIOS files extracted to ${dest}/" } diff --git a/tests/test_download.py b/tests/test_download.py index a3b286272..fc0c51d6c 100644 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -371,6 +371,10 @@ class ReleaseServer: ] self.index.write_text(json.dumps(release)) + def drop_last_asset(self) -> None: + """A part the release lists but no longer serves: its URL gives 404.""" + (self.root / "assets" / self.names[-1]).unlink() + def corrupt_last_volume(self) -> None: target = self.root / "assets" / self.names[-1] target.write_bytes(target.read_bytes()[:-16] + b"0" * 16) @@ -561,6 +565,15 @@ class TestDownloadShell(DownloaderCase): proc = self.run_cli("nintendo", str(self.dest), expect_success=False) self.assertIn(self.platform_label, proc.stdout + proc.stderr) + def test_a_failed_part_leaves_no_staging_behind(self): + """The EXIT trap read a variable local to the function that set it: + under set -u it failed on `staging: unbound variable` and left the + parts already downloaded in the BIOS folder.""" + self.server.drop_last_asset() + proc = self.run_cli(self.platform, str(self.dest), expect_success=False) + self.assertNotIn("unbound variable", proc.stderr) + self.assertEqual(list(self.dest.iterdir()), []) + class TestWholePackPython(WholePackCase, TestDownloadPython): def test_info_reports_every_volume(self):