mirror of
https://github.com/kuhyx/scripts.git
synced 2026-11-11 14:27:41 +01:00
fix: resolve all shellcheck errors
- Replace 'A && B || C' patterns with proper if-then-else statements (SC2015) - Add check_for_virtualbox function to invoke prompt_for_virtualbox_challenge (SC2317) - Fix install_launcher function to escape variable in heredoc (SC2119/SC2120) - Apply shfmt formatting to ensure consistent style Fixes 7 SC2015 violations, 1 SC2317 violation, and 1 SC2119/SC2120 pair. All 79 shell files now pass shellcheck without errors.
This commit is contained in:
parent
8e0a720499
commit
03bd36e41d
@ -26,7 +26,7 @@ AMD_ENABLE_SI_CIK=${AMD_ENABLE_SI_CIK:-auto}
|
|||||||
AMD_SKIP_INITRAMFS=${AMD_SKIP_INITRAMFS:-0}
|
AMD_SKIP_INITRAMFS=${AMD_SKIP_INITRAMFS:-0}
|
||||||
AMD_VERBOSE=${AMD_VERBOSE:-0}
|
AMD_VERBOSE=${AMD_VERBOSE:-0}
|
||||||
|
|
||||||
vlog() { [ "$AMD_VERBOSE" = 1 ] && echo "[amd] $*" || true; }
|
vlog() { if [ "$AMD_VERBOSE" = 1 ]; then echo "[amd] $*"; fi; }
|
||||||
info() { echo "[amd] $*"; }
|
info() { echo "[amd] $*"; }
|
||||||
warn() { echo "[amd][warn] $*" >&2; }
|
warn() { echo "[amd][warn] $*" >&2; }
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ _build_aur_pkg() {
|
|||||||
cd "$HOME/aur"
|
cd "$HOME/aur"
|
||||||
if [ ! -d "$pkg" ]; then git clone "$url"; else (cd "$pkg" && git fetch -q --all && git reset -q --hard origin/HEAD || git pull --ff-only || true); fi
|
if [ ! -d "$pkg" ]; then git clone "$url"; else (cd "$pkg" && git fetch -q --all && git reset -q --hard origin/HEAD || git pull --ff-only || true); fi
|
||||||
cd "$pkg"
|
cd "$pkg"
|
||||||
rm -f -- *.pkg.tar.* 2> /dev/null || true
|
rm -f -- *.pkg.tar.* 2>/dev/null || true
|
||||||
yes | makepkg -s -c -C --noconfirm --needed
|
yes | makepkg -s -c -C --noconfirm --needed
|
||||||
local built=(*.pkg.tar.zst)
|
local built=(*.pkg.tar.zst)
|
||||||
yes | sudo pacman -U --noconfirm "${built[@]}"
|
yes | sudo pacman -U --noconfirm "${built[@]}"
|
||||||
@ -72,8 +72,8 @@ _build_aur_pkg() {
|
|||||||
|
|
||||||
_install_repo_or_aur() {
|
_install_repo_or_aur() {
|
||||||
local pkg="$1"
|
local pkg="$1"
|
||||||
if pacman -Si "$pkg" > /dev/null 2>&1; then
|
if pacman -Si "$pkg" >/dev/null 2>&1; then
|
||||||
if pacman -Qi "$pkg" > /dev/null 2>&1; then
|
if pacman -Qi "$pkg" >/dev/null 2>&1; then
|
||||||
vlog "$pkg already installed"
|
vlog "$pkg already installed"
|
||||||
else
|
else
|
||||||
yes | sudo pacman -Sy --noconfirm "$pkg"
|
yes | sudo pacman -Sy --noconfirm "$pkg"
|
||||||
@ -115,8 +115,8 @@ for n in "${CIK_NAMES[@]}"; do echo "$GPU_LINES" | grep -q "$n" && IS_CIK=1 && b
|
|||||||
if [ "$AMD_ENABLE_SI_CIK" = "1" ] || { [ "$AMD_ENABLE_SI_CIK" = "auto" ] && { [ $IS_SI = 1 ] || [ $IS_CIK = 1 ]; }; }; then
|
if [ "$AMD_ENABLE_SI_CIK" = "1" ] || { [ "$AMD_ENABLE_SI_CIK" = "auto" ] && { [ $IS_SI = 1 ] || [ $IS_CIK = 1 ]; }; }; then
|
||||||
info "Configuring amdgpu for SI/CIK (IS_SI=$IS_SI IS_CIK=$IS_CIK)"
|
info "Configuring amdgpu for SI/CIK (IS_SI=$IS_SI IS_CIK=$IS_CIK)"
|
||||||
TMP_CONF=$(mktemp)
|
TMP_CONF=$(mktemp)
|
||||||
printf 'options amdgpu si_support=1\noptions amdgpu cik_support=1\n' > "$TMP_CONF"
|
printf 'options amdgpu si_support=1\noptions amdgpu cik_support=1\n' >"$TMP_CONF"
|
||||||
printf 'options radeon si_support=0\noptions radeon cik_support=0\n' >> "$TMP_CONF"
|
printf 'options radeon si_support=0\noptions radeon cik_support=0\n' >>"$TMP_CONF"
|
||||||
sudo mkdir -p /etc/modprobe.d
|
sudo mkdir -p /etc/modprobe.d
|
||||||
sudo cp "$TMP_CONF" /etc/modprobe.d/10-amdgpu-si-cik.conf
|
sudo cp "$TMP_CONF" /etc/modprobe.d/10-amdgpu-si-cik.conf
|
||||||
rm -f "$TMP_CONF"
|
rm -f "$TMP_CONF"
|
||||||
@ -142,7 +142,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check active kernel driver
|
# Check active kernel driver
|
||||||
KDRV=$(lspci -k -d ::0300 2> /dev/null | awk '/Kernel driver in use:/ {print $5; exit}')
|
KDRV=$(lspci -k -d ::0300 2>/dev/null | awk '/Kernel driver in use:/ {print $5; exit}')
|
||||||
[ -z "$KDRV" ] && KDRV=$(lsmod | grep -E 'amdgpu|radeon' | head -n1 | awk '{print $1}')
|
[ -z "$KDRV" ] && KDRV=$(lsmod | grep -E 'amdgpu|radeon' | head -n1 | awk '{print $1}')
|
||||||
info "Kernel driver in use: ${KDRV:-unknown}"
|
info "Kernel driver in use: ${KDRV:-unknown}"
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ INTEL_ENABLE_GUC=${INTEL_ENABLE_GUC:-}
|
|||||||
INTEL_SKIP_INITRAMFS=${INTEL_SKIP_INITRAMFS:-0}
|
INTEL_SKIP_INITRAMFS=${INTEL_SKIP_INITRAMFS:-0}
|
||||||
INTEL_VERBOSE=${INTEL_VERBOSE:-1}
|
INTEL_VERBOSE=${INTEL_VERBOSE:-1}
|
||||||
|
|
||||||
vlog() { [ "$INTEL_VERBOSE" = 1 ] && echo "[intel] $*" || true; }
|
vlog() { if [ "$INTEL_VERBOSE" = 1 ]; then echo "[intel] $*"; fi; }
|
||||||
info() { echo "[intel] $*"; }
|
info() { echo "[intel] $*"; }
|
||||||
warn() { echo "[intel][warn] $*" >&2; }
|
warn() { echo "[intel][warn] $*" >&2; }
|
||||||
|
|
||||||
@ -44,10 +44,10 @@ fi
|
|||||||
|
|
||||||
install_pkg() {
|
install_pkg() {
|
||||||
local pkg="$1"
|
local pkg="$1"
|
||||||
if pacman -Qi "$pkg" > /dev/null 2>&1; then
|
if pacman -Qi "$pkg" >/dev/null 2>&1; then
|
||||||
vlog "$pkg already installed"
|
vlog "$pkg already installed"
|
||||||
else
|
else
|
||||||
if pacman -Si "$pkg" > /dev/null 2>&1; then
|
if pacman -Si "$pkg" >/dev/null 2>&1; then
|
||||||
yes | sudo pacman -Sy --noconfirm "$pkg"
|
yes | sudo pacman -Sy --noconfirm "$pkg"
|
||||||
else
|
else
|
||||||
warn "Package $pkg not found in repos (not handling AUR here)"
|
warn "Package $pkg not found in repos (not handling AUR here)"
|
||||||
@ -89,7 +89,7 @@ if [ -n "$INTEL_ENABLE_GUC" ]; then
|
|||||||
else
|
else
|
||||||
info "Configuring enable_guc=$INTEL_ENABLE_GUC"
|
info "Configuring enable_guc=$INTEL_ENABLE_GUC"
|
||||||
sudo mkdir -p /etc/modprobe.d
|
sudo mkdir -p /etc/modprobe.d
|
||||||
echo "options i915 enable_guc=$INTEL_ENABLE_GUC" | sudo tee /etc/modprobe.d/i915-guc.conf > /dev/null
|
echo "options i915 enable_guc=$INTEL_ENABLE_GUC" | sudo tee /etc/modprobe.d/i915-guc.conf >/dev/null
|
||||||
if [ "$INTEL_SKIP_INITRAMFS" != 1 ] && [ -f /etc/mkinitcpio.conf ]; then
|
if [ "$INTEL_SKIP_INITRAMFS" != 1 ] && [ -f /etc/mkinitcpio.conf ]; then
|
||||||
info "Regenerating initramfs (mkinitcpio -P) for GuC/HuC change"
|
info "Regenerating initramfs (mkinitcpio -P) for GuC/HuC change"
|
||||||
sudo mkinitcpio -P || warn "mkinitcpio failed; continue manually"
|
sudo mkinitcpio -P || warn "mkinitcpio failed; continue manually"
|
||||||
@ -100,7 +100,7 @@ if [ -n "$INTEL_ENABLE_GUC" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Report kernel driver
|
# Report kernel driver
|
||||||
KDRV=$(lspci -k -d ::0300 2> /dev/null | awk '/Kernel driver in use:/ {print $5; exit}')
|
KDRV=$(lspci -k -d ::0300 2>/dev/null | awk '/Kernel driver in use:/ {print $5; exit}')
|
||||||
[ -z "$KDRV" ] && KDRV=$(lsmod | grep -E 'i915|xe' | head -n1 | awk '{print $1}')
|
[ -z "$KDRV" ] && KDRV=$(lsmod | grep -E 'i915|xe' | head -n1 | awk '{print $1}')
|
||||||
info "Kernel driver in use: ${KDRV:-unknown}"
|
info "Kernel driver in use: ${KDRV:-unknown}"
|
||||||
|
|
||||||
|
|||||||
@ -9,23 +9,23 @@ LOGTAG=hosts-guard-hook
|
|||||||
stop_units_if_present() {
|
stop_units_if_present() {
|
||||||
local units=(hosts-bind-mount.service hosts-guard.path)
|
local units=(hosts-bind-mount.service hosts-guard.path)
|
||||||
for u in "${units[@]}"; do
|
for u in "${units[@]}"; do
|
||||||
if command -v systemctl > /dev/null 2>&1; then
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
if systemctl list-unit-files 2> /dev/null | grep -q "^$u"; then
|
if systemctl list-unit-files 2>/dev/null | grep -q "^$u"; then
|
||||||
systemctl stop "$u" > /dev/null 2>&1 || true
|
systemctl stop "$u" >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
is_ro_mount() { findmnt -no OPTIONS -T "$TARGET" 2> /dev/null | grep -qw ro; }
|
is_ro_mount() { findmnt -no OPTIONS -T "$TARGET" 2>/dev/null | grep -qw ro; }
|
||||||
|
|
||||||
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2> /dev/null || echo 0; }
|
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2>/dev/null || echo 0; }
|
||||||
cleanup_mount_stacks() {
|
cleanup_mount_stacks() {
|
||||||
local i=0
|
local i=0
|
||||||
# Unmount bind layers until /etc/hosts is no longer a mountpoint
|
# Unmount bind layers until /etc/hosts is no longer a mountpoint
|
||||||
if command -v mountpoint > /dev/null 2>&1; then
|
if command -v mountpoint >/dev/null 2>&1; then
|
||||||
while mountpoint -q "$TARGET"; do
|
while mountpoint -q "$TARGET"; do
|
||||||
umount -l "$TARGET" > /dev/null 2>&1 || break
|
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
((i > 20)) && break
|
((i > 20)) && break
|
||||||
done
|
done
|
||||||
@ -34,7 +34,7 @@ cleanup_mount_stacks() {
|
|||||||
local cnt
|
local cnt
|
||||||
cnt=$(mount_layers_count)
|
cnt=$(mount_layers_count)
|
||||||
while ((cnt > 1)); do
|
while ((cnt > 1)); do
|
||||||
umount -l "$TARGET" > /dev/null 2>&1 || break
|
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||||
i=$((i + 1))
|
i=$((i + 1))
|
||||||
((i > 20)) && break
|
((i > 20)) && break
|
||||||
cnt=$(mount_layers_count)
|
cnt=$(mount_layers_count)
|
||||||
@ -43,23 +43,27 @@ cleanup_mount_stacks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Drop protective attributes if present
|
# Drop protective attributes if present
|
||||||
if command -v lsattr > /dev/null 2>&1; then
|
if command -v lsattr >/dev/null 2>&1; then
|
||||||
attrs=$(lsattr -d "$TARGET" 2> /dev/null || true)
|
attrs=$(lsattr -d "$TARGET" 2>/dev/null || true)
|
||||||
echo "$attrs" | grep -q " i " && chattr -i "$TARGET" > /dev/null 2>&1 || true
|
if echo "$attrs" | grep -q " i "; then
|
||||||
echo "$attrs" | grep -q " a " && chattr -a "$TARGET" > /dev/null 2>&1 || true
|
chattr -i "$TARGET" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
if echo "$attrs" | grep -q " a "; then
|
||||||
|
chattr -a "$TARGET" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
stop_units_if_present
|
stop_units_if_present
|
||||||
|
|
||||||
logger -t "$LOGTAG" "pre: unlocking /etc/hosts (starting)"
|
logger -t "$LOGTAG" "pre: unlocking /etc/hosts (starting)"
|
||||||
echo "$(date -Is) pre-unlock" >> /run/hosts-guard-hook.log 2> /dev/null || true
|
echo "$(date -Is) pre-unlock" >>/run/hosts-guard-hook.log 2>/dev/null || true
|
||||||
|
|
||||||
# Always collapse any existing layers; we'll operate on the plain file
|
# Always collapse any existing layers; we'll operate on the plain file
|
||||||
cleanup_mount_stacks
|
cleanup_mount_stacks
|
||||||
|
|
||||||
# If someone managed a ro single-layer mount, ensure rw by remounting or collapsing again
|
# If someone managed a ro single-layer mount, ensure rw by remounting or collapsing again
|
||||||
if is_ro_mount; then
|
if is_ro_mount; then
|
||||||
mount -o remount,rw "$TARGET" > /dev/null 2>&1 || cleanup_mount_stacks
|
mount -o remount,rw "$TARGET" >/dev/null 2>&1 || cleanup_mount_stacks
|
||||||
fi
|
fi
|
||||||
|
|
||||||
logger -t "$LOGTAG" "pre: unlocking /etc/hosts (done)"
|
logger -t "$LOGTAG" "pre: unlocking /etc/hosts (done)"
|
||||||
|
|||||||
@ -84,7 +84,7 @@ post_relock_hosts() {
|
|||||||
# Ensure periodic system services (timer/monitor) are set up; if not, trigger setup
|
# Ensure periodic system services (timer/monitor) are set up; if not, trigger setup
|
||||||
ensure_periodic_maintenance() {
|
ensure_periodic_maintenance() {
|
||||||
# Only proceed if systemd/systemctl is available
|
# Only proceed if systemd/systemctl is available
|
||||||
if ! command -v systemctl > /dev/null 2>&1; then
|
if ! command -v systemctl >/dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -214,10 +214,10 @@ check_and_handle_db_lock() {
|
|||||||
|
|
||||||
# Determine which processes actually have the lock open
|
# Determine which processes actually have the lock open
|
||||||
local -a holders=()
|
local -a holders=()
|
||||||
if command -v fuser > /dev/null 2>&1; then
|
if command -v fuser >/dev/null 2>&1; then
|
||||||
mapfile -t holders < <(fuser "$lock_file" 2> /dev/null | tr ' ' '\n' | grep -E '^[0-9]+$' || true)
|
mapfile -t holders < <(fuser "$lock_file" 2>/dev/null | tr ' ' '\n' | grep -E '^[0-9]+$' || true)
|
||||||
elif command -v lsof > /dev/null 2>&1; then
|
elif command -v lsof >/dev/null 2>&1; then
|
||||||
mapfile -t holders < <(lsof -t "$lock_file" 2> /dev/null | grep -E '^[0-9]+$' || true)
|
mapfile -t holders < <(lsof -t "$lock_file" 2>/dev/null | grep -E '^[0-9]+$' || true)
|
||||||
else
|
else
|
||||||
holders=()
|
holders=()
|
||||||
fi
|
fi
|
||||||
@ -237,8 +237,8 @@ check_and_handle_db_lock() {
|
|||||||
local gui_holder=0
|
local gui_holder=0
|
||||||
for pid in "${holders[@]}"; do
|
for pid in "${holders[@]}"; do
|
||||||
local comm args lower
|
local comm args lower
|
||||||
comm=$(ps -p "$pid" -o comm= 2> /dev/null || true)
|
comm=$(ps -p "$pid" -o comm= 2>/dev/null || true)
|
||||||
args=$(ps -p "$pid" -o args= 2> /dev/null || true)
|
args=$(ps -p "$pid" -o args= 2>/dev/null || true)
|
||||||
lower="${comm,,} ${args,,}"
|
lower="${comm,,} ${args,,}"
|
||||||
if [[ $lower == *" pacman"* || $lower == pacman* || $lower == *"/pacman "* || $lower == *" pamac"* ]]; then
|
if [[ $lower == *" pacman"* || $lower == pacman* || $lower == *"/pacman "* || $lower == *" pamac"* ]]; then
|
||||||
pac_holder=1
|
pac_holder=1
|
||||||
@ -254,21 +254,21 @@ check_and_handle_db_lock() {
|
|||||||
|
|
||||||
if [[ $gui_holder -eq 1 ]]; then
|
if [[ $gui_holder -eq 1 ]]; then
|
||||||
echo -e "${YELLOW}A background software updater is holding the pacman lock. Attempting to stop it...${NC}" >&2
|
echo -e "${YELLOW}A background software updater is holding the pacman lock. Attempting to stop it...${NC}" >&2
|
||||||
if command -v systemctl > /dev/null 2>&1; then
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
systemctl --quiet stop packagekit.service 2> /dev/null || true
|
systemctl --quiet stop packagekit.service 2>/dev/null || true
|
||||||
systemctl --quiet stop packagekit 2> /dev/null || true
|
systemctl --quiet stop packagekit 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
pkill -x packagekitd 2> /dev/null || true
|
pkill -x packagekitd 2>/dev/null || true
|
||||||
pkill -f gnome-software 2> /dev/null || true
|
pkill -f gnome-software 2>/dev/null || true
|
||||||
pkill -f discover 2> /dev/null || true
|
pkill -f discover 2>/dev/null || true
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
# Re-check holders
|
# Re-check holders
|
||||||
holders=()
|
holders=()
|
||||||
if command -v fuser > /dev/null 2>&1; then
|
if command -v fuser >/dev/null 2>&1; then
|
||||||
mapfile -t holders < <(fuser "$lock_file" 2> /dev/null | tr ' ' '\n' | grep -E '^[0-9]+$' || true)
|
mapfile -t holders < <(fuser "$lock_file" 2>/dev/null | tr ' ' '\n' | grep -E '^[0-9]+$' || true)
|
||||||
elif command -v lsof > /dev/null 2>&1; then
|
elif command -v lsof >/dev/null 2>&1; then
|
||||||
mapfile -t holders < <(lsof -t "$lock_file" 2> /dev/null | grep -E '^[0-9]+$' || true)
|
mapfile -t holders < <(lsof -t "$lock_file" 2>/dev/null | grep -E '^[0-9]+$' || true)
|
||||||
fi
|
fi
|
||||||
if [[ ${#holders[@]} -gt 0 ]]; then
|
if [[ ${#holders[@]} -gt 0 ]]; then
|
||||||
echo -e "${RED}Cannot free the pacman lock; another process still holds it. Try again later.${NC}" >&2
|
echo -e "${RED}Cannot free the pacman lock; another process still holds it. Try again later.${NC}" >&2
|
||||||
@ -279,7 +279,7 @@ check_and_handle_db_lock() {
|
|||||||
|
|
||||||
# Decide whether to remove the lock
|
# Decide whether to remove the lock
|
||||||
local now epoch age
|
local now epoch age
|
||||||
if epoch=$(stat -c %Y "$lock_file" 2> /dev/null); then
|
if epoch=$(stat -c %Y "$lock_file" 2>/dev/null); then
|
||||||
now=$(date +%s)
|
now=$(date +%s)
|
||||||
age=$((now - epoch))
|
age=$((now - epoch))
|
||||||
else
|
else
|
||||||
@ -317,7 +317,7 @@ check_and_handle_db_lock() {
|
|||||||
function remove_installed_blocked_packages() {
|
function remove_installed_blocked_packages() {
|
||||||
# args not used; kept for future policy extension
|
# args not used; kept for future policy extension
|
||||||
# List installed package names
|
# List installed package names
|
||||||
mapfile -t installed_names < <("$PACMAN_BIN" -Qq 2> /dev/null)
|
mapfile -t installed_names < <("$PACMAN_BIN" -Qq 2>/dev/null)
|
||||||
local to_remove=()
|
local to_remove=()
|
||||||
for name in "${installed_names[@]}"; do
|
for name in "${installed_names[@]}"; do
|
||||||
if is_blocked_package_name "$name"; then
|
if is_blocked_package_name "$name"; then
|
||||||
@ -508,8 +508,8 @@ function prompt_for_steam_challenge() {
|
|||||||
read_status=$?
|
read_status=$?
|
||||||
|
|
||||||
# Kill the timer display
|
# Kill the timer display
|
||||||
kill "$display_pid" 2> /dev/null
|
kill "$display_pid" 2>/dev/null
|
||||||
wait "$display_pid" 2> /dev/null
|
wait "$display_pid" 2>/dev/null
|
||||||
echo # Add a newline after the timer
|
echo # Add a newline after the timer
|
||||||
|
|
||||||
# Check if read timed out
|
# Check if read timed out
|
||||||
@ -536,8 +536,30 @@ function prompt_for_steam_challenge() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function check_for_virtualbox() {
|
||||||
|
# List of VirtualBox-related packages
|
||||||
|
local vbox_packages=("virtualbox" "virtualbox-host-modules-arch" "virtualbox-guest-iso" "virtualbox-ext-oracle")
|
||||||
|
|
||||||
|
# Check if the command is an installation command
|
||||||
|
if [[ $1 == "-S" || $1 == "-Sy" || $1 == "-Syu" || $1 == "-Syyu" || $1 == "-U" ]]; then
|
||||||
|
# Check all arguments
|
||||||
|
for arg in "$@"; do
|
||||||
|
# Strip repository prefix if present
|
||||||
|
local package_name="${arg##*/}"
|
||||||
|
|
||||||
|
# Check if argument matches any VirtualBox package
|
||||||
|
for package in "${vbox_packages[@]}"; do
|
||||||
|
if [[ $arg == "$package" || $arg == *"/$package-"* || $arg == *"/$package/"* ||
|
||||||
|
$arg == *"/$package" || $package_name == "$package" ]]; then
|
||||||
|
return 0 # VirtualBox package found
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
return 1 # No VirtualBox package found
|
||||||
|
}
|
||||||
|
|
||||||
# Function to prompt for solving a word unscrambling challenge (for virtualbox - always active)
|
# Function to prompt for solving a word unscrambling challenge (for virtualbox - always active)
|
||||||
# shellcheck disable=SC2329 # Invoked dynamically when matching VirtualBox packages
|
|
||||||
function prompt_for_virtualbox_challenge() {
|
function prompt_for_virtualbox_challenge() {
|
||||||
echo -e "${YELLOW}WARNING: You are trying to install VirtualBox.${NC}"
|
echo -e "${YELLOW}WARNING: You are trying to install VirtualBox.${NC}"
|
||||||
echo -e "${YELLOW}VirtualBox challenge will begin shortly...${NC}"
|
echo -e "${YELLOW}VirtualBox challenge will begin shortly...${NC}"
|
||||||
@ -629,8 +651,8 @@ function prompt_for_virtualbox_challenge() {
|
|||||||
read_status=$?
|
read_status=$?
|
||||||
|
|
||||||
# Kill the timer display
|
# Kill the timer display
|
||||||
kill "$display_pid" 2> /dev/null
|
kill "$display_pid" 2>/dev/null
|
||||||
wait "$display_pid" 2> /dev/null
|
wait "$display_pid" 2>/dev/null
|
||||||
echo # Add a newline after the timer
|
echo # Add a newline after the timer
|
||||||
|
|
||||||
# Check if read timed out
|
# Check if read timed out
|
||||||
@ -681,6 +703,13 @@ if check_for_steam "$@"; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check for VirtualBox (challenge-eligible package)
|
||||||
|
if check_for_virtualbox "$@"; then
|
||||||
|
if ! prompt_for_virtualbox_challenge; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Display operation
|
# Display operation
|
||||||
display_operation "$1"
|
display_operation "$1"
|
||||||
|
|
||||||
|
|||||||
@ -37,7 +37,7 @@ fail() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
Usage: $SCRIPT_NAME [options]
|
Usage: $SCRIPT_NAME [options]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@ -90,14 +90,14 @@ done
|
|||||||
REPO_DIR="$INSTALL_ROOT/unreal-mcp"
|
REPO_DIR="$INSTALL_ROOT/unreal-mcp"
|
||||||
|
|
||||||
# ---------- Dependencies ----------
|
# ---------- Dependencies ----------
|
||||||
require_cmd() { command -v "$1" > /dev/null 2>&1; }
|
require_cmd() { command -v "$1" >/dev/null 2>&1; }
|
||||||
|
|
||||||
ensure_packages_arch() {
|
ensure_packages_arch() {
|
||||||
# Install with pacman using sudo when needed; keep idempotent with --needed
|
# Install with pacman using sudo when needed; keep idempotent with --needed
|
||||||
local pkgs=(git jq uv python rsync)
|
local pkgs=(git jq uv python rsync)
|
||||||
local to_install=()
|
local to_install=()
|
||||||
for p in "${pkgs[@]}"; do
|
for p in "${pkgs[@]}"; do
|
||||||
if ! pacman -Qi "$p" > /dev/null 2>&1; then
|
if ! pacman -Qi "$p" >/dev/null 2>&1; then
|
||||||
to_install+=("$p")
|
to_install+=("$p")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@ -173,10 +173,10 @@ install_launcher() {
|
|||||||
local python_dir="$REPO_DIR/Python"
|
local python_dir="$REPO_DIR/Python"
|
||||||
local launcher="$bin_dir/unreal-mcp-server"
|
local launcher="$bin_dir/unreal-mcp-server"
|
||||||
mkdir -p "$bin_dir"
|
mkdir -p "$bin_dir"
|
||||||
cat > "$launcher" << EOF
|
cat >"$launcher" <<EOF
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
exec uv --directory "$python_dir" run unreal_mcp_server.py "${1:-}" < /dev/null
|
exec uv --directory "$python_dir" run unreal_mcp_server.py "\${1:-}" < /dev/null
|
||||||
EOF
|
EOF
|
||||||
chmod +x "$launcher"
|
chmod +x "$launcher"
|
||||||
if [[ $EUID -eq 0 ]]; then chown "$ACTUAL_USER:$ACTUAL_USER" "$launcher"; fi
|
if [[ $EUID -eq 0 ]]; then chown "$ACTUAL_USER:$ACTUAL_USER" "$launcher"; fi
|
||||||
@ -199,7 +199,7 @@ configure_continue() {
|
|||||||
local tmp_file
|
local tmp_file
|
||||||
tmp_file="$(mktemp)"
|
tmp_file="$(mktemp)"
|
||||||
if [[ ! -f $cont_cfg ]]; then
|
if [[ ! -f $cont_cfg ]]; then
|
||||||
cat > "$tmp_file" << JSON
|
cat >"$tmp_file" <<JSON
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
"unrealMCP": {
|
"unrealMCP": {
|
||||||
@ -221,7 +221,7 @@ JSON
|
|||||||
command: "uv",
|
command: "uv",
|
||||||
args: ["--directory", $dir, "run", "unreal_mcp_server.py"]
|
args: ["--directory", $dir, "run", "unreal_mcp_server.py"]
|
||||||
}
|
}
|
||||||
' "$cont_cfg" > "$tmp_file" && mv "$tmp_file" "$cont_cfg"
|
' "$cont_cfg" >"$tmp_file" && mv "$tmp_file" "$cont_cfg"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $EUID -eq 0 ]]; then chown "$ACTUAL_USER:$ACTUAL_USER" "$cont_cfg"; fi
|
if [[ $EUID -eq 0 ]]; then chown "$ACTUAL_USER:$ACTUAL_USER" "$cont_cfg"; fi
|
||||||
@ -247,12 +247,12 @@ configure_vscode_user_mcp() {
|
|||||||
local candidates=(code code-insiders codium)
|
local candidates=(code code-insiders codium)
|
||||||
local found_any=false
|
local found_any=false
|
||||||
for cli in "${candidates[@]}"; do
|
for cli in "${candidates[@]}"; do
|
||||||
if ! command -v "$cli" > /dev/null 2>&1; then
|
if ! command -v "$cli" >/dev/null 2>&1; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
found_any=true
|
found_any=true
|
||||||
log "Registering MCP server in VS Code user profile via: $cli --add-mcp"
|
log "Registering MCP server in VS Code user profile via: $cli --add-mcp"
|
||||||
if "$cli" --add-mcp "$json" > "/tmp/${cli}-add-mcp.log" 2>&1; then
|
if "$cli" --add-mcp "$json" >"/tmp/${cli}-add-mcp.log" 2>&1; then
|
||||||
log "[$cli] user profile: unrealMCP added/updated"
|
log "[$cli] user profile: unrealMCP added/updated"
|
||||||
else
|
else
|
||||||
sed -n '1,200p' "/tmp/${cli}-add-mcp.log" || true
|
sed -n '1,200p' "/tmp/${cli}-add-mcp.log" || true
|
||||||
@ -281,7 +281,7 @@ configure_vscode_user_mcp() {
|
|||||||
local name
|
local name
|
||||||
for name in "${unreal_profiles[@]}"; do
|
for name in "${unreal_profiles[@]}"; do
|
||||||
log "[$cli] Adding unrealMCP to profile: $name"
|
log "[$cli] Adding unrealMCP to profile: $name"
|
||||||
if "$cli" --profile "$name" --add-mcp "$json" > "/tmp/${cli}-add-mcp-${name// /_}.log" 2>&1; then
|
if "$cli" --profile "$name" --add-mcp "$json" >"/tmp/${cli}-add-mcp-${name// /_}.log" 2>&1; then
|
||||||
log "[$cli] profile '$name': unrealMCP added/updated"
|
log "[$cli] profile '$name': unrealMCP added/updated"
|
||||||
else
|
else
|
||||||
sed -n '1,200p' "/tmp/${cli}-add-mcp-${name// /_}.log" || true
|
sed -n '1,200p' "/tmp/${cli}-add-mcp-${name// /_}.log" || true
|
||||||
@ -307,7 +307,7 @@ install_plugin_into_project() {
|
|||||||
local upath="$PROJECT_UPROJECT"
|
local upath="$PROJECT_UPROJECT"
|
||||||
if [[ -d $upath ]]; then
|
if [[ -d $upath ]]; then
|
||||||
# Resolve .uproject in the provided directory
|
# Resolve .uproject in the provided directory
|
||||||
mapfile -t _uprojects < <(find "$upath" -maxdepth 1 -type f -name "*.uproject" 2> /dev/null || true)
|
mapfile -t _uprojects < <(find "$upath" -maxdepth 1 -type f -name "*.uproject" 2>/dev/null || true)
|
||||||
if [[ ${#_uprojects[@]} -eq 0 ]]; then
|
if [[ ${#_uprojects[@]} -eq 0 ]]; then
|
||||||
fail "--project directory '$upath' contains no .uproject files"
|
fail "--project directory '$upath' contains no .uproject files"
|
||||||
elif [[ ${#_uprojects[@]} -gt 1 ]]; then
|
elif [[ ${#_uprojects[@]} -gt 1 ]]; then
|
||||||
@ -349,7 +349,7 @@ print_summary() {
|
|||||||
if [[ -n $RESOLVED_PROJECT_DIR ]]; then
|
if [[ -n $RESOLVED_PROJECT_DIR ]]; then
|
||||||
plugin_dest="$RESOLVED_PROJECT_DIR/Plugins/UnrealMCP"
|
plugin_dest="$RESOLVED_PROJECT_DIR/Plugins/UnrealMCP"
|
||||||
fi
|
fi
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
============================================
|
============================================
|
||||||
Unreal MCP setup complete
|
Unreal MCP setup complete
|
||||||
============================================
|
============================================
|
||||||
|
|||||||
@ -65,7 +65,7 @@ err() { echo -e "${RED}[ERR ]${RESET} $*" >&2; }
|
|||||||
success() { echo -e "${GREEN}[OK ]${RESET} $*"; }
|
success() { echo -e "${GREEN}[OK ]${RESET} $*"; }
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat << EOF
|
cat <<EOF
|
||||||
${SCRIPT_NAME} v${VERSION}
|
${SCRIPT_NAME} v${VERSION}
|
||||||
Setup or uninstall a self-hosted LibreTranslate instance via Docker.
|
Setup or uninstall a self-hosted LibreTranslate instance via Docker.
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ gen_api_key() {
|
|||||||
key=$(head -c 256 /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 40 || true)
|
key=$(head -c 256 /dev/urandom | tr -dc 'A-Za-z0-9' | head -c 40 || true)
|
||||||
if [[ -z $key || ${#key} -lt 40 ]]; then
|
if [[ -z $key || ${#key} -lt 40 ]]; then
|
||||||
# Fallback using openssl if available
|
# Fallback using openssl if available
|
||||||
if command -v openssl > /dev/null 2>&1; then
|
if command -v openssl >/dev/null 2>&1; then
|
||||||
key=$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 40 || true)
|
key=$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 40 || true)
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -128,7 +128,7 @@ gen_api_key() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
need_cmd() {
|
need_cmd() {
|
||||||
command -v "$1" > /dev/null 2>&1 || {
|
command -v "$1" >/dev/null 2>&1 || {
|
||||||
err "Required command '$1' not found"
|
err "Required command '$1' not found"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@ -250,7 +250,7 @@ ensure_root() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_docker() {
|
install_docker() {
|
||||||
if command -v docker > /dev/null 2>&1; then
|
if command -v docker >/dev/null 2>&1; then
|
||||||
log "Docker already installed"
|
log "Docker already installed"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -259,7 +259,7 @@ install_docker() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
log "Installing Docker..."
|
log "Installing Docker..."
|
||||||
if command -v apt-get > /dev/null 2>&1; then
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
apt-get update -y
|
apt-get update -y
|
||||||
apt-get install -y ca-certificates curl gnupg
|
apt-get install -y ca-certificates curl gnupg
|
||||||
install -d -m 0755 /etc/apt/keyrings
|
install -d -m 0755 /etc/apt/keyrings
|
||||||
@ -276,7 +276,7 @@ install_docker() {
|
|||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
echo "$VERSION_CODENAME"
|
echo "$VERSION_CODENAME"
|
||||||
) stable" \
|
) stable" \
|
||||||
> /etc/apt/sources.list.d/docker.list
|
>/etc/apt/sources.list.d/docker.list
|
||||||
apt-get update -y
|
apt-get update -y
|
||||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
else
|
else
|
||||||
@ -284,8 +284,8 @@ install_docker() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
# Attempt to start docker daemon if dockerd exists and systemctl available; otherwise rely on user
|
# Attempt to start docker daemon if dockerd exists and systemctl available; otherwise rely on user
|
||||||
if command -v systemctl > /dev/null 2>&1; then
|
if command -v systemctl >/dev/null 2>&1; then
|
||||||
(systemctl enable --now docker 2> /dev/null && success "Docker installed and started") || warn "Docker installed; ensure dockerd is running"
|
(systemctl enable --now docker 2>/dev/null && success "Docker installed and started") || warn "Docker installed; ensure dockerd is running"
|
||||||
else
|
else
|
||||||
warn "Docker installed; please ensure docker daemon is running"
|
warn "Docker installed; please ensure docker daemon is running"
|
||||||
fi
|
fi
|
||||||
@ -299,12 +299,12 @@ pull_image() {
|
|||||||
|
|
||||||
detect_container_user() {
|
detect_container_user() {
|
||||||
# Determine uid/gid of configured user inside image so host dirs can be chowned
|
# Determine uid/gid of configured user inside image so host dirs can be chowned
|
||||||
if ! command -v docker > /dev/null 2>&1; then
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
local uid gid
|
local uid gid
|
||||||
uid=$(docker run --rm --entrypoint /usr/bin/id "${IMAGE}:${TAG}" -u 2> /dev/null || echo "")
|
uid=$(docker run --rm --entrypoint /usr/bin/id "${IMAGE}:${TAG}" -u 2>/dev/null || echo "")
|
||||||
gid=$(docker run --rm --entrypoint /usr/bin/id "${IMAGE}:${TAG}" -g 2> /dev/null || echo "")
|
gid=$(docker run --rm --entrypoint /usr/bin/id "${IMAGE}:${TAG}" -g 2>/dev/null || echo "")
|
||||||
if [[ -n $uid && -n $gid ]]; then
|
if [[ -n $uid && -n $gid ]]; then
|
||||||
CONTAINER_UID=$uid
|
CONTAINER_UID=$uid
|
||||||
CONTAINER_GID=$gid
|
CONTAINER_GID=$gid
|
||||||
@ -315,12 +315,12 @@ write_env_file() {
|
|||||||
mkdir -p "${CONFIG_DIR}" "${DATA_DIR}" "${CACHE_DIR}"
|
mkdir -p "${CONFIG_DIR}" "${DATA_DIR}" "${CACHE_DIR}"
|
||||||
detect_container_user
|
detect_container_user
|
||||||
if [[ -n ${CONTAINER_UID:-} && -n ${CONTAINER_GID:-} ]]; then
|
if [[ -n ${CONTAINER_UID:-} && -n ${CONTAINER_GID:-} ]]; then
|
||||||
if command -v stat > /dev/null 2>&1; then
|
if command -v stat >/dev/null 2>&1; then
|
||||||
for d in "${DATA_DIR}" "${CACHE_DIR}"; do
|
for d in "${DATA_DIR}" "${CACHE_DIR}"; do
|
||||||
if [[ -d $d ]]; then
|
if [[ -d $d ]]; then
|
||||||
CUR_UID=$(stat -c %u "$d" 2> /dev/null || echo -1)
|
CUR_UID=$(stat -c %u "$d" 2>/dev/null || echo -1)
|
||||||
if [[ ${CUR_UID} -ne ${CONTAINER_UID} ]]; then
|
if [[ ${CUR_UID} -ne ${CONTAINER_UID} ]]; then
|
||||||
chown "${CONTAINER_UID}":"${CONTAINER_GID}" "$d" 2> /dev/null || warn "Unable to chown $d to ${CONTAINER_UID}:${CONTAINER_GID}"
|
chown "${CONTAINER_UID}":"${CONTAINER_GID}" "$d" 2>/dev/null || warn "Unable to chown $d to ${CONTAINER_UID}:${CONTAINER_GID}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@ -344,14 +344,14 @@ write_env_file() {
|
|||||||
echo "${API_KEY_LINE}"
|
echo "${API_KEY_LINE}"
|
||||||
[[ -n ${PRELOAD_LANGS} ]] && echo "LT_PRELOAD_LANGS=${PRELOAD_LANGS}"
|
[[ -n ${PRELOAD_LANGS} ]] && echo "LT_PRELOAD_LANGS=${PRELOAD_LANGS}"
|
||||||
for kv in "${EXTRA_ENV[@]:-}"; do echo "$kv"; done
|
for kv in "${EXTRA_ENV[@]:-}"; do echo "$kv"; done
|
||||||
} > "${ENV_FILE}.tmp"
|
} >"${ENV_FILE}.tmp"
|
||||||
mv "${ENV_FILE}.tmp" "${ENV_FILE}"
|
mv "${ENV_FILE}.tmp" "${ENV_FILE}"
|
||||||
chmod 600 "${ENV_FILE}"
|
chmod 600 "${ENV_FILE}"
|
||||||
success "Environment file written: ${ENV_FILE}"
|
success "Environment file written: ${ENV_FILE}"
|
||||||
}
|
}
|
||||||
|
|
||||||
start_container_ephemeral() {
|
start_container_ephemeral() {
|
||||||
docker rm -f "${SERVICE_NAME}" > /dev/null 2>&1 || true
|
docker rm -f "${SERVICE_NAME}" >/dev/null 2>&1 || true
|
||||||
docker run -d --name "${SERVICE_NAME}" \
|
docker run -d --name "${SERVICE_NAME}" \
|
||||||
--env-file "${ENV_FILE}" \
|
--env-file "${ENV_FILE}" \
|
||||||
-v "${DATA_DIR}:/home/libretranslate/.local/share/argos-translate" \
|
-v "${DATA_DIR}:/home/libretranslate/.local/share/argos-translate" \
|
||||||
@ -372,7 +372,7 @@ health_check() {
|
|||||||
local attempt=0
|
local attempt=0
|
||||||
while true; do
|
while true; do
|
||||||
attempt=$((attempt + 1))
|
attempt=$((attempt + 1))
|
||||||
if curl ${DEBUG:+-v} -fsS "$url" > /dev/null 2>&1; then
|
if curl ${DEBUG:+-v} -fsS "$url" >/dev/null 2>&1; then
|
||||||
success "Service healthy (attempt $attempt)"
|
success "Service healthy (attempt $attempt)"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
@ -405,8 +405,8 @@ sample_request() {
|
|||||||
|
|
||||||
uninstall_all() {
|
uninstall_all() {
|
||||||
log "Uninstalling LibreTranslate (ephemeral mode)..."
|
log "Uninstalling LibreTranslate (ephemeral mode)..."
|
||||||
docker rm -f "${SERVICE_NAME}" 2> /dev/null || true
|
docker rm -f "${SERVICE_NAME}" 2>/dev/null || true
|
||||||
docker rmi "${IMAGE}:${TAG}" 2> /dev/null || true
|
docker rmi "${IMAGE}:${TAG}" 2>/dev/null || true
|
||||||
if [[ ${KEEP_DATA} -eq 0 ]]; then
|
if [[ ${KEEP_DATA} -eq 0 ]]; then
|
||||||
rm -rf "${DATA_DIR}" "${CONFIG_DIR}" || true
|
rm -rf "${DATA_DIR}" "${CONFIG_DIR}" || true
|
||||||
success "Data directories removed"
|
success "Data directories removed"
|
||||||
@ -448,7 +448,7 @@ main() {
|
|||||||
CMD_STATUS=$?
|
CMD_STATUS=$?
|
||||||
set -e
|
set -e
|
||||||
log "Command exited with status ${CMD_STATUS}; stopping container"
|
log "Command exited with status ${CMD_STATUS}; stopping container"
|
||||||
docker stop "${SERVICE_NAME}" > /dev/null 2>&1 || true
|
docker stop "${SERVICE_NAME}" >/dev/null 2>&1 || true
|
||||||
exit ${CMD_STATUS}
|
exit ${CMD_STATUS}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -457,9 +457,9 @@ main() {
|
|||||||
trap 'log "Stopping container"; docker stop "${SERVICE_NAME}" >/dev/null 2>&1 || true; exit 0' INT TERM
|
trap 'log "Stopping container"; docker stop "${SERVICE_NAME}" >/dev/null 2>&1 || true; exit 0' INT TERM
|
||||||
docker logs -f "${SERVICE_NAME}"
|
docker logs -f "${SERVICE_NAME}"
|
||||||
log "Logs ended; stopping container"
|
log "Logs ended; stopping container"
|
||||||
docker stop "${SERVICE_NAME}" > /dev/null 2>&1 || true
|
docker stop "${SERVICE_NAME}" >/dev/null 2>&1 || true
|
||||||
else
|
else
|
||||||
log "Ephemeral container left running in background (id: $(docker inspect --format '{{.Id}}' ${SERVICE_NAME} 2> /dev/null || echo unknown))"
|
log "Ephemeral container left running in background (id: $(docker inspect --format '{{.Id}}' ${SERVICE_NAME} 2>/dev/null || echo unknown))"
|
||||||
log "Stop manually with: docker stop ${SERVICE_NAME}"
|
log "Stop manually with: docker stop ${SERVICE_NAME}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -476,7 +476,9 @@ main() {
|
|||||||
else
|
else
|
||||||
echo "API key authentication DISABLED (public instance)."
|
echo "API key authentication DISABLED (public instance)."
|
||||||
fi
|
fi
|
||||||
[[ -n ${PRELOAD_LANGS} ]] && echo "Preloaded languages requested: ${PRELOAD_LANGS}" || true
|
if [[ -n ${PRELOAD_LANGS} ]]; then
|
||||||
|
echo "Preloaded languages requested: ${PRELOAD_LANGS}"
|
||||||
|
fi
|
||||||
echo "Environment file: ${ENV_FILE}"
|
echo "Environment file: ${ENV_FILE}"
|
||||||
echo "Manage: docker logs -f ${SERVICE_NAME} | docker stop ${SERVICE_NAME}"
|
echo "Manage: docker logs -f ${SERVICE_NAME} | docker stop ${SERVICE_NAME}"
|
||||||
echo "Uninstall: sudo ${SCRIPT_NAME} --uninstall"
|
echo "Uninstall: sudo ${SCRIPT_NAME} --uninstall"
|
||||||
|
|||||||
@ -14,7 +14,7 @@ PY_RUNNER="$TOOLS_DIR/transcribe_fw.py"
|
|||||||
VENV_DIR="$PROJECT_DIR/.venv"
|
VENV_DIR="$PROJECT_DIR/.venv"
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
cat << USAGE
|
cat <<USAGE
|
||||||
Usage: $(basename "$0") [--online] [--prepare-model NAME --model-dir DIR] [-m model] [-l lang] [-o outdir] [audio_file]
|
Usage: $(basename "$0") [--online] [--prepare-model NAME --model-dir DIR] [-m model] [-l lang] [-o outdir] [audio_file]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@ -34,23 +34,23 @@ log() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
detect_pkg_mgr() {
|
detect_pkg_mgr() {
|
||||||
if command -v apt-get > /dev/null 2>&1; then
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
echo apt
|
echo apt
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if command -v dnf > /dev/null 2>&1; then
|
if command -v dnf >/dev/null 2>&1; then
|
||||||
echo dnf
|
echo dnf
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if command -v yum > /dev/null 2>&1; then
|
if command -v yum >/dev/null 2>&1; then
|
||||||
echo yum
|
echo yum
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if command -v pacman > /dev/null 2>&1; then
|
if command -v pacman >/dev/null 2>&1; then
|
||||||
echo pacman
|
echo pacman
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if command -v zypper > /dev/null 2>&1; then
|
if command -v zypper >/dev/null 2>&1; then
|
||||||
echo zypper
|
echo zypper
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
@ -66,17 +66,21 @@ has_libcublas12() {
|
|||||||
/usr/local/cuda-12*/lib64 \
|
/usr/local/cuda-12*/lib64 \
|
||||||
/opt/cuda/lib64 \
|
/opt/cuda/lib64 \
|
||||||
/opt/cuda/targets/x86_64-linux/lib; do
|
/opt/cuda/targets/x86_64-linux/lib; do
|
||||||
[[ -e "$d/libcublas.so.12" ]] && return 0 || true
|
if [[ -e "$d/libcublas.so.12" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
# venv-provided NVIDIA CUDA libs
|
# venv-provided NVIDIA CUDA libs
|
||||||
if [[ -x "$VENV_DIR/bin/python" ]]; then
|
if [[ -x "$VENV_DIR/bin/python" ]]; then
|
||||||
local pyver
|
local pyver
|
||||||
pyver="$("$VENV_DIR"/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2> /dev/null || true)"
|
pyver="$("$VENV_DIR"/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || true)"
|
||||||
if [[ -n $pyver ]]; then
|
if [[ -n $pyver ]]; then
|
||||||
for d in "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib" \
|
for d in "$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib" \
|
||||||
"$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib" \
|
"$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib" \
|
||||||
"$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib"; do
|
"$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib"; do
|
||||||
[[ -e "$d/libcublas.so.12" ]] && return 0 || true
|
if [[ -e "$d/libcublas.so.12" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -94,7 +98,7 @@ ensure_cuda_runtime() {
|
|||||||
if has_libcublas12; then
|
if has_libcublas12; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if ! command -v sudo > /dev/null 2>&1; then
|
if ! command -v sudo >/dev/null 2>&1; then
|
||||||
log "sudo not found; skipping CUDA runtime install attempt."
|
log "sudo not found; skipping CUDA runtime install attempt."
|
||||||
else
|
else
|
||||||
log "CUDA cuBLAS 12 not found; attempting to install CUDA runtime (manager: $mgr)"
|
log "CUDA cuBLAS 12 not found; attempting to install CUDA runtime (manager: $mgr)"
|
||||||
@ -125,7 +129,7 @@ ensure_cuda_runtime() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
install_system_deps() {
|
install_system_deps() {
|
||||||
have_cmd() { command -v "$1" > /dev/null 2>&1; }
|
have_cmd() { command -v "$1" >/dev/null 2>&1; }
|
||||||
local need_ffmpeg=0 need_espeak=0
|
local need_ffmpeg=0 need_espeak=0
|
||||||
have_cmd ffmpeg || need_ffmpeg=1
|
have_cmd ffmpeg || need_ffmpeg=1
|
||||||
have_cmd espeak-ng || need_espeak=1
|
have_cmd espeak-ng || need_espeak=1
|
||||||
@ -153,7 +157,7 @@ install_system_deps() {
|
|||||||
mgr="$(detect_pkg_mgr)"
|
mgr="$(detect_pkg_mgr)"
|
||||||
log "Detected package manager: $mgr (installing missing: $([[ $need_ffmpeg -eq 1 ]] && echo ffmpeg)$([[ $need_espeak -eq 1 ]] && echo espeak-ng)$([[ $need_libsndfile -eq 1 ]] && echo libsndfile))"
|
log "Detected package manager: $mgr (installing missing: $([[ $need_ffmpeg -eq 1 ]] && echo ffmpeg)$([[ $need_espeak -eq 1 ]] && echo espeak-ng)$([[ $need_libsndfile -eq 1 ]] && echo libsndfile))"
|
||||||
|
|
||||||
if ! command -v sudo > /dev/null 2>&1; then
|
if ! command -v sudo >/dev/null 2>&1; then
|
||||||
log "sudo not found; skipping system package installation attempt."
|
log "sudo not found; skipping system package installation attempt."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -230,13 +234,13 @@ install_python_deps() {
|
|||||||
export PIP_DEFAULT_TIMEOUT=${PIP_DEFAULT_TIMEOUT:-20}
|
export PIP_DEFAULT_TIMEOUT=${PIP_DEFAULT_TIMEOUT:-20}
|
||||||
if [[ $OFFLINE -eq 1 ]]; then
|
if [[ $OFFLINE -eq 1 ]]; then
|
||||||
# Offline: do not install, just verify modules
|
# Offline: do not install, just verify modules
|
||||||
if ! python -c 'import faster_whisper' > /dev/null 2>&1; then
|
if ! python -c 'import faster_whisper' >/dev/null 2>&1; then
|
||||||
echo "Python dependency 'faster_whisper' not found in offline mode. Run with --online to install." >&2
|
echo "Python dependency 'faster_whisper' not found in offline mode. Run with --online to install." >&2
|
||||||
exit 7
|
exit 7
|
||||||
fi
|
fi
|
||||||
# If diarization requested offline, check for its deps too (warn-only)
|
# If diarization requested offline, check for its deps too (warn-only)
|
||||||
if [[ ${FW_DIARIZE:-} == "1" ]]; then
|
if [[ ${FW_DIARIZE:-} == "1" ]]; then
|
||||||
python - << 'PY' || true
|
python - <<'PY' || true
|
||||||
try:
|
try:
|
||||||
import soundfile, speechbrain, torch # noqa: F401
|
import soundfile, speechbrain, torch # noqa: F401
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -247,7 +251,7 @@ PY
|
|||||||
fi
|
fi
|
||||||
if [[ $has_nvidia_flag -eq 1 ]]; then
|
if [[ $has_nvidia_flag -eq 1 ]]; then
|
||||||
# If ctranslate2 is not installed, attempt CUDA-enabled wheel (quiet, with fallback)
|
# If ctranslate2 is not installed, attempt CUDA-enabled wheel (quiet, with fallback)
|
||||||
if ! "$VENV_DIR/bin/python" -c 'import ctranslate2' > /dev/null 2>&1; then
|
if ! "$VENV_DIR/bin/python" -c 'import ctranslate2' >/dev/null 2>&1; then
|
||||||
log "Installing CUDA-enabled CTranslate2 (cu12 wheel)"
|
log "Installing CUDA-enabled CTranslate2 (cu12 wheel)"
|
||||||
python -m pip install -q --retries 1 --upgrade "ctranslate2<5,>=4.0" --extra-index-url https://download.opennmt.net/ctranslate2/cu12 ||
|
python -m pip install -q --retries 1 --upgrade "ctranslate2<5,>=4.0" --extra-index-url https://download.opennmt.net/ctranslate2/cu12 ||
|
||||||
log "Warning: could not reach cu12 wheel index; will proceed with available ctranslate2"
|
log "Warning: could not reach cu12 wheel index; will proceed with available ctranslate2"
|
||||||
@ -266,7 +270,7 @@ PY
|
|||||||
python -m pip install -q --retries 1 --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cpu torch torchaudio ||
|
python -m pip install -q --retries 1 --upgrade --force-reinstall --index-url https://download.pytorch.org/whl/cpu torch torchaudio ||
|
||||||
log "Warning: failed to install torch/torchaudio CPU wheels"
|
log "Warning: failed to install torch/torchaudio CPU wheels"
|
||||||
fi
|
fi
|
||||||
python - << 'PY'
|
python - <<'PY'
|
||||||
import sys
|
import sys
|
||||||
print(f"[PY] Python {sys.version.split()[0]} dependencies installed.")
|
print(f"[PY] Python {sys.version.split()[0]} dependencies installed.")
|
||||||
PY
|
PY
|
||||||
@ -282,14 +286,14 @@ ensure_runner() {
|
|||||||
generate_test_audio() {
|
generate_test_audio() {
|
||||||
local tmpwav
|
local tmpwav
|
||||||
tmpwav="${PROJECT_DIR}/test_fw.wav"
|
tmpwav="${PROJECT_DIR}/test_fw.wav"
|
||||||
if command -v espeak-ng > /dev/null 2>&1; then
|
if command -v espeak-ng >/dev/null 2>&1; then
|
||||||
log "Generating test audio via espeak-ng -> $tmpwav" >&2
|
log "Generating test audio via espeak-ng -> $tmpwav" >&2
|
||||||
espeak-ng -w "$tmpwav" "This is a quick test of faster whisper transcription." > /dev/null 2>&1 || true
|
espeak-ng -w "$tmpwav" "This is a quick test of faster whisper transcription." >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
# If espeak-ng failed or not present, try espeak
|
# If espeak-ng failed or not present, try espeak
|
||||||
if [[ ! -s $tmpwav ]] && command -v espeak > /dev/null 2>&1; then
|
if [[ ! -s $tmpwav ]] && command -v espeak >/dev/null 2>&1; then
|
||||||
log "espeak-ng unavailable or failed; trying espeak -> $tmpwav" >&2
|
log "espeak-ng unavailable or failed; trying espeak -> $tmpwav" >&2
|
||||||
espeak -w "$tmpwav" "This is a quick test of faster whisper transcription." > /dev/null 2>&1 || true
|
espeak -w "$tmpwav" "This is a quick test of faster whisper transcription." >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
# Fallback: generate tone via Python stdlib (no external deps)
|
# Fallback: generate tone via Python stdlib (no external deps)
|
||||||
if [[ ! -s $tmpwav ]]; then
|
if [[ ! -s $tmpwav ]]; then
|
||||||
@ -299,7 +303,7 @@ generate_test_audio() {
|
|||||||
# Final fallback: tone via ffmpeg
|
# Final fallback: tone via ffmpeg
|
||||||
if [[ ! -s $tmpwav ]]; then
|
if [[ ! -s $tmpwav ]]; then
|
||||||
log "Creating a 3s sine tone WAV via ffmpeg -> $tmpwav" >&2
|
log "Creating a 3s sine tone WAV via ffmpeg -> $tmpwav" >&2
|
||||||
ffmpeg -f lavfi -i sine=frequency=1000:duration=3 -ar 16000 -ac 1 -f wav -y "$tmpwav" > /dev/null 2>&1 || true
|
ffmpeg -f lavfi -i sine=frequency=1000:duration=3 -ar 16000 -ac 1 -f wav -y "$tmpwav" >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
echo "$tmpwav"
|
echo "$tmpwav"
|
||||||
}
|
}
|
||||||
@ -311,7 +315,7 @@ prepare_model() {
|
|||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source "$VENV_DIR/bin/activate"
|
source "$VENV_DIR/bin/activate"
|
||||||
log "Preparing model '$name' into $MODEL_DIR"
|
log "Preparing model '$name' into $MODEL_DIR"
|
||||||
python - << PY
|
python - <<PY
|
||||||
import sys, os
|
import sys, os
|
||||||
from faster_whisper import WhisperModel
|
from faster_whisper import WhisperModel
|
||||||
name = os.environ.get('FW_PREPARE_NAME')
|
name = os.environ.get('FW_PREPARE_NAME')
|
||||||
@ -402,7 +406,7 @@ main() {
|
|||||||
|
|
||||||
# Detect NVIDIA GPU and enforce CUDA if present
|
# Detect NVIDIA GPU and enforce CUDA if present
|
||||||
has_nvidia=0
|
has_nvidia=0
|
||||||
if command -v nvidia-smi > /dev/null 2>&1 && nvidia-smi -L > /dev/null 2>&1; then
|
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi -L >/dev/null 2>&1; then
|
||||||
has_nvidia=1
|
has_nvidia=1
|
||||||
fi
|
fi
|
||||||
install_python_deps "$has_nvidia"
|
install_python_deps "$has_nvidia"
|
||||||
@ -441,7 +445,7 @@ main() {
|
|||||||
# Include system and possible venv-provided CUDA libs
|
# Include system and possible venv-provided CUDA libs
|
||||||
local pyver venv_cuda_paths=""
|
local pyver venv_cuda_paths=""
|
||||||
if [[ -x "$VENV_DIR/bin/python" ]]; then
|
if [[ -x "$VENV_DIR/bin/python" ]]; then
|
||||||
pyver="$("$VENV_DIR"/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2> /dev/null || true)"
|
pyver="$("$VENV_DIR"/bin/python -c 'import sys;print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || true)"
|
||||||
if [[ -n $pyver ]]; then
|
if [[ -n $pyver ]]; then
|
||||||
venv_cuda_paths="$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib"
|
venv_cuda_paths="$VENV_DIR/lib/python$pyver/site-packages/nvidia/cublas/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cudnn/lib:$VENV_DIR/lib/python$pyver/site-packages/nvidia/cuda_runtime/lib"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user