#!/usr/bin/env bash set -Eeuo pipefail ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) cd "$ROOT" ENV_FILE="$ROOT/.env" DATA_DIR="$ROOT/data" GPG_DIR="$ROOT/gpg" DEFAULT_HTTP_PORT=18965 log() { printf '[rustbox-package-builder] %s\n' "$*"; } die() { printf '[rustbox-package-builder] ERROR: %s\n' "$*" >&2; exit 1; } require_cmd() { command -v "$1" >/dev/null 2>&1 || die "missing command: $1"; } require_cmd docker if ! docker info >/dev/null 2>&1; then die "Docker daemon is unavailable for the current user" fi if docker compose version >/dev/null 2>&1; then COMPOSE=(docker compose) elif command -v docker-compose >/dev/null 2>&1; then COMPOSE=(docker-compose) else die "Docker Compose is required" fi if [[ ! -f "$ENV_FILE" ]]; then cp "$ROOT/.env.example" "$ENV_FILE" chmod 0600 "$ENV_FILE" die "created .env; set SOURCE_REPO and REPOSITORY_URL, then run ./start.sh again" fi set -a source "$ENV_FILE" set +a : "${SOURCE_REPO:?SOURCE_REPO is required in .env}" : "${REPOSITORY_URL:?REPOSITORY_URL is required in .env}" HTTP_PORT=${HTTP_PORT:-$DEFAULT_HTTP_PORT} [[ "$HTTP_PORT" =~ ^[0-9]+$ ]] || die "HTTP_PORT must be numeric" (( HTTP_PORT >= 1024 && HTTP_PORT <= 65535 )) || die "HTTP_PORT must be between 1024 and 65535" REPOSITORY_URL=${REPOSITORY_URL%/} case "$REPOSITORY_URL" in http://*|https://*) ;; *) die "REPOSITORY_URL must start with http:// or https://" ;; esac if [[ "$REPOSITORY_URL" == http://* && ! "$REPOSITORY_URL" =~ :[0-9]+$ ]]; then REPOSITORY_URL="${REPOSITORY_URL}:${HTTP_PORT}" if grep -q '^REPOSITORY_URL=' "$ENV_FILE"; then sed -i "s#^REPOSITORY_URL=.*#REPOSITORY_URL=${REPOSITORY_URL}#" "$ENV_FILE" fi export REPOSITORY_URL log "REPOSITORY_URL updated to $REPOSITORY_URL" fi mkdir -p "$DATA_DIR"/{repository,state,cargo,work,packages} "$GPG_DIR" chmod 0700 "$GPG_DIR" 2>/dev/null || true log "building builder and repository dashboard" "${COMPOSE[@]}" --env-file "$ENV_FILE" build rustbox-package-builder repository-dashboard if [[ ! -s "$GPG_DIR/private-key.asc" ]]; then log "generating persistent GPG signing key" IMAGE_REF=$("${COMPOSE[@]}" --env-file "$ENV_FILE" config | awk ' $1 == "rustbox-package-builder:" { in_builder=1; next } in_builder && $1 == "image:" { print $2; exit } ') [[ -n "$IMAGE_REF" ]] || die "cannot resolve builder image name" uid=$(id -u) gid=$(id -g) docker run --rm --user "$uid:$gid" --entrypoint /bin/bash -e HOME=/tmp \ -v "$GPG_DIR:/out" "$IMAGE_REF" -lc ' set -Eeuo pipefail export GNUPGHOME=/tmp/rustbox-keygen mkdir -p "$GNUPGHOME" && chmod 0700 "$GNUPGHOME" cat > /tmp/gpg-batch <<"KEY" Key-Type: RSA Key-Length: 3072 Key-Usage: sign Name-Real: RustBox Package Repository Name-Email: packages@localhost Expire-Date: 0 %no-protection %commit KEY gpg --batch --generate-key /tmp/gpg-batch fingerprint=$(gpg --batch --with-colons --list-secret-keys | awk -F: '\''/^sec:/ {seen=1; next} seen && /^fpr:/ {print $10; exit}'\'') test -n "$fingerprint" gpg --batch --armor --export-secret-keys "$fingerprint" > /out/private-key.asc gpg --batch --armor --export "$fingerprint" > /out/public-key.asc printf "%s\n" "$fingerprint" > /out/fingerprint chmod 0600 /out/private-key.asc chmod 0644 /out/public-key.asc /out/fingerprint ' fi log "starting builder and repository HTTP service" "${COMPOSE[@]}" --env-file "$ENV_FILE" up -d rustbox-package-builder repository-http printf '\nRepository: %s/\n' "$REPOSITORY_URL" printf 'Local HTTP: http://127.0.0.1:%s/\n' "$HTTP_PORT" printf 'Health: http://127.0.0.1:%s/healthz\n' "$HTTP_PORT" printf 'Builder log: ' printf '%q ' "${COMPOSE[@]}" printf 'logs -f rustbox-package-builder\n'