Skip to content

Instantly share code, notes, and snippets.

@zudsniper
Last active March 6, 2025 20:48
Show Gist options
  • Save zudsniper/08058256b4f008eaf87bd092fe9683e0 to your computer and use it in GitHub Desktop.
Save zudsniper/08058256b4f008eaf87bd092fe9683e0 to your computer and use it in GitHub Desktop.
make_appimage_wrapper.sh -- generate simple 'install_App.sh' scripts to install or update your appimage apps for ubuntu.
#!/bin/bash
# make_appimage_wrapper.sh v2
# > still wonky -- this one is gen'd by claude 3.7 sonnet, o1, o3-mini-high.
# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Script author
AUTHOR="@zudsniper (github)"
# Default values
VERBOSE=false
APP_NAME=""
ICON_PATH=""
SHOW_HELP=false
# Print banner
print_banner() {
echo -e "${CYAN}╔═════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}║ ${GREEN}AppImage${CYAN} Wrapper Generator ║${NC}"
echo -e "${CYAN}║ ║${NC}"
echo -e "${CYAN}║ ${YELLOW}${AUTHOR}${CYAN} ║${NC}"
echo -e "${CYAN}╚═════════════════════════════════════════╝${NC}"
echo ""
}
# Print help message
print_help() {
echo -e "${BLUE}Usage:${NC} $0 [OPTIONS] APPIMAGE_PATH_OR_URL"
echo ""
echo -e "${BLUE}Description:${NC}"
echo " Create an installation script for an AppImage file that can be executed"
echo " to install the application with desktop integration."
echo ""
echo -e "${BLUE}Options:${NC}"
echo " --name, -n NAME Application name (required)"
echo " --icon, -i PATH Path or URL to icon image (optional; supported formats: svg, png, jpeg, jpg, ico)"
echo " --verbose, -v Enable verbose output"
echo " --help, -h Display this help message"
echo ""
echo -e "${BLUE}Example:${NC}"
echo " $0 --name MyApp --icon https://example.com/icon.png https://example.com/app.AppImage"
echo " $0 -n MyApp -i /path/to/icon.svg /path/to/app.AppImage"
echo ""
echo -e "${BLUE}Output:${NC}"
echo " Creates install_NAME.sh script in the current directory"
echo ""
}
# Log message
log() {
if [ "$VERBOSE" = true ] || [ "$1" != "verbose" ]; then
local level="$1"
local message="$2"
case "$level" in
"info")
echo -e "${GREEN}[INFO]${NC} $message"
;;
"warn")
echo -e "${YELLOW}[WARNING]${NC} $message"
;;
"error")
echo -e "${RED}[ERROR]${NC} $message"
;;
"verbose")
echo -e "${BLUE}[VERBOSE]${NC} $message"
;;
*)
echo -e "$message"
;;
esac
fi
}
# Parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--name|-n)
APP_NAME="$2"
log "verbose" "Application name set to: $APP_NAME"
shift 2
;;
--icon|-i)
ICON_PATH="$2"
log "verbose" "Icon path set to: $ICON_PATH"
shift 2
;;
--verbose|-v)
VERBOSE=true
log "verbose" "Verbose mode enabled"
shift
;;
--help|-h)
SHOW_HELP=true
shift
;;
*)
if [[ $1 == -* ]]; then
log "error" "Unknown option: $1"
print_help
exit 1
else
APPIMAGE_PATH="$1"
log "verbose" "AppImage path set to: $APPIMAGE_PATH"
shift
fi
;;
esac
done
}
# Validate arguments
validate_args() {
# Check if help should be shown
if [ "$SHOW_HELP" = true ]; then
print_help
exit 0
fi
# Check if app name is provided
if [ -z "$APP_NAME" ]; then
log "error" "Application name is required. Use --name or -n option. Use --help for more options."
exit 1
fi
# Check if appimage path is provided
if [ -z "$APPIMAGE_PATH" ]; then
log "error" "AppImage path or URL is required. Use --help for more options."
exit 1
fi
# Check if icon is accessible if provided as local file
if [ -n "$ICON_PATH" ] && [[ ! "$ICON_PATH" =~ ^https?:// ]]; then
if [ ! -f "$ICON_PATH" ] || [ ! -r "$ICON_PATH" ]; then
log "error" "The specified icon file does not exist or is not readable: $ICON_PATH"
exit 1
fi
# Check if icon is a supported format
local ext="${ICON_PATH##*.}"
if [[ ! "$ext" =~ ^(svg|png|jpe?g|ico)$ ]]; then
log "warn" "Icon format may not be supported. Supported formats: svg, png, jpeg, jpg, ico"
fi
fi
# Check if appimage is accessible if provided as local file
if [[ ! "$APPIMAGE_PATH" =~ ^https?:// ]]; then
if [ ! -f "$APPIMAGE_PATH" ] || [ ! -r "$APPIMAGE_PATH" ]; then
log "error" "The specified AppImage file does not exist or is not readable: $APPIMAGE_PATH"
exit 1
fi
# Check if AppImage is executable
if [ ! -x "$APPIMAGE_PATH" ]; then
log "warn" "The AppImage file is not executable. Permissions may need to be fixed during installation."
fi
fi
}
# Generate the installation script for the AppImage
generate_script() {
local output_file="install_${APP_NAME// /_}.sh"
log "info" "Generating installation script: $output_file"
# Compute the desktop entry path (hardcoded for use in the generated script)
local desktop_entry_path="/usr/share/applications/${APP_NAME// /_}.desktop"
# Determine if AppImage is a URL or a local file
local is_url=false
if [[ "$APPIMAGE_PATH" =~ ^https?:// ]]; then
is_url=true
log "info" "Creating auto-update script with URL: $APPIMAGE_PATH"
else
log "warn" "Using local AppImage path. Auto-update is not configured."
fi
# Create the installation script header
cat > "$output_file" << EOL
#!/bin/bash
# Installation script for ${APP_NAME}
# Generated by AppImage Wrapper Generator
# Author: ${AUTHOR}
install${APP_NAME// /}() {
local CUSTOM_APPIMAGE="\$1"
local APP_NAME="${APP_NAME}"
local INSTALL_PATH="/opt/${APP_NAME// /_}.appimage"
local ICON_INSTALL="/opt/${APP_NAME// /_}.png"
local DESKTOP_ENTRY_PATH="${desktop_entry_path}"
local TEMP_APPIMAGE="/tmp/${APP_NAME// /_}.appimage"
EOL
# Insert URL or local file assignment for the AppImage
if [ "$is_url" = true ]; then
cat >> "$output_file" << EOL
local APPIMAGE_URL="$APPIMAGE_PATH"
EOL
else
cat >> "$output_file" << EOL
local APPIMAGE_PATH="$APPIMAGE_PATH"
EOL
fi
# Insert ICON_URL assignment if an icon was provided
if [ -n "$ICON_PATH" ]; then
echo " local ICON_URL=\"$ICON_PATH\"" >> "$output_file"
fi
cat >> "$output_file" << EOL
# Check if the AppImage wrapper already exists and if it is running
if [ -f "\$INSTALL_PATH" ]; then
if pgrep -f "\$INSTALL_PATH" > /dev/null; then
echo "\${APP_NAME} is currently running."
read -p "Do you want to kill it and update? [y/N] " user_response
if [[ "\$user_response" =~ ^[Yy]\$ ]]; then
echo "Killing running \${APP_NAME}..."
pkill -f "\$INSTALL_PATH"
else
echo "Update cancelled. Exiting."
exit 1
fi
fi
fi
echo "Checking for existing \${APP_NAME} installation..."
# Check if a custom AppImage path was provided and if it exists
if [ -n "\$CUSTOM_APPIMAGE" ]; then
if [ -f "\$CUSTOM_APPIMAGE" ] && [ -r "\$CUSTOM_APPIMAGE" ]; then
echo "Using provided AppImage file: \$CUSTOM_APPIMAGE"
TEMP_APPIMAGE="\$CUSTOM_APPIMAGE"
else
echo "Error: The specified AppImage file does not exist or is not readable: \$CUSTOM_APPIMAGE"
exit 1
fi
fi
# Detect the user's shell
local SHELL_NAME=\$(basename "\$SHELL")
local RC_FILE=""
case "\$SHELL_NAME" in
bash)
RC_FILE="\$HOME/.bashrc"
;;
zsh)
RC_FILE="\$HOME/.zshrc"
;;
fish)
RC_FILE="\$HOME/.config/fish/config.fish"
;;
*)
echo "Unsupported shell: \$SHELL_NAME"
echo "Please manually add the alias to your shell configuration file."
return 1
;;
esac
# Notify if updating an existing installation
if [ -f "\$INSTALL_PATH" ]; then
echo "\${APP_NAME} is already installed. Updating existing installation..."
else
echo "Performing a fresh installation of \${APP_NAME}..."
fi
# Install curl if not installed
if ! command -v curl &> /dev/null; then
echo "curl is not installed. Installing..."
sudo apt-get update
sudo apt-get install -y curl || { echo "Failed to install curl."; exit 1; }
fi
# If an icon is provided, ensure ImageMagick is available for conversion
if [ -n "\$ICON_URL" ]; then
if ! command -v convert &> /dev/null; then
echo "ImageMagick 'convert' not found. Installing imagemagick..."
sudo apt-get update
sudo apt-get install -y imagemagick || { echo "Failed to install ImageMagick."; exit 1; }
fi
fi
EOL
# Add AppImage download or copy logic
if [ "$is_url" = true ]; then
cat >> "$output_file" << EOL
# Download AppImage if not provided
if [ "\$TEMP_APPIMAGE" = "/tmp/${APP_NAME// /_}.appimage" ]; then
echo "Downloading \${APP_NAME} AppImage..."
curl -L "\$APPIMAGE_URL" -o "\$TEMP_APPIMAGE" || { echo "Failed to download AppImage."; exit 1; }
fi
EOL
else
cat >> "$output_file" << EOL
# Copy local AppImage if not provided
if [ "\$TEMP_APPIMAGE" = "/tmp/${APP_NAME// /_}.appimage" ]; then
echo "Copying \${APP_NAME} AppImage..."
cp "\$APPIMAGE_PATH" "\$TEMP_APPIMAGE" || { echo "Failed to copy AppImage."; exit 1; }
fi
EOL
fi
# Add icon processing logic if provided
if [ -n "$ICON_PATH" ]; then
cat >> "$output_file" << 'EOL'
echo "Processing ${APP_NAME} icon..."
ICON_TEMP="/tmp/${APP_NAME// /_}_icon"
# Determine if ICON_URL is a URL or a local file
if [[ "$ICON_URL" =~ ^https?:// ]]; then
echo "Downloading icon from URL..."
curl -L "$ICON_URL" -o "$ICON_TEMP" || { echo "Failed to download icon."; exit 1; }
else
echo "Copying icon from local file..."
cp "$ICON_URL" "$ICON_TEMP" || { echo "Failed to copy icon."; exit 1; }
fi
echo "Converting icon to 128x128 PNG..."
convert "$ICON_TEMP" -resize 128x128 "/tmp/${APP_NAME// /_}.png" || { echo "Icon conversion failed."; exit 1; }
rm "$ICON_TEMP"
EOL
fi
# Continue installation steps
cat >> "$output_file" << EOL
# Move to final destination
echo "Installing \${APP_NAME} files..."
sudo cp "\$TEMP_APPIMAGE" "\$INSTALL_PATH"
sudo chmod +x "\$INSTALL_PATH"
EOL
# Add icon installation step if provided
if [ -n "$ICON_PATH" ]; then
cat >> "$output_file" << 'EOL'
sudo mv "/tmp/${APP_NAME// /_}.png" "$ICON_INSTALL"
EOL
fi
# Create the .desktop entry using the hardcoded desktop entry path
cat >> "$output_file" << EOL
echo "Creating .desktop entry..."
sudo bash -c "cat > '${desktop_entry_path}'" <<INNEREOF
[Desktop Entry]
Name=${APP_NAME}
Exec=\$INSTALL_PATH
Type=Application
Categories=Application;
INNEREOF
EOL
# Add the icon line to the desktop entry if provided
if [ -n "$ICON_PATH" ]; then
cat >> "$output_file" << EOL
# Add icon to desktop entry
sudo sed -i '/Type=Application/a\\Icon=\$ICON_INSTALL' '${desktop_entry_path}'
EOL
fi
# Add shell alias setup
cat >> "$output_file" << EOL
# Add alias to the appropriate RC file
local APP_ALIAS="${APP_NAME// /_}"
echo "Adding \$APP_ALIAS alias to \$RC_FILE..."
if [ "\$SHELL_NAME" = "fish" ]; then
# Fish shell uses a different syntax for functions
if ! grep -q "function \$APP_ALIAS" "\$RC_FILE"; then
echo "function \$APP_ALIAS" >> "\$RC_FILE"
echo " \$INSTALL_PATH \\\$argv > /dev/null 2>&1 & disown" >> "\$RC_FILE"
echo "end" >> "\$RC_FILE"
else
echo "Alias already exists in \$RC_FILE."
fi
else
if ! grep -q "function \$APP_ALIAS" "\$RC_FILE"; then
cat >> "\$RC_FILE" <<INNEREOF
# ${APP_NAME} alias
function \$APP_ALIAS() {
\$INSTALL_PATH "\\\${@}" > /dev/null 2>&1 & disown
}
INNEREOF
else
echo "Alias already exists in \$RC_FILE."
fi
fi
# Inform the user to reload the shell
echo "To apply changes, please restart your terminal or run the following command:"
echo " source \$RC_FILE"
echo "\${APP_NAME} installation or update complete. You can find it in your application menu."
}
install${APP_NAME// /} "\$1"
EOL
# Make the generated installation script executable
chmod +x "$output_file"
log "info" "Installation script generated successfully: $output_file"
log "info" "To install ${APP_NAME}, run: ./$output_file"
}
# Main function
main() {
print_banner
# Parse and validate arguments
parse_args "$@"
validate_args
# Generate the installation script
generate_script
}
# Run the script
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment