#!/bin/bash
# Build a machine-readable source archive for EUPL-1.2 Article 5 compliance.
# Run on the production host after every deploy.
#
# Output:  /opt/stats/public/source.zip
# Served:  https://stats.wise-relations.com/source.zip
# Linked:  tpl/impressum.gohtml (Quellcode und Lizenzen)
#
# Two modes:
#   1. $REPO_DIR contains .git     → git archive HEAD (commit SHA in prefix)
#   2. $REPO_DIR is a plain tree   → zip working tree (UTC timestamp in prefix)
#
# Both satisfy EUPL-5 “complete source code of the deployed version”.
# Mode 2 exists so deploys without a git checkout (e.g. tar-transfer) don't
# leave /source.zip stale.

set -euo pipefail

REPO_DIR="${REPO_DIR:-/opt/stats/src}"
OUT_DIR="${OUT_DIR:-/opt/stats/public}"
OUT_FILE="$OUT_DIR/source.zip"

[[ -d "$REPO_DIR" ]] || { echo "error: $REPO_DIR does not exist" >&2; exit 1; }
mkdir -p "$OUT_DIR"

if [[ -d "$REPO_DIR/.git" ]]; then
    cd "$REPO_DIR"
    sha="$(git rev-parse --short HEAD)"
    prefix="stats.wise-relations.com-$sha"
    git archive --format=zip --prefix="$prefix/" -o "$OUT_FILE.tmp" HEAD
    ident="commit $sha"
else
    command -v zip >/dev/null \
        || { echo "error: zip not installed (apt install zip)" >&2; exit 1; }

    stamp="$(date -u +%Y%m%d-%H%M%S)"
    prefix="stats.wise-relations.com-$stamp"

    # Stage under the same filesystem as REPO_DIR so `cp -al` hardlinks work.
    parent="$(dirname "$REPO_DIR")"
    staging="$parent/.source-staging-$$"
    trap 'rm -rf "$staging"' EXIT

    mkdir -p "$staging"
    # Hardlink if possible (near-instant, no disk copy); fall back to real copy.
    cp -al "$REPO_DIR" "$staging/$prefix" 2>/dev/null \
        || cp -a "$REPO_DIR" "$staging/$prefix"

    # Strip things that don't belong in a source distribution.
    rm -rf "$staging/$prefix/.git" \
           "$staging/$prefix/data" \
           "$staging/$prefix/node_modules"
    find "$staging/$prefix" -maxdepth 2 -name 'goatcounter'       -type f -delete 2>/dev/null || true
    find "$staging/$prefix" -maxdepth 2 -name 'goatcounter.exe*'          -delete 2>/dev/null || true
    find "$staging/$prefix"              -name '*.sqlite'                 -delete 2>/dev/null || true
    find "$staging/$prefix"              -name '*.sqlite-*'               -delete 2>/dev/null || true

    (cd "$staging" && zip -r -q "$OUT_FILE.tmp" "$prefix")
    ident="snapshot $stamp (working tree; no git history)"
fi

mv "$OUT_FILE.tmp" "$OUT_FILE"
echo "Wrote $OUT_FILE ($(stat -c%s "$OUT_FILE") bytes, $ident)"
