mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-18 17:33:30 -05:00
fix: compare release digests, not only sizes
This commit is contained in:
1 parent
d600a54a6e
commit
d98f00cfbc
3 files changed
+143
-9
No files matched your search
@@ -59,9 +59,15 @@ def compare(
|
||||
assets: dict[str, int],
|
||||
notes_current: bool = True,
|
||||
registered: Iterable[str] | None = None,
|
||||
expected_digests: dict[str, str] | None = None,
|
||||
asset_digests: dict[str, str] | None = None,
|
||||
) -> list[Finding]:
|
||||
"""Files the release lacks or serves at another size, sorted by kind.
|
||||
|
||||
At the same size, the sha256 the release lists for an asset is held
|
||||
against the collection's: a dump rebuilt at its old size and never
|
||||
re-uploaded was invisible to a size comparison.
|
||||
|
||||
*registered* is every path .gitignore lists; an asset name depends on
|
||||
which other paths share its basename, so it defaults to *expected* only
|
||||
when the caller has nothing wider. A release description that no longer
|
||||
@@ -73,17 +79,41 @@ def compare(
|
||||
findings.append(("notes", "release description", 0, None))
|
||||
names = asset_names([*(registered or ()), *expected])
|
||||
for path, size in sorted(expected.items()):
|
||||
published = next(
|
||||
(assets[name] for name in _spellings(names[path]) if name in assets),
|
||||
None,
|
||||
served = next(
|
||||
(name for name in _spellings(names[path]) if name in assets), None
|
||||
)
|
||||
published = assets[served] if served else None
|
||||
if published is None:
|
||||
findings.append(("missing", path, size, None))
|
||||
elif published != size:
|
||||
findings.append(("size", path, size, published))
|
||||
else:
|
||||
ours = (expected_digests or {}).get(path)
|
||||
theirs = (asset_digests or {}).get(served)
|
||||
if ours and theirs and ours != theirs:
|
||||
findings.append(("content", path, size, published))
|
||||
return sorted(findings)
|
||||
|
||||
|
||||
def expected_digests(db: dict, gitignore_text: str) -> dict[str, str]:
|
||||
"""sha256 of each gitignored database path."""
|
||||
ignored = set(registered_paths(gitignore_text))
|
||||
return {
|
||||
entry["path"]: entry["sha256"].lower()
|
||||
for entry in db.get("files", {}).values()
|
||||
if entry.get("path") in ignored and entry.get("sha256")
|
||||
}
|
||||
|
||||
|
||||
def digests_of(assets_json: list[dict]) -> dict[str, str]:
|
||||
"""sha256 the release lists for each asset, by name."""
|
||||
return {
|
||||
a["name"]: str(a["digest"]).removeprefix("sha256:").lower()
|
||||
for a in assets_json
|
||||
if str(a.get("digest") or "").startswith("sha256:")
|
||||
}
|
||||
|
||||
|
||||
ASSET_URL = f"https://github.com/{LARGE_FILES_REPO}/releases/download/{LARGE_FILES_RELEASE}/"
|
||||
NOT_INDEXED = "Not indexed"
|
||||
SECTIONS = (
|
||||
@@ -257,8 +287,9 @@ def cache_hashes(names: set[str], cache_dir: str = ".cache/large") -> dict[str,
|
||||
return hashes
|
||||
|
||||
|
||||
def fetch_release() -> tuple[dict[str, int], str]:
|
||||
"""Name and size of every asset of the large-files release, and its page."""
|
||||
def fetch_release() -> tuple[dict[str, int], str, dict[str, str]]:
|
||||
"""Name and size of every asset of the large-files release, its page,
|
||||
and the sha256 it lists per asset."""
|
||||
result = subprocess.run(
|
||||
[
|
||||
"gh", "release", "view", LARGE_FILES_RELEASE,
|
||||
@@ -267,7 +298,11 @@ def fetch_release() -> tuple[dict[str, int], str]:
|
||||
capture_output=True, text=True, check=True,
|
||||
)
|
||||
data = json.loads(result.stdout)
|
||||
return {a["name"]: a["size"] for a in data["assets"]}, data.get("body", "")
|
||||
return (
|
||||
{a["name"]: a["size"] for a in data["assets"]},
|
||||
data.get("body", ""),
|
||||
digests_of(data["assets"]),
|
||||
)
|
||||
|
||||
|
||||
def fetch_assets() -> dict[str, int]:
|
||||
@@ -298,7 +333,7 @@ def main() -> int:
|
||||
db = load_database(args.db)
|
||||
expected = expected_assets(db, gitignore_text)
|
||||
try:
|
||||
assets, body = fetch_release()
|
||||
assets, body, asset_digests = fetch_release()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError, KeyError) as exc:
|
||||
print(f"ERROR: cannot list release assets: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
@@ -315,6 +350,8 @@ def main() -> int:
|
||||
assets,
|
||||
notes_current=rendered.strip() == body.strip(),
|
||||
registered=registered_paths(gitignore_text),
|
||||
expected_digests=expected_digests(db, gitignore_text),
|
||||
asset_digests=asset_digests,
|
||||
)
|
||||
|
||||
if args.json:
|
||||
@@ -332,6 +369,8 @@ def main() -> int:
|
||||
print(f" MISSING {path} ({size} bytes)")
|
||||
elif kind == "size":
|
||||
print(f" SIZE {path}: local {size} != release {published}")
|
||||
elif kind == "content":
|
||||
print(f" CONTENT {path}: same size, other sha256 on the release")
|
||||
else:
|
||||
print(" NOTES release description differs from the rendered page"
|
||||
" (--notes FILE, then gh release edit large-files --notes-file FILE)")
|
||||
|
||||
Reference in new issue
Block a user