forked from Scrut1ny/AutoVirt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.sh
More file actions
executable file
·192 lines (158 loc) · 6.88 KB
/
utils.sh
File metadata and controls
executable file
·192 lines (158 loc) · 6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env bash
# =============================================================================
# ANSI ESCAPE CODES - Text Styles, Colors, Backgrounds
# =============================================================================
# Styles
readonly RESET=$'\033[0m'
readonly TEXT_BOLD=$'\033[1m'
readonly TEXT_DIM=$'\033[2m'
readonly TEXT_ITALIC=$'\033[3m'
readonly TEXT_UNDER=$'\033[4m'
readonly TEXT_BLINK=$'\033[5m'
readonly TEXT_REVERSE=$'\033[7m'
readonly TEXT_HIDDEN=$'\033[8m'
readonly TEXT_STRIKE=$'\033[9m'
# Foreground colors
readonly TEXT_BLACK=$'\033[30m' TEXT_GRAY=$'\033[90m'
readonly TEXT_RED=$'\033[31m' TEXT_BRIGHT_RED=$'\033[91m'
readonly TEXT_GREEN=$'\033[32m' TEXT_BRIGHT_GREEN=$'\033[92m'
readonly TEXT_YELLOW=$'\033[33m' TEXT_BRIGHT_YELLOW=$'\033[93m'
readonly TEXT_BLUE=$'\033[34m' TEXT_BRIGHT_BLUE=$'\033[94m'
readonly TEXT_MAGENTA=$'\033[35m' TEXT_BRIGHT_MAGENTA=$'\033[95m'
readonly TEXT_CYAN=$'\033[36m' TEXT_BRIGHT_CYAN=$'\033[96m'
readonly TEXT_WHITE=$'\033[37m' TEXT_BRIGHT_WHITE=$'\033[97m'
# Background colors
readonly BACK_BLACK=$'\033[40m' BACK_GRAY=$'\033[100m'
readonly BACK_RED=$'\033[41m' BACK_BRIGHT_RED=$'\033[101m'
readonly BACK_GREEN=$'\033[42m' BACK_BRIGHT_GREEN=$'\033[102m'
readonly BACK_YELLOW=$'\033[43m' BACK_BRIGHT_YELLOW=$'\033[103m'
readonly BACK_BLUE=$'\033[44m' BACK_BRIGHT_BLUE=$'\033[104m'
readonly BACK_MAGENTA=$'\033[45m' BACK_BRIGHT_MAGENTA=$'\033[105m'
readonly BACK_CYAN=$'\033[46m' BACK_BRIGHT_CYAN=$'\033[106m'
readonly BACK_WHITE=$'\033[47m' BACK_BRIGHT_WHITE=$'\033[107m'
# =============================================================================
# LOGGING (low-level)
# =============================================================================
__log::write() {
local stream=$1; shift
if [[ $stream == stderr ]]; then
printf '%b\n' "$*" >&2
else
printf '%b\n' "$*"
fi
printf '%b\n' "$*" >>"$LOG_FILE"
}
# =============================================================================
# FORMAT / LOG HELPERS
# =============================================================================
__fmtr::line() {
local icon=$1 color=$2; shift 2
printf '\n %b%s%b %s' "$color" "$icon" "$RESET" "$*"
}
fmtr::log() { __log::write stdout "$(__fmtr::line '[+]' "$TEXT_BRIGHT_GREEN" "$@")"; }
fmtr::info() { __log::write stdout "$(__fmtr::line '[i]' "$TEXT_BRIGHT_CYAN" "$@")"; }
fmtr::warn() { __log::write stdout "$(__fmtr::line '[!]' "$TEXT_BRIGHT_YELLOW" "$@")"; }
fmtr::error() { __log::write stderr "$(__fmtr::line '[-]' "$TEXT_BRIGHT_RED" "$@")"; }
fmtr::fatal() {
__log::write stderr "$(printf '\n %b%s %s%b' "$TEXT_RED$TEXT_BOLD" '[X]' "$*" "$RESET")"
}
fmtr::box_text() {
local text=$1 pad border
printf -v pad '%*s' $(( ${#text} + 2 )) ''
border=${pad// /═}
printf '\n ╔%s╗\n ║ %s ║\n ╚%s╝\n' "$border" "$text" "$border"
}
fmtr::ask() {
__log::write stdout "$(printf '\n %b[?]%b %s' "$TEXT_BLACK$BACK_BRIGHT_GREEN" "$RESET" "$1")"
}
fmtr::ask_inline() {
printf '\n %b[?]%b %s' "$TEXT_BLACK$BACK_BRIGHT_GREEN" "$RESET" "$1"
}
# =============================================================================
# PROMPTS
# =============================================================================
prmt::yes_or_no() {
local prompt=$* ans
while :; do
read -rp "$prompt [y/n]: " ans
printf '%s\n' "$ans" >>"$LOG_FILE"
case ${ans,,} in
y*) return 0 ;;
n*) return 1 ;;
*) printf '\n [!] Please answer y/n\n' ;;
esac
done
}
prmt::quick_prompt() {
local response
read -n1 -srp "$1" response
printf '%s\n' "$response"
printf '%s\n' "$response" >>"$LOG_FILE"
}
# =============================================================================
# DEBUG
# =============================================================================
dbg::fail() { fmtr::fatal "$1"; exit 1; }
# =============================================================================
# COMPATIBILITY
# =============================================================================
# Sets $ROOT_ESC to the first available privilege escalation tool (sudo, doas, pkexec).
compat::get_escalation_cmd() {
local cmd
for cmd in sudo doas pkexec; do
if command -v -- "$cmd" &>/dev/null; then
ROOT_ESC=$cmd
export ROOT_ESC
return 0
fi
done
fmtr::error "No supported privilege escalation tool found (sudo/doas/pkexec)."
exit 1
}
# =============================================================================
# PACKAGES
# =============================================================================
install_req_pkgs() {
local component=$1
[[ -n $component ]] || { fmtr::error "Component name not specified!"; exit 1; }
fmtr::log "Checking for required missing $component packages..."
local mgr install_flags check_cmd
case $DISTRO in
Arch) mgr=pacman; install_flags='-S --noconfirm'; check_cmd='pacman -Q' ;;
Debian) mgr=apt; install_flags='-y install'; check_cmd='dpkg -s' ;;
openSUSE) mgr=zypper; install_flags='install -y'; check_cmd='rpm -q' ;;
Fedora) mgr=dnf; install_flags='-yq install'; check_cmd='rpm -q' ;;
*) fmtr::error "Unsupported distribution: $DISTRO."; exit 1 ;;
esac
local pkg_var="REQUIRED_PKGS_${DISTRO}"
declare -n req="$pkg_var" 2>/dev/null || { fmtr::error "$component packages undefined for $DISTRO."; exit 1; }
local -a missing=()
local pkg
for pkg in "${req[@]}"; do
$check_cmd "$pkg" &>/dev/null || missing+=("$pkg")
done
(( ${#missing[@]} )) || { fmtr::log "All required $component packages already installed."; return 0; }
fmtr::warn "Missing required $component packages: ${missing[*]}"
if prmt::yes_or_no "$(fmtr::ask_inline "Install required missing $component packages?")"; then
$ROOT_ESC "$mgr" $install_flags "${missing[@]}" &>>"$LOG_FILE" || { fmtr::error "Failed to install required $component packages"; exit 1; }
fmtr::log "Installed: ${missing[*]}"
else
fmtr::log "Exiting due to required missing $component packages."
exit 1
fi
}
# =============================================================================
# LOGGING (init / side-effects)
# =============================================================================
log::init() {
: "${LOG_PATH:=$(pwd)/logs}"
: "${LOG_FILE:=$LOG_PATH/$(date +%s).log}"
export LOG_PATH LOG_FILE
mkdir -p -- "$LOG_PATH" || { printf 'Failed to create log directory.\n' >&2; exit 1; }
: >"$LOG_FILE" || { printf 'Failed to create log file.\n' >&2; exit 1; }
}
# =============================================================================
# AUTO-INIT (when sourced/executed)
# =============================================================================
log::init
compat::get_escalation_cmd