Files
OmniNX-Installer-Payload/tools/audit_update_list.py
T
niklascfw 3e0d9c9950
Build / Build (push) Successful in 13s
Build Desktop Installer / Build (win-arm64) (push) Successful in 25s
Build Desktop Installer / Build (win-x64) (push) Successful in 10s
Deletion lists: clean up Downloader sysmodules and foreign leftovers again
Update mode:
- Sysmodules offered by OmniNX Downloader are removed again, since an old
  build may not run on the new Atmosphere (SysDVR, Fizeau, MissionControl,
  ldn_mitm), plus sys-botbase and emuiibo. Title IDs taken from the
  current release zips. Users reinstall them via the Downloader.
- Configs of other CFW packs (kefir-updater, blue_pack_updater) and the
  old Ultrahand name (uberhand) are removed again.
- Former OmniNX folders games, NSPs (Tools), scripts and tools are removed
  again. Patched Apps stays out: the Downloader installs into it.

Clean mode: also removes sept/ and fusee-secondary.bin (old Atmosphere
boot chain).
2026-11-13 14:53:39 +01:00

81 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""Audit source/deletion_lists_update.h against the OmniNX pack repo.
Lists every update-mode deletion entry and whether the pack ships it now,
shipped it in the past, or never did. Entries under switch/ or config/ that
the pack never shipped are almost always user installs and should not be in
the update list (see the header comment in deletion_lists_update.h).
usage: python3 tools/audit_update_list.py ../OmniNX
"""
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
UPDATE_H = ROOT / "source" / "deletion_lists_update.h"
PACK_PREFIX = re.compile(r"^(?:variants/[^/]+/(?:extras/hekate-ams-pro/)?|staging/)")
# Not shipped as files, but removed on purpose during updates.
INTENTIONAL = {
"config/nx-hbmenu", # hbmenu settings (hbmenu.nro is shipped)
"config/sys-patch", # sys-patch settings (sys-patch is shipped)
"switch/tinfoil/db", # stale title DB cache
"config/blue_pack_updater", # other CFW packs
"config/kefir-updater",
"config/uberhand", # old Ultrahand name
}
def pack_paths(repo: Path, all_history: bool) -> list[str]:
if all_history:
cmd = ["git", "-C", str(repo), "log", "--all", "--name-only", "--format=", "--", "variants", "staging"]
else:
cmd = ["git", "-C", str(repo), "ls-files", "variants", "staging"]
out = subprocess.run(cmd, check=True, capture_output=True, text=True).stdout
paths = set()
for line in out.splitlines():
line = line.strip()
if line and PACK_PREFIX.match(line):
paths.add(PACK_PREFIX.sub("", line).lower())
return sorted(paths)
def covered(paths: list[str], entry: str) -> bool:
return any(p == entry or p.startswith(entry + "/") for p in paths)
def main() -> int:
if len(sys.argv) != 2:
print(__doc__.strip())
return 2
repo = Path(sys.argv[1])
current = pack_paths(repo, all_history=False)
history = pack_paths(repo, all_history=True)
text = UPDATE_H.read_text(encoding="utf-8")
suspicious = 0
for m in re.finditer(r"static const char\*\s+(\w+)\[\]\s*=\s*\{(.*?)\};", text, re.S):
for entry in re.findall(r'"sd:/([^"]+)"', m.group(2)):
e = entry.lower()
if covered(current, e):
state = "shipped"
elif covered(history, e):
state = "dropped"
else:
state = "never"
flag = ""
if state == "never" and e not in INTENTIONAL and (e.startswith("switch/") or e.startswith("config/")):
flag = " <-- user install? remove from update list"
suspicious += 1
print(f"{state:8} {m.group(1):36} {entry}{flag}")
print(f"\n{suspicious} suspicious entr{'y' if suspicious == 1 else 'ies'}")
return 1 if suspicious else 0
if __name__ == "__main__":
sys.exit(main())