Files
mtgc/scripts/sync-server-image.sh
Garrett Mills de55fc634a Replace folder sync with an HTTP sync server, keeping the app offline-first
Folder sync left too much to the user's sync tool: platform file access
(the Android SAF plugin), choosing the document, merging conflict copies —
and its merge base could fall out of step with the document (absorbing
conflict copies, "forget", picking a new Android folder), reading every
difference as a deletion.

The new mtgc-server crate stores one versioned library per user and accepts
a write only when it names the version it replaces. It never merges: devices
still do that with merge3, through a new sync cycle over a `Remote` trait in
mtgc-core. The base advances only on knowledge — to what was read, or to a
write the server confirmed — and is stored with the server and account it
belongs to, so a different account starts from an empty ancestor instead of
deleting. The working copy is only rewritten under the app-state lock, and
sync commands now run off the main thread.

Sign-in happens in the browser on the server's pages, via the owner's OIDC
provider and/or local username/password accounts (Argon2id, managed with
`mtgc-server user ...`), and returns a per-device revocable token to the app
by PKCE-protected code: a loopback port on desktop, the mtgc:// scheme on
Android.

The Info tab gains sign-in, the first-sync combine/replace choice, the
account's devices, and JSON export/import; the top bar shows sync state.
Includes a Dockerfile, Compose/Caddy example, and scripts to build and push
${DOCKER_REGISTRY}/mtgc/sync-server.
2026-10-08 22:32:08 -05:00

69 lines
1.9 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# sync-server-image.sh — build or push the mtgc sync server's container image.
#
# The image is tagged ${DOCKER_REGISTRY}/mtgc/sync-server:${IMAGE_TAG}.
#
# Usage:
# DOCKER_REGISTRY=registry.example.com ./scripts/sync-server-image.sh build
# DOCKER_REGISTRY=registry.example.com ./scripts/sync-server-image.sh push
#
# Or through npm: `npm run sync-server:build` / `npm run sync-server:push`.
#
# Environment:
# DOCKER_REGISTRY (required) registry host, optionally with a namespace path
# IMAGE_TAG tag to build/push (default: latest)
# CONTAINER_ENGINE docker or podman (default: docker if installed, else podman)
#
# `push` pushes what `build` produced; it doesn't rebuild. Log in to the
# registry first (`docker login "$DOCKER_REGISTRY"`).
#
set -euo pipefail
usage() {
sed -n '3,20p' "$0" | sed 's/^# \{0,1\}//'
exit "${1:-0}"
}
[ $# -eq 1 ] || usage 1
case "$1" in
build | push) action="$1" ;;
-h | --help) usage ;;
*) usage 1 ;;
esac
if [ -z "${DOCKER_REGISTRY:-}" ]; then
echo "sync-server-image: set DOCKER_REGISTRY (e.g. registry.example.com)" >&2
exit 1
fi
engine="${CONTAINER_ENGINE:-}"
if [ -z "$engine" ]; then
if command -v docker >/dev/null 2>&1; then
engine=docker
elif command -v podman >/dev/null 2>&1; then
engine=podman
else
echo "sync-server-image: neither docker nor podman is installed" >&2
exit 1
fi
fi
image="${DOCKER_REGISTRY%/}/mtgc/sync-server:${IMAGE_TAG:-latest}"
# The Dockerfile builds from the workspace root, so run from there whatever
# directory this was invoked in.
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$repo_root"
case "$action" in
build)
echo "==> building $image"
"$engine" build -f crates/mtgc-server/Dockerfile -t "$image" .
;;
push)
echo "==> pushing $image"
"$engine" push "$image"
;;
esac