Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions core/core.func
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,26 @@ stop_spinner() {
stty sane 2>/dev/null || true
}

# A helper opening its own block (setup_uv, setup_nodejs) stopped the outer
# one's spinner and nothing brought it back.
declare -ga _MSG_BLOCKS=()

_msg_block_resume() {
((${#_MSG_BLOCKS[@]})) || return 0
SPINNER_MSG="${_MSG_BLOCKS[-1]}"

if is_verbose_mode || is_alpine; then
printf "\r\e[2K%s %b" "${TAB}⏳${TAB}" "${YW}${SPINNER_MSG}${CL}" >&2
return 0
fi

color_spinner
spinner &
SPINNER_PID=$!
echo "$SPINNER_PID" >/tmp/.spinner.pid
disown "$SPINNER_PID" 2>/dev/null || true
}

# ------------------------------------------------------------------------------
# _cs_os_family()
#
Expand Down Expand Up @@ -1151,7 +1171,10 @@ msg_info() {
fi
local sanitized_key
sanitized_key=$(printf '%s' "$msg" | sed 's/\x1b\[[0-9;]*m//g; s/[^a-zA-Z0-9_]/_/g')
[[ -n "${MSG_INFO_SHOWN["$sanitized_key"]+x}" ]] && return
if [[ -n "${MSG_INFO_SHOWN["$sanitized_key"]+x}" ]]; then
_MSG_BLOCKS+=("$msg")
return
fi
MSG_INFO_SHOWN["$sanitized_key"]=1

_dev_step_start "$msg"
Expand All @@ -1161,6 +1184,7 @@ msg_info() {

stop_spinner
SPINNER_MSG="$msg"
_MSG_BLOCKS+=("$msg")

if is_verbose_mode || is_alpine; then
local HOURGLASS="${TAB}⏳${TAB}"
Expand Down Expand Up @@ -1200,12 +1224,14 @@ msg_ok() {
local msg="$1"
[[ -z "$msg" ]] && return
stop_spinner
((${#_MSG_BLOCKS[@]})) && unset '_MSG_BLOCKS[-1]'
clear_line
echo -e "$CM${GN}${msg}${CL}$(_dev_step_end "$msg")"
log_msg "[OK] $msg"
local sanitized_key
sanitized_key=$(printf '%s' "$msg" | sed 's/\x1b\[[0-9;]*m//g; s/[^a-zA-Z0-9_]/_/g')
unset 'MSG_INFO_SHOWN['"$sanitized_key"']' 2>/dev/null || true
_msg_block_resume
}

# ------------------------------------------------------------------------------
Expand All @@ -1218,6 +1244,7 @@ msg_ok() {
# ------------------------------------------------------------------------------
msg_error() {
stop_spinner
_MSG_BLOCKS=()
local msg="$1"
echo -e "${BFR:-}${CROSS:-✖️}${RD}${msg}${CL}" >&2
log_msg "[ERROR] $msg"
Expand All @@ -1233,6 +1260,7 @@ msg_error() {
# ------------------------------------------------------------------------------
msg_warn() {
stop_spinner
_MSG_BLOCKS=()
local msg="$1"
echo -e "${BFR:-}${INFO:-ℹ️} ${YWB}${msg}${CL}" >&2
log_msg "[WARN] $msg"
Expand All @@ -1255,6 +1283,7 @@ msg_custom() {
# Align with CM/CROSS: TAB + icon + TAB + message (not a single leading space).
echo -e "${BFR:-}${TAB:- }${symbol}${TAB:- }${color}${msg}${CL:-\e[0m}"
log_msg "$msg"
_msg_block_resume
}

# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -2043,6 +2072,16 @@ prompt_select() {
# # Require user input (no default)
# db_pass=$(prompt_password "Database password:" "" 60 12)
# ------------------------------------------------------------------------------
# random_password [length] - alphanumeric, because base64 carries / and +.
# Reads a fixed chunk rather than piping urandom into head, which SIGPIPEs.
random_password() {
local len="${1:-24}" out=""
while ((${#out} < len)); do
out+="$(LC_ALL=C tr -dc 'A-Za-z0-9' < <(head -c 256 /dev/urandom))"
done
printf '%s' "${out:0:len}"
}

prompt_password() {
local message="${1:-Enter password:}"
local default="${2:-}"
Expand Down Expand Up @@ -2248,7 +2287,7 @@ check_or_create_swap() {
msg_error "No active swap detected"

if ! prompt_confirm "Do you want to create a swap file?" "n" 60; then
msg_info "Skipping swap file creation"
msg_custom "ℹ️" "${YW}" "Skipping swap file creation"
return 1
fi

Expand Down
1 change: 1 addition & 0 deletions lib/API.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ _cs_apt_install_optional
_cs_clean_target_dir
_cs_drop_pm_shim
_cs_repair_dpkg
_cs_write_cargo_net
_cs_write_cargo_profile
_deploy_source_tarball
_deploy_unpacked_archive
Expand Down
4 changes: 2 additions & 2 deletions lib/alpine.func
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 +337,14 @@ check_for_gh_release() {
msg_ok "$app pinned v$pinned installed (upstream v$release)"
return 1
fi
msg_info "$app pinned v$pinned (upstream v$release) → update/downgrade"
msg_ok "$app pinned v$pinned (upstream v$release) → update/downgrade"
CHECK_UPDATE_RELEASE="$pinned"
return 0
fi

if [ "$release" != "$current" ] || [ ! -f "$current_file" ]; then
CHECK_UPDATE_RELEASE="$release"
msg_info "New release available: v$release (current: v${current:-none})"
msg_ok "New release available: v$release (current: v${current:-none})"
return 0
fi

Expand Down
7 changes: 4 additions & 3 deletions lib/db.func
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ EOF
local HAD_MARIADB_REPO=false
if [[ -f /etc/apt/sources.list.d/mariadb.sources ]] || [[ -f /etc/apt/sources.list.d/mariadb.list ]]; then
HAD_MARIADB_REPO=true
msg_info "Removing MariaDB official repository (switching to distribution packages)"
msg_custom "ℹ️" "${YW}" "Removing MariaDB official repository (switching to distribution packages)"
fi

# Clean up any existing MariaDB repository files to avoid conflicts
Expand Down Expand Up @@ -250,7 +250,7 @@ EOF

# Check if old repo points to a different version
if [[ -n "$OLD_REPO_VERSION" ]] && [[ "${OLD_REPO_VERSION%.*}" != "${MARIADB_VERSION%.*}" ]]; then
msg_info "Cleaning up old MariaDB repository (was: $OLD_REPO_VERSION, requested: $MARIADB_VERSION)"
msg_custom "ℹ️" "${YW}" "Cleaning up old MariaDB repository (was: $OLD_REPO_VERSION, requested: $MARIADB_VERSION)"
cleanup_old_repo_files "mariadb"
$STD apt update || msg_warn "APT update had issues, continuing..."
fi
Expand Down Expand Up @@ -570,7 +570,7 @@ setup_meilisearch() {
local NEEDS_MIGRATION=false
if [[ "$CURRENT_MAJOR_MINOR" != "$NEW_MAJOR_MINOR" ]]; then
NEEDS_MIGRATION=true
msg_info "MeiliSearch version change detected (${CURRENT_VERSION} → ${NEW_VERSION}), preparing data migration"
msg_custom "ℹ️" "${YW}" "MeiliSearch version change detected (${CURRENT_VERSION} → ${NEW_VERSION}), preparing data migration"
fi

# Read connection + storage paths for the in-place (dumpless) upgrade
Expand Down Expand Up @@ -1258,6 +1258,7 @@ setup_postgresql() {
msg_error "Failed to backup PostgreSQL databases"
return 150
}
msg_ok "Backed up PostgreSQL ${CURRENT_PG_VERSION} databases to ${PG_BACKUP_FILE}"
$STD systemctl stop postgresql || true
$STD apt purge -y "postgresql-${CURRENT_PG_VERSION}" "postgresql-client-${CURRENT_PG_VERSION}" 2>/dev/null || true
else
Expand Down
45 changes: 37 additions & 8 deletions lib/forge.func
Original file line number Diff line number Diff line change
Expand Up @@ -470,21 +470,45 @@ _download_source_tarball() {
# directory" for entries deleted on purpose. A file rather than an array,
# because node_modules reaches tens of thousands of paths.
_cs_clean_target_dir() {
local dir="${1:?directory}" list
local dir="${1:?directory}" list entry stash=""
[[ -d "$dir" ]] || return 0
dir="${dir%/}"

# Moved aside rather than pruned from find: a kept path can be nested, and
# removing its parent would take it along. mv also keeps a symlink a symlink.
local -a keep=()
[[ -n "${CLEAN_INSTALL_KEEP:-}" ]] && read -ra keep <<<"$CLEAN_INSTALL_KEEP"
if ((${#keep[@]})); then
stash="$(mktemp -d -p "$(dirname "$dir")" .clean-keep.XXXXXX)" || return 1
for entry in "${keep[@]}"; do
entry="${entry#/}"
[[ -n "$entry" && -e "$dir/$entry" ]] || continue
mkdir -p "$stash/$(dirname "$entry")"
mv "$dir/$entry" "$stash/$entry" || msg_warn "Could not preserve ${entry}"
done
fi

# mountpoint lives in util-linux, which a minimal Alpine may not have. Without
# it the -exec below would fail once per directory, and there is nothing to
# protect anyway -- so drop the top-level entries and let rm recurse.
if ! command -v mountpoint >/dev/null 2>&1; then
find "${dir:?}" -mindepth 1 -maxdepth 1 -print0 | xargs -0 rm -rf --
return 0
else
list="$(mktemp)" || return 1
find "${dir:?}" -mindepth 1 \( -type d -exec mountpoint -q {} \; -prune \) -o -print0 >"$list"
xargs -0 rm -rf -- <"$list"
rm -f "$list"
fi

if [[ -n "$stash" ]]; then
for entry in "${keep[@]}"; do
entry="${entry#/}"
[[ -n "$entry" && -e "$stash/$entry" ]] || continue
mkdir -p "$dir/$(dirname "$entry")"
mv "$stash/$entry" "$dir/$entry" || msg_warn "Could not restore ${entry}"
done
rm -rf "$stash"
fi

list="$(mktemp)" || return 1
find "${dir:?}" -mindepth 1 \( -type d -exec mountpoint -q {} \; -prune \) -o -print0 >"$list"
xargs -0 rm -rf -- <"$list"
rm -f "$list"
}

# ------------------------------------------------------------------------------
Expand All @@ -498,6 +522,8 @@ _cs_clean_target_dir() {
# - Honors CLEAN_INSTALL=1 (wipes <target> first, dotfiles included, mount
# points preserved — back up config dotfiles like .env via create_backup
# and call restore_backup BEFORE any build step that sources them).
# - Honors CLEAN_INSTALL_KEEP, a space-separated list of paths relative to
# <target> that the wipe leaves alone (e.g. "geodata .env data/uploads").
# - Does NOT own <workdir>: the caller creates it and is responsible for its
# cleanup (typically via a RETURN trap on its tmpdir).
# - cp failures are non-fatal here, matching the previous inline behavior.
Expand Down Expand Up @@ -543,6 +569,8 @@ _deploy_source_tarball() {
# - Honors CLEAN_INSTALL=1 (wipes <target> first, dotfiles included, mount
# points preserved — back up config dotfiles like .env via create_backup
# and call restore_backup BEFORE any build step that sources them).
# - Honors CLEAN_INSTALL_KEEP, a space-separated list of paths relative to
# <target> that the wipe leaves alone (e.g. "geodata .env data/uploads").
# - Does NOT own <workdir>: the caller creates it and cleans it up.
#
# Returns: 0 on success, 65 on unsupported format, 251 on extraction failure,
Expand Down Expand Up @@ -2222,6 +2250,7 @@ fetch_and_deploy_from_url() {
msg_error "Download failed: $url"
return 250
}
msg_ok "Downloaded ${filename}"

# Auto-detect archive type using file description
local file_desc
Expand All @@ -2248,7 +2277,7 @@ fetch_and_deploy_from_url() {
return 65
fi

msg_info "Detected archive type: $archive_type (file type: $file_desc)"
debug_log "Detected archive type: $archive_type (file type: $file_desc)"

if [[ "$archive_type" == "deb" ]]; then
msg_info "Installing .deb package"
Expand Down
19 changes: 11 additions & 8 deletions lib/hwaccel.func
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ setup_hwaccel() {
selection="${selection^^}" # uppercase
else
echo ""
msg_info "Timeout - configuring all GPUs automatically"
msg_custom "ℹ️" "${YW}" "Timeout - configuring all GPUs automatically"
selection="A"
fi

Expand Down Expand Up @@ -391,7 +391,7 @@ _setup_intel_arc() {
# For Trixie/Sid: Fetch latest drivers from GitHub (Debian repo packages may be too old or missing)
# For Bookworm: Use repo packages (GitHub latest requires libstdc++6 >= 13.1, unavailable on Bookworm)
if [[ "$os_codename" == "trixie" || "$os_codename" == "sid" ]]; then
msg_info "Fetching Intel compute-runtime from GitHub for Arc support"
msg_custom "ℹ️" "${YW}" "Fetching Intel compute-runtime from GitHub for Arc support"

# intel-opencl-icd declares it; dpkg refuses the package without it.
_cs_apt_install_optional ocl-icd-libopencl1
Expand Down Expand Up @@ -449,7 +449,7 @@ _setup_intel_modern() {

# For Trixie/Sid: Fetch from GitHub (Debian packages too old or missing)
if [[ "$os_codename" == "trixie" || "$os_codename" == "sid" ]]; then
msg_info "Fetching Intel compute-runtime from GitHub"
msg_custom "ℹ️" "${YW}" "Fetching Intel compute-runtime from GitHub"

# intel-opencl-icd declares it; dpkg refuses the package without it.
_cs_apt_install_optional ocl-icd-libopencl1
Expand Down Expand Up @@ -684,7 +684,7 @@ _setup_nvidia_gpu() {
return 0
fi

msg_info "Host NVIDIA driver version: ${nvidia_host_version}"
msg_custom "ℹ️" "${YW}" "Host NVIDIA driver version: ${nvidia_host_version}"

if [[ "$os_id" == "debian" ]]; then
# Enable non-free components
Expand Down Expand Up @@ -728,6 +728,7 @@ _setup_nvidia_gpu() {
cuda_keyring="$(mktemp)"
if curl -fsSL -o "$cuda_keyring" "https://developer.download.nvidia.com/compute/cuda/repos/${cuda_repos[0]}/x86_64/cuda-keyring_1.1-1_all.deb" 2>/dev/null; then
$STD dpkg -i "$cuda_keyring" 2>/dev/null || true
msg_ok "Added NVIDIA CUDA repository keyring"
else
msg_warn "Failed to download NVIDIA CUDA keyring"
fi
Expand Down Expand Up @@ -842,6 +843,7 @@ NVIDIA_PIN
cuda_keyring="$(mktemp)"
if curl -fsSL -o "$cuda_keyring" "https://developer.download.nvidia.com/compute/cuda/repos/${ubuntu_cuda_repo}/x86_64/cuda-keyring_1.1-1_all.deb" 2>/dev/null; then
$STD dpkg -i "$cuda_keyring" 2>/dev/null || true
msg_ok "Added NVIDIA CUDA repository (${ubuntu_cuda_repo})"
else
msg_warn "Failed to download NVIDIA CUDA keyring"
fi
Expand Down Expand Up @@ -900,7 +902,7 @@ NVIDIA_PIN
if command -v update-glx &>/dev/null; then
local nvidia_glx_dir="/usr/lib/nvidia"
if [[ ! -f "${nvidia_glx_dir}/libGL.so.1" ]] && [[ -d /usr/lib/mesa-diverted ]]; then
msg_info "NVIDIA GLX libs missing in container - falling back to mesa"
msg_custom "ℹ️" "${YW}" "NVIDIA GLX libs missing in container - falling back to mesa"
$STD update-glx --set glx /usr/lib/mesa-diverted 2>/dev/null || true
ldconfig 2>/dev/null || true
fi
Expand Down Expand Up @@ -1083,7 +1085,7 @@ _setup_gpu_permissions() {
# Verify VA-API
if command -v vainfo &>/dev/null; then
if vainfo &>/dev/null; then
msg_info "VA-API verified and working"
msg_custom "✔️" "${GN}" "VA-API verified and working"
else
msg_warn "vainfo test failed - check GPU passthrough"
fi
Expand All @@ -1109,11 +1111,12 @@ _setup_gpu_permissions() {
}
done
fi
msg_ok "Configured NVIDIA device permissions"

# Verify nvidia-smi
if command -v nvidia-smi &>/dev/null; then
if nvidia-smi &>/dev/null; then
msg_info "nvidia-smi verified and working"
msg_custom "✔️" "${GN}" "nvidia-smi verified and working"
else
msg_warn "nvidia-smi test failed - check driver version match"
fi
Expand All @@ -1124,7 +1127,7 @@ _setup_gpu_permissions() {
if [[ -e /dev/kfd ]]; then
chgrp render /dev/kfd 2>/dev/null || true
chmod 660 /dev/kfd 2>/dev/null || true
msg_info "AMD ROCm compute device configured"
msg_custom "✔️" "${GN}" "AMD ROCm compute device configured"
fi

# Add service user to render and video groups for GPU hardware acceleration
Expand Down
Loading
Loading