Files
featherChat/warzone/scripts/build-bleeding.sh
Siavash Sameni 9dd7341809 fix: build-bleeding uses fedora-43
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 10:06:10 +04:00

284 lines
8.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Build featherChat Linux x86_64 bleeding-edge binaries on Hetzner Cloud.
# Uses latest Fedora VM + Arch Linux Docker container for the actual build.
#
# Usage:
# ./scripts/build-bleeding.sh --all Create VM + build + download
# ./scripts/build-bleeding.sh --ship Build + deploy to all servers + destroy
# ./scripts/build-bleeding.sh --prepare Create VM only
# ./scripts/build-bleeding.sh --build Build in Arch Docker container
# ./scripts/build-bleeding.sh --transfer Download binaries
# ./scripts/build-bleeding.sh --destroy Delete VM
VM_NAME="fc-bleeding"
SSH_KEY_NAME="wz"
SSH_KEY_PATH="/Users/manwe/CascadeProjects/wzp"
SERVER_TYPE="cx33"
IMAGE="fedora-43"
REMOTE_USER="root"
OUTPUT_DIR="target/linux-x86_64-bleeding"
PROJECT_DIR="/Users/manwe/CascadeProjects/featherChat/warzone"
SSH_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10"
BINS="warzone-server warzone-client"
# Production servers (shared with build-linux.sh)
PROD_SERVERS=("root@mequ" "root@kh3rad3ree")
PROD_SERVICE="warzone-server"
PROD_BIN_DIR="/home/warzone"
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
get_vm_ip() {
local ip
ip=$(hcloud server list -o columns=name,ipv4 -o noheader 2>/dev/null | grep "$VM_NAME" | awk '{print $2}' | tr -d ' ')
if [ -z "$ip" ]; then
echo "ERROR: No VM '$VM_NAME' found. Run --prepare first." >&2
exit 1
fi
echo "$ip"
}
ssh_cmd() {
local ip
ip=$(get_vm_ip)
ssh $SSH_OPTS -i "$SSH_KEY_PATH" "$REMOTE_USER@$ip" "$@"
}
# ---------------------------------------------------------------------------
# --prepare: Create Fedora VM, install Docker
# ---------------------------------------------------------------------------
do_prepare() {
local existing
existing=$(hcloud server list -o columns=name -o noheader 2>/dev/null | grep "$VM_NAME" || true)
if [ -n "$existing" ]; then
echo "VM already exists: $existing"
echo "Reusing it. Uploading fresh source..."
do_upload
return
fi
echo "[1/5] Creating Hetzner VM: $VM_NAME ($SERVER_TYPE, $IMAGE)..."
hcloud server create \
--name "$VM_NAME" \
--type "$SERVER_TYPE" \
--image "$IMAGE" \
--ssh-key "$SSH_KEY_NAME" \
--location fsn1 \
--quiet
local ip
ip=$(get_vm_ip)
echo " VM: $VM_NAME @ $ip"
echo "[2/5] Waiting for SSH..."
for i in $(seq 1 30); do
if ssh $SSH_OPTS -i "$SSH_KEY_PATH" "$REMOTE_USER@$ip" "echo ok" &>/dev/null; then
break
fi
sleep 2
done
echo "[3/5] Installing Docker on Fedora..."
ssh_cmd "dnf install -y -q docker > /dev/null 2>&1 && systemctl start docker && systemctl enable docker" 2>/dev/null
echo "[4/5] Pulling Arch Linux Docker image..."
ssh_cmd "docker pull archlinux:latest" 2>/dev/null
echo "[5/5] Uploading source..."
do_upload
echo ""
echo "=== VM Ready ==="
echo "IP: $ip"
echo "Next: ./scripts/build-bleeding.sh --build"
}
do_upload() {
echo " Creating source tarball..."
tar czf /tmp/fc-bleeding-src.tar.gz \
--exclude='target' \
--exclude='.git' \
--exclude='.claude' \
--exclude='warzone-phone' \
--exclude='notes' \
-C "$PROJECT_DIR" . 2>/dev/null
local ip
ip=$(get_vm_ip)
local size
size=$(du -h /tmp/fc-bleeding-src.tar.gz | cut -f1)
echo " Uploading $size to VM..."
scp $SSH_OPTS -i "$SSH_KEY_PATH" /tmp/fc-bleeding-src.tar.gz "$REMOTE_USER@$ip:/root/fc-bleeding-src.tar.gz" 2>/dev/null
ssh_cmd "rm -rf /root/featherChat && mkdir -p /root/featherChat && tar xzf /root/fc-bleeding-src.tar.gz -C /root/featherChat" 2>/dev/null
rm -f /tmp/fc-bleeding-src.tar.gz
echo " Source uploaded."
}
# ---------------------------------------------------------------------------
# --build: Build inside Arch Linux Docker container
# ---------------------------------------------------------------------------
do_build() {
local ip
ip=$(get_vm_ip)
echo "=== Bleeding Edge Build on $ip ==="
echo " Host: Fedora ($IMAGE)"
echo " Build: Arch Linux (Docker, latest)"
echo ""
echo "[1/3] Building in Arch Linux container..."
ssh_cmd "docker run --rm -v /root/featherChat:/build -w /build archlinux:latest bash -c '
# Install deps
pacman -Sy --noconfirm base-devel pkg-config openssl rustup wasm-pack > /dev/null 2>&1
rustup default stable 2>/dev/null
rustup target add wasm32-unknown-unknown 2>/dev/null
# Build WASM
echo \"[wasm] Building...\"
wasm-pack build crates/warzone-wasm --target web --out-dir ../../wasm-pkg 2>&1 | tail -3
# Build release binaries
echo \"[cargo] Building release...\"
cargo build --release --bin warzone-server --bin warzone-client 2>&1
'"
echo ""
echo "[2/3] Verifying binaries..."
ssh_cmd "ls -lh /root/featherChat/target/release/warzone-server /root/featherChat/target/release/warzone-client"
echo ""
echo "[3/3] Checking linked libraries..."
ssh_cmd "docker run --rm -v /root/featherChat:/build archlinux:latest ldd /build/target/release/warzone-server | head -10"
echo ""
echo "=== Build Complete ==="
echo "Next: ./scripts/build-bleeding.sh --transfer"
}
# ---------------------------------------------------------------------------
# --transfer: Download binaries
# ---------------------------------------------------------------------------
do_transfer() {
local ip
ip=$(get_vm_ip)
echo "=== Downloading bleeding-edge binaries from $ip ==="
mkdir -p "$OUTPUT_DIR"
for bin in $BINS; do
echo " $bin..."
scp $SSH_OPTS -i "$SSH_KEY_PATH" "$REMOTE_USER@$ip:/root/featherChat/target/release/$bin" "$OUTPUT_DIR/$bin" 2>/dev/null
done
# Copy federation example
scp $SSH_OPTS -i "$SSH_KEY_PATH" "$REMOTE_USER@$ip:/root/featherChat/federation.example.json" "$OUTPUT_DIR/" 2>/dev/null || true
echo ""
echo "=== Transfer Complete ==="
ls -lh "$OUTPUT_DIR"/warzone-*
echo ""
echo "Built with: Arch Linux latest (bleeding edge)"
echo "Deploy: scp $OUTPUT_DIR/warzone-server $OUTPUT_DIR/warzone-client user@server:~/warzone/"
}
# ---------------------------------------------------------------------------
# --destroy
# ---------------------------------------------------------------------------
do_destroy() {
local existing
existing=$(hcloud server list -o columns=name -o noheader 2>/dev/null | grep "$VM_NAME" || true)
if [ -z "$existing" ]; then
echo "No VM '$VM_NAME' to destroy."
return
fi
echo "Deleting VM: $VM_NAME"
hcloud server delete "$VM_NAME"
echo "Done."
}
# ---------------------------------------------------------------------------
# --update-all / --ship
# ---------------------------------------------------------------------------
do_update() {
local host="$1"
echo "=== Updating $host (bleeding) ==="
ssh "$host" "systemctl stop $PROD_SERVICE 2>/dev/null || true"
scp "$OUTPUT_DIR/warzone-server" "$OUTPUT_DIR/warzone-client" "$host:$PROD_BIN_DIR/"
ssh "$host" "chmod +x $PROD_BIN_DIR/warzone-server $PROD_BIN_DIR/warzone-client && systemctl start $PROD_SERVICE"
sleep 1
local status
status=$(ssh "$host" "systemctl is-active $PROD_SERVICE 2>/dev/null" || true)
echo " $host: $status"
}
do_update_all() {
for host in "${PROD_SERVERS[@]}"; do
do_update "$host"
done
}
do_ship() {
echo "========================================"
echo " SHIPPING (bleeding edge) to production"
echo "========================================"
echo ""
do_prepare
echo ""
do_build
echo ""
do_transfer
echo ""
do_update_all
echo ""
do_destroy
echo ""
echo "========================================"
echo " BLEEDING EDGE SHIP COMPLETE"
echo "========================================"
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
case "${1:-}" in
--prepare) do_prepare ;;
--build) do_build ;;
--transfer) do_transfer ;;
--destroy) do_destroy ;;
--upload) do_upload ;;
--all)
do_prepare
do_build
do_transfer
echo "VM still running. Destroy: ./scripts/build-bleeding.sh --destroy"
;;
--ship) do_ship ;;
--update-all) do_update_all ;;
*)
echo "Usage: $0 <command>"
echo ""
echo " --all Create Fedora VM + build in Arch Docker + download"
echo " --ship Build + deploy to all servers + destroy VM"
echo " --prepare Create VM, install Docker, upload source"
echo " --build Build in Arch Linux Docker container"
echo " --transfer Download binaries to $OUTPUT_DIR"
echo " --destroy Delete the VM"
echo " --upload Re-upload source to existing VM"
echo " --update-all Deploy bleeding binaries to all servers"
echo ""
echo "Output: $OUTPUT_DIR/warzone-{server,client}"
echo "Host VM: Fedora latest | Build: Arch Linux latest (Docker)"
exit 1
;;
esac