merge from VE
This commit is contained in:
parent
7ec74ce70a
commit
699a3b3a8c
333
misc/tools.func
333
misc/tools.func
@ -72,15 +72,19 @@ stop_all_services() {
|
|||||||
local service_patterns=("$@")
|
local service_patterns=("$@")
|
||||||
|
|
||||||
for pattern in "${service_patterns[@]}"; do
|
for pattern in "${service_patterns[@]}"; do
|
||||||
# Find all matching services
|
# Find all matching services (grep || true to handle no matches)
|
||||||
systemctl list-units --type=service --all 2>/dev/null |
|
local services
|
||||||
grep -oE "${pattern}[^ ]*\.service" |
|
services=$(systemctl list-units --type=service --all 2>/dev/null |
|
||||||
sort -u |
|
grep -oE "${pattern}[^ ]*\.service" 2>/dev/null | sort -u) || true
|
||||||
|
|
||||||
|
if [[ -n "$services" ]]; then
|
||||||
while read -r service; do
|
while read -r service; do
|
||||||
$STD systemctl stop "$service" 2>/dev/null || true
|
$STD systemctl stop "$service" 2>/dev/null || true
|
||||||
$STD systemctl disable "$service" 2>/dev/null || true
|
$STD systemctl disable "$service" 2>/dev/null || true
|
||||||
done
|
done <<<"$services"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@ -188,6 +192,8 @@ install_packages_with_retry() {
|
|||||||
if [[ $retry -le $max_retries ]]; then
|
if [[ $retry -le $max_retries ]]; then
|
||||||
msg_warn "Package installation failed, retrying ($retry/$max_retries)..."
|
msg_warn "Package installation failed, retrying ($retry/$max_retries)..."
|
||||||
sleep 2
|
sleep 2
|
||||||
|
# Fix any interrupted dpkg operations before retry
|
||||||
|
$STD dpkg --configure -a 2>/dev/null || true
|
||||||
$STD apt update 2>/dev/null || true
|
$STD apt update 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@ -213,6 +219,8 @@ upgrade_packages_with_retry() {
|
|||||||
if [[ $retry -le $max_retries ]]; then
|
if [[ $retry -le $max_retries ]]; then
|
||||||
msg_warn "Package upgrade failed, retrying ($retry/$max_retries)..."
|
msg_warn "Package upgrade failed, retrying ($retry/$max_retries)..."
|
||||||
sleep 2
|
sleep 2
|
||||||
|
# Fix any interrupted dpkg operations before retry
|
||||||
|
$STD dpkg --configure -a 2>/dev/null || true
|
||||||
$STD apt update 2>/dev/null || true
|
$STD apt update 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@ -1178,6 +1186,12 @@ cleanup_orphaned_sources() {
|
|||||||
# This should be called at the start of any setup function
|
# This should be called at the start of any setup function
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
ensure_apt_working() {
|
ensure_apt_working() {
|
||||||
|
# Fix interrupted dpkg operations first
|
||||||
|
# This can happen if a previous installation was interrupted (e.g., by script error)
|
||||||
|
if [[ -f /var/lib/dpkg/lock-frontend ]] || dpkg --audit 2>&1 | grep -q "interrupted"; then
|
||||||
|
$STD dpkg --configure -a 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
# Clean up orphaned sources first
|
# Clean up orphaned sources first
|
||||||
cleanup_orphaned_sources
|
cleanup_orphaned_sources
|
||||||
|
|
||||||
@ -1208,6 +1222,7 @@ setup_deb822_repo() {
|
|||||||
local suite="$4"
|
local suite="$4"
|
||||||
local component="${5:-main}"
|
local component="${5:-main}"
|
||||||
local architectures="${6-}" # optional
|
local architectures="${6-}" # optional
|
||||||
|
local enabled="${7-}" # optional: "true" or "false"
|
||||||
|
|
||||||
# Validate required parameters
|
# Validate required parameters
|
||||||
if [[ -z "$name" || -z "$gpg_url" || -z "$repo_url" || -z "$suite" ]]; then
|
if [[ -z "$name" || -z "$gpg_url" || -z "$repo_url" || -z "$suite" ]]; then
|
||||||
@ -1235,9 +1250,13 @@ setup_deb822_repo() {
|
|||||||
echo "Types: deb"
|
echo "Types: deb"
|
||||||
echo "URIs: $repo_url"
|
echo "URIs: $repo_url"
|
||||||
echo "Suites: $suite"
|
echo "Suites: $suite"
|
||||||
echo "Components: $component"
|
# Flat repositories (suite="./" or absolute path) must not have Components
|
||||||
|
if [[ "$suite" != "./" && -n "$component" ]]; then
|
||||||
|
echo "Components: $component"
|
||||||
|
fi
|
||||||
[[ -n "$architectures" ]] && echo "Architectures: $architectures"
|
[[ -n "$architectures" ]] && echo "Architectures: $architectures"
|
||||||
echo "Signed-By: /etc/apt/keyrings/${name}.gpg"
|
echo "Signed-By: /etc/apt/keyrings/${name}.gpg"
|
||||||
|
[[ -n "$enabled" ]] && echo "Enabled: $enabled"
|
||||||
} >/etc/apt/sources.list.d/${name}.sources
|
} >/etc/apt/sources.list.d/${name}.sources
|
||||||
|
|
||||||
$STD apt update
|
$STD apt update
|
||||||
@ -1439,15 +1458,32 @@ check_for_gh_release() {
|
|||||||
|
|
||||||
ensure_dependencies jq
|
ensure_dependencies jq
|
||||||
|
|
||||||
# Fetch releases and exclude drafts/prereleases
|
# Try /latest endpoint for non-pinned versions (most efficient)
|
||||||
local releases_json
|
local releases_json=""
|
||||||
releases_json=$(curl -fsSL --max-time 20 \
|
|
||||||
-H 'Accept: application/vnd.github+json' \
|
if [[ -z "$pinned_version_in" ]]; then
|
||||||
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
releases_json=$(curl -fsSL --max-time 20 \
|
||||||
"https://api.github.com/repos/${source}/releases") || {
|
-H 'Accept: application/vnd.github+json' \
|
||||||
msg_error "Unable to fetch releases for ${app}"
|
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
||||||
return 1
|
"https://api.github.com/repos/${source}/releases/latest" 2>/dev/null)
|
||||||
}
|
|
||||||
|
if [[ $? -eq 0 ]] && [[ -n "$releases_json" ]]; then
|
||||||
|
# Wrap single release in array for consistent processing
|
||||||
|
releases_json="[$releases_json]"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If no releases yet (pinned version OR /latest failed), fetch up to 100
|
||||||
|
if [[ -z "$releases_json" ]]; then
|
||||||
|
# Fetch releases and exclude drafts/prereleases
|
||||||
|
releases_json=$(curl -fsSL --max-time 20 \
|
||||||
|
-H 'Accept: application/vnd.github+json' \
|
||||||
|
-H 'X-GitHub-Api-Version: 2022-11-28' \
|
||||||
|
"https://api.github.com/repos/${source}/releases?per_page=100") || {
|
||||||
|
msg_error "Unable to fetch releases for ${app}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
mapfile -t raw_tags < <(jq -r '.[] | select(.draft==false and .prerelease==false) | .tag_name' <<<"$releases_json")
|
mapfile -t raw_tags < <(jq -r '.[] | select(.draft==false and .prerelease==false) | .tag_name' <<<"$releases_json")
|
||||||
if ((${#raw_tags[@]} == 0)); then
|
if ((${#raw_tags[@]} == 0)); then
|
||||||
@ -1721,12 +1757,13 @@ function fetch_and_deploy_gh_release() {
|
|||||||
|
|
||||||
### Tarball Mode ###
|
### Tarball Mode ###
|
||||||
if [[ "$mode" == "tarball" || "$mode" == "source" ]]; then
|
if [[ "$mode" == "tarball" || "$mode" == "source" ]]; then
|
||||||
url=$(echo "$json" | jq -r '.tarball_url // empty')
|
# GitHub API's tarball_url/zipball_url can return HTTP 300 Multiple Choices
|
||||||
[[ -z "$url" ]] && url="https://github.com/$repo/archive/refs/tags/v$version.tar.gz"
|
# when a branch and tag share the same name. Use explicit refs/tags/ URL instead.
|
||||||
|
local direct_tarball_url="https://github.com/$repo/archive/refs/tags/$tag_name.tar.gz"
|
||||||
filename="${app_lc}-${version}.tar.gz"
|
filename="${app_lc}-${version}.tar.gz"
|
||||||
|
|
||||||
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$url" || {
|
curl $download_timeout -fsSL -o "$tmpdir/$filename" "$direct_tarball_url" || {
|
||||||
msg_error "Download failed: $url"
|
msg_error "Download failed: $direct_tarball_url"
|
||||||
rm -rf "$tmpdir"
|
rm -rf "$tmpdir"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@ -2548,93 +2585,200 @@ function setup_hwaccel() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Detect GPU vendor (Intel, AMD, NVIDIA)
|
# Detect GPU vendor (Intel, AMD, NVIDIA)
|
||||||
local gpu_vendor
|
local gpu_vendor gpu_info
|
||||||
gpu_vendor=$(lspci 2>/dev/null | grep -Ei 'vga|3d|display' | grep -Eo 'Intel|AMD|NVIDIA' | head -n1 || echo "")
|
gpu_info=$(lspci 2>/dev/null | grep -Ei 'vga|3d|display' || echo "")
|
||||||
|
gpu_vendor=$(echo "$gpu_info" | grep -Eo 'Intel|AMD|NVIDIA' | head -n1 || echo "")
|
||||||
|
|
||||||
# Detect CPU vendor (relevant for AMD APUs)
|
# Detect CPU vendor (relevant for AMD APUs)
|
||||||
local cpu_vendor
|
local cpu_vendor
|
||||||
cpu_vendor=$(lscpu 2>/dev/null | grep -i 'Vendor ID' | awk '{print $3}' || echo "")
|
cpu_vendor=$(lscpu 2>/dev/null | grep -i 'Vendor ID' | awk '{print $3}' || echo "")
|
||||||
|
|
||||||
if [[ -z "$gpu_vendor" && -z "$cpu_vendor" ]]; then
|
if [[ -z "$gpu_vendor" && -z "$cpu_vendor" ]]; then
|
||||||
msg_error "No GPU or CPU vendor detected (missing lspci/lscpu output)"
|
msg_warn "No GPU or CPU vendor detected - skipping hardware acceleration setup"
|
||||||
return 1
|
msg_ok "Setup Hardware Acceleration (skipped - no GPU detected)"
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Detect OS with fallbacks
|
# Detect OS with fallbacks
|
||||||
local os_id os_codename
|
local os_id os_codename os_version
|
||||||
os_id=$(grep -oP '(?<=^ID=).+' /etc/os-release 2>/dev/null | tr -d '"' || grep '^ID=' /etc/os-release 2>/dev/null | cut -d'=' -f2 | tr -d '"' || echo "debian")
|
os_id=$(grep -oP '(?<=^ID=).+' /etc/os-release 2>/dev/null | tr -d '"' || echo "debian")
|
||||||
os_codename=$(grep -oP '(?<=^VERSION_CODENAME=).+' /etc/os-release 2>/dev/null | tr -d '"' || grep '^VERSION_CODENAME=' /etc/os-release 2>/dev/null | cut -d'=' -f2 | tr -d '"' || echo "unknown")
|
os_codename=$(grep -oP '(?<=^VERSION_CODENAME=).+' /etc/os-release 2>/dev/null | tr -d '"' || echo "unknown")
|
||||||
|
os_version=$(grep -oP '(?<=^VERSION_ID=).+' /etc/os-release 2>/dev/null | tr -d '"' || echo "")
|
||||||
|
|
||||||
# Validate os_id
|
[[ -z "$os_id" ]] && os_id="debian"
|
||||||
if [[ -z "$os_id" ]]; then
|
|
||||||
os_id="debian"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Determine if we are on a VM or LXC
|
# Determine if we are in a privileged LXC container
|
||||||
local in_ct="${CTTYPE:-0}"
|
local in_ct="${CTTYPE:-0}"
|
||||||
|
|
||||||
case "$gpu_vendor" in
|
case "$gpu_vendor" in
|
||||||
Intel)
|
Intel)
|
||||||
if [[ "$os_id" == "ubuntu" ]]; then
|
# Detect Intel GPU generation for driver selection
|
||||||
$STD apt -y install intel-opencl-icd || {
|
# Gen 9+ (Skylake and newer) benefit from non-free drivers
|
||||||
msg_error "Failed to install intel-opencl-icd"
|
local intel_gen=""
|
||||||
return 1
|
local needs_nonfree=false
|
||||||
}
|
|
||||||
else
|
# Check for specific Intel GPU models that need non-free drivers
|
||||||
# For Debian: fetch Intel GPU drivers from GitHub
|
if echo "$gpu_info" | grep -Ei 'HD Graphics [56][0-9]{2}|UHD Graphics|Iris|Arc|DG[12]' &>/dev/null; then
|
||||||
fetch_and_deploy_gh_release "" "intel/intel-graphics-compiler" "binary" "latest" "" "intel-igc-core-2_*_amd64.deb" || {
|
needs_nonfree=true
|
||||||
msg_warn "Failed to deploy Intel IGC core 2"
|
intel_gen="gen9+"
|
||||||
}
|
|
||||||
fetch_and_deploy_gh_release "" "intel/intel-graphics-compiler" "binary" "latest" "" "intel-igc-opencl-2_*_amd64.deb" || {
|
|
||||||
msg_warn "Failed to deploy Intel IGC OpenCL 2"
|
|
||||||
}
|
|
||||||
fetch_and_deploy_gh_release "" "intel/compute-runtime" "binary" "latest" "" "libigdgmm12_*_amd64.deb" || {
|
|
||||||
msg_warn "Failed to deploy Intel GDGMM12"
|
|
||||||
}
|
|
||||||
fetch_and_deploy_gh_release "" "intel/compute-runtime" "binary" "latest" "" "intel-opencl-icd_*_amd64.deb" || {
|
|
||||||
msg_warn "Failed to deploy Intel OpenCL ICD"
|
|
||||||
}
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$STD apt -y install va-driver-all ocl-icd-libopencl1 vainfo intel-gpu-tools || {
|
if [[ "$os_id" == "ubuntu" ]]; then
|
||||||
msg_error "Failed to install Intel GPU dependencies"
|
# Ubuntu: Use packages from Ubuntu repos
|
||||||
return 1
|
$STD apt -y install \
|
||||||
}
|
va-driver-all \
|
||||||
|
ocl-icd-libopencl1 \
|
||||||
|
intel-opencl-icd \
|
||||||
|
vainfo \
|
||||||
|
intel-gpu-tools || {
|
||||||
|
msg_error "Failed to install Intel GPU dependencies"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
# Try to install intel-media-va-driver for newer GPUs
|
||||||
|
$STD apt -y install intel-media-va-driver 2>/dev/null || true
|
||||||
|
|
||||||
|
elif [[ "$os_id" == "debian" ]]; then
|
||||||
|
# Debian: Check version and install appropriate drivers
|
||||||
|
if [[ "$needs_nonfree" == true ]]; then
|
||||||
|
# Add non-free repo for intel-media-va-driver-non-free
|
||||||
|
if [[ "$os_codename" == "bookworm" ]]; then
|
||||||
|
# Debian 12 Bookworm
|
||||||
|
if [[ ! -f /etc/apt/sources.list.d/non-free.list && ! -f /etc/apt/sources.list.d/non-free.sources ]]; then
|
||||||
|
cat <<EOF >/etc/apt/sources.list.d/non-free.sources
|
||||||
|
Types: deb
|
||||||
|
URIs: http://deb.debian.org/debian
|
||||||
|
Suites: bookworm bookworm-updates
|
||||||
|
Components: non-free non-free-firmware
|
||||||
|
EOF
|
||||||
|
$STD apt update
|
||||||
|
fi
|
||||||
|
$STD apt -y install \
|
||||||
|
intel-media-va-driver-non-free \
|
||||||
|
ocl-icd-libopencl1 \
|
||||||
|
intel-opencl-icd \
|
||||||
|
vainfo \
|
||||||
|
intel-gpu-tools || {
|
||||||
|
msg_warn "Non-free driver install failed, falling back to open drivers"
|
||||||
|
needs_nonfree=false
|
||||||
|
}
|
||||||
|
|
||||||
|
elif [[ "$os_codename" == "trixie" || "$os_codename" == "sid" ]]; then
|
||||||
|
# Debian 13 Trixie / Sid
|
||||||
|
if [[ ! -f /etc/apt/sources.list.d/non-free.sources ]]; then
|
||||||
|
cat <<'EOF' >/etc/apt/sources.list.d/non-free.sources
|
||||||
|
Types: deb
|
||||||
|
URIs: http://deb.debian.org/debian
|
||||||
|
Suites: trixie trixie-updates
|
||||||
|
Components: non-free non-free-firmware
|
||||||
|
|
||||||
|
Types: deb
|
||||||
|
URIs: http://deb.debian.org/debian-security
|
||||||
|
Suites: trixie-security
|
||||||
|
Components: non-free non-free-firmware
|
||||||
|
EOF
|
||||||
|
$STD apt update
|
||||||
|
fi
|
||||||
|
$STD apt -y install \
|
||||||
|
intel-media-va-driver-non-free \
|
||||||
|
ocl-icd-libopencl1 \
|
||||||
|
mesa-opencl-icd \
|
||||||
|
mesa-va-drivers \
|
||||||
|
libvpl2 \
|
||||||
|
vainfo \
|
||||||
|
intel-gpu-tools 2>/dev/null || {
|
||||||
|
msg_warn "Non-free driver install failed, falling back to open drivers"
|
||||||
|
needs_nonfree=false
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Fallback to open drivers or older Intel GPUs
|
||||||
|
if [[ "$needs_nonfree" == false ]]; then
|
||||||
|
# Fetch latest Intel drivers from GitHub for Debian
|
||||||
|
fetch_and_deploy_gh_release "" "intel/intel-graphics-compiler" "binary" "latest" "" "intel-igc-core-2_*_amd64.deb" || {
|
||||||
|
msg_warn "Failed to deploy Intel IGC core 2"
|
||||||
|
}
|
||||||
|
fetch_and_deploy_gh_release "" "intel/intel-graphics-compiler" "binary" "latest" "" "intel-igc-opencl-2_*_amd64.deb" || {
|
||||||
|
msg_warn "Failed to deploy Intel IGC OpenCL 2"
|
||||||
|
}
|
||||||
|
fetch_and_deploy_gh_release "" "intel/compute-runtime" "binary" "latest" "" "libigdgmm12_*_amd64.deb" || {
|
||||||
|
msg_warn "Failed to deploy Intel GDGMM12"
|
||||||
|
}
|
||||||
|
fetch_and_deploy_gh_release "" "intel/compute-runtime" "binary" "latest" "" "intel-opencl-icd_*_amd64.deb" || {
|
||||||
|
msg_warn "Failed to deploy Intel OpenCL ICD"
|
||||||
|
}
|
||||||
|
|
||||||
|
$STD apt -y install \
|
||||||
|
va-driver-all \
|
||||||
|
ocl-icd-libopencl1 \
|
||||||
|
mesa-opencl-icd \
|
||||||
|
mesa-va-drivers \
|
||||||
|
vainfo \
|
||||||
|
intel-gpu-tools || {
|
||||||
|
msg_error "Failed to install Intel GPU dependencies"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
AMD)
|
AMD)
|
||||||
$STD apt -y install mesa-va-drivers mesa-vdpau-drivers mesa-opencl-icd vainfo clinfo || {
|
$STD apt -y install \
|
||||||
|
mesa-va-drivers \
|
||||||
|
mesa-vdpau-drivers \
|
||||||
|
mesa-opencl-icd \
|
||||||
|
ocl-icd-libopencl1 \
|
||||||
|
vainfo \
|
||||||
|
clinfo 2>/dev/null || {
|
||||||
msg_error "Failed to install AMD GPU dependencies"
|
msg_error "Failed to install AMD GPU dependencies"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# For AMD CPUs without discrete GPU (APUs)
|
# AMD firmware for better GPU support
|
||||||
if [[ "$cpu_vendor" == "AuthenticAMD" && -n "$gpu_vendor" ]]; then
|
if [[ "$os_id" == "debian" ]]; then
|
||||||
$STD apt -y install libdrm-amdgpu1 firmware-amd-graphics || true
|
$STD apt -y install firmware-amd-graphics 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
$STD apt -y install libdrm-amdgpu1 2>/dev/null || true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
NVIDIA)
|
NVIDIA)
|
||||||
# NVIDIA needs manual driver setup - skip for now
|
# NVIDIA needs manual driver setup or passthrough from host
|
||||||
msg_info "NVIDIA GPU detected - manual driver setup required"
|
msg_warn "NVIDIA GPU detected - driver must be installed manually or passed through from host"
|
||||||
|
# Install basic VA-API support for potential hybrid setups
|
||||||
|
$STD apt -y install va-driver-all vainfo 2>/dev/null || true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
# If no discrete GPU, but AMD CPU (e.g., Ryzen APU)
|
# No discrete GPU detected - check for AMD APU
|
||||||
if [[ "$cpu_vendor" == "AuthenticAMD" ]]; then
|
if [[ "$cpu_vendor" == "AuthenticAMD" ]]; then
|
||||||
$STD apt -y install mesa-opencl-icd ocl-icd-libopencl1 clinfo || {
|
$STD apt -y install \
|
||||||
msg_error "Failed to install Mesa OpenCL stack"
|
mesa-va-drivers \
|
||||||
return 1
|
mesa-vdpau-drivers \
|
||||||
}
|
mesa-opencl-icd \
|
||||||
|
ocl-icd-libopencl1 \
|
||||||
|
vainfo 2>/dev/null || true
|
||||||
else
|
else
|
||||||
msg_warn "No supported GPU vendor detected - skipping GPU acceleration"
|
msg_warn "No supported GPU vendor detected - skipping GPU driver installation"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ -d /dev/dri ]]; then
|
# Set permissions for /dev/dri (only in privileged containers and if /dev/dri exists)
|
||||||
|
if [[ "$in_ct" == "0" && -d /dev/dri ]]; then
|
||||||
chgrp video /dev/dri 2>/dev/null || true
|
chgrp video /dev/dri 2>/dev/null || true
|
||||||
chmod 755 /dev/dri 2>/dev/null || true
|
chmod 755 /dev/dri 2>/dev/null || true
|
||||||
chmod 660 /dev/dri/* 2>/dev/null || true
|
chmod 660 /dev/dri/* 2>/dev/null || true
|
||||||
$STD adduser "$(id -u -n)" video
|
$STD adduser "$(id -u -n)" video 2>/dev/null || true
|
||||||
$STD adduser "$(id -u -n)" render
|
$STD adduser "$(id -u -n)" render 2>/dev/null || true
|
||||||
|
|
||||||
|
# Sync GID for video/render groups between host and container
|
||||||
|
local host_video_gid host_render_gid
|
||||||
|
host_video_gid=$(getent group video | cut -d: -f3)
|
||||||
|
host_render_gid=$(getent group render | cut -d: -f3)
|
||||||
|
if [[ -n "$host_video_gid" && -n "$host_render_gid" ]]; then
|
||||||
|
sed -i "s/^video:x:[0-9]*:/video:x:$host_video_gid:/" /etc/group 2>/dev/null || true
|
||||||
|
sed -i "s/^render:x:[0-9]*:/render:x:$host_render_gid:/" /etc/group 2>/dev/null || true
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cache_installed_version "hwaccel" "1.0"
|
cache_installed_version "hwaccel" "1.0"
|
||||||
@ -2780,12 +2924,19 @@ function setup_java() {
|
|||||||
INSTALLED_VERSION=$(dpkg -l 2>/dev/null | awk '/temurin-.*-jdk/{print $2}' | grep -oP 'temurin-\K[0-9]+' | head -n1 || echo "")
|
INSTALLED_VERSION=$(dpkg -l 2>/dev/null | awk '/temurin-.*-jdk/{print $2}' | grep -oP 'temurin-\K[0-9]+' | head -n1 || echo "")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Validate INSTALLED_VERSION is not empty if matched
|
# Validate INSTALLED_VERSION is not empty if JDK package found
|
||||||
local JDK_COUNT=0
|
local JDK_COUNT=0
|
||||||
JDK_COUNT=$(dpkg -l 2>/dev/null | grep -c "temurin-.*-jdk" || true)
|
JDK_COUNT=$(dpkg -l 2>/dev/null | grep -c "temurin-.*-jdk" || true)
|
||||||
if [[ -z "$INSTALLED_VERSION" && "${JDK_COUNT:-0}" -gt 0 ]]; then
|
if [[ -z "$INSTALLED_VERSION" && "${JDK_COUNT:-0}" -gt 0 ]]; then
|
||||||
msg_warn "Found Temurin JDK but cannot determine version"
|
msg_warn "Found Temurin JDK but cannot determine version - attempting reinstall"
|
||||||
INSTALLED_VERSION="0"
|
# Try to get actual package name for purge
|
||||||
|
local OLD_PACKAGE
|
||||||
|
OLD_PACKAGE=$(dpkg -l 2>/dev/null | awk '/temurin-.*-jdk/{print $2}' | head -n1 || echo "")
|
||||||
|
if [[ -n "$OLD_PACKAGE" ]]; then
|
||||||
|
msg_info "Removing existing package: $OLD_PACKAGE"
|
||||||
|
$STD apt purge -y "$OLD_PACKAGE" || true
|
||||||
|
fi
|
||||||
|
INSTALLED_VERSION="" # Reset to trigger fresh install
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Scenario 1: Already at correct version
|
# Scenario 1: Already at correct version
|
||||||
@ -3234,7 +3385,6 @@ function setup_mongodb() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Verify MongoDB was installed correctly
|
|
||||||
if ! command -v mongod >/dev/null 2>&1; then
|
if ! command -v mongod >/dev/null 2>&1; then
|
||||||
msg_error "MongoDB binary not found after installation"
|
msg_error "MongoDB binary not found after installation"
|
||||||
return 1
|
return 1
|
||||||
@ -3410,12 +3560,12 @@ EOF
|
|||||||
# - Optionally installs or updates global npm modules
|
# - Optionally installs or updates global npm modules
|
||||||
#
|
#
|
||||||
# Variables:
|
# Variables:
|
||||||
# NODE_VERSION - Node.js version to install (default: 22)
|
# NODE_VERSION - Node.js version to install (default: 24 LTS)
|
||||||
# NODE_MODULE - Comma-separated list of global modules (e.g. "yarn,@vue/cli@5.0.0")
|
# NODE_MODULE - Comma-separated list of global modules (e.g. "yarn,@vue/cli@5.0.0")
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
function setup_nodejs() {
|
function setup_nodejs() {
|
||||||
local NODE_VERSION="${NODE_VERSION:-22}"
|
local NODE_VERSION="${NODE_VERSION:-24}"
|
||||||
local NODE_MODULE="${NODE_MODULE:-}"
|
local NODE_MODULE="${NODE_MODULE:-}"
|
||||||
|
|
||||||
# ALWAYS clean up legacy installations first (nvm, etc.) to prevent conflicts
|
# ALWAYS clean up legacy installations first (nvm, etc.) to prevent conflicts
|
||||||
@ -3477,14 +3627,11 @@ function setup_nodejs() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# CRITICAL: Force APT cache refresh AFTER repository setup
|
# Force APT cache refresh after repository setup
|
||||||
# This ensures NodeSource is the only nodejs source in APT cache
|
|
||||||
$STD apt update
|
$STD apt update
|
||||||
|
|
||||||
# Install dependencies (NodeSource is now the only nodejs source)
|
|
||||||
ensure_dependencies curl ca-certificates gnupg
|
ensure_dependencies curl ca-certificates gnupg
|
||||||
|
|
||||||
# Install Node.js from NodeSource
|
|
||||||
install_packages_with_retry "nodejs" || {
|
install_packages_with_retry "nodejs" || {
|
||||||
msg_error "Failed to install Node.js ${NODE_VERSION} from NodeSource"
|
msg_error "Failed to install Node.js ${NODE_VERSION} from NodeSource"
|
||||||
return 1
|
return 1
|
||||||
@ -3635,7 +3782,7 @@ function setup_php() {
|
|||||||
local CURRENT_PHP=""
|
local CURRENT_PHP=""
|
||||||
CURRENT_PHP=$(is_tool_installed "php" 2>/dev/null) || true
|
CURRENT_PHP=$(is_tool_installed "php" 2>/dev/null) || true
|
||||||
|
|
||||||
# CRITICAL: If wrong version is installed, remove it FIRST before any pinning
|
# Remove conflicting PHP version before pinning
|
||||||
if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
|
if [[ -n "$CURRENT_PHP" && "$CURRENT_PHP" != "$PHP_VERSION" ]]; then
|
||||||
msg_info "Removing conflicting PHP ${CURRENT_PHP} (need ${PHP_VERSION})"
|
msg_info "Removing conflicting PHP ${CURRENT_PHP} (need ${PHP_VERSION})"
|
||||||
stop_all_services "php.*-fpm"
|
stop_all_services "php.*-fpm"
|
||||||
@ -3782,7 +3929,6 @@ EOF
|
|||||||
|
|
||||||
local INSTALLED_VERSION=$(php -v 2>/dev/null | awk '/^PHP/{print $2}' | cut -d. -f1,2)
|
local INSTALLED_VERSION=$(php -v 2>/dev/null | awk '/^PHP/{print $2}' | cut -d. -f1,2)
|
||||||
|
|
||||||
# Critical: if major.minor doesn't match, fail and cleanup
|
|
||||||
if [[ "$INSTALLED_VERSION" != "$PHP_VERSION" ]]; then
|
if [[ "$INSTALLED_VERSION" != "$PHP_VERSION" ]]; then
|
||||||
msg_error "PHP version mismatch: requested ${PHP_VERSION} but got ${INSTALLED_VERSION}"
|
msg_error "PHP version mismatch: requested ${PHP_VERSION} but got ${INSTALLED_VERSION}"
|
||||||
msg_error "This indicates a critical package installation issue"
|
msg_error "This indicates a critical package installation issue"
|
||||||
@ -3862,11 +4008,14 @@ function setup_postgresql() {
|
|||||||
local SUITE
|
local SUITE
|
||||||
case "$DISTRO_CODENAME" in
|
case "$DISTRO_CODENAME" in
|
||||||
trixie | forky | sid)
|
trixie | forky | sid)
|
||||||
|
|
||||||
if verify_repo_available "https://apt.postgresql.org/pub/repos/apt" "trixie-pgdg"; then
|
if verify_repo_available "https://apt.postgresql.org/pub/repos/apt" "trixie-pgdg"; then
|
||||||
SUITE="trixie-pgdg"
|
SUITE="trixie-pgdg"
|
||||||
|
|
||||||
else
|
else
|
||||||
SUITE="bookworm-pgdg"
|
SUITE="bookworm-pgdg"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
SUITE=$(get_fallback_suite "$DISTRO_ID" "$DISTRO_CODENAME" "https://apt.postgresql.org/pub/repos/apt")
|
SUITE=$(get_fallback_suite "$DISTRO_ID" "$DISTRO_CODENAME" "https://apt.postgresql.org/pub/repos/apt")
|
||||||
@ -4387,7 +4536,7 @@ function setup_rust() {
|
|||||||
# Get currently installed version
|
# Get currently installed version
|
||||||
local CURRENT_VERSION=""
|
local CURRENT_VERSION=""
|
||||||
if command -v rustc &>/dev/null; then
|
if command -v rustc &>/dev/null; then
|
||||||
CURRENT_VERSION=$(rustc --version 2>/dev/null | awk '{print $2}')
|
CURRENT_VERSION=$(rustc --version 2>/dev/null | awk '{print $2}' 2>/dev/null) || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Scenario 1: Rustup not installed - fresh install
|
# Scenario 1: Rustup not installed - fresh install
|
||||||
@ -4406,7 +4555,8 @@ function setup_rust() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local RUST_VERSION=$(rustc --version 2>/dev/null | awk '{print $2}')
|
local RUST_VERSION
|
||||||
|
RUST_VERSION=$(rustc --version 2>/dev/null | awk '{print $2}' 2>/dev/null) || true
|
||||||
if [[ -z "$RUST_VERSION" ]]; then
|
if [[ -z "$RUST_VERSION" ]]; then
|
||||||
msg_error "Failed to determine Rust version"
|
msg_error "Failed to determine Rust version"
|
||||||
return 1
|
return 1
|
||||||
@ -4437,7 +4587,8 @@ function setup_rust() {
|
|||||||
# Ensure PATH is updated for current shell session
|
# Ensure PATH is updated for current shell session
|
||||||
export PATH="$CARGO_BIN:$PATH"
|
export PATH="$CARGO_BIN:$PATH"
|
||||||
|
|
||||||
local RUST_VERSION=$(rustc --version 2>/dev/null | awk '{print $2}')
|
local RUST_VERSION
|
||||||
|
RUST_VERSION=$(rustc --version 2>/dev/null | awk '{print $2}' 2>/dev/null) || true
|
||||||
if [[ -z "$RUST_VERSION" ]]; then
|
if [[ -z "$RUST_VERSION" ]]; then
|
||||||
msg_error "Failed to determine Rust version after update"
|
msg_error "Failed to determine Rust version after update"
|
||||||
return 1
|
return 1
|
||||||
@ -4647,6 +4798,7 @@ function setup_uv() {
|
|||||||
if [[ -d /usr/share/zsh/site-functions ]]; then
|
if [[ -d /usr/share/zsh/site-functions ]]; then
|
||||||
$STD uv generate-shell-completion zsh >/usr/share/zsh/site-functions/_uv 2>/dev/null || true
|
$STD uv generate-shell-completion zsh >/usr/share/zsh/site-functions/_uv 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Optional: Install specific Python version if requested
|
# Optional: Install specific Python version if requested
|
||||||
if [[ -n "${PYTHON_VERSION:-}" ]]; then
|
if [[ -n "${PYTHON_VERSION:-}" ]]; then
|
||||||
msg_info "Installing Python $PYTHON_VERSION via uv"
|
msg_info "Installing Python $PYTHON_VERSION via uv"
|
||||||
@ -4805,6 +4957,7 @@ function setup_docker() {
|
|||||||
|
|
||||||
# Cleanup old repository configurations
|
# Cleanup old repository configurations
|
||||||
if [ -f /etc/apt/sources.list.d/docker.list ]; then
|
if [ -f /etc/apt/sources.list.d/docker.list ]; then
|
||||||
|
msg_info "Migrating from old Docker repository format"
|
||||||
rm -f /etc/apt/sources.list.d/docker.list
|
rm -f /etc/apt/sources.list.d/docker.list
|
||||||
rm -f /etc/apt/keyrings/docker.asc
|
rm -f /etc/apt/keyrings/docker.asc
|
||||||
fi
|
fi
|
||||||
@ -4818,7 +4971,6 @@ function setup_docker() {
|
|||||||
"$(get_os_info codename)" \
|
"$(get_os_info codename)" \
|
||||||
"stable" \
|
"stable" \
|
||||||
"$(dpkg --print-architecture)"
|
"$(dpkg --print-architecture)"
|
||||||
msg_ok "Set up Docker Repository"
|
|
||||||
|
|
||||||
# Install or upgrade Docker
|
# Install or upgrade Docker
|
||||||
if [ "$docker_installed" = true ]; then
|
if [ "$docker_installed" = true ]; then
|
||||||
@ -4826,8 +4978,7 @@ function setup_docker() {
|
|||||||
DOCKER_LATEST_VERSION=$(apt-cache policy docker-ce | grep Candidate | awk '{print $2}' | cut -d':' -f2 | cut -d'-' -f1)
|
DOCKER_LATEST_VERSION=$(apt-cache policy docker-ce | grep Candidate | awk '{print $2}' | cut -d':' -f2 | cut -d'-' -f1)
|
||||||
|
|
||||||
if [ "$DOCKER_CURRENT_VERSION" != "$DOCKER_LATEST_VERSION" ]; then
|
if [ "$DOCKER_CURRENT_VERSION" != "$DOCKER_LATEST_VERSION" ]; then
|
||||||
msg_ok "Docker update available ($DOCKER_CURRENT_VERSION → $DOCKER_LATEST_VERSION)"
|
msg_info "Updating Docker $DOCKER_CURRENT_VERSION → $DOCKER_LATEST_VERSION"
|
||||||
msg_info "Updating Docker"
|
|
||||||
$STD apt install -y --only-upgrade \
|
$STD apt install -y --only-upgrade \
|
||||||
docker-ce \
|
docker-ce \
|
||||||
docker-ce-cli \
|
docker-ce-cli \
|
||||||
@ -4873,8 +5024,7 @@ EOF
|
|||||||
PORTAINER_LATEST=$(curl -fsSL https://registry.hub.docker.com/v2/repositories/portainer/portainer-ce/tags?page_size=100 | grep -oP '"name":"\K[0-9]+\.[0-9]+\.[0-9]+"' | head -1 | tr -d '"')
|
PORTAINER_LATEST=$(curl -fsSL https://registry.hub.docker.com/v2/repositories/portainer/portainer-ce/tags?page_size=100 | grep -oP '"name":"\K[0-9]+\.[0-9]+\.[0-9]+"' | head -1 | tr -d '"')
|
||||||
|
|
||||||
if [ "$PORTAINER_CURRENT" != "$PORTAINER_LATEST" ]; then
|
if [ "$PORTAINER_CURRENT" != "$PORTAINER_LATEST" ]; then
|
||||||
msg_ok "Portainer update available ($PORTAINER_CURRENT → $PORTAINER_LATEST)"
|
read -r -p "${TAB3}Update Portainer $PORTAINER_CURRENT → $PORTAINER_LATEST? <y/N> " prompt
|
||||||
read -r -p "${TAB3}Update Portainer? <y/N> " prompt
|
|
||||||
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
|
if [[ ${prompt,,} =~ ^(y|yes)$ ]]; then
|
||||||
msg_info "Updating Portainer"
|
msg_info "Updating Portainer"
|
||||||
docker stop portainer
|
docker stop portainer
|
||||||
@ -4889,8 +5039,6 @@ EOF
|
|||||||
-v portainer_data:/data \
|
-v portainer_data:/data \
|
||||||
portainer/portainer-ce:latest
|
portainer/portainer-ce:latest
|
||||||
msg_ok "Updated Portainer to $PORTAINER_LATEST"
|
msg_ok "Updated Portainer to $PORTAINER_LATEST"
|
||||||
else
|
|
||||||
msg_ok "Skipped Portainer update"
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
msg_ok "Portainer is up-to-date ($PORTAINER_CURRENT)"
|
msg_ok "Portainer is up-to-date ($PORTAINER_CURRENT)"
|
||||||
@ -4938,7 +5086,6 @@ EOF
|
|||||||
done < <(docker ps --format '{{.Names}} {{.Image}}')
|
done < <(docker ps --format '{{.Names}} {{.Image}}')
|
||||||
|
|
||||||
if [ ${#containers_with_updates[@]} -gt 0 ]; then
|
if [ ${#containers_with_updates[@]} -gt 0 ]; then
|
||||||
msg_ok "Found ${#containers_with_updates[@]} container(s) with updates"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "${TAB3}Container updates available:"
|
echo "${TAB3}Container updates available:"
|
||||||
for info in "${container_info[@]}"; do
|
for info in "${container_info[@]}"; do
|
||||||
@ -4967,8 +5114,6 @@ EOF
|
|||||||
msg_ok "Stopped and removed $container (please recreate with updated image)"
|
msg_ok "Stopped and removed $container (please recreate with updated image)"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
else
|
|
||||||
msg_ok "Skipped container updates"
|
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
msg_ok "All containers are up-to-date"
|
msg_ok "All containers are up-to-date"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user