Random Musings

O for a muse of fire, that would ascend the brightest heaven of invention!


pkg repo shenanigans

Tuesday, 10 Jun 2025 Tags: freebsdpoudriere

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