#!/bin/sh
# The nightly backup: both applications, into one dated folder, with old folders removed.
#
#   sh deploy/backup.sh                     # writes deploy/_backup/<date>/
#   BACKUP_DIR=/var/www/private/thinkera.academy/backups sh deploy/backup.sh
#
# The platform and the site are found next to deploy/: the platform in platform/ or platform/moodle, the site in
# thinkera.academy/, cms/ or site/ (whichever holds a docker-compose.yml and a .env). PLATFORM_DIR and SITE_DIR
# say it outright when a server is laid out differently.
#
# It reuses the export scripts, so a backup and a folder prepared for a move are the same thing: anything
# here can be restored with import-platform.sh and import-site.sh, and it is worth proving that once.
#
# Everything is written to a folder named .partial first and renamed at the end, so a run cut short by a
# reboot never leaves a half-written folder that looks complete.
set -e

here=$(cd "$(dirname "$0")" && pwd)
root=$(cd "$here/.." && pwd)
keep=${BACKUP_KEEP:-14}
base=${BACKUP_DIR:-$here/_backup}
day=$(date +%Y-%m-%d)
work="$base/$day.partial"
final="$base/$day"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S')  $1"
}

fail() {
    log "FAILED: $1"
    rm -rf "$work"
    exit 1
}

rm -rf "$work"
mkdir -p "$work"
log "backing up into $final"

# The same export scripts, told to write here instead of into _export — so a backup and a folder prepared
# for a move stay one piece of code, and a nightly run never touches a folder someone is about to copy.
EXPORT_DIR="$work"
export EXPORT_DIR

# the first of these folders that holds an application (its compose file and its .env)
find_app() {
    for d in "$@"; do
        if [ -f "$d/docker-compose.yml" ] && [ -f "$d/.env" ]; then
            echo "$d"
            return 0
        fi
    done
    return 1
}
platform=${PLATFORM_DIR:-$(find_app "$root/platform/moodle" "$root/platform")} \
    || fail "no platform found in $root/platform or $root/platform/moodle (set PLATFORM_DIR)"
site=${SITE_DIR:-$(find_app "$root/thinkera.academy" "$root/cms" "$root/site")} \
    || fail "no site found in $root/thinkera.academy, $root/cms or $root/site (set SITE_DIR)"
log "platform: $platform"
log "site: $site"

( cd "$platform" && sh "$here/export-platform.sh" >/dev/null ) || fail "the platform export"
log "platform done"
( cd "$site" && sh "$here/export-site.sh" >/dev/null ) || fail "the site export"
log "site done"

for f in moodle-db.dump moodledata.tgz site-db.dump site-media.tgz SHA256SUMS; do
    [ -f "$work/$f" ] || fail "$f was not written"
done

# A backup nobody can restore is not a backup: the checksums are verified before the folder is named.
( cd "$work" && sha256sum -c SHA256SUMS >/dev/null ) || fail "the checksums do not match what was written"
log "checksums verified"

rm -rf "$final"
mv "$work" "$final"
size=$(du -sh "$final" | cut -f1)
log "kept $size in $final"

# Older folders go, newest first, keeping $keep of them. Only folders this script names are touched.
old=$(ls -1d "$base"/20??-??-?? 2>/dev/null | sort -r | tail -n +"$((keep + 1))")
for d in $old; do
    rm -rf "$d"
    log "removed $d"
done
log "done; $(ls -1d "$base"/20??-??-?? 2>/dev/null | wc -l) backup(s) kept"
