🔒 Repository is read-only – file editing is disabled.

PaganLinux/apply-pagan-hooks.py main

191 linii Raw ← Powrót
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
#!/usr/bin/env python3
"""
apply-pagan-hooks.py – nakłada hooki pre/post-install na zmigrowane receptury.

Obsługuje pakiety, które w cards generowały skrypty post-install/post-remove
do $PKGMK_ROOT (kernele, moduły nvidia/vboxhost, pakiet bazowy nutyx).
W nowym systemie pag uruchamia hooki z katalogu hooks/ w pakiecie (.pag),
a pagbuild osadza je na podstawie pola `hooks:` w PAGBUILD.yaml.

Kroki:
  1. usuwa z faz build/package bloki `echo "..." > $PKGMK_ROOT/$name.post-*`,
  2. dodaje pole `hooks:` z gotowymi skryptami (ścieżki absolutne, odporne
     na runtime – wersja jądra znajdowana globem /usr/lib/modules),
  3. branding nutyx -> pagan w recepturze pakietu bazowego nutyx.

Użycie: python3 apply-pagan-hooks.py [--recipes ./recipes] [--dry-run]
"""

import argparse
import os
import re
import sys

try:
    import yaml
except ImportError:
    print("Brak PyYAML", file=sys.stderr)
    sys.exit(2)

# ── Specyfikacja hooków ──
def _kernel_hook(glob_pattern: str, initrd_name: str) -> str:
    return (
        f'KREL="$(basename /usr/lib/modules/{glob_pattern} 2>/dev/null | head -n1)"\n'
        f'[ -n "$KREL" ] || exit 0\n'
        f'mkinitramfs "$KREL"\n'
        f'rm -f /boot/{initrd_name}\n'
        f'mv "/boot/initrd-$KREL" /boot/{initrd_name}'
    )


HOOKS = {
    "kernel-612": {
        "post-install": _kernel_hook("6.12.*", "initrd-612"),
        "post-remove": "rm -f /boot/initrd-612",
    },
    "kernel-618": {
        "post-install": _kernel_hook("6.18.*", "initrd-618"),
        "post-remove": "rm -f /boot/initrd-618",
    },
    "kernel-66": {
        "post-install": _kernel_hook("6.6.*", "initrd-66"),
        "post-remove": "rm -f /boot/initrd-66",
    },
    "kernel": {
        "post-install": _kernel_hook("7*", "initrd-stable"),
        "post-remove": "rm -f /boot/initrd-stable",
    },
    "kernel-mainline": {
        "post-install": _kernel_hook("7*", "initrd-mainline"),
        "post-remove": "rm -f /boot/initrd-mainline",
    },
    "nvidia-kernel-612": {
        "post-install": 'depmod -a "$(basename /usr/lib/modules/6.12.* 2>/dev/null)"',
    },
    "nvidia-kernel-618": {
        "post-install": 'depmod -a "$(basename /usr/lib/modules/6.18.* 2>/dev/null)"',
    },
    "nvidia-kernel-66": {
        "post-install": 'depmod -a "$(basename /usr/lib/modules/6.6.* 2>/dev/null)"',
    },
    "nvidia-580-kernel-618": {
        "post-install": 'depmod -a "$(basename /usr/lib/modules/* 2>/dev/null)"',
    },
    "nvidia-580": {
        "post-install": (
            'ln -sf "libEGL.so.${PKG_VERSION}" /usr/lib/libEGL.so.1\n'
            "ln -sf libEGL.so.1 /usr/lib/libEGL.so"
        ),
    },
    "vboxhost-kernel-612": {
        "post-install": 'depmod -a "$(basename /usr/lib/modules/6.12.* 2>/dev/null)"',
    },
    "vboxhost-kernel-618": {
        "post-install": 'depmod -a "$(basename /usr/lib/modules/6.18.* 2>/dev/null)"',
    },
    "vboxhost-kernel-66": {
        "post-install": 'depmod -a "$(basename /usr/lib/modules/6.6.* 2>/dev/null)"',
    },
    "vboxhost-kernel": {
        "post-install": 'depmod -a "$(basename /usr/lib/modules/7* 2>/dev/null)"',
    },
    "nutyx": {
        "post-install": (
            'if [ -f /usr/lib/os-release ]; then\n'
            '  sed -i "/VERSION/d" /usr/lib/os-release\n'
            '  sed -i "/URL/d" /usr/lib/os-release\n'
            '  sed -i "/LOGO/d" /usr/lib/os-release\n'
            '  printf \'VERSION=systemd\\nVERSION_ID=%s\\nLOGO=pagan.png\\n'
            'HOME_URL="https://paganlinux.eu"\\n\' "$PKG_VERSION" >> /usr/lib/os-release\n'
            "fi"
        ),
    },
}

