|
|
@@ -0,0 +1,140 @@
|
|
|
+#!/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 <<EOF
|
|
|
+smartbotic-automation Production Build Script
|
|
|
+
|
|
|
+Usage: $0 [OPTIONS] [VERSION]
|
|
|
+
|
|
|
+Options:
|
|
|
+ --rebuild-base Force rebuild the base image
|
|
|
+ --no-cache Build without using BuildKit caches
|
|
|
+ --deb-revision N Debian revision suffix (default: 1)
|
|
|
+ --repo Generate APT repo from built packages
|
|
|
+ --suite NAME Distribution suite for repo (e.g., trixie)
|
|
|
+ --sync Generate repo and sync to repository.smartbotics.ai
|
|
|
+
|
|
|
+Environment:
|
|
|
+ BUILD_JOBS Parallel build jobs (default: nproc)
|
|
|
+ DEB_REPO_DIR Path to smartbotics-deb-repo (default: /data/smartbotics-deb-repo)
|
|
|
+EOF
|
|
|
+ exit 0 ;;
|
|
|
+ *) VERSION="$1"; shift ;;
|
|
|
+ esac
|
|
|
+done
|
|
|
+
|
|
|
+if [ -z "$VERSION" ]; then
|
|
|
+ VERSION="$(tr -d '[:space:]' < VERSION 2>/dev/null || true)"
|
|
|
+ if [ -z "$VERSION" ]; then
|
|
|
+ log_error "Could not read version from VERSION file"; exit 1
|
|
|
+ fi
|
|
|
+fi
|
|
|
+
|
|
|
+if ! command -v docker &>/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."
|