fix: unwind a terminated run to drop its scratch

This commit is contained in:
Abdessamad Derraz committed 2026-11-06 03:31:28 +01:00
1 parent 9b08925dd0
commit af3c90e448
2 files changed
+51

No files matched your search

+13
View File
@@ -15,6 +15,7 @@ import functools
import json
import os
import re
import signal
import sys
import zipfile
from pathlib import Path
@@ -3564,6 +3565,10 @@ from dumpcatalog import ( # noqa: E402,F401
)
def _exit_on_signal(signum: int, _frame: object) -> None:
sys.exit(128 + signum)
def run_cli(main: Callable[[], int | None]) -> None:
"""Run a command-line entry point to its exit status.
@@ -3571,7 +3576,15 @@ def run_cli(main: Callable[[], int | None]) -> None:
and the next write died on a BrokenPipeError traceback. Output nobody
reads any more ends the run quietly, with the status a shell gives a
writer whose reader left.
SIGTERM (timeout, kill) and SIGHUP (a closed terminal) end the process
without unwinding by default: a pack build left its multi-GB hidden
.partial behind. Raised as SystemExit, they run the cleanup a failed
write runs, and the status stays the one a shell gives the signal.
"""
for name in ("SIGTERM", "SIGHUP"):
if hasattr(signal, name):
signal.signal(getattr(signal, name), _exit_on_signal)
try:
code = main()
sys.stdout.flush()
+38
View File
@@ -296,5 +296,43 @@ class RestoreSkipsDownloadsInProgress(unittest.TestCase):
self.assertIn(str(cache / "done.bin"), index.values())
class ATerminatedBuildLeavesNoScratch(unittest.TestCase):
"""`timeout 120 generate_pack.py --platform RetroArch` left a 3.4 GB
hidden .partial in dist/: SIGTERM ended the process without running the
cleanup a failed write runs."""
CHILD = (
"import sys, time\n"
"sys.path.insert(0, 'scripts')\n"
"from common import run_cli\n"
"from generate_pack import _writing_pack\n"
"def main():\n"
" with _writing_pack(sys.argv[1]) as zf:\n"
" zf.writestr('a.bin', b'x')\n"
" print('writing', flush=True)\n"
" time.sleep(60)\n"
"run_cli(main)\n"
)
def test_sigterm_removes_the_partial_pack(self):
import signal # noqa: PLC0415
import subprocess # noqa: PLC0415
if not hasattr(signal, "SIGTERM") or os.name != "posix":
self.skipTest("POSIX signals")
with tempfile.TemporaryDirectory(dir=REPO_ROOT / "tmp") as tmp:
pack = Path(tmp) / "Demo_BIOS_Pack.zip"
child = subprocess.Popen(
[sys.executable, "-c", self.CHILD, str(pack)], cwd=REPO_ROOT,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True,
)
self.assertEqual(child.stdout.readline().strip(), "writing")
self.assertTrue(list(Path(tmp).glob(".*.partial")))
child.send_signal(signal.SIGTERM)
child.communicate(timeout=60)
self.assertEqual(child.returncode, 128 + signal.SIGTERM)
self.assertEqual(sorted(p.name for p in Path(tmp).iterdir()), [])
if __name__ == "__main__":
unittest.main()