summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xscripts/deploy.sh24
-rwxr-xr-xscripts/publish.sh37
-rw-r--r--scripts/render-installer.py49
-rw-r--r--web/install.ps1 (renamed from scripts/installers/windows.ps1.in)45
-rw-r--r--web/install.sh (renamed from scripts/installers/linux.sh.in)50
5 files changed, 100 insertions, 105 deletions
diff --git a/scripts/deploy.sh b/scripts/deploy.sh
index b18d462..63bd31c 100755
--- a/scripts/deploy.sh
+++ b/scripts/deploy.sh
@@ -95,6 +95,20 @@ origin=$(printf '%s' "$URL" | sed -E 's#^(https?://[^/]+).*#\1#')
95grep -oE '[0-9a-f]{64} [A-Za-z0-9._-]+' "$tmp/page.html" > "$tmp/sums" || true 95grep -oE '[0-9a-f]{64} [A-Za-z0-9._-]+' "$tmp/page.html" > "$tmp/sums" || true
96[ -s "$tmp/sums" ] || die "no SHA-256 lines on the page (is index.php being served?)" 96[ -s "$tmp/sums" ] || die "no SHA-256 lines on the page (is index.php being served?)"
97 97
98for script in install.sh install.ps1; do
99 grep -qE "href=\"[^\"]*/$script\"" "$tmp/page.html" \
100 || die "$script is not linked from the page"
101 curl -fsSL --max-time 30 "$origin/$script" -o "$tmp/$script" \
102 || die "could not fetch $script"
103 cmp -s "web/$script" "$tmp/$script" \
104 || die "$script served from the site differs from the local file"
105done
106
107curl -fsSL --max-time 30 "$origin/latest.php" -o "$tmp/latest.txt" \
108 || die "could not fetch latest.php"
109newest=$(awk '$1 == "version" { print $2; exit }' "$tmp/latest.txt")
110[ -n "$newest" ] || die "latest.php has no version line"
111
98failed=0 112failed=0
99verified=0 113verified=0
100for local in "${artifacts[@]}"; do 114for local in "${artifacts[@]}"; do
@@ -132,6 +146,16 @@ for local in "${artifacts[@]}"; do
132 continue 146 continue
133 fi 147 fi
134 148
149 version=$(printf '%s' "$file" | sed -E 's/^zagan-bet-[a-z]+-([0-9]+\.[0-9]+\.[0-9]+)-.*/\1/')
150 if [ "$version" = "$newest" ]; then
151 latest_hash=$(awk -v kind="$kind" -v name="$file" '$1 == kind && $5 == name { print $6 }' "$tmp/latest.txt")
152 if [ "$latest_hash" != "$local_hash" ]; then
153 echo " $file: latest.php shows ${latest_hash:-nothing}, local is $local_hash"
154 failed=1
155 continue
156 fi
157 fi
158
135 echo " $file: ok" 159 echo " $file: ok"
136 verified=$((verified + 1)) 160 verified=$((verified + 1))
137done 161done
diff --git a/scripts/publish.sh b/scripts/publish.sh
index 3a04631..fbcd588 100755
--- a/scripts/publish.sh
+++ b/scripts/publish.sh
@@ -5,20 +5,19 @@
5# zagan-bet-client-<version>-<platform>-<arch>[.exe] 5# zagan-bet-client-<version>-<platform>-<arch>[.exe]
6# zagan-bet-server-<version>-<platform>-<arch>[.exe] 6# zagan-bet-server-<version>-<platform>-<arch>[.exe]
7# zagan-bet-gui-<version>-<platform>-<arch>[.exe] 7# zagan-bet-gui-<version>-<platform>-<arch>[.exe]
8# zagan-bet-gui-<version>-<platform>-<arch>-install.sh
9# zagan-bet-gui-<version>-<platform>-<arch>-install.ps1
10# 8#
11# Cargo always writes target/<triple>/<profile>/<bin>, so the rename happens 9# Cargo always writes target/<triple>/<profile>/<bin>, so the rename happens
12# here after each build. The version comes from Cargo.toml. 10# here after each build. The version comes from Cargo.toml.
13# 11#
14# The GUI uses the workspace's `gui-release` profile (small, stripped, LTO). 12# The GUI uses the workspace's `gui-release` profile (small, stripped, LTO).
15# The public git repository is the GPL source for these binaries, so publish 13# The installers are stable site files (web/install.sh and web/install.ps1):
16# from a clean tree (or set ALLOW_DIRTY=1 for a preview). 14# they ask web/latest.php for the newest build, so they are not regenerated
15# here. The public git repository is the GPL source for these binaries, so
16# publish from a clean tree (or set ALLOW_DIRTY=1 for a preview).
17# 17#
18# Usage: 18# Usage:
19# ./scripts/publish.sh 19# ./scripts/publish.sh
20# DEST=/srv/www/bin ./scripts/publish.sh 20# DEST=/srv/www/bin ./scripts/publish.sh
21# URL_BASE=https://staging.example/ ./scripts/publish.sh
22set -euo pipefail 21set -euo pipefail
23 22
24ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) 23ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
@@ -31,22 +30,12 @@ if [ -z "${VERSION:-}" ]; then
31fi 30fi
32 31
33DEST=${DEST:-web/bin} 32DEST=${DEST:-web/bin}
34URL_BASE=${URL_BASE:-https://zagan.2137697.xyz}
35 33
36if [ "${ALLOW_DIRTY:-0}" != "1" ] && [ -n "$(git status --porcelain)" ]; then 34if [ "${ALLOW_DIRTY:-0}" != "1" ] && [ -n "$(git status --porcelain)" ]; then
37 echo "the working tree is dirty; commit the release first (or ALLOW_DIRTY=1)" >&2 35 echo "the working tree is dirty; commit the release first (or ALLOW_DIRTY=1)" >&2
38 exit 1 36 exit 1
39fi 37fi
40 38
41command -v python3 >/dev/null || {
42 echo "python3 is required to render the installers" >&2
43 exit 1
44}
45
46hash_of() {
47 sha256sum "$1" | awk '{print $1}'
48}
49
50publish() { 39publish() {
51 local triple=$1 kind=$2 platform=$3 arch=$4 40 local triple=$1 kind=$2 platform=$3 arch=$4
52 local ext="" 41 local ext=""
@@ -85,23 +74,13 @@ publish_gui() {
85 74
86 mkdir -p "$DEST/gui" 75 mkdir -p "$DEST/gui"
87 install -m 0755 "$source" "$DEST/gui/$artifact" 76 install -m 0755 "$source" "$DEST/gui/$artifact"
88 local sha
89 sha=$(hash_of "$DEST/gui/$artifact")
90 echo " $DEST/gui/$artifact ($(du -h "$DEST/gui/$artifact" | cut -f1))" 77 echo " $DEST/gui/$artifact ($(du -h "$DEST/gui/$artifact" | cut -f1))"
91
92 if [ "$platform" = linux ]; then
93 python3 scripts/render-installer.py \
94 scripts/installers/linux.sh.in \
95 "$DEST/gui/zagan-bet-gui-$VERSION-linux-$arch-install.sh" \
96 "$VERSION" "$artifact" "$sha" "$URL_BASE/bin/gui/$artifact"
97 elif [ "$platform" = windows ]; then
98 python3 scripts/render-installer.py \
99 scripts/installers/windows.ps1.in \
100 "$DEST/gui/zagan-bet-gui-$VERSION-windows-$arch-install.ps1" \
101 "$VERSION" "$artifact" "$sha" "$URL_BASE/bin/gui/$artifact"
102 fi
103} 78}
104 79
80rm web/bin/client/*
81rm web/bin/gui/*
82rm web/bin/server/*
83
105publish_gui x86_64-unknown-linux-gnu linux x86_64 84publish_gui x86_64-unknown-linux-gnu linux x86_64
106publish_gui x86_64-pc-windows-gnu windows x86_64 85publish_gui x86_64-pc-windows-gnu windows x86_64
107 86
diff --git a/scripts/render-installer.py b/scripts/render-installer.py
deleted file mode 100644
index 1a00551..0000000
--- a/scripts/render-installer.py
+++ /dev/null
@@ -1,49 +0,0 @@
1#!/usr/bin/env python3
2"""Fill an installer template with one published artifact's details.
3
4Usage: render-installer.py <template> <output> <version> <binary> <sha256> <url>
5
6The Linux template embeds the application icon so the installer works offline.
7"""
8
9from __future__ import annotations
10
11import pathlib
12import sys
13
14
15def main(argv: list[str]) -> int:
16 if len(argv) != 7:
17 print(
18 "usage: render-installer.py <template> <output> <version> "
19 "<binary> <sha256> <url>",
20 file=sys.stderr,
21 )
22 return 2
23
24 template, output, version, binary, sha256, url = argv[1:]
25 root = pathlib.Path(__file__).resolve().parent.parent
26 icon = (root / "gui" / "assets" / "zagan-bet.svg").read_text()
27
28 text = pathlib.Path(template).read_text()
29 replacements = {
30 "__VERSION__": version,
31 "__BINARY__": binary,
32 "__SHA256__": sha256,
33 "__URL__": url,
34 "__ICON__": icon.rstrip("\n"),
35 }
36 for placeholder, value in replacements.items():
37 text = text.replace(placeholder, value)
38
39 destination = pathlib.Path(output)
40 destination.write_text(text)
41 if destination.suffix == ".sh":
42 destination.chmod(0o755)
43
44 print(f" {destination} ({destination.stat().st_size} bytes)")
45 return 0
46
47
48if __name__ == "__main__":
49 raise SystemExit(main(sys.argv))
diff --git a/scripts/installers/windows.ps1.in b/web/install.ps1
index 4b8e61d..92eef83 100644
--- a/scripts/installers/windows.ps1.in
+++ b/web/install.ps1
@@ -1,21 +1,18 @@
1# Zagan-Bet desktop installer for Windows. 1# Zagan-Bet installer for Windows.
2# 2#
3# Verifies the app against its published SHA-256, installs it for the current 3# Asks the site which build is newest, verifies its SHA-256, installs it for
4# user and adds a Start-menu shortcut. Put the downloaded app next to this 4# the current user and adds a Start-menu shortcut. Point it at a staging site
5# script, or run the script on its own and it will fetch the matching binary. 5# with -Site http://127.0.0.1:8899; add -NoPause for automation.
6# 6#
7# Run it with: 7# Run it with:
8# powershell -ExecutionPolicy Bypass -File .\zagan-bet-gui-*-install.ps1 8# powershell -ExecutionPolicy Bypass -File .\install.ps1
9# Add -NoPause to run it unattended. 9param(
10param([switch]$NoPause) 10 [string]$Site = "https://zagan.2137697.xyz",
11 [switch]$NoPause
12)
11 13
12$ErrorActionPreference = "Stop" 14$ErrorActionPreference = "Stop"
13 15
14$Version = "__VERSION__"
15$Binary = "__BINARY__"
16$Sha256 = "__SHA256__"
17$Url = "__URL__"
18
19function Finish([int]$Code) { 16function Finish([int]$Code) {
20 if (-not $NoPause) { 17 if (-not $NoPause) {
21 Read-Host "Press Enter to close" | Out-Null 18 Read-Host "Press Enter to close" | Out-Null
@@ -28,6 +25,30 @@ function Stop-Install([string]$Message) {
28 Finish 1 25 Finish 1
29} 26}
30 27
28try {
29 $latest = (Invoke-WebRequest -Uri "$Site/latest.php" -UseBasicParsing).Content
30} catch {
31 Stop-Install "could not read $Site/latest.php: $_"
32}
33
34$line = ($latest -split "`r?`n") |
35 Where-Object { $_ -match '^gui windows x86_64 ' } |
36 Select-Object -First 1
37if (-not $line) {
38 Stop-Install "no Windows build is published yet"
39}
40
41$parts = $line.Trim() -split '\s+'
42if ($parts.Count -lt 6) {
43 Stop-Install "the latest-build file is malformed"
44}
45$Version = $parts[3]
46$Binary = $parts[4]
47$Sha256 = $parts[5]
48$Url = "$Site/bin/gui/$Binary"
49
50Write-Host "Newest Zagan-Bet is $Version."
51
31$here = Split-Path -Parent $MyInvocation.MyCommand.Path 52$here = Split-Path -Parent $MyInvocation.MyCommand.Path
32$candidates = @( 53$candidates = @(
33 (Join-Path $here $Binary), 54 (Join-Path $here $Binary),
diff --git a/scripts/installers/linux.sh.in b/web/install.sh
index 5b53c02..998b262 100644
--- a/scripts/installers/linux.sh.in
+++ b/web/install.sh
@@ -1,24 +1,38 @@
1#!/usr/bin/env bash 1#!/usr/bin/env bash
2# Zagan-Bet desktop installer for Linux. 2# Zagan-Bet installer for Linux.
3# 3#
4# Verifies the app against its published SHA-256, installs it for the current 4# Asks the site which build is newest, verifies its SHA-256, installs it for
5# user and adds a launcher. Put the downloaded app next to this script, or run 5# the current user and adds a launcher. Point it at a staging site with
6# the script on its own and it will fetch the matching binary. 6# ZAGAN_SITE=http://127.0.0.1:8899.
7set -euo pipefail 7set -euo pipefail
8 8
9VERSION="__VERSION__" 9SITE=${ZAGAN_SITE:-https://zagan.2137697.xyz}
10BINARY="__BINARY__" 10PLATFORM=linux
11SHA256="__SHA256__" 11ARCH=x86_64
12URL="__URL__"
13 12
14say() { printf '%s\n' "$*"; } 13say() { printf '%s\n' "$*"; }
15die() { printf 'install: %s\n' "$*" >&2; exit 1; } 14die() { printf 'install: %s\n' "$*" >&2; exit 1; }
16 15
16command -v curl >/dev/null 2>&1 || die "curl is required"
17command -v sha256sum >/dev/null 2>&1 || die "sha256sum is required" 17command -v sha256sum >/dev/null 2>&1 || die "sha256sum is required"
18 18
19latest=$(curl -fsSL --max-time 30 "$SITE/latest.php") \
20 || die "could not read $SITE/latest.php"
21line=$(printf '%s\n' "$latest" \
22 | awk -v p="$PLATFORM" -v a="$ARCH" '$1 == "gui" && $2 == p && $3 == a { print; exit }')
23[ -n "$line" ] || die "no Linux build is published yet"
24
25version=$(printf '%s\n' "$line" | awk '{print $4}')
26binary=$(printf '%s\n' "$line" | awk '{print $5}')
27sha=$(printf '%s\n' "$line" | awk '{print $6}')
28[ -n "$version" ] && [ -n "$binary" ] && [ -n "$sha" ] \
29 || die "the latest-build file is malformed"
30
31say "Newest Zagan-Bet is $version."
32
19here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) 33here=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
20source_file="" 34source_file=""
21for candidate in "$here/$BINARY" "./$BINARY" "$HOME/Downloads/$BINARY"; do 35for candidate in "$here/$binary" "./$binary" "$HOME/Downloads/$binary"; do
22 if [ -f "$candidate" ]; then 36 if [ -f "$candidate" ]; then
23 source_file=$candidate 37 source_file=$candidate
24 break 38 break
@@ -27,16 +41,17 @@ done
27 41
28cleanup="" 42cleanup=""
29if [ -z "$source_file" ]; then 43if [ -z "$source_file" ]; then
30 command -v curl >/dev/null 2>&1 || die "put $BINARY next to this installer, or install curl"
31 cleanup=$(mktemp) || die "cannot create a temporary file" 44 cleanup=$(mktemp) || die "cannot create a temporary file"
32 say "Downloading $BINARY..." 45 say "Downloading $binary..."
33 curl -fsSL --max-time 300 "$URL" -o "$cleanup" || die "download failed" 46 curl -fsSL --max-time 300 "$SITE/bin/gui/$binary" -o "$cleanup" \
47 || die "download failed"
34 source_file=$cleanup 48 source_file=$cleanup
35fi 49fi
36trap 'if [ -n "$cleanup" ]; then rm -f "$cleanup"; fi' EXIT 50trap 'if [ -n "$cleanup" ]; then rm -f "$cleanup"; fi' EXIT
37 51
38actual=$(sha256sum "$source_file" | awk '{print $1}') 52actual=$(sha256sum "$source_file" | awk '{print $1}')
39[ "$actual" = "$SHA256" ] || die "checksum mismatch: expected $SHA256, got $actual" 53[ "$actual" = "$sha" ] \
54 || die "checksum mismatch: expected $sha, got $actual"
40 55
41bin_dir="${XDG_BIN_HOME:-$HOME/.local/bin}" 56bin_dir="${XDG_BIN_HOME:-$HOME/.local/bin}"
42data_dir="${XDG_DATA_HOME:-$HOME/.local/share}" 57data_dir="${XDG_DATA_HOME:-$HOME/.local/share}"
@@ -48,7 +63,12 @@ mkdir -p "$bin_dir" "$desktop_dir" "$icon_dir"
48install -m 0755 "$source_file" "$app" 63install -m 0755 "$source_file" "$app"
49 64
50cat > "$icon_dir/zagan-bet.svg" <<'ICON' 65cat > "$icon_dir/zagan-bet.svg" <<'ICON'
51__ICON__ 66<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64">
67 <rect width="64" height="64" rx="14" fill="#0a0e12"/>
68 <rect x="9" y="9" width="46" height="46" rx="10" fill="#0f1a14" stroke="#1f7d52" stroke-width="2"/>
69 <path d="M22 20h20L22 44h20" fill="none" stroke="#4ec27b" stroke-width="6"
70 stroke-linecap="round" stroke-linejoin="round"/>
71</svg>
52ICON 72ICON
53 73
54cat > "$desktop_dir/zagan-bet.desktop" <<DESKTOP 74cat > "$desktop_dir/zagan-bet.desktop" <<DESKTOP
@@ -70,7 +90,7 @@ if command -v gtk-update-icon-cache >/dev/null 2>&1; then
70 gtk-update-icon-cache -q "$data_dir/icons/hicolor" >/dev/null 2>&1 || true 90 gtk-update-icon-cache -q "$data_dir/icons/hicolor" >/dev/null 2>&1 || true
71fi 91fi
72 92
73say "Installed Zagan-Bet $VERSION to $app" 93say "Installed Zagan-Bet $version to $app"
74say "A launcher was added to your applications menu." 94say "A launcher was added to your applications menu."
75case ":$PATH:" in 95case ":$PATH:" in
76 *":$bin_dir:"*) ;; 96 *":$bin_dir:"*) ;;