mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 13:33:24 -05:00
fix: keep the cache when an archive yields nothing
This commit is contained in:
1 parent
6fca4149f5
commit
6c75f5ae15
2 files changed
+56
No files matched your search
@@ -210,6 +210,15 @@ def get_remote_sha(source_url: str, version: str) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
class NothingExtracted(Exception):
|
||||
"""An archive that yields no file for the cache.
|
||||
|
||||
Promoting it replaced the cache with an empty directory, recorded the new
|
||||
version and reported success, so the next run read "up to date" and the
|
||||
packs left without the directory.
|
||||
"""
|
||||
|
||||
|
||||
def _is_safe_tar_member(member: tarfile.TarInfo, dest: Path) -> bool:
|
||||
"""Reject path traversal, absolute paths, and symlinks in tar members."""
|
||||
if member.issym() or member.islnk():
|
||||
@@ -293,6 +302,8 @@ def _download_and_extract(
|
||||
shutil.copyfileobj(src, dst)
|
||||
file_count += 1
|
||||
|
||||
if not file_count:
|
||||
raise NothingExtracted(f"no file under {source_path} in the archive")
|
||||
_promote(extract_dir, cache_dir, Path(tmpdir))
|
||||
|
||||
return file_count
|
||||
@@ -354,6 +365,8 @@ def _download_and_extract_zip(
|
||||
shutil.copyfileobj(src, dst)
|
||||
file_count += 1
|
||||
|
||||
if not file_count:
|
||||
raise NothingExtracted("the archive holds no file to extract")
|
||||
# The old tree is stepped aside rather than deleted: removing it
|
||||
# first and then failing to move the new one in left the cache with
|
||||
# nothing at all, and the next run reads that as "never fetched".
|
||||
@@ -450,6 +463,7 @@ def _refresh_entry(
|
||||
OSError,
|
||||
tarfile.TarError,
|
||||
zipfile.BadZipFile,
|
||||
NothingExtracted,
|
||||
) as exc:
|
||||
log.warning("[%s] download failed: %s", key, exc)
|
||||
return None
|
||||
|
||||
@@ -8,6 +8,7 @@ failed, the cache left at the old version.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
@@ -63,5 +64,46 @@ class RefreshFailuresAreFailures(unittest.TestCase):
|
||||
self.assertIn("sys.exit(1)", source[source.index("failed = update_changed(report)"):])
|
||||
|
||||
|
||||
class AnEmptyExtractionKeepsTheCache(unittest.TestCase):
|
||||
"""An archive without the cited subtree replaced the cache with an empty
|
||||
directory, recorded the version and reported success."""
|
||||
|
||||
def setUp(self):
|
||||
import refresh_data_dirs
|
||||
|
||||
self.module = refresh_data_dirs
|
||||
scratch = Path(__file__).resolve().parent.parent / "tmp"
|
||||
scratch.mkdir(exist_ok=True)
|
||||
self.root = Path(tempfile.mkdtemp(dir=scratch))
|
||||
self.addCleanup(shutil.rmtree, self.root, True)
|
||||
self.cache = self.root / "cache"
|
||||
self.cache.mkdir()
|
||||
(self.cache / "keep.dat").write_bytes(b"cached")
|
||||
|
||||
def test_a_tarball_without_the_subtree(self):
|
||||
import tarfile
|
||||
|
||||
archive = self.root / "archive.tar.gz"
|
||||
payload = self.root / "a.txt"
|
||||
payload.write_bytes(b"x")
|
||||
with tarfile.open(archive, "w:gz") as tf:
|
||||
tf.add(payload, arcname="repo-main/OtherDir/a.txt")
|
||||
with self.assertRaises(self.module.NothingExtracted):
|
||||
self.module._download_and_extract(
|
||||
archive.as_uri(), "repo-main/Data/Sys", str(self.cache), []
|
||||
)
|
||||
self.assertEqual((self.cache / "keep.dat").read_bytes(), b"cached")
|
||||
|
||||
def test_a_zip_with_no_file(self):
|
||||
import zipfile
|
||||
|
||||
archive = self.root / "archive.zip"
|
||||
with zipfile.ZipFile(archive, "w") as zf:
|
||||
zf.writestr("only/", b"")
|
||||
with self.assertRaises(self.module.NothingExtracted):
|
||||
self.module._download_and_extract_zip(archive.as_uri(), str(self.cache))
|
||||
self.assertEqual((self.cache / "keep.dat").read_bytes(), b"cached")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user