136 lines
5.7 KiB
Bash
136 lines
5.7 KiB
Bash
#!/bin/bash
|
|||
|
|
## pkg-cache-repos.sh — BUILD-TIME ONLY, OPT-IN. Points dnf/apt at the internal
|
||
|
|
## package cache (nginx proxy_cache, CT130 "pkg-cache" on the Proxmox cluster)
|
||
|
|
## when PKG_CACHE is set; a no-op otherwise, so builds behave exactly as before
|
||
|
|
## without it.
|
||
|
|
##
|
||
|
|
## PKG_CACHE=http://192.168.1.40 pkg-cache-repos.sh rpm # AlmaLinux/EPEL/Remi
|
||
|
|
## PKG_CACHE=http://192.168.1.40 pkg-cache-repos.sh apt # Ubuntu + LiteSpeed
|
||
|
|
## pkg-cache-repos.sh release-urls # prints EPEL+Remi release RPM URLs
|
||
|
|
## pkg-cache-repos.sh restore # put the original repo files back
|
||
|
|
##
|
||
|
|
## Every RUN that rewrites must `restore` before it ends, so no shipped layer
|
||
|
|
## carries the cache's LAN address in /etc/yum.repos.d or /etc/apt (images run on
|
||
|
|
## hosts that cannot reach it). restore is a no-op when nothing was rewritten.
|
||
|
|
##
|
||
|
|
## Why: on 2026-10-21 (PHP security release) builds failed on Remi mirrors lagging
|
||
|
|
## hours behind origin, Remi's origin timing out over HTTPS, and an EPEL mirror
|
||
|
|
## with a broken certificate. The cache fetches from the ORIGINS over HTTPS (with
|
||
|
|
## origin/mirror fallbacks and stale-on-error), keeps metadata only ~3 minutes,
|
||
|
|
## and keeps immutable .rpm/.deb files long-term.
|
||
|
|
##
|
||
|
|
## Integrity is unchanged: dnf/apt still verify package GPG signatures (and apt
|
||
|
|
## the signed InRelease/Release.gpg); the build's php.net version gates
|
||
|
|
## (EXPECT_PHP_MIN / EXPECT_PHP_VERSION) still fail a build that gets old PHP.
|
||
|
|
##
|
||
|
|
## rpm: each rewritten baseurl keeps the upstream origin as a SECOND url, so if
|
||
|
|
## the cache dies mid-build dnf fails over to the origin by itself.
|
||
|
|
## apt: apt has no per-source failover; CI only sets PKG_CACHE after probing the
|
||
|
|
## cache, and a build without PKG_CACHE uses the upstream sources.
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
MODE="${1:?usage: pkg-cache-repos.sh rpm|apt|release-urls|restore}"
|
||
|
|
STATE=/var/lib/pkg-cache-repos # pristine copies of every file we rewrite
|
||
|
|
|
||
|
|
if [ "$MODE" = restore ]; then
|
||
|
|
[ -d "$STATE" ] || exit 0
|
||
|
|
(cd "$STATE" && find . -type f) | while read -r rel; do
|
||
|
|
cat "$STATE/$rel" > "/${rel#./}"
|
||
|
|
done
|
||
|
|
rm -rf "$STATE"
|
||
|
|
echo "pkg-cache-repos: original repository files restored"
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Keep the first-seen (pre-rewrite) copy of a file; later calls in the same RUN
|
||
|
|
# never overwrite it.
|
||
|
|
save() {
|
||
|
|
[ -e "$STATE$1" ] && return 0
|
||
|
|
mkdir -p "$STATE$(dirname "$1")"
|
||
|
|
cp -p "$1" "$STATE$1"
|
||
|
|
}
|
||
|
|
C="${PKG_CACHE:-}"
|
||
|
|
C="${C%/}"
|
||
|
|
|
||
|
|
if [ "$MODE" = release-urls ]; then
|
||
|
|
if [ -n "$C" ]; then
|
||
|
|
echo "$C/epel/epel-release-latest-10.noarch.rpm $C/remi/enterprise/remi-release-10.rpm"
|
||
|
|
else
|
||
|
|
echo "https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm https://rpms.remirepo.net/enterprise/remi-release-10.rpm"
|
||
|
|
fi
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [ -z "$C" ]; then
|
||
|
|
echo "pkg-cache-repos($MODE): PKG_CACHE not set - using upstream repositories"
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
case "$C" in
|
||
|
|
http://*|https://*) ;;
|
||
|
|
*) echo "FATAL(pkg-cache-repos): PKG_CACHE must be an http(s) URL, got '$C'" >&2; exit 1 ;;
|
||
|
|
esac
|
||
|
|
|
||
|
|
rewrite_rpm() {
|
||
|
|
local f="$1"
|
||
|
|
grep -q -E '^#? ?baseurl=https?://(repo\.almalinux\.org|download\.example|rpms\.remirepo\.net)/' "$f" || return 0
|
||
|
|
save "$f"
|
||
|
|
# Per [section]: a (commented or live) baseurl on a known origin becomes
|
||
|
|
# "baseurl=<cache>/<prefix>/<path> <origin>/<path>", and that section's
|
||
|
|
# mirrorlist/metalink is commented out (dnf prefers them over baseurl).
|
||
|
|
# Sections without a known origin (vault debug/source, ...) are untouched.
|
||
|
|
awk -v C="$C" '
|
||
|
|
function flush( i) {
|
||
|
|
for (i = 1; i <= n; i++) {
|
||
|
|
if (hit && buf[i] ~ /^(mirrorlist|metalink)=/) buf[i] = "#" buf[i]
|
||
|
|
print buf[i]
|
||
|
|
}
|
||
|
|
n = 0; hit = 0
|
||
|
|
}
|
||
|
|
function rw(line, re, prefix, origin, p) {
|
||
|
|
if (match(line, re)) {
|
||
|
|
p = substr(line, RSTART + RLENGTH); sub(/[ \t].*$/, "", p)
|
||
|
|
hit = 1
|
||
|
|
return "baseurl=" C "/" prefix "/" p " " origin "/" p
|
||
|
|
}
|
||
|
|
return line
|
||
|
|
}
|
||
|
|
/^\[/ { flush() }
|
||
|
|
{
|
||
|
|
l = $0
|
||
|
|
if (l ~ /^#? ?baseurl=/) {
|
||
|
|
l = rw(l, "^#? ?baseurl=https?://repo\\.almalinux\\.org/almalinux/", "almalinux", "https://repo.almalinux.org/almalinux")
|
||
|
|
l = rw(l, "^#? ?baseurl=https?://download\\.example/pub/epel/", "epel", "https://dl.fedoraproject.org/pub/epel")
|
||
|
|
l = rw(l, "^#? ?baseurl=https?://rpms\\.remirepo\\.net/", "remi", "https://rpms.remirepo.net")
|
||
|
|
}
|
||
|
|
buf[++n] = l
|
||
|
|
}
|
||
|
|
END { flush() }
|
||
|
|
' "$f" > "$f.pkgcache" && cat "$f.pkgcache" > "$f" && rm -f "$f.pkgcache"
|
||
|
|
}
|
||
|
|
|
||
|
|
rewrite_apt() {
|
||
|
|
local f="$1"
|
||
|
|
grep -q -E 'https?://([a-z]{2}\.)?(archive|security)\.ubuntu\.com/|https?://rpms\.litespeedtech\.com/' "$f" || return 0
|
||
|
|
save "$f"
|
||
|
|
sed -i -E \
|
||
|
|
-e "s%https?://(archive|[a-z]{2}\.archive)\.ubuntu\.com/ubuntu/?%$C/ubuntu/%g" \
|
||
|
|
-e "s%https?://security\.ubuntu\.com/ubuntu/?%$C/ubuntu-security/%g" \
|
||
|
|
-e "s%https?://rpms\.litespeedtech\.com/%$C/litespeed/%g" \
|
||
|
|
"$f"
|
||
|
|
}
|
||
|
|
|
||
|
|
case "$MODE" in
|
||
|
|
rpm)
|
||
|
|
for f in /etc/yum.repos.d/*.repo; do [ -f "$f" ] && rewrite_rpm "$f"; done
|
||
|
|
echo "pkg-cache-repos(rpm): repos now via $C:"
|
||
|
|
grep -h '^baseurl=' /etc/yum.repos.d/*.repo | grep -F "$C/" | sort -u | sed 's/^/ /'
|
||
|
|
;;
|
||
|
|
apt)
|
||
|
|
for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do
|
||
|
|
[ -f "$f" ] && rewrite_apt "$f"
|
||
|
|
done
|
||
|
|
echo "pkg-cache-repos(apt): sources now via $C:"
|
||
|
|
grep -h -E '^(deb|URIs:)' /etc/apt/sources.list /etc/apt/sources.list.d/* 2>/dev/null | grep -F "$C/" | sort -u | sed 's/^/ /'
|
||
|
|
;;
|
||
|
|
*) echo "FATAL(pkg-cache-repos): unknown mode '$MODE'" >&2; exit 1 ;;
|
||
|
|
esac
|