Files
nix-config/scripts/hooks.py
mjallen18 bd799661b9 fix avahi
2026-03-31 13:33:42 -05:00

246 lines
7.8 KiB
Python

#!/usr/bin/env python3
"""
Per-package hooks for version management.
Each hook is a callable registered by package name (the relative path under
packages/, e.g. 'raspberrypi/linux-rpi') and source component name.
A hook can override:
- fetch_candidates(comp, merged_vars) -> Candidates
- prefetch_source(comp, merged_vars) -> Optional[str] (not yet needed)
Hooks are invoked by both the CLI updater and the TUI.
Adding a new hook:
1. Define a function or class with the required signature.
2. Register it via register_candidates_hook(pkg_name, src_name, fn) at module
level below.
"""
from __future__ import annotations
import re
from typing import Callable, Dict, Optional, Tuple
from lib import (
Candidates,
Json,
gh_head_commit,
gh_list_tags,
gh_ref_date,
gh_release_date,
http_get_text,
)
# ---------------------------------------------------------------------------
# Hook registry
# ---------------------------------------------------------------------------
# (pkg_name, src_name) -> fn(comp, merged_vars) -> Candidates
_CANDIDATES_HOOKS: Dict[Tuple[str, str], Callable] = {}
def register_candidates_hook(pkg: str, src: str, fn: Callable) -> None:
_CANDIDATES_HOOKS[(pkg, src)] = fn
def get_candidates_hook(pkg: str, src: str) -> Optional[Callable]:
return _CANDIDATES_HOOKS.get((pkg, src))
# ---------------------------------------------------------------------------
# Raspberry Pi linux — stable_YYYYMMDD tag selection
# ---------------------------------------------------------------------------
def _rpi_linux_stable_candidates(comp: Json, merged_vars: Json) -> Candidates:
from lib import render, gh_latest_release, gh_latest_tag
c = Candidates()
owner = comp.get("owner", "raspberrypi")
repo = comp.get("repo", "linux")
branch: Optional[str] = comp.get("branch") or None
tags_all = gh_list_tags(owner, repo)
rendered = render(comp, merged_vars)
cur_tag = str(rendered.get("tag") or "")
if cur_tag.startswith("stable_") or not branch:
# Pick the most recent stable_YYYYMMDD tag
stable_tags = sorted(
[t for t in tags_all if re.match(r"^stable_\d{8}$", t)],
reverse=True,
)
if stable_tags:
c.tag = stable_tags[0]
c.tag_date = gh_ref_date(owner, repo, c.tag)
else:
# Series-based tracking: pick latest rpi-X.Y.* tag
mm = str(merged_vars.get("modDirVersion") or "")
m = re.match(r"^(\d+)\.(\d+)", mm)
if m:
base = f"rpi-{m.group(1)}.{m.group(2)}"
series = [
t
for t in tags_all
if t == f"{base}.y"
or t.startswith(f"{base}.y")
or t.startswith(f"{base}.")
]
series.sort(reverse=True)
if series:
c.tag = series[0]
c.tag_date = gh_ref_date(owner, repo, c.tag)
if branch:
commit = gh_head_commit(owner, repo, branch)
if commit:
c.commit = commit
c.commit_date = gh_ref_date(owner, repo, commit)
return c
register_candidates_hook(
"raspberrypi/linux-rpi", "stable", _rpi_linux_stable_candidates
)
register_candidates_hook(
"raspberrypi/linux-rpi", "unstable", _rpi_linux_stable_candidates
)
# ---------------------------------------------------------------------------
# CachyOS linux — version from upstream PKGBUILD / .SRCINFO
# ---------------------------------------------------------------------------
def _parse_cachyos_linux_version(text: str, is_srcinfo: bool) -> Optional[str]:
if is_srcinfo:
m = re.search(r"^\s*pkgver\s*=\s*([^\s#]+)\s*$", text, re.MULTILINE)
if m:
v = m.group(1).strip().replace(".rc", "-rc")
return v
return None
# PKGBUILD
env: Dict[str, str] = {}
for line in text.splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
ma = re.match(r"^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.+)$", line)
if ma:
key, val = ma.group(1), ma.group(2).strip()
val = re.sub(r"\s+#.*$", "", val).strip()
if (val.startswith('"') and val.endswith('"')) or (
val.startswith("'") and val.endswith("'")
):
val = val[1:-1]
env[key] = val
m2 = re.search(r"^\s*pkgver\s*=\s*(.+)$", text, re.MULTILINE)
if not m2:
return None
raw = m2.group(1).strip().strip("\"'")
def expand(s: str) -> str:
s = re.sub(r"\$\{([^}]+)\}", lambda mb: env.get(mb.group(1), mb.group(0)), s)
s = re.sub(
r"\$([A-Za-z_][A-Za-z0-9_]*)",
lambda mu: env.get(mu.group(1), mu.group(0)),
s,
)
return s
return expand(raw).strip().replace(".rc", "-rc")
def _cachyos_linux_suffix(variant_name: Optional[str]) -> str:
if not variant_name:
return ""
return {"rc": "-rc", "hardened": "-hardened", "lts": "-lts"}.get(variant_name, "")
def fetch_cachyos_linux_version(suffix: str) -> Optional[str]:
bases = [
"https://raw.githubusercontent.com/CachyOS/linux-cachyos/master",
"https://raw.githubusercontent.com/cachyos/linux-cachyos/master",
]
for base in bases:
text = http_get_text(f"{base}/linux-cachyos{suffix}/.SRCINFO")
if text:
v = _parse_cachyos_linux_version(text, is_srcinfo=True)
if v:
return v
text = http_get_text(f"{base}/linux-cachyos{suffix}/PKGBUILD")
if text:
v = _parse_cachyos_linux_version(text, is_srcinfo=False)
if v:
return v
return None
def linux_tarball_url(version: str) -> str:
if "-rc" in version:
return f"https://git.kernel.org/torvalds/t/linux-{version}.tar.gz"
parts = version.split(".")
major = parts[0] if parts else "6"
ver_for_tar = ".".join(parts[:2]) if version.endswith(".0") else version
return (
f"https://cdn.kernel.org/pub/linux/kernel/v{major}.x/linux-{ver_for_tar}.tar.xz"
)
# Note: linux-cachyos is not yet in the repo, but the hook is defined here
# so it can be activated when that package is added.
def _cachyos_linux_candidates(comp: Json, merged_vars: Json) -> Candidates:
c = Candidates()
# The variant name is not available here; the TUI/CLI must pass it via merged_vars
suffix = str(merged_vars.get("_cachyos_suffix") or "")
latest = fetch_cachyos_linux_version(suffix)
if latest:
c.tag = latest # use tag slot for display consistency
return c
register_candidates_hook("linux-cachyos", "linux", _cachyos_linux_candidates)
# ---------------------------------------------------------------------------
# CachyOS ZFS — commit pinned in PKGBUILD
# ---------------------------------------------------------------------------
def fetch_cachyos_zfs_commit(suffix: str) -> Optional[str]:
bases = [
"https://raw.githubusercontent.com/CachyOS/linux-cachyos/master",
"https://raw.githubusercontent.com/cachyos/linux-cachyos/master",
]
for base in bases:
text = http_get_text(f"{base}/linux-cachyos{suffix}/PKGBUILD")
if not text:
continue
m = re.search(
r"git\+https://github\.com/cachyos/zfs\.git#commit=([0-9a-f]+)", text
)
if m:
return m.group(1)
return None
def _cachyos_zfs_candidates(comp: Json, merged_vars: Json) -> Candidates:
c = Candidates()
suffix = str(merged_vars.get("_cachyos_suffix") or "")
sha = fetch_cachyos_zfs_commit(suffix)
if sha:
c.commit = sha
url = comp.get("url") or ""
c.commit_date = (
gh_ref_date("cachyos", "zfs", sha) if "github.com" in url else ""
)
return c
register_candidates_hook("linux-cachyos", "zfs", _cachyos_zfs_candidates)