From 0f07b8cff54fd32cacac6842abbe112cacd1ef8f Mon Sep 17 00:00:00 2001 From: Philip Peterson <1326208+philip-peterson@users.noreply.github.com> Date: Fri, 30 Oct 2026 23:45:13 -0800 Subject: [PATCH] Throwaway: upload a build's dnf cache to the forge's RPM registry, and time it Co-Authored-By: Claude Opus 5.5 --- .forgejo/upload-rpms.sh | 47 ++++++++++++++++++++++++++ .forgejo/workflows/rpm-mirror-test.yml | 36 ++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100755 .forgejo/upload-rpms.sh create mode 100644 .forgejo/workflows/rpm-mirror-test.yml diff --git a/.forgejo/upload-rpms.sh b/.forgejo/upload-rpms.sh new file mode 100755 index 00000000..30bbf34b --- /dev/null +++ b/.forgejo/upload-rpms.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# Uploads the RPMs a build downloaded (its dnf cache, kept by +# Containerfile.in's cache mounts) to this forge's RPM registry, one group +# per upstream repository: fedora, updates, terra, copr-ublue-os-packages... +# Each group is a dnf repository at +# https://forge.quinefoundation.com/api/packages/quine-global-labs/rpm/. +# +# Usage: upload-rpms.sh CACHE_DIR (a libdnf5 cache: one directory per +# repository, -/packages/*.rpm) +# +# Needs REGISTRY_USER and REGISTRY_TOKEN (package write access). Packages +# the registry already has are skipped (409). Best effort: a failed upload +# is a warning, not a failure. +set -euo pipefail + +cache=$1 +api=${RPM_API:-https://forge.quinefoundation.com/api/packages/quine-global-labs/rpm} + +# The token goes to curl in a file, not on its command line. +netrc=$(mktemp) +trap 'rm -f "$netrc"' EXIT +chmod 600 "$netrc" +printf 'machine %s login %s password %s\n' \ + "$(sed -E 's|^https?://([^/]+).*|\1|' <<<"$api")" "$REGISTRY_USER" "$REGISTRY_TOKEN" >"$netrc" + +upload() { # group rpm + local code + code=$(curl -sS -o /dev/null -w '%{http_code}' --retry 3 --netrc-file "$netrc" \ + --upload-file "$2" "$api/$1/upload") || code=000 + case $code in + 201) echo "new $1 ${2##*/}" ;; + 409) echo "had $1 ${2##*/}" ;; + *) echo "::warning::$code uploading ${2##*/} to $1" ;; + esac +} +export -f upload +export api netrc + +for dir in "$cache"/*/; do + id=$(basename "$dir") + id=${id%-*} # the hash libdnf5 appends + [[ $id == @* ]] && continue # @commandline: local files, not a repository + # copr:copr.fedorainfracloud.org:ublue-os:packages -> copr-ublue-os-packages + group=$(sed -E 's/^copr:[^:]+:/copr-/; s/:/-/g' <<<"$id") + find "$dir" -name '*.rpm' -printf "$group\0%p\0" +done | xargs -0 -n 2 -P 4 bash -c 'upload "$@"' _ | + tee /dev/stderr | awk '{n[$1]++} END {for (k in n) printf "%s: %d\n", k, n[k]}' diff --git a/.forgejo/workflows/rpm-mirror-test.yml b/.forgejo/workflows/rpm-mirror-test.yml new file mode 100644 index 00000000..1d104197 --- /dev/null +++ b/.forgejo/workflows/rpm-mirror-test.yml @@ -0,0 +1,36 @@ +name: RPM mirror test + +# Throwaway (branch rpm-mirror-test): uploads the last build's dnf cache to +# the forge's RPM registry and times it, then checks dnf can read a group. +on: + push: + branches: [rpm-mirror-test] + +jobs: + upload: + runs-on: runner-x86-linux + steps: + - uses: https://forge.quinefoundation.com/quine-global-labs/mirror-actions-checkout@v4 + + - name: Upload the dnf cache + env: + REGISTRY_USER: ${{ vars.REGISTRY_USER || github.actor }} + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + cache=$(dirname "$(ls -d /var/tmp/buildah-cache-0/*/fedora-* | head -1)") + echo "cache: $cache ($(du -sh "$cache" | cut -f1))" + start=$(date +%s) + .forgejo/upload-rpms.sh "$cache" + echo "took $(( $(date +%s) - start ))s" + + - name: dnf reads the groups + run: | + api=https://forge.quinefoundation.com/api/packages/quine-global-labs/rpm + sleep 30 # the registry rebuilds repodata after uploads + for g in fedora updates terra; do + curl -fsS -o /dev/null -w "$g repomd: %{http_code}\n" "$api/$g/repodata/repomd.xml" + done + podman run --rm registry.fedoraproject.org/fedora:latest \ + dnf -q repoquery --disablerepo='*' --repofrompath="f,$api/fedora" \ + --repofrompath="u,$api/updates" --setopt=f.gpgcheck=0 --setopt=u.gpgcheck=0 \ + --available | wc -l