feat: add --source option to install script for building from source

- Added --source, --from-source, and --branch options (all equivalent)
- Allows building and installing Pulse from source code
- Optional branch parameter (defaults to main)
- Builds frontend and backend locally before installing
- Removes separate install-from-main.sh script - integrated into main script

Usage:
  curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/install.sh | bash -s -- --source
  curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/install.sh | bash -s -- --source develop
This commit is contained in:
Pulse Monitor
2025-09-11 15:15:27 +00:00
parent 26a6c2fa76
commit ac3e1eaacb
2 changed files with 237 additions and 249 deletions
+237 -144
View File
@@ -1157,154 +1157,235 @@ download_pulse() {
print_info "Latest version: $LATEST_RELEASE"
fi
# Detect architecture
ARCH=$(uname -m)
case $ARCH in
x86_64)
PULSE_ARCH="amd64"
;;
aarch64)
PULSE_ARCH="arm64"
;;
armv7l)
PULSE_ARCH="armv7"
;;
*)
print_error "Unsupported architecture: $ARCH"
exit 1
;;
esac
print_info "Detected architecture: $ARCH ($PULSE_ARCH)"
# Download architecture-specific release
DOWNLOAD_URL="https://github.com/$GITHUB_REPO/releases/download/$LATEST_RELEASE/pulse-${LATEST_RELEASE}-linux-${PULSE_ARCH}.tar.gz"
print_info "Downloading from: $DOWNLOAD_URL"
# Detect and stop existing service BEFORE downloading (to free the binary)
EXISTING_SERVICE=$(detect_service_name)
if timeout 5 systemctl is-active --quiet $EXISTING_SERVICE 2>/dev/null; then
print_info "Stopping existing Pulse service ($EXISTING_SERVICE)..."
safe_systemctl stop $EXISTING_SERVICE || true
sleep 2 # Give the process time to fully stop and release the binary
fi
cd /tmp
# Download with timeout (60 seconds should be enough for ~5MB file)
if ! wget -q --timeout=60 --tries=2 -O pulse.tar.gz "$DOWNLOAD_URL"; then
print_error "Failed to download Pulse release"
print_info "This can happen due to network issues or GitHub rate limiting"
print_info "You can try downloading manually from: $DOWNLOAD_URL"
exit 1
fi
# Extract to temporary directory first
TEMP_EXTRACT="/tmp/pulse-extract-$$"
mkdir -p "$TEMP_EXTRACT"
tar -xzf pulse.tar.gz -C "$TEMP_EXTRACT"
# Ensure install directory and bin subdirectory exist
mkdir -p "$INSTALL_DIR/bin"
# Copy Pulse binary to the correct location (/opt/pulse/bin/pulse)
# First, backup the old binary if it exists
if [[ -f "$INSTALL_DIR/bin/pulse" ]]; then
mv "$INSTALL_DIR/bin/pulse" "$INSTALL_DIR/bin/pulse.old" 2>/dev/null || true
fi
if [[ -f "$TEMP_EXTRACT/bin/pulse" ]]; then
if ! cp "$TEMP_EXTRACT/bin/pulse" "$INSTALL_DIR/bin/pulse"; then
print_error "Failed to copy new binary to $INSTALL_DIR/bin/pulse"
# Try to restore old binary
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
elif [[ -f "$TEMP_EXTRACT/pulse" ]]; then
# Fallback for old archives (pre-v4.3.1)
if ! cp "$TEMP_EXTRACT/pulse" "$INSTALL_DIR/bin/pulse"; then
print_error "Failed to copy new binary to $INSTALL_DIR/bin/pulse"
# Try to restore old binary
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
else
print_error "Pulse binary not found in archive"
# Try to restore old binary
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
# Verify the new binary was copied and is executable
if [[ ! -f "$INSTALL_DIR/bin/pulse" ]]; then
print_error "Binary installation failed - file not found after copy"
# Try to restore old binary
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
chmod +x "$INSTALL_DIR/bin/pulse"
chown -R pulse:pulse "$INSTALL_DIR"
# Clean up old binary backup if everything succeeded
rm -f "$INSTALL_DIR/bin/pulse.old"
# Create symlink in /usr/local/bin for PATH convenience
ln -sf "$INSTALL_DIR/bin/pulse" /usr/local/bin/pulse
print_success "Pulse binary installed to $INSTALL_DIR/bin/pulse"
print_success "Symlink created at /usr/local/bin/pulse"
# Copy VERSION file if present
if [[ -f "$TEMP_EXTRACT/VERSION" ]]; then
cp "$TEMP_EXTRACT/VERSION" "$INSTALL_DIR/VERSION"
chown pulse:pulse "$INSTALL_DIR/VERSION"
fi
# Verify the installed version matches what we expected
INSTALLED_VERSION=$("$INSTALL_DIR/bin/pulse" --version 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\.]+)?' | head -1 || echo "unknown")
if [[ "$INSTALLED_VERSION" != "$LATEST_RELEASE" ]]; then
print_warn "Version verification issue: Expected $LATEST_RELEASE but binary reports $INSTALLED_VERSION"
print_info "This can happen if the binary wasn't properly replaced. Trying to fix..."
# Check if we should build from source
if [[ "$BUILD_FROM_SOURCE" == "true" ]]; then
print_info "Building Pulse from source (branch: $SOURCE_BRANCH)..."
# Force remove and recopy
rm -f "$INSTALL_DIR/bin/pulse"
if [[ -f "/tmp/pulse.tar.gz" ]]; then
# Re-extract and try again
TEMP_EXTRACT2="/tmp/pulse-extract2-$$"
mkdir -p "$TEMP_EXTRACT2"
tar -xzf /tmp/pulse.tar.gz -C "$TEMP_EXTRACT2"
if [[ -f "$TEMP_EXTRACT2/bin/pulse" ]]; then
cp -f "$TEMP_EXTRACT2/bin/pulse" "$INSTALL_DIR/bin/pulse"
elif [[ -f "$TEMP_EXTRACT2/pulse" ]]; then
cp -f "$TEMP_EXTRACT2/pulse" "$INSTALL_DIR/bin/pulse"
fi
chmod +x "$INSTALL_DIR/bin/pulse"
chown -R pulse:pulse "$INSTALL_DIR"
rm -rf "$TEMP_EXTRACT2"
# Check version again
INSTALLED_VERSION=$("$INSTALL_DIR/bin/pulse" --version 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\.]+)?' | head -1 || echo "unknown")
if [[ "$INSTALLED_VERSION" == "$LATEST_RELEASE" ]]; then
print_success "Version issue resolved - now running $INSTALLED_VERSION"
else
print_warn "Version mismatch persists. You may need to restart the service or reboot."
fi
# Install build dependencies
print_info "Installing build dependencies..."
if ! (apt-get update >/dev/null 2>&1 && apt-get install -y git golang-go make nodejs npm >/dev/null 2>&1); then
print_error "Failed to install build dependencies"
exit 1
fi
else
print_success "Version verified: $INSTALLED_VERSION"
# Create temp directory for build
TEMP_BUILD="/tmp/pulse-build-$$"
mkdir -p "$TEMP_BUILD"
cd "$TEMP_BUILD"
print_info "Cloning repository (branch: $SOURCE_BRANCH)..."
if ! git clone --depth 1 --branch "$SOURCE_BRANCH" "https://github.com/$GITHUB_REPO.git" >/dev/null 2>&1; then
print_error "Failed to clone repository (branch: $SOURCE_BRANCH)"
print_info "Make sure the branch exists and is accessible"
exit 1
fi
cd Pulse
print_info "Building frontend..."
cd frontend-modern
if ! (npm ci >/dev/null 2>&1 && npm run build >/dev/null 2>&1); then
print_error "Failed to build frontend"
exit 1
fi
cd ..
print_info "Building backend..."
if ! make build >/dev/null 2>&1; then
print_error "Failed to build backend"
exit 1
fi
# Detect and stop existing service BEFORE installing new binary
EXISTING_SERVICE=$(detect_service_name)
if timeout 5 systemctl is-active --quiet $EXISTING_SERVICE 2>/dev/null; then
print_info "Stopping existing Pulse service ($EXISTING_SERVICE)..."
safe_systemctl stop $EXISTING_SERVICE || true
sleep 2 # Give the process time to fully stop and release the binary
fi
# Ensure install directory and bin subdirectory exist
mkdir -p "$INSTALL_DIR/bin"
# Copy the built binary
if [[ -f "$INSTALL_DIR/bin/pulse" ]]; then
mv "$INSTALL_DIR/bin/pulse" "$INSTALL_DIR/bin/pulse.old" 2>/dev/null || true
fi
if ! cp bin/pulse "$INSTALL_DIR/bin/pulse"; then
print_error "Failed to copy built binary to $INSTALL_DIR/bin/pulse"
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
chmod +x "$INSTALL_DIR/bin/pulse"
# Update VERSION file to show it's from source
echo "$SOURCE_BRANCH-$(git rev-parse --short HEAD)" > "$INSTALL_DIR/VERSION"
# Cleanup
cd /
rm -rf "$TEMP_BUILD"
print_success "Successfully built and installed Pulse from source (branch: $SOURCE_BRANCH)"
# Skip the rest of the download/install logic
SKIP_DOWNLOAD=true
fi
# Cleanup
rm -rf "$TEMP_EXTRACT" pulse.tar.gz
# Only do download if not building from source
if [[ "$SKIP_DOWNLOAD" != "true" ]]; then
# Detect architecture
ARCH=$(uname -m)
case $ARCH in
x86_64)
PULSE_ARCH="amd64"
;;
aarch64)
PULSE_ARCH="arm64"
;;
armv7l)
PULSE_ARCH="armv7"
;;
*)
print_error "Unsupported architecture: $ARCH"
exit 1
;;
esac
print_info "Detected architecture: $ARCH ($PULSE_ARCH)"
# Download architecture-specific release
DOWNLOAD_URL="https://github.com/$GITHUB_REPO/releases/download/$LATEST_RELEASE/pulse-${LATEST_RELEASE}-linux-${PULSE_ARCH}.tar.gz"
print_info "Downloading from: $DOWNLOAD_URL"
# Detect and stop existing service BEFORE downloading (to free the binary)
EXISTING_SERVICE=$(detect_service_name)
if timeout 5 systemctl is-active --quiet $EXISTING_SERVICE 2>/dev/null; then
print_info "Stopping existing Pulse service ($EXISTING_SERVICE)..."
safe_systemctl stop $EXISTING_SERVICE || true
sleep 2 # Give the process time to fully stop and release the binary
fi
cd /tmp
# Download with timeout (60 seconds should be enough for ~5MB file)
if ! wget -q --timeout=60 --tries=2 -O pulse.tar.gz "$DOWNLOAD_URL"; then
print_error "Failed to download Pulse release"
print_info "This can happen due to network issues or GitHub rate limiting"
print_info "You can try downloading manually from: $DOWNLOAD_URL"
exit 1
fi
# Extract to temporary directory first
TEMP_EXTRACT="/tmp/pulse-extract-$$"
mkdir -p "$TEMP_EXTRACT"
tar -xzf pulse.tar.gz -C "$TEMP_EXTRACT"
# Ensure install directory and bin subdirectory exist
mkdir -p "$INSTALL_DIR/bin"
# Copy Pulse binary to the correct location (/opt/pulse/bin/pulse)
# First, backup the old binary if it exists
if [[ -f "$INSTALL_DIR/bin/pulse" ]]; then
mv "$INSTALL_DIR/bin/pulse" "$INSTALL_DIR/bin/pulse.old" 2>/dev/null || true
fi
if [[ -f "$TEMP_EXTRACT/bin/pulse" ]]; then
if ! cp "$TEMP_EXTRACT/bin/pulse" "$INSTALL_DIR/bin/pulse"; then
print_error "Failed to copy new binary to $INSTALL_DIR/bin/pulse"
# Try to restore old binary
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
elif [[ -f "$TEMP_EXTRACT/pulse" ]]; then
# Fallback for old archives (pre-v4.3.1)
if ! cp "$TEMP_EXTRACT/pulse" "$INSTALL_DIR/bin/pulse"; then
print_error "Failed to copy new binary to $INSTALL_DIR/bin/pulse"
# Try to restore old binary
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
else
print_error "Pulse binary not found in archive"
# Try to restore old binary
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
# Verify the new binary was copied and is executable
if [[ ! -f "$INSTALL_DIR/bin/pulse" ]]; then
print_error "Binary installation failed - file not found after copy"
# Try to restore old binary
if [[ -f "$INSTALL_DIR/bin/pulse.old" ]]; then
mv "$INSTALL_DIR/bin/pulse.old" "$INSTALL_DIR/bin/pulse"
fi
exit 1
fi
chmod +x "$INSTALL_DIR/bin/pulse"
chown -R pulse:pulse "$INSTALL_DIR"
# Clean up old binary backup if everything succeeded
rm -f "$INSTALL_DIR/bin/pulse.old"
# Create symlink in /usr/local/bin for PATH convenience
ln -sf "$INSTALL_DIR/bin/pulse" /usr/local/bin/pulse
print_success "Pulse binary installed to $INSTALL_DIR/bin/pulse"
print_success "Symlink created at /usr/local/bin/pulse"
# Copy VERSION file if present
if [[ -f "$TEMP_EXTRACT/VERSION" ]]; then
cp "$TEMP_EXTRACT/VERSION" "$INSTALL_DIR/VERSION"
chown pulse:pulse "$INSTALL_DIR/VERSION"
fi
# Verify the installed version matches what we expected
INSTALLED_VERSION=$("$INSTALL_DIR/bin/pulse" --version 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\.]+)?' | head -1 || echo "unknown")
if [[ "$INSTALLED_VERSION" != "$LATEST_RELEASE" ]]; then
print_warn "Version verification issue: Expected $LATEST_RELEASE but binary reports $INSTALLED_VERSION"
print_info "This can happen if the binary wasn't properly replaced. Trying to fix..."
# Force remove and recopy
rm -f "$INSTALL_DIR/bin/pulse"
if [[ -f "/tmp/pulse.tar.gz" ]]; then
# Re-extract and try again
TEMP_EXTRACT2="/tmp/pulse-extract2-$$"
mkdir -p "$TEMP_EXTRACT2"
tar -xzf /tmp/pulse.tar.gz -C "$TEMP_EXTRACT2"
if [[ -f "$TEMP_EXTRACT2/bin/pulse" ]]; then
cp -f "$TEMP_EXTRACT2/bin/pulse" "$INSTALL_DIR/bin/pulse"
elif [[ -f "$TEMP_EXTRACT2/pulse" ]]; then
cp -f "$TEMP_EXTRACT2/pulse" "$INSTALL_DIR/bin/pulse"
fi
chmod +x "$INSTALL_DIR/bin/pulse"
chown -R pulse:pulse "$INSTALL_DIR"
rm -rf "$TEMP_EXTRACT2"
# Check version again
INSTALLED_VERSION=$("$INSTALL_DIR/bin/pulse" --version 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\.]+)?' | head -1 || echo "unknown")
if [[ "$INSTALLED_VERSION" == "$LATEST_RELEASE" ]]; then
print_success "Version issue resolved - now running $INSTALLED_VERSION"
else
print_warn "Version mismatch persists. You may need to restart the service or reboot."
fi
fi
else
print_success "Version verified: $INSTALLED_VERSION"
fi
# Cleanup
rm -rf "$TEMP_EXTRACT" pulse.tar.gz
fi # End of SKIP_DOWNLOAD check
}
setup_directories() {
@@ -2170,6 +2251,17 @@ while [[ $# -gt 0 ]]; do
ENABLE_AUTO_UPDATES=true
shift
;;
--source|--from-source|--branch)
BUILD_FROM_SOURCE=true
# Optional: specify branch
if [[ -n "$2" ]] && [[ ! "$2" =~ ^-- ]]; then
SOURCE_BRANCH="$2"
shift 2
else
SOURCE_BRANCH="main"
shift
fi
;;
-h|--help)
echo "Usage: $0 [OPTIONS]"
echo ""
@@ -2177,6 +2269,7 @@ while [[ $# -gt 0 ]]; do
echo " --rc, --pre Install latest RC/pre-release version"
echo " --stable Install latest stable version (default)"
echo " --version VERSION Install specific version (e.g., v4.4.0-rc.1)"
echo " --source [BRANCH] Build and install from source (default: main)"
echo " --enable-auto-updates Enable automatic stable updates (via systemd timer)"
echo ""
echo "Management options:"
-105
View File
@@ -1,105 +0,0 @@
#!/usr/bin/env bash
# Script to build and install Pulse from main branch
# This allows testing latest changes without creating a release
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
# Check if running as root
if [[ $EUID -ne 0 ]]; then
print_error "This script must be run as root"
exit 1
fi
print_info "Building Pulse from main branch..."
# Install dependencies
print_info "Installing build dependencies..."
apt-get update >/dev/null 2>&1
apt-get install -y git golang-go make nodejs npm >/dev/null 2>&1 || {
print_error "Failed to install dependencies"
exit 1
}
# Create temp directory
TEMP_DIR=$(mktemp -d)
cd "$TEMP_DIR"
print_info "Cloning repository..."
git clone --depth 1 https://github.com/rcourtman/Pulse.git >/dev/null 2>&1 || {
print_error "Failed to clone repository"
exit 1
}
cd Pulse
print_info "Building frontend..."
cd frontend-modern
npm ci >/dev/null 2>&1 || {
print_error "Failed to install frontend dependencies"
exit 1
}
npm run build >/dev/null 2>&1 || {
print_error "Failed to build frontend"
exit 1
}
cd ..
print_info "Building backend..."
make build >/dev/null 2>&1 || {
print_error "Failed to build backend"
exit 1
}
# Detect service name
SERVICE_NAME="pulse"
if systemctl list-unit-files --no-legend | grep -q "^pulse-backend.service"; then
SERVICE_NAME="pulse-backend"
fi
# Stop service if running
if systemctl is-active --quiet "$SERVICE_NAME"; then
print_info "Stopping $SERVICE_NAME service..."
systemctl stop "$SERVICE_NAME"
fi
# Backup existing binary
if [[ -f /opt/pulse/bin/pulse ]]; then
print_info "Backing up existing binary..."
cp /opt/pulse/bin/pulse /opt/pulse/bin/pulse.backup
fi
# Install new binary
print_info "Installing new binary..."
mkdir -p /opt/pulse/bin
cp bin/pulse /opt/pulse/bin/pulse
chmod +x /opt/pulse/bin/pulse
# Update VERSION file to show it's from main
echo "main-$(git rev-parse --short HEAD)" > /opt/pulse/VERSION
# Start service
print_info "Starting $SERVICE_NAME service..."
systemctl start "$SERVICE_NAME" || {
print_warning "Failed to start service automatically. You may need to start it manually."
}
# Cleanup
cd /
rm -rf "$TEMP_DIR"
print_success "Successfully installed Pulse from main branch!"
print_info "Version: main-$(cd /opt/pulse && git rev-parse --short HEAD 2>/dev/null || echo 'unknown')"
print_info "Access Pulse at: http://$(hostname -I | awk '{print $1}'):7655"