#!/usr/bin/env bash set -Eeuo pipefail ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) cd "$ROOT" ENV_FILE="$ROOT/.env" GPG_DIR="$ROOT/gpg" DATA_DIR="$ROOT/data" SERVICE="rust-package-builder" HTTP_SERVICE="repository-http" DEFAULT_HTTP_PORT=18765 DEFAULT_OPNSENSE_HTTP_PORT=18766 log() { printf '[start] %s\n' "$*"; } warn() { printf '[start] WARN: %s\n' "$*" >&2; } die() { printf '[start] ERROR: %s\n' "$*" >&2; exit 1; } require_cmd() { command -v "$1" >/dev/null 2>&1 || die "brak wymaganego polecenia: $1"; } write_env_file() { cat > "$ENV_FILE" </dev/null || true } update_env_var() { local key=$1 value=$2 tmp="$ENV_FILE.tmp.$$" awk -v key="$key" -v value="$value" ' BEGIN { found=0 } index($0, key "=") == 1 { print key "=" value; found=1; next } { print } END { if (!found) print key "=" value } ' "$ENV_FILE" > "$tmp" mv "$tmp" "$ENV_FILE" chmod 0600 "$ENV_FILE" 2>/dev/null || true } load_env_file() { set -a # shellcheck disable=SC1090 source "$ENV_FILE" set +a } normalize_repo_url() { local url_var=$1 port_var=$2 default_port=$3 label=$4 local url=${!url_var:-} port=${!port_var:-} rest hostpart explicit_port="" url=${url%/} [[ -n "$url" ]] || die "$url_var jest wymagane" case "$url" in http://*) rest=${url#http://} ;; https://*) rest=${url#https://} ;; *) die "$url_var musi zaczynac sie od http:// albo https://" ;; esac [[ "$rest" != */* ]] || die "$url_var nie moze zawierac sciezki: $url" hostpart=$rest if [[ "$hostpart" =~ ^\[[^]]+\]:([0-9]+)$ ]]; then explicit_port=${BASH_REMATCH[1]} elif [[ "$hostpart" =~ ^[^:]+:([0-9]+)$ ]]; then explicit_port=${BASH_REMATCH[1]} fi if [[ "$url" == http://* && -n "$explicit_port" ]]; then port=$explicit_port else port=${port:-$default_port} if [[ "$url" == http://* && -z "$explicit_port" ]]; then url="${url}:${port}" log "$label URL bez portu - ustawiono $url" elif [[ "$url" == https://* ]]; then warn "$label uzywa HTTPS. Wbudowany nginx nasluchuje lokalnie po HTTP na porcie $port; TLS wymaga reverse proxy." fi fi [[ "$port" =~ ^[0-9]+$ ]] || die "$port_var musi byc liczba" (( port >= 1024 && port <= 65535 )) || die "$port_var musi byc z zakresu 1024-65535" printf -v "$url_var" '%s' "$url" printf -v "$port_var" '%s' "$port" export "$url_var" "$port_var" update_env_var "$url_var" "$url" update_env_var "$port_var" "$port" } require_cmd docker require_cmd awk if ! docker info >/dev/null 2>&1; then die "Docker daemon nie jest dostepny dla aktualnego uzytkownika" 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 "brak Docker Compose (docker compose lub docker-compose)" fi [[ -f "$ENV_FILE" ]] || write_env_file load_env_file if [[ "${FREEBSD_NATIVE_ENABLED:-1}" == "0" ]]; then warn "Native FreeBSD builds are DISABLED by existing .env; set FREEBSD_NATIVE_ENABLED=1 and rerun ./start.sh to publish native PKG" fi : "${SOURCE_REPO:?Uzupelnij SOURCE_REPO w .env albo ustaw zmienna przed uruchomieniem start.sh}" : "${REPOSITORY_URL:?Uzupelnij REPOSITORY_URL dla APT/RPM}" : "${OPNSENSE_REPOSITORY_URL:?Uzupelnij OPNSENSE_REPOSITORY_URL dla repo FreeBSD pkg}" case "$SOURCE_REPO" in http://*|https://*|ssh://*|git@*|file://*) ;; *) die "SOURCE_REPO ma nieobslugiwany format: $SOURCE_REPO" ;; esac normalize_repo_url REPOSITORY_URL HTTP_PORT "$DEFAULT_HTTP_PORT" "APT/RPM/SUSE" normalize_repo_url OPNSENSE_REPOSITORY_URL OPNSENSE_HTTP_PORT "$DEFAULT_OPNSENSE_HTTP_PORT" "OPNsense" [[ "$HTTP_PORT" != "$OPNSENSE_HTTP_PORT" ]] || die "HTTP_PORT i OPNSENSE_HTTP_PORT musza byc rozne" mkdir -p "$DATA_DIR/repository" "$DATA_DIR/state" "$DATA_DIR/cargo" "$DATA_DIR/work" "$GPG_DIR" chmod 0700 "$GPG_DIR" 2>/dev/null || true log "budowanie obrazu buildera oraz panelu repozytorium" "${COMPOSE[@]}" --env-file "$ENV_FILE" build "$SERVICE" repository-dashboard if [[ ! -s "$GPG_DIR/private-key.asc" ]]; then log "brak klucza GPG - generowanie stalego klucza podpisujacego Linux APT/RPM" IMAGE_REF=$("${COMPOSE[@]}" --env-file "$ENV_FILE" config | awk ' $1 == "rust-package-builder:" { in_builder=1; next } in_builder && $1 == "image:" { print $2; exit } ') [[ -n "$IMAGE_REF" ]] || die "nie mozna ustalic nazwy zbudowanego obrazu buildera" docker image inspect "$IMAGE_REF" >/dev/null 2>&1 || die "zbudowany obraz nie istnieje: $IMAGE_REF" 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/rpb-keygen mkdir -p "$GNUPGHOME" chmod 0700 "$GNUPGHOME" cat > /tmp/gpg-batch <<"KEY" Key-Type: RSA Key-Length: 3072 Key-Usage: sign Name-Real: Rust Package Builder 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 ' [[ -s "$GPG_DIR/private-key.asc" ]] || die "generowanie prywatnego klucza GPG nie powiodlo sie" [[ -s "$GPG_DIR/public-key.asc" ]] || die "generowanie publicznego klucza GPG nie powiodlo sie" else log "uzywanie istniejacego klucza GPG" fi log "uruchamianie buildera, panelu i nginx przez Docker Compose" "${COMPOSE[@]}" --env-file "$ENV_FILE" up -d "$SERVICE" "$HTTP_SERVICE" fingerprint="" [[ -r "$GPG_DIR/fingerprint" ]] && fingerprint=$(tr -d '[:space:]' < "$GPG_DIR/fingerprint") log "gotowe" printf '\nSOURCE_REPO: %s\n' "$SOURCE_REPO" printf 'APT/RPM URL: %s/\n' "${REPOSITORY_URL%/}" printf 'SUSE/Zypper RPM URL: %s/suse/x86_64/\n' "${REPOSITORY_URL%/}" printf 'APT/RPM local HTTP port: %s\n' "$HTTP_PORT" printf 'OPNsense pkg URL: %s/\n' "${OPNSENSE_REPOSITORY_URL%/}" printf 'OPNsense local HTTP port: %s\n' "$OPNSENSE_HTTP_PORT" [[ "${FREEBSD_NATIVE_ENABLED:-1}" == "1" ]] && printf 'Native FreeBSD pkg URL: %s/freebsd/\n' "${OPNSENSE_REPOSITORY_URL%/}" [[ -n "$fingerprint" ]] && printf 'GPG fingerprint: %s\n' "$fingerprint" printf 'Publiczny katalog: %s\n\n' "$DATA_DIR/repository" printf 'Health Linux: http://127.0.0.1:%s/healthz\n' "$HTTP_PORT" printf 'Health OPNsense: http://127.0.0.1:%s/healthz\n\n' "$OPNSENSE_HTTP_PORT" printf 'Logi buildera:\n ' printf '%q ' "${COMPOSE[@]}" printf 'logs -f %q\n' "$SERVICE" printf 'Logi HTTP:\n ' printf '%q ' "${COMPOSE[@]}" printf 'logs -f %q\n' "$HTTP_SERVICE"