thirdculture-docker/sync.sh

102 lines
4.7 KiB
Shell
Executable file

#!/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