Files
dotfiles/script/install
2025-08-24 17:43:35 +01:00

170 lines
4.3 KiB
Bash
Executable File

#!/usr/bin/env bash
set -eo pipefail
# --------------------------------------------------------------------
# Script to run all install scripts contained in install.d
#
if [[ -t 1 && -n "$TERM" && "$TERM" != "dumb" ]]; then
BLUE="\033[0;34m"
CYAN="\033[0;36m"
CYAN_BOLD="\033[1;36m"
RED="\033[1;31m"
GREEN="\033[1;32m"
YELLOW="\033[1;33m"
GREY="\033[1;30m"
NC="\033[0m"
else
BLUE=""
CYAN=""
CYAN_BOLD=""
RED=""
GREEN=""
YELLOW=""
GREY=""
NC=""
fi
# Log functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $*"
}
log_pass() {
echo -e "${GREEN}[PASS]${NC} $*"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $*"
}
log_error() {
echo -e "${RED}[FAIL]${NC} $*"
}
log_debug() {
echo -e "${CYAN}$*${NC}"
}
# Export log functions so they're available in sourced scripts
export -f log_info
export -f log_pass
export -f log_warn
export -f log_error
export -f log_debug
printf "\n\t${CYAN} <<< ${CYAN_BOLD}dots${CYAN} >>> ${NC}\n"
printf "\t${GREY}==============${NC}\n\n"
# High-resolution time helpers
# now_ns prints current time in nanoseconds using GNU date if available.
# On systems where %N isn't supported (e.g., BSD date), it falls back to
# seconds precision multiplied to nanoseconds. This avoids external deps like bc.
now_ns() {
local ns
ns=$(date +%s%N 2>/dev/null || true)
if [[ "$ns" =~ ^[0-9]+$ ]]; then
echo "$ns"
else
# Fallback: seconds precision
local s
s=$(date +%s)
echo $(( s * 1000000000 ))
fi
}
# Prevent running as root
if [[ $EUID -eq 0 && -z "$SKIP_SUDO_CHECK" ]]; then
echo -e "${RED}Failed: Running as sudo. Please run as user${NC}\n"
exit 1
fi
# Ensure sudo credentials are cached
if [[ -z "$SKIP_SUDO_CHECK" ]]; then
echo -e "${YELLOW}Checking sudo credentials...${NC}"
sudo -v
fi
# Set up directory variables
if [ -L "$0" ]; then
dir=$(dirname $(readlink -f "$0"))
else
dir=$(dirname "$0")
fi
install_dir="$dir/install.d"
export DOTFILES=$(dirname "$dir")
# Set up log destination
if [[ -z "$LOG_TARGET" ]]; then
timestamp=$(date +%Y-%m-%dT%H:%M:%S)
uuid=$(
uuidgen 2> /dev/null \
|| cat /proc/sys/kernel/random/uuid 2> /dev/null \
|| echo $RANDOM
)
log_dir="$dir/logs"
mkdir -p "$log_dir"
log_target=${LOG_TARGET:-"$log_dir/$uuid.log"}
else
log_target="$LOG_TARGET"
fi
touch "$log_target"
if [[ ! -f "$log_target" ]]; then
echo -e "${RED}Failed: Unable to create log file \"$log_target\"${NC}\n"
exit 1
fi
log_abs_target=$(readlink -f "$log_target")
# Set up targets
targets=($@)
# Run install scripts
run() {
echo -e "Running \"$(basename "$0")\" at \"$(date)\""
echo -e "Running as \"$(whoami)\" on \"$(hostname)\""
if [[ -n "$targets" ]]; then
echo -e "Running ${YELLOW}${#targets[@]}${NC} install target(s): ${YELLOW}${targets[@]}${NC}"
else
echo -e "Running all install targets"
fi
for script in $install_dir/*.sh; do
if [[ -n "$targets" ]]; then
script_name=$(basename "$script" .sh)
script_name=${script_name#*-}
if [[ ! " ${targets[*]} " =~ " $script_name " ]]; then
continue
fi
fi
local script_name=$(basename "$script")
printf "\n\n${CYAN}<<< ${CYAN_BOLD}$script_name:${NC}\n"
local start_ns=$(now_ns)
source "$script"
local end_ns=$(now_ns)
local execution_ms=$(( (end_ns - start_ns) / 1000000 ))
local execution_ms_formatted=$(printf "%'d" "$execution_ms")
local time_color="$GREY"
if (( execution_ms < 2000 )); then
time_color="$GREEN"
elif (( execution_ms < 5000 )); then
time_color="$YELLOW"
else
time_color="$RED"
fi
printf "\n${CYAN}>>> ${CYAN_BOLD}${script_name}, ${NC}"
printf "completed in ${time_color}${execution_ms_formatted}ms${NC}\n"
done
}
echo -e "\ninstall: Logging to \"$log_abs_target\""
total_start_ns=$(now_ns)
run 2>&1 | tee "$log_abs_target"
total_end_ns=$(now_ns)
total_ms=$(( (total_end_ns - total_start_ns) / 1000000 ))
total_s=$(( total_ms / 1000 ))
total_ms_rem=$(( total_ms % 1000 ))
echo -e "\nThank you!"
printf "Total time: ${GREEN}%d.%03ds${NC}\n\n" "$total_s" "$total_ms_rem"