2024-01-27 21:15:25 -08:00
|
|
|
#!/usr/bin/env sh
|
2024-01-21 20:49:34 -08:00
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
skip_questions()
|
|
|
|
{
|
|
|
|
while :; do
|
|
|
|
case $1 in
|
|
|
|
-y | --yes ) return 0 ;;
|
|
|
|
* ) break ;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
shift 1
|
|
|
|
done
|
|
|
|
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
ask_for_sudo()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
sudo -v >/dev/null 2>&1
|
2024-01-21 20:49:34 -08:00
|
|
|
|
|
|
|
# Update existing 'sudo' timestamp until this script has finished.
|
|
|
|
#
|
|
|
|
# https://gist.github.com/cowboy/3118588
|
|
|
|
|
|
|
|
while true; do
|
|
|
|
sudo -n true
|
|
|
|
sleep 60
|
|
|
|
kill -0 "$$" || exit
|
2024-01-27 21:15:25 -08:00
|
|
|
done >/dev/null 2>&1 &
|
2024-01-21 20:49:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
print_in_color()
|
|
|
|
{
|
2024-01-25 13:58:01 -08:00
|
|
|
string=$(echo "$1" | tr -s " ")
|
|
|
|
|
2024-01-21 20:49:34 -08:00
|
|
|
printf "%b" \
|
|
|
|
"$(tput setaf "$2" 2> /dev/null)" \
|
2024-01-25 13:58:01 -08:00
|
|
|
"$string" \
|
2024-01-21 20:49:34 -08:00
|
|
|
"$(tput sgr0 2> /dev/null)"
|
|
|
|
}
|
|
|
|
|
|
|
|
print_in_red()
|
|
|
|
{
|
|
|
|
print_in_color "$1" 1
|
|
|
|
}
|
|
|
|
|
|
|
|
print_in_yellow()
|
|
|
|
{
|
|
|
|
print_in_color "$1" 3
|
|
|
|
}
|
|
|
|
|
|
|
|
print_in_green()
|
|
|
|
{
|
|
|
|
print_in_color "$1" 2
|
|
|
|
}
|
|
|
|
|
|
|
|
print_in_purple()
|
|
|
|
{
|
|
|
|
print_in_color "$1" 5
|
|
|
|
}
|
|
|
|
|
|
|
|
print_title()
|
|
|
|
{
|
|
|
|
print_in_purple "\n • $1\n\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
print_success()
|
|
|
|
{
|
|
|
|
print_in_green " [✔] $1\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
print_warning()
|
|
|
|
{
|
|
|
|
print_in_yellow " [!] $1\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
print_error()
|
|
|
|
{
|
|
|
|
print_in_red " [✖] $1 $2\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
print_question()
|
|
|
|
{
|
|
|
|
print_in_yellow " [?] $1\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
print_result()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
if [ "$1" = 0 ]; then
|
2024-01-21 20:49:34 -08:00
|
|
|
print_success "$2"
|
|
|
|
else
|
|
|
|
print_error "$2"
|
|
|
|
fi
|
|
|
|
|
|
|
|
return "$1"
|
|
|
|
}
|
|
|
|
|
|
|
|
print_error_stream()
|
|
|
|
{
|
|
|
|
while read -r line; do
|
|
|
|
print_error "↳ ERROR: $line"
|
|
|
|
done
|
|
|
|
}
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
2024-01-27 21:15:25 -08:00
|
|
|
# https://stackoverflow.com/a/32270158
|
|
|
|
# POSIX read -n 1
|
|
|
|
# Usage: var="$(read_char)"
|
|
|
|
read_char()
|
|
|
|
{
|
|
|
|
old=$(stty -g)
|
|
|
|
stty raw -echo min 0
|
|
|
|
printf '%s' "$(dd bs=1 count=1 2>/dev/null)"
|
|
|
|
stty "$old"
|
|
|
|
}
|
|
|
|
|
2024-01-21 20:49:34 -08:00
|
|
|
ask()
|
|
|
|
{
|
|
|
|
print_question "$1"
|
|
|
|
read -r
|
|
|
|
}
|
|
|
|
|
|
|
|
get_answer()
|
|
|
|
{
|
|
|
|
printf "%s" "$REPLY"
|
|
|
|
}
|
|
|
|
|
|
|
|
ask_for_confirmation()
|
|
|
|
{
|
|
|
|
print_question "$1 (y/n) "
|
2024-01-27 21:15:25 -08:00
|
|
|
REPLY="$(read_char)"
|
2024-01-21 20:49:34 -08:00
|
|
|
printf "\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
answer_is_yes()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
expr "$REPLY" : '[Yy]$'
|
2024-01-21 20:49:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
show_spinner()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
readonly FRAMES='/-\|'
|
2024-01-21 20:49:34 -08:00
|
|
|
|
2024-01-27 21:15:25 -08:00
|
|
|
readonly NUMBER_OF_FRAMES=${#FRAMES}
|
2024-01-21 20:49:34 -08:00
|
|
|
|
2024-01-27 21:15:25 -08:00
|
|
|
readonly CMDS="$2"
|
|
|
|
readonly MSG="$3"
|
|
|
|
readonly PID="$1"
|
2024-01-21 20:49:34 -08:00
|
|
|
|
2024-01-27 21:15:25 -08:00
|
|
|
i=0
|
|
|
|
frame_text=""
|
2024-01-21 20:49:34 -08:00
|
|
|
|
|
|
|
# Provide more space so that the text hopefully doesn't reach the bottom line
|
|
|
|
# of the terminal window.
|
|
|
|
#
|
|
|
|
# This is a workaround for escape sequences not tracking the buffer position
|
|
|
|
# (accounting for scrolling).
|
|
|
|
#
|
|
|
|
# See also: https://unix.stackexchange.com/a/278888
|
|
|
|
|
|
|
|
printf "\n\n\n"
|
|
|
|
tput cuu 3
|
|
|
|
tput sc
|
|
|
|
|
2024-01-27 21:15:25 -08:00
|
|
|
while kill -0 "$PID" >/dev/null 2>&1; do
|
|
|
|
i=$((i+1))
|
|
|
|
num=$((i % NUMBER_OF_FRAMES))
|
|
|
|
frame="$(echo $FRAMES | cut -c ${num}-$((num + 1)))"
|
|
|
|
frame_text=" [$frame] $MSG"
|
2024-01-21 20:49:34 -08:00
|
|
|
|
|
|
|
# Print frame text.
|
|
|
|
printf "%s" "$frame_text"
|
|
|
|
|
|
|
|
sleep 0.2
|
|
|
|
|
|
|
|
# Clear frame text.
|
|
|
|
tput rc
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
cmd_exists()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
command -v "$1" >/dev/null 2>&1
|
2024-01-21 20:49:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
is_git_repository()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
git rev-parse >/dev/null 2>&1
|
|
|
|
}
|
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
# https://stackoverflow.com/a/29835459
|
|
|
|
# POSIX compliant way of finding BASH_SOURCE
|
|
|
|
# Usage: sh_source "$0"
|
|
|
|
rreadlink()
|
|
|
|
(
|
|
|
|
target=$1
|
|
|
|
fname=
|
|
|
|
targetDir=
|
|
|
|
CDPATH=
|
|
|
|
|
|
|
|
{ \unalias command; \unset-f command; } >/dev/null 2>&1
|
|
|
|
# shellcheck disable=SC2034
|
|
|
|
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on
|
|
|
|
|
|
|
|
while :; do
|
|
|
|
[ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: $target does not exist." >&2; return 1; }
|
|
|
|
# shellcheck disable=SC2164
|
|
|
|
command cd "$(command dirname -- "$target")"
|
|
|
|
fname=$(command basename -- "$target")
|
|
|
|
[ "$fname" = '/' ] && fname=''
|
|
|
|
|
|
|
|
if [ -L "$fname" ]; then
|
|
|
|
target=$(command ls -l "$fname")
|
|
|
|
target=${target#* -> }
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
|
|
|
|
break
|
|
|
|
done
|
|
|
|
|
|
|
|
targetDir=$(command pwd -P)
|
|
|
|
if [ "$fname" = '.' ]; then
|
|
|
|
command printf '%s\n' "${targetDir%/}"
|
|
|
|
elif [ "$fname" = '..' ]; then
|
|
|
|
command printf '%s\n' "${targetDir%/}/$fname"
|
|
|
|
fi
|
|
|
|
)
|
|
|
|
|
|
|
|
sh_source()
|
|
|
|
{
|
|
|
|
printf '%s' "$(dirname -- "$(rreadlink "$1")")"
|
2024-01-21 20:49:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
set_trap()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
trap | grep "'$2' $1" >/dev/null 2>&1 \
|
2024-01-25 13:58:01 -08:00
|
|
|
|| trap '$2' "$1"
|
2024-01-21 20:49:34 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
kill_all_subproccesses()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
i=""
|
2024-01-21 20:49:34 -08:00
|
|
|
|
|
|
|
for i in $(jobs -p); do
|
|
|
|
kill "$i"
|
2024-01-27 21:15:25 -08:00
|
|
|
wait "$i" >/dev/null 2>&1
|
2024-01-21 20:49:34 -08:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
execute()
|
|
|
|
{
|
2024-01-27 21:15:25 -08:00
|
|
|
readonly CMDS="$1"
|
|
|
|
readonly MSG="${2:-$1}"
|
|
|
|
|
|
|
|
readonly TMP_FILE
|
|
|
|
TMP_FILE="$(mktemp /tmp/XXXXX)"
|
2024-01-21 20:49:34 -08:00
|
|
|
|
2024-01-27 21:15:25 -08:00
|
|
|
exit_code=0
|
|
|
|
cmds_pid=""
|
2024-01-21 20:49:34 -08:00
|
|
|
|
|
|
|
# If the current process is ended, also end all its subproccesses.
|
|
|
|
set_trap "EXIT" "kill_all_subproccesses"
|
|
|
|
|
|
|
|
# Execute commands in background
|
|
|
|
# shellcheck disable=SC2261
|
|
|
|
eval "$CMDS" \
|
2024-01-27 21:15:25 -08:00
|
|
|
>/dev/null 2>&1 \
|
2024-01-21 20:49:34 -08:00
|
|
|
2> "$TMP_FILE" &
|
|
|
|
|
|
|
|
cmds_pid=$!
|
|
|
|
|
|
|
|
# Show a spinner if the commands require more time to complete.
|
|
|
|
show_spinner "$cmds_pid" "$CMDS" "$MSG"
|
|
|
|
|
|
|
|
# Wait for the commands to no longer be executing in the background, and then
|
|
|
|
# get their exit code.
|
2024-01-27 21:15:25 -08:00
|
|
|
wait "$cmds_pid" >/dev/null 2>&1
|
2024-01-21 20:49:34 -08:00
|
|
|
exit_code=$?
|
|
|
|
|
|
|
|
# Print output based on what happened.
|
|
|
|
print_result $exit_code "$MSG"
|
|
|
|
|
2024-01-27 21:15:25 -08:00
|
|
|
if [ $exit_code -ne 0 ]; then
|
2024-01-21 20:49:34 -08:00
|
|
|
print_error_stream < "$TMP_FILE"
|
|
|
|
fi
|
|
|
|
|
|
|
|
rm -rf "$TMP_FILE"
|
|
|
|
|
|
|
|
return $exit_code
|
|
|
|
}
|