mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 13:33:24 -05:00
fix: preserve release assets by registered path
This commit is contained in:
1 parent
969026b88d
commit
8f4dd17507
2 files changed
+54
-32
No files matched your search
+24
-28
@@ -13,6 +13,7 @@ from __future__ import annotations
|
|||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -257,33 +258,33 @@ def save_cache(cache_path: str, cache: dict):
|
|||||||
json.dump(cache, f)
|
json.dump(cache, f)
|
||||||
|
|
||||||
|
|
||||||
def _load_gitignored_large_files() -> dict[str, str]:
|
def _load_gitignored_large_files() -> set[str]:
|
||||||
"""Read .gitignore and return {filename: bios_path} for large files."""
|
"""The bios/ paths .gitignore registers as release assets."""
|
||||||
gitignore = Path(".gitignore")
|
gitignore = Path(".gitignore")
|
||||||
if not gitignore.exists():
|
if not gitignore.exists():
|
||||||
return {}
|
return set()
|
||||||
entries = {}
|
return {
|
||||||
for line in gitignore.read_text().splitlines():
|
line.strip()
|
||||||
line = line.strip()
|
for line in gitignore.read_text().splitlines()
|
||||||
if line.startswith("bios/") and not line.startswith("#"):
|
if line.strip().startswith("bios/")
|
||||||
name = Path(line).name
|
}
|
||||||
entries[name] = line
|
|
||||||
return entries
|
|
||||||
|
|
||||||
|
|
||||||
def _preserve_large_file_entries(files: dict, db_path: str) -> int:
|
def _preserve_large_file_entries(files: dict, db_path: str) -> int:
|
||||||
"""Preserve database entries for large files not on disk.
|
"""Keep the entries of release assets the checkout does not hold.
|
||||||
|
|
||||||
Large files (>50 MB) are stored as GitHub release assets and listed
|
Files kept out of git live as assets of the large-files release, and
|
||||||
in .gitignore. When generate_db runs locally without them, their
|
.gitignore registers their paths. An entry survives a scan that missed
|
||||||
entries would be lost. This reads the existing database, downloads
|
its file only under that registered path: a bare name is shared by
|
||||||
missing files from the release, and re-adds entries with paths
|
other files (pak0.pk3, history.db), and a path rewritten into the
|
||||||
pointing to the local cache.
|
download cache is no longer one .gitignore knows, so the manifest
|
||||||
|
would send the installer to the repository for it. A fetched asset is
|
||||||
|
written back to its registered path.
|
||||||
"""
|
"""
|
||||||
from common import fetch_large_file
|
from common import fetch_large_file
|
||||||
|
|
||||||
large_files = _load_gitignored_large_files()
|
registered = _load_gitignored_large_files()
|
||||||
if not large_files:
|
if not registered:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -299,22 +300,17 @@ def _preserve_large_file_entries(files: dict, db_path: str) -> int:
|
|||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
for sha1, entry in existing_db.get("files", {}).items():
|
for sha1, entry in existing_db.get("files", {}).items():
|
||||||
if sha1 in files:
|
|
||||||
continue
|
|
||||||
name = entry.get("name", "")
|
|
||||||
path = entry.get("path", "")
|
path = entry.get("path", "")
|
||||||
# Match by gitignored bios/ path OR by filename of a known large file
|
if sha1 in files or path not in registered or path in scanned_paths:
|
||||||
if path not in large_files.values() and name not in large_files:
|
|
||||||
continue
|
continue
|
||||||
cached = fetch_large_file(
|
cached = fetch_large_file(
|
||||||
path if path in large_files.values() else name,
|
path,
|
||||||
expected_sha1=entry.get("sha1", ""),
|
expected_sha1=entry.get("sha1", ""),
|
||||||
expected_md5=entry.get("md5", ""),
|
expected_md5=entry.get("md5", ""),
|
||||||
)
|
)
|
||||||
if cached:
|
if cached and not os.path.exists(path):
|
||||||
entry = {**entry, "path": cached}
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||||
elif path in scanned_paths:
|
shutil.copy2(cached, path)
|
||||||
continue
|
|
||||||
files[sha1] = entry
|
files[sha1] = entry
|
||||||
count += 1
|
count += 1
|
||||||
return count
|
return count
|
||||||
|
|||||||
@@ -280,15 +280,41 @@ class PreservedLargeFileEntries(unittest.TestCase):
|
|||||||
self.assertEqual(count, 1)
|
self.assertEqual(count, 1)
|
||||||
self.assertIn("b" * 40, files)
|
self.assertIn("b" * 40, files)
|
||||||
|
|
||||||
def test_verified_cache_hit_repoints_the_entry(self):
|
def test_a_fetched_asset_returns_to_its_registered_path(self):
|
||||||
|
cache = self.tmp / "cache" / "FW.PUP"
|
||||||
|
cache.parent.mkdir()
|
||||||
|
cache.write_bytes(b"firmware")
|
||||||
|
common.fetch_large_file = lambda *a, **k: str(cache)
|
||||||
|
db_path = self._write_db(
|
||||||
|
{"b" * 40: {"name": "FW.PUP", "path": "bios/Sony/PS3/FW.PUP"}}
|
||||||
|
)
|
||||||
|
files: dict = {}
|
||||||
|
count = self.generate_db._preserve_large_file_entries(files, db_path)
|
||||||
|
self.assertEqual(count, 1)
|
||||||
|
self.assertEqual(files["b" * 40]["path"], "bios/Sony/PS3/FW.PUP")
|
||||||
|
self.assertEqual((self.tmp / "bios/Sony/PS3/FW.PUP").read_bytes(), b"firmware")
|
||||||
|
|
||||||
|
def test_a_file_sharing_only_the_name_is_not_preserved(self):
|
||||||
|
common.fetch_large_file = lambda *a, **k: "/cache/large/FW.PUP"
|
||||||
|
db_path = self._write_db(
|
||||||
|
{"c" * 40: {"name": "FW.PUP", "path": "bios/Sony/PSP/FW.PUP"}}
|
||||||
|
)
|
||||||
|
files: dict = {}
|
||||||
|
self.assertEqual(
|
||||||
|
self.generate_db._preserve_large_file_entries(files, db_path), 0
|
||||||
|
)
|
||||||
|
self.assertEqual(files, {})
|
||||||
|
|
||||||
|
def test_a_second_revision_under_a_rescanned_path_is_dropped(self):
|
||||||
common.fetch_large_file = lambda *a, **k: "/cache/large/FW.PUP"
|
common.fetch_large_file = lambda *a, **k: "/cache/large/FW.PUP"
|
||||||
db_path = self._write_db(
|
db_path = self._write_db(
|
||||||
{"b" * 40: {"name": "FW.PUP", "path": "bios/Sony/PS3/FW.PUP"}}
|
{"b" * 40: {"name": "FW.PUP", "path": "bios/Sony/PS3/FW.PUP"}}
|
||||||
)
|
)
|
||||||
files = {"a" * 40: {"name": "FW.PUP", "path": "bios/Sony/PS3/FW.PUP"}}
|
files = {"a" * 40: {"name": "FW.PUP", "path": "bios/Sony/PS3/FW.PUP"}}
|
||||||
count = self.generate_db._preserve_large_file_entries(files, db_path)
|
self.assertEqual(
|
||||||
self.assertEqual(count, 1)
|
self.generate_db._preserve_large_file_entries(files, db_path), 0
|
||||||
self.assertEqual(files["b" * 40]["path"], "/cache/large/FW.PUP")
|
)
|
||||||
|
self.assertEqual(list(files), ["a" * 40])
|
||||||
|
|
||||||
|
|
||||||
class ReleaseAssetNames(unittest.TestCase):
|
class ReleaseAssetNames(unittest.TestCase):
|
||||||
|
|||||||
Reference in new issue
Block a user