# Bloki echo piszące skrypty do $PKGMK_ROOT – usuwane z faz build/package
AUTOGEN_RE = re.compile(
    r'[ \t]*(?:echo|cat)\s+(?P<q>["\'])(?P<body>.*?)(?P=q)\s*>>?\s*'
    r'\$PKGMK_ROOT/\$name\.(?:post-install|post-remove|pre-install|pre-remove)\s*',
    re.S,
)

NUTYX_RE = re.compile(r"NutyX|Nutyx|nutyx", re.IGNORECASE)


def find_recipe(recipes_root, pkgname):
    for dirpath, _dirs, files in os.walk(recipes_root):
        if "PAGBUILD.yaml" not in files:
            continue
        fp = os.path.join(dirpath, "PAGBUILD.yaml")
        try:
            with open(fp, encoding="utf-8") as f:
                d = yaml.safe_load(f) or {}
            if d.get("pkgname") == pkgname:
                return fp
        except Exception:
            pass
    return None


def dump_recipe(data):
    class D(yaml.Dumper):
        pass

    def str_rep(dumper, s):
        if "\n" in s:
            return dumper.represent_scalar("tag:yaml.org,2002:str", s, style="|")
        if re.match(r"^\d+\.\d+", s) or ":" in s or s.startswith("https://"):
            return dumper.represent_scalar("tag:yaml.org,2002:str", s, style="'")
        return dumper.represent_scalar("tag:yaml.org,2002:str", s)

    D.add_representer(str, str_rep)
    return yaml.dump(data, Dumper=D, default_flow_style=False,
                     allow_unicode=True, sort_keys=False, width=120)


def patch_recipe(fp, hooks, dry_run):
    with open(fp, encoding="utf-8") as f:
        data = yaml.safe_load(f) or {}

    # 1. usuń bloki autogen post-install/post-remove z faz
    for phase in ("build", "package"):
        body = data.get(phase)
        if isinstance(body, str) and "$PKGMK_ROOT" in body:
            data[phase] = AUTOGEN_RE.sub("", body).strip("\n")

    # 2. branding nutyx -> pagan (pakiet bazowy)
    if data.get("pkgname") == "nutyx":
        for phase in ("build", "package"):
            body = data.get(phase)
            if isinstance(body, str):
                data[phase] = body.replace("logo_nutyx_120.png", "logo_nutyx_120.png")
                data[phase] = data[phase].replace("nutyx.png", "pagan.png")

    # 3. hooki
    data["hooks"] = hooks

    if dry_run:
        print(f"[dry-run] {fp}: hooks={list(hooks.keys())}")
        return

    with open(fp, "w", encoding="utf-8") as f:
        f.write(dump_recipe(data))
    print(f"✅ {os.path.relpath(fp)}: hooks={list(hooks.keys())}")


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--recipes", default="recipes")
    ap.add_argument("--dry-run", action="store_true")
    args = ap.parse_args()

    for pkgname, hooks in HOOKS.items():
        fp = find_recipe(args.recipes, pkgname)
        if not fp:
            print(f"⚠  {pkgname}: nie znaleziono PAGBUILD.yaml (pomiń)")
            continue
        patch_recipe(fp, hooks, args.dry_run)


if __name__ == "__main__":
    main()