Files
2026-10-22 16:10:02 +02:00

203 lines
7.3 KiB
Bash
Executable File

#!/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" <<ENV
SOURCE_REPO=${SOURCE_REPO:-}
REPOSITORY_URL=${REPOSITORY_URL:-}
OPNSENSE_REPOSITORY_URL=${OPNSENSE_REPOSITORY_URL:-}
ENV
chmod 0600 "$ENV_FILE" 2>/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"