#!/usr/bin/env bash # ./sync.sh live edits down → merge with yours → push to forgejo + live # ./sync.sh pull only bring live edits down (start of a work session) # ./sync.sh unify one time: fold the werc/ and werc/sites/ repos into this one, adopt it on live set -euo pipefail cd "$(dirname "$0")" HOST=${SITE_HOST:-chillin@192.168.2.69} BR=main LIVE=refs/remotes/live/$BR # Runs on home in the live checkout. git runs as werc's own user, so web edits and deploys share one owner. live() { set -euo pipefail cd /opt/thirdculture.top/site export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock g() { docker compose --progress quiet run --rm --no-deps -T -u lighttpd -v "$PWD:/s" -w /s --entrypoint git werc \ -c safe.directory='*' -c user.name=werc -c user.email=werc@thirdculture.diy "$@"; } case $1 in head) g rev-parse -q --verify main || true ;; commit) g add -A; g diff --cached --quiet || g commit -qm "users: live edits" ;; bundle) g bundle create -q - main ${2:+"^$2"} ;; deploy) cat > .incoming.bundle g fetch -q .incoming.bundle +main:refs/heads/incoming; rm -f .incoming.bundle [ -z "$(g status --porcelain)" ] || { echo "live changed during the sync, run it again" >&2; exit 1; } old=$(g rev-parse main) g merge -q --ff-only incoming g log --oneline "$old..main" if g diff --name-only "$old" main | grep -qE '^(Dockerfile|docker-compose.yml|init.sh|etc/)'; then docker compose up -d --build fi ;; adopt) cat > .incoming.bundle if [ -d werc/.git ]; then mkdir -p ../site-oldgit; mv werc/.git ../site-oldgit/werc.git; mv werc/sites/.git ../site-oldgit/sites.git fi rm -f werc/.gitignore docker compose --progress quiet run --rm --no-deps -T -u 0 -v "$PWD:/s" --entrypoint chown werc -R lighttpd /s g init -q -b main g fetch -q .incoming.bundle +refs/heads/unify-base:refs/heads/incoming; rm -f .incoming.bundle g reset -q incoming g checkout -- .gitignore g status --short ;; esac } on_live() { ssh "$HOST" "bash -c $(printf %q "$(declare -f live); live $*")"; } need_clean() { [ ! -d werc/.git ] || { echo "not one repo yet: run ./sync.sh unify first"; exit 1; } [ -z "$(git status --porcelain)" ] || { echo "commit or stash your changes first:"; git status --short; exit 1; } } pull_live() { on_live commit head=$(on_live head) [ -n "$head" ] || { echo "live isn't a git checkout yet: ./sync.sh unify"; exit 1; } base=$(git rev-parse -q --verify $LIVE || true) if [ "$head" != "$base" ]; then tmp=$(mktemp); on_live bundle "$base" > "$tmp" git fetch -q "$tmp" "+$BR:$LIVE"; rm -f "$tmp" fi git merge --no-edit $LIVE || { echo "conflict: fix the files, git commit, then ./sync.sh again"; exit 1; } } deploy() { git push -q origin $BR if git merge-base --is-ancestor HEAD $LIVE; then echo "live is up to date"; return; fi tmp=$(mktemp); git bundle create -q "$tmp" $BR "^$LIVE" on_live deploy < "$tmp"; rm -f "$tmp" git update-ref $LIVE $BR } unify() { [ -d werc/.git ] || { echo "already one repo"; return; } [ "$(git branch --show-current)" = $BR ] || { echo "switch to $BR first"; exit 1; } stage=$(mktemp -d); idx=$(mktemp -u) echo "== snapshot live" rsync -az --exclude=.git --exclude=/werc.tar.gz --exclude=/werc/etc/users/ --exclude=/werc/etc/misaki_sso.secret \ --exclude=.htpasswd --exclude=/scripts/.env/ "$HOST:/opt/thirdculture.top/site/" "$stage/" cp .gitignore "$stage/.gitignore"; rm -f "$stage/werc/.gitignore" GIT_INDEX_FILE=$idx git --work-tree="$stage" add -A c1=$(git commit-tree "$(GIT_INDEX_FILE=$idx git write-tree)" -p HEAD -m "site: live as it was, werc + sites folded in") rm -rf "$idx" "$stage" echo "== your local changes on top" mkdir -p ../site-oldgit; mv werc/.git ../site-oldgit/werc.git; mv werc/sites/.git ../site-oldgit/sites.git rm -f werc/.gitignore rm -rf werc/sites/default.cat-v.org werc/sites/tst.cat-v.org werc/sites/werc.cat-v.org werc/sites/CREATE-SITE-DIRECTORIES-HERE git update-ref refs/heads/$BR "$c1" git reset -q git add -A; git commit -qm "site: one repo, local changes since live" echo "== adopt on live" git branch -f unify-base "$c1" tmp=$(mktemp); git bundle create -q "$tmp" unify-base; on_live adopt < "$tmp"; rm -f "$tmp" git branch -D -q unify-base; git update-ref $LIVE "$c1" git remote set-url origin https://git.thirdculture.diy/q/thirdculture-docker.git echo "== deploy"; deploy } case ${1:-sync} in sync) need_clean; pull_live; deploy ;; pull) need_clean; pull_live ;; unify) unify ;; *) sed -n '2,4p' "$0"; exit 2 ;; esac