Files
wehub-resource-sync 91e75e620b
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:03:19 +08:00

370 lines
12 KiB
Bash
Executable File

#!/bin/bash
set -e
# Lume Local/Debug Installer
# This script builds and installs Lume from the local source code
# Get the directory where this script is located
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# Navigate to the lume root directory (one level up from scripts/)
LUME_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# Define colors for output
BOLD=$(tput bold)
NORMAL=$(tput sgr0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
BLUE=$(tput setaf 4)
YELLOW=$(tput setaf 3)
# Check if running as root or with sudo
if [ "$(id -u)" -eq 0 ] || [ -n "$SUDO_USER" ]; then
echo "${RED}Error: Do not run this script with sudo or as root.${NORMAL}"
exit 1
fi
# Default installation directory (user-specific, doesn't require sudo)
DEFAULT_INSTALL_DIR="$HOME/.local/bin"
INSTALL_DIR="${INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"
# Default .app bundle installation directory
APP_INSTALL_DIR="$HOME/.local/share/lume"
# Build configuration (debug or release)
BUILD_CONFIG="debug"
# Entitlement profile to use for local ad-hoc signing.
# Default excludes com.apple.vm.networking because macOS kills ad-hoc binaries
# carrying that restricted entitlement.
USE_BRIDGED_ENTITLEMENT=false
# Option to skip background service setup (default: install it)
INSTALL_BACKGROUND_SERVICE=true
# Default port for lume serve (default: 7777)
LUME_PORT=7777
# Track whether we're using the .app bundle format
USE_APP_BUNDLE=false
# Ad-hoc signatures can become invalid when stale provenance metadata is
# carried across rebuilds. Clear extended attributes before signing.
clear_signature_metadata() {
xattr -c "$1" 2>/dev/null || true
}
# Parse command line arguments
while [ "$#" -gt 0 ]; do
case "$1" in
--install-dir)
INSTALL_DIR="$2"
shift
;;
--port)
LUME_PORT="$2"
shift
;;
--release)
BUILD_CONFIG="release"
;;
--bridged-entitlement)
USE_BRIDGED_ENTITLEMENT=true
;;
--no-background-service)
INSTALL_BACKGROUND_SERVICE=false
;;
--help)
echo "${BOLD}${BLUE}Lume Local Installer${NORMAL}"
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --install-dir DIR Install to the specified directory (default: $DEFAULT_INSTALL_DIR)"
echo " --port PORT Specify the port for lume serve (default: 7777)"
echo " --release Build release configuration instead of debug"
echo " --bridged-entitlement Sign with com.apple.vm.networking entitlement (requires proper Apple-approved signing)"
echo " --no-background-service Do not setup the Lume background service (LaunchAgent)"
echo " --help Display this help message"
echo ""
echo "Examples:"
echo " $0 # Build debug and install to $DEFAULT_INSTALL_DIR"
echo " $0 --release # Build release and install"
echo " $0 --port 7778 # Use port 7778 for the daemon"
exit 0
;;
*)
echo "${RED}Unknown option: $1${NORMAL}"
echo "Use --help for usage information"
exit 1
;;
esac
shift
done
echo "${BOLD}${BLUE}"
echo " ⠀⣀⣀⡀⠀⠀⠀⠀⢀⣀⣀⣀⡀⠘⠋⢉⠙⣷⠀⠀ ⠀"
echo " ⠀⠀⢀⣴⣿⡿⠋⣉⠁⣠⣾⣿⣿⣿⣿⡿⠿⣦⡈⠀⣿⡇⠃⠀"
echo " ⠀⠀⠀⣽⣿⣧⠀⠃⢰⣿⣿⡏⠙⣿⠿⢧⣀⣼⣷⠀⡿⠃⠀⠀"
echo " ⠀⠀⠀⠉⣿⣿⣦⠀⢿⣿⣿⣷⣾⡏⠀⠀⢹⣿⣿⠀⠀⠀⠀⠀⠀"
echo " ⠀⠀⠀⠀⠀⠉⠛⠁⠈⠿⣿⣿⣿⣷⣄⣠⡼⠟⠁${NORMAL}${BOLD} Lume Local Installer${NORMAL}"
echo "${BLUE} Build from source${NORMAL}"
echo ""
echo "Building ${BOLD}$BUILD_CONFIG${NORMAL} configuration from ${BOLD}$LUME_DIR${NORMAL}"
echo ""
# Check for required tools
if ! command -v swift &> /dev/null; then
echo "${RED}Error: Swift is required but not installed.${NORMAL}"
echo "Install Xcode Command Line Tools: xcode-select --install"
exit 1
fi
# Build lume
build_lume() {
echo "Building lume ($BUILD_CONFIG)..."
cd "$LUME_DIR"
if [ "$BUILD_CONFIG" = "release" ]; then
swift build -c release --product lume
BUILD_PATH="$LUME_DIR/.build/release"
else
swift build --product lume
BUILD_PATH="$LUME_DIR/.build/debug"
fi
# Use local-safe entitlements by default.
ENTITLEMENTS_FILE="$LUME_DIR/resources/lume.local.entitlements"
if [ "$USE_BRIDGED_ENTITLEMENT" = true ]; then
ENTITLEMENTS_FILE="$LUME_DIR/resources/lume.entitlements"
fi
if [ "$USE_BRIDGED_ENTITLEMENT" = true ]; then
# Assemble .app bundle for provisioning profile support
echo "Assembling .app bundle for bridged networking..."
APP_BUNDLE="$BUILD_PATH/lume.app"
rm -rf "$APP_BUNDLE"
mkdir -p "$APP_BUNDLE/Contents/MacOS"
cp -f "$BUILD_PATH/lume" "$APP_BUNDLE/Contents/MacOS/lume"
# Copy resource bundle to Contents/Resources/.
# It CANNOT go in Contents/MacOS/ (breaks codesign: "bundle format unrecognized")
# and CANNOT go at the .app root (breaks codesign: "unsealed contents").
# The Swift code uses Bundle.lumeResources which checks resourceURL first.
mkdir -p "$APP_BUNDLE/Contents/Resources"
if [ -d "$BUILD_PATH/lume_lume.bundle" ]; then
cp -rf "$BUILD_PATH/lume_lume.bundle" "$APP_BUNDLE/Contents/Resources/"
fi
# Stamp Info.plist with version
CURRENT_VERSION=$("$BUILD_PATH/lume" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' || echo "0.0.0")
sed "s/__VERSION__/$CURRENT_VERSION/g" "$LUME_DIR/resources/Info.plist" > "$APP_BUNDLE/Contents/Info.plist"
# Embed provisioning profile if available
if [ -f "$LUME_DIR/resources/embedded.provisionprofile" ]; then
cp "$LUME_DIR/resources/embedded.provisionprofile" "$APP_BUNDLE/Contents/embedded.provisionprofile"
else
echo "${YELLOW}Warning: No provisioning profile found at $LUME_DIR/resources/embedded.provisionprofile${NORMAL}"
echo "${YELLOW}Bridged networking requires a provisioning profile from Apple Developer portal.${NORMAL}"
fi
# Sign the bundle
clear_signature_metadata "$APP_BUNDLE/Contents/MacOS/lume"
codesign --force --entitlements "$ENTITLEMENTS_FILE" --sign - "$APP_BUNDLE/Contents/MacOS/lume"
codesign --force --sign - "$APP_BUNDLE"
# Verify the signed binary can launch from the bundle
if "$APP_BUNDLE/Contents/MacOS/lume" --version >/dev/null 2>&1; then
USE_APP_BUNDLE=true
else
echo "${YELLOW}Warning: binary did not launch from .app bundle with bridged entitlement; falling back to standalone binary.${NORMAL}"
ENTITLEMENTS_FILE="$LUME_DIR/resources/lume.local.entitlements"
clear_signature_metadata "$BUILD_PATH/lume"
codesign --force --entitlements "$ENTITLEMENTS_FILE" --sign - "$BUILD_PATH/lume"
USE_APP_BUNDLE=false
fi
else
# Standard standalone binary (no .app bundle needed)
clear_signature_metadata "$BUILD_PATH/lume"
codesign --force --entitlements "$ENTITLEMENTS_FILE" --sign - "$BUILD_PATH/lume"
# Verify the signed binary can launch
if ! "$BUILD_PATH/lume" --version >/dev/null 2>&1; then
echo "${RED}Error: signed binary could not launch; refusing to install it.${NORMAL}"
exit 1
fi
USE_APP_BUNDLE=false
fi
echo "${GREEN}Build complete!${NORMAL}"
}
# Install the binary
install_binary() {
echo "Installing to $INSTALL_DIR..."
# Create install directory if it doesn't exist
mkdir -p "$INSTALL_DIR"
if [ "$USE_APP_BUNDLE" = true ]; then
# Install as .app bundle with wrapper script
mkdir -p "$APP_INSTALL_DIR"
rm -rf "$APP_INSTALL_DIR/lume.app"
cp -R "$BUILD_PATH/lume.app" "$APP_INSTALL_DIR/"
# Remove old standalone binary if it's a Mach-O file (migration)
if [ -f "$INSTALL_DIR/lume" ] && file "$INSTALL_DIR/lume" | grep -q "Mach-O"; then
rm -f "$INSTALL_DIR/lume"
fi
rm -rf "$INSTALL_DIR/lume_lume.bundle"
# Create wrapper script
cat > "$INSTALL_DIR/lume" <<WRAPPER_EOF
#!/bin/sh
exec "$APP_INSTALL_DIR/lume.app/Contents/MacOS/lume" "\$@"
WRAPPER_EOF
chmod +x "$INSTALL_DIR/lume"
echo "${GREEN}Installation complete!${NORMAL}"
echo "Lume installed to ${BOLD}$APP_INSTALL_DIR/lume.app${NORMAL}"
echo "CLI available at ${BOLD}$INSTALL_DIR/lume${NORMAL}"
else
# Install as standalone binary
# Replace the inode so taskgated does not reuse a stale signature cache.
rm -f "$INSTALL_DIR/lume"
cp -f "$BUILD_PATH/lume" "$INSTALL_DIR/lume"
chmod +x "$INSTALL_DIR/lume"
# Copy the resource bundle if it exists (contains unattended presets)
if [ -d "$BUILD_PATH/lume_lume.bundle" ]; then
rm -rf "$INSTALL_DIR/lume_lume.bundle"
cp -rf "$BUILD_PATH/lume_lume.bundle" "$INSTALL_DIR/"
echo "Resource bundle installed to ${BOLD}$INSTALL_DIR/lume_lume.bundle${NORMAL}"
fi
echo "${GREEN}Installation complete!${NORMAL}"
echo "Lume has been installed to ${BOLD}$INSTALL_DIR/lume${NORMAL}"
fi
# Check if the installation directory is in PATH
if [ -n "${PATH##*$INSTALL_DIR*}" ]; then
echo ""
echo "${YELLOW}Note: $INSTALL_DIR is not in your PATH${NORMAL}"
echo "Add this to your shell profile:"
echo " export PATH=\"\$PATH:$INSTALL_DIR\""
fi
}
# Setup background service (LaunchAgent)
setup_background_service() {
SERVICE_NAME="com.trycua.lume_daemon"
PLIST_PATH="$HOME/Library/LaunchAgents/$SERVICE_NAME.plist"
LUME_BIN="$INSTALL_DIR/lume"
echo ""
echo "Setting up LaunchAgent to run lume daemon..."
# Create LaunchAgents directory if it doesn't exist
mkdir -p "$HOME/Library/LaunchAgents"
# Unload existing service if present
if [ -f "$PLIST_PATH" ]; then
echo "Existing LaunchAgent found. Unloading..."
launchctl unload "$PLIST_PATH" 2>/dev/null || true
fi
# Create the plist file
cat <<EOF > "$PLIST_PATH"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>$SERVICE_NAME</string>
<key>ProgramArguments</key>
<array>
<string>$LUME_BIN</string>
<string>serve</string>
<string>--port</string>
<string>$LUME_PORT</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>WorkingDirectory</key>
<string>$HOME</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$HOME/.local/bin</string>
<key>HOME</key>
<string>$HOME</string>
</dict>
<key>StandardOutPath</key>
<string>/tmp/lume_daemon.log</string>
<key>StandardErrorPath</key>
<string>/tmp/lume_daemon.error.log</string>
<key>ProcessType</key>
<string>Interactive</string>
<key>SessionType</key>
<string>Aqua</string>
</dict>
</plist>
EOF
# Set permissions
chmod 644 "$PLIST_PATH"
touch /tmp/lume_daemon.log /tmp/lume_daemon.error.log
chmod 644 /tmp/lume_daemon.log /tmp/lume_daemon.error.log
# Load the LaunchAgent
echo "Loading LaunchAgent..."
launchctl load "$PLIST_PATH"
echo "${GREEN}Lume daemon LaunchAgent installed and loaded!${NORMAL}"
echo "To check status: launchctl list | grep $SERVICE_NAME"
echo "To view logs: tail -f /tmp/lume_daemon.log"
}
# Remove background service
remove_background_service() {
SERVICE_NAME="com.trycua.lume_daemon"
PLIST_PATH="$HOME/Library/LaunchAgents/$SERVICE_NAME.plist"
if [ -f "$PLIST_PATH" ]; then
echo "Removing existing Lume background service (LaunchAgent)..."
launchctl unload "$PLIST_PATH" 2>/dev/null || true
rm "$PLIST_PATH"
echo "Lume background service removed."
fi
}
# Main installation flow
main() {
build_lume
install_binary
echo ""
echo "${GREEN}${BOLD}Lume ($BUILD_CONFIG) has been successfully installed!${NORMAL}"
echo "Run ${BOLD}lume${NORMAL} to get started."
if [ "$USE_BRIDGED_ENTITLEMENT" = false ]; then
echo "${YELLOW}Note: local installer signs without com.apple.vm.networking by default.${NORMAL}"
fi
if [ "$INSTALL_BACKGROUND_SERVICE" = true ]; then
setup_background_service
else
remove_background_service
echo "Skipping background service setup (use without --no-background-service to enable)."
fi
echo ""
echo "${YELLOW}Note: This is a local build. Auto-updater is not installed.${NORMAL}"
}
# Run the installation
main