🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
#!/bin/bash
# =============================================================================
# repo-index.sh – buduje indeks repozytorium PaganOS z gotowych .pag
#
# Dla każdego pakietu w katalogu wyjściowym:
# • wylicza SHA256,
# • czyta metadata.json z wnętrza .pag,
# • generuje podpis detach (GPG), jeśli klucz dostępny,
# a na końcu tworzy:
# • repo.json – pełny indeks (czytelny dla menedżera pakietów),
# • packages.db – lekka baza (name/version/sha256/path),
# • repo.db – alias/symlink do repo.json (kompat staranne narzędzia).
#
# Użycie:
# ./repo-index.sh [--out /var/cache/pagbuild/output] [--repo ./repo] \
# [--gpg-key KEYID] [--sign-all]
# =============================================================================
set -euo pipefail
OUT_DIR="${1:-/var/cache/pagbuild/output}"
REPO_DIR="${REPO_DIR:-$PWD/repo}"
GPG_KEY="${GPG_KEY:-}"
SIGN_ALL=0
while [[ $# -gt 0 ]]; do
case "$1" in
--out) OUT_DIR="$2"; shift 2 ;;
--repo) REPO_DIR="$2"; shift 2 ;;
--gpg-key) GPG_KEY="$2"; shift 2 ;;
--sign-all) SIGN_ALL=1; shift ;;
-h|--help) sed -n '1,20p' "$0"; exit 0 ;;
*) echo "Nieznany argument: $1" >&2; exit 2 ;;
esac
done
mkdir -p "$REPO_DIR"
# Znajdź python3 (host)
PY=python3
command -v "$PY" >/dev/null || { echo "Brak python3" >&2; exit 1; }
# Podpis (jeśli zdefiniowano klucz lub --sign-all i klucz istnieje)
GPG="$(command -v gpg2 || command -v gpg || true)"
sign_file() { # $1 -> plik
# Usuń stary podpis ZAWSZE: detach-sign nie nadpisuje istniejącego .asc
# ("File exists"), a nadpisany repo.json bez świeżego .asc = BAD SIGNATURE
# dla klientów pag. Bez klucza też usuwamy – lepszy czytelny brak podpisu
# niż nieaktualny (klienci: fail-closed „nie można pobrać podpisu”).
rm -f "${1}.asc"
[[ -n "$GPG" && -n "$GPG_KEY" ]] || return 0
"$GPG" --detach-sign --armor --local-user "$GPG_KEY" --batch --no-tty "$1" 2>/dev/null \
&& echo " -> ${1}.asc" || echo " (brak podpisu: ${1})"
}
# Zbierz pakiety
mapfile -t PKGS < <(find "$OUT_DIR" -maxdepth 1 -name '*.pag' | sort)
if [[ ${#PKGS[@]} -eq 0 ]]; then
echo "Brak pakietów w $OUT_DIR" >&2
exit 1
fi
echo "Indeksowanie ${#PKGS[@]} pakietów z $OUT_DIR"
ENTRIES_JSON=()
DB_ROWS=()
for f in "${PKGS[@]}"; do
name_full=$(basename "$f")
# metadata.json wewnątrz .pag (top-level)
sha=$(sha256sum "$f" | awk '{print $1}')
meta=$("$PY" -c "
import sys, tarfile, json, io
try:
t=tarfile.open('$f','r:xz')
b=t.extractfile('metadata.json').read()
print(json.dumps(json.loads(b.decode())))
except Exception:
print('{}')
" 2>/dev/null || echo '{}')
# Podstawowe pola (z metadata albo z nazwy)
entry=$("$PY" - "$f" "$sha" "$meta" <<'PY'
import sys, json, re
fn, sha, meta = sys.argv[1], sys.argv[2], sys.argv[3] or '{}'
try: m=json.loads(meta)
except Exception: m={}
base=fn[:-4] if fn.endswith('.pag') else fn
name=m.get('name') or base.rsplit('-',2)[0]
ver =m.get('version') or base.rsplit('-',2)[1]
rel =str(m.get('release', m.get('pkgrel', 1)))
# filename = sama nazwa (bez ścieżki) – menedżer pakietów pobiera go z repo
fn_base = __import__('os').path.basename(fn)
print(json.dumps({
'file': fn_base, 'sha256': sha, 'name': name, 'version': ver, 'release': rel,
'size': __import__('os').path.getsize(fn),
'description': m.get('description',''), 'license': m.get('license',[]),
'depends': m.get('depends',[]), 'url': m.get('url',''),
'filename': fn_base,
# Wirtualne zależności (sekcja `provides:` w PAGBUILD.yaml) MUSZĄ trafić do
# repo.json – inaczej klient `pag` nie rozwiąże np. `python3` -> `python`
# i odmówi instalacji pakietu, którego zależność jest wirtualna.
# pagbuild zapisuje je w metadata.json; dawne wersje tego skryptu je gubiły.
'provides': m.get('provides',[]),
'provides_so': m.get('provides_so',[]),
'requires_so': m.get('requires_so',[]),
}))
PY
)
ENTRY="{\"$entry\"}"
# zbuduj obiekt JSON poprawnie
ENTRY=$("$PY" -c "import sys,json; print(json.dumps(json.loads('$entry')))")
ENTRIES_JSON+=("$entry")
row=$("$PY" -c "import sys,json; d=json.loads('$entry'); print(f\"{d['name']}|{d['version']}|{d['release']}|{d['sha256']}|{d['file']}\")")
DB_ROWS+=("$row")
if [[ $SIGN_ALL -eq 1 ]]; then
sign_file "$f"
fi
echo " + $name_full ($([ -n "$sha" ] && echo "${sha:0:12}" || echo '?')...)"
done
# repo.json – jeden obiekt JSON z listą
{
echo '{'
echo ' "generated": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",'
echo ' "count": '"${#PKGS[@]}"','
echo ' "packages": ['
for i in "${!ENTRIES_JSON[@]}"; do
sep=","
[[ $i -lt $(( ${#ENTRIES_JSON[@]} - 1 )) ]] || sep=""
echo " ${ENTRIES_JSON[$i]}$sep"
done
echo ' ]'
echo '}'
} > "$REPO_DIR/repo.json"
# packages.db – prosta tabela
{
echo "#name|version|release|sha256|file"
printf '%s\n' "${DB_ROWS[@]}"
} > "$REPO_DIR/packages.db"
# repo.db – alias do repo.json (kompat)
ln -sf repo.json "$REPO_DIR/repo.db"
# Podpisz cały indeks (jeśli klucz)
sign_file "$REPO_DIR/repo.json"
# Sumy indeksu
sha256sum "$REPO_DIR/repo.json" > "$REPO_DIR/repo.json.sha256"
echo ""
echo "Repozytorium gotowe w: $REPO_DIR"
echo " repo.json ($(wc -c < "$REPO_DIR/repo.json") B)"
echo " packages.db ($(wc -l < "$REPO_DIR/packages.db") wierszy)"
echo " repo.json.sha256"
[[ -n "$GPG_KEY" ]] && echo " Podpisano indeks i pakiety (klucz: $GPG_KEY)"