#!/bin/bash # ============================================================================= # scripts/lib/slackbuild-common.sh # # Shared helper functions sourced by every packages/*/*.SlackBuild script. # Centralizing this logic means each individual SlackBuild only has to # describe *how to compile* its component — fetching, checksum verification, # and final .txz packaging are implemented once, here, and used the same way # by all seven packages. This is what keeps the seven build scripts # consistent and short instead of each reinventing (and potentially # forgetting) checksum verification or Slackware package metadata. # # Every SlackBuild is expected to: # 1. `. "$(dirname "$0")/../../scripts/lib/slackbuild-common.sh"` # 2. `. "$(dirname "$0")/../../versions.env"` # 3. Call sb_init, sb_fetch_and_verify, do its own compile steps into # $PKG, then call sb_make_package. # # Not meant to be run directly. # ============================================================================= set -eu # ----------------------------------------------------------------------------- # sb_init # # Sets up the standard SlackBuild working directories and exports the # variables every subsequent helper (and the calling SlackBuild) relies on: # CWD - directory the SlackBuild itself lives in (packages//) # TMP - scratch/build directory (source is extracted and compiled here) # PKG - staging directory that becomes the .txz payload # OUTPUT - where the finished .txz + checksum files are written # All three of TMP/PKG/OUTPUT are safe to delete/recreate; nothing outside # of them is ever touched, and nothing under them is ever committed to git # (see .gitignore: packages/**/src, packages/**/pkg, packages/**/work). # ----------------------------------------------------------------------------- sb_init() { local pkg_name="$1" PRGNAM="$pkg_name" CWD="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)" TMP="${TMP:-$CWD/work}" PKG="${PKG:-$TMP/package-$PRGNAM}" OUTPUT="${OUTPUT:-$CWD/../../dist}" export PRGNAM CWD TMP PKG OUTPUT rm -rf "$TMP" mkdir -p "$TMP" "$PKG" "$OUTPUT" echo "==> [$PRGNAM] TMP=$TMP" echo "==> [$PRGNAM] PKG=$PKG" echo "==> [$PRGNAM] OUTPUT=$OUTPUT" } # ----------------------------------------------------------------------------- # sb_fetch_and_verify # # Downloads a source tarball into $TMP and verifies it against the SHA256 # pinned in versions.env before anything is extracted or built. Aborts the # build loudly on any mismatch — a checksum mismatch means either # versions.env is stale (a legitimate new upstream release) or the source is # not what it claims to be; either way, an unreviewed build must not proceed. # ----------------------------------------------------------------------------- sb_fetch_and_verify() { local url="$1" local expected_sha256="$2" local dest_name="$3" local dest_path="$TMP/$dest_name" # All progress/diagnostic output here must go to stderr, not stdout: # callers capture this function's return value via `tarball=$(sb_fetch_and_verify ...)`, # and command substitution captures everything written to stdout — a # stray stdout echo above the final `echo "$dest_path"` would get # concatenated into that captured value instead of just printing to the # log. echo "==> [$PRGNAM] Fetching $url" >&2 curl -fL --retry 3 --retry-delay 2 -o "$dest_path" "$url" local actual_sha256 actual_sha256=$(sha256sum "$dest_path" | awk '{print $1}') if [ "$actual_sha256" != "$expected_sha256" ]; then echo "!! [$PRGNAM] SHA256 MISMATCH for $dest_name" >&2 echo "!! expected: $expected_sha256" >&2 echo "!! actual: $actual_sha256" >&2 echo "!! Refusing to build against unverified source. If upstream" >&2 echo "!! genuinely released a new version, update versions.env via" >&2 echo "!! scripts/update-versions.sh instead of editing the hash by hand." >&2 exit 1 fi echo "==> [$PRGNAM] SHA256 verified ($actual_sha256)" >&2 echo "$dest_path" } # ----------------------------------------------------------------------------- # sb_extract [strip-components] # # Extracts a verified tarball into $TMP/src, normalizing away the # "-/" wrapper directory GitHub/cgit archives always contain, # so every SlackBuild can `cd "$TMP/src"` regardless of upstream's archive # layout. # ----------------------------------------------------------------------------- sb_extract() { local tarball="$1" local strip="${2:-1}" mkdir -p "$TMP/src" tar -xf "$tarball" -C "$TMP/src" --strip-components="$strip" echo "$TMP/src" } # ----------------------------------------------------------------------------- # sb_install_docs [readme-file] # # Installs upstream's license (and optionally README) into the standard # Slackware package documentation location, plus this project's own build # metadata, so `installpkg` output and /usr/doc/-/ are # populated per Slackware convention. # ----------------------------------------------------------------------------- sb_install_docs() { local license_file="$1" local readme_file="${2:-}" local docdir="$PKG/usr/doc/$PRGNAM-$VERSION" mkdir -p "$docdir" [ -f "$license_file" ] && cp "$license_file" "$docdir/" [ -n "$readme_file" ] && [ -f "$readme_file" ] && cp "$readme_file" "$docdir/" { echo "Built by unraid-podman from upstream source." echo "Package: $PRGNAM $VERSION" echo "Built: $(date -u +%Y-%m-%dT%H:%M:%SZ)" } > "$docdir/unraid-podman.build-info" } # ----------------------------------------------------------------------------- # sb_make_package # # Finalizes the Slackware package: installs slack-desc + doinst.sh (if # present) into $PKG/install/, strips binaries, sets root:root ownership, # runs makepkg to produce the .txz, then writes SHA256 + MD5 sidecar files # next to it. # # - SHA256 is used by scripts/build-packages.sh / CI to verify build # artifacts between jobs. # - MD5 is additionally generated because Unraid's .plg mechanism # verifies downloads via MD5 by convention (see # docs/ARCHITECTURE.md section 3.2) — scripts/release.sh reads the .md5 # file to populate plugin/podman.plg's entities. # # Produces: $OUTPUT/---.txz (+ .sha256, .md5) # ----------------------------------------------------------------------------- sb_make_package() { local version="$1" local arch="$2" local build="$3" local tag="$4" mkdir -p "$PKG/install" if [ -f "$CWD/slack-desc" ]; then cp "$CWD/slack-desc" "$PKG/install/slack-desc" else echo "!! [$PRGNAM] missing packages/$PRGNAM/slack-desc" >&2 exit 1 fi [ -f "$CWD/doinst.sh" ] && cp "$CWD/doinst.sh" "$PKG/install/doinst.sh" # Strip debug symbols where possible to keep package size down; ignore # failures (e.g. static/stripped-already binaries, non-ELF files). find "$PKG" -type f \( -perm -u+x -o -name '*.so*' \) -exec sh -c \ 'file "$1" | grep -q ELF && strip --strip-unneeded "$1" 2>/dev/null || true' _ {} \; local pkg_file="$PRGNAM-$version-$arch-$build$tag.txz" ( cd "$PKG" && makepkg --linkadd y --chown y "$OUTPUT/$pkg_file" ) ( cd "$OUTPUT" && sha256sum "$pkg_file" > "$pkg_file.sha256" ) ( cd "$OUTPUT" && md5sum "$pkg_file" > "$pkg_file.md5" ) echo "==> [$PRGNAM] built $OUTPUT/$pkg_file" }