250 lines
9.2 KiB
Bash
Executable File
250 lines
9.2 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
# Arguments passed from the main script
|
|
VERSION="$1"
|
|
ARCHITECTURE="$2"
|
|
WORK_DIR="$3" # The top-level build directory (e.g., ./build)
|
|
APP_STAGING_DIR="$4" # Directory containing the prepared app files (e.g., ./build/electron-app)
|
|
PACKAGE_NAME="$5"
|
|
MAINTAINER="$6"
|
|
DESCRIPTION="$7"
|
|
|
|
echo "--- Starting Debian Package Build ---"
|
|
echo "Version: $VERSION"
|
|
echo "Architecture: $ARCHITECTURE"
|
|
echo "Work Directory: $WORK_DIR"
|
|
echo "App Staging Directory: $APP_STAGING_DIR"
|
|
echo "Package Name: $PACKAGE_NAME"
|
|
|
|
PACKAGE_ROOT="$WORK_DIR/package"
|
|
INSTALL_DIR="$PACKAGE_ROOT/usr"
|
|
|
|
# Clean previous package structure if it exists
|
|
rm -rf "$PACKAGE_ROOT"
|
|
|
|
# Create Debian package structure
|
|
echo "Creating package structure in $PACKAGE_ROOT..."
|
|
mkdir -p "$PACKAGE_ROOT/DEBIAN"
|
|
mkdir -p "$INSTALL_DIR/lib/$PACKAGE_NAME"
|
|
mkdir -p "$INSTALL_DIR/share/applications"
|
|
mkdir -p "$INSTALL_DIR/share/icons"
|
|
mkdir -p "$INSTALL_DIR/bin"
|
|
|
|
# --- Icon Installation ---
|
|
echo "🎨 Installing icons..."
|
|
# Map icon sizes to their corresponding extracted files (relative to WORK_DIR)
|
|
declare -A icon_files=(
|
|
["16"]="claude_13_16x16x32.png"
|
|
["24"]="claude_11_24x24x32.png"
|
|
["32"]="claude_10_32x32x32.png"
|
|
["48"]="claude_8_48x48x32.png"
|
|
["64"]="claude_7_64x64x32.png"
|
|
["256"]="claude_6_256x256x32.png"
|
|
)
|
|
|
|
for size in 16 24 32 48 64 256; do
|
|
icon_dir="$INSTALL_DIR/share/icons/hicolor/${size}x${size}/apps"
|
|
mkdir -p "$icon_dir"
|
|
icon_source_path="$WORK_DIR/${icon_files[$size]}"
|
|
if [ -f "$icon_source_path" ]; then
|
|
echo "Installing ${size}x${size} icon from $icon_source_path..."
|
|
install -Dm 644 "$icon_source_path" "$icon_dir/claude-desktop.png"
|
|
else
|
|
echo "Warning: Missing ${size}x${size} icon at $icon_source_path"
|
|
fi
|
|
done
|
|
echo "✓ Icons installed"
|
|
|
|
# --- Copy Application Files ---
|
|
echo "📦 Copying application files from $APP_STAGING_DIR..."
|
|
cp "$APP_STAGING_DIR/app.asar" "$INSTALL_DIR/lib/$PACKAGE_NAME/"
|
|
cp -r "$APP_STAGING_DIR/app.asar.unpacked" "$INSTALL_DIR/lib/$PACKAGE_NAME/"
|
|
|
|
# Copy local electron if it was packaged (check if node_modules exists in staging)
|
|
if [ -d "$APP_STAGING_DIR/node_modules" ]; then
|
|
echo "Copying packaged electron..."
|
|
cp -r "$APP_STAGING_DIR/node_modules" "$INSTALL_DIR/lib/$PACKAGE_NAME/"
|
|
fi
|
|
echo "✓ Application files copied"
|
|
|
|
# --- Create Desktop Entry ---
|
|
echo "📝 Creating desktop entry..."
|
|
cat > "$INSTALL_DIR/share/applications/claude-desktop.desktop" << EOF
|
|
[Desktop Entry]
|
|
Name=Claude
|
|
Exec=/usr/bin/claude-desktop %u
|
|
Icon=claude-desktop
|
|
Type=Application
|
|
Terminal=false
|
|
Categories=Office;Utility;
|
|
MimeType=x-scheme-handler/claude;
|
|
StartupWMClass=Claude
|
|
EOF
|
|
echo "✓ Desktop entry created"
|
|
|
|
# --- Create Launcher Script ---
|
|
echo "🚀 Creating launcher script..."
|
|
cat > "$INSTALL_DIR/bin/claude-desktop" << EOF
|
|
#!/bin/bash
|
|
LOG_FILE="\$HOME/claude-desktop-launcher.log"
|
|
echo "--- Claude Desktop Launcher Start ---" >> "\$LOG_FILE"
|
|
echo "Timestamp: \$(date)" >> "\$LOG_FILE"
|
|
echo "Arguments: \$@" >> "\$LOG_FILE"
|
|
|
|
export ELECTRON_FORCE_IS_PACKAGED=true
|
|
|
|
# Detect if Wayland is likely running
|
|
IS_WAYLAND=false
|
|
if [ ! -z "\$WAYLAND_DISPLAY" ]; then
|
|
IS_WAYLAND=true
|
|
echo "Wayland detected" >> "\$LOG_FILE"
|
|
fi
|
|
|
|
# Check for display issues and set compatibility mode if needed
|
|
if [ "\$IS_WAYLAND" = true ]; then
|
|
echo "Setting Wayland compatibility mode..." >> "\$LOG_FILE"
|
|
# Use native Wayland backend with GlobalShortcuts Portal support
|
|
export ELECTRON_OZONE_PLATFORM_HINT=wayland
|
|
# Keep GPU acceleration enabled for better performance
|
|
echo "Wayland compatibility mode enabled (using native Wayland backend)" >> "\$LOG_FILE"
|
|
elif [ -z "\$DISPLAY" ] && [ -z "\$WAYLAND_DISPLAY" ]; then
|
|
echo "No display detected (TTY session) - cannot start graphical application" >> "\$LOG_FILE"
|
|
# No graphical environment detected; display error message in TTY session
|
|
echo "Error: Claude Desktop requires a graphical desktop environment." >&2
|
|
echo "Please run from within an X11 or Wayland session, not from a TTY." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Determine Electron executable path
|
|
ELECTRON_EXEC="electron" # Default to global
|
|
LOCAL_ELECTRON_PATH="/usr/lib/$PACKAGE_NAME/node_modules/electron/dist/electron" # Correct path to executable
|
|
if [ -f "\$LOCAL_ELECTRON_PATH" ]; then
|
|
ELECTRON_EXEC="\$LOCAL_ELECTRON_PATH"
|
|
echo "Using local Electron: \$ELECTRON_EXEC" >> "\$LOG_FILE"
|
|
else
|
|
# Check if global electron exists before declaring it as the choice
|
|
if command -v electron &> /dev/null; then
|
|
echo "Using global Electron: \$ELECTRON_EXEC" >> "\$LOG_FILE"
|
|
else
|
|
echo "Error: Electron executable not found (checked local \$LOCAL_ELECTRON_PATH and global path)." >> "\$LOG_FILE" # Log the correct path checked
|
|
# Optionally, display an error to the user via zenity or kdialog if available
|
|
if command -v zenity &> /dev/null; then
|
|
zenity --error --text="Claude Desktop cannot start because the Electron framework is missing. Please ensure Electron is installed globally or reinstall Claude Desktop."
|
|
elif command -v kdialog &> /dev/null; then
|
|
kdialog --error "Claude Desktop cannot start because the Electron framework is missing. Please ensure Electron is installed globally or reinstall Claude Desktop."
|
|
fi
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Base command arguments array, starting with app path
|
|
APP_PATH="/usr/lib/$PACKAGE_NAME/app.asar"
|
|
ELECTRON_ARGS=("\$APP_PATH")
|
|
|
|
# Add compatibility flags
|
|
if [ "\$IS_WAYLAND" = true ]; then
|
|
echo "Adding compatibility flags for Wayland session" >> "\$LOG_FILE"
|
|
ELECTRON_ARGS+=("--no-sandbox")
|
|
# Enable Wayland features for Electron 37+
|
|
ELECTRON_ARGS+=("--enable-features=UseOzonePlatform,WaylandWindowDecorations,GlobalShortcutsPortal")
|
|
ELECTRON_ARGS+=("--ozone-platform=wayland")
|
|
ELECTRON_ARGS+=("--enable-wayland-ime")
|
|
ELECTRON_ARGS+=("--wayland-text-input-version=3")
|
|
echo "Enabled native Wayland support with GlobalShortcuts Portal" >> "\$LOG_FILE"
|
|
fi
|
|
|
|
# Change to the application directory
|
|
APP_DIR="/usr/lib/$PACKAGE_NAME"
|
|
echo "Changing directory to \$APP_DIR" >> "\$LOG_FILE"
|
|
cd "\$APP_DIR" || { echo "Failed to cd to \$APP_DIR" >> "\$LOG_FILE"; exit 1; }
|
|
|
|
# Execute Electron with app path, flags, and script arguments
|
|
# Redirect stdout and stderr to the log file
|
|
FINAL_CMD="\"\$ELECTRON_EXEC\" \"\${ELECTRON_ARGS[@]}\" \"\$@\""
|
|
echo "Executing: \$FINAL_CMD" >> "\$LOG_FILE"
|
|
"\$ELECTRON_EXEC" "\${ELECTRON_ARGS[@]}" "\$@" >> "\$LOG_FILE" 2>&1
|
|
EXIT_CODE=\$?
|
|
echo "Electron exited with code: \$EXIT_CODE" >> "\$LOG_FILE"
|
|
echo "--- Claude Desktop Launcher End ---" >> "\$LOG_FILE"
|
|
exit \$EXIT_CODE
|
|
EOF
|
|
chmod +x "$INSTALL_DIR/bin/claude-desktop"
|
|
echo "✓ Launcher script created"
|
|
|
|
# --- Create Control File ---
|
|
echo "📄 Creating control file..."
|
|
# Determine dependencies based on whether electron was packaged
|
|
DEPENDS="nodejs, npm, p7zip-full" # Base dependencies
|
|
# Electron is now always packaged locally, so it's not listed as an external dependency.
|
|
echo "Electron is packaged locally; not adding to external Depends list."
|
|
|
|
cat > "$PACKAGE_ROOT/DEBIAN/control" << EOF
|
|
Package: $PACKAGE_NAME
|
|
Version: $VERSION
|
|
Architecture: $ARCHITECTURE
|
|
Maintainer: $MAINTAINER
|
|
Depends: $DEPENDS
|
|
Description: $DESCRIPTION
|
|
Claude is an AI assistant from Anthropic.
|
|
This package provides the desktop interface for Claude.
|
|
.
|
|
Supported on Debian-based Linux distributions (Debian, Ubuntu, Linux Mint, MX Linux, etc.)
|
|
Requires: nodejs (>= 12.0.0), npm
|
|
EOF
|
|
echo "✓ Control file created"
|
|
|
|
# --- Create Postinst Script ---
|
|
echo "⚙️ Creating postinst script..."
|
|
cat > "$PACKAGE_ROOT/DEBIAN/postinst" << EOF
|
|
#!/bin/sh
|
|
set -e
|
|
|
|
# Update desktop database for MIME types
|
|
echo "Updating desktop database..."
|
|
update-desktop-database /usr/share/applications &> /dev/null || true
|
|
|
|
# Set correct permissions for chrome-sandbox if electron is installed globally or locally packaged
|
|
echo "Setting chrome-sandbox permissions..."
|
|
SANDBOX_PATH=""
|
|
# Electron is always packaged locally now, so only check the local path.
|
|
LOCAL_SANDBOX_PATH="/usr/lib/$PACKAGE_NAME/node_modules/electron/dist/chrome-sandbox" # Correct path to sandbox
|
|
if [ -f "\$LOCAL_SANDBOX_PATH" ]; then
|
|
SANDBOX_PATH="\$LOCAL_SANDBOX_PATH"
|
|
fi
|
|
|
|
if [ -n "\$SANDBOX_PATH" ] && [ -f "\$SANDBOX_PATH" ]; then
|
|
echo "Found chrome-sandbox at: \$SANDBOX_PATH"
|
|
chown root:root "\$SANDBOX_PATH" || echo "Warning: Failed to chown chrome-sandbox"
|
|
chmod 4755 "\$SANDBOX_PATH" || echo "Warning: Failed to chmod chrome-sandbox"
|
|
echo "Permissions set for \$SANDBOX_PATH"
|
|
else
|
|
echo "Warning: chrome-sandbox binary not found in local package at \$LOCAL_SANDBOX_PATH. Sandbox may not function correctly." # Log the correct path checked
|
|
fi
|
|
|
|
exit 0
|
|
EOF
|
|
chmod +x "$PACKAGE_ROOT/DEBIAN/postinst"
|
|
echo "✓ Postinst script created"
|
|
|
|
# --- Build .deb Package ---
|
|
echo "📦 Building .deb package..."
|
|
DEB_FILE="$WORK_DIR/${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb"
|
|
|
|
# Fix DEBIAN directory permissions (must be 755 for dpkg-deb)
|
|
echo "Setting DEBIAN directory permissions..."
|
|
chmod 755 "$PACKAGE_ROOT/DEBIAN"
|
|
|
|
# Fix script permissions in DEBIAN directory
|
|
echo "Setting script permissions..."
|
|
chmod 755 "$PACKAGE_ROOT/DEBIAN/postinst"
|
|
|
|
if ! dpkg-deb --build "$PACKAGE_ROOT" "$DEB_FILE"; then
|
|
echo "❌ Failed to build .deb package"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ .deb package built successfully: $DEB_FILE"
|
|
echo "--- Debian Package Build Finished ---"
|
|
|
|
exit 0 |