#!/bin/bash # # Purpose : Compile and install applications from compile.conf CONF_FILE="$HOME/.local/share/HamPackServer/compile.conf" TMP_DIR="/tmp/hampack-build" VERSION_FILE="$HOME/.local/state/HamPackServer/.installed_versions" # Get the installed version of an app get_installed_version() { local app="$1" local gui="$2" # Skip --version check for GUI apps as it would launch them if [ "$gui" != "true" ]; then if command -v "$app" &> /dev/null; then local ver ver=$("$app" --version 2>&1 | grep -oP '\d+\.\d+[\.\d]*' | head -n1) if [ -n "$ver" ]; then echo "$ver" return fi fi fi # Fall back to version file if [ -f "$VERSION_FILE" ]; then local stored stored=$(grep "^$app=" "$VERSION_FILE" | cut -d'=' -f2) if [ -n "$stored" ]; then echo "$stored" return fi fi echo "unknown" } # Save installed version to version file save_installed_version() { local app="$1" local version="$2" touch "$VERSION_FILE" if grep -q "^$app=" "$VERSION_FILE"; then sed -i "s/^$app=.*/$app=$version/" "$VERSION_FILE" else echo "$app=$version" >> "$VERSION_FILE" fi } # Ask the user whether to proceed when version can't be determined ask_user_proceed() { local app="$1" local latest="$2" echo "Warning: could not determine installed version of $app." echo "compile.conf specifies version $latest." read -rp "Compile and install $app anyway? [y/N] " response [[ "$response" =~ ^[yY] ]] } # Check if an update is needed needs_update() { local app="$1" local install_path="$2" local latest="$3" local gui="$4" # Not installed at all if ! command -v "$app" &> /dev/null && [ ! -f "$install_path" ]; then echo " $app is not installed." return 0 fi local installed installed=$(get_installed_version "$app" "$gui") if [ "$installed" = "unknown" ]; then if ask_user_proceed "$app" "$latest"; then return 0 else return 1 fi fi echo " Installed version : $installed" echo " Latest version : $latest" if [ "$installed" = "$latest" ]; then echo " $app is up to date, skipping." return 1 fi echo " Update available for $app." return 0 } # Generate desktop file with absolute paths generate_desktop() { local desktop="$1" local tmp_desktop="/tmp/$(basename "$desktop")" sed "s|\$HOME|$HOME|g" "$desktop" > "$tmp_desktop" echo "$tmp_desktop" } # Install desktop file if specified install_desktop() { local desktop="$1" if [ -z "$desktop" ]; then return fi if [ ! -f "$desktop" ]; then echo " Warning: desktop file $desktop not found, skipping." return fi echo " Installing desktop file..." mkdir -p "$HOME/.local/share/applications" local resolved resolved=$(generate_desktop "$desktop") cp "$resolved" "$HOME/.local/share/applications/$(basename "$desktop")" chmod +x "$HOME/.local/share/applications/$(basename "$desktop")" rm -f "$resolved" echo " Desktop file installed." } # Fetch source via git or wget fetch_source() { local app="$1" local git_url="$2" local wget_url="$3" local src_dir="$TMP_DIR/$app" rm -rf "$src_dir" mkdir -p "$src_dir" if [ -n "$git_url" ]; then echo " Cloning $git_url..." git clone "$git_url" "$src_dir" elif [ -n "$wget_url" ]; then echo " Downloading $wget_url..." local filename="${wget_url##*/}" local filepath="$TMP_DIR/$filename" wget -q "$wget_url" -O "$filepath" echo " Extracting $filename..." case "$filename" in *.zip) unzip -q "$filepath" -d "$src_dir" # If the zip extracted into a single subdirectory, flatten it local contents contents=$(ls -1 "$src_dir") local count count=$(echo "$contents" | wc -l) if [ "$count" -eq 1 ] && [ -d "$src_dir/$contents" ]; then echo " Descending into $contents..." local inner="$src_dir/$contents" shopt -s dotglob mv "$inner"/* "$src_dir/" shopt -u dotglob rm -rf "$inner" fi ;; *.tar.gz|*.tgz) tar -xzf "$filepath" -C "$src_dir" --strip-components=1 ;; *.tar.bz2) tar -xjf "$filepath" -C "$src_dir" --strip-components=1 ;; *.tar.xz) tar -xJf "$filepath" -C "$src_dir" --strip-components=1 ;; *) echo " Error: unknown file type for $filename" exit 1 ;; esac rm -f "$filepath" else echo " Error: no git or wget URL specified for $app" exit 1 fi } # cd into source directory and run steps run_steps() { local app="$1" local steps="$2" local src_dir="$TMP_DIR/$app" if [ ! -d "$src_dir" ]; then echo " Error: source directory $src_dir not found." exit 1 fi echo " Changing into $src_dir..." cd "$src_dir" echo " Building $app..." IFS=',' read -ra step_list <<< "$steps" for step in "${step_list[@]}"; do step=$(echo "$step" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') echo " Running: $step" eval "$step" done } # Process a single app process_app() { local app="$1" local git_url="$2" local wget_url="$3" local install_path="$4" local steps="$5" local version="$6" local desktop="$7" local gui="$8" echo "" echo "=== $app ===" # Check if already installed if command -v "$app" &> /dev/null || [ -f "$install_path" ]; then if [ -z "$version" ]; then echo " $app is already installed, skipping." return fi fi if [ -z "$version" ]; then echo " Warning: no version specified in compile.conf for $app." read -rp " Compile and install $app anyway? [y/N] " response if [[ ! "$response" =~ ^[yY] ]]; then echo " Skipping $app." return fi elif ! needs_update "$app" "$install_path" "$version" "$gui"; then return fi fetch_source "$app" "$git_url" "$wget_url" run_steps "$app" "$steps" install_desktop "$desktop" save_installed_version "$app" "$version" # Return to a safe directory after build cd "$HOME" echo " $app $version installed successfully." } # Parse compile.conf and process each app process_conf() { local app="" git_url="" wget_url="" install_path="" steps="" version="" desktop="" gui="" while IFS= read -r line || [ -n "$line" ]; do [[ -z "$line" || "$line" == \#* ]] && continue if [[ "$line" =~ ^\[(.+)\]$ ]]; then if [ -n "$app" ]; then process_app "$app" "$git_url" "$wget_url" "$install_path" "$steps" "$version" "$desktop" "$gui" fi app="${BASH_REMATCH[1]}" git_url="" wget_url="" install_path="" steps="" version="" desktop="" gui="" continue fi local key="${line%%=*}" local raw_value="${line#*=}" # Steps are stored raw so quotes and variables expand correctly at eval time if [ "$key" = "steps" ]; then steps="$raw_value" continue fi local value value=$(eval echo "$raw_value") case "$key" in git) git_url="$value" ;; wget) wget_url="$value" ;; install) install_path="$value" ;; version) version="$value" ;; desktop) desktop="$value" ;; gui) gui="$value" ;; esac done < "$CONF_FILE" # Process the last app in the file if [ -n "$app" ]; then process_app "$app" "$git_url" "$wget_url" "$install_path" "$steps" "$version" "$desktop" "$gui" fi } # --- Main --- if [ ! -f "$CONF_FILE" ]; then echo "Error: $CONF_FILE not found." exit 1 fi mkdir -p "$TMP_DIR" mkdir -p "$HOME/.local/state/HamPackServer" echo "Starting HamPack source builds..." process_conf echo "Updating desktop database..." update-desktop-database "$HOME/.local/share/applications/" echo "" echo "Cleaning up..." rm -rf "$TMP_DIR" echo "All done."