242 lines · 6.9 KB · Text
RawDownload
#!/usr/bin/env bash## Cross-compiles the Oz CLI for Linux x86_64 (musl) on macOS and uploads it# to a remote host via rsync for local remote-server development.## Uses rsync for delta transfers — after the first deploy, only changed bytes# are sent, which is dramatically faster for iterative development.## Prerequisites:#   brew install filosottile/musl-cross/musl-cross#   rustup target add x86_64-unknown-linux-musl## Usage:#   script/deploy_remote_server --host user@hostname [--profile release] set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # DefaultsPROFILE_MODE="dev-remote"HOST="" usage() {  cat <<EOFUsage: $(basename "$0") --host <user@hostname> [OPTIONS] Cross-compile the Oz CLI for Linux x86_64 and upload it to a remote host. Required:  --host <user@hostname>    Remote host to upload to Options:  --profile <profile>       Build profile: dev-remote (default, strips symbols), dev, release, or optimized                            Use --profile dev if you need symbols for remote debugging  --help                    Show this help messageEOF  exit 0} # Parse argumentswhile [[ $# -gt 0 ]]; do  case "$1" in    --host)      HOST="$2"      shift 2      ;;    --profile)      PROFILE_MODE="$2"      shift 2      ;;    --help)      usage      ;;    *)      echo "Error: Unknown argument: $1" >&2      echo "Run with --help for usage." >&2      exit 1      ;;  esacdone # Validate required argumentsif [[ -z "$HOST" ]]; then  echo "Error: --host is required." >&2  echo "Run with --help for usage." >&2  exit 1fi # Validate profilecase "$PROFILE_MODE" in  dev-remote|dev|release|optimized) ;;  *)    echo "Error: Unsupported profile '$PROFILE_MODE'. Use 'dev-remote', 'dev', 'release', or 'optimized'." >&2    exit 1    ;;esac TARGET="x86_64-unknown-linux-musl"source "$SCRIPT_DIR/linux/configure_musl_toolchain" "$TARGET" # Check for musl targetif ! rustup target list --installed 2>/dev/null | grep -q x86_64-unknown-linux-musl; then  echo "Error: x86_64-unknown-linux-musl target not installed." >&2  echo "Install it with: rustup target add x86_64-unknown-linux-musl" >&2  exit 1fi # Select the requested Cargo build profile.case "$PROFILE_MODE" in  dev-remote)    CARGO_PROFILE="dev-remote"    ;;  dev)    CARGO_PROFILE="dev"    ;;  release)    CARGO_PROFILE="release"    ;;  optimized)    CARGO_PROFILE="release-lto-debug_assertions"    ;;esac FEATURES="release_bundle,crash_reporting,standalone,agent_mode_debug,remote_codebase_indexing"WARP_BIN="warp"BINARY_NAME="oz-local"REMOTE_DIR=".warp-local/remote-server"# Global, version-independent resources location read by the daemon. Must# match BUNDLED_RESOURCES_DIR_NAME in crates/remote_server/src/setup.rs.BUNDLED_RESOURCES_DIR_NAME="bundled_resources" # Determine the output directoryCARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$WORKSPACE_ROOT/target}"case "$CARGO_PROFILE" in  dev)    OUTPUT_DIR="$CARGO_TARGET_DIR/$TARGET/debug"    ;;  *)    OUTPUT_DIR="$CARGO_TARGET_DIR/$TARGET/$CARGO_PROFILE"    ;;esacBUILT_BINARY="$OUTPUT_DIR/$WARP_BIN"LOCAL_RESOURCES_DIR="$OUTPUT_DIR/remote-server-resources" echo "==> Building Oz CLI for $TARGET (profile=$CARGO_PROFILE)"echo "    Binary: $WARP_BIN -> $BINARY_NAME"echo "    Features: $FEATURES"echo "" cargo build \    -p warp \    --bin "$WARP_BIN" \    --target "$TARGET" \    --profile "$CARGO_PROFILE" \    --features "$FEATURES" if [[ ! -f "$BUILT_BINARY" ]]; then  echo "Error: Expected binary not found at $BUILT_BINARY" >&2  exit 1fi BINARY_SIZE=$(du -h "$BUILT_BINARY" | cut -f1)echo ""echo "==> Build complete ($BINARY_SIZE)"# Prepare the bundled resources tree (skills, settings schema) deployed to# the global, version-independent location the daemon reads.rm -rf "$LOCAL_RESOURCES_DIR""$WORKSPACE_ROOT/script/prepare_bundled_resources" \  "$LOCAL_RESOURCES_DIR" \  local \  "$CARGO_PROFILE" # Resolve $HOME on the remote so our upload lands in the same directory the# Warp client checks. The client runs `test -x ~/.warp-local/...` and lets# the remote login shell expand `~` to $HOME, while rsync's remote path# expansion can differ (e.g. on Namespace devboxes, the initial directory# is /workspaces but $HOME is elsewhere). Using an absolute path derived# from the remote $HOME keeps both sides consistent.REMOTE_HOME=$(ssh "$HOST" 'printf %s "$HOME"')if [[ -z "$REMOTE_HOME" ]]; then  echo "Error: could not resolve remote \$HOME on $HOST" >&2  exit 1fi REMOTE_ABS_DIR="$REMOTE_HOME/$REMOTE_DIR" # Ensure rsync is available on the remote hostif ! ssh "$HOST" "command -v rsync" &>/dev/null; then  echo "==> rsync not found on remote host, installing..."  ssh "$HOST" "sudo apt-get install -y rsync || sudo yum install -y rsync || sudo dnf install -y rsync || sudo apk add rsync"  if ! ssh "$HOST" "command -v rsync" &>/dev/null; then    echo "Error: failed to install rsync on $HOST. Please install it manually and re-run." >&2    exit 1  fifi # Ensure the remote install directory existsssh "$HOST" "mkdir -p $REMOTE_ABS_DIR" echo "==> Uploading binary to $HOST:$REMOTE_ABS_DIR/$BINARY_NAME" # Upload via rsync with delta transfer and compression.# After the first deploy, only changed bytes are transferred.rsync -z -t --partial --progress \  "$BUILT_BINARY" \  "$HOST:$REMOTE_ABS_DIR/$BINARY_NAME" # Set executable permissions (done separately for openrsync compatibility on macOS)ssh "$HOST" "chmod 755 $REMOTE_ABS_DIR/$BINARY_NAME" echo "==> Uploading bundled resources to $HOST:$REMOTE_ABS_DIR/$BUNDLED_RESOURCES_DIR_NAME"rsync -z -rlt --delete --partial --progress \  "$LOCAL_RESOURCES_DIR/" \  "$HOST:$REMOTE_ABS_DIR/$BUNDLED_RESOURCES_DIR_NAME/" echo "==> Stopping stale remote-server daemons on $HOST"ssh "$HOST" bash <<'EOF'set -euo pipefail REMOTE_SERVER_ROOT="$HOME/.warp-local/remote-server"shopt -s nullglob for pid_file in "$REMOTE_SERVER_ROOT"/*/server.pid; do  daemon_dir="$(dirname "$pid_file")"  pid="$(cat "$pid_file" 2>/dev/null || true)"  if [[ -z "$pid" || ! "$pid" =~ ^[0-9]+$ ]]; then    rm -f "$daemon_dir/server.sock" "$pid_file"    continue  fi   if [[ ! -r "/proc/$pid/cmdline" ]]; then    rm -f "$daemon_dir/server.sock" "$pid_file"    continue  fi   cmdline="$(tr '\0' ' ' <"/proc/$pid/cmdline" || true)"  if [[ "$cmdline" != *remote-server-daemon* ]]; then    continue  fi   echo "    Stopping stale daemon pid=$pid dir=$daemon_dir"  kill "$pid" 2>/dev/null || true  for _ in {1..50}; do    if ! kill -0 "$pid" 2>/dev/null; then      break    fi    sleep 0.1  done  if kill -0 "$pid" 2>/dev/null; then    echo "    Force-stopping stale daemon pid=$pid"    kill -9 "$pid" 2>/dev/null || true  fi  rm -f "$daemon_dir/server.sock" "$pid_file"doneEOF echo ""echo "==> Done! Binary deployed to $HOST:$REMOTE_ABS_DIR/$BINARY_NAME"echo "    Bundled resources: $REMOTE_ABS_DIR/$BUNDLED_RESOURCES_DIR_NAME"echo "    (resolved from ~/$REMOTE_DIR on remote)"