mirror of
https://github.com/kuhyx/scripts.git
synced 2026-07-04 13:03:05 +02: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_VERBOSE=${AMD_VERBOSE:-0}
|
||||
|
||||
vlog() { [ "$AMD_VERBOSE" = 1 ] && echo "[amd] $*" || true; }
|
||||
vlog() { if [ "$AMD_VERBOSE" = 1 ]; then echo "[amd] $*"; fi; }
|
||||
info() { echo "[amd] $*"; }
|
||||
warn() { echo "[amd][warn] $*" >&2; }
|
||||
|
||||
@ -64,7 +64,7 @@ _build_aur_pkg() {
|
||||
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
|
||||
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
|
||||
local built=(*.pkg.tar.zst)
|
||||
yes | sudo pacman -U --noconfirm "${built[@]}"
|
||||
@ -72,8 +72,8 @@ _build_aur_pkg() {
|
||||
|
||||
_install_repo_or_aur() {
|
||||
local pkg="$1"
|
||||
if pacman -Si "$pkg" > /dev/null 2>&1; then
|
||||
if pacman -Qi "$pkg" > /dev/null 2>&1; then
|
||||
if pacman -Si "$pkg" >/dev/null 2>&1; then
|
||||
if pacman -Qi "$pkg" >/dev/null 2>&1; then
|
||||
vlog "$pkg already installed"
|
||||
else
|
||||
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
|
||||
info "Configuring amdgpu for SI/CIK (IS_SI=$IS_SI IS_CIK=$IS_CIK)"
|
||||
TMP_CONF=$(mktemp)
|
||||
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 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"
|
||||
sudo mkdir -p /etc/modprobe.d
|
||||
sudo cp "$TMP_CONF" /etc/modprobe.d/10-amdgpu-si-cik.conf
|
||||
rm -f "$TMP_CONF"
|
||||
@ -142,7 +142,7 @@ else
|
||||
fi
|
||||
|
||||
# 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}')
|
||||
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_VERBOSE=${INTEL_VERBOSE:-1}
|
||||
|
||||
vlog() { [ "$INTEL_VERBOSE" = 1 ] && echo "[intel] $*" || true; }
|
||||
vlog() { if [ "$INTEL_VERBOSE" = 1 ]; then echo "[intel] $*"; fi; }
|
||||
info() { echo "[intel] $*"; }
|
||||
warn() { echo "[intel][warn] $*" >&2; }
|
||||
|
||||
@ -44,10 +44,10 @@ fi
|
||||
|
||||
install_pkg() {
|
||||
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"
|
||||
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"
|
||||
else
|
||||
warn "Package $pkg not found in repos (not handling AUR here)"
|
||||
@ -89,7 +89,7 @@ if [ -n "$INTEL_ENABLE_GUC" ]; then
|
||||
else
|
||||
info "Configuring enable_guc=$INTEL_ENABLE_GUC"
|
||||
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
|
||||
info "Regenerating initramfs (mkinitcpio -P) for GuC/HuC change"
|
||||
sudo mkinitcpio -P || warn "mkinitcpio failed; continue manually"
|
||||
@ -100,7 +100,7 @@ if [ -n "$INTEL_ENABLE_GUC" ]; then
|
||||
fi
|
||||
|
||||
# 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}')
|
||||
info "Kernel driver in use: ${KDRV:-unknown}"
|
||||
|
||||
|
||||
@ -9,23 +9,23 @@ LOGTAG=hosts-guard-hook
|
||||
stop_units_if_present() {
|
||||
local units=(hosts-bind-mount.service hosts-guard.path)
|
||||
for u in "${units[@]}"; do
|
||||
if command -v systemctl > /dev/null 2>&1; then
|
||||
if systemctl list-unit-files 2> /dev/null | grep -q "^$u"; then
|
||||
systemctl stop "$u" > /dev/null 2>&1 || true
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
if systemctl list-unit-files 2>/dev/null | grep -q "^$u"; then
|
||||
systemctl stop "$u" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
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() {
|
||||
local i=0
|
||||
# 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
|
||||
umount -l "$TARGET" > /dev/null 2>&1 || break
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
done
|
||||
@ -34,7 +34,7 @@ cleanup_mount_stacks() {
|
||||
local cnt
|
||||
cnt=$(mount_layers_count)
|
||||
while ((cnt > 1)); do
|
||||
umount -l "$TARGET" > /dev/null 2>&1 || break
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
cnt=$(mount_layers_count)
|
||||
@ -43,23 +43,27 @@ cleanup_mount_stacks() {
|
||||
}
|
||||
|
||||
# Drop protective attributes if present
|
||||
if command -v lsattr > /dev/null 2>&1; then
|
||||
attrs=$(lsattr -d "$TARGET" 2> /dev/null || true)
|
||||
echo "$attrs" | grep -q " i " && chattr -i "$TARGET" > /dev/null 2>&1 || true
|
||||
echo "$attrs" | grep -q " a " && chattr -a "$TARGET" > /dev/null 2>&1 || true
|
||||
if command -v lsattr >/dev/null 2>&1; then
|
||||
attrs=$(lsattr -d "$TARGET" 2>/dev/null || true)
|
||||
if echo "$attrs" | grep -q " i "; then
|
||||
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
|
||||
|
||||
stop_units_if_present
|
||||
|
||||
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
|
||||
cleanup_mount_stacks
|
||||
|
||||
# If someone managed a ro single-layer mount, ensure rw by remounting or collapsing again
|
||||
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
|
||||
|
||||
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_maintenance() {
|
||||
# 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
|
||||
fi
|
||||
|
||||
@ -214,10 +214,10 @@ check_and_handle_db_lock() {
|
||||
|
||||
# Determine which processes actually have the lock open
|
||||
local -a holders=()
|
||||
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)
|
||||
elif command -v lsof > /dev/null 2>&1; then
|
||||
mapfile -t holders < <(lsof -t "$lock_file" 2> /dev/null | grep -E '^[0-9]+$' || true)
|
||||
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)
|
||||
elif command -v lsof >/dev/null 2>&1; then
|
||||
mapfile -t holders < <(lsof -t "$lock_file" 2>/dev/null | grep -E '^[0-9]+$' || true)
|
||||
else
|
||||
holders=()
|
||||
fi
|
||||
@ -237,8 +237,8 @@ check_and_handle_db_lock() {
|
||||
local gui_holder=0
|
||||
for pid in "${holders[@]}"; do
|
||||
local comm args lower
|
||||
comm=$(ps -p "$pid" -o comm= 2> /dev/null || true)
|
||||
args=$(ps -p "$pid" -o args= 2> /dev/null || true)
|
||||
comm=$(ps -p "$pid" -o comm= 2>/dev/null || true)
|
||||
args=$(ps -p "$pid" -o args= 2>/dev/null || true)
|
||||
lower="${comm,,} ${args,,}"
|
||||
if [[ $lower == *" pacman"* || $lower == pacman* || $lower == *"/pacman "* || $lower == *" pamac"* ]]; then
|
||||
pac_holder=1
|
||||
@ -254,21 +254,21 @@ check_and_handle_db_lock() {
|
||||
|
||||
if [[ $gui_holder -eq 1 ]]; then
|
||||
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
|
||||
systemctl --quiet stop packagekit.service 2> /dev/null || true
|
||||
systemctl --quiet stop packagekit 2> /dev/null || true
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl --quiet stop packagekit.service 2>/dev/null || true
|
||||
systemctl --quiet stop packagekit 2>/dev/null || true
|
||||
fi
|
||||
pkill -x packagekitd 2> /dev/null || true
|
||||
pkill -f gnome-software 2> /dev/null || true
|
||||
pkill -f discover 2> /dev/null || true
|
||||
pkill -x packagekitd 2>/dev/null || true
|
||||
pkill -f gnome-software 2>/dev/null || true
|
||||
pkill -f discover 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
# Re-check holders
|
||||
holders=()
|
||||
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)
|
||||
elif command -v lsof > /dev/null 2>&1; then
|
||||
mapfile -t holders < <(lsof -t "$lock_file" 2> /dev/null | grep -E '^[0-9]+$' || true)
|
||||
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)
|
||||
elif command -v lsof >/dev/null 2>&1; then
|
||||
mapfile -t holders < <(lsof -t "$lock_file" 2>/dev/null | grep -E '^[0-9]+$' || true)
|
||||
fi
|
||||
if [[ ${#holders[@]} -gt 0 ]]; then
|
||||
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
|
||||
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)
|
||||
age=$((now - epoch))
|
||||
else
|
||||
@ -317,7 +317,7 @@ check_and_handle_db_lock() {
|
||||
function remove_installed_blocked_packages() {
|
||||
# args not used; kept for future policy extension
|
||||
# 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=()
|
||||
for name in "${installed_names[@]}"; do
|
||||
if is_blocked_package_name "$name"; then
|
||||
@ -508,8 +508,8 @@ function prompt_for_steam_challenge() {
|
||||
read_status=$?
|
||||
|
||||
# Kill the timer display
|
||||
kill "$display_pid" 2> /dev/null
|
||||
wait "$display_pid" 2> /dev/null
|
||||
kill "$display_pid" 2>/dev/null
|
||||
wait "$display_pid" 2>/dev/null
|
||||
echo # Add a newline after the timer
|
||||
|
||||
# Check if read timed out
|
||||
@ -536,8 +536,30 @@ function prompt_for_steam_challenge() {
|
||||
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)
|
||||
# shellcheck disable=SC2329 # Invoked dynamically when matching VirtualBox packages
|
||||
function prompt_for_virtualbox_challenge() {
|
||||
echo -e "${YELLOW}WARNING: You are trying to install VirtualBox.${NC}"
|
||||
echo -e "${YELLOW}VirtualBox challenge will begin shortly...${NC}"
|
||||
@ -629,8 +651,8 @@ function prompt_for_virtualbox_challenge() {
|
||||
read_status=$?
|
||||
|
||||
# Kill the timer display
|
||||
kill "$display_pid" 2> /dev/null
|
||||
wait "$display_pid" 2> /dev/null
|
||||
kill "$display_pid" 2>/dev/null
|
||||
wait "$display_pid" 2>/dev/null
|
||||
echo # Add a newline after the timer
|
||||
|
||||
# Check if read timed out
|
||||
@ -681,6 +703,13 @@ if check_for_steam "$@"; then
|
||||
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 "$1"
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ fail() {
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
cat <<EOF
|
||||
Usage: $SCRIPT_NAME [options]
|
||||
|
||||
Options:
|
||||
@ -90,14 +90,14 @@ done
|
||||
REPO_DIR="$INSTALL_ROOT/unreal-mcp"
|
||||
|
||||
# ---------- Dependencies ----------
|
||||
require_cmd() { command -v "$1" > /dev/null 2>&1; }
|
||||
require_cmd() { command -v "$1" >/dev/null 2>&1; }
|
||||
|
||||
ensure_packages_arch() {
|
||||
# Install with pacman using sudo when needed; keep idempotent with --needed
|
||||
local pkgs=(git jq uv python rsync)
|
||||
local to_install=()
|
||||
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")
|
||||
fi
|
||||
done
|
||||
@ -173,10 +173,10 @@ install_launcher() {
|
||||
local python_dir="$REPO_DIR/Python"
|
||||
local launcher="$bin_dir/unreal-mcp-server"
|
||||
mkdir -p "$bin_dir"
|
||||
cat > "$launcher" << EOF
|
||||
cat >"$launcher" <<EOF
|
||||
#!/bin/bash
|
||||
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
|
||||
chmod +x "$launcher"
|
||||
if [[ $EUID -eq 0 ]]; then chown "$ACTUAL_USER:$ACTUAL_USER" "$launcher"; fi
|
||||
@ -199,7 +199,7 @@ configure_continue() {
|
||||
local tmp_file
|
||||
tmp_file="$(mktemp)"
|
||||
if [[ ! -f $cont_cfg ]]; then
|
||||
cat > "$tmp_file" << JSON
|
||||
cat >"$tmp_file" <<JSON
|
||||
{
|
||||
"mcpServers": {
|
||||
"unrealMCP": {
|
||||
@ -221,7 +221,7 @@ JSON
|
||||
command: "uv",
|
||||
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
|
||||
|
||||
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 found_any=false
|
||||
for cli in "${candidates[@]}"; do
|
||||
if ! command -v "$cli" > /dev/null 2>&1; then
|
||||
if ! command -v "$cli" >/dev/null 2>&1; then
|
||||
continue
|
||||
fi
|
||||
found_any=true
|
||||
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"
|
||||
else
|
||||
sed -n '1,200p' "/tmp/${cli}-add-mcp.log" || true
|
||||
@ -281,7 +281,7 @@ configure_vscode_user_mcp() {
|
||||
local name
|
||||
for name in "${unreal_profiles[@]}"; do
|
||||
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"
|
||||
else
|
||||
sed -n '1,200p' "/tmp/${cli}-add-mcp-${name// /_}.log" || true
|
||||
@ -307,7 +307,7 @@ install_plugin_into_project() {
|
||||
local upath="$PROJECT_UPROJECT"
|
||||
if [[ -d $upath ]]; then
|
||||
# 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
|
||||
fail "--project directory '$upath' contains no .uproject files"
|
||||
elif [[ ${#_uprojects[@]} -gt 1 ]]; then
|
||||
@ -349,7 +349,7 @@ print_summary() {
|
||||
if [[ -n $RESOLVED_PROJECT_DIR ]]; then
|
||||
plugin_dest="$RESOLVED_PROJECT_DIR/Plugins/UnrealMCP"
|
||||
fi
|
||||
cat << EOF
|
||||
cat <<EOF
|
||||
============================================
|
||||
Unreal MCP setup complete
|
||||
============================================
|
||||
|
||||
@ -65,7 +65,7 @@ err() { echo -e "${RED}[ERR ]${RESET} $*" >&2; }
|
||||
success() { echo -e "${GREEN}[OK ]${RESET} $*"; }
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
cat <<EOF
|
||||
${SCRIPT_NAME} v${VERSION}
|
||||
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)
|
||||
if [[ -z $key || ${#key} -lt 40 ]]; then
|
||||
# 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)
|
||||
fi
|
||||
fi
|
||||
@ -128,7 +128,7 @@ gen_api_key() {
|
||||
}
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" > /dev/null 2>&1 || {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
err "Required command '$1' not found"
|
||||
return 1
|
||||
}
|
||||
@ -250,7 +250,7 @@ ensure_root() {
|
||||
}
|
||||
|
||||
install_docker() {
|
||||
if command -v docker > /dev/null 2>&1; then
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
log "Docker already installed"
|
||||
return 0
|
||||
fi
|
||||
@ -259,7 +259,7 @@ install_docker() {
|
||||
exit 1
|
||||
fi
|
||||
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 install -y ca-certificates curl gnupg
|
||||
install -d -m 0755 /etc/apt/keyrings
|
||||
@ -276,7 +276,7 @@ install_docker() {
|
||||
. /etc/os-release
|
||||
echo "$VERSION_CODENAME"
|
||||
) stable" \
|
||||
> /etc/apt/sources.list.d/docker.list
|
||||
>/etc/apt/sources.list.d/docker.list
|
||||
apt-get update -y
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
else
|
||||
@ -284,8 +284,8 @@ install_docker() {
|
||||
exit 1
|
||||
fi
|
||||
# Attempt to start docker daemon if dockerd exists and systemctl available; otherwise rely on user
|
||||
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"
|
||||
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"
|
||||
else
|
||||
warn "Docker installed; please ensure docker daemon is running"
|
||||
fi
|
||||
@ -299,12 +299,12 @@ pull_image() {
|
||||
|
||||
detect_container_user() {
|
||||
# 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
|
||||
fi
|
||||
local uid gid
|
||||
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 "")
|
||||
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 "")
|
||||
if [[ -n $uid && -n $gid ]]; then
|
||||
CONTAINER_UID=$uid
|
||||
CONTAINER_GID=$gid
|
||||
@ -315,12 +315,12 @@ write_env_file() {
|
||||
mkdir -p "${CONFIG_DIR}" "${DATA_DIR}" "${CACHE_DIR}"
|
||||
detect_container_user
|
||||
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
|
||||
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
|
||||
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
|
||||
done
|
||||
@ -344,14 +344,14 @@ write_env_file() {
|
||||
echo "${API_KEY_LINE}"
|
||||
[[ -n ${PRELOAD_LANGS} ]] && echo "LT_PRELOAD_LANGS=${PRELOAD_LANGS}"
|
||||
for kv in "${EXTRA_ENV[@]:-}"; do echo "$kv"; done
|
||||
} > "${ENV_FILE}.tmp"
|
||||
} >"${ENV_FILE}.tmp"
|
||||
mv "${ENV_FILE}.tmp" "${ENV_FILE}"
|
||||
chmod 600 "${ENV_FILE}"
|
||||
success "Environment file written: ${ENV_FILE}"
|
||||
}
|
||||
|
||||
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}" \
|
||||
--env-file "${ENV_FILE}" \
|
||||
-v "${DATA_DIR}:/home/libretranslate/.local/share/argos-translate" \
|
||||
@ -372,7 +372,7 @@ health_check() {
|
||||
local attempt=0
|
||||
while true; do
|
||||
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)"
|
||||
return 0
|
||||
else
|
||||
@ -405,8 +405,8 @@ sample_request() {
|
||||
|
||||
uninstall_all() {
|
||||
log "Uninstalling LibreTranslate (ephemeral mode)..."
|
||||
docker rm -f "${SERVICE_NAME}" 2> /dev/null || true
|
||||
docker rmi "${IMAGE}:${TAG}" 2> /dev/null || true
|
||||
docker rm -f "${SERVICE_NAME}" 2>/dev/null || true
|
||||
docker rmi "${IMAGE}:${TAG}" 2>/dev/null || true
|
||||
if [[ ${KEEP_DATA} -eq 0 ]]; then
|
||||
rm -rf "${DATA_DIR}" "${CONFIG_DIR}" || true
|
||||
success "Data directories removed"
|
||||
@ -448,7 +448,7 @@ main() {
|
||||
CMD_STATUS=$?
|
||||
set -e
|
||||
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}
|
||||
fi
|
||||
|
||||
@ -457,9 +457,9 @@ main() {
|
||||
trap 'log "Stopping container"; docker stop "${SERVICE_NAME}" >/dev/null 2>&1 || true; exit 0' INT TERM
|
||||
docker logs -f "${SERVICE_NAME}"
|
||||
log "Logs ended; stopping container"
|
||||
docker stop "${SERVICE_NAME}" > /dev/null 2>&1 || true
|
||||
docker stop "${SERVICE_NAME}" >/dev/null 2>&1 || true
|
||||
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}"
|
||||
fi
|
||||
|
||||
@ -476,7 +476,9 @@ main() {
|
||||
else
|
||||
echo "API key authentication DISABLED (public instance)."
|
||||
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 "Manage: docker logs -f ${SERVICE_NAME} | docker stop ${SERVICE_NAME}"
|
||||
echo "Uninstall: sudo ${SCRIPT_NAME} --uninstall"
|
||||
|
||||
@ -14,7 +14,7 @@ PY_RUNNER="$TOOLS_DIR/transcribe_fw.py"
|
||||
VENV_DIR="$PROJECT_DIR/.venv"
|
||||
|
||||
usage() {
|
||||
cat << USAGE
|
||||
cat <<USAGE
|
||||
Usage: $(basename "$0") [--online] [--prepare-model NAME --model-dir DIR] [-m model] [-l lang] [-o outdir] [audio_file]
|
||||
|
||||
Options:
|
||||
@ -34,23 +34,23 @@ log() {
|
||||
}
|
||||
|
||||
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
|
||||
return
|
||||
fi
|
||||
if command -v dnf > /dev/null 2>&1; then
|
||||
if command -v dnf >/dev/null 2>&1; then
|
||||
echo dnf
|
||||
return
|
||||
fi
|
||||
if command -v yum > /dev/null 2>&1; then
|
||||
if command -v yum >/dev/null 2>&1; then
|
||||
echo yum
|
||||
return
|
||||
fi
|
||||
if command -v pacman > /dev/null 2>&1; then
|
||||
if command -v pacman >/dev/null 2>&1; then
|
||||
echo pacman
|
||||
return
|
||||
fi
|
||||
if command -v zypper > /dev/null 2>&1; then
|
||||
if command -v zypper >/dev/null 2>&1; then
|
||||
echo zypper
|
||||
return
|
||||
fi
|
||||
@ -66,17 +66,21 @@ has_libcublas12() {
|
||||
/usr/local/cuda-12*/lib64 \
|
||||
/opt/cuda/lib64 \
|
||||
/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
|
||||
# venv-provided NVIDIA CUDA libs
|
||||
if [[ -x "$VENV_DIR/bin/python" ]]; then
|
||||
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
|
||||
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/cuda_runtime/lib"; do
|
||||
[[ -e "$d/libcublas.so.12" ]] && return 0 || true
|
||||
if [[ -e "$d/libcublas.so.12" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
@ -94,7 +98,7 @@ ensure_cuda_runtime() {
|
||||
if has_libcublas12; then
|
||||
return 0
|
||||
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."
|
||||
else
|
||||
log "CUDA cuBLAS 12 not found; attempting to install CUDA runtime (manager: $mgr)"
|
||||
@ -125,7 +129,7 @@ ensure_cuda_runtime() {
|
||||
}
|
||||
|
||||
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
|
||||
have_cmd ffmpeg || need_ffmpeg=1
|
||||
have_cmd espeak-ng || need_espeak=1
|
||||
@ -153,7 +157,7 @@ install_system_deps() {
|
||||
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))"
|
||||
|
||||
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."
|
||||
return 0
|
||||
fi
|
||||
@ -230,13 +234,13 @@ install_python_deps() {
|
||||
export PIP_DEFAULT_TIMEOUT=${PIP_DEFAULT_TIMEOUT:-20}
|
||||
if [[ $OFFLINE -eq 1 ]]; then
|
||||
# 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
|
||||
exit 7
|
||||
fi
|
||||
# If diarization requested offline, check for its deps too (warn-only)
|
||||
if [[ ${FW_DIARIZE:-} == "1" ]]; then
|
||||
python - << 'PY' || true
|
||||
python - <<'PY' || true
|
||||
try:
|
||||
import soundfile, speechbrain, torch # noqa: F401
|
||||
except Exception as e:
|
||||
@ -247,7 +251,7 @@ PY
|
||||
fi
|
||||
if [[ $has_nvidia_flag -eq 1 ]]; then
|
||||
# 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)"
|
||||
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"
|
||||
@ -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 ||
|
||||
log "Warning: failed to install torch/torchaudio CPU wheels"
|
||||
fi
|
||||
python - << 'PY'
|
||||
python - <<'PY'
|
||||
import sys
|
||||
print(f"[PY] Python {sys.version.split()[0]} dependencies installed.")
|
||||
PY
|
||||
@ -282,14 +286,14 @@ ensure_runner() {
|
||||
generate_test_audio() {
|
||||
local tmpwav
|
||||
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
|
||||
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
|
||||
# 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
|
||||
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
|
||||
# Fallback: generate tone via Python stdlib (no external deps)
|
||||
if [[ ! -s $tmpwav ]]; then
|
||||
@ -299,7 +303,7 @@ generate_test_audio() {
|
||||
# Final fallback: tone via ffmpeg
|
||||
if [[ ! -s $tmpwav ]]; then
|
||||
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
|
||||
echo "$tmpwav"
|
||||
}
|
||||
@ -311,7 +315,7 @@ prepare_model() {
|
||||
# shellcheck disable=SC1091
|
||||
source "$VENV_DIR/bin/activate"
|
||||
log "Preparing model '$name' into $MODEL_DIR"
|
||||
python - << PY
|
||||
python - <<PY
|
||||
import sys, os
|
||||
from faster_whisper import WhisperModel
|
||||
name = os.environ.get('FW_PREPARE_NAME')
|
||||
@ -402,7 +406,7 @@ main() {
|
||||
|
||||
# Detect NVIDIA GPU and enforce CUDA if present
|
||||
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
|
||||
fi
|
||||
install_python_deps "$has_nvidia"
|
||||
@ -441,7 +445,7 @@ main() {
|
||||
# Include system and possible venv-provided CUDA libs
|
||||
local pyver venv_cuda_paths=""
|
||||
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
|
||||
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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user