#!/usr/bin/env bash # Stage a packaging tree at build/stage/ for nfpm consumption. # # Usage: packaging/stage.sh [VERSION] # # VERSION defaults to the version in pyproject.toml. # The staged tree contains: # /opt/fenris/vendor/ — bundled pure-Python application dependencies # /usr/bin/fenris — unprivileged wrapper # /usr/libexec/fenris/ — fenris-monitor, fenris-collect # /usr/lib/systemd/system/ — fenris-collect.{timer,service} # /usr/share/polkit-1/actions/ — polkit policy # /usr/lib/sysusers.d/fenris.conf # /usr/lib/tmpfiles.d/fenris.conf set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" STAGE_DIR="${REPO_ROOT}/build/stage" # --- Resolve version --- if [ -n "${1:-}" ]; then VERSION="$1" else VERSION="$(sed -n 's/^version = "\(.*\)"/\1/p' "${REPO_ROOT}/pyproject.toml")" fi if [ -z "${VERSION}" ]; then echo "Error: could not determine version" >&2 exit 1 fi echo "Staging fenris ${VERSION} ..." # --- Clean previous stage --- rm -rf "${STAGE_DIR}" mkdir -p "${STAGE_DIR}" # --- Use pre-built wheel from dist/ --- WHEEL=$(ls "${REPO_ROOT}"/dist/fenris-"${VERSION}"-*.whl 2>/dev/null | head -1) if [ -z "${WHEEL}" ]; then echo "Error: no wheel found in dist/ — run 'make dist/fenris-*.whl' first" >&2 exit 1 fi echo " Using wheel: $(basename "${WHEEL}")" # --- Vendor runtime packages without an interpreter --- # A copied Python binary contains an ABI and build-host dynamic-library path. # It fails after rolling-distribution Python upgrades (for example Tumbleweed # 3.12 -> 3.13). Fenris and its locked dependencies are pure Python, so place # them in a version-neutral directory and execute with the target's python3. echo " Installing version-neutral runtime packages ..." VENDOR_DIR="${STAGE_DIR}/opt/fenris/vendor" mkdir -p "${VENDOR_DIR}" python3 -m pip install --disable-pip-version-check --no-compile \ --target "${VENDOR_DIR}" -r "${REPO_ROOT}/requirements.txt" "${WHEEL}" # Package files must be importable by unprivileged Fenris users regardless of # the builder's umask. pip otherwise preserves a restrictive umask in the # vendored runtime, which makes the installed CLI fail before it can read the # observation store. chmod -R a+rX "${VENDOR_DIR}" # --- Inject version into wrapper from pyproject.toml --- # The wrapper has a hardcoded version string; patch it for packaging. WRAPPER_SRC="${REPO_ROOT}/scripts/fenris" WRAPPER_DST="${STAGE_DIR}/usr/bin/fenris" mkdir -p "$(dirname "${WRAPPER_DST}")" sed "s|version=\"%(prog)s [0-9.]*\"|version=\"%(prog)s ${VERSION}\"|g" \ "${WRAPPER_SRC}" > "${WRAPPER_DST}" chmod 0755 "${WRAPPER_DST}" # --- Privileged helpers --- echo " Installing helpers ..." mkdir -p "${STAGE_DIR}/usr/libexec/fenris" install -m 0755 "${REPO_ROOT}/src/fenris/monitor.py" "${STAGE_DIR}/usr/libexec/fenris/fenris-monitor" install -m 0755 "${REPO_ROOT}/src/fenris/collect.py" "${STAGE_DIR}/usr/libexec/fenris/fenris-collect" # --- systemd units (vendor placement) --- echo " Installing systemd units ..." mkdir -p "${STAGE_DIR}/usr/lib/systemd/system" install -m 0644 "${REPO_ROOT}/units/fenris-collect.timer" "${STAGE_DIR}/usr/lib/systemd/system/" install -m 0644 "${REPO_ROOT}/units/fenris-collect.service" "${STAGE_DIR}/usr/lib/systemd/system/" # --- runit service files --- echo " Installing runit service files ..." mkdir -p "${STAGE_DIR}/etc/sv/fenris-collect/log" install -m 0755 "${REPO_ROOT}/units/runit/fenris-collect/run" "${STAGE_DIR}/etc/sv/fenris-collect/run" install -m 0755 "${REPO_ROOT}/units/runit/fenris-collect/log/run" "${STAGE_DIR}/etc/sv/fenris-collect/log/run" # --- polkit policy --- echo " Installing polkit policy ..." mkdir -p "${STAGE_DIR}/usr/share/polkit-1/actions" install -m 0644 "${REPO_ROOT}/polkit/com.bongbetic.fenris.monitor.policy" \ "${STAGE_DIR}/usr/share/polkit-1/actions/" # --- sysusers and tmpfiles fragments --- echo " Installing sysusers/tmpfiles fragments ..." mkdir -p "${STAGE_DIR}/usr/lib/sysusers.d" install -m 0644 "${REPO_ROOT}/packaging/sysusers.d/fenris.conf" "${STAGE_DIR}/usr/lib/sysusers.d/" mkdir -p "${STAGE_DIR}/usr/lib/tmpfiles.d" install -m 0644 "${REPO_ROOT}/packaging/tmpfiles.d/fenris.conf" "${STAGE_DIR}/usr/lib/tmpfiles.d/" echo "Stage complete: ${STAGE_DIR}"