mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-20 18:59:07 -05:00
feat: watch the release page of off-forge profiles
About forty profiles describe projects published outside any forge (Altirra, ePSXe, DraStic, mednafen, xroar). profile_sync skipped them as an unsupported host and check_freshness reported the same UNKNOWN line every run, so a new release adding a firmware went unseen. A profile can now name the page announcing its releases and a pattern for the version: --check-version reads it, and check_freshness --profiles calls the profile stale when the page announces another version than core_version.
This commit is contained in:
1 parent
d43aa5354c
commit
282f8d5d0a
7 files changed
+102
No files matched your search
@@ -1097,6 +1097,16 @@ def summarize_profile_sync(report: object) -> list[Finding]:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
name = str(row.get("name") or "?")
|
||||
if row.get("skipped") and row.get("page_version"):
|
||||
# Off any forge, the release page is the feed: a version there
|
||||
# beyond the declared one is a release the profile does not cover.
|
||||
declared, announced = str(row.get("declared_version") or ""), str(row["page_version"])
|
||||
findings.append(Finding(
|
||||
"profiles", name, OK if announced == declared else STALE,
|
||||
local=declared, remote=announced,
|
||||
detail="" if announced == declared else "a newer release is announced",
|
||||
))
|
||||
continue
|
||||
if row.get("skipped"):
|
||||
findings.append(Finding("profiles", name, UNKNOWN, detail=str(row["skipped"])))
|
||||
continue
|
||||
|
||||
@@ -1114,6 +1114,10 @@ class ProfileReport:
|
||||
# Repositories whose pin is no ancestor of the branch the profile
|
||||
# tracks: history was rewritten, or the pin lies on another branch.
|
||||
orphaned: list[str] = field(default_factory=list)
|
||||
# A profile off any forge names the page announcing its releases
|
||||
# (version_source): the version read there, beside the one declared.
|
||||
declared_version: str | None = None
|
||||
page_version: str | None = None
|
||||
|
||||
# Skips that say the profile cannot be checked as written: a repository
|
||||
# that no longer answers, no pin to read, a death the forge contradicts.
|
||||
@@ -2032,6 +2036,11 @@ def format_report(report: ProfileReport, changed_only: bool = False) -> str:
|
||||
lines.append(f" not read (unsupported host): {url}")
|
||||
for line in report.orphaned:
|
||||
lines.append(f" orphaned pin: {line}")
|
||||
if report.declared_version or report.page_version:
|
||||
lines.append(
|
||||
f" version page: declared {report.declared_version or '-'}, "
|
||||
f"announced {report.page_version or 'unreadable'}"
|
||||
)
|
||||
if report.skipped:
|
||||
lines.append(f" skipped: {report.skipped}")
|
||||
return "\n".join(lines)
|
||||
@@ -2137,6 +2146,25 @@ def check_version(
|
||||
)
|
||||
|
||||
|
||||
def page_version(profile: dict, cache_dir: str, offline: bool) -> str | None:
|
||||
"""The latest version a profile's version_source page announces.
|
||||
|
||||
Forty-odd profiles live off any forge: profile_sync could only say
|
||||
"unsupported host", and a new Altirra or mednafen release went unseen.
|
||||
"""
|
||||
source = profile.get("version_source") or {}
|
||||
url, pattern = str(source.get("url") or ""), str(source.get("pattern") or "")
|
||||
if not url or not pattern:
|
||||
return None
|
||||
try:
|
||||
text = upstream.fetch_page(url, cache_dir, offline)
|
||||
except upstream.UpstreamError as exc:
|
||||
print(f"{profile.get('emulator', '?')}: {url}: {exc}", file=sys.stderr)
|
||||
return None
|
||||
match = re.search(pattern, text or "")
|
||||
return match.group(1) if match else None
|
||||
|
||||
|
||||
def version_warning(report: VersionReport | None, pin: str | None) -> str | None:
|
||||
"""Flag a declared version that names a tag away from the resolved pin."""
|
||||
if report is None or not report.tag_commit or not pin:
|
||||
@@ -3810,6 +3838,9 @@ def main() -> None:
|
||||
name=name, entries=[], counts={}, skipped=f"upstream error: {exc}"
|
||||
)
|
||||
failed.add(name)
|
||||
if args.check_version and profile.get("version_source"):
|
||||
report.declared_version = str(profile.get("core_version") or "") or None
|
||||
report.page_version = page_version(profile, args.cache_dir, args.offline)
|
||||
reports.append(report)
|
||||
if writes:
|
||||
try:
|
||||
|
||||
@@ -400,6 +400,26 @@ def _api(
|
||||
return payload
|
||||
|
||||
|
||||
def fetch_page(url: str, cache_dir: str, offline: bool) -> str | None:
|
||||
"""A web page's text, cached like a moving API answer (MOVING_TTL).
|
||||
|
||||
A project published outside a forge (Altirra, mednafen, ePSXe) says its
|
||||
version on a download page: that page is the only release feed there is.
|
||||
"""
|
||||
key = hashlib.sha256(url.encode()).hexdigest()
|
||||
target = Path(cache_dir) / "_pages" / f"{key}.txt"
|
||||
if target.is_file():
|
||||
fresh = time.time() - target.stat().st_mtime <= MOVING_TTL
|
||||
if fresh or offline:
|
||||
raw = target.read_text(encoding="utf-8")
|
||||
return None if raw == ABSENT else raw
|
||||
if offline:
|
||||
return None
|
||||
text = _http_text(url)
|
||||
write_cache(target, ABSENT if text is None else text)
|
||||
return text
|
||||
|
||||
|
||||
def _project(repo: Repo) -> str:
|
||||
return urllib.parse.quote(f"{repo.owner}/{repo.name}", safe="")
|
||||
|
||||
|
||||
Reference in new issue
Block a user