/
Targy
/
OpenGEA
Обзор
Документация
Войти
/
Targy
/
OpenGEA
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
scripts/run.sh
251 строка
8 KB
kotler
OpenGEA: усечённый релиз для opensource
14 мар 2026, 19:23
14 мар 2026, 19:23
cae5e88
Код
Авторство
О чём код?
#!/usr/bin/env bash # Запуск/остановка/перезапуск OpenGEA: бэкенд (FastAPI), фронтенд (Vite), агенты. # Процессы запускаются в фоне с выводом в логи; скрипт сразу возвращает управление. # Запуск из корня репозитория: ./scripts/run.sh start|stop|restart|rebuild [backend|frontend|agents|all] set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" BACKEND="$REPO_ROOT/backend" FRONTEND="$REPO_ROOT/frontend" PORTS_YAML="$BACKEND/agents/ports.yaml" PID_DIR="${GEA_PID_DIR:-/tmp/gea-pids}" LOG_DIR="${GEA_LOG_DIR:-$PID_DIR/logs}" VENV="${GEA_VENV:-$REPO_ROOT/.venv}" [ -d "$BACKEND/.venv" ] && [ ! -d "$VENV" ] && VENV="$BACKEND/.venv" BACKEND_PORT="${GEA_BACKEND_PORT:-8000}" FRONTEND_PORTS="${GEA_FRONTEND_PORTS:-5174 5175 5176}" mkdir -p "$PID_DIR" "$LOG_DIR" # Цвета и префиксы (только при выводе в TTY) if [ -t 1 ]; then R='\033[0;31m'; G='\033[0;32m'; B='\033[0;34m'; Y='\033[0;33m'; N='\033[0m' OK="[OK]"; ERR="[ERROR]"; INF="[INFO]" else R=; G=; B=; Y=; N= OK="[OK]"; ERR="[ERROR]"; INF="[INFO]" fi print_banner() { if [ -t 1 ]; then echo -e "${B}" echo ' ____ _____ _ ' echo ' / ___| ____| / \ ' echo '| | _| _| / _ \ ' echo '| |_| | |___ / ___ \ ' echo ' \____|_____/_/ \_\' echo -e "${N}" fi } usage() { echo "Usage: $0 start|stop|restart|rebuild [backend|frontend|agents|all]" echo " start start the selected target(s) in background (logs: $LOG_DIR)" echo " stop stop the selected target(s) and free their ports" echo " restart stop then start" echo " rebuild build frontend (npm run build) then restart selected target(s)" echo " target backend (:$BACKEND_PORT) | frontend (:$FRONTEND_PORTS) | agents | all (default)" echo "" echo " To stop everything: $0 stop or ./scripts/stop.sh" echo "PIDs: $PID_DIR Logs: $LOG_DIR" exit 0 } # Освободить порт (убить процесс, слушающий порт) kill_port() { local port="$1" local pids pids=$(lsof -ti ":$port" 2>/dev/null | tr '\n' ' ') || true if [ -n "$pids" ]; then echo -e "${B}${INF}${N} Freeing port $port (PIDs: $pids)" echo "$pids" | xargs kill -9 2>/dev/null || true sleep 0.2 fi } # Список портов агентов из ports.yaml get_agent_ports() { grep -E '^[a-z0-9_-]+: [0-9]+' "$PORTS_YAML" 2>/dev/null | sed 's/.*: *//' | tr -d ' ' | sort -n -u } # Освободить порты перед запуском цели free_ports() { local target="$1" case "$target" in backend) kill_port "$BACKEND_PORT" ;; frontend) for p in $FRONTEND_PORTS; do kill_port "$p"; done ;; agents) for p in $(get_agent_ports); do kill_port "$p"; done ;; all) kill_port "$BACKEND_PORT" for p in $FRONTEND_PORTS; do kill_port "$p"; done for p in $(get_agent_ports); do kill_port "$p"; done ;; esac } # Очистить логи для цели перед стартом (свежие логи с временными метками) rotate_logs() { local target="$1" case "$target" in backend) : > "$LOG_DIR/backend.log" ;; frontend) : > "$LOG_DIR/frontend.log" ;; agents) for f in "$LOG_DIR"/agent-*.log; do [ -f "$f" ] && : > "$f" || true; done ;; all) : > "$LOG_DIR/backend.log" : > "$LOG_DIR/frontend.log" for f in "$LOG_DIR"/agent-*.log; do [ -f "$f" ] && : > "$f" || true; done ;; *) ;; esac } # --- Backend --- start_backend() { free_ports backend local pidfile="$PID_DIR/gea-backend.pid" if [ -f "$pidfile" ] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then echo -e "${G}${OK}${N} Backend already running (PID $(cat "$pidfile"))" return 0 fi rm -f "$pidfile" nohup bash -c "cd \"$BACKEND\" && \"${VENV}/bin/python\" -m uvicorn api.main:app --host 0.0.0.0 --port $BACKEND_PORT 2>&1 | \"${VENV}/bin/python\" -u \"$SCRIPT_DIR/ts_log.py\"" >> "$LOG_DIR/backend.log" 2>&1 & echo $! > "$pidfile" echo -e "${G}${OK}${N} Backend started on port $BACKEND_PORT (PID $(cat "$pidfile")), log: $LOG_DIR/backend.log" } stop_backend() { kill_port "$BACKEND_PORT" local pidfile="$PID_DIR/gea-backend.pid" if [ -f "$pidfile" ]; then local pid=$(cat "$pidfile") kill "$pid" 2>/dev/null || true rm -f "$pidfile" echo -e "${G}${OK}${N} Backend stopped (was PID $pid)" else echo -e "${B}${INF}${N} Backend not running" fi } # --- Frontend --- start_frontend() { # npm может быть недоступен в PATH при nohup (nvm/fnm); подставляем явный путь local npm_cmd npm_cmd=$(command -v npm 2>/dev/null) || true if [ -z "$npm_cmd" ] && [ -f "$HOME/.nvm/nvm.sh" ]; then # shellcheck source=/dev/null . "$HOME/.nvm/nvm.sh" npm_cmd=$(command -v npm 2>/dev/null) || true fi if [ -z "$npm_cmd" ]; then echo "Error: npm not found. Install Node.js/npm or run from a shell where npm is in PATH." return 1 fi free_ports frontend local pidfile="$PID_DIR/gea-frontend.pid" if [ -f "$pidfile" ] && kill -0 "$(cat "$pidfile")" 2>/dev/null; then echo -e "${G}${OK}${N} Frontend already running (PID $(cat "$pidfile"))" return 0 fi rm -f "$pidfile" nohup env PATH="$PATH" bash -c "cd \"$FRONTEND\" && \"$npm_cmd\" run dev 2>&1 | \"${VENV}/bin/python\" -u \"$SCRIPT_DIR/ts_log.py\"" >> "$LOG_DIR/frontend.log" 2>&1 & echo $! > "$pidfile" echo -e "${G}${OK}${N} Frontend started (PID $(cat "$pidfile")), log: $LOG_DIR/frontend.log" } # Убить процесс и его дочерние (npm run dev порождает bash -> npm -> node) kill_process_tree() { local pid="$1" [ -z "$pid" ] && return if kill -0 "$pid" 2>/dev/null; then local child for child in $(pgrep -P "$pid" 2>/dev/null); do kill_process_tree "$child" done kill -9 "$pid" 2>/dev/null || true fi } stop_frontend() { # Сначала освобождаем порты (vite может быть дочерним процессом) for p in $FRONTEND_PORTS; do kill_port "$p"; done local pidfile="$PID_DIR/gea-frontend.pid" if [ -f "$pidfile" ]; then local pid pid=$(cat "$pidfile") kill_process_tree "$pid" rm -f "$pidfile" echo -e "${G}${OK}${N} Frontend stopped (was PID $pid)" else echo -e "${B}${INF}${N} Frontend not running" fi } # --- Frontend build (для rebuild) --- build_frontend() { local npm_cmd npm_cmd=$(command -v npm 2>/dev/null) || true if [ -z "$npm_cmd" ] && [ -f "$HOME/.nvm/nvm.sh" ]; then # shellcheck source=/dev/null . "$HOME/.nvm/nvm.sh" npm_cmd=$(command -v npm 2>/dev/null) || true fi if [ -z "$npm_cmd" ]; then echo "Error: npm not found. Install Node.js/npm or run from a shell where npm is in PATH." return 1 fi echo -e "${B}${INF}${N} Building frontend (npm run build)..." (cd "$FRONTEND" && env PATH="$PATH" "$npm_cmd" run build) echo -e "${G}${OK}${N} Frontend build done." } # --- Agents (delegate to start-agents.sh; порты освобождаются внутри) --- start_agents() { free_ports agents GEA_VENV="$VENV" GEA_PID_DIR="$PID_DIR" GEA_LOG_DIR="$LOG_DIR" "$SCRIPT_DIR/start-agents.sh" --all } stop_agents() { GEA_PID_DIR="$PID_DIR" "$SCRIPT_DIR/stop-agents.sh" --all for p in $(get_agent_ports); do kill_port "$p"; done } # --- Dispatch --- run_start() { print_banner rotate_logs "$1" case "$1" in backend) start_backend ;; frontend) start_frontend ;; agents) start_agents ;; all) start_backend; start_frontend; start_agents ;; *) echo "Unknown target: $1"; usage ;; esac if [ "$1" = "all" ] || [ "$1" = "frontend" ]; then echo "" echo -e " ${B}→ http://localhost:${FRONTEND_PORTS%% *}${N}" fi } run_stop() { case "$1" in backend) stop_backend ;; frontend) stop_frontend ;; agents) stop_agents ;; all) stop_backend; stop_frontend; stop_agents ;; *) echo "Unknown target: $1"; usage ;; esac } run_rebuild() { build_frontend || return 1 run_stop "$1" run_start "$1" } CMD="${1:-}" TARGET="${2:-all}" case "$CMD" in start) run_start "$TARGET" ;; stop) run_stop "$TARGET" ;; restart) run_stop "$TARGET"; run_start "$TARGET" ;; rebuild) run_rebuild "$TARGET" ;; -h|--help) usage ;; *) echo "Unknown command: $CMD"; usage ;; esac