diff --git a/scripts/auth-sudo.sh b/scripts/auth-sudo.sh index c3e237e..2168373 100644 --- a/scripts/auth-sudo.sh +++ b/scripts/auth-sudo.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to authenticate sudo early diff --git a/scripts/check-env.sh b/scripts/check-env.sh index c79bdf4..109d343 100644 --- a/scripts/check-env.sh +++ b/scripts/check-env.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh # shellcheck disable=SC2034 @@ -9,20 +9,27 @@ check_env() { print_step "Check the environment for necessary tools and permissions" start_spinner "Checking..." - + { - local req_message - local pm_message - local priv_message - - # Check for required commands - REQUIREMENTS="curl sudo" - for req in $REQUIREMENTS; do - if ! command_exists "$req"; then - req_message="$(msg_err "Missing required command: $req")" - exit 1 - fi - done + pm_message + priv_message + continue=true + + # Determine privilege escalation method + if [ "$(id -u)" -eq 0 ]; then + # Running as root + SUDO_CMD="" + priv_message="$(msg_ok "Running as root, sudo is not needed.")" + elif command_exists sudo; then + SUDO_CMD="sudo" + priv_message="$(msg_ok "Using ${BOLD}${ITALIC}${MAGENTA}sudo${RC} for privilege escalation.")" + elif command_exists doas && [ -f "/etc/doas.conf" ]; then + SUDO_CMD="doas" + priv_message="$(msg_ok "Using ${BOLD}${ITALIC}${MAGENTA}doas${RC} for privilege escalation.")" + else + priv_message="$(msg_err "No suitable privilege escalation tool found (sudo/doas).")" + continue=false + fi # Determine the package manager to use PACKAGEMANAGER="apt-get dnf yum pacman zypper apk" @@ -36,25 +43,15 @@ check_env() { if [ -z "$PACKAGER" ]; then pm_message="$(msg_err "No supported package manager found.")" - exit 1 + continue=false fi - # Determine privilege escalation method - if [ "$(id -u)" -eq 0 ]; then - # Running as root - SUDO_CMD="" - priv_message="$(msg_ok "Running as root, sudo is not needed.")" - elif command_exists sudo; then - SUDO_CMD="sudo" - priv_message="$(msg_ok "Using ${BOLD}${ITALIC}${MAGENTA}sudo${RC} for privilege escalation.")" - elif command_exists doas && [ -f "/etc/doas.conf" ]; then - SUDO_CMD="doas" - priv_message="$(msg_ok "Using doas for privilege escalation.")" - else - priv_message="$(msg_err "No suitable privilege escalation tool found (sudo/doas).")" - exit 1 - fi - } >> "$LOG_FILE" 2>&1 - stop_spinner "$req_message" "$pm_message" "$priv_message" + } >> "${LOG_FILE:-/dev/null}" 2>&1 + + stop_spinner "$pm_message" "$priv_message" + + if [ "$continue" = false ]; then + exit 1 + fi } diff --git a/scripts/command-exists.sh b/scripts/command-exists.sh index d69ada8..bea10ee 100644 --- a/scripts/command-exists.sh +++ b/scripts/command-exists.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to check if a command exists diff --git a/scripts/conf-zsh-env.sh b/scripts/conf-zsh-env.sh index b5bf720..a105230 100644 --- a/scripts/conf-zsh-env.sh +++ b/scripts/conf-zsh-env.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh # shellcheck disable=SC1091 @@ -10,12 +10,12 @@ conf_zsh_env() { print_step "Configure zsh environment" start_spinner "Configuring..." - { - local message - local zshenv_path - local os_id - local os_like + message="" + zshenv_path="" + os_id="" + os_like="" + { # zsh's global config dir varies: # Debian/Arch/Alpine use /etc/zsh, # RHEL/Fedora-family use /etc/zshenv @@ -42,7 +42,7 @@ conf_zsh_env() { fi EOF message="$(msg_ok "Zsh environment configured successfully!")" - } >> "$LOG_FILE" 2>&1 + } >> "${LOG_FILE:-/dev/null}" 2>&1 stop_spinner "$message" } \ No newline at end of file diff --git a/scripts/head.sh b/scripts/head.sh index 6c018a1..92d5c7c 100644 --- a/scripts/head.sh +++ b/scripts/head.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Head @@ -10,11 +10,15 @@ head() { # Define and format output using printf to control line width (80 characters) if [ -f /etc/os-release ]; then # shellcheck source=/dev/null - . /etc/os-release - os_name="${ID^}" # e.g. "Ubuntu" or "Debian" - desc="${PRETTY_NAME}" # e.g. "Debian GNU/Linux 12 (bookworm)" - version="${VERSION_ID}" # e.g. "12" - codename="${VERSION_CODENAME}" # e.g. "bookworm" + eval "$( + . /etc/os-release + rest="${ID#?}" + first="${ID%"$rest"}" + printf 'os_name=%s\n' "\"$(printf '%s' "$first" | tr '[:lower:]' '[:upper:]')$rest\"" + printf 'desc=%s\n' "\"$PRETTY_NAME\"" + printf 'version=%s\n' "\"$VERSION_ID\"" + printf 'codename=%s\n' "\"$VERSION_CODENAME\"" + )" else os_name="Unknown" desc="Unknown" diff --git a/scripts/install-deps.sh b/scripts/install-deps.sh index b302b94..cdac882 100644 --- a/scripts/install-deps.sh +++ b/scripts/install-deps.sh @@ -1,7 +1,28 @@ -#!/usr/bin/env bash +#!/bin/sh # shellcheck disable=SC2086 +pkg_installed() { + case "$PACKAGER" in + apt-get) dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -q "install ok installed" ;; + dnf|yum|zypper) rpm -q "$1" >/dev/null 2>&1 ;; + pacman) pacman -Q "$1" >/dev/null 2>&1 ;; + apk) apk info -e "$1" >/dev/null 2>&1 ;; + *) return 1 ;; + esac +} + +install_pkg() { + case "$PACKAGER" in + apt-get) $SUDO_CMD env DEBIAN_FRONTEND=noninteractive apt-get install -y "$@" ;; + dnf|yum) $SUDO_CMD "$PACKAGER" install -y "$@" ;; + pacman) $SUDO_CMD pacman -S --noconfirm --needed "$@" ;; + zypper) $SUDO_CMD zypper --non-interactive install "$@" ;; + apk) $SUDO_CMD apk add "$@" ;; + *) printf 'Unsupported package manager: %s\n' "$PACKAGER"; return 1 ;; + esac +} + ################################################################################## ##### Function to install dependencies ################################################################################## @@ -10,42 +31,33 @@ install_deps() { DEPENDENCIES="stow curl tree wget unzip fontconfig ca-certificates jq" print_step "Install dependencies" - start_spinner "Installing..." - - { - printf "\n##### Function to install dependencies #####\n" - - local message - local install_status - - case "$PACKAGER" in - pacman) - ${SUDO_CMD} pacman-key --init - ${SUDO_CMD} "${PACKAGER}" -Sy --needed --noconfirm archlinux-keyring - ${SUDO_CMD} "${PACKAGER}" -Syu --needed --noconfirm ${DEPENDENCIES} - ;; - dnf | yum | zypper | apt | apt-get) - ${SUDO_CMD} "${PACKAGER}" install -y ${DEPENDENCIES} - ;; - apk) - ${SUDO_CMD} "${PACKAGER}" add ${DEPENDENCIES} - ;; - *) - ${SUDO_CMD} "${PACKAGER}" install -yq ${DEPENDENCIES} - ;; - esac - install_status=$? - - if [ "$install_status" -eq 0 ]; then - message="$(msg_ok "Dependencies installed!")" - else - message="$(msg_err "Something went wrong while installing dependencies! Check ${BOLD}${LOG_FILE}${RC} for details.")" + + for dep in $DEPENDENCIES; do + start_spinner "Installing..." + + message="" + install_status=0 + + { + if pkg_installed "$dep"; then + message="$(msg_skip "$dep")" + printf "\n--- %s skipped (already installed) ---\n" "$dep" + elif install_pkg "$dep"; then + message="$(msg_install_ok "$dep")" + printf "\n--- %s installed ---\n" "$dep" + else + install_status=$? + message="$(msg_err "Something went wrong while installing ${BOLD}${ITALIC}${MAGENTA}$dep${RC} pkg! Check ${BOLD}${LOG_FILE}${RC} for details.")" + printf "\n--- %s FAILED (exit %s) ---\n" "$dep" "$install_status" + fi + } >> "${LOG_FILE:-/dev/null}" 2>&1 + + if [ "$install_status" -ne 0 ]; then + stop_spinner "$message" + exit 1 fi - } >> "$LOG_FILE" 2>&1 - - stop_spinner "$message" - if [ "$install_status" -ne 0 ]; then - exit 1 - fi + stop_spinner "$message" + + done } \ No newline at end of file diff --git a/scripts/install-eza.sh b/scripts/install-eza.sh index bb21f7a..bdf87db 100644 --- a/scripts/install-eza.sh +++ b/scripts/install-eza.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to install eza @@ -8,11 +8,11 @@ install_eza() { print_step "Install eza" start_spinner "Installing..." + message="" + { printf "\n##### Function to install eza #####\n" - local message - if command_exists eza; then message="$(msg_skip "eza")" printf "Installation skipped - eza is already present!\n" @@ -23,12 +23,12 @@ install_eza() { ${SUDO_CMD} chown root:root eza ${SUDO_CMD} mv eza /usr/local/bin/eza if verify_installed eza; then - message="$(msg_ok "Successfully installed ${BOLD}eza${RC}.")" + message="$(msg_install_ok "eza")" else - message="$(msg_err "Installation of ${BOLD}eza${RC} could not be verified! Check ${BOLD}${LOG_FILE}${RC} for details.")" + message="$(msg_install_err "eza")" fi fi - } >> "$LOG_FILE" 2>&1 + } >> "${LOG_FILE:-/dev/null}" 2>&1 stop_spinner "$message" } \ No newline at end of file diff --git a/scripts/install-fd.sh b/scripts/install-fd.sh index 9e4b156..010114f 100644 --- a/scripts/install-fd.sh +++ b/scripts/install-fd.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to install fd @@ -11,28 +11,28 @@ install_fd() { print_step "Install fd" start_spinner "Installing..." + message="" + { printf "\n##### Function to install fd #####\n" - - local message if command_exists fd; then message="$(msg_skip "fd")" printf "Installation skipped - fd is already present!\n" else - local fd_version + fd_version fd_version=$(curl -s https://api.github.com/repos/sharkdp/fd/releases/latest | jq -r '.tag_name') cd /tmp || exit wget -c "https://github.com/sharkdp/fd/releases/download/${fd_version}/fd-${fd_version}-x86_64-unknown-linux-musl.tar.gz" -O - | tar xz ${SUDO_CMD} mv fd-*/fd /usr/local/bin/fd ${SUDO_CMD} chmod +x /usr/local/bin/fd if verify_installed fd; then - message="$(msg_ok "Successfully installed ${BOLD}fd${RC}.")" + message="$(msg_install_ok "fd")" else - message="$(msg_err "Installation of ${BOLD}fd${RC} could not be verified! Check ${BOLD}${LOG_FILE}${RC} for details.")" + message="$(msg_install_err "fd")" fi fi - } >> "$LOG_FILE" 2>&1 + } >> "${LOG_FILE:-/dev/null}" 2>&1 stop_spinner "$message" } \ No newline at end of file diff --git a/scripts/install-fzf.sh b/scripts/install-fzf.sh index d3c54fa..3d1e73e 100644 --- a/scripts/install-fzf.sh +++ b/scripts/install-fzf.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to install fzf @@ -8,12 +8,11 @@ install_fzf() { print_step "Install fzf" start_spinner "Installing..." + message="" + { printf "\n##### Function to install fzf #####\n" - local clone_message - local message - if command_exists fzf; then message="$(msg_skip "fzf")" printf "Installation skipped - fzf is already present!\n" @@ -23,12 +22,12 @@ install_fzf() { mkdir -p "$HOME/.local/bin" ln -sf "$HOME/.fzf/bin/fzf" "$HOME/.local/bin/fzf" if verify_installed fzf; then - message="$(msg_ok "Successfully installed ${BOLD}fzf${RC}.")" + message="$(msg_install_ok "fzf")" else - message="$(msg_err "Installation of ${BOLD}fzf${RC} could not be verified! Check ${BOLD}${LOG_FILE}${RC} for details.")" + message="$(msg_install_err "fzf")" fi fi - } >> "$LOG_FILE" 2>&1 + } >> "${LOG_FILE:-/dev/null}" 2>&1 - stop_spinner "$clone_message" "$message" + stop_spinner "$message" } \ No newline at end of file diff --git a/scripts/install-nerd-font.sh b/scripts/install-nerd-font.sh index 2fa1b0d..1490fa9 100644 --- a/scripts/install-nerd-font.sh +++ b/scripts/install-nerd-font.sh @@ -1,142 +1,140 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Fetch the canonical list of Nerd Font names (= release asset names) ################################################################################## get_font_list() { - local json json=$(curl -fsSL "$FONTS_JSON_URL") || { printf "Failed to fetch font list from %s\n" "$FONTS_JSON_URL" | tee -a "$LOG_FILE" >&2 - exit 0 + return 1 } if command -v python3 >/dev/null 2>&1; then printf '%s' "$json" | python3 -c ' import json, sys data = json.load(sys.stdin) -names = sorted(f["folderName"] for f in data["fonts"]) -print("\n".join(names)) +print("\n".join(sorted(f["folderName"] for f in data["fonts"]))) ' elif command -v jq >/dev/null 2>&1; then printf '%s' "$json" | jq -r '.fonts[].folderName' | sort else printf "Need python3 or jq installed to parse the font list\n" | tee -a "$LOG_FILE" >&2 - exit 0 + return 1 fi } +# True if directory $1 directly contains a .ttf/.otf file (any case) +has_font_files() { + for f in "$1"/*; do + case "$f" in + *.[tT][tT][fF]|*.[oO][tT][fF]) [ -f "$f" ] && return 0 ;; + esac + done + return 1 +} + ################################################################################## ##### Function to install Nerd font ################################################################################## install_nerd_font() { - print_step "Install Nerd font" # Ask for Nerd font at all - local need_nerd_font while true; do - read -rp "Do you want Nerd font [Y/n] " need_nerd_font + printf "Do you want Nerd font [Y/n] " + read -r need_nerd_font || { echo; return 0; } # EOF -> skip case "$need_nerd_font" in - [Yy]*) break ;; + ''|[Yy]*) break ;; [Nn]*) printf "Skipping font installation.\n" | tee -a "$LOG_FILE" - echo return 0 ;; *) echo "Please answer y or n." ;; esac done - + # Menu is interactive, so it happens before the spinner starts. - mapfile -t fonts < <(get_font_list) + fonts=$(get_font_list) + total=$(printf '%s\n' "$fonts" | grep -c .) - # Check if fonts list is populated - if [ "${#fonts[@]}" -eq 0 ]; then + if [ "$total" -eq 0 ]; then printf "No fonts available - continuing without font installation.\n" | tee -a "$LOG_FILE" return 0 fi - + # Print menu echo - local cols=3 - local col_width=26 - local total=${#fonts[@]} - local total_items=$((total + 1)) - for ((i = 0; i < total_items; i++)); do - if (( i == 0 )); then - local skip_label="Skip installation" - local skip_pad=$(( col_width - ${#skip_label} )) - (( skip_pad < 0 )) && skip_pad=0 - printf "%3d) %s%s%s%*s" 0 "${BOLD}${GREEN}" "$skip_label" "${RC}" "$skip_pad" "" - else - printf "%3d) %-*s" "$i" "$col_width" "${fonts[$((i - 1))]}" - fi - if (( (i + 1) % cols == 0 )); then - echo - fi - done - if (( total_items % cols != 0 )); then - echo - fi - echo - - local choice + cols=3 + col_width=26 + i=0 + printf "%3d) %s%-${col_width}s%s" 0 "${BOLD}${GREEN}" "Skip installation" "${RC}" + while IFS= read -r font; do + i=$((i + 1)) + if [ $((i % cols)) -eq 0 ]; then echo; fi + printf "%3d) %-${col_width}s" "$i" "$font" + done </dev/null | grep -q .; then - message="$(msg_skip "$NERD_FONT_FAMILY")" + + message="" + font_dir="$FONT_INSTALL_ROOT/${font_family}NerdFont" + + # Already installed? (checked by font files, not fc-list name, + # since the internal family name doesn't always match) + if has_font_files "$font_dir"; then + message="$(msg_skip "$font_family")" + elif ! tmp_dir=$(mktemp -d); then + message="$(msg_err "Could not create a temporary directory!")" else - local tmp_dir archive url - tmp_dir=$(mktemp -d) - archive="$tmp_dir/${NERD_FONT_FAMILY}.zip" - url="https://github.com/ryanoasis/nerd-fonts/releases/latest/download/${NERD_FONT_FAMILY}.zip" - + archive="$tmp_dir/${font_family}.zip" + url="https://github.com/ryanoasis/nerd-fonts/releases/latest/download/${font_family}.zip" + if ! curl -fsSL "$url" -o "$archive"; then - message="$(msg_err "Failed to download ${BOLD}$NERD_FONT_FAMILY${RC}! Check ${BOLD}${LOG_FILE}${RC} for details.")" + message="$(msg_err "Failed to download ${BOLD}$font_family${RC}! Check ${BOLD}${LOG_FILE}${RC} for details.")" else mkdir -p "$tmp_dir/unpacked" "$font_dir" if ! unzip -qq -o "$archive" -d "$tmp_dir/unpacked"; then - message="$(msg_err "Failed to extract ${BOLD}$NERD_FONT_FAMILY${RC}! Check ${BOLD}${LOG_FILE}${RC} for details.")" + message="$(msg_err "Failed to extract ${BOLD}$font_family${RC}! Check ${BOLD}${LOG_FILE}${RC} for details.")" else - find "$tmp_dir/unpacked" -type f \( -iname '*.ttf' -o -iname '*.otf' \) -exec cp {} "$font_dir/" \; - - if ! find "$font_dir" -maxdepth 1 \( -iname '*.ttf' -o -iname '*.otf' \) | grep -q .; then - message="$(msg_err "No font files found for ${BOLD}$NERD_FONT_FAMILY${RC}!")" + find "$tmp_dir/unpacked" -type f \ + \( -name '*.[tT][tT][fF]' -o -name '*.[oO][tT][fF]' \) \ + -exec cp {} "$font_dir/" \; + + if ! has_font_files "$font_dir"; then + message="$(msg_err "No font files found for ${BOLD}$font_family${RC}!")" else fc-cache -f "$font_dir" >/dev/null 2>&1 - message="$(msg_ok "Font ${BOLD}$NERD_FONT_FAMILY${RC} installed.")" + message="$(msg_ok "Font ${BOLD}${ITALIC}${MAGENTA}$font_family${RC} installed.")" fi fi fi - + rm -rf "$tmp_dir" fi - } >> "$LOG_FILE" 2>&1 - + } >> "${LOG_FILE:-/dev/null}" 2>&1 + stop_spinner "$message" | tee -a "$LOG_FILE" } \ No newline at end of file diff --git a/scripts/install-ohmyposh.sh b/scripts/install-ohmyposh.sh index 56e58bd..bf6e1ef 100644 --- a/scripts/install-ohmyposh.sh +++ b/scripts/install-ohmyposh.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to install oh-my-posh @@ -8,12 +8,12 @@ install_ohmyposh() { print_step "Install oh-my-posh" start_spinner "Installing..." + mkdir_message="" + mkdir_confirm="" + message="" + { printf "\n##### Function to install oh-my-posh #####\n" - - local mkdir_message - local mkdir_confirm - local message if command_exists oh-my-posh; then message="$(msg_skip "oh-my-posh")" @@ -29,12 +29,12 @@ install_ohmyposh() { # Install Oh My Posh if curl -sS https://ohmyposh.dev/install.sh | bash -s -- -d ~/.local/bin && verify_installed oh-my-posh; then - message="$(msg_ok "Successfully installed ${BOLD}oh-my-posh${RC}!")" + message="$(msg_install_ok "oh-my-posh")" else - message="$(msg_err "Installation of ${BOLD}oh-my-posh${RC} could not be verified! Check ${BOLD}${LOG_FILE}${RC} for details.")" + message="$(msg_install_err "oh-my-posh")" fi fi - } >> "$LOG_FILE" 2>&1 + } >> "${LOG_FILE:-/dev/null}" 2>&1 stop_spinner "$mkdir_message" "$mkdir_confirm" "$message" } \ No newline at end of file diff --git a/scripts/install-zoxide.sh b/scripts/install-zoxide.sh index 4e98f50..96d08ce 100644 --- a/scripts/install-zoxide.sh +++ b/scripts/install-zoxide.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to install zoxide @@ -8,10 +8,10 @@ install_zoxide() { print_step "Install zoxide" start_spinner "Installing..." + message="" + { printf "\n##### Function to install zoxide #####\n" - - local message if command_exists zoxide; then message="$(msg_skip "zoxide")" @@ -19,12 +19,12 @@ install_zoxide() { else curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh if verify_installed zoxide; then - message="$(msg_ok "Successfully installed ${BOLD}zoxide${RC}.")" + message="$(msg_install_ok "zoxide")" else - message="$(msg_err "Installation of ${BOLD}zoxide${RC} could not be verified! Check ${BOLD}${LOG_FILE}${RC} for details.")" + message="$(msg_install_err "zoxide")" fi fi - } >> "$LOG_FILE" 2>&1 + } >> "${LOG_FILE:-/dev/null}" 2>&1 stop_spinner "$message" } diff --git a/scripts/install-zsh.sh b/scripts/install-zsh.sh index d176360..7f3b529 100644 --- a/scripts/install-zsh.sh +++ b/scripts/install-zsh.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to install zsh @@ -11,9 +11,12 @@ install_zsh() { { printf "\n##### Function to install zsh #####\n" - local message - - if ! command_exists zsh; then + message + + if command_exists zsh; then + message="$(msg_skip "zsh")" + printf "Installation skipped - zsh is already present!\n" + else case "$PACKAGER" in pacman) ${SUDO_CMD} "$PACKAGER" -S --needed --noconfirm zsh @@ -26,15 +29,13 @@ install_zsh() { ;; esac if verify_installed zsh; then - message="$(msg_ok "Successfully installed ${BOLD}zsh${RC}.")" + message="$(msg_install_ok "zsh")" else - message="$(msg_err "Installation of ${BOLD}zsh${RC} could not be verified! Check ${BOLD}${LOG_FILE}${RC} for details.")" + message="$(msg_install_err "zsh")" fi - else - message="$(msg_skip "zsh")" fi - } >> "$LOG_FILE" 2>&1 + } >> "${LOG_FILE:-/dev/null}" 2>&1 stop_spinner "$message" } \ No newline at end of file diff --git a/scripts/logging.sh b/scripts/logging.sh index b3789fd..5dcba74 100644 --- a/scripts/logging.sh +++ b/scripts/logging.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Log file diff --git a/scripts/output.sh b/scripts/output.sh index 3bcd8ba..973257d 100644 --- a/scripts/output.sh +++ b/scripts/output.sh @@ -1,17 +1,29 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Output helpers ################################################################################## # Section header: ==> Title print_step() { - printf '%s==>%s %s%s%s\n' \ + printf '\n%s==>%s %s%s%s\n' \ "${BOLD}${BLUE}" "${RC}" "${BOLD}${ITALIC}${YELLOW}" "$1" "${RC}" } # Status line builders (==> message), no trailing newline msg_ok() { printf '[%s%s] %s' "${BOLD}${GREEN}${SUCCESS}" "${RC}" "$1"; } + +msg_install_ok() { + printf '[%s%s] Successfully installed %s%s%s package.' \ + "${BOLD}${GREEN}${SUCCESS}" "${RC}" "${BOLD}${ITALIC}${MAGENTA}" "$1" "${RC}" +} + +msg_install_err() { + printf '[%s%s] Installation of %s%s%s could not be verified! Check %s for details.' \ + "${BOLD}${RED}${FAILED}" "${RC}" "${BOLD}${ITALIC}${MAGENTA}" "$1" "${RC}" "${BOLD}${LOG_FILE}${RC}" +} + msg_err() { printf '[%s%s] %s' "${BOLD}${RED}${FAILED}" "${RC}" "$1"; } + msg_warn() { printf '[%s%s] %s' "${BOLD}${YELLOW}${WARNING}" "${RC}" "$1"; } # "Installation skipped - is already present!" diff --git a/scripts/setup-zsh-conf.sh b/scripts/setup-zsh-conf.sh index 334bf66..a6ad6d6 100644 --- a/scripts/setup-zsh-conf.sh +++ b/scripts/setup-zsh-conf.sh @@ -1,7 +1,68 @@ -#!/usr/bin/env bash +#!/bin/sh # shellcheck disable=SC2059 +################################################################################## +##### Steps for zsh configuration (stops at the first failure) +################################################################################## +_setup_zsh_conf_steps() { + + # Check if the dotfiles directory exists + cd "$DOTFILES_DIR" || { + message="$(msg_err "Dotfiles directory '$DOTFILES_DIR' not found")" + return 1 + } + + # Check if stow is available + if ! command_exists stow; then + message="$(msg_err "${BOLD}Stow${RC} is not installed. Please install it first.")" + return 1 + fi + + # Back up existing configs that would conflict + for rc in .nanorc .vimrc; do + if [ -f "$HOME/$rc" ] && [ ! -L "$HOME/$rc" ]; then + mv "$HOME/$rc" "$HOME/$rc.bak" + printf '%s backed up to ~/%s.bak\n' "$rc" "$rc" + fi + done + + # Dry run first to check for conflicts (same target as the real run) + printf 'Checking for potential stow conflicts...\n' + if ! stow -n -t "$HOME" .; then + message="$(msg_err "${BOLD}Stow${RC} detected conflicts. You may need to manually resolve conflicts.")" + return 1 + fi + + # Perform actual stow + printf 'Creating symlinks...\n' + if ! stow -t "$HOME" .; then + message="$(msg_err "Failed to create symlinks.")" + return 1 + fi + + # Verify critical files were linked + if [ ! -f "$HOME/.config/zsh/.zshrc" ]; then + message="$(msg_err "Failed to create ${BOLD}.zshrc${RC} symlink.")" + return 1 + fi + + # Change default shell to zsh for current user + zsh_path="$(command -v zsh)" || { + message="$(msg_err "${BOLD}zsh${RC} not found in PATH.")" + return 1 + } + if ! ${SUDO_CMD} chsh -s "$zsh_path" "$(id -un)"; then + message="$(msg_err "Failed to change default shell to ${BOLD}zsh${RC}.")" + return 1 + fi + + # Create required directories + mkdir -p "$HOME/.local/state/zsh" "$HOME/.cache/zsh" + + message="$(msg_ok "Configuration of ${BOLD}${ITALIC}${MAGENTA}zsh${RC} setup completed successfully!")" +} + ################################################################################## ##### Function to setup zsh configuration ################################################################################## @@ -10,70 +71,24 @@ setup_zsh_conf() { print_step "Setup zsh configuration" start_spinner "Configuring..." + message="" + continue=true + { printf "\n##### Function to setup zsh configuration #####\n" - local message - - # Check if the dotfiles directory exists - cd "$DOTFILES_DIR" || { - message="$(msg_err "Dotfiles directory '$DOTFILES_DIR' not found")" - exit 1 - } - - # Check if stow is available - if ! command_exists stow; then - message="$(msg_err "${BOLD}Stow${RC} is not installed. Please install it first.")" - exit 1 - fi - - # Check if ~/.nanorc exists - if [ -f "$HOME/.nanorc" ]; then - mv "$HOME/.nanorc" "$HOME/.nanorc.bak" - printf "%snano configuration file backup in ~/.nanorc.bak%s\n" "${GREEN}" "${RC}" - fi - - # Check if ~/.vimrc exists - if [ -f "$HOME/.vimrc" ]; then - mv "$HOME/.vimrc" "$HOME/.vimrc.bak" - printf "%svim configuration file backup in ~/.vimrc.bak%s\n" "${GREEN}" "${RC}" - fi - - # Do stow dry run first to check for conflicts - printf "$(msg_warn "Checking for potential stow conflicts...")" - - if ! stow -n .; then - message="$(msg_err "${BOLD}Stow${RC} detected conflicts. You may need to manually resolve conflicts.")" - exit 1 - fi - - # If dry run successful, perform actual stow - printf "$(msg_warn "Creating symlinks...")" - - if ! stow -t "$HOME" .; then - message="$(msg_err "Failed to create symlinks.")" - exit 1 - fi - - # Verify critical files were linked - if [ ! -f "$HOME/.config/zsh/.zshrc" ]; then - message="$(msg_err "Failed to create ${BOLD}.zshrc${RC} symlink.")" - exit 1 - fi - - # Change default shell to zsh for current user - ${SUDO_CMD} chsh -s "$(which zsh)" "$USER" + _setup_zsh_conf_steps || continue=false - # Create required directories - mkdir -p "$HOME/.local/state/zsh" # history - mkdir -p "$HOME/.cache/zsh" # completion cache - - message="$(msg_ok "Configuration of ${BOLD}${ITALIC}${MAGENTA}zsh${RC} setup completed successfully!")" - - } >> "$LOG_FILE" 2>&1 + } >> "${LOG_FILE:-/dev/null}" 2>&1 stop_spinner "$message" + if [ "$continue" = false ]; then + exit 1 + fi + # Source the new configuration + printf "\n" printf "%sPlease execute %sexec zsh%s %sand the installation will continue ...%s" "${BOLD}${ITALIC}" "${BOLD}${MAGENTA}" "${RC}" "${BOLD}${ITALIC}" "${RC}" + printf "\n" } \ No newline at end of file diff --git a/scripts/spinner.sh b/scripts/spinner.sh index ed8dea7..b07a21c 100644 --- a/scripts/spinner.sh +++ b/scripts/spinner.sh @@ -1,51 +1,62 @@ -#!/usr/bin/env bash +#!/bin/sh # shellcheck disable=SC2034 ################################################################################## ##### Spinner ################################################################################## -# Define an array of Braille patterns for a spinner -eight_dot_cell_pattern=("⣾" "⢿" "⡿" "⣷" "⣯" "⢟" "⡻" "⣽") -six_dot_cell_pattern=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏") +# Braille patterns for the spinner (space-separated frames) +eight_dot_cell_pattern="⣾ ⢿ ⡿ ⣷ ⣯ ⢟ ⡻ ⣽" +six_dot_cell_pattern="⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏" # Set the pattern -braille_spinner=("${six_dot_cell_pattern[@]}") +braille_spinner="$six_dot_cell_pattern" -# Set the duration for each spinner frame (in seconds) +# Duration of each spinner frame (in seconds) frame_duration=0.2 -# Function to start the spinner in the background +spinner_pid="" + +# Start the spinner in the background start_spinner() { action_message=$1 ( - idx=0 while :; do - printf "\r[%s] %s" "${braille_spinner[idx]}" "$action_message" - idx=$(( (idx + 1) % ${#braille_spinner[@]} )) - sleep "$frame_duration" + for frame in $braille_spinner; do + printf "\r[%s] %s" "$frame" "$action_message" + sleep "$frame_duration" + done done ) & spinner_pid=$! - disown } -# Function to stop the spinner with U+2800 +# Stop the spinner and print the result messages stop_spinner() { - kill -9 "$spinner_pid" 2>/dev/null # Stop the spinner loop - wait "$spinner_pid" 2>/dev/null + if [ -n "$spinner_pid" ]; then + kill "$spinner_pid" 2>/dev/null + wait "$spinner_pid" 2>/dev/null + spinner_pid="" + fi - # Move to start of line and clear it, instead of just moving to a new line + # Move to start of line and clear it printf "\r\033[K" - # Process all arguments for msg in "$@"; do - [[ -n "$msg" ]] && printf "%b\n" "$msg" + if [ -n "$msg" ]; then + printf "%b\n" "$msg" + fi done - - printf "\n" } -# Kill the spinner when the script exits, regardless of success or failure or someone pressing Ctrl+C -trap 'kill -9 "$spinner_pid" 2>/dev/null; printf "\n"' EXIT \ No newline at end of file +# Kill the spinner on exit, error, or Ctrl+C +cleanup_spinner() { + if [ -n "$spinner_pid" ]; then + kill "$spinner_pid" 2>/dev/null + printf "\r\033[K" + fi +} +trap cleanup_spinner EXIT +trap 'exit 130' INT +trap 'exit 143' TERM \ No newline at end of file diff --git a/scripts/update-system.sh b/scripts/update-system.sh index cd9ae30..d251c59 100644 --- a/scripts/update-system.sh +++ b/scripts/update-system.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to update system packages @@ -8,8 +8,8 @@ update_system() { print_step "Update system packages" start_spinner "Updating..." - local message - local unsupported=0 + message="" + unsupported=0 { printf "\n##### Function to update system packages #####\n" diff --git a/scripts/verify-installed.sh b/scripts/verify-installed.sh index 0beefa4..55b21fd 100644 --- a/scripts/verify-installed.sh +++ b/scripts/verify-installed.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh ################################################################################## ##### Function to verify a tool is available after installing diff --git a/setup.sh b/setup.sh index 3e07d37..4f62bca 100755 --- a/setup.sh +++ b/setup.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/sh # shellcheck disable=SC2034,SC1090 @@ -8,10 +8,12 @@ BOX_WIDTH=76 ################################################################################## ##### Load external functions ################################################################################## -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd -P)" for f in "$SCRIPT_DIR"/scripts/*; do - [[ -f "$f" ]] && source "$f" + if [ -f "$f" ]; then + . "$f" + fi done ################################################################################## @@ -19,11 +21,11 @@ done ################################################################################## head start_log -install_nerd_font "$@" check_env auth_sudo update_system install_deps +install_nerd_font "$@" install_zsh conf_zsh_env install_ohmyposh