# .build.yml # # SourceHut build manifest for YAMS (single Linux target). # Key points: # - Compute version from Git ref (GIT_REF) or release channel (RELEASE_CHANNEL) at runtime; no manifest expressions. # - Persist computed version into ~/.buildenv for subsequent tasks. # - Add static build tags for search/badges. # - Gate packaging steps so they run for tag builds and for nightly/weekly channels. # - Install Conan via pipx (or venv fallback), since Debian doesn't provide python3-conan. image: debian/trixie secrets: - 46f739e5-4538-45dd-a79f-bf173b7a2ed9 sources: - https://git.sr.ht/~trevon/yams # Static metadata for search and badges (unrelated to Git tags) tags: - linux - release - cmake - conan - yams - nightly - weekly environment: # Define consistent directories (setup.sh uses build/release for Release builds). BUILD_DIR: build/release STAGE_DIR: stage # relative to BUILD_DIR (Meson --destdir uses builddir as base) # Optional: set this to "nightly" or "weekly" via scheduler/env to produce # date/week-based releases on non-tag builds. # RELEASE_CHANNEL: packages: # Build dependencies (Debian/apt) - build-essential # gcc, make, etc. - cmake - meson - ninja-build - zip - ccache - dpkg-dev - fakeroot - rpm - lld - clang - llvm - python3 - python3-pip - python3-venv - pipx - git - libncurses-dev - libtinfo-dev - pkg-config - libboost-all-dev - liburing-dev # enables io_uring async path instead of fallback - libarchive-dev # enables archive extraction features - libacl1-dev # required for libarchive ACL support - libtag1-dev # enables taglib (audio metadata) detection - libsqlite3-dev # enables SQLite database support - libssl-dev - libcurl4-gnutls-dev # use gnutls variant; required by libmediainfo-dev (conflicts with openssl variant) - libsqlite3-dev - libncurses-dev - protobuf-compiler - libprotobuf-dev - libmediainfo-dev # enables MediaInfo-based video metadata extraction - mediainfo # MediaInfo CLI tool used at runtime for JSON output - xz-utils # for extracting Zig tarball tasks: # Determine version from the Git ref and persist to ~/.buildenv for later tasks. - compute_version: | set -e # Detect repository root (sr.ht often checks out into ./yams). Support Meson or CMake projects. if [ -d yams ] && { [ -f yams/meson.build ] || [ -f yams/CMakeLists.txt ]; }; then REPO_DIR="yams" else REPO_DIR="." fi cd "${REPO_DIR}" CHANNEL="${RELEASE_CHANNEL:-}" # Auto-channelize main branch builds as nightly when not tagged if [[ -z "${CHANNEL}" && "${GIT_REF:-}" == "refs/heads/main" ]]; then CHANNEL="nightly" export RELEASE_CHANNEL="nightly" # Persist for subsequent tasks which may source this echo "RELEASE_CHANNEL=nightly" >> ~/.buildenv fi # Determine numeric base version from latest tag (strip leading v), fallback to 0.0.0 RAW_TAG_NUMERIC="$(git describe --tags --abbrev=0 2>/dev/null || echo 0.0.0)" BASE_NUMERIC_VERSION="${RAW_TAG_NUMERIC#v}" if [ "$CHANNEL" = "nightly" ]; then CLEAN_VERSION_DISPLAY="nightly-$(date -u +%Y%m%d)" CLEAN_VERSION_CMAKE="${BASE_NUMERIC_VERSION}" elif [ "$CHANNEL" = "weekly" ]; then CLEAN_VERSION_DISPLAY="weekly-$(date -u +%G)w$(date -u +%V)" CLEAN_VERSION_CMAKE="${BASE_NUMERIC_VERSION}" else # Prefer tag-triggered builds; otherwise use last tag as numeric if [[ "${GIT_REF:-}" =~ ^refs/tags/ ]]; then RAW_TAG="${GIT_REF#refs/tags/}" CLEAN_VERSION_DISPLAY="${RAW_TAG#v}" CLEAN_VERSION_CMAKE="${RAW_TAG#v}" else CLEAN_VERSION_DISPLAY="${BASE_NUMERIC_VERSION}" CLEAN_VERSION_CMAKE="${BASE_NUMERIC_VERSION}" fi fi # Persist for subsequent tasks echo "YAMS_VERSION=${CLEAN_VERSION_DISPLAY}" >> ~/.buildenv echo "YAMS_VERSION_CMAKE=${CLEAN_VERSION_CMAKE}" >> ~/.buildenv echo "Computed YAMS_VERSION(display)=${CLEAN_VERSION_DISPLAY}, YAMS_VERSION_CMAKE=${CLEAN_VERSION_CMAKE} (GIT_REF=${GIT_REF:-n/a}, RELEASE_CHANNEL=${CHANNEL:-n/a})" - install_zig: | set -e # Install Zig 0.15.2 stable for zyp PDF plugin ARCH=$(uname -m) case "$ARCH" in x86_64) ZIG_ARCH="x86_64" ;; aarch64) ZIG_ARCH="aarch64" ;; *) echo "Unsupported architecture: $ARCH"; exit 1 ;; esac ZIG_VERSION="0.15.2" curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-${ZIG_ARCH}-linux-${ZIG_VERSION}.tar.xz" -o /tmp/zig.tar.xz sudo tar -xJf /tmp/zig.tar.xz -C /opt sudo mv /opt/zig-${ZIG_ARCH}-linux-${ZIG_VERSION} /opt/zig sudo ln -sf /opt/zig/zig /usr/local/bin/zig rm /tmp/zig.tar.xz zig version echo "PATH=/opt/zig:${PATH}" >> ~/.buildenv - setup: | set -e # Ensure pipx/venv/pip path is prepared export PATH="${HOME}/.local/bin:${PATH}" # Configure git identity and signing key (requested) git config --global user.name "Trevon" || true git config --global user.email "git@trevon.dev" || true git config --global user.signingkey "C1E8284DAE319BA313FCB40038686EA797D7A8A7" || true # Note: actual signed commits/tags require the private key in the agent; we only set identity here. # Configure ccache (optional acceleration) export CCACHE_DIR="${HOME}/.cache/ccache" mkdir -p "${CCACHE_DIR}" echo "CCACHE_DIR=${CCACHE_DIR}" >> ~/.buildenv if command -v ccache >/dev/null 2>&1; then ccache --set-config=max_size=2G || true ccache --zero-stats || true ccache -s || true fi # Install Conan via pipx when available; otherwise fallback to user pip or an isolated venv if ! command -v conan >/dev/null 2>&1; then if command -v pipx >/dev/null 2>&1; then pipx install 'conan<3' --pip-args='--upgrade' || true fi fi if ! command -v conan >/dev/null 2>&1; then python3 -m pip install --user --upgrade 'conan<3' || true hash -r fi if ! command -v conan >/dev/null 2>&1; then python3 -m venv /opt/conan . /opt/conan/bin/activate python -m pip install --upgrade pip setuptools wheel python -m pip install 'conan<3' export PATH="/opt/conan/bin:${PATH}" hash -r fi # Persist Conan PATH and CPU count for subsequent tasks and fail fast if missing if command -v conan >/dev/null 2>&1; then CONAN_DIR="$(dirname "$(command -v conan)")" echo "PATH=${CONAN_DIR}:\$PATH" >> ~/.buildenv else echo "Conan is not available after installation attempts" >&2 exit 1 fi CONAN_CPU_COUNT="${CONAN_CPU_COUNT:-$(nproc || getconf _NPROCESSORS_ONLN || echo 2)}" echo "CONAN_CPU_COUNT=${CONAN_CPU_COUNT}" >> ~/.buildenv # Detect and move into repository root if [ -d yams ] && { [ -f yams/meson.build ] || [ -f yams/CMakeLists.txt ]; }; then REPO_DIR="yams" else REPO_DIR="." fi cd "${REPO_DIR}" # Configure Conan (use explicit GCC host/build profiles for Debian CI) conan --version conan profile detect --force || true echo "Conan profile configured (default, overridden by setup.sh):" conan profile show -pr default || conan profile show || true - yams_semver_guard: | set -e if [ -d yams ] && { [ -f yams/meson.build ] || [ -f yams/CMakeLists.txt ]; }; then REPO_DIR="yams" else REPO_DIR="." fi cd "${REPO_DIR}" if [ -f scripts/ci/check_yams_semver.py ]; then echo "Running YAMS semver guard..." python3 scripts/ci/check_yams_semver.py else echo "No semver guard script found; skipping." fi - build: | set -e export PATH="${HOME}/.local/bin:/opt/conan/bin:${PATH}" if ! command -v conan >/dev/null 2>&1; then echo "conan not found in PATH; aborting build" >&2 exit 1 fi if [ -d yams ] && [ -f yams/meson.build ]; then REPO_DIR="yams" else REPO_DIR="." fi cd "${REPO_DIR}" export YAMS_DISABLE_MODEL_PRELOAD=1 CLEAN_VERSION_MESON="${YAMS_VERSION}" echo "Starting build (Meson version ${CLEAN_VERSION_MESON})" # Use setup.sh with environment variables for consistent build configuration export YAMS_COMPILER=gcc export YAMS_CPPSTD=20 export YAMS_CONAN_HOST_PROFILE=./conan/profiles/host-linux-gcc export YAMS_CONAN_ARCH=x86_64 # Configure FAST_MODE via extra Meson flags if [ "${FAST_MODE:-0}" = "1" ]; then echo "FAST_MODE=1: build will skip ONNX and tests" export YAMS_EXTRA_MESON_FLAGS="-Dyams-version=${CLEAN_VERSION_MESON} -Denable-onnx=disabled -Dplugin-onnx=false -Dbuild-tests=false" else export YAMS_EXTRA_MESON_FLAGS="-Dyams-version=${CLEAN_VERSION_MESON}" fi # Set install prefix to /usr for Linux packages (matches GitHub workflow) export YAMS_INSTALL_PREFIX="/usr" # Run setup.sh (Release build) - it now respects all YAMS_* environment variables ./setup.sh Release # Build the project meson compile -C build/release # Install the built artifacts into build-local staging directory (BUILD_DIR/STAGE_DIR). meson install -C build/release --destdir "${STAGE_DIR}" # Show ccache stats after build (if available) if command -v ccache >/dev/null 2>&1; then ccache -s || true fi - test: | set -e # Run test suite; do not fail the build solely due to test failures so we can publish logs if [ -d yams ] && [ -f yams/meson.build ]; then REPO_DIR="yams" else REPO_DIR="." fi cd "${REPO_DIR}" mkdir -p artifacts || true if [ -d "${BUILD_DIR}" ]; then echo "Running meson tests in ${BUILD_DIR}..." meson test -C "${BUILD_DIR}" --print-errorlogs || true # Collect logs and common debug info if [ -d "${BUILD_DIR}/meson-logs" ]; then tar -C "${BUILD_DIR}" -czf artifacts/meson-logs.tar.gz meson-logs || true cp -vf "${BUILD_DIR}/meson-logs/testlog.txt" artifacts/testlog.txt 2>/dev/null || true cp -vf "${BUILD_DIR}/meson-logs/meson-log.txt" artifacts/meson-log.txt 2>/dev/null || true fi # Export compile_commands if generated if [ -f "${BUILD_DIR}/compile_commands.json" ]; then cp -vf "${BUILD_DIR}/compile_commands.json" artifacts/compile_commands.json || true fi else echo "BUILD_DIR ${BUILD_DIR} missing; skipping meson tests" | tee artifacts/test-notes.txt fi - package: | set -e # Package on tag builds or when explicitly channelized as nightly/weekly # Auto-channelize main branch builds as nightly when not tagged if [[ -z "${RELEASE_CHANNEL:-}" && "${GIT_REF:-}" == "refs/heads/main" ]]; then export RELEASE_CHANNEL=nightly fi if [[ "${GIT_REF:-}" != refs/tags/* && "${RELEASE_CHANNEL:-}" != "nightly" && "${RELEASE_CHANNEL:-}" != "weekly" ]]; then echo "Skipping packaging (not a tag build and no release channel): GIT_REF=${GIT_REF:-n/a} RELEASE_CHANNEL=${RELEASE_CHANNEL:-n/a}" exit 0 fi if [ -d yams ] && { [ -f yams/meson.build ] || [ -f yams/CMakeLists.txt ]; }; then REPO_DIR="yams" else REPO_DIR="." fi cd "${REPO_DIR}" CLEAN_VERSION="${YAMS_VERSION}" echo "Packaging the release..." # Package from the staged install under BUILD_DIR/STAGE_DIR if [ ! -d "${BUILD_DIR}/${STAGE_DIR}" ]; then echo "ERROR: Stage directory ${BUILD_DIR}/${STAGE_DIR} not found" >&2 ls -al "${BUILD_DIR}" || true exit 1 fi cd "${BUILD_DIR}/${STAGE_DIR}" tar -czf "../yams-${CLEAN_VERSION}-linux-x86_64.tar.gz" . echo "Created asset: yams-${CLEAN_VERSION}-linux-x86_64.tar.gz" # Also publish a raw stage archive for debugging/inspection tar -czf "../yams-${CLEAN_VERSION}-stage.tar.gz" . if command -v zip >/dev/null 2>&1; then # Only attempt zip if there are regular files to include; otherwise zip exits with "Nothing to do!" if find . -type f -print -quit | grep -q .; then zip -qry "../yams-${CLEAN_VERSION}-stage.zip" . || echo "zip failed; continuing (tarball already created)" else echo "Stage contains no regular files; skipping zip archive" fi fi - package_meson: | set -e # Package on tag builds or when explicitly channelized as nightly/weekly if [[ "${GIT_REF:-}" != refs/tags/* && "${RELEASE_CHANNEL:-}" != "nightly" && "${RELEASE_CHANNEL:-}" != "weekly" ]]; then echo "Skipping packaging (not a tag build and no release channel): GIT_REF=${GIT_REF:-n/a} RELEASE_CHANNEL=${RELEASE_CHANNEL:-n/a}" exit 0 fi if [ -d yams ] && [ -f yams/meson.build ]; then REPO_DIR="yams" else REPO_DIR="." fi cd "${REPO_DIR}" CLEAN_VERSION="${YAMS_VERSION}" echo "Packaging with Meson..." if [ -x scripts/build-deb.sh ]; then scripts/build-deb.sh "${CLEAN_VERSION}" "${BUILD_DIR}" else echo "scripts/build-deb.sh not found; skipping distro package step" fi - collect_artifacts: | set -e ART_DIR="artifacts" mkdir -p "${ART_DIR}" rm -f "${ART_DIR}/yams"*.tar.gz "${ART_DIR}/yams"*.deb "${ART_DIR}/yams"*.rpm 2>/dev/null || true # Determine repository root if [ -d yams ] && { [ -f yams/meson.build ] || [ -f yams/CMakeLists.txt ]; }; then REPO_DIR="yams" else REPO_DIR="." fi # Publish a minimal, size-safe artifact set so SourceHut can retain them reliably. # Policy: # - Tag builds: prefer distro packages (.deb, .rpm) if available; fall back to the tarball. # - Nightly/weekly: publish only the primary tarball (avoid duplicates and stage archives). shopt -s nullglob || true if [[ "${GIT_REF:-}" == refs/tags/* ]]; then # Prefer distro packages on tagged releases if compgen -G "${REPO_DIR}/${BUILD_DIR}/*.deb" > /dev/null; then for f in "${REPO_DIR}/${BUILD_DIR}"/*.deb; do cp -v "$f" "${ART_DIR}/"; done fi if compgen -G "${REPO_DIR}/${BUILD_DIR}/*.rpm" > /dev/null; then for f in "${REPO_DIR}/${BUILD_DIR}"/*.rpm; do cp -v "$f" "${ART_DIR}/"; done fi # Fallback to tarball when packages are missing if ! compgen -G "${ART_DIR}/*" > /dev/null; then for f in "${REPO_DIR}/${BUILD_DIR}"/yams-*-linux-x86_64.tar.gz; do cp -v "$f" "${ART_DIR}/"; done fi else # Nightly/weekly: publish only the primary tarball for f in "${REPO_DIR}/${BUILD_DIR}"/yams-*-linux-x86_64.tar.gz; do cp -v "$f" "${ART_DIR}/"; done fi # Provide stable filenames expected by SourceHut (no globbing in artifacts list) if compgen -G "${ART_DIR}/*.tar.gz" > /dev/null; then TARBALL=$(ls -1 "${ART_DIR}"/*.tar.gz | head -1) cp -v "$TARBALL" "${ART_DIR}/yams.tar.gz" fi if compgen -G "${ART_DIR}/*.deb" > /dev/null; then DEB=$(ls -1 "${ART_DIR}"/*.deb | head -1) cp -v "$DEB" "${ART_DIR}/yams.deb" fi if compgen -G "${ART_DIR}/*.rpm" > /dev/null; then RPM=$(ls -1 "${ART_DIR}"/*.rpm | head -1) cp -v "$RPM" "${ART_DIR}/yams.rpm" fi echo "Collected artifacts:" && ls -l "${ART_DIR}" || true # Fallback for CI branches: if no artifacts were collected (packaging gated), # compress the staged install to provide a basic artifact for inspection. if [ "$(find "${ART_DIR}" -type f | wc -l | tr -d ' ')" -eq 0 ]; then if [ -d "${REPO_DIR}/${BUILD_DIR}/${STAGE_DIR}" ]; then echo "No release artifacts; creating CI tarball from ${REPO_DIR}/${BUILD_DIR}/${STAGE_DIR}" >&2 tar -C "${REPO_DIR}/${BUILD_DIR}/${STAGE_DIR}" -czf "${ART_DIR}/yams.tar.gz" . ls -l "${ART_DIR}" || true else echo "WARNING: Stage dir ${REPO_DIR}/${BUILD_DIR}/${STAGE_DIR} missing; no artifacts to publish" >&2 fi fi # Ensure artifacts listed in manifest exist (SourceHut fails if any are missing). for f in yams.deb yams.rpm meson-logs.tar.gz testlog.txt meson-log.txt compile_commands.json; do if [ ! -f "${ART_DIR}/${f}" ]; then echo "Not produced in this build." > "${ART_DIR}/${f}" fi done echo "collect_artifacts completed successfully" exit 0 artifacts: # SourceHut interprets artifact names literally (no shell globs). Provide # stable filenames in collect_artifacts. - "artifacts/yams.tar.gz" - "artifacts/yams.deb" - "artifacts/yams.rpm" - "artifacts/meson-logs.tar.gz" - "artifacts/testlog.txt" - "artifacts/meson-log.txt" - "artifacts/compile_commands.json"