mirror of
https://github.com/aaddrick/claude-desktop-debian.git
synced 2026-05-17 08:36:35 +03:00
refactor: apply bash style guide to all build scripts
Apply consistent bash style guide (style.ysap.sh) across all scripts: - Change shebang to #!/usr/bin/env bash - Remove set -e/set -euo pipefail, add explicit error handling - Convert indentation from 4 spaces to tabs - Use lowercase for variables, UPPERCASE only for exports/constants - Use [[ ]] for conditionals, (( )) for arithmetic - Use single quotes for literals, double quotes for expansion - Remove emoji characters from output messages Files refactored: - build.sh (~991 lines) - scripts/build-appimage.sh (~311 lines) - scripts/build-deb-package.sh (~242 lines) - scripts/launcher-common.sh (~95 lines) Tested: AppImage build completes successfully in distrobox. Fixes #179 Co-Authored-By: Claude <claude@anthropic.com>
This commit is contained in:
@@ -1,168 +1,168 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 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 and DESCRIPTION might not be directly used by AppImage tools but passed for consistency
|
||||
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
|
||||
package_name="$5"
|
||||
# MAINTAINER and DESCRIPTION might not be directly used by AppImage tools
|
||||
# but passed for consistency
|
||||
|
||||
echo "--- Starting AppImage Build ---"
|
||||
echo "Version: $VERSION"
|
||||
echo "Architecture: $ARCHITECTURE"
|
||||
echo "Work Directory: $WORK_DIR"
|
||||
echo "App Staging Directory: $APP_STAGING_DIR"
|
||||
echo "Package Name: $PACKAGE_NAME"
|
||||
echo '--- Starting AppImage Build ---'
|
||||
echo "Version: $version"
|
||||
echo "Architecture: $architecture"
|
||||
echo "Work Directory: $work_dir"
|
||||
echo "App Staging Directory: $app_staging_dir"
|
||||
echo "Package Name: $package_name"
|
||||
|
||||
COMPONENT_ID="io.github.aaddrick.claude-desktop-debian"
|
||||
component_id='io.github.aaddrick.claude-desktop-debian'
|
||||
# Define AppDir structure path
|
||||
APPDIR_PATH="$WORK_DIR/${COMPONENT_ID}.AppDir"
|
||||
rm -rf "$APPDIR_PATH"
|
||||
mkdir -p "$APPDIR_PATH/usr/bin"
|
||||
mkdir -p "$APPDIR_PATH/usr/lib"
|
||||
mkdir -p "$APPDIR_PATH/usr/share/icons/hicolor/256x256/apps"
|
||||
mkdir -p "$APPDIR_PATH/usr/share/applications"
|
||||
appdir_path="$work_dir/${component_id}.AppDir"
|
||||
rm -rf "$appdir_path"
|
||||
mkdir -p "$appdir_path/usr/bin" || exit 1
|
||||
mkdir -p "$appdir_path/usr/lib" || exit 1
|
||||
mkdir -p "$appdir_path/usr/share/icons/hicolor/256x256/apps" || exit 1
|
||||
mkdir -p "$appdir_path/usr/share/applications" || exit 1
|
||||
|
||||
echo "📦 Staging application files into AppDir..."
|
||||
echo 'Staging application files into AppDir...'
|
||||
# Copy node_modules first to set up Electron directory structure
|
||||
if [ -d "$APP_STAGING_DIR/node_modules" ]; then
|
||||
echo "Copying node_modules from staging to AppDir..."
|
||||
cp -a "$APP_STAGING_DIR/node_modules" "$APPDIR_PATH/usr/lib/"
|
||||
if [[ -d $app_staging_dir/node_modules ]]; then
|
||||
echo 'Copying node_modules from staging to AppDir...'
|
||||
cp -a "$app_staging_dir/node_modules" "$appdir_path/usr/lib/" || exit 1
|
||||
fi
|
||||
|
||||
# Install app.asar in Electron's resources directory where process.resourcesPath points
|
||||
RESOURCES_DIR="$APPDIR_PATH/usr/lib/node_modules/electron/dist/resources"
|
||||
mkdir -p "$RESOURCES_DIR"
|
||||
if [ -f "$APP_STAGING_DIR/app.asar" ]; then
|
||||
cp -a "$APP_STAGING_DIR/app.asar" "$RESOURCES_DIR/"
|
||||
resources_dir="$appdir_path/usr/lib/node_modules/electron/dist/resources"
|
||||
mkdir -p "$resources_dir" || exit 1
|
||||
if [[ -f $app_staging_dir/app.asar ]]; then
|
||||
cp -a "$app_staging_dir/app.asar" "$resources_dir/" || exit 1
|
||||
fi
|
||||
if [ -d "$APP_STAGING_DIR/app.asar.unpacked" ]; then
|
||||
cp -a "$APP_STAGING_DIR/app.asar.unpacked" "$RESOURCES_DIR/"
|
||||
if [[ -d $app_staging_dir/app.asar.unpacked ]]; then
|
||||
cp -a "$app_staging_dir/app.asar.unpacked" "$resources_dir/" || exit 1
|
||||
fi
|
||||
echo "✓ Application files copied to Electron resources directory"
|
||||
echo 'Application files copied to Electron resources directory'
|
||||
|
||||
# Copy shared launcher library
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
mkdir -p "$APPDIR_PATH/usr/lib/claude-desktop"
|
||||
cp "$SCRIPT_DIR/launcher-common.sh" "$APPDIR_PATH/usr/lib/claude-desktop/"
|
||||
echo "✓ Shared launcher library copied"
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
mkdir -p "$appdir_path/usr/lib/claude-desktop" || exit 1
|
||||
cp "$script_dir/launcher-common.sh" "$appdir_path/usr/lib/claude-desktop/" || exit 1
|
||||
echo 'Shared launcher library copied'
|
||||
|
||||
# Ensure Electron is bundled within the AppDir for portability
|
||||
# Check if electron was copied into the staging dir's node_modules
|
||||
# The actual executable is usually inside the 'dist' directory
|
||||
BUNDLED_ELECTRON_PATH="$APPDIR_PATH/usr/lib/node_modules/electron/dist/electron"
|
||||
echo "Checking for executable at: $BUNDLED_ELECTRON_PATH"
|
||||
if [ ! -x "$BUNDLED_ELECTRON_PATH" ]; then # Check if it exists and is executable
|
||||
echo "❌ Electron executable not found or not executable in staging area ($BUNDLED_ELECTRON_PATH)."
|
||||
echo " AppImage requires Electron to be bundled. Ensure the main script copies it correctly."
|
||||
exit 1
|
||||
bundled_electron_path="$appdir_path/usr/lib/node_modules/electron/dist/electron"
|
||||
echo "Checking for executable at: $bundled_electron_path"
|
||||
if [[ ! -x $bundled_electron_path ]]; then
|
||||
echo 'Electron executable not found or not executable in staging area.' >&2
|
||||
echo "Path checked: $bundled_electron_path" >&2
|
||||
echo 'AppImage requires Electron to be bundled. Ensure the main script copies it correctly.' >&2
|
||||
exit 1
|
||||
fi
|
||||
# Ensure the bundled electron is executable (redundant check, but safe)
|
||||
chmod +x "$BUNDLED_ELECTRON_PATH"
|
||||
chmod +x "$bundled_electron_path" || exit 1
|
||||
|
||||
# --- Create AppRun Script ---
|
||||
echo "🚀 Creating AppRun script..."
|
||||
cat > "$APPDIR_PATH/AppRun" << 'EOF'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo 'Creating AppRun script...'
|
||||
cat > "$appdir_path/AppRun" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Find the location of the AppRun script
|
||||
APPDIR=$(dirname "$(readlink -f "$0")")
|
||||
appdir=$(dirname "$(readlink -f "$0")")
|
||||
|
||||
# Source shared launcher library
|
||||
source "$APPDIR/usr/lib/claude-desktop/launcher-common.sh"
|
||||
source "$appdir/usr/lib/claude-desktop/launcher-common.sh"
|
||||
|
||||
# Setup logging and environment
|
||||
setup_logging
|
||||
setup_logging || exit 1
|
||||
setup_electron_env
|
||||
|
||||
# Detect display backend
|
||||
detect_display_backend
|
||||
|
||||
# Log startup info
|
||||
log_message "--- Claude Desktop AppImage Start ---"
|
||||
log_message '--- Claude Desktop AppImage Start ---'
|
||||
log_message "Timestamp: $(date)"
|
||||
log_message "Arguments: $@"
|
||||
log_message "APPDIR: $APPDIR"
|
||||
log_message "APPDIR: $appdir"
|
||||
|
||||
# Path to the bundled Electron executable and app
|
||||
ELECTRON_EXEC="$APPDIR/usr/lib/node_modules/electron/dist/electron"
|
||||
APP_PATH="$APPDIR/usr/lib/node_modules/electron/dist/resources/app.asar"
|
||||
electron_exec="$appdir/usr/lib/node_modules/electron/dist/electron"
|
||||
app_path="$appdir/usr/lib/node_modules/electron/dist/resources/app.asar"
|
||||
|
||||
# Build electron args (appimage mode adds --no-sandbox)
|
||||
build_electron_args "appimage"
|
||||
build_electron_args 'appimage'
|
||||
|
||||
# Add app path LAST - Chromium flags must come before this
|
||||
ELECTRON_ARGS+=("$APP_PATH")
|
||||
electron_args+=("$app_path")
|
||||
|
||||
# Change to HOME directory before exec'ing Electron to avoid CWD permission issues
|
||||
cd "$HOME" || exit 1
|
||||
|
||||
# Execute Electron
|
||||
log_message "Executing: $ELECTRON_EXEC ${ELECTRON_ARGS[*]} $*"
|
||||
exec "$ELECTRON_EXEC" "${ELECTRON_ARGS[@]}" "$@" >> "$LOG_FILE" 2>&1
|
||||
log_message "Executing: $electron_exec ${electron_args[*]} $*"
|
||||
exec "$electron_exec" "${electron_args[@]}" "$@" >> "$log_file" 2>&1
|
||||
EOF
|
||||
chmod +x "$APPDIR_PATH/AppRun"
|
||||
echo "✓ AppRun script created"
|
||||
chmod +x "$appdir_path/AppRun" || exit 1
|
||||
echo 'AppRun script created'
|
||||
|
||||
# --- Create Desktop Entry (Bundled inside AppDir) ---
|
||||
echo "📝 Creating bundled desktop entry..."
|
||||
echo 'Creating bundled desktop entry...'
|
||||
# This is the desktop file *inside* the AppImage, used by tools like appimaged
|
||||
cat > "$APPDIR_PATH/$COMPONENT_ID.desktop" << EOF
|
||||
cat > "$appdir_path/$component_id.desktop" << EOF
|
||||
[Desktop Entry]
|
||||
Name=Claude
|
||||
Exec=AppRun %u
|
||||
Icon=$COMPONENT_ID
|
||||
Icon=$component_id
|
||||
Type=Application
|
||||
Terminal=false
|
||||
Categories=Network;Utility;
|
||||
Comment=Claude Desktop for Linux
|
||||
MimeType=x-scheme-handler/claude;
|
||||
StartupWMClass=Claude
|
||||
X-AppImage-Version=$VERSION
|
||||
X-AppImage-Version=$version
|
||||
X-AppImage-Name=Claude Desktop
|
||||
EOF
|
||||
# Also place it in the standard location for tools like appimaged and validation
|
||||
mkdir -p "$APPDIR_PATH/usr/share/applications"
|
||||
cp "$APPDIR_PATH/$COMPONENT_ID.desktop" "$APPDIR_PATH/usr/share/applications/"
|
||||
echo "✓ Bundled desktop entry created and copied to usr/share/applications/"
|
||||
mkdir -p "$appdir_path/usr/share/applications" || exit 1
|
||||
cp "$appdir_path/$component_id.desktop" "$appdir_path/usr/share/applications/" || exit 1
|
||||
echo 'Bundled desktop entry created and copied to usr/share/applications/'
|
||||
|
||||
# --- Copy Icons ---
|
||||
echo "🎨 Copying icons..."
|
||||
echo 'Copying icons...'
|
||||
# Use the 256x256 icon as the main AppImage icon
|
||||
ICON_SOURCE_PATH="$WORK_DIR/claude_6_256x256x32.png"
|
||||
if [ -f "$ICON_SOURCE_PATH" ]; then
|
||||
# Standard location within AppDir
|
||||
cp "$ICON_SOURCE_PATH" "$APPDIR_PATH/usr/share/icons/hicolor/256x256/apps/${COMPONENT_ID}.png"
|
||||
# Top-level icon (used by appimagetool) - Should match the Icon field in the .desktop file
|
||||
cp "$ICON_SOURCE_PATH" "$APPDIR_PATH/${COMPONENT_ID}.png"
|
||||
# Top-level icon without extension (fallback for some tools)
|
||||
cp "$ICON_SOURCE_PATH" "$APPDIR_PATH/${COMPONENT_ID}"
|
||||
# Hidden .DirIcon (fallback for some systems/tools)
|
||||
cp "$ICON_SOURCE_PATH" "$APPDIR_PATH/.DirIcon"
|
||||
echo "✓ Icon copied to standard path, top-level (.png and no ext), and .DirIcon"
|
||||
icon_source_path="$work_dir/claude_6_256x256x32.png"
|
||||
if [[ -f $icon_source_path ]]; then
|
||||
# Standard location within AppDir
|
||||
cp "$icon_source_path" "$appdir_path/usr/share/icons/hicolor/256x256/apps/${component_id}.png" || exit 1
|
||||
# Top-level icon (used by appimagetool) - Should match the Icon field in .desktop
|
||||
cp "$icon_source_path" "$appdir_path/${component_id}.png" || exit 1
|
||||
# Top-level icon without extension (fallback for some tools)
|
||||
cp "$icon_source_path" "$appdir_path/${component_id}" || exit 1
|
||||
# Hidden .DirIcon (fallback for some systems/tools)
|
||||
cp "$icon_source_path" "$appdir_path/.DirIcon" || exit 1
|
||||
echo 'Icon copied to standard path, top-level (.png and no ext), and .DirIcon'
|
||||
else
|
||||
echo "Warning: Missing 256x256 icon at $ICON_SOURCE_PATH. AppImage icon might be missing."
|
||||
echo "Warning: Missing 256x256 icon at $icon_source_path. AppImage icon might be missing."
|
||||
fi
|
||||
|
||||
# --- Create AppStream Metadata ---
|
||||
echo "📄 Creating AppStream metadata..."
|
||||
METADATA_DIR="$APPDIR_PATH/usr/share/metainfo"
|
||||
mkdir -p "$METADATA_DIR"
|
||||
echo 'Creating AppStream metadata...'
|
||||
metadata_dir="$appdir_path/usr/share/metainfo"
|
||||
mkdir -p "$metadata_dir" || exit 1
|
||||
|
||||
# Use the package name for the appdata file name (seems required by appimagetool warning)
|
||||
# Use reverse-DNS for component ID and filename, following common practice
|
||||
APPDATA_FILE="$METADATA_DIR/${COMPONENT_ID}.appdata.xml" # Filename matches component ID
|
||||
appdata_file="$metadata_dir/${component_id}.appdata.xml"
|
||||
|
||||
# Generate the AppStream XML file
|
||||
# Use MIT license based on LICENSE-MIT file in repo
|
||||
# ID follows reverse DNS convention
|
||||
cat > "$APPDATA_FILE" << EOF
|
||||
cat > "$appdata_file" << EOF
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>$COMPONENT_ID</id>
|
||||
<id>$component_id</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>MIT</project_license>
|
||||
<developer id="io.github.aaddrick">
|
||||
@@ -178,9 +178,9 @@ cat > "$APPDATA_FILE" << EOF
|
||||
</p>
|
||||
</description>
|
||||
|
||||
<launchable type="desktop-id">${COMPONENT_ID}.desktop</launchable> <!-- Reference the actual .desktop file -->
|
||||
<launchable type="desktop-id">${component_id}.desktop</launchable>
|
||||
|
||||
<icon type="stock">${COMPONENT_ID}</icon> <!-- Use the icon name from .desktop -->
|
||||
<icon type="stock">${component_id}</icon>
|
||||
<url type="homepage">https://github.com/aaddrick/claude-desktop-debian</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
@@ -188,7 +188,7 @@ cat > "$APPDATA_FILE" << EOF
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<provides>
|
||||
<binary>AppRun</binary> <!-- Provide the actual binary -->
|
||||
<binary>AppRun</binary>
|
||||
</provides>
|
||||
|
||||
<categories>
|
||||
@@ -199,113 +199,116 @@ cat > "$APPDATA_FILE" << EOF
|
||||
<content_rating type="oars-1.1" />
|
||||
|
||||
<releases>
|
||||
<release version="$VERSION" date="$(date +%Y-%m-%d)">
|
||||
<release version="$version" date="$(date +%Y-%m-%d)">
|
||||
<description>
|
||||
<p>Version $VERSION.</p>
|
||||
<p>Version $version.</p>
|
||||
</description>
|
||||
</release>
|
||||
</releases>
|
||||
|
||||
</component>
|
||||
EOF
|
||||
echo "✓ AppStream metadata created at $APPDATA_FILE"
|
||||
echo "AppStream metadata created at $appdata_file"
|
||||
|
||||
|
||||
# --- Get appimagetool ---
|
||||
APPIMAGETOOL_PATH=""
|
||||
appimagetool_path=''
|
||||
if command -v appimagetool &> /dev/null; then
|
||||
APPIMAGETOOL_PATH=$(command -v appimagetool)
|
||||
echo "✓ Found appimagetool in PATH: $APPIMAGETOOL_PATH"
|
||||
elif [ -f "$WORK_DIR/appimagetool-x86_64.AppImage" ]; then # Check for specific arch first
|
||||
APPIMAGETOOL_PATH="$WORK_DIR/appimagetool-x86_64.AppImage"
|
||||
echo "✓ Found downloaded x86_64 appimagetool: $APPIMAGETOOL_PATH"
|
||||
elif [ -f "$WORK_DIR/appimagetool-aarch64.AppImage" ]; then # Check for other arch
|
||||
APPIMAGETOOL_PATH="$WORK_DIR/appimagetool-aarch64.AppImage"
|
||||
echo "✓ Found downloaded aarch64 appimagetool: $APPIMAGETOOL_PATH"
|
||||
appimagetool_path=$(command -v appimagetool)
|
||||
echo "Found appimagetool in PATH: $appimagetool_path"
|
||||
elif [[ -f $work_dir/appimagetool-x86_64.AppImage ]]; then
|
||||
appimagetool_path="$work_dir/appimagetool-x86_64.AppImage"
|
||||
echo "Found downloaded x86_64 appimagetool: $appimagetool_path"
|
||||
elif [[ -f $work_dir/appimagetool-aarch64.AppImage ]]; then
|
||||
appimagetool_path="$work_dir/appimagetool-aarch64.AppImage"
|
||||
echo "Found downloaded aarch64 appimagetool: $appimagetool_path"
|
||||
else
|
||||
echo "🛠️ Downloading appimagetool..."
|
||||
# Determine architecture for download URL
|
||||
TOOL_ARCH=""
|
||||
case "$ARCHITECTURE" in # Use target ARCHITECTURE passed to script
|
||||
"amd64") TOOL_ARCH="x86_64" ;;
|
||||
"arm64") TOOL_ARCH="aarch64" ;;
|
||||
*) echo "❌ Unsupported architecture for appimagetool download: $ARCHITECTURE"; exit 1 ;;
|
||||
esac
|
||||
echo 'Downloading appimagetool...'
|
||||
# Determine architecture for download URL
|
||||
tool_arch=''
|
||||
case "$architecture" in
|
||||
'amd64') tool_arch='x86_64' ;;
|
||||
'arm64') tool_arch='aarch64' ;;
|
||||
*)
|
||||
echo "Unsupported architecture for appimagetool download: $architecture" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
APPIMAGETOOL_URL="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-${TOOL_ARCH}.AppImage"
|
||||
APPIMAGETOOL_PATH="$WORK_DIR/appimagetool-${TOOL_ARCH}.AppImage"
|
||||
appimagetool_url="https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-${tool_arch}.AppImage"
|
||||
appimagetool_path="$work_dir/appimagetool-${tool_arch}.AppImage"
|
||||
|
||||
if wget -q -O "$APPIMAGETOOL_PATH" "$APPIMAGETOOL_URL"; then
|
||||
chmod +x "$APPIMAGETOOL_PATH"
|
||||
echo "✓ Downloaded appimagetool to $APPIMAGETOOL_PATH"
|
||||
else
|
||||
echo "❌ Failed to download appimagetool from $APPIMAGETOOL_URL"
|
||||
rm -f "$APPIMAGETOOL_PATH" # Clean up partial download
|
||||
exit 1
|
||||
fi
|
||||
if wget -q -O "$appimagetool_path" "$appimagetool_url"; then
|
||||
chmod +x "$appimagetool_path" || exit 1
|
||||
echo "Downloaded appimagetool to $appimagetool_path"
|
||||
else
|
||||
echo "Failed to download appimagetool from $appimagetool_url" >&2
|
||||
rm -f "$appimagetool_path"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Build AppImage ---
|
||||
echo "📦 Building AppImage..."
|
||||
OUTPUT_FILENAME="${PACKAGE_NAME}-${VERSION}-${ARCHITECTURE}.AppImage"
|
||||
OUTPUT_PATH="$WORK_DIR/$OUTPUT_FILENAME"
|
||||
echo 'Building AppImage...'
|
||||
output_filename="${package_name}-${version}-${architecture}.AppImage"
|
||||
output_path="$work_dir/$output_filename"
|
||||
|
||||
# --- Prepare Update Information (GitHub Actions only) ---
|
||||
# Check if running in GitHub Actions workflow
|
||||
if [ "$GITHUB_ACTIONS" = "true" ]; then
|
||||
echo "🔄 Running in GitHub Actions - embedding update information for automatic updates..."
|
||||
|
||||
# Check if zsyncmake is available (required for generating .zsync files)
|
||||
if ! command -v zsyncmake &> /dev/null; then
|
||||
echo "⚠️ zsyncmake not found. Installing zsync package for .zsync file generation..."
|
||||
if command -v apt-get &> /dev/null; then
|
||||
sudo apt-get update && sudo apt-get install -y zsync
|
||||
elif command -v dnf &> /dev/null; then
|
||||
sudo dnf install -y zsync
|
||||
elif command -v zypper &> /dev/null; then
|
||||
sudo zypper install -y zsync
|
||||
else
|
||||
echo "⚠️ Cannot install zsync automatically. .zsync files may not be generated."
|
||||
fi
|
||||
fi
|
||||
if [[ $GITHUB_ACTIONS == 'true' ]]; then
|
||||
echo 'Running in GitHub Actions - embedding update information for automatic updates...'
|
||||
|
||||
# Format: gh-releases-zsync|<username>|<repository>|<tag>|<filename-pattern>
|
||||
# Using 'latest' tag to always point to the most recent release
|
||||
UPDATE_INFO="gh-releases-zsync|aaddrick|claude-desktop-debian|latest|claude-desktop-*-${ARCHITECTURE}.AppImage.zsync"
|
||||
echo "Update info: $UPDATE_INFO"
|
||||
# Check if zsyncmake is available (required for generating .zsync files)
|
||||
if ! command -v zsyncmake &> /dev/null; then
|
||||
echo 'zsyncmake not found. Installing zsync package for .zsync file generation...'
|
||||
if command -v apt-get &> /dev/null; then
|
||||
sudo apt-get update && sudo apt-get install -y zsync
|
||||
elif command -v dnf &> /dev/null; then
|
||||
sudo dnf install -y zsync
|
||||
elif command -v zypper &> /dev/null; then
|
||||
sudo zypper install -y zsync
|
||||
else
|
||||
echo 'Cannot install zsync automatically. .zsync files may not be generated.'
|
||||
fi
|
||||
fi
|
||||
|
||||
# Execute appimagetool with update information
|
||||
export ARCH="$ARCHITECTURE"
|
||||
echo "Using ARCH=$ARCH" # Debug output
|
||||
if "$APPIMAGETOOL_PATH" --updateinformation "$UPDATE_INFO" "$APPDIR_PATH" "$OUTPUT_PATH"; then
|
||||
echo "✓ AppImage built successfully with embedded update info: $OUTPUT_PATH"
|
||||
# Check if zsync file was generated
|
||||
ZSYNC_FILE="${OUTPUT_PATH}.zsync"
|
||||
if [ -f "$ZSYNC_FILE" ]; then
|
||||
echo "✓ zsync file generated: $ZSYNC_FILE"
|
||||
echo "📤 zsync file will be included in release artifacts"
|
||||
else
|
||||
echo "⚠️ zsync file not generated (zsyncmake may not be installed)"
|
||||
fi
|
||||
else
|
||||
echo "❌ Failed to build AppImage using $APPIMAGETOOL_PATH"
|
||||
exit 1
|
||||
fi
|
||||
# Format: gh-releases-zsync|<username>|<repository>|<tag>|<filename-pattern>
|
||||
# Using 'latest' tag to always point to the most recent release
|
||||
update_info="gh-releases-zsync|aaddrick|claude-desktop-debian|latest|claude-desktop-*-${architecture}.AppImage.zsync"
|
||||
echo "Update info: $update_info"
|
||||
|
||||
# Execute appimagetool with update information
|
||||
export ARCH="$architecture"
|
||||
echo "Using ARCH=$ARCH"
|
||||
if "$appimagetool_path" --updateinformation "$update_info" "$appdir_path" "$output_path"; then
|
||||
echo "AppImage built successfully with embedded update info: $output_path"
|
||||
# Check if zsync file was generated
|
||||
zsync_file="${output_path}.zsync"
|
||||
if [[ -f $zsync_file ]]; then
|
||||
echo "zsync file generated: $zsync_file"
|
||||
echo 'zsync file will be included in release artifacts'
|
||||
else
|
||||
echo 'zsync file not generated (zsyncmake may not be installed)'
|
||||
fi
|
||||
else
|
||||
echo "Failed to build AppImage using $appimagetool_path" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "🏠 Running locally - building AppImage without update information"
|
||||
echo " (Update info and zsync files are only generated in GitHub Actions for releases)"
|
||||
|
||||
# Execute appimagetool without update information
|
||||
export ARCH="$ARCHITECTURE"
|
||||
echo "Using ARCH=$ARCH" # Debug output
|
||||
if "$APPIMAGETOOL_PATH" "$APPDIR_PATH" "$OUTPUT_PATH"; then
|
||||
echo "✓ AppImage built successfully: $OUTPUT_PATH"
|
||||
else
|
||||
echo "❌ Failed to build AppImage using $APPIMAGETOOL_PATH"
|
||||
exit 1
|
||||
fi
|
||||
echo 'Running locally - building AppImage without update information'
|
||||
echo '(Update info and zsync files are only generated in GitHub Actions for releases)'
|
||||
|
||||
# Execute appimagetool without update information
|
||||
export ARCH="$architecture"
|
||||
echo "Using ARCH=$ARCH"
|
||||
if "$appimagetool_path" "$appdir_path" "$output_path"; then
|
||||
echo "AppImage built successfully: $output_path"
|
||||
else
|
||||
echo "Failed to build AppImage using $appimagetool_path" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "--- AppImage Build Finished ---"
|
||||
echo '--- AppImage Build Finished ---'
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -1,85 +1,84 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# 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"
|
||||
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
|
||||
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"
|
||||
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"
|
||||
package_root="$work_dir/package"
|
||||
install_dir="$package_root/usr"
|
||||
|
||||
# Clean previous package structure if it exists
|
||||
rm -rf "$PACKAGE_ROOT"
|
||||
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"
|
||||
echo "Creating package structure in $package_root..."
|
||||
mkdir -p "$package_root/DEBIAN" || exit 1
|
||||
mkdir -p "$install_dir/lib/$package_name" || exit 1
|
||||
mkdir -p "$install_dir/share/applications" || exit 1
|
||||
mkdir -p "$install_dir/share/icons" || exit 1
|
||||
mkdir -p "$install_dir/bin" || exit 1
|
||||
|
||||
# --- Icon Installation ---
|
||||
echo "🎨 Installing icons..."
|
||||
# Map icon sizes to their corresponding extracted files (relative to WORK_DIR)
|
||||
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"
|
||||
['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
|
||||
icon_dir="$install_dir/share/icons/hicolor/${size}x${size}/apps"
|
||||
mkdir -p "$icon_dir" || exit 1
|
||||
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" || exit 1
|
||||
else
|
||||
echo "Warning: Missing ${size}x${size} icon at $icon_source_path"
|
||||
fi
|
||||
done
|
||||
echo "✓ Icons installed"
|
||||
echo 'Icons installed'
|
||||
|
||||
# --- Copy Application Files ---
|
||||
echo "📦 Copying application files from $APP_STAGING_DIR..."
|
||||
echo "Copying application files from $app_staging_dir..."
|
||||
|
||||
# Copy local electron first 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/"
|
||||
if [[ -d $app_staging_dir/node_modules ]]; then
|
||||
echo 'Copying packaged electron...'
|
||||
cp -r "$app_staging_dir/node_modules" "$install_dir/lib/$package_name/" || exit 1
|
||||
fi
|
||||
|
||||
# Install app.asar in Electron's resources directory where process.resourcesPath points
|
||||
RESOURCES_DIR="$INSTALL_DIR/lib/$PACKAGE_NAME/node_modules/electron/dist/resources"
|
||||
mkdir -p "$RESOURCES_DIR"
|
||||
cp "$APP_STAGING_DIR/app.asar" "$RESOURCES_DIR/"
|
||||
cp -r "$APP_STAGING_DIR/app.asar.unpacked" "$RESOURCES_DIR/"
|
||||
echo "✓ Application files copied to Electron resources directory"
|
||||
resources_dir="$install_dir/lib/$package_name/node_modules/electron/dist/resources"
|
||||
mkdir -p "$resources_dir" || exit 1
|
||||
cp "$app_staging_dir/app.asar" "$resources_dir/" || exit 1
|
||||
cp -r "$app_staging_dir/app.asar.unpacked" "$resources_dir/" || exit 1
|
||||
echo 'Application files copied to Electron resources directory'
|
||||
|
||||
# Copy shared launcher library
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cp "$SCRIPT_DIR/launcher-common.sh" "$INSTALL_DIR/lib/$PACKAGE_NAME/"
|
||||
echo "✓ Shared launcher library copied"
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cp "$script_dir/launcher-common.sh" "$install_dir/lib/$package_name/" || exit 1
|
||||
echo 'Shared launcher library copied'
|
||||
|
||||
# --- Create Desktop Entry ---
|
||||
echo "📝 Creating desktop entry..."
|
||||
cat > "$INSTALL_DIR/share/applications/claude-desktop.desktop" << EOF
|
||||
echo 'Creating desktop entry...'
|
||||
cat > "$install_dir/share/applications/claude-desktop.desktop" << EOF
|
||||
[Desktop Entry]
|
||||
Name=Claude
|
||||
Exec=/usr/bin/claude-desktop %u
|
||||
@@ -90,106 +89,108 @@ Categories=Office;Utility;
|
||||
MimeType=x-scheme-handler/claude;
|
||||
StartupWMClass=Claude
|
||||
EOF
|
||||
echo "✓ Desktop entry created"
|
||||
echo 'Desktop entry created'
|
||||
|
||||
# --- Create Launcher Script ---
|
||||
echo "🚀 Creating launcher script..."
|
||||
cat > "$INSTALL_DIR/bin/claude-desktop" << EOF
|
||||
#!/bin/bash
|
||||
echo 'Creating launcher script...'
|
||||
cat > "$install_dir/bin/claude-desktop" << EOF
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Source shared launcher library
|
||||
source "/usr/lib/$PACKAGE_NAME/launcher-common.sh"
|
||||
source "/usr/lib/$package_name/launcher-common.sh"
|
||||
|
||||
# Setup logging and environment
|
||||
setup_logging
|
||||
setup_logging || exit 1
|
||||
setup_electron_env
|
||||
|
||||
# Log startup info
|
||||
log_message "--- Claude Desktop Launcher Start ---"
|
||||
log_message '--- Claude Desktop Launcher Start ---'
|
||||
log_message "Timestamp: \$(date)"
|
||||
log_message "Arguments: \$@"
|
||||
|
||||
# Check for display
|
||||
if ! check_display; then
|
||||
log_message "No display detected (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
|
||||
log_message 'No display detected (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
|
||||
|
||||
# Detect display backend
|
||||
detect_display_backend
|
||||
if [ "\$IS_WAYLAND" = true ]; then
|
||||
log_message "Wayland detected"
|
||||
if [[ \$is_wayland == true ]]; then
|
||||
log_message 'Wayland detected'
|
||||
fi
|
||||
|
||||
# Determine Electron executable path
|
||||
ELECTRON_EXEC="electron"
|
||||
LOCAL_ELECTRON_PATH="/usr/lib/$PACKAGE_NAME/node_modules/electron/dist/electron"
|
||||
if [ -f "\$LOCAL_ELECTRON_PATH" ]; then
|
||||
ELECTRON_EXEC="\$LOCAL_ELECTRON_PATH"
|
||||
log_message "Using local Electron: \$ELECTRON_EXEC"
|
||||
electron_exec='electron'
|
||||
local_electron_path="/usr/lib/$package_name/node_modules/electron/dist/electron"
|
||||
if [[ -f \$local_electron_path ]]; then
|
||||
electron_exec="\$local_electron_path"
|
||||
log_message "Using local Electron: \$electron_exec"
|
||||
else
|
||||
if command -v electron &> /dev/null; then
|
||||
log_message "Using global Electron: \$ELECTRON_EXEC"
|
||||
else
|
||||
log_message "Error: Electron executable not found"
|
||||
if command -v zenity &> /dev/null; then
|
||||
zenity --error --text="Claude Desktop cannot start because the Electron framework is missing."
|
||||
elif command -v kdialog &> /dev/null; then
|
||||
kdialog --error "Claude Desktop cannot start because the Electron framework is missing."
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
if command -v electron &> /dev/null; then
|
||||
log_message "Using global Electron: \$electron_exec"
|
||||
else
|
||||
log_message 'Error: Electron executable not found'
|
||||
if command -v zenity &> /dev/null; then
|
||||
zenity --error \
|
||||
--text='Claude Desktop cannot start because the Electron framework is missing.'
|
||||
elif command -v kdialog &> /dev/null; then
|
||||
kdialog --error \
|
||||
'Claude Desktop cannot start because the Electron framework is missing.'
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# App path
|
||||
APP_PATH="/usr/lib/$PACKAGE_NAME/node_modules/electron/dist/resources/app.asar"
|
||||
app_path="/usr/lib/$package_name/node_modules/electron/dist/resources/app.asar"
|
||||
|
||||
# Build electron args
|
||||
build_electron_args "deb"
|
||||
build_electron_args 'deb'
|
||||
|
||||
# Add app path LAST
|
||||
ELECTRON_ARGS+=("\$APP_PATH")
|
||||
electron_args+=("\$app_path")
|
||||
|
||||
# Change to application directory
|
||||
APP_DIR="/usr/lib/$PACKAGE_NAME"
|
||||
log_message "Changing directory to \$APP_DIR"
|
||||
cd "\$APP_DIR" || { log_message "Failed to cd to \$APP_DIR"; exit 1; }
|
||||
app_dir="/usr/lib/$package_name"
|
||||
log_message "Changing directory to \$app_dir"
|
||||
cd "\$app_dir" || { log_message "Failed to cd to \$app_dir"; exit 1; }
|
||||
|
||||
# Execute Electron
|
||||
log_message "Executing: \$ELECTRON_EXEC \${ELECTRON_ARGS[*]} \$*"
|
||||
"\$ELECTRON_EXEC" "\${ELECTRON_ARGS[@]}" "\$@" >> "\$LOG_FILE" 2>&1
|
||||
EXIT_CODE=\$?
|
||||
log_message "Electron exited with code: \$EXIT_CODE"
|
||||
log_message "--- Claude Desktop Launcher End ---"
|
||||
exit \$EXIT_CODE
|
||||
log_message "Executing: \$electron_exec \${electron_args[*]} \$*"
|
||||
"\$electron_exec" "\${electron_args[@]}" "\$@" >> "\$log_file" 2>&1
|
||||
exit_code=\$?
|
||||
log_message "Electron exited with code: \$exit_code"
|
||||
log_message '--- Claude Desktop Launcher End ---'
|
||||
exit \$exit_code
|
||||
EOF
|
||||
chmod +x "$INSTALL_DIR/bin/claude-desktop"
|
||||
echo "✓ Launcher script created"
|
||||
chmod +x "$install_dir/bin/claude-desktop" || exit 1
|
||||
echo 'Launcher script created'
|
||||
|
||||
# --- Create Control File ---
|
||||
echo "📄 Creating control file..."
|
||||
# Electron is bundled with its own Node.js runtime, so nodejs/npm are not runtime dependencies.
|
||||
# p7zip is only used at build time to extract the installer.
|
||||
# No external dependencies are required at runtime.
|
||||
echo 'Creating control file...'
|
||||
# Electron is bundled with its own Node.js runtime, so nodejs/npm are not
|
||||
# runtime dependencies. p7zip is only used at build time to extract the
|
||||
# installer. No external dependencies are required at runtime.
|
||||
|
||||
cat > "$PACKAGE_ROOT/DEBIAN/control" << EOF
|
||||
Package: $PACKAGE_NAME
|
||||
Version: $VERSION
|
||||
Architecture: $ARCHITECTURE
|
||||
Maintainer: $MAINTAINER
|
||||
Description: $DESCRIPTION
|
||||
cat > "$package_root/DEBIAN/control" << EOF
|
||||
Package: $package_name
|
||||
Version: $version
|
||||
Architecture: $architecture
|
||||
Maintainer: $maintainer
|
||||
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.)
|
||||
EOF
|
||||
echo "✓ Control file created"
|
||||
echo 'Control file created'
|
||||
|
||||
# --- Create Postinst Script ---
|
||||
echo "⚙️ Creating postinst script..."
|
||||
cat > "$PACKAGE_ROOT/DEBIAN/postinst" << EOF
|
||||
echo 'Creating postinst script...'
|
||||
cat > "$package_root/DEBIAN/postinst" << EOF
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
@@ -197,11 +198,12 @@ set -e
|
||||
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
|
||||
# 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
|
||||
LOCAL_SANDBOX_PATH="/usr/lib/$package_name/node_modules/electron/dist/chrome-sandbox"
|
||||
if [ -f "\$LOCAL_SANDBOX_PATH" ]; then
|
||||
SANDBOX_PATH="\$LOCAL_SANDBOX_PATH"
|
||||
fi
|
||||
@@ -212,32 +214,32 @@ if [ -n "\$SANDBOX_PATH" ] && [ -f "\$SANDBOX_PATH" ]; then
|
||||
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
|
||||
echo "Warning: chrome-sandbox binary not found in local package at \$LOCAL_SANDBOX_PATH. Sandbox may not function correctly."
|
||||
fi
|
||||
|
||||
exit 0
|
||||
EOF
|
||||
chmod +x "$PACKAGE_ROOT/DEBIAN/postinst"
|
||||
echo "✓ Postinst script created"
|
||||
chmod +x "$package_root/DEBIAN/postinst" || exit 1
|
||||
echo 'Postinst script created'
|
||||
|
||||
# --- Build .deb Package ---
|
||||
echo "📦 Building .deb package..."
|
||||
DEB_FILE="$WORK_DIR/${PACKAGE_NAME}_${VERSION}_${ARCHITECTURE}.deb"
|
||||
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"
|
||||
echo 'Setting DEBIAN directory permissions...'
|
||||
chmod 755 "$package_root/DEBIAN" || exit 1
|
||||
|
||||
# Fix script permissions in DEBIAN directory
|
||||
echo "Setting script permissions..."
|
||||
chmod 755 "$PACKAGE_ROOT/DEBIAN/postinst"
|
||||
echo 'Setting script permissions...'
|
||||
chmod 755 "$package_root/DEBIAN/postinst" || exit 1
|
||||
|
||||
if ! dpkg-deb --build "$PACKAGE_ROOT" "$DEB_FILE"; then
|
||||
echo "❌ Failed to build .deb package"
|
||||
exit 1
|
||||
if ! dpkg-deb --build "$package_root" "$deb_file"; then
|
||||
echo 'Failed to build .deb package' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✓ .deb package built successfully: $DEB_FILE"
|
||||
echo "--- Debian Package Build Finished ---"
|
||||
echo "Deb package built successfully: $deb_file"
|
||||
echo '--- Debian Package Build Finished ---'
|
||||
|
||||
exit 0
|
||||
exit 0
|
||||
|
||||
123
scripts/launcher-common.sh
Normal file → Executable file
123
scripts/launcher-common.sh
Normal file → Executable file
@@ -1,95 +1,96 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Common launcher functions for Claude Desktop (AppImage and deb)
|
||||
# This file is sourced by both launchers to avoid code duplication
|
||||
|
||||
# Setup logging directory and file
|
||||
# Sets: LOG_DIR, LOG_FILE
|
||||
# Sets: log_dir, log_file
|
||||
setup_logging() {
|
||||
LOG_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/claude-desktop-debian"
|
||||
mkdir -p "$LOG_DIR"
|
||||
LOG_FILE="$LOG_DIR/launcher.log"
|
||||
log_dir="${XDG_CACHE_HOME:-$HOME/.cache}/claude-desktop-debian"
|
||||
mkdir -p "$log_dir" || return 1
|
||||
log_file="$log_dir/launcher.log"
|
||||
}
|
||||
|
||||
# Log a message to the log file
|
||||
# Usage: log_message "message"
|
||||
log_message() {
|
||||
echo "$1" >> "$LOG_FILE"
|
||||
echo "$1" >> "$log_file"
|
||||
}
|
||||
|
||||
# Detect display backend (Wayland vs X11)
|
||||
# Sets: IS_WAYLAND, USE_X11_ON_WAYLAND
|
||||
# Sets: is_wayland, use_x11_on_wayland
|
||||
detect_display_backend() {
|
||||
# Detect if Wayland is likely running
|
||||
IS_WAYLAND=false
|
||||
if [ -n "$WAYLAND_DISPLAY" ]; then
|
||||
IS_WAYLAND=true
|
||||
fi
|
||||
# Detect if Wayland is likely running
|
||||
is_wayland=false
|
||||
if [[ -n $WAYLAND_DISPLAY ]]; then
|
||||
is_wayland=true
|
||||
fi
|
||||
|
||||
# Determine display backend mode
|
||||
# Default: Use X11/XWayland on Wayland sessions for global hotkey support
|
||||
# Set CLAUDE_USE_WAYLAND=1 to use native Wayland (global hotkeys won't work)
|
||||
USE_X11_ON_WAYLAND=true
|
||||
if [ "$CLAUDE_USE_WAYLAND" = "1" ]; then
|
||||
USE_X11_ON_WAYLAND=false
|
||||
fi
|
||||
# Determine display backend mode
|
||||
# Default: Use X11/XWayland on Wayland sessions for global hotkey support
|
||||
# Set CLAUDE_USE_WAYLAND=1 to use native Wayland (global hotkeys won't work)
|
||||
use_x11_on_wayland=true
|
||||
if [[ $CLAUDE_USE_WAYLAND == '1' ]]; then
|
||||
use_x11_on_wayland=false
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if we have a valid display (not running from TTY)
|
||||
# Returns: 0 if display available, 1 if not
|
||||
check_display() {
|
||||
if [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
if [[ -z $DISPLAY && -z $WAYLAND_DISPLAY ]]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Build Electron arguments array based on display backend
|
||||
# Requires: IS_WAYLAND, USE_X11_ON_WAYLAND to be set (call detect_display_backend first)
|
||||
# Sets: ELECTRON_ARGS array
|
||||
# Requires: is_wayland, use_x11_on_wayland to be set
|
||||
# (call detect_display_backend first)
|
||||
# Sets: electron_args array
|
||||
# Arguments: $1 = "appimage" or "deb" (affects --no-sandbox behavior)
|
||||
build_electron_args() {
|
||||
local package_type="${1:-deb}"
|
||||
local package_type="${1:-deb}"
|
||||
|
||||
# Initialize args array
|
||||
ELECTRON_ARGS=()
|
||||
# Initialize args array
|
||||
electron_args=()
|
||||
|
||||
# AppImage always needs --no-sandbox due to FUSE constraints
|
||||
if [ "$package_type" = "appimage" ]; then
|
||||
ELECTRON_ARGS+=("--no-sandbox")
|
||||
fi
|
||||
# AppImage always needs --no-sandbox due to FUSE constraints
|
||||
if [[ $package_type == 'appimage' ]]; then
|
||||
electron_args+=('--no-sandbox')
|
||||
fi
|
||||
|
||||
# Disable CustomTitlebar for better Linux integration
|
||||
ELECTRON_ARGS+=("--disable-features=CustomTitlebar")
|
||||
# Disable CustomTitlebar for better Linux integration
|
||||
electron_args+=('--disable-features=CustomTitlebar')
|
||||
|
||||
# Add compatibility flags based on display backend
|
||||
if [ "$IS_WAYLAND" = true ]; then
|
||||
if [ "$USE_X11_ON_WAYLAND" = true ]; then
|
||||
# Default: Use X11 via XWayland for global hotkey support
|
||||
log_message "Using X11 backend via XWayland (for global hotkey support)"
|
||||
# Deb package needs --no-sandbox for XWayland mode too
|
||||
if [ "$package_type" = "deb" ]; then
|
||||
ELECTRON_ARGS+=("--no-sandbox")
|
||||
fi
|
||||
ELECTRON_ARGS+=("--ozone-platform=x11")
|
||||
else
|
||||
# Native Wayland mode (user opted in via CLAUDE_USE_WAYLAND=1)
|
||||
log_message "Using native Wayland backend (global hotkeys may not work)"
|
||||
if [ "$package_type" = "deb" ]; then
|
||||
ELECTRON_ARGS+=("--no-sandbox")
|
||||
fi
|
||||
ELECTRON_ARGS+=("--enable-features=UseOzonePlatform,WaylandWindowDecorations")
|
||||
ELECTRON_ARGS+=("--ozone-platform=wayland")
|
||||
ELECTRON_ARGS+=("--enable-wayland-ime")
|
||||
ELECTRON_ARGS+=("--wayland-text-input-version=3")
|
||||
fi
|
||||
else
|
||||
# X11 session - no special flags needed
|
||||
log_message "X11 session detected"
|
||||
fi
|
||||
# Add compatibility flags based on display backend
|
||||
if [[ $is_wayland == true ]]; then
|
||||
if [[ $use_x11_on_wayland == true ]]; then
|
||||
# Default: Use X11 via XWayland for global hotkey support
|
||||
log_message 'Using X11 backend via XWayland (for global hotkey support)'
|
||||
# Deb package needs --no-sandbox for XWayland mode too
|
||||
if [[ $package_type == 'deb' ]]; then
|
||||
electron_args+=('--no-sandbox')
|
||||
fi
|
||||
electron_args+=('--ozone-platform=x11')
|
||||
else
|
||||
# Native Wayland mode (user opted in via CLAUDE_USE_WAYLAND=1)
|
||||
log_message 'Using native Wayland backend (global hotkeys may not work)'
|
||||
if [[ $package_type == 'deb' ]]; then
|
||||
electron_args+=('--no-sandbox')
|
||||
fi
|
||||
electron_args+=('--enable-features=UseOzonePlatform,WaylandWindowDecorations')
|
||||
electron_args+=('--ozone-platform=wayland')
|
||||
electron_args+=('--enable-wayland-ime')
|
||||
electron_args+=('--wayland-text-input-version=3')
|
||||
fi
|
||||
else
|
||||
# X11 session - no special flags needed
|
||||
log_message 'X11 session detected'
|
||||
fi
|
||||
}
|
||||
|
||||
# Set common environment variables
|
||||
setup_electron_env() {
|
||||
export ELECTRON_FORCE_IS_PACKAGED=true
|
||||
export ELECTRON_USE_SYSTEM_TITLE_BAR=1
|
||||
export ELECTRON_FORCE_IS_PACKAGED=true
|
||||
export ELECTRON_USE_SYSTEM_TITLE_BAR=1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user