Linux Script Updates
This commit is contained in:
parent
7baf6321ca
commit
fb8c1a98e9
317
Borealis.sh
317
Borealis.sh
@ -1,171 +1,252 @@
|
|||||||
#////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Launch-Borealis.sh
|
|
||||||
|
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Color codes
|
#////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Borealis.sh
|
||||||
|
|
||||||
|
# =================== ASCII Color Codes ===================
|
||||||
GREEN="\033[0;32m"
|
GREEN="\033[0;32m"
|
||||||
YELLOW="\033[1;33m"
|
YELLOW="\033[1;33m"
|
||||||
RED="\033[0;31m"
|
RED="\033[0;31m"
|
||||||
|
CYAN="\033[0;36m"
|
||||||
|
BLUE="\033[1;34m"
|
||||||
|
GRAY="\033[0;37m"
|
||||||
|
DARKGRAY="\033[1;30m"
|
||||||
RESET="\033[0m"
|
RESET="\033[0m"
|
||||||
|
# =================== ASCII Icons Only ===================
|
||||||
# ASCII-only icons
|
|
||||||
CHECKMARK="[OK]"
|
CHECKMARK="[OK]"
|
||||||
HOURGLASS="[WAIT]"
|
HOURGLASS="[WAIT]"
|
||||||
CROSSMARK="[X]"
|
CROSSMARK="[X]"
|
||||||
INFO="[i]"
|
INFO="[i]"
|
||||||
|
# =================== ASCII Banner ===================
|
||||||
|
ascii_banner() {
|
||||||
|
cat <<EOF
|
||||||
|
============================================================
|
||||||
|
BBBBBBBBBB OOOO RRRRRR EEEEEEE AAAAAA L III SSSS
|
||||||
|
BB BB O O RR RR EE AA AA L I SS
|
||||||
|
BBBBBBBBB O O RRRRRR EEEE AAAAAAAA L I SSS
|
||||||
|
BB BB O O RR RR EE AA AA L I SS
|
||||||
|
BBBBBBBBB OOOO RR RR EEEEEEE AA AA LLLLL III SSSS
|
||||||
|
============================================================
|
||||||
|
EOF
|
||||||
|
echo -e "${DARKGRAY}Drag-&-Drop Automation Orchestration | Macros | Data Collection & Analysis${RESET}"
|
||||||
|
}
|
||||||
|
# =================== Utility/Progress Functions ===================
|
||||||
run_step() {
|
run_step() {
|
||||||
local message="$1"
|
local message="\$1"; shift
|
||||||
shift
|
echo -ne "\${CYAN}\${HOURGLASS} \$message...\${RESET}"
|
||||||
echo -e "${GREEN}${HOURGLASS} ${message}...${RESET}"
|
if "\$@"; then
|
||||||
if "$@"; then
|
echo -e "\r\${GREEN}\${CHECKMARK} \$message\${RESET} "
|
||||||
echo -e "${GREEN}${CHECKMARK} ${message} completed.${RESET}"
|
|
||||||
else
|
else
|
||||||
echo -e "${RED}${CROSSMARK} ${message} failed!${RESET}"
|
echo -e "\r\${RED}\${CROSSMARK} \$message failed!\${RESET} "
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
pause_prompt() {
|
||||||
|
echo -ne "\nPress ENTER to continue..."; read _
|
||||||
|
}
|
||||||
detect_distro() {
|
detect_distro() {
|
||||||
if [ -f /etc/os-release ]; then
|
if [ -f /etc/os-release ]; then
|
||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
DISTRO_ID="$ID"
|
DISTRO_ID="\$ID"
|
||||||
else
|
else
|
||||||
DISTRO_ID="unknown"
|
DISTRO_ID="unknown"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
# =================== Dependency Installation ===================
|
||||||
install_core_dependencies() {
|
install_core_dependencies() {
|
||||||
case "$DISTRO_ID" in
|
detect_distro
|
||||||
|
case "\$DISTRO_ID" in
|
||||||
ubuntu|debian)
|
ubuntu|debian)
|
||||||
sudo apt update -qq
|
sudo apt update -qq
|
||||||
sudo apt install -y python3 python3-venv python3-pip nodejs npm git curl tesseract-ocr
|
sudo apt install -y python3 python3-venv python3-pip nodejs npm git curl tesseract-ocr p7zip-full
|
||||||
;;
|
;;
|
||||||
rhel|centos|fedora|rocky)
|
rhel|centos|fedora|rocky)
|
||||||
sudo dnf install -y python3 python3-pip nodejs npm git curl tesseract
|
sudo dnf install -y python3 python3-pip python3-virtualenv nodejs npm git curl tesseract p7zip
|
||||||
;;
|
;;
|
||||||
arch)
|
arch)
|
||||||
sudo pacman -Sy --noconfirm python python-venv python-pip nodejs npm git curl tesseract
|
sudo pacman -Sy --noconfirm python python-venv python-pip nodejs npm git curl tesseract p7zip
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo -e "${RED}${CROSSMARK} Unsupported Linux distribution: ${DISTRO_ID}${RESET}"
|
echo -e "\${RED}\${CROSSMARK} Unsupported Linux distribution: \${DISTRO_ID}\${RESET}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
launch_server() {
|
ensure_tesseract_data() {
|
||||||
echo -e "${GREEN}Deploying Borealis - Server Dashboard...${RESET}"
|
# Make sure tesseract English and OSD traineddata are present (Windows script always downloads these)
|
||||||
echo "===================================================================================="
|
local tessdata_dir="Data/Server/Python_API_Endpoints/Tesseract-OCR/tessdata"
|
||||||
|
mkdir -p "\$tessdata_dir"
|
||||||
detect_distro
|
[ ! -f "\$tessdata_dir/eng.traineddata" ] && \
|
||||||
run_step "Install System Dependencies" install_core_dependencies
|
curl -L -o "\$tessdata_dir/eng.traineddata" "https://github.com/tesseract-ocr/tessdata/raw/main/eng.traineddata"
|
||||||
|
[ ! -f "\$tessdata_dir/osd.traineddata" ] && \
|
||||||
# Paths
|
curl -L -o "\$tessdata_dir/osd.traineddata" "https://github.com/tesseract-ocr/tessdata/raw/main/osd.traineddata"
|
||||||
venvFolder="Server"
|
|
||||||
dataSource="Data/Server"
|
|
||||||
dataDestination="${venvFolder}/Borealis"
|
|
||||||
customUIPath="${dataSource}/WebUI"
|
|
||||||
webUIDestination="${venvFolder}/web-interface"
|
|
||||||
venvPython="${venvFolder}/bin/python3"
|
|
||||||
|
|
||||||
# Create Python venv
|
|
||||||
run_step "Create Virtual Python Environment" bash -c "
|
|
||||||
if [ ! -f '${venvFolder}/bin/activate' ]; then
|
|
||||||
python3 -m venv '${venvFolder}'
|
|
||||||
fi
|
|
||||||
"
|
|
||||||
|
|
||||||
# Install Python requirements
|
|
||||||
run_step "Install Python Server Dependencies" bash -c "
|
|
||||||
source '${venvFolder}/bin/activate'
|
|
||||||
pip install --upgrade pip > /dev/null
|
|
||||||
pip install --no-input -r '${dataSource}/server-requirements.txt'
|
|
||||||
"
|
|
||||||
|
|
||||||
# Copy Python server components
|
|
||||||
run_step "Copy Python Server Components" bash -c "
|
|
||||||
rm -rf '${dataDestination}' && mkdir -p '${dataDestination}'
|
|
||||||
cp -r '${dataSource}/Python_API_Endpoints' '${dataDestination}/'
|
|
||||||
cp -r '${dataSource}/Sounds' '${dataDestination}/'
|
|
||||||
cp -r '${dataSource}/Workflows' '${dataDestination}/'
|
|
||||||
cp '${dataSource}/server.py' '${dataDestination}/'
|
|
||||||
"
|
|
||||||
|
|
||||||
# Setup Vite WebUI assets
|
|
||||||
run_step "Setup Vite WebUI assets" bash -c "
|
|
||||||
rm -rf '${webUIDestination}' && mkdir -p '${webUIDestination}'
|
|
||||||
cp -r '${customUIPath}/'* '${webUIDestination}/'
|
|
||||||
"
|
|
||||||
|
|
||||||
# Install NPM packages for Vite
|
|
||||||
run_step "Install Vite Web Frontend NPM Packages" bash -c "
|
|
||||||
cd '${webUIDestination}'
|
|
||||||
npm install --silent --no-fund --audit=false
|
|
||||||
cd - > /dev/null
|
|
||||||
"
|
|
||||||
|
|
||||||
# Launch Vite Web Frontend in Dev Mode
|
|
||||||
run_step "Start Vite Web Frontend (Dev Mode)" bash -c "
|
|
||||||
cd '${webUIDestination}'
|
|
||||||
npm run dev --silent
|
|
||||||
cd - > /dev/null
|
|
||||||
"
|
|
||||||
|
|
||||||
# Launch Flask server
|
|
||||||
echo -e "\n${GREEN}Launching Borealis Flask Server...${RESET}"
|
|
||||||
echo "===================================================================================="
|
|
||||||
source '${venvFolder}/bin/activate'
|
|
||||||
python3 "${dataDestination}/server.py"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
launch_agent() {
|
check_version_cmd() {
|
||||||
echo -e "${GREEN}Deploying Borealis Agent...${RESET}"
|
# $1 = cmd, $2 = min version, e.g. check_version_cmd node 18
|
||||||
echo "===================================================================================="
|
if ! command -v "$1" >/dev/null; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
local ver=\$("$1" --version 2>/dev/null | grep -Eo '[0-9.]+' | head -n1 | cut -d. -f1)
|
||||||
|
[ "\$ver" -ge "\$2" ] 2>/dev/null
|
||||||
|
}
|
||||||
|
# =================== Menu Functions ===================
|
||||||
|
menu_server() {
|
||||||
|
clear
|
||||||
|
ascii_banner
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}Configure Borealis Server Mode:${RESET}"
|
||||||
|
echo -e " 1) Build & Launch > ${DARKGRAY}Production Flask Server${RESET} ${CYAN}@ http://localhost:5000${RESET}"
|
||||||
|
echo -e " 2) [Skip Build] & Immediately Launch > ${DARKGRAY}Production Flask Server${RESET} ${CYAN}@ http://localhost:5000${RESET}"
|
||||||
|
echo -e " 3) Launch > ${DARKGRAY}[Hotload-Ready]${RESET} ${GREEN}Vite Dev Server${RESET} ${CYAN}@ http://localhost:5173${RESET}"
|
||||||
|
echo -ne "${CYAN}Enter choice [1/2/3]: ${RESET}"
|
||||||
|
read mode_choice
|
||||||
|
|
||||||
detect_distro
|
borealis_operation_mode="production"
|
||||||
|
if [ "\$mode_choice" = "3" ]; then
|
||||||
|
borealis_operation_mode="developer"
|
||||||
|
fi
|
||||||
|
|
||||||
|
venvFolder="Server"
|
||||||
|
dataSource="Data/Server"
|
||||||
|
dataDestination="\${venvFolder}/Borealis"
|
||||||
|
customUIPath="\${dataSource}/WebUI"
|
||||||
|
webUIDestination="\${venvFolder}/web-interface"
|
||||||
|
venvPython="\${venvFolder}/bin/python3"
|
||||||
|
|
||||||
|
# ---- Build mode 1: always build ----
|
||||||
|
if [ "\$mode_choice" = "1" ] || [ "\$mode_choice" = "3" ]; then
|
||||||
|
run_step "Install System Dependencies" install_core_dependencies
|
||||||
|
run_step "Ensure Tesseract Traineddata" ensure_tesseract_data
|
||||||
|
run_step "Create Python Virtual Environment" bash -c "if [ ! -f '\${venvFolder}/bin/activate' ]; then python3 -m venv '\${venvFolder}'; fi"
|
||||||
|
run_step "Install Python Server Dependencies" bash -c "source '\${venvFolder}/bin/activate'; pip install --upgrade pip > /dev/null; pip install --no-input -r '\${dataSource}/server-requirements.txt'"
|
||||||
|
run_step "Copy Python Server Components" bash -c "rm -rf '\${dataDestination}' && mkdir -p '\${dataDestination}'; cp -r '\${dataSource}/Python_API_Endpoints' '\${dataDestination}/'; cp -r '\${dataSource}/Sounds' '\${dataDestination}/'; cp -r '\${dataSource}/Workflows' '\${dataDestination}/'; cp '\${dataSource}/server.py' '\${dataDestination}/'"
|
||||||
|
run_step "Setup Vite WebUI assets" bash -c "rm -rf '\${webUIDestination}' && mkdir -p '\${webUIDestination}'; cp -r '\${customUIPath}/'* '\${webUIDestination}/'"
|
||||||
|
run_step "Install Vite Web Frontend NPM Packages" bash -c "cd '\${webUIDestination}'; npm install --silent --no-fund --audit=false; cd - > /dev/null"
|
||||||
|
fi
|
||||||
|
# ---- Build mode 2: skip build ----
|
||||||
|
if [ "\$mode_choice" = "2" ]; then
|
||||||
|
# No build steps, just activate venv and launch.
|
||||||
|
run_step "Install System Dependencies" install_core_dependencies
|
||||||
|
run_step "Ensure Tesseract Traineddata" ensure_tesseract_data
|
||||||
|
[ ! -f '\${venvFolder}/bin/activate' ] && { echo -e "\${RED}\${CROSSMARK} Server venv not found! Run option 1 first.\${RESET}"; exit 1; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- Start Vite frontend in proper mode ----
|
||||||
|
if [ "\$borealis_operation_mode" = "developer" ]; then
|
||||||
|
run_step "Start Vite Web Frontend (Dev Mode)" bash -c "cd '\${webUIDestination}'; npm run dev --silent; cd - > /dev/null &"
|
||||||
|
else
|
||||||
|
run_step "Vite Web Frontend: Build for Production" bash -c "cd '\${webUIDestination}'; npm run build --silent; cd - > /dev/null"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---- Start Flask server ----
|
||||||
|
echo -e "\n${GREEN}Launching Borealis Flask Server...${RESET}"
|
||||||
|
echo "===================================================================================="
|
||||||
|
source "\${venvFolder}/bin/activate"
|
||||||
|
python3 "\${dataDestination}/server.py"
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_agent() {
|
||||||
|
clear
|
||||||
|
ascii_banner
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}Deploying Borealis Agent...${RESET}"
|
||||||
|
echo "===================================================================================="
|
||||||
run_step "Install System Dependencies" install_core_dependencies
|
run_step "Install System Dependencies" install_core_dependencies
|
||||||
|
|
||||||
venvFolder="Agent"
|
venvFolder="Agent"
|
||||||
agentSourcePath="Data/Agent/borealis-agent.py"
|
agentSourcePath="Data/Agent/borealis-agent.py"
|
||||||
agentRequirements="Data/Agent/agent-requirements.txt"
|
agentRequirements="Data/Agent/agent-requirements.txt"
|
||||||
agentDestinationFolder="${venvFolder}/Borealis"
|
agentDestinationFolder="\${venvFolder}/Borealis"
|
||||||
|
|
||||||
run_step "Create Virtual Python Environment for Agent" bash -c "
|
|
||||||
if [ ! -f '${venvFolder}/bin/activate' ]; then
|
|
||||||
python3 -m venv '${venvFolder}'
|
|
||||||
fi
|
|
||||||
"
|
|
||||||
|
|
||||||
run_step "Install Agent Dependencies" bash -c "
|
|
||||||
source '${venvFolder}/bin/activate'
|
|
||||||
pip install --upgrade pip > /dev/null
|
|
||||||
pip install --no-input -r '${agentRequirements}'
|
|
||||||
"
|
|
||||||
|
|
||||||
run_step "Copy Agent Script" bash -c "
|
|
||||||
mkdir -p '${agentDestinationFolder}'
|
|
||||||
cp '${agentSourcePath}' '${agentDestinationFolder}/'
|
|
||||||
"
|
|
||||||
|
|
||||||
|
run_step "Create Python Virtual Environment for Agent" bash -c "if [ ! -f '\${venvFolder}/bin/activate' ]; then python3 -m venv '\${venvFolder}'; fi"
|
||||||
|
run_step "Install Agent Dependencies" bash -c "source '\${venvFolder}/bin/activate'; pip install --upgrade pip > /dev/null; pip install --no-input -r '\${agentRequirements}'"
|
||||||
|
run_step "Copy Agent Script" bash -c "mkdir -p '\${agentDestinationFolder}'; cp '\${agentSourcePath}' '\${agentDestinationFolder}/'"
|
||||||
echo -e "\n${GREEN}Launching Borealis Agent...${RESET}"
|
echo -e "\n${GREEN}Launching Borealis Agent...${RESET}"
|
||||||
echo "===================================================================================="
|
echo "===================================================================================="
|
||||||
source '${venvFolder}/bin/activate'
|
source "\${venvFolder}/bin/activate"
|
||||||
python3 "${agentDestinationFolder}/borealis-agent.py"
|
python3 "\${agentDestinationFolder}/borealis-agent.py"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Main menu
|
menu_electron() {
|
||||||
|
clear
|
||||||
|
ascii_banner
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}Deploying Borealis Electron Desktop App...${RESET}"
|
||||||
|
echo "===================================================================================="
|
||||||
|
electronSource="Data/Electron"
|
||||||
|
electronDestination="ElectronApp"
|
||||||
|
venvFolder="Server"
|
||||||
|
webUIDestination="\${venvFolder}/web-interface"
|
||||||
|
staticBuild="\${webUIDestination}/build"
|
||||||
|
|
||||||
echo -e "${GREEN}Deploying Borealis - Workflow Automation Tool...${RESET}"
|
run_step "Install System Dependencies" install_core_dependencies
|
||||||
echo "===================================================================================="
|
run_step "Prepare ElectronApp folder" bash -c "rm -rf '\${electronDestination}'; mkdir -p '\${electronDestination}'; cp -r '\${venvFolder}/Borealis' '\${electronDestination}/Server'; cp '\${electronSource}/package.json' '\${electronDestination}/'; cp '\${electronSource}/main.js' '\${electronDestination}/'; cp -r '\${staticBuild}/'* '\${electronDestination}/renderer/'"
|
||||||
echo "Please choose which module you want to launch / (re)deploy:"
|
run_step "Install Electron dependencies" bash -c "cd '\${electronDestination}'; npm install --silent --no-fund --audit=false; cd - > /dev/null"
|
||||||
echo "- Server (Web Dashboard) [1]"
|
run_step "ElectronApp: Package with electron-builder" bash -c "cd '\${electronDestination}'; npm run dist; cd - > /dev/null"
|
||||||
echo "- Agent (Local/Remote Client) [2]"
|
run_step "ElectronApp: Launch in dev mode" bash -c "cd '\${electronDestination}'; npm run dev; cd - > /dev/null"
|
||||||
|
}
|
||||||
|
|
||||||
read -p "Enter 1 or 2: " choice
|
menu_packager() {
|
||||||
|
clear
|
||||||
|
ascii_banner
|
||||||
|
echo ""
|
||||||
|
echo -e "${CYAN}Packager: Build Standalone EXE/Binary via PyInstaller${RESET}"
|
||||||
|
echo "1) Package Borealis Server"
|
||||||
|
echo "2) Package Borealis Agent"
|
||||||
|
echo -ne "${CYAN}Enter choice [1/2]: ${RESET}"
|
||||||
|
read exe_choice
|
||||||
|
if [ "\$exe_choice" = "1" ]; then
|
||||||
|
(cd Data/Server && bash Package-Borealis-Server.sh)
|
||||||
|
elif [ "\$exe_choice" = "2" ]; then
|
||||||
|
(cd Data/Agent && bash Package_Borealis-Agent.sh)
|
||||||
|
else
|
||||||
|
echo -e "\${RED}Invalid Choice. Exiting...\${RESET}"; exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
case "${choice}" in
|
menu_update() {
|
||||||
1) launch_server ;;
|
clear
|
||||||
2) launch_agent ;;
|
ascii_banner
|
||||||
*) echo -e "${YELLOW}Invalid selection. Exiting...${RESET}"; exit 1 ;;
|
echo ""
|
||||||
|
echo -e "${CYAN}Updating Borealis...${RESET}"
|
||||||
|
scriptDir="\$(dirname "\$0")"
|
||||||
|
updateZip="Update_Staging/main.zip"
|
||||||
|
updateDir="Update_Staging/borealis"
|
||||||
|
preservePath="Data/Server/Python_API_Endpoints/Tesseract-OCR"
|
||||||
|
preserveBackupPath="Update_Staging/Tesseract-OCR"
|
||||||
|
|
||||||
|
run_step "Updating: Move Tesseract-OCR Folder Somewhere Safe to Restore Later" bash -c "[ -d '\$preservePath' ] && mkdir -p Update_Staging && mv '\$preservePath' '\$preserveBackupPath'"
|
||||||
|
run_step "Updating: Clean Up Folders to Prepare for Update" bash -c "rm -rf Data Server/web-interface/src Server/web-interface/build Server/web-interface/public Server/Borealis"
|
||||||
|
run_step "Updating: Create Update Staging Folder" bash -c "mkdir -p Update_Staging"
|
||||||
|
run_step "Updating: Download Update" curl -L -o "\$updateZip" "https://git.bunny-lab.io/bunny-lab/Borealis/archive/main.zip"
|
||||||
|
run_step "Updating: Extract Update Files" bash -c "unzip -o '\$updateZip' -d Update_Staging"
|
||||||
|
run_step "Updating: Copy Update Files into Production Borealis Root Folder" bash -c "cp -r '\$updateDir/'* ."
|
||||||
|
run_step "Updating: Restore Tesseract-OCR Folder" bash -c "[ -d '\$preserveBackupPath' ] && mkdir -p Data/Server/Python_API_Endpoints && mv '\$preserveBackupPath' Data/Server/Python_API_Endpoints/"
|
||||||
|
run_step "Updating: Clean Up Update Staging Folder" bash -c "rm -rf Update_Staging"
|
||||||
|
echo -e "\n${GREEN}Update Complete! Please Re-Launch the Borealis Script.${RESET}"
|
||||||
|
pause_prompt
|
||||||
|
exec bash "\$0"
|
||||||
|
}
|
||||||
|
|
||||||
|
# =================== MAIN MENU ===================
|
||||||
|
clear
|
||||||
|
ascii_banner
|
||||||
|
echo "Please choose which function you want to launch:"
|
||||||
|
echo -e " 1) Borealis Server"
|
||||||
|
echo -e " 2) Borealis Agent"
|
||||||
|
echo -e " 3) Build Electron App ${DARKGRAY}[Experimental]${RESET}"
|
||||||
|
echo -e " 4) Package Self-Contained EXE of Server or Agent ${DARKGRAY}[Experimental]${RESET}"
|
||||||
|
echo -e " 5) Update Borealis ${DARKGRAY}[Requires Re-Build]${RESET}"
|
||||||
|
echo -e "Type a number and press ${CYAN}<ENTER>${RESET}"
|
||||||
|
read choice
|
||||||
|
|
||||||
|
case "\$choice" in
|
||||||
|
1) menu_server ;;
|
||||||
|
2) menu_agent ;;
|
||||||
|
3) menu_electron ;;
|
||||||
|
4) menu_packager ;;
|
||||||
|
5) menu_update ;;
|
||||||
|
*) echo -e "\${YELLOW}Invalid selection. Exiting...\${RESET}"; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user