Pārlūkot izejas kodu

build(pkg): build.sh orchestrator + Debian-13 Docker base/build images

Fszontagh 1 mēnesi atpakaļ
vecāks
revīzija
07b977ffba
3 mainītis faili ar 340 papildinājumiem un 0 dzēšanām
  1. 27 0
      packaging/Dockerfile.base
  2. 12 0
      packaging/Dockerfile.build
  3. 301 0
      packaging/build.sh

+ 27 - 0
packaging/Dockerfile.base

@@ -0,0 +1,27 @@
+FROM debian:13-slim
+
+ARG REPO_USER
+ARG REPO_PASS
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+        ca-certificates curl gnupg cmake ninja-build g++ pkg-config \
+        nlohmann-json3-dev libspdlog-dev libssl-dev libsystemd-dev git \
+    && rm -rf /var/lib/apt/lists/*
+
+# Node 22 for the web UI build (vite 7 needs node >=20.19/22).
+RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
+    && apt-get install -y --no-install-recommends nodejs \
+    && rm -rf /var/lib/apt/lists/*
+
+# Smartbotics apt repo — provides libsmartbotic-db-client-dev (2.3.x).
+RUN curl -fsSL https://repository.smartbotics.ai/smartbotics-repo.gpg \
+        | gpg --dearmor -o /usr/share/keyrings/smartbotics-repo.gpg \
+    && printf 'machine repository.smartbotics.ai\nlogin %s\npassword %s\n' "$REPO_USER" "$REPO_PASS" \
+        > /etc/apt/auth.conf.d/smartbotics.conf \
+    && chmod 600 /etc/apt/auth.conf.d/smartbotics.conf \
+    && echo "deb [signed-by=/usr/share/keyrings/smartbotics-repo.gpg] https://repository.smartbotics.ai trixie main" \
+        > /etc/apt/sources.list.d/smartbotics.list \
+    && apt-get update \
+    && apt-get install -y --no-install-recommends libsmartbotic-db-client-dev \
+    && rm -rf /var/lib/apt/lists/*

+ 12 - 0
packaging/Dockerfile.build

@@ -0,0 +1,12 @@
+ARG BASE_IMAGE=smartbotic-vectorapi-build-base:debian13
+FROM ${BASE_IMAGE} AS builder
+ARG BUILD_VERSION=0.1.0
+ARG BUILD_DEB_REVISION=1
+WORKDIR /build
+COPY . /build/
+RUN cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_WEBUI=ON -DBUILD_TESTS=OFF -S . \
+    && cmake --build build -j"$(nproc)"
+RUN OUTPUT_DIR=/packages BUILD_DEB_REVISION=${BUILD_DEB_REVISION} packaging/deb/create-debs.sh
+
+FROM scratch AS packages
+COPY --from=builder /packages/*.deb /

+ 301 - 0
packaging/build.sh

@@ -0,0 +1,301 @@
+#!/usr/bin/env bash
+#
+# packaging/build.sh — Top-level build orchestrator for smartbotic-vectorapi
+#
+# Supports two modes:
+#   Default:  Docker build targeting Debian 13 (production .debs)
+#   --local:  Native build on current system (development/testing)
+#
+set -euo pipefail
+
+# ---------------------------------------------------------------------------
+# Paths
+# ---------------------------------------------------------------------------
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
+
+BASE_IMAGE_NAME="smartbotic-vectorapi-build-base:debian13"
+BUILD_JOBS="${BUILD_JOBS:-$(nproc)}"
+DEB_REPO_DIR="${DEB_REPO_DIR:-/data/smartbotics-deb-repo}"
+
+# Output directories — separate to prevent local/Docker overwriting each other
+#   dist/local/    — native build for current system
+#   dist/debian13/ — Docker build for Debian 13 production
+DIST_BASE="${PROJECT_DIR}/dist"
+
+VERSION="$(cat "$PROJECT_DIR/VERSION")"
+GIT_COMMIT="$(git -C "$PROJECT_DIR" rev-parse --short HEAD 2>/dev/null || echo "unknown")"
+
+# ---------------------------------------------------------------------------
+# Defaults
+# ---------------------------------------------------------------------------
+LOCAL_MODE=0
+INSTALL_AFTER=0
+SKIP_TESTS=0
+DEB_REVISION=1
+REBUILD_BASE=0
+NO_CACHE=0
+DO_REPO=0
+SUITE=""
+DO_SYNC=0
+
+# ---------------------------------------------------------------------------
+# Colored logging
+# ---------------------------------------------------------------------------
+log_info()    { printf '\033[1;34m[INFO]\033[0m  %s\n' "$*"; }
+log_success() { printf '\033[1;32m[OK]\033[0m    %s\n' "$*"; }
+log_warn()    { printf '\033[1;33m[WARN]\033[0m  %s\n' "$*"; }
+log_error()   { printf '\033[1;31m[ERROR]\033[0m %s\n' "$*"; }
+
+# ---------------------------------------------------------------------------
+# Usage
+# ---------------------------------------------------------------------------
+usage() {
+    cat <<EOF
+Usage: packaging/build.sh [OPTIONS]
+
+Build modes:
+  (default)            Docker build targeting Debian 13 (production)
+  --local              Native build for current system (development)
+
+Options:
+  --install            Install .debs locally after build (--local only)
+  --skip-tests         Skip running tests (no-op; tests disabled by default)
+  --deb-revision N     Debian revision suffix (default: 1)
+  --rebuild-base       Force rebuild Docker base image
+  --no-cache           Build without Docker caches
+  --repo               Add packages to local APT repository
+  --suite NAME         Distribution suite (e.g., trixie)
+  --sync               Add to repo and upload to repository.smartbotics.ai
+
+Environment variables:
+  BUILD_JOBS           Parallel build jobs (default: nproc)
+  DEB_REPO_DIR         Path to smartbotics-deb-repo (default: /data/smartbotics-deb-repo)
+EOF
+    exit 0
+}
+
+# ---------------------------------------------------------------------------
+# Argument parsing
+# ---------------------------------------------------------------------------
+while [[ $# -gt 0 ]]; do
+    case "$1" in
+        --local)        LOCAL_MODE=1; shift ;;
+        --install)      INSTALL_AFTER=1; shift ;;
+        --skip-tests)   SKIP_TESTS=1; shift ;;
+        --deb-revision) DEB_REVISION="$2"; shift 2 ;;
+        --rebuild-base) REBUILD_BASE=1; shift ;;
+        --no-cache)     NO_CACHE=1; shift ;;
+        --repo)         DO_REPO=1; shift ;;
+        --suite)        SUITE="$2"; shift 2 ;;
+        --sync)         DO_SYNC=1; shift ;;
+        -h|--help)      usage ;;
+        *)
+            log_error "Unknown option: $1"
+            usage
+            ;;
+    esac
+done
+
+# Validate option combinations
+if [[ $INSTALL_AFTER -eq 1 && $LOCAL_MODE -eq 0 ]]; then
+    log_error "--install is only supported with --local"
+    exit 1
+fi
+
+if [[ $DO_SYNC -eq 1 && $DO_REPO -eq 0 ]]; then
+    DO_REPO=1
+fi
+
+if [[ $DO_REPO -eq 1 && -z "$SUITE" ]]; then
+    log_error "--repo requires --suite NAME"
+    exit 1
+fi
+
+# ---------------------------------------------------------------------------
+# Set output directory based on mode
+# ---------------------------------------------------------------------------
+if [[ $LOCAL_MODE -eq 1 ]]; then
+    OUTPUT_DIR="${DIST_BASE}/local"
+else
+    OUTPUT_DIR="${DIST_BASE}/debian13"
+fi
+mkdir -p "$OUTPUT_DIR"
+
+# ---------------------------------------------------------------------------
+# Banner
+# ---------------------------------------------------------------------------
+log_info "smartbotic-vectorapi build v${VERSION} (${GIT_COMMIT})"
+log_info "Build jobs: ${BUILD_JOBS}"
+if [[ $LOCAL_MODE -eq 1 ]]; then
+    log_info "Mode: local (native)"
+else
+    log_info "Mode: Docker (Debian 13)"
+fi
+log_info "Output: ${OUTPUT_DIR}"
+
+# ---------------------------------------------------------------------------
+# Local build
+# ---------------------------------------------------------------------------
+build_local() {
+    log_info "Configuring CMake (Release)..."
+    cmake -B "$PROJECT_DIR/build" -G Ninja \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DBUILD_WEBUI=ON \
+        -DBUILD_TESTS=OFF \
+        -S "$PROJECT_DIR"
+
+    log_info "Building with ${BUILD_JOBS} jobs..."
+    cmake --build "$PROJECT_DIR/build" -j"$BUILD_JOBS"
+    log_success "Build completed"
+
+    log_info "Creating .deb packages..."
+    OUTPUT_DIR="$OUTPUT_DIR" BUILD_DEB_REVISION="$DEB_REVISION" "$PROJECT_DIR/packaging/deb/create-debs.sh"
+    log_success "Packages created"
+
+    if [[ $INSTALL_AFTER -eq 1 ]]; then
+        log_info "Installing .deb packages..."
+        sudo dpkg -i \
+            "$OUTPUT_DIR"/smartbotic-vectorapi_*.deb \
+            "$OUTPUT_DIR"/smartbotic-vectorapi-webui_*.deb \
+            || sudo apt-get install -f -y
+        log_success "Packages installed"
+    fi
+}
+
+# ---------------------------------------------------------------------------
+# Docker build
+# ---------------------------------------------------------------------------
+build_docker() {
+    if ! command -v docker &>/dev/null; then
+        log_error "Docker is not installed or not in PATH"
+        exit 1
+    fi
+
+    # Read repo credentials from the .env file (key names: RepoUser / RepoPass)
+    local env_file="${DEB_REPO_DIR}/.env"
+    if [[ ! -f "$env_file" ]]; then
+        log_error "Repository .env not found: $env_file"
+        exit 1
+    fi
+    local REPO_USER REPO_PASS
+    REPO_USER="$(grep '^RepoUser:' "$env_file" | awk '{print $2}')"
+    REPO_PASS="$(grep '^RepoPass:' "$env_file" | awk '{print $2}')"
+    if [[ -z "$REPO_USER" || -z "$REPO_PASS" ]]; then
+        log_error "Could not parse RepoUser/RepoPass from $env_file"
+        exit 1
+    fi
+
+    # Check / build base image
+    if [[ $REBUILD_BASE -eq 1 ]] || ! docker image inspect "$BASE_IMAGE_NAME" &>/dev/null; then
+        if [[ $REBUILD_BASE -eq 1 ]]; then
+            log_info "Rebuilding base image (--rebuild-base)..."
+        else
+            log_info "Base image not found, building ${BASE_IMAGE_NAME}..."
+        fi
+
+        local base_cache_args=()
+        if [[ $NO_CACHE -eq 1 ]]; then
+            base_cache_args+=("--no-cache")
+        fi
+
+        docker buildx build \
+            -f "$PROJECT_DIR/packaging/Dockerfile.base" \
+            -t "$BASE_IMAGE_NAME" \
+            --build-arg "REPO_USER=${REPO_USER}" \
+            --build-arg "REPO_PASS=${REPO_PASS}" \
+            "${base_cache_args[@]+"${base_cache_args[@]}"}" \
+            "$PROJECT_DIR"
+        log_success "Base image built: ${BASE_IMAGE_NAME}"
+    else
+        log_info "Using existing base image: ${BASE_IMAGE_NAME}"
+    fi
+
+    # Build packages
+    log_info "Building packages in Docker..."
+
+    local build_cache_args=()
+    if [[ $NO_CACHE -eq 1 ]]; then
+        build_cache_args+=("--no-cache")
+    fi
+
+    docker buildx build \
+        -f "$PROJECT_DIR/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_JOBS=${BUILD_JOBS}" \
+        --build-arg "BUILD_GIT_COMMIT=${GIT_COMMIT}" \
+        --target packages \
+        --output "type=local,dest=$OUTPUT_DIR" \
+        "${build_cache_args[@]+"${build_cache_args[@]}"}" \
+        "$PROJECT_DIR"
+
+    log_success "Docker build completed"
+}
+
+# ---------------------------------------------------------------------------
+# Main
+# ---------------------------------------------------------------------------
+if [[ $LOCAL_MODE -eq 1 ]]; then
+    build_local
+else
+    build_docker
+fi
+
+# ---------------------------------------------------------------------------
+# List created packages
+# ---------------------------------------------------------------------------
+echo ""
+log_info "Created packages:"
+ls -lh "$OUTPUT_DIR"/*.deb 2>/dev/null || {
+    log_error "No .deb files found in $OUTPUT_DIR"
+    exit 1
+}
+
+# ---------------------------------------------------------------------------
+# Repository operations
+# ---------------------------------------------------------------------------
+if [[ $DO_REPO -eq 1 ]]; then
+    echo ""
+    log_info "Adding packages to repository (suite: ${SUITE})..."
+
+    if [[ ! -x "$DEB_REPO_DIR/scripts/add-packages.sh" ]]; then
+        log_error "Repository tool not found: $DEB_REPO_DIR/scripts/add-packages.sh"
+        exit 1
+    fi
+
+    "$DEB_REPO_DIR/scripts/add-packages.sh" "$OUTPUT_DIR"
+    log_success "Packages added to staging"
+
+    "$DEB_REPO_DIR/scripts/create-repo.sh" --suite "$SUITE"
+    log_success "Repository created for suite: ${SUITE}"
+
+    if [[ $DO_SYNC -eq 1 ]]; then
+        log_info "Syncing repository to repository.smartbotics.ai..."
+        "$DEB_REPO_DIR/scripts/sync-repo.sh"
+        log_success "Repository synced"
+    fi
+fi
+
+# ---------------------------------------------------------------------------
+# Next steps
+# ---------------------------------------------------------------------------
+echo ""
+log_success "Build complete! (v${VERSION}-${DEB_REVISION})"
+echo ""
+if [[ $LOCAL_MODE -eq 1 && $INSTALL_AFTER -eq 0 ]]; then
+    log_info "To install locally:"
+    echo "  sudo dpkg -i ${OUTPUT_DIR}/*.deb || sudo apt-get install -f -y"
+    echo ""
+fi
+if [[ $DO_REPO -eq 0 ]]; then
+    log_info "To publish to repository:"
+    echo "  packaging/build.sh --repo --suite trixie"
+    echo ""
+fi
+if [[ $DO_REPO -eq 1 && $DO_SYNC -eq 0 ]]; then
+    log_info "To sync repository to remote:"
+    echo "  packaging/build.sh --repo --suite ${SUITE} --sync"
+    echo ""
+fi