diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-30 00:40:10 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-30 00:40:10 +0100 |
| commit | 79588a8bba1648ea4d396a1d1e9884af54e497e2 (patch) | |
| tree | bcc795839e1b848bb8e4c5ba017aaef6e9399ecb /scripts | |
| parent | add publish script that names release artifacts from Cargo.toml and the targe... (diff) | |
| download | zagan-bet-79588a8bba1648ea4d396a1d1e9884af54e497e2.tar.gz zagan-bet-79588a8bba1648ea4d396a1d1e9884af54e497e2.zip | |
add deploy script with live verification; cache file hashes by size and mtime
Diffstat (limited to '')
| -rwxr-xr-x | scripts/deploy.sh | 136 | ||||
| -rwxr-xr-x | scripts/publish.sh | 3 |
2 files changed, 138 insertions, 1 deletions
diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..99129ad --- /dev/null +++ b/scripts/deploy.sh | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | #!/usr/bin/env bash | ||
| 2 | # Upload web/ and verify every published artifact over the public URL. | ||
| 3 | # | ||
| 4 | # Usage: | ||
| 5 | # ./scripts/deploy.sh user@host:/srv/zagan.bet https://zagan.bet/ | ||
| 6 | # ./scripts/deploy.sh /srv/staging http://127.0.0.1:8899/ | ||
| 7 | # ./scripts/deploy.sh --verify-only user@host:/srv/zagan.bet https://zagan.bet/ | ||
| 8 | # | ||
| 9 | # The target may be a local directory, which is handy for staging and for | ||
| 10 | # testing the verification itself. Old versions are left in place on purpose; | ||
| 11 | # prune them by hand when you want to drop them. | ||
| 12 | # | ||
| 13 | # Environment: | ||
| 14 | # DEPLOY_TARGET, DEPLOY_URL same as the two arguments | ||
| 15 | # SSH_PORT ssh port for a remote target | ||
| 16 | set -euo pipefail | ||
| 17 | |||
| 18 | ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) | ||
| 19 | cd "$ROOT" | ||
| 20 | |||
| 21 | die() { echo "deploy: $*" >&2; exit 1; } | ||
| 22 | |||
| 23 | VERIFY_ONLY=0 | ||
| 24 | if [ "${1:-}" = "--verify-only" ]; then | ||
| 25 | VERIFY_ONLY=1 | ||
| 26 | shift | ||
| 27 | fi | ||
| 28 | |||
| 29 | TARGET=${1:-${DEPLOY_TARGET:-}} | ||
| 30 | URL=${2:-${DEPLOY_URL:-}} | ||
| 31 | if [ -z "$TARGET" ] || [ -z "$URL" ]; then | ||
| 32 | cat >&2 <<'EOF' | ||
| 33 | usage: scripts/deploy.sh [--verify-only] <target> <url> | ||
| 34 | |||
| 35 | target user@host:/srv/zagan.bet or a local directory | ||
| 36 | url public URL of the page, e.g. https://zagan.bet/ | ||
| 37 | --verify-only skips the upload and only checks the live page | ||
| 38 | |||
| 39 | environment: | ||
| 40 | DEPLOY_TARGET, DEPLOY_URL same as the two arguments | ||
| 41 | SSH_PORT ssh port for a remote target | ||
| 42 | EOF | ||
| 43 | exit 2 | ||
| 44 | fi | ||
| 45 | |||
| 46 | for tool in rsync curl sha256sum; do | ||
| 47 | command -v "$tool" >/dev/null || die "$tool is required" | ||
| 48 | done | ||
| 49 | |||
| 50 | [ -f web/index.php ] || die "web/index.php is missing" | ||
| 51 | |||
| 52 | shopt -s nullglob | ||
| 53 | artifacts=(web/bin/client/zagan-bet-* web/bin/server/zagan-bet-*) | ||
| 54 | shopt -u nullglob | ||
| 55 | [ ${#artifacts[@]} -gt 0 ] || die "no artifacts in web/bin; run scripts/publish.sh first" | ||
| 56 | |||
| 57 | if [ "$VERIFY_ONLY" -eq 0 ]; then | ||
| 58 | echo "==> uploading web/ to $TARGET" | ||
| 59 | |||
| 60 | # --delay-updates writes to temp names and renames at the end, so a visitor | ||
| 61 | # never sees a half-written binary. Old versions are kept: no --delete. | ||
| 62 | RSYNC_FLAGS=( | ||
| 63 | -a --delay-updates --human-readable --chmod=D755,F644 | ||
| 64 | --exclude=README.md --exclude=.gitignore | ||
| 65 | ) | ||
| 66 | |||
| 67 | if [[ "$TARGET" == *:* ]]; then | ||
| 68 | host=${TARGET%%:*} | ||
| 69 | path=${TARGET#*:} | ||
| 70 | ssh_args=() | ||
| 71 | if [ -n "${SSH_PORT:-}" ]; then | ||
| 72 | ssh_args+=(-p "$SSH_PORT") | ||
| 73 | fi | ||
| 74 | ssh ${ssh_args[@]+"${ssh_args[@]}"} "$host" "mkdir -p $(printf '%q' "$path")" | ||
| 75 | rsync "${RSYNC_FLAGS[@]}" -e "ssh ${ssh_args[*]:-}" web/ "$host:$path/" | ||
| 76 | else | ||
| 77 | mkdir -p "$TARGET" | ||
| 78 | rsync "${RSYNC_FLAGS[@]}" web/ "$TARGET/" | ||
| 79 | fi | ||
| 80 | fi | ||
| 81 | |||
| 82 | echo "==> verifying $URL" | ||
| 83 | tmp=$(mktemp -d) | ||
| 84 | trap 'rm -rf "$tmp"' EXIT | ||
| 85 | |||
| 86 | curl -fsSL --max-time 30 "$URL" -o "$tmp/page.html" \ | ||
| 87 | || die "could not fetch $URL" | ||
| 88 | |||
| 89 | origin=$(printf '%s' "$URL" | sed -E 's#^(https?://[^/]+).*#\1#') | ||
| 90 | grep -oE '[0-9a-f]{64} [A-Za-z0-9._-]+' "$tmp/page.html" > "$tmp/sums" || true | ||
| 91 | [ -s "$tmp/sums" ] || die "no SHA-256 lines on the page (is index.php being served?)" | ||
| 92 | |||
| 93 | failed=0 | ||
| 94 | verified=0 | ||
| 95 | for local in "${artifacts[@]}"; do | ||
| 96 | [ -f "$local" ] || continue | ||
| 97 | |||
| 98 | file=$(basename "$local") | ||
| 99 | kind=$(basename "$(dirname "$local")") | ||
| 100 | local_hash=$(sha256sum "$local" | cut -d' ' -f1) | ||
| 101 | |||
| 102 | href=$(grep -oE "href=\"[^\"]*/bin/$kind/$file\"" "$tmp/page.html" | head -1 \ | ||
| 103 | | sed 's/^href="//;s/"$//' || true) | ||
| 104 | if [ -z "$href" ]; then | ||
| 105 | echo " $file: not listed on the page" | ||
| 106 | failed=1 | ||
| 107 | continue | ||
| 108 | fi | ||
| 109 | |||
| 110 | shown=$(awk -v name="$file" '$2 == name { print $1 }' "$tmp/sums" | head -1) | ||
| 111 | if [ "$shown" != "$local_hash" ]; then | ||
| 112 | echo " $file: page shows ${shown:-nothing}, local is $local_hash" | ||
| 113 | failed=1 | ||
| 114 | continue | ||
| 115 | fi | ||
| 116 | |||
| 117 | if ! curl -fsSL --max-time 120 "$origin$href" -o "$tmp/$file"; then | ||
| 118 | echo " $file: download failed" | ||
| 119 | failed=1 | ||
| 120 | continue | ||
| 121 | fi | ||
| 122 | |||
| 123 | remote_hash=$(sha256sum "$tmp/$file" | cut -d' ' -f1) | ||
| 124 | if [ "$remote_hash" != "$local_hash" ]; then | ||
| 125 | echo " $file: downloaded bytes differ from local" | ||
| 126 | failed=1 | ||
| 127 | continue | ||
| 128 | fi | ||
| 129 | |||
| 130 | echo " $file: ok" | ||
| 131 | verified=$((verified + 1)) | ||
| 132 | done | ||
| 133 | |||
| 134 | [ "$failed" -eq 0 ] || die "verification failed" | ||
| 135 | |||
| 136 | echo "==> $verified artifact(s) verified at $URL" | ||
diff --git a/scripts/publish.sh b/scripts/publish.sh index d8cc77a..8240859 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh | |||
| @@ -27,7 +27,7 @@ DEST=${DEST:-web/bin} | |||
| 27 | publish() { | 27 | publish() { |
| 28 | local triple=$1 kind=$2 platform=$3 arch=$4 | 28 | local triple=$1 kind=$2 platform=$3 arch=$4 |
| 29 | local ext="" | 29 | local ext="" |
| 30 | if [ "$kind" = client ] && [ "$platform" = windows ]; then | 30 | if [ "$platform" = windows ]; then |
| 31 | ext=".exe" | 31 | ext=".exe" |
| 32 | fi | 32 | fi |
| 33 | 33 | ||
| @@ -51,6 +51,7 @@ publish x86_64-unknown-linux-gnu client linux x86_64 | |||
| 51 | publish i686-unknown-linux-gnu client linux i686 | 51 | publish i686-unknown-linux-gnu client linux i686 |
| 52 | publish x86_64-pc-windows-gnu client windows x86_64 | 52 | publish x86_64-pc-windows-gnu client windows x86_64 |
| 53 | publish x86_64-unknown-linux-gnu server linux x86_64 | 53 | publish x86_64-unknown-linux-gnu server linux x86_64 |
| 54 | publish x86_64-pc-windows-gnu server windows x86_64 | ||
| 54 | 55 | ||
| 55 | echo | 56 | echo |
| 56 | echo "published $VERSION to $DEST" | 57 | echo "published $VERSION to $DEST" |
