From 38ddae0d85c3e93efaf7c2edae098753b49fd807 Mon Sep 17 00:00:00 2001
From: "David M. Klein" <4+leander19961@noreply.localhost>
Date: Thu, 3 Sep 2026 14:25:32 +0200
Subject: [PATCH] =?UTF-8?q?Verzeichnis=20'mirror=20'=20l=C3=B6schen?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
mirror/Dockerfile | 65 ---
.../almalinux-baseline.repo | 44 --
mirror/entrypoint.sh | 12 -
mirror/run-as-mirror.sh | 62 ---
mirror/sync.sh | 526 ------------------
5 files changed, 709 deletions(-)
delete mode 100644 mirror/Dockerfile
delete mode 100644 mirror/config/alma-baseline.repo.d/almalinux-baseline.repo
delete mode 100644 mirror/entrypoint.sh
delete mode 100644 mirror/run-as-mirror.sh
delete mode 100644 mirror/sync.sh
diff --git a/mirror/Dockerfile b/mirror/Dockerfile
deleted file mode 100644
index 0901fff..0000000
--- a/mirror/Dockerfile
+++ /dev/null
@@ -1,65 +0,0 @@
-FROM almalinux:10
-
-# dnf-plugins-core -> dnf download, repoquery, config-manager
-# createrepo_c -> Repo-Metadaten bauen
-# rpm-sign, gnupg2 -> Pakete umsignieren
-# git, openssh-clients -> packages.yaml vor jedem Sync aus einem Git-Repo ziehen
-# python3-pyyaml, jq -> packages.yaml (YAML) nach JSON wandeln und auswerten
-# cpio -> Pakete fuer die AppStream-Erzeugung teilweise entpacken
-# rsync -> privaten Paketstand pflegen + alle Fremdrepos zu
-# einem gemeinsamen Repo zusammenfuehren
-# util-linux-core -> stellt setpriv (root -> mirror-User droppen) sicher
-RUN dnf -y install epel-release \
- && dnf -y install \
- dnf-plugins-core \
- createrepo_c \
- rpm-sign \
- gnupg2 \
- git \
- openssh-clients \
- python3-pyyaml \
- util-linux-core \
- findutils \
- cpio \
- rsync \
- procps-ng \
- jq \
- && dnf clean all
-
-# AppStream-Metadaten fuer Discover/GNOME Software: das noetige Werkzeug
-# unterscheidet sich je nach Alma-Version.
-# - AlmaLinux 9: appstream-glib (aus EPEL) liefert `appstream-builder`,
-# das direkt ein Verzeichnis voller .rpm-Dateien einliest.
-# - AlmaLinux 10: appstream-glib ist (Stand jetzt) weder in AlmaLinux 10
-# selbst noch in EPEL 10 paketiert. Stattdessen wird `appstreamcli`
-# genutzt - dessen "compose"-Kommando ist aber NICHT im Basispaket
-# `appstream` enthalten, sondern im separaten Subpaket
-# `appstream-compose` (liegt im selben AlmaLinux-10-AppStream-Repo).
-# Ohne dieses Subpaket bricht `appstreamcli compose` zur Laufzeit mit
-# "AppStream Compose binary ... was not found" ab.
-# sync.sh erkennt zur Laufzeit, welches der beiden Werkzeuge vorhanden ist.
-# Ist keins von beiden installierbar, bricht der Build NICHT ab - die
-# Discover-Katalogerzeugung wird dann zur Laufzeit einfach uebersprungen
-# (Pakete bleiben trotzdem ganz normal per dnf/pkcon installierbar).
-RUN (dnf -y install appstream-glib || dnf -y install appstream appstream-compose || dnf -y install appstream || \
- echo "WARNUNG (Build): weder appstream-glib noch appstream verfuegbar - AppStream/Discover-Metadaten werden zur Laufzeit uebersprungen.") \
- && dnf clean all
-
-RUN useradd -r -m -d /var/lib/mirror-gpg mirror
-
-COPY entrypoint.sh /usr/local/bin/entrypoint.sh
-COPY run-as-mirror.sh /usr/local/bin/run-as-mirror.sh
-COPY sync.sh /usr/local/bin/sync.sh
-RUN chmod +x /usr/local/bin/entrypoint.sh /usr/local/bin/run-as-mirror.sh /usr/local/bin/sync.sh
-
-RUN mkdir -p /srv/dnf /var/cache/mirror /var/lib/mirror-gpg \
- && chown -R mirror:mirror /srv/dnf /var/cache/mirror /var/lib/mirror-gpg
-
-ENV HOME=/var/lib/mirror-gpg
-ENV GNUPGHOME=/var/lib/mirror-gpg/.gnupg
-
-# Bleibt root: entrypoint.sh chownt den bind-gemounteten ./gpg-Ordner (der dem
-# Host gehoert, nicht dem Image) und wechselt danach per setpriv fest zu
-# "mirror". Alles Weitere (Sync-Loop, git, dnf download, gpg) laeuft
-# unprivilegiert.
-ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
diff --git a/mirror/config/alma-baseline.repo.d/almalinux-baseline.repo b/mirror/config/alma-baseline.repo.d/almalinux-baseline.repo
deleted file mode 100644
index e58021c..0000000
--- a/mirror/config/alma-baseline.repo.d/almalinux-baseline.repo
+++ /dev/null
@@ -1,44 +0,0 @@
-# OPTIONAL. Standardmaessig fragt sync.sh fuer die "was kann Alma sowieso
-# schon aufloesen?"-Pruefung einfach die im Mirror-Image bereits vorhandenen
-# System-Repos ab (das Image ist selbst AlmaLinux, hat also baseos/appstream/
-# extras/crb + epel schon konfiguriert) - dafuer ist diese Datei NICHT noetig.
-#
-# Setze die Env-Variable ALMA_BASELINE_REPOSDIR=/etc/mirror/alma-baseline.repo.d,
-# wenn du stattdessen explizit gegen andere/eigene Repo-Definitionen pruefen
-# willst (z.B. anderer Releasever, eigener interner Alma-Spiegel). Es wird
-# daraus nie etwas gespiegelt, nur `dnf repoquery` dagegen ausgefuehrt.
-
-[baseos]
-name=AlmaLinux $releasever - BaseOS
-mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos
-gpgcheck=1
-gpgkey=https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-10
-enabled=1
-
-[appstream]
-name=AlmaLinux $releasever - AppStream
-mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/appstream
-gpgcheck=1
-gpgkey=https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-10
-enabled=1
-
-[extras]
-name=AlmaLinux $releasever - Extras
-mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/extras
-gpgcheck=1
-gpgkey=https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-10
-enabled=1
-
-[crb]
-name=AlmaLinux $releasever - CRB
-mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/crb
-gpgcheck=1
-gpgkey=https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-10
-enabled=1
-
-[epel]
-name=Extra Packages for Enterprise Linux $releasever - $basearch
-metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-$releasever&arch=$basearch&infra=$infra&content=$contentdir
-gpgcheck=1
-gpgkey=https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-10
-enabled=1
diff --git a/mirror/entrypoint.sh b/mirror/entrypoint.sh
deleted file mode 100644
index 5444f7f..0000000
--- a/mirror/entrypoint.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-# Startet als root, damit der bind-gemountete ./gpg-Ordner (der auf dem Host
-# meist root oder dem einladenden User gehoert) dem "mirror"-User im Container
-# gehoert - danach wird per setpriv dauerhaft zu diesem unprivilegierten User
-# gewechselt (ersetzt den Prozess direkt, kein Wrapper-Kindprozess, damit
-# Signale/PID 1 sauber bleiben).
-set -euo pipefail
-
-mkdir -p /var/lib/mirror-gpg /srv/dnf /var/cache/mirror
-chown -R mirror:mirror /var/lib/mirror-gpg /srv/dnf /var/cache/mirror
-
-exec setpriv --reuid=mirror --regid=mirror --init-groups /usr/local/bin/run-as-mirror.sh
diff --git a/mirror/run-as-mirror.sh b/mirror/run-as-mirror.sh
deleted file mode 100644
index fdc9469..0000000
--- a/mirror/run-as-mirror.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/bash
-# Laeuft als unprivilegierter User "mirror" (siehe entrypoint.sh, der als
-# root die Verzeichnisrechte setzt und dann per setpriv hierher wechselt).
-set -euo pipefail
-
-: "${GPG_NAME:?GPG_NAME muss gesetzt sein}"
-: "${GPG_EMAIL:?GPG_EMAIL muss gesetzt sein}"
-: "${SYNC_INTERVAL_SECONDS:=21600}"
-
-mkdir -p "$GNUPGHOME"
-chmod 700 "$GNUPGHOME"
-echo "allow-loopback-pinentry" > "$GNUPGHOME/gpg-agent.conf"
-echo "pinentry-mode loopback" > "$GNUPGHOME/gpg.conf"
-
-PASSPHRASE_FILE=/run/secrets/gpg_passphrase
-if [ -z "${GPG_PASSPHRASE:-}" ] && [ ! -f "$PASSPHRASE_FILE" ]; then
- PASSPHRASE_FILE=""
-fi
-
-# GPG-Key nur beim allerersten Start erzeugen. Das gnupg-Home liegt im
-# bind-gemounteten ./gpg-Ordner neben der docker-compose.yml - der Key (und
-# damit der Public Key, den alle Clients einmalig vertrauen) bleibt ueber
-# Container-Neustarts/-Updates hinweg gleich UND ist direkt auf dem Host
-# sichtbar/sicherbar, statt in einem anonymen Docker-Volume zu stecken.
-if ! gpg --batch --list-secret-keys "$GPG_NAME" >/dev/null 2>&1; then
- echo "[entrypoint] Erzeuge neuen Signing-Key fuer '$GPG_NAME <$GPG_EMAIL>' ..."
- KEYPARAMS=$(mktemp)
- {
- echo "%echo Generating mirror signing key"
- echo "Key-Type: RSA"
- echo "Key-Length: 4096"
- echo "Name-Real: $GPG_NAME"
- echo "Name-Email: $GPG_EMAIL"
- echo "Expire-Date: 0"
- if [ -n "$PASSPHRASE_FILE" ]; then
- echo "Passphrase: $(cat "$PASSPHRASE_FILE")"
- else
- echo "%no-protection"
- fi
- echo "%commit"
- } > "$KEYPARAMS"
- gpg --batch --gen-key "$KEYPARAMS"
- rm -f "$KEYPARAMS"
-else
- echo "[entrypoint] Signing-Key existiert bereits, wird wiederverwendet."
-fi
-
-mkdir -p /srv/dnf
-gpg --batch --yes --armor --export "$GPG_NAME" > /srv/dnf/RPM-GPG-KEY-mirror
-echo "[entrypoint] Public Key nach /srv/dnf/RPM-GPG-KEY-mirror exportiert."
-
-term_handler() {
- echo "[entrypoint] Beende nach aktuellem Sync-Lauf ..."
- exit 0
-}
-trap term_handler SIGTERM SIGINT
-
-while true; do
- /usr/local/bin/sync.sh || echo "[entrypoint] sync.sh ist mit Fehler beendet, naechster Versuch in ${SYNC_INTERVAL_SECONDS}s"
- sleep "$SYNC_INTERVAL_SECONDS" &
- wait $!
-done
diff --git a/mirror/sync.sh b/mirror/sync.sh
deleted file mode 100644
index 27ae619..0000000
--- a/mirror/sync.sh
+++ /dev/null
@@ -1,526 +0,0 @@
-#!/bin/bash
-# Ein Sync-Durchlauf:
-# 0. packages.yaml frisch aus Git ziehen (Fremdrepos + Paketnamen je Repo)
-# 1. je Fremdrepo genau die dort gelisteten Pakete per `dnf download` holen,
-# filtern (Alma-Baseline) und in einen privaten, pro Fremdrepo getrennten
-# Paket-Cache signieren
-# 2. ALLE Fremdrepos zu EINEM gemeinsamen, oeffentlichen Ausgabe-Repo
-# zusammenfuehren (ein repodata, ein GPG-Key, eine Client-.repo-Datei) -
-# Clients binden nur dieses eine Repo ein, unabhaengig davon, aus wie
-# vielen Fremdrepos die Pakete urspruenglich stammen
-# 3. Repo-Metadaten (createrepo_c) + AppStream-Metadaten (fuer Discover) bauen
-# 4. repomd.xml signieren, Client-.repo-Datei schreiben
-set -uo pipefail
-
-CACHE=/var/cache/mirror
-OUT=/srv/dnf
-SOURCES_GIT_CHECKOUT="$CACHE/sources-git"
-PACKAGES_JSON="$CACHE/packages.json"
-SIGNED_ROOT="$CACHE/signed"
-
-: "${GPG_NAME:?}"
-: "${MIRROR_DOMAIN:?}"
-: "${SOURCES_GIT_URL:?SOURCES_GIT_URL muss auf das Git-Repo mit packages.yaml zeigen}"
-: "${SOURCES_GIT_REF:=main}"
-: "${MIRROR_REPO_ID:=company-mirror}"
-: "${ALMA_RELEASEVER:=10}"
-: "${ALMA_BASEARCH:=x86_64}"
-: "${ALMA_BASELINE_REPOIDS:=baseos,appstream,extras,crb,epel}"
-
-mkdir -p "$CACHE/stage" "$CACHE/appstream-cache" "$CACHE/tmp-repos" "$SIGNED_ROOT" "$OUT"
-
-log() { echo "[sync $(date '+%F %T')] $*"; }
-
-# Zieht packages.yaml vor JEDEM Sync-Lauf frisch aus einem Git-Repo (statt aus
-# lokal gemounteten Dateien), damit Aenderungen an der Paketliste ohne
-# Container-Neubau/-Neustart wirksam werden.
-fetch_packages_yaml() {
- if [ -n "${SOURCES_GIT_SSH_KEY:-}" ] && [ -f "$SOURCES_GIT_SSH_KEY" ]; then
- export GIT_SSH_COMMAND="ssh -i ${SOURCES_GIT_SSH_KEY} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=${CACHE}/known_hosts"
- fi
-
- if [ -d "$SOURCES_GIT_CHECKOUT/.git" ]; then
- log "Aktualisiere packages.yaml aus Git ($SOURCES_GIT_URL @ $SOURCES_GIT_REF) ..."
- if git -C "$SOURCES_GIT_CHECKOUT" fetch --depth 1 origin "$SOURCES_GIT_REF" >>"$CACHE/git-sources.log" 2>&1 \
- && git -C "$SOURCES_GIT_CHECKOUT" reset --hard FETCH_HEAD >>"$CACHE/git-sources.log" 2>&1 \
- && git -C "$SOURCES_GIT_CHECKOUT" clean -fdx >>"$CACHE/git-sources.log" 2>&1; then
- :
- else
- log "WARNUNG: git fetch fehlgeschlagen, siehe $CACHE/git-sources.log - verwende letzten bekannten Stand von packages.yaml weiter."
- fi
- else
- log "Klone packages.yaml aus Git ($SOURCES_GIT_URL @ $SOURCES_GIT_REF) ..."
- rm -rf "$SOURCES_GIT_CHECKOUT"
- if ! git clone --branch "$SOURCES_GIT_REF" --single-branch --depth 1 \
- "$SOURCES_GIT_URL" "$SOURCES_GIT_CHECKOUT" >>"$CACHE/git-sources.log" 2>&1; then
- log "FEHLER: Erstklon von packages.yaml aus Git fehlgeschlagen, siehe $CACHE/git-sources.log"
- return 1
- fi
- fi
-
- local yaml_file="$SOURCES_GIT_CHECKOUT/packages.yaml"
- if [ ! -f "$yaml_file" ]; then
- log "FEHLER: $yaml_file existiert nicht im Git-Repo."
- return 1
- fi
-
- if ! python3 -c '
-import sys, json, yaml
-with open(sys.argv[1]) as f:
- data = yaml.safe_load(f) or {}
-data.setdefault("repos", [])
-data.setdefault("force_include", [])
-json.dump(data, sys.stdout)
-' "$yaml_file" > "$PACKAGES_JSON.tmp" 2>"$CACHE/packages-yaml-parse.log"; then
- log "FEHLER: packages.yaml ist kein gueltiges YAML, siehe $CACHE/packages-yaml-parse.log"
- rm -f "$PACKAGES_JSON.tmp"
- return 1
- fi
- mv "$PACKAGES_JSON.tmp" "$PACKAGES_JSON"
-}
-
-refresh_alma_names() {
- log "Ermittle Paketnamen, die AlmaLinux selbst bereitstellt ..."
- local -a enable_args=()
- local id
- IFS=',' read -ra ids <<< "$ALMA_BASELINE_REPOIDS"
- for id in "${ids[@]}"; do
- enable_args+=(--enablerepo="$id")
- done
-
- local -a reposdir_args=()
- if [ -n "${ALMA_BASELINE_REPOSDIR:-}" ] && ls "${ALMA_BASELINE_REPOSDIR}"/*.repo >/dev/null 2>&1; then
- reposdir_args=(--setopt="reposdir=${ALMA_BASELINE_REPOSDIR}")
- fi
-
- if ! dnf repoquery -y --quiet -a --qf '%{name}' \
- --disablerepo='*' "${enable_args[@]}" \
- --releasever="$ALMA_RELEASEVER" --forcearch="$ALMA_BASEARCH" \
- "${reposdir_args[@]}" 2>>"$CACHE/repoquery.log" | sort -u > "$CACHE/alma-names.txt.tmp"; then
- log "WARNUNG: repoquery gegen AlmaLinux-Baseline fehlgeschlagen, siehe $CACHE/repoquery.log"
- log "Verwende ggf. vorherigen Stand von alma-names.txt weiter."
- rm -f "$CACHE/alma-names.txt.tmp"
- return
- fi
- mv "$CACHE/alma-names.txt.tmp" "$CACHE/alma-names.txt"
- log "$(wc -l < "$CACHE/alma-names.txt") Paketnamen als 'ueber Alma aufloesbar' erfasst."
-}
-
-is_force_included() {
- local name="$1" f
- for f in "${FORCE_INCLUDE_NAMES[@]}"; do
- [ "$f" = "$name" ] && return 0
- done
- return 1
-}
-
-# Liest einen einzelnen Schluessel aus dem [Desktop Entry]-Abschnitt einer
-# .desktop-Datei (ignoriert lokalisierte Varianten wie Name[de]= und andere
-# Abschnitte wie [Desktop Action ...]).
-desktop_get() {
- local file="$1" key="$2"
- awk -v key="$key" '
- /^\[Desktop Entry\]/ { insec=1; next }
- /^\[/ { insec=0 }
- insec && index($0, key "=") == 1 { sub("^" key "=", ""); print; exit }
- ' "$file"
-}
-
-xml_escape() {
- local s="$1"
- s="${s//&/&}"
- s="${s//<}"
- s="${s//>/>}"
- s="${s//\"/"}"
- s="${s//\'/'}"
- printf '%s' "$s"
-}
-
-# appstreamcli compose (AppStream 1.0+) ignoriert .desktop-Dateien komplett,
-# wenn keine begleitende .metainfo.xml existiert - anders als das aeltere
-# appstream-builder, das genau das frueher automatisch synthetisiert hat.
-# Die meisten unabhaengigen Drittanbieter-RPMs (z.B. jpackage-basierte Apps
-# wie XPipe) liefern aber nur eine .desktop-Datei mit. Deshalb hier selbst
-# eine minimale Ersatz-Metainfo aus den Desktop-Datei-Feldern erzeugen, damit
-# die Anwendung ueberhaupt einen Katalogeintrag in Discover bekommt. Bringt
-# ein Paket schon eine echte .metainfo.xml mit (die auf dasselbe Desktop-File
-# verweist), hat diese immer Vorrang - hier wird dann nichts generiert.
-generate_fallback_metainfo() {
- local composeroot="$1" pkgmap="$2"
- local appdir="$composeroot/usr/share/applications"
- local metadir="$composeroot/usr/share/metainfo"
- local desktop_file base name summary categories cat pkgname
-
- [ -d "$appdir" ] || return
- mkdir -p "$metadir"
-
- for desktop_file in "$appdir"/*.desktop; do
- [ -e "$desktop_file" ] || continue
- base=$(basename "$desktop_file")
-
- if grep -rlq "type=\"desktop-id\">${base}<" "$metadir" 2>/dev/null; then
- continue
- fi
-
- pkgname=""
- [ -f "$pkgmap" ] && pkgname=$(awk -F'\t' -v b="$base" '$1 == b {print $2; exit}' "$pkgmap")
- [ -z "$pkgname" ] && pkgname="${base%.desktop}"
-
- name=$(desktop_get "$desktop_file" "Name")
- summary=$(desktop_get "$desktop_file" "Comment")
- categories=$(desktop_get "$desktop_file" "Categories")
- [ -z "$name" ] && name="${base%.desktop}"
- [ -z "$summary" ] && summary="$name"
-
- {
- echo ''
- echo ''
- echo " ${base}"
- echo " $(xml_escape "$pkgname")"
- echo ' CC0-1.0'
- echo ' LicenseRef-proprietary'
- echo " $(xml_escape "$name")"
- echo " $(xml_escape "$summary")"
- echo " "
- echo " $(xml_escape "$summary")
"
- echo " "
- echo " ${base}"
- if [ -n "$categories" ]; then
- echo ' '
- local IFS=';'
- for cat in $categories; do
- [ -z "$cat" ] && continue
- echo " $(xml_escape "$cat")"
- done
- echo ' '
- fi
- echo ''
- } > "$metadir/${base%.desktop}.metainfo.xml"
- done
-}
-
-# AlmaLinux 9: appstream-glib (aus EPEL) liest ein Verzeichnis voller
-# .rpm-Dateien direkt ein.
-generate_appstream_via_builder() {
- local id="$1" out="$2"
- local asout="$CACHE/appstream/$id"
- mkdir -p "$asout"
- if appstream-builder \
- --origin="$id" --basename="$id" \
- --cache-dir="$CACHE/appstream-cache/$id" \
- --packages-dir="$out" \
- --output-dir="$asout" \
- --min-icon-size=48 --enable-hidpi \
- >>"$CACHE/appstream-$id.log" 2>&1; then
- [ -f "$asout/$id.xml.gz" ] && modifyrepo_c --mdtype=appstream "$asout/$id.xml.gz" "$out/repodata"
- [ -f "$asout/$id-icons.tar.gz" ] && modifyrepo_c --mdtype=appstream-icons "$asout/$id-icons.tar.gz" "$out/repodata"
- else
- log "WARNUNG: appstream-builder fuer $id fehlgeschlagen (nicht fatal), siehe $CACHE/appstream-$id.log"
- fi
-}
-
-# AlmaLinux 10: appstream-glib gibt es (Stand jetzt) weder dort noch in
-# EPEL 10, stattdessen `appstream`/appstreamcli. Dessen "compose"-Kommando
-# arbeitet nicht auf .rpm-Dateien, sondern auf einem Verzeichnisbaum wie
-# einem Dateisystem-Root (/usr/share/applications, /usr/share/metainfo, ...).
-# Wir entpacken deshalb erst die dafuer relevanten Pfade aus allen Paketen in
-# so einen Baum und rufen dann `appstreamcli compose` darauf auf.
-generate_appstream_via_compose() {
- local id="$1" out="$2"
- local composeroot="$CACHE/appstream-root/$id"
- local asout="$CACHE/appstream/$id"
- local pkgmap="$CACHE/appstream-pkgmap-$id.txt"
- local rpm
-
- rm -rf "$composeroot"
- mkdir -p "$composeroot/usr/share/applications" "$composeroot/usr/share/metainfo"
- : > "$pkgmap"
-
- for rpm in "$out"/*.rpm; do
- [ -e "$rpm" ] || continue
- local pkgname
- pkgname=$(rpm -qp --qf '%{NAME}' "$rpm" 2>/dev/null)
-
- # Icons/Pixmaps liegen so gut wie immer am Standard-FHS-Pfad - dafuer
- # reicht ein blinder Glob-Extract, eine Paketzuordnung brauchen wir
- # dafuer nicht.
- (cd "$composeroot" && rpm2cpio "$rpm" | cpio -idm --quiet \
- './usr/share/icons/*' \
- './usr/share/pixmaps/*') >>"$CACHE/appstream-$id.log" 2>&1
-
- # .desktop-/AppStream-Dateien koennen dagegen auch ausserhalb der
- # Standardpfade liegen (u.a. alle jpackage-basierten Java/JavaFX-Apps
- # wie z.B. XPipe legen sie direkt im eigenen Installationsverzeichnis
- # ab, z.B. /opt//.desktop, und verschieben sie erst per
- # %post-Skript - das sehen wir beim reinen Lesen des Pakets nicht).
- # Deshalb IMMER das ganze Paket nur AUFLISTEN (kein teurer Voll-
- # Extract, bei z.T. >100 MB grossen JRE-Bundles) und alle
- # .desktop/.metainfo.xml/.appdata.xml-Dateien gezielt herausgreifen -
- # dabei merken wir uns, aus welchem RPM-Paket jede .desktop-Datei
- # stammt, fuer in der (Fallback-)Metainfo weiter unten.
- local matches
- mapfile -t matches < <(rpm2cpio "$rpm" 2>/dev/null | cpio -t --quiet 2>/dev/null \
- | grep -E '\.desktop$|\.metainfo\.xml$|\.appdata\.xml$')
-
- if [ "${#matches[@]}" -gt 0 ]; then
- local extractroot f base destdir
- extractroot=$(mktemp -d)
- (cd "$extractroot" && rpm2cpio "$rpm" | cpio -idm --quiet "${matches[@]}") >>"$CACHE/appstream-$id.log" 2>&1
- for f in "${matches[@]}"; do
- [ -f "$extractroot/$f" ] || continue
- base=$(basename "$f")
- case "$base" in
- *.desktop)
- destdir="$composeroot/usr/share/applications"
- printf '%s\t%s\n' "$base" "$pkgname" >> "$pkgmap"
- ;;
- *)
- destdir="$composeroot/usr/share/metainfo"
- ;;
- esac
- # Nicht ueberschreiben, falls bereits ein anderes Paket schon
- # eine gleichnamige Datei mitgebracht hat.
- if [ ! -e "$destdir/$base" ]; then
- cp "$extractroot/$f" "$destdir/$base"
- # Vom Hersteller mitgelieferte .metainfo.xml/.appdata.xml
- # haben so gut wie nie ein (das kennt nur die
- # Distro/das Repo, nicht der Upstream-Entwickler) - ohne
- # das bleibt die Komponente in Discover trotz gueltiger
- # Metainfo nicht installierbar. Deshalb hier direkt
- # ergaenzen, falls es fehlt.
- if [ "$base" != "${base%.desktop}" ]; then
- : # ist eine .desktop-Datei, braucht selbst kein
- elif ! grep -q '' "$destdir/$base" 2>/dev/null; then
- sed -i "s## $(xml_escape "$pkgname")\n#" "$destdir/$base"
- fi
- fi
- done
- rm -rf "$extractroot"
- fi
- done
-
- if [ -z "$(find "$composeroot" -type f 2>/dev/null)" ]; then
- log "Keine Desktop-/AppStream-Dateien in den Paketen gefunden, ueberspringe Katalog-Generierung."
- return
- fi
-
- generate_fallback_metainfo "$composeroot" "$pkgmap"
-
- rm -rf "$asout"
- mkdir -p "$asout"
- # Exit-Code NICHT sofort als fatal behandeln: appstreamcli compose liefert
- # bei einzelnen fehlerhaften Komponenten ("Run failed, some data was
- # ignored") einen Fehler-Exitcode, schreibt aber trotzdem einen Katalog
- # mit allen UEBRIGEN, gueltigen Komponenten. Nur wenn am Ende wirklich
- # gar kein Katalog entstanden ist, brechen wir ab.
- if ! appstreamcli compose --prefix=/usr --origin="$id" --result-root="$asout" "$composeroot" \
- >>"$CACHE/appstream-$id.log" 2>&1; then
- log "WARNUNG: appstreamcli compose meldet Fehler bei einzelnen Komponenten, siehe $CACHE/appstream-$id.log - verwende ggf. trotzdem erzeugten Teil-Katalog."
- fi
-
- local catalog
- catalog=$(find "$asout" -type f \( -iname '*.xml.gz' -o -iname '*.yml.gz' \) | head -n1)
- if [ -z "$catalog" ]; then
- log "WARNUNG: appstreamcli compose hat keinen Katalog erzeugt, siehe $CACHE/appstream-$id.log"
- return
- fi
- modifyrepo_c --mdtype=appstream "$catalog" "$out/repodata"
-
- local icons_dir
- icons_dir=$(find "$asout" -type d -iname 'icons' | head -n1)
- if [ -n "$icons_dir" ] && [ -n "$(find "$icons_dir" -type f 2>/dev/null)" ]; then
- tar -C "$icons_dir" -czf "$asout/$id-icons.tar.gz" .
- modifyrepo_c --mdtype=appstream-icons "$asout/$id-icons.tar.gz" "$out/repodata"
- fi
-}
-
-# Holt + filtert + signiert die Pakete EINES Fremdrepos in einen privaten,
-# nur intern genutzten Cache ($SIGNED_ROOT/$id) - noch NICHT im oeffentlichen
-# Ausgabeverzeichnis. Der eigentliche Merge zu einem gemeinsamen Repo passiert
-# erst danach, einmalig fuer alle Fremdrepos zusammen (siehe unten).
-# Args: id baseurl gpgkey gpgcheck(0/1) paket1 [paket2 ...]
-sync_one_repo() {
- local id="$1" baseurl="$2" gpgkey="$3" gpgcheck="$4"
- shift 4
- local -a packages=("$@")
- local stage="$CACHE/stage/$id"
- local signed="$SIGNED_ROOT/$id"
- local tmp_repofile="$CACHE/tmp-repos/$id.repo"
-
- log "== $id: hole ${#packages[@]} Paket(e) aus $baseurl =="
- rm -f "$CACHE/tmp-repos"/*.repo
- {
- echo "[$id]"
- echo "name=$id"
- echo "baseurl=$baseurl"
- echo "enabled=1"
- echo "gpgcheck=$gpgcheck"
- [ -n "$gpgkey" ] && echo "gpgkey=$gpgkey"
- } > "$tmp_repofile"
-
- rm -rf "$stage"
- mkdir -p "$stage"
- if ! dnf --setopt="reposdir=$CACHE/tmp-repos" \
- --disablerepo='*' --enablerepo="$id" \
- --forcearch="$ALMA_BASEARCH" \
- download --destdir="$stage" "${packages[@]}" \
- >>"$CACHE/download-$id.log" 2>&1; then
- log "FEHLER: dnf download fuer $id fehlgeschlagen, siehe $CACHE/download-$id.log - ueberspringe (bisheriger Stand von $id bleibt im gemeinsamen Repo erhalten)."
- return 1
- fi
-
- log "== $id: filtere Pakete, die Alma bereits bereitstellt =="
- local removed=0 kept=0
- while IFS= read -r -d '' rpm; do
- local name
- name=$(rpm -qp --qf '%{NAME}' "$rpm" 2>/dev/null)
- if [ -z "$name" ]; then
- continue
- fi
- if grep -qxF "$name" "$CACHE/alma-names.txt" 2>/dev/null && ! is_force_included "$name"; then
- rm -f "$rpm"
- removed=$((removed + 1))
- else
- kept=$((kept + 1))
- fi
- done < <(find "$stage" -maxdepth 1 -name '*.rpm' -print0)
- log "$id: $kept Pakete werden gespiegelt, $removed uebersprungen (bereits ueber Alma verfuegbar)."
-
- log "== $id: aktualisiere internen Paketstand und signiere neue/geaenderte Pakete =="
- mkdir -p "$signed"
- local changed_list rsync_out
- changed_list=$(mktemp)
- rsync_out=$(mktemp)
- if ! rsync -ai --delete --include='*.rpm' --exclude='*' "$stage"/ "$signed"/ > "$rsync_out" 2>&1; then
- log "FEHLER: rsync (interner Paketstand) fuer $id fehlgeschlagen: $(cat "$rsync_out") - ueberspringe $id fuer diesen Lauf."
- rm -f "$changed_list" "$rsync_out"
- return 1
- fi
- awk '/^[><]f/{print $2}' "$rsync_out" > "$changed_list"
- rm -f "$rsync_out"
-
- local resign_failed=0
- while IFS= read -r f; do
- [ -z "$f" ] && continue
- if ! rpmsign --resign \
- --define "_gpg_name $GPG_NAME" \
- --define "_gpg_path $GNUPGHOME" \
- "$signed/$f" >>"$CACHE/rpmsign-$id.log" 2>&1; then
- log "FEHLER: Signieren von $signed/$f fehlgeschlagen, siehe $CACHE/rpmsign-$id.log"
- resign_failed=1
- fi
- done < "$changed_list"
- local changed_count
- changed_count=$(wc -l < "$changed_list")
- rm -f "$changed_list"
- log "$id: $changed_count Pakete neu signiert."
- if [ "$resign_failed" -ne 0 ]; then
- log "FEHLER: mind. ein Paket in $id konnte nicht signiert werden - $id wird bei der Zusammenfuehrung uebersprungen."
- return 1
- fi
-
- log "== $id: fertig =="
-}
-
-if ! fetch_packages_yaml; then
- log "FEHLER: keine packages.yaml verfuegbar, breche Sync-Lauf komplett ab."
- exit 1
-fi
-
-mapfile -t FORCE_INCLUDE_NAMES < <(jq -r '.force_include[]? // empty' "$PACKAGES_JSON")
-
-refresh_alma_names
-if [ ! -s "$CACHE/alma-names.txt" ]; then
- log "FEHLER: keine Alma-Baseline-Namen verfuegbar, breche Sync-Lauf ab (Sicherheitsnetz gegen versehentliches Doppel-Spiegeln)."
- exit 1
-fi
-
-overall_status=0
-all_ids=()
-repo_count=$(jq '.repos | length' "$PACKAGES_JSON")
-for ((i = 0; i < repo_count; i++)); do
- repo_json=$(jq -c ".repos[$i]" "$PACKAGES_JSON")
- id=$(jq -r '.id // empty' <<<"$repo_json")
- baseurl=$(jq -r '.baseurl // empty' <<<"$repo_json")
- gpgkey=$(jq -r '.gpgkey // empty' <<<"$repo_json")
- gpgcheck=$(jq -r 'if .gpgcheck == false then "0" else "1" end' <<<"$repo_json")
- mapfile -t packages < <(jq -r '.packages[]? // empty' <<<"$repo_json")
-
- if [ -z "$id" ] || [ -z "$baseurl" ] || [ "${#packages[@]}" -eq 0 ]; then
- log "WARNUNG: Eintrag Nr. $((i + 1)) in packages.yaml unvollstaendig (id/baseurl/packages fehlt), ueberspringe."
- overall_status=1
- continue
- fi
-
- all_ids+=("$id")
- sync_one_repo "$id" "$baseurl" "$gpgkey" "$gpgcheck" "${packages[@]}" || overall_status=1
-done
-
-# Internen Paketstand von Fremdrepos aufraeumen, die nicht mehr in
-# packages.yaml stehen - sonst wuerden deren alte Pakete beim Merge unten
-# unnoetig im Cache liegen bleiben (sie werden ja schon jetzt nicht mehr in
-# die Merge-Quellenliste aufgenommen, siehe unten - das hier ist nur Hygiene).
-if [ -d "$SIGNED_ROOT" ]; then
- for d in "$SIGNED_ROOT"/*/; do
- [ -d "$d" ] || continue
- existing_id=$(basename "$d")
- keep=0
- for id in "${all_ids[@]}"; do
- [ "$id" = "$existing_id" ] && keep=1 && break
- done
- if [ "$keep" -eq 0 ]; then
- log "Entferne internen Paketstand des nicht mehr in packages.yaml gelisteten Fremdrepos '$existing_id' ..."
- rm -rf "$d"
- fi
- done
-fi
-
-log "== Fuehre alle Fremdrepos zu EINEM gemeinsamen Ausgabe-Repo zusammen =="
-merge_sources=()
-for id in "${all_ids[@]}"; do
- [ -d "$SIGNED_ROOT/$id" ] && merge_sources+=("$SIGNED_ROOT/$id/")
-done
-
-if [ "${#merge_sources[@]}" -eq 0 ]; then
- log "FEHLER: kein Fremdrepo hat je erfolgreich Pakete geliefert - gemeinsames Repo bleibt unveraendert/leer."
- exit 1
-fi
-
-if ! rsync -ai --delete --include='*.rpm' --exclude='*' "${merge_sources[@]}" "$OUT"/ >>"$CACHE/merge.log" 2>&1; then
- log "FEHLER: Zusammenfuehren der Fremdrepos zum gemeinsamen Repo fehlgeschlagen, siehe $CACHE/merge.log"
- exit 1
-fi
-
-log "== baue Repo-Metadaten fuer das gemeinsame Repo =="
-if ! createrepo_c --update "$OUT" >>"$CACHE/createrepo.log" 2>&1; then
- log "FEHLER: createrepo_c fehlgeschlagen, siehe $CACHE/createrepo.log"
- exit 1
-fi
-
-log "== baue AppStream-Metadaten (fuer Discover/GNOME Software) =="
-if command -v appstream-builder >/dev/null 2>&1; then
- generate_appstream_via_builder "$MIRROR_REPO_ID" "$OUT"
-elif command -v appstreamcli >/dev/null 2>&1; then
- generate_appstream_via_compose "$MIRROR_REPO_ID" "$OUT"
-else
- log "WARNUNG: weder appstream-builder noch appstreamcli installiert - Pakete erscheinen ohne App-Katalogeintrag in Discover."
-fi
-
-log "== signiere repomd.xml =="
-gpg --batch --yes --detach-sign --armor --local-user "$GPG_NAME" \
- --output "$OUT/repodata/repomd.xml.asc" "$OUT/repodata/repomd.xml"
-
-cat > "$OUT/$MIRROR_REPO_ID.repo" <