pkg repo shenanigans
Tuesday, 10 Jun 2025
FreeBSD’s poudriere(8) tool is tightly integrated with the pkg(8) repository system, which is used to manage packages on FreeBSD systems.
This post is a stub, so I can at least share the snippets I mentioned in our last jails WG call.
Bryan Drewery wrote a gist outlining how he uses poudriere hooks to sync a locally build repository up to an S3 bucket, webserver, or NFS share.
This can be combined with pkg-base
tooling, which is a Makefile target
to the FreeBSD build system, that creates a repository of packages that,
together, comprise the equivalent of base.txz
, kernel.txz
, and similar
files, used to install FreeBSD systems.
These packages can be used to install a FreeBSD system, but at a more granular level, allowing you to install only the packages you need. The base system packages are then copied back into the same directory that poudriere uses to store its packages, and they are then incorporated and signed as part of the repository.
We use the [net/s5cmd] tool for syncing the packages to S3, as it is significantly faster than the default aws tool kit.
#!/bin/sh
# /usr/local/etc/poudriere.d/hooks/pkgrepo.sh
# PACKAGES PKG_REPO_SIGNING_KEY PKG_REPO_FROM_HOST PKG_REPO_META_FILE
[ -f "${POUDRIERED}/hooks/config" ] && . "${POUDRIERED}/hooks/config"
fetch_custom_packages() {
local indie=$(pkg info -f -F ${PACKAGES}/Latest/pkg.pkg | awk '$1 == "Architecture" {print $3}' | sed -e 's/FreeBSD/indie/')
[ "${FETCH_PKG_FROM_S3:-0}" -eq 1 ] || return 0
/usr/local/bin/s5cmd \
--endpoint-url ${S3_ENDPOINT_URL} \
--credentials-file ${S3_CREDENTIALS_FILE} \
--profile ${S3_PROFILE} \
sync s3://pkg/${indie}/\*.pkg ${PACKAGES}/All/
# ignore errors if there are no packages because indie:15:amd64/ "dir" is not present
return 0
}
status="$1"
shift
case ${status} in
"sign")
fetch_custom_packages "$@"
;;
esac
exit 0
#!/bin/sh
# /usr/local/etc/poudriere.d/hooks/bulk.sh
[ -f "${POUDRIERED}/hooks/config" ] && . "${POUDRIERED}/hooks/config"
bulk_sync() {
local arch=$(pkg info -f -F ${PACKAGES}/Latest/pkg.pkg | awk '$1 == "Architecture" {print $3}')
curl ${NTFY_URL} -d "$(hostname -s) ${arch} built $1 failed $2 ignored $3 skipped $4"
[ "${SHOULD_SYNC_TO_S3:-0}" -eq 1 ] || return 0
touch ${PACKAGES}/.commitid
(cd /usr/ports && git rev-parse HEAD > ${PACKAGES}/.commitid)
(cd ${PACKAGES} && s5cmd \
--endpoint-url ${S3_ENDPOINT_URL} \
--credentials-file ${S3_CREDENTIALS_FILE} \
--profile ${S3_PROFILE} \
sync --delete \
--include 'All/*.pkg' \
--include 'Latest/pkg.*' \
--include .buildname \
--include .commitid \
--include .jailversion \
--include data.pkg \
--include meta.conf \
--include packagesite.pkg \
--no-follow-symlinks \
. \
s3://pkg/${arch}/ )
return 0
}
status="$1"
shift
case ${status} in
"done")
test $2 -le 0 && bulk_sync "$@"
;;
esac
exit 0