195 lines
6.4 KiB
Bash
Executable File
195 lines
6.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
|
||
set -euo pipefail
|
||
shopt -s nullglob
|
||
|
||
# ---- Configurable Variables ----
|
||
repoDir="/var/www/packages.stormux.org"
|
||
keyId="52ADA49000F1FF0456F8AEEFB4CDE1CD56EF8E82"
|
||
repoName="stormux"
|
||
dbName="${repoName}.db.tar.gz"
|
||
filesName="${repoName}.files.tar.gz"
|
||
rebuildDb="${REBUILD_DB:-false}"
|
||
|
||
require_cmd() {
|
||
local cmd="$1"
|
||
|
||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||
echo "❌ Required command not found: $cmd"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# ---- Safety Checks ----
|
||
if [[ ! -d "$repoDir" ]]; then
|
||
echo "❌ Repo dir does not exist: $repoDir"
|
||
exit 1
|
||
fi
|
||
|
||
require_cmd "gpg"
|
||
require_cmd "repo-add"
|
||
require_cmd "repo-remove"
|
||
|
||
# ---- Create Architecture Directories ----
|
||
mkdir -p "$repoDir/x86_64" "$repoDir/aarch64"
|
||
|
||
# ---- Process Each Architecture ----
|
||
process_arch() {
|
||
local arch="$1"
|
||
local archDir="$repoDir/$arch"
|
||
local pkgFiles=()
|
||
local selectedPkgFiles=()
|
||
local repoAddArgs=()
|
||
local -A currentPkgNames=()
|
||
local -A newestPkgByName=()
|
||
local repoPkgNames=()
|
||
local dbFile="$dbName"
|
||
local filesFile="$filesName"
|
||
local dbSig="${dbFile}.sig"
|
||
local filesSig="${filesFile}.sig"
|
||
local dbLink="${repoName}.db"
|
||
local filesLink="${repoName}.files"
|
||
|
||
echo "🏗️ Processing $arch packages..."
|
||
|
||
# Enter arch directory (packages should already be sorted by update.sh)
|
||
cd "$archDir" || return 1
|
||
|
||
# Select only the newest archive for each package name. repo-add cannot
|
||
# safely consume multiple versions of the same package in a single run.
|
||
pkgFiles=( *.pkg.tar.zst *.pkg.tar.xz )
|
||
for pkg in "${pkgFiles[@]}"; do
|
||
local pkgName pkgVersion existingPkg existingVersion
|
||
pkgName="$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgname = //p' | head -n1)"
|
||
pkgVersion="$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgver = //p' | head -n1)-$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgrel = //p' | head -n1)"
|
||
|
||
if [[ -z "$pkgName" || -z "$pkgVersion" ]]; then
|
||
echo "❌ Unable to determine package metadata for $pkg"
|
||
cd "$repoDir" || exit 1
|
||
return 1
|
||
fi
|
||
|
||
existingPkg="${currentPkgNames[$pkgName]:-}"
|
||
if [[ -z "$existingPkg" ]]; then
|
||
currentPkgNames["$pkgName"]="$pkg"
|
||
else
|
||
existingVersion="$(bsdtar -xOqf "$existingPkg" .PKGINFO | sed -n 's/^pkgver = //p' | head -n1)-$(bsdtar -xOqf "$existingPkg" .PKGINFO | sed -n 's/^pkgrel = //p' | head -n1)"
|
||
if (( $(vercmp "$pkgVersion" "$existingVersion") > 0 )); then
|
||
currentPkgNames["$pkgName"]="$pkg"
|
||
fi
|
||
fi
|
||
done
|
||
|
||
for pkgName in "${!currentPkgNames[@]}"; do
|
||
newestPkgByName["$pkgName"]="${currentPkgNames[$pkgName]}"
|
||
selectedPkgFiles+=( "${currentPkgNames[$pkgName]}" )
|
||
done
|
||
|
||
pkgFiles=( "${selectedPkgFiles[@]}" )
|
||
|
||
# Sign all unsigned selected packages
|
||
echo "🔏 Signing $arch packages..."
|
||
for pkg in "${pkgFiles[@]}"; do
|
||
if [[ ! -f "$pkg.sig" ]]; then
|
||
echo " 📝 Signing $pkg"
|
||
gpg --default-key "$keyId" --detach-sign "$pkg"
|
||
else
|
||
echo " ✅ $pkg already signed"
|
||
fi
|
||
done
|
||
|
||
# Track which package names should remain in the repo after this run.
|
||
for pkg in "${pkgFiles[@]}"; do
|
||
local pkgName
|
||
pkgName="$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgname = //p' | head -n1)"
|
||
if [[ -n "$pkgName" ]]; then
|
||
currentPkgNames["$pkgName"]=1
|
||
else
|
||
echo "❌ Unable to determine package name for $pkg"
|
||
cd "$repoDir" || exit 1
|
||
return 1
|
||
fi
|
||
done
|
||
|
||
# Rebuild database for this architecture
|
||
if [[ "$rebuildDb" == "true" ]]; then
|
||
echo "🗃️ Rebuilding $arch repo database..."
|
||
rm -f "$dbFile" "$dbSig" "$filesFile" "$filesSig" "$dbLink" "$filesLink"
|
||
elif [[ -f "$dbFile" ]]; then
|
||
echo "🗃️ Updating $arch repo database..."
|
||
else
|
||
echo "🆕 Creating new $arch repo database..."
|
||
fi
|
||
|
||
# Remove packages that still exist in the repo database but are no longer
|
||
# present in the current directory. repo-remove with --remove also deletes
|
||
# the matching package archive and detached signature from disk.
|
||
if [[ -f "$dbFile" ]]; then
|
||
mapfile -t repoPkgNames < <(
|
||
bsdtar -tf "$dbFile" |
|
||
awk -F/ 'NF == 2 && $2 == "desc" {print $1}' |
|
||
while read -r entry; do
|
||
bsdtar -xOf "$dbFile" "${entry}/desc" |
|
||
awk 'found {print; exit} /^%NAME%$/ {found=1}'
|
||
done |
|
||
sort -u
|
||
)
|
||
|
||
for pkgName in "${repoPkgNames[@]}"; do
|
||
if [[ -z "${currentPkgNames[$pkgName]:-}" ]]; then
|
||
echo "🧹 Removing stale repo package $pkgName"
|
||
repo-remove --sign --key "$keyId" --remove "$dbFile" "$pkgName"
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# Only run repo-add if there are packages
|
||
if ((${#pkgFiles[@]} > 0)); then
|
||
repoAddArgs=(--sign --key "$keyId" --remove)
|
||
if [[ "$rebuildDb" != "true" && -f "$dbFile" ]]; then
|
||
repoAddArgs+=(--verify)
|
||
fi
|
||
|
||
repo-add "${repoAddArgs[@]}" "$dbFile" "${pkgFiles[@]}"
|
||
|
||
if [[ ! -f "$dbFile" ]]; then
|
||
echo "❌ repo-add did not create $dbFile"
|
||
cd "$repoDir" || exit 1
|
||
return 1
|
||
fi
|
||
|
||
if [[ ! -e "$dbLink" ]]; then
|
||
ln -s "$dbFile" "$dbLink"
|
||
fi
|
||
|
||
if [[ -f "$filesFile" && ! -e "$filesLink" ]]; then
|
||
ln -s "$filesFile" "$filesLink"
|
||
fi
|
||
|
||
echo "✅ $arch repo updated successfully"
|
||
else
|
||
echo "ℹ️ No $arch packages found"
|
||
fi
|
||
|
||
# Remove orphaned package archives and detached signatures that are not part
|
||
# of the current package set. This keeps the on-disk repo contents aligned
|
||
# with the package database after rebuilds and package removals.
|
||
for pkg in *.pkg.tar.zst *.pkg.tar.xz; do
|
||
local pkgName
|
||
pkgName="$(bsdtar -xOqf "$pkg" .PKGINFO | sed -n 's/^pkgname = //p' | head -n1)"
|
||
if [[ -z "${newestPkgByName[$pkgName]:-}" || "${newestPkgByName[$pkgName]}" != "$pkg" ]]; then
|
||
echo "🧹 Removing orphaned package file $pkg"
|
||
rm -f "$pkg" "$pkg.sig"
|
||
fi
|
||
done
|
||
|
||
cd "$repoDir" || exit
|
||
}
|
||
|
||
# ---- Process Both Architectures ----
|
||
process_arch "x86_64"
|
||
process_arch "aarch64"
|
||
|
||
# ---- Done ----
|
||
echo "✅ All repositories updated and signed successfully."
|