mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-24 12:13:28 +00:00
32e0d453c4
Windows 11 25H2 ships exclusively on ARM64 hardware. When users on ARM64 attempt to install the host agent, the Service Control Manager fails to load the amd64 binary with ERROR_BAD_EXE_FORMAT, surfaced as "The Pulse Host Agent is not compatible with this Windows version". Changes: - Dockerfile: Build pulse-host-agent-windows-arm64.exe alongside amd64 - Dockerfile: Copy windows-arm64 binary and create symlink for download endpoint - install-host-agent.ps1: Use RuntimeInformation.OSArchitecture to detect ARM64 - build-release.sh: Build darwin-amd64, darwin-arm64, windows-amd64, windows-arm64 - build-release.sh: Package Windows binaries as .zip archives - validate-release.sh: Check for windows-arm64 binary and symlink - validate-release.sh: Add architecture validation for all darwin/windows variants The installer now correctly detects ARM64 and downloads the appropriate binary.
356 lines
13 KiB
Bash
Executable File
356 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Build script for Pulse releases
|
|
# Creates release archives for different architectures
|
|
|
|
set -euo pipefail
|
|
|
|
# Use Go 1.24 if available
|
|
if [ -x /usr/local/go/bin/go ]; then
|
|
export PATH=/usr/local/go/bin:$PATH
|
|
fi
|
|
|
|
# Force static binaries so release artifacts run on older glibc hosts
|
|
export CGO_ENABLED=0
|
|
|
|
VERSION=${1:-$(cat VERSION)}
|
|
BUILD_DIR="build"
|
|
RELEASE_DIR="release"
|
|
|
|
echo "Building Pulse v${VERSION}..."
|
|
|
|
# Clean previous builds
|
|
rm -rf $BUILD_DIR $RELEASE_DIR
|
|
mkdir -p $BUILD_DIR $RELEASE_DIR
|
|
|
|
# Build frontend
|
|
echo "Building frontend..."
|
|
npm --prefix frontend-modern ci
|
|
npm --prefix frontend-modern run build
|
|
|
|
# Copy frontend dist for embedding (required for Go embed)
|
|
echo "Copying frontend dist for embedding..."
|
|
rm -rf internal/api/frontend-modern
|
|
mkdir -p internal/api/frontend-modern
|
|
cp -r frontend-modern/dist internal/api/frontend-modern/
|
|
|
|
# Build for different architectures
|
|
declare -A builds=(
|
|
["linux-amd64"]="GOOS=linux GOARCH=amd64"
|
|
["linux-arm64"]="GOOS=linux GOARCH=arm64"
|
|
["linux-armv7"]="GOOS=linux GOARCH=arm GOARM=7"
|
|
)
|
|
|
|
for build_name in "${!builds[@]}"; do
|
|
echo "Building for $build_name..."
|
|
|
|
# Get build environment
|
|
build_env="${builds[$build_name]}"
|
|
|
|
build_time=$(date -u '+%Y-%m-%d_%H:%M:%S')
|
|
git_commit=$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown')
|
|
|
|
# Build backend binary with version info
|
|
env $build_env go build \
|
|
-ldflags="-s -w -X main.Version=v${VERSION} -X main.BuildTime=${build_time} -X main.GitCommit=${git_commit} -X github.com/rcourtman/pulse-go-rewrite/internal/dockeragent.Version=v${VERSION}" \
|
|
-trimpath \
|
|
-o "$BUILD_DIR/pulse-$build_name" \
|
|
./cmd/pulse
|
|
|
|
# Build docker agent binary
|
|
env $build_env go build \
|
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/dockeragent.Version=v${VERSION}" \
|
|
-trimpath \
|
|
-o "$BUILD_DIR/pulse-docker-agent-$build_name" \
|
|
./cmd/pulse-docker-agent
|
|
|
|
# Build host agent binary
|
|
env $build_env go build \
|
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=v${VERSION}" \
|
|
-trimpath \
|
|
-o "$BUILD_DIR/pulse-host-agent-$build_name" \
|
|
./cmd/pulse-host-agent
|
|
|
|
# Build temperature proxy binary
|
|
env $build_env go build \
|
|
-ldflags="-s -w -X main.Version=v${VERSION} -X main.BuildTime=${build_time} -X main.GitCommit=${git_commit}" \
|
|
-trimpath \
|
|
-o "$BUILD_DIR/pulse-sensor-proxy-$build_name" \
|
|
./cmd/pulse-sensor-proxy
|
|
|
|
# Create release archive with proper structure
|
|
tar_name="pulse-v${VERSION}-${build_name}.tar.gz"
|
|
|
|
# Create staging directory
|
|
staging_dir="$BUILD_DIR/staging-$build_name"
|
|
rm -rf "$staging_dir"
|
|
mkdir -p "$staging_dir/bin"
|
|
mkdir -p "$staging_dir/scripts"
|
|
|
|
# Copy binaries and VERSION file
|
|
cp "$BUILD_DIR/pulse-$build_name" "$staging_dir/bin/pulse"
|
|
cp "$BUILD_DIR/pulse-docker-agent-$build_name" "$staging_dir/bin/pulse-docker-agent"
|
|
cp "$BUILD_DIR/pulse-host-agent-$build_name" "$staging_dir/bin/pulse-host-agent"
|
|
cp "$BUILD_DIR/pulse-sensor-proxy-$build_name" "$staging_dir/bin/pulse-sensor-proxy"
|
|
cp "scripts/install-docker-agent.sh" "$staging_dir/scripts/install-docker-agent.sh"
|
|
cp "scripts/install-container-agent.sh" "$staging_dir/scripts/install-container-agent.sh"
|
|
cp "scripts/install-host-agent.sh" "$staging_dir/scripts/install-host-agent.sh"
|
|
cp "scripts/install-host-agent.ps1" "$staging_dir/scripts/install-host-agent.ps1"
|
|
cp "scripts/uninstall-host-agent.sh" "$staging_dir/scripts/uninstall-host-agent.sh"
|
|
cp "scripts/uninstall-host-agent.ps1" "$staging_dir/scripts/uninstall-host-agent.ps1"
|
|
cp "scripts/install-sensor-proxy.sh" "$staging_dir/scripts/install-sensor-proxy.sh"
|
|
cp "scripts/install-docker.sh" "$staging_dir/scripts/install-docker.sh"
|
|
chmod 755 "$staging_dir/scripts/"*.sh "$staging_dir/scripts/"*.ps1
|
|
echo "$VERSION" > "$staging_dir/VERSION"
|
|
|
|
# Create tarball from staging directory
|
|
cd "$staging_dir"
|
|
tar -czf "../../$RELEASE_DIR/$tar_name" .
|
|
cd ../..
|
|
|
|
# Cleanup staging
|
|
rm -rf "$staging_dir"
|
|
|
|
echo "Created $RELEASE_DIR/$tar_name"
|
|
done
|
|
|
|
# Create universal tarball with all binaries
|
|
echo "Creating universal tarball..."
|
|
universal_dir="$BUILD_DIR/universal"
|
|
rm -rf "$universal_dir"
|
|
mkdir -p "$universal_dir/bin"
|
|
mkdir -p "$universal_dir/scripts"
|
|
|
|
# Copy all binaries to bin/ directory to maintain consistent structure
|
|
for build_name in "${!builds[@]}"; do
|
|
cp "$BUILD_DIR/pulse-$build_name" "$universal_dir/bin/pulse-${build_name}"
|
|
cp "$BUILD_DIR/pulse-docker-agent-$build_name" "$universal_dir/bin/pulse-docker-agent-${build_name}"
|
|
cp "$BUILD_DIR/pulse-host-agent-$build_name" "$universal_dir/bin/pulse-host-agent-${build_name}"
|
|
cp "$BUILD_DIR/pulse-sensor-proxy-$build_name" "$universal_dir/bin/pulse-sensor-proxy-${build_name}"
|
|
done
|
|
|
|
cp "scripts/install-docker-agent.sh" "$universal_dir/scripts/install-docker-agent.sh"
|
|
cp "scripts/install-container-agent.sh" "$universal_dir/scripts/install-container-agent.sh"
|
|
cp "scripts/install-host-agent.sh" "$universal_dir/scripts/install-host-agent.sh"
|
|
cp "scripts/install-host-agent.ps1" "$universal_dir/scripts/install-host-agent.ps1"
|
|
cp "scripts/uninstall-host-agent.sh" "$universal_dir/scripts/uninstall-host-agent.sh"
|
|
cp "scripts/uninstall-host-agent.ps1" "$universal_dir/scripts/uninstall-host-agent.ps1"
|
|
cp "scripts/install-sensor-proxy.sh" "$universal_dir/scripts/install-sensor-proxy.sh"
|
|
cp "scripts/install-docker.sh" "$universal_dir/scripts/install-docker.sh"
|
|
chmod 755 "$universal_dir/scripts/"*.sh "$universal_dir/scripts/"*.ps1
|
|
|
|
# Create a detection script that creates the pulse symlink based on architecture
|
|
cat > "$universal_dir/bin/pulse" << 'EOF'
|
|
#!/bin/sh
|
|
# Auto-detect architecture and run appropriate binary
|
|
|
|
ARCH=$(uname -m)
|
|
case "$ARCH" in
|
|
x86_64|amd64)
|
|
exec "$(dirname "$0")/pulse-linux-amd64" "$@"
|
|
;;
|
|
aarch64|arm64)
|
|
exec "$(dirname "$0")/pulse-linux-arm64" "$@"
|
|
;;
|
|
armv7l|armhf)
|
|
exec "$(dirname "$0")/pulse-linux-armv7" "$@"
|
|
;;
|
|
*)
|
|
echo "Unsupported architecture: $ARCH" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$universal_dir/bin/pulse"
|
|
|
|
cat > "$universal_dir/bin/pulse-docker-agent" << 'EOF'
|
|
#!/bin/sh
|
|
# Auto-detect architecture and run appropriate pulse-docker-agent binary
|
|
|
|
ARCH=$(uname -m)
|
|
case "$ARCH" in
|
|
x86_64|amd64)
|
|
exec "$(dirname "$0")/pulse-docker-agent-linux-amd64" "$@"
|
|
;;
|
|
aarch64|arm64)
|
|
exec "$(dirname "$0")/pulse-docker-agent-linux-arm64" "$@"
|
|
;;
|
|
armv7l|armhf)
|
|
exec "$(dirname "$0")/pulse-docker-agent-linux-armv7" "$@"
|
|
;;
|
|
*)
|
|
echo "Unsupported architecture: $ARCH" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$universal_dir/bin/pulse-docker-agent"
|
|
|
|
cat > "$universal_dir/bin/pulse-sensor-proxy" << 'EOF'
|
|
#!/bin/sh
|
|
# Auto-detect architecture and run appropriate pulse-sensor-proxy binary
|
|
|
|
ARCH=$(uname -m)
|
|
case "$ARCH" in
|
|
x86_64|amd64)
|
|
exec "$(dirname "$0")/pulse-sensor-proxy-linux-amd64" "$@"
|
|
;;
|
|
aarch64|arm64)
|
|
exec "$(dirname "$0")/pulse-sensor-proxy-linux-arm64" "$@"
|
|
;;
|
|
armv7l|armhf)
|
|
exec "$(dirname "$0")/pulse-sensor-proxy-linux-armv7" "$@"
|
|
;;
|
|
*)
|
|
echo "Unsupported architecture: $ARCH" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$universal_dir/bin/pulse-sensor-proxy"
|
|
|
|
cat > "$universal_dir/bin/pulse-host-agent" << 'EOF'
|
|
#!/bin/sh
|
|
# Auto-detect architecture and run appropriate pulse-host-agent binary
|
|
|
|
ARCH=$(uname -m)
|
|
case "$ARCH" in
|
|
x86_64|amd64)
|
|
exec "$(dirname "$0")/pulse-host-agent-linux-amd64" "$@"
|
|
;;
|
|
aarch64|arm64)
|
|
exec "$(dirname "$0")/pulse-host-agent-linux-arm64" "$@"
|
|
;;
|
|
armv7l|armhf)
|
|
exec "$(dirname "$0")/pulse-host-agent-linux-armv7" "$@"
|
|
;;
|
|
*)
|
|
echo "Unsupported architecture: $ARCH" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$universal_dir/bin/pulse-host-agent"
|
|
|
|
# Add VERSION file
|
|
echo "$VERSION" > "$universal_dir/VERSION"
|
|
|
|
# Build host agent for macOS
|
|
echo "Building host agent for macOS amd64..."
|
|
env GOOS=darwin GOARCH=amd64 go build \
|
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=v${VERSION}" \
|
|
-trimpath \
|
|
-o "$BUILD_DIR/pulse-host-agent-darwin-amd64" \
|
|
./cmd/pulse-host-agent
|
|
|
|
echo "Building host agent for macOS arm64..."
|
|
env GOOS=darwin GOARCH=arm64 go build \
|
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=v${VERSION}" \
|
|
-trimpath \
|
|
-o "$BUILD_DIR/pulse-host-agent-darwin-arm64" \
|
|
./cmd/pulse-host-agent
|
|
|
|
# Build host agent for Windows
|
|
echo "Building host agent for Windows amd64..."
|
|
env GOOS=windows GOARCH=amd64 go build \
|
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=v${VERSION}" \
|
|
-trimpath \
|
|
-o "$BUILD_DIR/pulse-host-agent-windows-amd64.exe" \
|
|
./cmd/pulse-host-agent
|
|
|
|
echo "Building host agent for Windows arm64..."
|
|
env GOOS=windows GOARCH=arm64 go build \
|
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=v${VERSION}" \
|
|
-trimpath \
|
|
-o "$BUILD_DIR/pulse-host-agent-windows-arm64.exe" \
|
|
./cmd/pulse-host-agent
|
|
|
|
# Package standalone host agent binaries
|
|
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-darwin-amd64.tar.gz" -C "$BUILD_DIR" pulse-host-agent-darwin-amd64
|
|
tar -czf "$RELEASE_DIR/pulse-host-agent-v${VERSION}-darwin-arm64.tar.gz" -C "$BUILD_DIR" pulse-host-agent-darwin-arm64
|
|
zip -j "$RELEASE_DIR/pulse-host-agent-v${VERSION}-windows-amd64.zip" "$BUILD_DIR/pulse-host-agent-windows-amd64.exe"
|
|
zip -j "$RELEASE_DIR/pulse-host-agent-v${VERSION}-windows-arm64.zip" "$BUILD_DIR/pulse-host-agent-windows-arm64.exe"
|
|
|
|
# Create universal tarball
|
|
cd "$universal_dir"
|
|
tar -czf "../../$RELEASE_DIR/pulse-v${VERSION}.tar.gz" .
|
|
cd ../..
|
|
|
|
# Cleanup
|
|
rm -rf "$universal_dir"
|
|
|
|
# Copy standalone pulse-sensor-proxy binaries to release directory
|
|
# These are needed by install-sensor-proxy.sh installer script
|
|
echo "Copying standalone pulse-sensor-proxy binaries..."
|
|
for build_name in "${!builds[@]}"; do
|
|
cp "$BUILD_DIR/pulse-sensor-proxy-$build_name" "$RELEASE_DIR/"
|
|
done
|
|
|
|
# Copy standalone pulse-host-agent binaries to release directory
|
|
# These are needed for manual host-agent installation without a running Pulse server
|
|
echo "Copying standalone pulse-host-agent binaries..."
|
|
for build_name in "${!builds[@]}"; do
|
|
cp "$BUILD_DIR/pulse-host-agent-$build_name" "$RELEASE_DIR/"
|
|
done
|
|
|
|
# Also copy standalone macOS and Windows host-agent binaries
|
|
cp "$BUILD_DIR/pulse-host-agent-darwin-amd64" "$RELEASE_DIR/"
|
|
cp "$BUILD_DIR/pulse-host-agent-darwin-arm64" "$RELEASE_DIR/"
|
|
cp "$BUILD_DIR/pulse-host-agent-windows-amd64.exe" "$RELEASE_DIR/"
|
|
cp "$BUILD_DIR/pulse-host-agent-windows-arm64.exe" "$RELEASE_DIR/"
|
|
|
|
# Optionally package Helm chart
|
|
if [ "${SKIP_HELM_PACKAGE:-0}" != "1" ]; then
|
|
if command -v helm >/dev/null 2>&1; then
|
|
echo "Packaging Helm chart..."
|
|
./scripts/package-helm-chart.sh "$VERSION"
|
|
if [ -f "dist/pulse-$VERSION.tgz" ]; then
|
|
cp "dist/pulse-$VERSION.tgz" "$RELEASE_DIR/"
|
|
fi
|
|
else
|
|
echo "Helm not found on PATH; skipping Helm chart packaging. Install Helm 3.9+ or set SKIP_HELM_PACKAGE=1 to silence this message."
|
|
fi
|
|
fi
|
|
|
|
# Copy install.sh to release directory (required for GitHub releases)
|
|
echo "Copying install.sh to release directory..."
|
|
cp install.sh "$RELEASE_DIR/"
|
|
|
|
# Generate checksums (include tarballs, helm chart, standalone binaries, and install.sh)
|
|
cd "$RELEASE_DIR"
|
|
shopt -s nullglob extglob
|
|
# Match tarballs, then standalone binaries (excluding .tar.gz and .sha256), then install.sh
|
|
checksum_files=( *.tar.gz pulse-sensor-proxy-!(*.tar.gz|*.sha256) pulse-host-agent-!(*.tar.gz|*.sha256) install.sh )
|
|
if compgen -G "pulse-*.tgz" > /dev/null; then
|
|
checksum_files+=( pulse-*.tgz )
|
|
fi
|
|
if [ ${#checksum_files[@]} -eq 0 ]; then
|
|
echo "Warning: no release artifacts found to checksum."
|
|
else
|
|
# Generate individual .sha256 files for each asset (required by install.sh)
|
|
for file in "${checksum_files[@]}"; do
|
|
sha256sum "$file" > "${file}.sha256"
|
|
done
|
|
|
|
# Also generate combined checksums.txt for convenience
|
|
sha256sum "${checksum_files[@]}" > checksums.txt
|
|
if [ -n "${SIGNING_KEY_ID:-}" ]; then
|
|
if command -v gpg >/dev/null 2>&1; then
|
|
echo "Signing checksums with GPG key ${SIGNING_KEY_ID}..."
|
|
gpg --batch --yes --detach-sign --armor \
|
|
--local-user "${SIGNING_KEY_ID}" \
|
|
--output checksums.txt.asc \
|
|
checksums.txt
|
|
else
|
|
echo "SIGNING_KEY_ID is set but gpg is not installed; skipping signature."
|
|
fi
|
|
fi
|
|
fi
|
|
shopt -u nullglob
|
|
cd ..
|
|
|
|
echo
|
|
echo "Release build complete!"
|
|
echo "Archives created in $RELEASE_DIR/"
|
|
ls -lh $RELEASE_DIR/
|