#!/usr/bin/env bash # Copies Printhive's data out of Docker's named volumes into ./data, for the # switch to host folders. Run it on the server, from the folder holding # docker-compose.yml, with the stack stopped. # # It only copies: the named volumes are left exactly as they were, so if # anything looks wrong you can put the old docker-compose.yml back and start # again with nothing lost. set -euo pipefail # Same settings Compose uses, so the copy lands where the stack will look. if [ -f .env ]; then DATA_DIR="${DATA_DIR:-$(grep -E '^DATA_DIR=' .env | tail -1 | cut -d= -f2-)}" PGDATA_DIR="${PGDATA_DIR:-$(grep -E '^PGDATA_DIR=' .env | tail -1 | cut -d= -f2-)}" fi DATA_DIR="${DATA_DIR:-./data}" PGDATA_DIR="${PGDATA_DIR:-./data/pgdata}" VOLUMES=(pgdata uploads thumbnails glb extracted) # Where each volume's contents should end up. target_for() { case "$1" in pgdata) echo "$PGDATA_DIR" ;; *) echo "$DATA_DIR/$1" ;; esac } # Compose names volumes "_", the project being this folder's name # unless it's set elsewhere. PROJECT="${COMPOSE_PROJECT_NAME:-$(basename "$(pwd)")}" if docker compose ps --status running --quiet 2>/dev/null | grep -q .; then echo "Printhive is still running. Stop it first: docker compose down" >&2 exit 1 fi echo "Project: $PROJECT" echo "Files: $DATA_DIR" echo "Database: $PGDATA_DIR" echo for name in "${VOLUMES[@]}"; do volume="${PROJECT}_${name}" target="$(target_for "$name")" if ! docker volume inspect "$volume" >/dev/null 2>&1; then echo "· $volume — no such volume, skipping (nothing to copy)" mkdir -p "$target" continue fi if [ -d "$target" ] && [ -n "$(ls -A "$target" 2>/dev/null)" ]; then echo "· $target already has files in it — skipping, so nothing is overwritten" >&2 continue fi mkdir -p "$target" # -a keeps ownership and timestamps, which Postgres's data folder needs. docker run --rm \ -v "$volume":/from:ro \ -v "$(cd "$(dirname "$target")" && pwd)/$(basename "$target")":/to \ alpine sh -c 'cp -a /from/. /to/' echo "· $volume → $target ($(du -sh "$target" | cut -f1))" done echo echo "Done. Start it up again with: docker compose up -d" echo "Once you're happy, the old volumes can be removed with:" for name in "${VOLUMES[@]}"; do echo " docker volume rm ${PROJECT}_${name}"; done