diff --git a/install.sh b/install.sh index a9b6b20..e74da0c 100644 --- a/install.sh +++ b/install.sh @@ -3,8 +3,8 @@ # --- 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 +# configuration file. The user can select one or more packages, 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. @@ -15,7 +15,7 @@ log() { echo "[$1] $2" } -# New function to get the version from a local script file. +# 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" @@ -27,7 +27,7 @@ get_local_version() { fi } -# New function to compare two version strings (e.g., "1.2.0" vs "1.10.0"). +# 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 @@ -41,6 +41,75 @@ is_version_greater() { fi } +# New function to process a single selected package. +process_package() { + local choice="$1" + # Check if the choice is a valid package name. + if [[ -z "${SCRIPT_PACKAGES[$choice]}" ]]; then + log "❌" "Invalid package name provided: '${choice}'" + return + fi + + 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 || "${filename}" == *.bash ]]; then + chmod +x "${filename}" + log "🤖" "Made '${filename}' executable." + fi + else + log "❌" "Error: Failed to download '${filename}'." + fi + fi + done + log "📦" "Package processing complete for '${choice}'." +} + + # --- Main Logic --- # Generate a unique temporary filename with a timestamp. @@ -62,10 +131,6 @@ 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 @@ -76,7 +141,7 @@ 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" @@ -95,92 +160,62 @@ for key in "${package_keys[@]}"; do 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: " +# --- User Interaction --- -# 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 +# Manually display the options with numbers. +echo +echo "-------------------------------------" +echo " Script Downloader " +echo "-------------------------------------" +for i in "${!options[@]}"; do + printf "%d) %s\n" "$((i+1))" "${options[$i]}" +done +echo + +# Prompt the user for one or more choices. +read -p "Please enter your choice(s) (e.g., 1 3 4), or press Enter to quit: " -r -a user_choices + +# If no choices are made, exit gracefully. +if [ ${#user_choices[@]} -eq 0 ]; then + log "👋" "No selection made. Exiting." + exit 0 +fi + +# Loop through the user's selections and process each one. +for choice_num in "${user_choices[@]}"; do + # Validate that the input is a number. + if ! [[ "$choice_num" =~ ^[0-9]+$ ]]; then + log "⚠️" "Skipping invalid input: '${choice_num}'. Not a number." + continue + fi + + # Convert selection number to array index (0-based). + index=$((choice_num - 1)) + + # Validate that the index is within the bounds of the options array. + if [[ -z "${options[$index]}" ]]; then + log "⚠️" "Skipping invalid choice: '${choice_num}'. Out of range." + continue + fi + + # Get the choice text from the array. + choice_with_status="${options[$index]}" + + # Strip the status message to get the package key. 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) + # Handle the "Quit" option. + if [[ "${choice}" == "Quit" ]]; then + log "👋" "Quit selected. Exiting now." + exit 0 + fi - 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 + # Process the selected package. + process_package "${choice}" done - +echo +log "🏁" "All selected packages have been processed."