Quiet dnf + live ASCII progress (recovered from orphaned PR #7) #8
+50
-6
@@ -71,16 +71,60 @@ pause_if_debug() {
|
|||||||
#------------------------------------------
|
#------------------------------------------
|
||||||
# Package helpers (dnf5)
|
# Package helpers (dnf5)
|
||||||
#------------------------------------------
|
#------------------------------------------
|
||||||
|
# True when gum is installed AND we are interactive (stdin tty + /dev/tty
|
||||||
|
# writable). stdout must NOT be checked: it is a pipe inside $(...).
|
||||||
|
# Unattended runs never get the TUI (see ui_quiet_run).
|
||||||
|
have_gum() {
|
||||||
|
command -v gum >/dev/null 2>&1 || return 1
|
||||||
|
[[ "${ASSUME_YES:-false}" == "true" ]] && return 1
|
||||||
|
[ -t 0 ] || return 1
|
||||||
|
[ -w /dev/tty ] || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Quiet dnf transaction: spinner while it runs, one ok-line after, full output
|
||||||
|
# appended to $SETUP_DNF_LOG and printed (tail) only on failure. Unattended or
|
||||||
|
# no-gum runs execute plainly with normal output (logs matter there).
|
||||||
|
ui_quiet_run() {
|
||||||
|
local msg="$1"
|
||||||
|
shift
|
||||||
|
local log="${SETUP_DNF_LOG:-/tmp/fedora-setup-dnf.log}"
|
||||||
|
local before n
|
||||||
|
|
||||||
|
if ! have_gum; then
|
||||||
|
"$@"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
before=$(wc -l < "$log" 2>/dev/null || echo 0)
|
||||||
|
if LOGFILE="$log" gum spin --title "$msg" -- \
|
||||||
|
bash -c 'exec "$@" >>"$LOGFILE" 2>&1' _ "$@"; then
|
||||||
|
n=$(sed -n "$((before+1)),\$p" "$log" 2>/dev/null | grep -c '^Installing:' || true)
|
||||||
|
local plural="s"
|
||||||
|
(( n == 1 )) && plural=""
|
||||||
|
ok "$msg (${n} package${plural})"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
local rc=$?
|
||||||
|
color_red " Failed: $msg"
|
||||||
|
color_red " Last lines from $log:"
|
||||||
|
sed -n "$((before+1)),\$p" "$log" 2>/dev/null | tail -n 20 | sed 's/^/ /' >&2
|
||||||
|
return "$rc"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
install_packages() {
|
install_packages() {
|
||||||
# -y : no prompts
|
# -y : no prompts
|
||||||
# weak deps on : keep default behaviour, stated explicitly so it is greppable
|
# weak deps on : keep default behaviour, stated explicitly so it is greppable
|
||||||
sudo dnf install -y --setopt=install_weak_deps=True "$@"
|
ui_quiet_run "Installing: $*" \
|
||||||
|
sudo dnf install -y --setopt=install_weak_deps=True "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Same, but a missing/renamed package warns instead of aborting the whole run.
|
# Same, but a missing/renamed package warns instead of aborting the whole run.
|
||||||
# Use for anything that is a nice-to-have rather than load-bearing.
|
# Use for anything that is a nice-to-have rather than load-bearing.
|
||||||
install_optional() {
|
install_optional() {
|
||||||
sudo dnf install -y --setopt=install_weak_deps=True "$@" \
|
ui_quiet_run "Installing (optional): $*" \
|
||||||
|
sudo dnf install -y --setopt=install_weak_deps=True "$@" \
|
||||||
|| warn "Optional packages not installed: $*"
|
|| warn "Optional packages not installed: $*"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,8 +158,8 @@ remove_packages() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ ${#packages_to_remove[@]} -gt 0 ]; then
|
if [ ${#packages_to_remove[@]} -gt 0 ]; then
|
||||||
info "Removing packages: ${packages_to_remove[*]}"
|
ui_quiet_run "Removing: ${packages_to_remove[*]}" \
|
||||||
sudo dnf remove -y "${packages_to_remove[@]}"
|
sudo dnf remove -y "${packages_to_remove[@]}"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +173,7 @@ install_group() {
|
|||||||
dnf group list --hidden 2>/dev/null | sed 's/^/ /' >&2 || true
|
dnf group list --hidden 2>/dev/null | sed 's/^/ /' >&2 || true
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
sudo dnf group install -y "$group"
|
ui_quiet_run "Installing group: @$group" sudo dnf group install -y "$group"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Try each candidate group/environment in turn; first one that exists wins.
|
# Try each candidate group/environment in turn; first one that exists wins.
|
||||||
@@ -138,7 +182,7 @@ install_group_any() {
|
|||||||
for g in "$@"; do
|
for g in "$@"; do
|
||||||
if dnf group info "$g" >/dev/null 2>&1; then
|
if dnf group info "$g" >/dev/null 2>&1; then
|
||||||
info "Using dnf group: @$g"
|
info "Using dnf group: @$g"
|
||||||
sudo dnf group install -y "$g"
|
ui_quiet_run "Installing group: @$g" sudo dnf group install -y "$g"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -16,16 +16,7 @@ if [[ -n "${_SB_UI_LOADED:-}" ]]; then
|
|||||||
fi
|
fi
|
||||||
_SB_UI_LOADED=1
|
_SB_UI_LOADED=1
|
||||||
|
|
||||||
have_gum() {
|
# have_gum lives in lib/common.sh (install_packages needs it too).
|
||||||
command -v gum >/dev/null 2>&1 || return 1
|
|
||||||
# stdin must be interactive — it is inherited by $(...) subshells, so
|
|
||||||
# menus still get the real terminal. stdout must NOT be checked: it is
|
|
||||||
# a pipe by definition inside $(ui_choose ...). gum draws its UI on
|
|
||||||
# /dev/tty and prints only the answer to stdout (which we capture).
|
|
||||||
[ -t 0 ] || return 1
|
|
||||||
[ -w /dev/tty ] || return 1
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Single choice from a list.
|
# Single choice from a list.
|
||||||
# ui_choose "<header>" "<prompt>" "<default>" item1 item2 ...
|
# ui_choose "<header>" "<prompt>" "<default>" item1 item2 ...
|
||||||
@@ -62,7 +53,8 @@ ui_choose() {
|
|||||||
local n=${#items[@]} answer
|
local n=${#items[@]} answer
|
||||||
while true; do
|
while true; do
|
||||||
if ! read -t 90 -rp "$prompt [1-$n] (default: shown above): " answer; then
|
if ! read -t 90 -rp "$prompt [1-$n] (default: shown above): " answer; then
|
||||||
printf "\n"; answer=""
|
printf "\n" >&2
|
||||||
|
answer=""
|
||||||
fi
|
fi
|
||||||
# empty/timeout -> the default item (its position in the list)
|
# empty/timeout -> the default item (its position in the list)
|
||||||
if [[ -z "$answer" ]]; then
|
if [[ -z "$answer" ]]; then
|
||||||
@@ -74,6 +66,10 @@ ui_choose() {
|
|||||||
echo "${items[-1]}"
|
echo "${items[-1]}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
if [[ "${answer,,}" == "x" ]]; then
|
||||||
|
echo "$default"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
if [[ "$answer" =~ ^[0-9]+$ ]] && (( answer >= 1 && answer <= n )); then
|
if [[ "$answer" =~ ^[0-9]+$ ]] && (( answer >= 1 && answer <= n )); then
|
||||||
echo "${items[$((answer-1))]}"
|
echo "${items[$((answer-1))]}"
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ source "$SCRIPT_DIR/lib/session.sh"
|
|||||||
# shellcheck source=lib/ui.sh
|
# shellcheck source=lib/ui.sh
|
||||||
source "$SCRIPT_DIR/lib/ui.sh"
|
source "$SCRIPT_DIR/lib/ui.sh"
|
||||||
|
|
||||||
|
# Full dnf output from quiet transactions lands here (shown on failure).
|
||||||
|
export SETUP_DNF_LOG="${SETUP_DNF_LOG:-/tmp/fedora-setup-dnf-$(id -u).log}"
|
||||||
|
: >> "$SETUP_DNF_LOG"
|
||||||
|
|
||||||
#------------------------------------------
|
#------------------------------------------
|
||||||
# Defaults + argument parsing
|
# Defaults + argument parsing
|
||||||
# DEBUG_MODE must be initialised before anything reads it under set -u.
|
# DEBUG_MODE must be initialised before anything reads it under set -u.
|
||||||
@@ -185,8 +189,8 @@ fi
|
|||||||
info "Ensuring Flathub is available (system-wide)..."
|
info "Ensuring Flathub is available (system-wide)..."
|
||||||
sudo flatpak remote-add --if-not-exists --system flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
sudo flatpak remote-add --if-not-exists --system flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||||
|
|
||||||
# Update the system (spinner when gum is present; output shown on failure)
|
# Update the system (spinner + one-line summary; full output in $SETUP_DNF_LOG)
|
||||||
ui_run "Updating the system" sudo dnf update -y
|
ui_quiet_run "Updating the system" sudo dnf update -y
|
||||||
pause_if_debug
|
pause_if_debug
|
||||||
|
|
||||||
#------------------------------------------
|
#------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user