#!/usr/bin/env python3 import json, os, re, subprocess, urllib.request from datetime import datetime import zoneinfo PKG_DIR = 'packages' REPO_DIR = 'repo' def parse_pkgbuild(path): data = {} with open(path) as f: text = f.read() for key in ('pkgname', 'pkgver', 'pkgrel', 'pkgdesc', 'url', 'license', 'arch'): m = re.search(rf'^{key}=[\'"]?(.+?)[\'"]?$', text, re.M) if m: val = m.group(1).strip("'\"") if key == 'arch': val = val.strip('()').replace("'", '').replace('"', '').strip() data[key] = val deps = re.search(r'^depends=\((.*?)\)', text, re.DOTALL | re.M) if deps: raw = deps.group(1) data['depends'] = [d.strip("'\" ") for d in raw.strip().split('\n') if d.strip()] return data def fetch_aur_info(pkgname): url = f"https://aur.archlinux.org/rpc/?v=5&type=info&arg[]={pkgname}" try: with urllib.request.urlopen(url, timeout=10) as resp: data = json.load(resp) if data['resultcount'] > 0: return data['results'][0] except Exception: pass return None def category_for(pkgname, keywords=None, description=None): if pkgname.startswith('calamares'): return 'installer' if pkgname.startswith('euri-wallpaper') or pkgname.startswith('euri-desktop'): return 'branding' if pkgname in ('euri-live', 'euri-release', 'euri-keyring', 'euri-mirrorlist'): return 'core' if pkgname in ('euri-welcome', 'euri-memes', 'euri-grub-theme'): return 'desktop' if pkgname in ('hal', 'downgrade'): return 'tool' if keywords: kw_lower = {k.lower() for k in keywords if isinstance(k, str)} if kw_lower & {'icon-theme', 'wallpaper', 'branding', 'sddm', 'grub'}: return 'branding' if kw_lower & {'installer', 'calamares', 'live'}: return 'installer' if kw_lower & {'keyring', 'mirrorlist'}: return 'core' if kw_lower & {'kwin', 'plasma', 'plasmoid', 'widget', 'wayland'}: return 'desktop' if kw_lower & {'cli', 'terminal', 'aur', 'helper', 'wrapper', 'alpm', 'search'}: return 'tool' if description: d = description.lower() if any(w in d for w in ['icon theme', 'icon-theme', 'wallpaper', 'branding', 'sddm']): return 'branding' if any(w in d for w in ['installer', 'calamares']): return 'installer' if any(w in d for w in ['kwin', 'plasma', 'plasmoid', 'wayland compositor']): return 'desktop' if any(w in d for w in ['terminal', 'cli', 'aur helper', 'pacman wrapper', 'package manager', 'prompt theme', 'shell prompt', 'shell tool', 'utility', 'search tool']): return 'tool' return 'other' cat_colors = { 'installer': '#4A9EFF', 'branding': '#9B59B6', 'core': '#2ECC71', 'desktop': '#F39C12', 'tool': '#E74C3C', 'other': '#7F8C8D', } pkgs = [] for f in sorted(os.listdir(REPO_DIR)): if not f.endswith('.pkg.tar.zst') or '-debug-' in f: continue fpath = os.path.join(REPO_DIR, f) size = os.path.getsize(fpath) mtime = os.path.getmtime(fpath) mtime_dt = datetime.fromtimestamp(mtime, tz=zoneinfo.ZoneInfo('Europe/Berlin')) # strip .pkg.tar.zst and arch to get base name base = re.sub(r'-[^-]+-x86_64\.pkg\.tar\.zst$', '', f) base = re.sub(r'-any\.pkg\.tar\.zst$', '', base) # remove version suffix to match directory dirname = re.sub(r'-\d+[\d.]*-\d+$', '', base) if dirname == 'calamares-branding-euri': dirname = 'calamares-branding-euri' pkgbuild_path = os.path.join(PKG_DIR, dirname, 'PKGBUILD') has_local = os.path.exists(pkgbuild_path) meta = parse_pkgbuild(pkgbuild_path) if has_local else {} # extract version from filename: name-ver-rel-arch.pkg.tar.zst ver_match = re.match(r'.+-(\d+[\d.]*)-(\d+)-(any|x86_64)\.pkg\.tar\.zst', f) pkgver = ver_match.group(1) if ver_match else (meta.get('pkgver', '?')) pkgrel = ver_match.group(2) if ver_match else (meta.get('pkgrel', '?')) arch = ver_match.group(3) if ver_match else (meta.get('arch', '?')) pkgname = meta.get('pkgname', dirname) aur_info = fetch_aur_info(pkgname) if not has_local else None keywords = aur_info.get('Keywords', []) if aur_info else [] description = meta.get('pkgdesc', aur_info.get('Description', '') if aur_info else '') cat = category_for(pkgname, keywords, description) pkgs.append({ 'file': f, 'name': pkgname, 'version': f'{pkgver}-{pkgrel}', 'arch': arch, 'size': size, 'mtime': mtime_dt.isoformat(), 'mtime_display': mtime_dt.strftime('%Y-%m-%d %H:%M CET/CEST'), 'category': cat, 'cat_color': cat_colors.get(cat, '#7F8C8D'), 'description': description, 'url': meta.get('url', aur_info.get('URL', '') if aur_info else ''), 'license': meta.get('license', ', '.join(aur_info.get('License', [])) if aur_info else ''), 'depends': meta.get('depends', aur_info.get('Depends', []) if aur_info else []), }) pkgs.sort(key=lambda p: p['name']) rows_json = json.dumps(pkgs) total_size_mb = sum(p['size'] for p in pkgs) / 1024 / 1024 generated = datetime.now(tz=zoneinfo.ZoneInfo('Europe/Berlin')).strftime('%Y-%m-%d %H:%M CET/CEST') html = f'''
Custom package repository for Euri Linux ISO builds.
Packages are built automatically via CI.
pacman.conf
# /etc/pacman.conf [euri-pkgs] SigLevel = Optional TrustAll Server = https://antergos-nas.taild4360b.ts.net/pkgs/$repo/os/$arch
| Package ▼ | Category ▼ |
|---|