From 49c444e8b92edc56f6efb16ea6af4c101c75175d Mon Sep 17 00:00:00 2001 From: gpatruno Date: Fri, 17 Jul 2026 00:22:52 +0200 Subject: [PATCH] big update optimization --- scripts/db-export.sh | 67 ++++++++++++++++++++ scripts/db-import.sh | 115 +++++++++++++++++++++++++++++++++++ scripts/docker-build-push.sh | 34 +++++++++++ 3 files changed, 216 insertions(+) create mode 100755 scripts/db-export.sh create mode 100755 scripts/db-import.sh create mode 100755 scripts/docker-build-push.sh diff --git a/scripts/db-export.sh b/scripts/db-export.sh new file mode 100755 index 0000000..c95c65d --- /dev/null +++ b/scripts/db-export.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +# Export local project SQLite DB (+ uploads) for backup / Docker import +# Usage: +# ./scripts/db-export.sh +# ./scripts/db-export.sh ./backups/my-backup +# +# Sources (local): +# server/prisma/dev.db (+ -wal / -shm if present) +# server/uploads/ +# +# Restore into Docker with: +# ./scripts/db-import.sh ./backups/... +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +LOCAL_DB="${LOCAL_DB:-$ROOT/server/prisma/dev.db}" +LOCAL_UPLOADS="${LOCAL_UPLOADS:-$ROOT/server/uploads}" +STAMP="$(date +%Y%m%d-%H%M%S)" +OUT="${1:-$ROOT/backups/casegambling-$STAMP}" + +if [[ ! -f "$LOCAL_DB" ]]; then + echo "Error: local database not found: $LOCAL_DB" >&2 + echo "Tip: run the app once or set LOCAL_DB=/path/to/dev.db" >&2 + exit 1 +fi + +mkdir -p "$OUT" + +echo "==> Exporting local database → $OUT/prod.db" +echo " source: $LOCAL_DB" +cp -f "$LOCAL_DB" "$OUT/prod.db" +# keep a copy under original name too (import accepts both) +cp -f "$LOCAL_DB" "$OUT/dev.db" + +if [[ -f "${LOCAL_DB}-wal" ]]; then + cp -f "${LOCAL_DB}-wal" "$OUT/prod.db-wal" + cp -f "${LOCAL_DB}-wal" "$OUT/dev.db-wal" +fi +if [[ -f "${LOCAL_DB}-shm" ]]; then + cp -f "${LOCAL_DB}-shm" "$OUT/prod.db-shm" + cp -f "${LOCAL_DB}-shm" "$OUT/dev.db-shm" +fi + +echo "==> Exporting local uploads → $OUT/uploads" +mkdir -p "$OUT/uploads" +if [[ -d "$LOCAL_UPLOADS" ]]; then + # copy contents; ignore empty/.gitkeep-only quietly + cp -a "$LOCAL_UPLOADS"/. "$OUT/uploads/" 2>/dev/null || true +else + echo " (no uploads dir at $LOCAL_UPLOADS)" +fi + +{ + echo "exported_at=$STAMP" + echo "source=local" + echo "local_db=$LOCAL_DB" + echo "local_uploads=$LOCAL_UPLOADS" + echo "database=prod.db" + echo "uploads=uploads/" +} > "$OUT/manifest.txt" + +TAR="$OUT.tar.gz" +tar -czf "$TAR" -C "$(dirname "$OUT")" "$(basename "$OUT")" +echo "==> Archive: $TAR" +echo "==> Done. Import to Docker: ./scripts/db-import.sh $OUT" diff --git a/scripts/db-import.sh b/scripts/db-import.sh new file mode 100755 index 0000000..3a92ea7 --- /dev/null +++ b/scripts/db-import.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +# Import SQLite DB (+ uploads) into the CaseGambling Docker container +# Usage: +# ./scripts/db-import.sh ./backups/casegambling-20260116-203000 +# ./db-import.sh ./casegambling-20260116-203000.tar.gz +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +# Project root: folder that contains docker-compose.yml +if [[ -f "$SCRIPT_DIR/docker-compose.yml" ]]; then + ROOT="$SCRIPT_DIR" +elif [[ -f "$SCRIPT_DIR/../docker-compose.yml" ]]; then + ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +else + ROOT="$SCRIPT_DIR" +fi + +# Resolve backup path from the caller's working directory (before any cd) +if [[ -z "${1:-}" ]]; then + echo "Usage: $0 " >&2 + echo "Example: $0 ./backups/casegambling-20260116-203000.tar.gz" >&2 + exit 1 +fi +if [[ "$1" = /* ]]; then + SRC="$1" +else + SRC="$(pwd)/$1" +fi + +cd "$ROOT" + +ENV_FILE="${ENV_FILE:-.env.prod}" +COMPOSE=(docker compose) +if [[ -f "$ENV_FILE" ]]; then + COMPOSE=(docker compose --env-file "$ENV_FILE") +fi + +SERVICE="${SERVICE:-casegambling}" + +TMP="" +cleanup() { + if [[ -n "$TMP" && -d "$TMP" ]]; then + rm -rf "$TMP" + fi +} +trap cleanup EXIT + +is_archive() { + case "$1" in + *.tar.gz|*.tgz) return 0 ;; + *) return 1 ;; + esac +} + +if [[ -f "$SRC" ]] && is_archive "$SRC"; then + echo "==> Extracting $(basename "$SRC")" + TMP="$(mktemp -d)" + tar -xzf "$SRC" -C "$TMP" + # Prefer a single top-level directory from the archive + mapfile -t DIRS < <(find "$TMP" -mindepth 1 -maxdepth 1 -type d | sort) + if [[ ${#DIRS[@]} -ge 1 ]]; then + SRC="${DIRS[0]}" + else + SRC="$TMP" + fi +elif [[ -f "$SRC" ]]; then + echo "Error: not a directory or .tar.gz archive: $SRC" >&2 + exit 1 +fi + +if [[ ! -d "$SRC" ]]; then + echo "Error: backup not found: $SRC" >&2 + echo "Pass a folder or a .tar.gz produced by ./scripts/db-export.sh" >&2 + exit 1 +fi + +DB="$SRC/prod.db" +if [[ ! -f "$DB" ]]; then + if [[ -f "$SRC/dev.db" ]]; then + DB="$SRC/dev.db" + else + echo "Error: no prod.db (or dev.db) in $SRC" >&2 + ls -la "$SRC" >&2 || true + exit 1 + fi +fi + +echo "==> Stopping $SERVICE (safe SQLite replace)" +"${COMPOSE[@]}" stop "$SERVICE" 2>/dev/null || docker stop "$SERVICE" 2>/dev/null || true + +echo "==> Clearing old SQLite sidecars on volume" +"${COMPOSE[@]}" run --rm --no-deps --entrypoint sh "$SERVICE" -c \ + 'rm -f /data/prod.db-wal /data/prod.db-shm' >/dev/null + +echo "==> Importing database ← $DB" +"${COMPOSE[@]}" cp "$DB" "$SERVICE:/data/prod.db" + +if [[ -f "$SRC/prod.db-wal" ]]; then + "${COMPOSE[@]}" cp "$SRC/prod.db-wal" "$SERVICE:/data/prod.db-wal" +fi +if [[ -f "$SRC/prod.db-shm" ]]; then + "${COMPOSE[@]}" cp "$SRC/prod.db-shm" "$SERVICE:/data/prod.db-shm" +fi + +if [[ -d "$SRC/uploads" ]]; then + echo "==> Importing uploads" + "${COMPOSE[@]}" run --rm --no-deps --entrypoint sh "$SERVICE" -c \ + 'rm -rf /app/uploads/* /app/uploads/.[!.]* 2>/dev/null; mkdir -p /app/uploads' >/dev/null + "${COMPOSE[@]}" cp "$SRC/uploads/." "$SERVICE:/app/uploads/" +fi + +echo "==> Starting $SERVICE" +"${COMPOSE[@]}" start "$SERVICE" 2>/dev/null || "${COMPOSE[@]}" up -d "$SERVICE" + +echo "==> Done. Check: ${COMPOSE[*]} logs -f --tail=50" diff --git a/scripts/docker-build-push.sh b/scripts/docker-build-push.sh new file mode 100755 index 0000000..1eca9db --- /dev/null +++ b/scripts/docker-build-push.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Build & push CaseGambling image to Docker Hub (user: foufure) +# Usage: +# ./scripts/docker-build-push.sh # tag: latest +# ./scripts/docker-build-push.sh v1.0.0 # tag: v1.0.0 + latest +# Requires: docker login (docker login) +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +DOCKERHUB_USER="${DOCKERHUB_USER:-foufure}" +# Docker Hub requires lowercase repository names +IMAGE_NAME="${IMAGE_NAME:-casegambling}" +IMAGE="${DOCKERHUB_USER}/${IMAGE_NAME}" +TAG="${1:-latest}" + +echo "==> Building ${IMAGE}:${TAG}" +docker build \ + -t "${IMAGE}:${TAG}" \ + -t "${IMAGE}:latest" \ + -f Dockerfile \ + . + +echo "==> Pushing ${IMAGE}:${TAG}" +docker push "${IMAGE}:${TAG}" + +if [[ "${TAG}" != "latest" ]]; then + echo "==> Pushing ${IMAGE}:latest" + docker push "${IMAGE}:latest" +fi + +echo "==> Done: ${IMAGE}:${TAG}" +echo " Pull: docker pull ${IMAGE}:${TAG}"