Files
Scripts/install.sh
2025-09-10 12:13:59 +02:00

185 lines
7.2 KiB
Bash

#!/bin/bash
# --- Main Script ---
# This script presents a menu of software packages defined in a remote
# configuration file. The user can select a package, and the script
# will download the corresponding files. It includes a feature to show
# a diff and ask for confirmation before overwriting existing config files.
# It can also check for updates to already-installed scripts.
# --- Functions ---
# A simple function to log messages with a consistent format.
log() {
echo "[$1] $2"
}
# New function to get the version from a local script file.
# It reads the first 5 lines and extracts the version number.
get_local_version() {
local file_path="$1"
if [[ -f "${file_path}" ]]; then
# Grep for the version line, then use awk to get the last field.
head -n 5 "${file_path}" | grep -m 1 "^# Version:" | awk '{print $NF}'
else
echo "0.0.0" # Return a base version if file doesn't exist.
fi
}
# New function to compare two version strings (e.g., "1.2.0" vs "1.10.0").
# Returns 0 if v1 is newer, 1 if they are the same or v2 is newer.
is_version_greater() {
local v1=$1
local v2=$2
# Use sort's version sorting capability to find the "highest" version.
# If the highest version is v1, then v1 > v2.
if [[ "$(printf '%s\n' "$v1" "$v2" | sort -V | head -n 1)" != "$v1" ]]; then
return 0 # v1 is greater
else
return 1 # v1 is not greater (equal or less)
fi
}
# --- Main Logic ---
# Generate a unique temporary filename with a timestamp.
conf_file="packages.conf.$(date +%Y%m%d%H%M%S)"
# Set up a trap to delete the temporary file on exit.
trap 'rm -f "${conf_file}"' EXIT
# Download the configuration file.
log "🔄" "Downloading configuration file..."
if ! curl -fsSL -o "${conf_file}" "https://git.technopunk.space/tomi/Scripts/raw/branch/main/packages.conf"; then
log "❌" "Error: Failed to download packages.conf. Exiting."
exit 1
fi
log "✅" "Configuration file downloaded successfully."
# Source the configuration file to load the SCRIPT_PACKAGES associative array.
source "${conf_file}"
# --- Update Check & User Interface ---
echo "-------------------------------------"
echo " Script Downloader "
echo "-------------------------------------"
# Create an array of options from the package names.
# We will modify this array to show installation and update status.
declare -a options
package_keys=("${!SCRIPT_PACKAGES[@]}")
log "🔎" "Checking for updates..."
for key in "${package_keys[@]}"; do
# The config format is now "VERSION|URL1 URL2..."
config_value="${SCRIPT_PACKAGES[$key]}"
remote_version=$(echo "${config_value}" | cut -d'|' -f1)
# Get just the URLs and assume the first URL is the main script to check.
urls=$(echo "${config_value}" | cut -d'|' -f2-)
read -r -a url_array <<< "$urls"
main_script_filename=$(basename "${url_array[0]}")
# Get the local version of the main script file.
local_version=$(get_local_version "${main_script_filename}")
status=""
if [[ -f "${main_script_filename}" ]]; then
status=" (Installed: v${local_version})"
# Compare versions
if is_version_greater "$remote_version" "$local_version"; then
status+=" [Update available: v${remote_version}]"
fi
fi
options+=("${key}${status}")
done
echo
options+=("Quit") # Add a Quit option to the menu.
# Set the prompt for the select menu.
PS3="Please enter your choice: "
# Display the menu and handle user input.
# Setting COLUMNS=1 forces the select menu to display vertically.
COLUMNS=1 select choice_with_status in "${options[@]}"; do
# Strip the status message from the choice for key lookup
choice=$(echo "${choice_with_status}" | sed 's/ (.*//')
case "${choice}" in
"Quit")
log "👋" "Exiting."
break # Exit the select loop.
;;
*)
# Check if the user's choice is a valid package name.
if [[ -n "${SCRIPT_PACKAGES[$choice]}" ]]; then
echo
log "⬇️" "Processing package: '${choice}'..."
# Get the config value and split it into version and URLs
config_value="${SCRIPT_PACKAGES[$choice]}"
remote_version=$(echo "${config_value}" | cut -d'|' -f1)
urls_to_download=$(echo "${config_value}" | cut -d'|' -f2-)
read -r -a urls_to_download_array <<< "$urls_to_download"
for url in "${urls_to_download_array[@]}"; do
filename=$(basename "${url}")
# If it's a .conf file AND it already exists, ask to overwrite.
if [[ "${filename}" == *.conf && -f "${filename}" ]]; then
log "->" "Found existing config file: '${filename}'."
tmp_file=$(mktemp)
if curl -fsSL -o "${tmp_file}" "${url}"; then
log "🔎" "Comparing versions..."
echo "-------------------- DIFF START --------------------"
if command -v colordiff &> /dev/null; then
colordiff -u "${filename}" "${tmp_file}"
else
# Attempt to use diff's color option, which is common.
diff --color=always -u "${filename}" "${tmp_file}" 2>/dev/null || diff -u "${filename}" "${tmp_file}"
fi
echo "--------------------- DIFF END ---------------------"
read -p "Do you want to overwrite '${filename}'? (y/N) " -n 1 -r REPLY
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
mv "${tmp_file}" "${filename}"
log "✅" "Updated '${filename}'."
else
rm "${tmp_file}"
log "🤷" "Kept existing version of '${filename}'."
fi
else
log "❌" "Error: Failed to download new version of '${filename}' for comparison."
rm -f "${tmp_file}"
fi
else
# Original download logic for all other files.
log "->" "Downloading '${filename}'..."
if curl -fsSL -o "${filename}" "${url}"; then
log "✅" "Successfully downloaded '${filename}'."
if [[ "${filename}" == *.sh ]]; then
chmod +x "${filename}"
log "🤖" "Made '${filename}' executable."
fi
else
log "❌" "Error: Failed to download '${filename}'."
fi
fi
done
echo
log "📦" "Package processing complete."
break
else
echo "Invalid selection. Please try again."
fi
;;
esac
done