gen-pacman-repo: fix package layout for pacman 7 repo-add

Three bugs caught while smoke-testing against an existing
build.ArchR-RK3326.aarch64/install_pkg tree:

1. BUILD_DIR auto-detection glob did not include the trailing arch
   suffix, so build.ArchR-RK3326.aarch64 never matched. Now matches
   build.*-RK3326*aarch64*.

2. Version sanitization used `echo | tr -c '[charset]' '.'` which
   turns the trailing newline into a stray '.', producing versions
   like "1.0.8." that pacman refuses. Swapped to printf.

3. Package layout was wrong for pacman 7 repo-add:
   - .PKGINFO must be the FIRST entry in the tar (pacman streams it).
   - No "./" prefix on file names (matches makepkg output).
   - .PKGINFO needs `pkgbase` and `xdata = pkgtype=pkg` lines, not
     just `pkgname`.
   Rewrote the packing block to assemble an explicit file list with
   .PKGINFO first, then tar -T.

Also: install_pkg name extraction is more robust now — sed strips
both 40-char git hashes and semver suffixes to recover the real
package name, and the package.mk lookup uses find rather than
literal globbing so packages nested at any depth are found.

Smoke test confirms repo-add accepts the resulting archive, signs
archr.db with the configured signer, and emits the expected
symlinks archr.db -> archr.db.tar.gz.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Douglas Teles
2026-06-23 17:43:08 -03:00
parent 43e464525f
commit 41d376a029
+53 -15
View File
@@ -26,8 +26,8 @@
set -euo pipefail
BUILD_DIR="${BUILD_DIR:-$(ls -1dt build.*-RK3326 2>/dev/null | head -1)}"
[ -z "${BUILD_DIR:-}" ] && { echo "BUILD_DIR not set and no build.*-RK3326 found"; exit 2; }
BUILD_DIR="${BUILD_DIR:-$(ls -1dt build.*-RK3326*aarch64* 2>/dev/null | head -1)}"
[ -z "${BUILD_DIR:-}" ] && { echo "BUILD_DIR not set and no build.*-RK3326*aarch64* found"; exit 2; }
[ -d "${BUILD_DIR}/install_pkg" ] || { echo "no install_pkg/ under ${BUILD_DIR}"; exit 2; }
OUT_DIR="${OUT_DIR:-${BUILD_DIR}/../repo-out}"
@@ -46,32 +46,58 @@ echo "gen-pacman-repo: build=${BUILD_DIR} out=${OUT_DIR} channel=${CHANNEL} sign
build_one_pkg() {
local src="$1"
local name
name="$(basename "${src}")"
local dirname
dirname="$(basename "${src}")"
# Skip anything that is not an actually built package tree.
[ -d "${src}" ] || return 0
# Pull version from the package.mk if present; fallback to date.
local pkgmk version
pkgmk="projects/ArchR/packages/*/${name}/package.mk packages/*/${name}/package.mk"
# The install_pkg dir name is "<pkgname>-<version_or_githash>". Strip
# the trailing suffix to recover the package name; the suffix is
# either a 40-char git hash or starts with a digit (semver).
local name version
name="$(echo "${dirname}" | sed -E 's/-[0-9a-f]{40}$//; s/-[0-9].*$//')"
# Try to recover the exact PKG_VERSION from a matching package.mk
# under either the ArchR overlay or the top-level packages tree.
# Search any depth; multiple categories share the same package name
# in some cases, take the ArchR overlay first.
local pkgmk=""
pkgmk="$(find projects/ArchR/packages -mindepth 2 -maxdepth 6 \
-path "*/${name}/package.mk" -print -quit 2>/dev/null)"
if [ -z "${pkgmk}" ]; then
pkgmk="$(find packages -mindepth 2 -maxdepth 6 \
-path "*/${name}/package.mk" -print -quit 2>/dev/null)"
fi
version=""
for f in $(ls ${pkgmk} 2>/dev/null); do
version="$(awk -F'"' '/^PKG_VERSION/ {print $2; exit}' "${f}")"
[ -n "${version}" ] && break
done
if [ -n "${pkgmk}" ]; then
version="$(awk -F'"' '/^PKG_VERSION/ {print $2; exit}' "${pkgmk}")"
fi
# Fallback: pull the suffix back out of the dirname.
if [ -z "${version}" ]; then
version="${dirname#${name}-}"
fi
version="${version:-$(date +%Y%m%d)}"
# pacman version must match [a-zA-Z0-9.+_]+; drop unsupported chars.
version="$(echo "${version}" | tr -c 'a-zA-Z0-9.+_' '.')"
# pacman version must match [a-zA-Z0-9.+_]+. Long hashes are fine
# by this charset, but '/' or '~' would break: tr the rest. Use
# printf instead of echo to avoid the trailing newline being
# turned into a stray '.' by tr -c.
version="$(printf '%s' "${version}" | tr -c 'a-zA-Z0-9.+_' '.')"
local pkgrel=1
local outfile="${OUT_DIR}/${name}-${version}-${pkgrel}-${ARCH}.pkg.tar.zst"
# .PKGINFO sidecar that pacman reads on install.
# .PKGINFO sidecar that pacman reads on install. pkgbase is
# required by repo-add (pacman 7+); xdata pkgtype=pkg matches
# makepkg output so clients treat us as a normal split-package.
local pkginfo="${src}/.PKGINFO"
cat >"${pkginfo}" <<EOF
# Generated by gen-pacman-repo
pkgname = ${name}
pkgbase = ${name}
xdata = pkgtype=pkg
pkgver = ${version}-${pkgrel}
pkgdesc = ArchR ${name} (channel: ${CHANNEL})
url = https://arch-r.io
@@ -82,7 +108,19 @@ arch = ${ARCH}
license = GPL
EOF
(cd "${src}" && tar --zstd -cf "${outfile}" --owner=0 --group=0 . )
# Pack with .PKGINFO as the FIRST tar entry; pacman/repo-add stream
# the archive and need .PKGINFO up front to validate. Drop the "./"
# prefix so listings match what makepkg produces.
(
cd "${src}"
filelist="$(mktemp)"
{
echo ".PKGINFO"
find . -mindepth 1 -maxdepth 1 -not -name '.PKGINFO' -printf '%P\n'
} > "${filelist}"
tar --zstd -cf "${outfile}" --owner=0 --group=0 -T "${filelist}"
rm -f "${filelist}"
)
rm -f "${pkginfo}"
if [ -n "${SIGNER}" ]; then