Pārlūkot izejas kodu

packaging: add create-debs.sh and build.sh orchestrator

create-debs.sh stages and builds 4 .deb packages:
  - smartbotic-database (server + systemd + config)
  - libsmartbotic-db-client (shared .so)
  - libsmartbotic-db-client-dev (headers + cmake config)
  - smartbotic-db-cli (CLI tool)

build.sh supports two modes:
  - Default: Docker build targeting Debian 13
  - --local: native build for current system
  - --install: dpkg -i locally after build
  - --sync --suite trixie: publish to repository.smartbotics.ai
fszontagh 3 mēneši atpakaļ
vecāks
revīzija
f693b5823d
2 mainītis faili ar 502 papildinājumiem un 0 dzēšanām
  1. 285 0
      packaging/build.sh
  2. 217 0
      packaging/deb/create-debs.sh

+ 285 - 0
packaging/build.sh

@@ -0,0 +1,285 @@
+#!/usr/bin/env bash
+#
+# packaging/build.sh — Top-level build orchestrator for smartbotic-database
+#
+# 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-db-build-base:debian13"
+OUTPUT_DIR="${PROJECT_DIR}/dist"
+BUILD_JOBS="${BUILD_JOBS:-$(nproc)}"
+DEB_REPO_DIR="${DEB_REPO_DIR:-/data/smartbotics-deb-repo}"
+
+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
+  --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
+
+# ---------------------------------------------------------------------------
+# Banner
+# ---------------------------------------------------------------------------
+log_info "smartbotic-database 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
+
+# ---------------------------------------------------------------------------
+# Local build
+# ---------------------------------------------------------------------------
+build_local() {
+    log_info "Configuring CMake (Release)..."
+    cmake -B "$PROJECT_DIR/build" -G Ninja \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DSMARTBOTIC_DB_BUILD_SERVICE=ON \
+        -DSMARTBOTIC_DB_BUILD_CLIENT=ON \
+        -DSMARTBOTIC_DB_BUILD_CLI=ON \
+        -DSMARTBOTIC_DB_BUILD_TESTS=ON \
+        -DBUILD_SHARED_LIBS=ON \
+        -S "$PROJECT_DIR"
+
+    log_info "Building with ${BUILD_JOBS} jobs..."
+    cmake --build "$PROJECT_DIR/build" -j"$BUILD_JOBS"
+    log_success "Build completed"
+
+    if [[ $SKIP_TESTS -eq 0 ]]; then
+        log_info "Running tests..."
+        LD_LIBRARY_PATH="$PROJECT_DIR/build/client" \
+            "$PROJECT_DIR/build/tests/test_vector_storage"
+        log_success "Tests passed"
+    else
+        log_warn "Tests skipped (--skip-tests)"
+    fi
+
+    log_info "Creating .deb packages..."
+    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"/libsmartbotic-db-client_*.deb \
+            "$OUTPUT_DIR"/libsmartbotic-db-client-dev_*.deb \
+            "$OUTPUT_DIR"/smartbotic-db-cli_*.deb \
+            "$OUTPUT_DIR"/smartbotic-database_*.deb \
+            2>/dev/null || 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
+
+    # 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" \
+            "${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..."
+    mkdir -p "$OUTPUT_DIR"
+
+    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

+ 217 - 0
packaging/deb/create-debs.sh

@@ -0,0 +1,217 @@
+#!/usr/bin/env bash
+#
+# create-debs.sh — build 4 .deb packages for smartbotic-database
+#
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+SOURCE_DIR="${SOURCE_DIR:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
+BUILD_DIR="${BUILD_DIR:-$SOURCE_DIR/build}"
+OUTPUT_DIR="${OUTPUT_DIR:-$SOURCE_DIR/dist}"
+BUILD_DEB_REVISION="${BUILD_DEB_REVISION:-1}"
+
+TEMPLATE_DIR="$SCRIPT_DIR/templates"
+SCRIPTS_DIR="$SCRIPT_DIR/scripts"
+CONFIG_DIR="$SCRIPT_DIR/config"
+SYSTEMD_DIR="$SCRIPT_DIR/systemd"
+
+VERSION="$(cat "$SOURCE_DIR/VERSION")"
+DEB_VERSION="${VERSION}-${BUILD_DEB_REVISION}"
+
+echo "=== smartbotic-database deb builder ==="
+echo "VERSION       : $VERSION"
+echo "DEB_VERSION   : $DEB_VERSION"
+echo "SOURCE_DIR    : $SOURCE_DIR"
+echo "BUILD_DIR     : $BUILD_DIR"
+echo "OUTPUT_DIR    : $OUTPUT_DIR"
+
+mkdir -p "$OUTPUT_DIR"
+
+# ---------------------------------------------------------------------------
+# Helper: calculate installed size (kB) of everything except DEBIAN/
+# ---------------------------------------------------------------------------
+calc_installed_size() {
+    local staging_dir="$1"
+    local total=0
+    for d in "$staging_dir"/*/; do
+        [ "$(basename "$d")" = "DEBIAN" ] && continue
+        total=$(( total + $(du -sk "$d" | awk '{print $1}') ))
+    done
+    # Include any regular files directly in staging root (unlikely but safe)
+    echo "$total"
+}
+
+# ---------------------------------------------------------------------------
+# Helper: substitute placeholders, set perms, run dpkg-deb
+# ---------------------------------------------------------------------------
+build_deb() {
+    local pkg_name="$1"
+    local staging_dir="$2"
+
+    local installed_size
+    installed_size="$(calc_installed_size "$staging_dir")"
+
+    # Substitute placeholders in control file
+    sed -i \
+        -e "s/{{VERSION}}/${DEB_VERSION}/g" \
+        -e "s/{{INSTALLED_SIZE}}/${installed_size}/g" \
+        "$staging_dir/DEBIAN/control"
+
+    # Fix permissions
+    find "$staging_dir" -type d -exec chmod 0755 {} +
+    find "$staging_dir/DEBIAN" -type f -exec chmod 0644 {} +
+    # Maintainer scripts must be executable
+    for f in postinst prerm postrm preinst; do
+        [ -f "$staging_dir/DEBIAN/$f" ] && chmod 0755 "$staging_dir/DEBIAN/$f"
+    done
+
+    local deb_file="${OUTPUT_DIR}/${pkg_name}_${DEB_VERSION}_amd64.deb"
+    dpkg-deb --build --root-owner-group "$staging_dir" "$deb_file"
+    echo "  -> $deb_file"
+}
+
+# ===================================================================
+# Package 1: smartbotic-database (server)
+# ===================================================================
+echo ""
+echo "--- Package: smartbotic-database ---"
+PKG1="$(mktemp -d)"
+trap "rm -rf '$PKG1'" EXIT
+
+mkdir -p "$PKG1/DEBIAN"
+mkdir -p "$PKG1/usr/bin"
+mkdir -p "$PKG1/etc/smartbotic-database"
+mkdir -p "$PKG1/lib/systemd/system"
+
+cp "$BUILD_DIR/service/smartbotic-database" "$PKG1/usr/bin/smartbotic-database"
+chmod 0755 "$PKG1/usr/bin/smartbotic-database"
+
+cp "$CONFIG_DIR/config.json" "$PKG1/etc/smartbotic-database/config.json"
+cp "$SYSTEMD_DIR/smartbotic-database.service" "$PKG1/lib/systemd/system/smartbotic-database.service"
+
+cp "$TEMPLATE_DIR/control.server" "$PKG1/DEBIAN/control"
+cp "$SCRIPTS_DIR/server.postinst" "$PKG1/DEBIAN/postinst"
+cp "$SCRIPTS_DIR/server.prerm"    "$PKG1/DEBIAN/prerm"
+cp "$SCRIPTS_DIR/server.postrm"   "$PKG1/DEBIAN/postrm"
+
+cat > "$PKG1/DEBIAN/conffiles" <<'EOF'
+/etc/smartbotic-database/config.json
+EOF
+
+build_deb "smartbotic-database" "$PKG1"
+
+# ===================================================================
+# Package 2: libsmartbotic-db-client (shared lib)
+# ===================================================================
+echo ""
+echo "--- Package: libsmartbotic-db-client ---"
+PKG2="$(mktemp -d)"
+trap "rm -rf '$PKG1' '$PKG2'" EXIT
+
+LIB_DIR="$PKG2/usr/lib/x86_64-linux-gnu"
+mkdir -p "$PKG2/DEBIAN"
+mkdir -p "$LIB_DIR"
+
+cp "$BUILD_DIR/client/libsmartbotic-db-client.so.${VERSION}" "$LIB_DIR/libsmartbotic-db-client.so.${VERSION}"
+chmod 0644 "$LIB_DIR/libsmartbotic-db-client.so.${VERSION}"
+
+SONAME_MAJOR="${VERSION%%.*}"
+ln -s "libsmartbotic-db-client.so.${VERSION}" "$LIB_DIR/libsmartbotic-db-client.so.${SONAME_MAJOR}"
+
+cp "$TEMPLATE_DIR/control.lib" "$PKG2/DEBIAN/control"
+cp "$SCRIPTS_DIR/lib.postinst" "$PKG2/DEBIAN/postinst"
+cp "$SCRIPTS_DIR/lib.postrm"   "$PKG2/DEBIAN/postrm"
+
+build_deb "libsmartbotic-db-client" "$PKG2"
+
+# ===================================================================
+# Package 3: libsmartbotic-db-client-dev (headers + cmake config)
+# ===================================================================
+echo ""
+echo "--- Package: libsmartbotic-db-client-dev ---"
+PKG3="$(mktemp -d)"
+trap "rm -rf '$PKG1' '$PKG2' '$PKG3'" EXIT
+
+DEV_LIB_DIR="$PKG3/usr/lib/x86_64-linux-gnu"
+DEV_INC_DIR="$PKG3/usr/include/smartbotic/database"
+DEV_PROTO_INC_DIR="$PKG3/usr/include/smartbotic/database/proto"
+DEV_PROTO_SHARE="$PKG3/usr/share/smartbotic-database/proto"
+DEV_CMAKE_DIR="$DEV_LIB_DIR/cmake/smartbotic-db-client"
+
+mkdir -p "$PKG3/DEBIAN"
+mkdir -p "$DEV_INC_DIR"
+mkdir -p "$DEV_PROTO_INC_DIR"
+mkdir -p "$DEV_PROTO_SHARE"
+mkdir -p "$DEV_CMAKE_DIR"
+mkdir -p "$DEV_LIB_DIR"
+
+# Source headers
+cp "$SOURCE_DIR/client/include/smartbotic/database/client.hpp"   "$DEV_INC_DIR/client.hpp"
+cp "$SOURCE_DIR/client/include/smartbotic/database/document.hpp" "$DEV_INC_DIR/document.hpp"
+
+# Generated proto headers
+cp "$BUILD_DIR/proto/generated/database.pb.h"      "$DEV_PROTO_INC_DIR/database.pb.h"
+cp "$BUILD_DIR/proto/generated/database.grpc.pb.h" "$DEV_PROTO_INC_DIR/database.grpc.pb.h"
+
+# Dev linker symlink
+ln -s "libsmartbotic-db-client.so.${SONAME_MAJOR}" "$DEV_LIB_DIR/libsmartbotic-db-client.so"
+
+# Proto source
+cp "$SOURCE_DIR/proto/database.proto" "$DEV_PROTO_SHARE/database.proto"
+
+# CMake config
+cat > "$DEV_CMAKE_DIR/smartbotic-db-clientConfig.cmake" <<'CMAKEOF'
+# smartbotic-db-client CMake config
+# Usage: find_package(smartbotic-db-client REQUIRED)
+# Provides: smartbotic::db-client target
+
+include(CMakeFindDependencyMacro)
+find_dependency(Protobuf REQUIRED)
+find_dependency(gRPC CONFIG QUIET)
+if(NOT gRPC_FOUND)
+    find_package(PkgConfig REQUIRED)
+    pkg_check_modules(GRPC REQUIRED IMPORTED_TARGET grpc++)
+endif()
+
+if(NOT TARGET smartbotic::db-client)
+    add_library(smartbotic::db-client SHARED IMPORTED)
+    set_target_properties(smartbotic::db-client PROPERTIES
+        IMPORTED_LOCATION "/usr/lib/x86_64-linux-gnu/libsmartbotic-db-client.so"
+        INTERFACE_INCLUDE_DIRECTORIES "/usr/include"
+    )
+    if(TARGET gRPC::grpc++)
+        set_property(TARGET smartbotic::db-client APPEND PROPERTY
+            INTERFACE_LINK_LIBRARIES protobuf::libprotobuf gRPC::grpc++)
+    else()
+        set_property(TARGET smartbotic::db-client APPEND PROPERTY
+            INTERFACE_LINK_LIBRARIES protobuf::libprotobuf PkgConfig::GRPC)
+    endif()
+endif()
+CMAKEOF
+
+cp "$TEMPLATE_DIR/control.dev" "$PKG3/DEBIAN/control"
+
+build_deb "libsmartbotic-db-client-dev" "$PKG3"
+
+# ===================================================================
+# Package 4: smartbotic-db-cli
+# ===================================================================
+echo ""
+echo "--- Package: smartbotic-db-cli ---"
+PKG4="$(mktemp -d)"
+trap "rm -rf '$PKG1' '$PKG2' '$PKG3' '$PKG4'" EXIT
+
+mkdir -p "$PKG4/DEBIAN"
+mkdir -p "$PKG4/usr/bin"
+
+cp "$BUILD_DIR/cli/smartbotic-db-cli" "$PKG4/usr/bin/smartbotic-db-cli"
+chmod 0755 "$PKG4/usr/bin/smartbotic-db-cli"
+
+cp "$TEMPLATE_DIR/control.cli" "$PKG4/DEBIAN/control"
+
+build_deb "smartbotic-db-cli" "$PKG4"
+
+# ===================================================================
+echo ""
+echo "=== All packages built in $OUTPUT_DIR ==="
+ls -lh "$OUTPUT_DIR"/*.deb