#!/usr/bin/env bash # Usage: ./backup.sh [label] # Creates backups/world-YYYY-MM-DD-HHMM[-label].tar.gz and uploads it # as a Gitea release asset on the `origin` remote. # # If the container is running, flushes world via rcon and archives via # docker exec. Otherwise archives data/world from the host directly. # # Token is read from $GITEA_TOKEN or ~/.gitea_token. If neither is set, # the local archive is still created and upload is skipped. set -euo pipefail cd "$(dirname "$0")" LABEL="${1:-}" STAMP="$(date +%Y-%m-%d-%H%M)" SUFFIX="${LABEL:+-$LABEL}" OUT="backups/world-${STAMP}${SUFFIX}.tar.gz" mkdir -p backups if docker ps --format '{{.Names}}' | grep -qx minecraft; then echo "Server running — flushing world via rcon..." docker exec minecraft rcon-cli save-off >/dev/null docker exec minecraft rcon-cli save-all flush >/dev/null trap 'docker exec minecraft rcon-cli save-on >/dev/null || true' EXIT echo "Archiving /data/world -> ${OUT}" docker exec minecraft tar -czf - -C /data world > "${OUT}" else echo "Server not running — archiving data/world from host." tar -czf "${OUT}" -C data world fi echo "Archive done: $(ls -lh "${OUT}" | awk '{print $5, $9}')" # --- Upload to Gitea as a release asset --- TOKEN="${GITEA_TOKEN:-}" if [[ -z "$TOKEN" && -r "$HOME/.gitea_token" ]]; then TOKEN="$(cat "$HOME/.gitea_token")" fi if [[ -z "$TOKEN" ]]; then echo "No Gitea token (set GITEA_TOKEN or ~/.gitea_token) — skipping upload." exit 0 fi URL="$(git config --get remote.origin.url)" SCHEME="${URL%%://*}" REST="${URL#*://}"; REST="${REST#*@}" # strip any embedded userinfo HOSTPORT="${REST%%/*}" REPO_PATH="${REST#*/}"; REPO_PATH="${REPO_PATH%.git}" OWNER="${REPO_PATH%/*}" REPO="${REPO_PATH#*/}" API="${SCHEME}://${HOSTPORT}/api/v1" TAG="backup-${STAMP}${SUFFIX}" NAME="World backup ${STAMP}${LABEL:+ ($LABEL)}" SHA="$(git rev-parse HEAD)" echo "Pushing main so the release target exists on remote..." git push origin main >/dev/null echo "Creating release '${TAG}' on ${OWNER}/${REPO}..." PAYLOAD=$(printf '{"tag_name":"%s","target_commitish":"%s","name":"%s","body":"Automated world backup"}' \ "$TAG" "$SHA" "$NAME") RESPONSE=$(curl -fsS -X POST \ -H "Authorization: token ${TOKEN}" \ -H "Content-Type: application/json" \ -d "$PAYLOAD" \ "${API}/repos/${OWNER}/${REPO}/releases") RELEASE_ID="${RESPONSE#*\"id\":}" RELEASE_ID="${RELEASE_ID%%,*}" if ! [[ "$RELEASE_ID" =~ ^[0-9]+$ ]]; then echo "Could not parse release id from response:" >&2 echo "$RESPONSE" >&2 exit 1 fi echo "Uploading asset to release ${RELEASE_ID}..." curl -fsS -X POST \ -H "Authorization: token ${TOKEN}" \ -F "attachment=@${OUT}" \ "${API}/repos/${OWNER}/${REPO}/releases/${RELEASE_ID}/assets?name=$(basename "${OUT}")" \ >/dev/null echo "Uploaded: ${SCHEME}://${HOSTPORT}/${OWNER}/${REPO}/releases/tag/${TAG}"