#!/usr/bin/env bash # smartbotic-automation production build orchestrator. # Modeled on /data/shadowman-cpp/packaging/build.sh. # # Usage: # packaging/build.sh # Build with version from VERSION # packaging/build.sh 1.2.0 # Override version # packaging/build.sh --rebuild-base # Force rebuild of base image # packaging/build.sh --sync --suite trixie # Build + publish to APT repo set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$PROJECT_DIR" BASE_IMAGE_NAME="smartbotic-automation-build-base:debian13" OUTPUT_DIR="${PROJECT_DIR}/dist/debian13" BUILD_JOBS="${BUILD_JOBS:-$(nproc)}" DEB_REPO_DIR="${DEB_REPO_DIR:-/data/smartbotics-deb-repo}" RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[OK]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } REBUILD_BASE=false NO_CACHE=false BUILD_REPO=false SYNC_REPO=false REPO_SUITE="" VERSION="" DEB_REVISION="1" while [[ $# -gt 0 ]]; do case $1 in --rebuild-base) REBUILD_BASE=true; shift ;; --no-cache) NO_CACHE=true; shift ;; --deb-revision) DEB_REVISION="$2"; shift 2 ;; --repo) BUILD_REPO=true; shift ;; --suite) REPO_SUITE="$2"; shift 2 ;; --sync) SYNC_REPO=true; BUILD_REPO=true; shift ;; --help|-h) cat </dev/null; then log_error "Docker not found in PATH"; exit 1 fi base_image_exists() { docker image inspect "$BASE_IMAGE_NAME" &>/dev/null; } build_base_image() { log_info "Building base image: $BASE_IMAGE_NAME" local repo_pass="" if [ -f "${DEB_REPO_DIR}/.env" ]; then repo_pass=$(grep -oP 'RepoPass:\s*\K.*' "${DEB_REPO_DIR}/.env" | tr -d '[:space:]') fi if [ -z "$repo_pass" ]; then log_error "Could not read RepoPass from ${DEB_REPO_DIR}/.env"; exit 1 fi docker buildx build \ -f packaging/Dockerfile.base \ --build-arg REPO_PASS="$repo_pass" \ -t "$BASE_IMAGE_NAME" \ . log_success "Base image built" } if $REBUILD_BASE; then build_base_image elif base_image_exists; then log_success "Base image cached: $BASE_IMAGE_NAME" else build_base_image fi GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo unknown) rm -rf "$OUTPUT_DIR"; mkdir -p "$OUTPUT_DIR" BUILD_ARGS=( -f packaging/Dockerfile.build --build-arg BASE_IMAGE="$BASE_IMAGE_NAME" --build-arg BUILD_VERSION="$VERSION" --build-arg BUILD_DEB_REVISION="$DEB_REVISION" --build-arg BUILD_GIT_COMMIT="$GIT_COMMIT" --build-arg BUILD_JOBS="$BUILD_JOBS" --target packages --output "type=local,dest=$OUTPUT_DIR" ) $NO_CACHE && BUILD_ARGS+=(--no-cache) log_info "Building smartbotic-automation ${VERSION}-${DEB_REVISION} (commit ${GIT_COMMIT})" docker buildx build "${BUILD_ARGS[@]}" . log_success "Built packages:" ls -lh "$OUTPUT_DIR"/*.deb if $BUILD_REPO; then if [ -z "$REPO_SUITE" ]; then log_error "--suite is required with --repo"; exit 1 fi if [ ! -d "$DEB_REPO_DIR" ]; then log_error "Repository dir not found: $DEB_REPO_DIR"; exit 1 fi "$DEB_REPO_DIR/scripts/add-packages.sh" "$OUTPUT_DIR" "$DEB_REPO_DIR/scripts/create-repo.sh" --suite "$REPO_SUITE" fi if $SYNC_REPO; then "$DEB_REPO_DIR/scripts/sync-repo.sh" fi log_success "Done."