#!/usr/bin/env bash # 在宿主机物理目录自动配置环境(无 Docker) # 数据落盘:$ROOT/.runtime/{postgres,venv,logs,pids} 与 platform/data/uploads # shellcheck disable=SC1091 set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=common.sh source "$SCRIPT_DIR/common.sh" c_info "根目录(物理): $ROOT" c_info "运行时目录: $RUNTIME" c_info "上传目录: $UPLOAD_DIR" need_pkgs=() have_cmd curl || need_pkgs+=(curl) have_cmd git || need_pkgs+=(git) have_cmd go || need_pkgs+=(golang-go) have_cmd python3 || need_pkgs+=(python3) have_cmd pip3 || need_pkgs+=(python3-pip) python3 -c "import venv" 2>/dev/null || need_pkgs+=(python3-venv) have_cmd node || need_pkgs+=(nodejs) have_cmd npm || need_pkgs+=(npm) have_cmd psql || need_pkgs+=(postgresql-client) have_cmd initdb || have_cmd pg_ctl || need_pkgs+=(postgresql) install_pkgs() { local os os="$(detect_os)" c_info "安装系统包 (OS=$os): ${need_pkgs[*]}" case "$os" in ubuntu|debian|linuxmint|pop) sudo_run apt-get update -y local pkgs=() for p in "${need_pkgs[@]}"; do case "$p" in golang-go) pkgs+=(golang-go) ;; python3) pkgs+=(python3 python3-venv python3-dev) ;; python3-pip) pkgs+=(python3-pip) ;; python3-venv) pkgs+=(python3-venv) ;; nodejs) pkgs+=(nodejs) ;; npm) pkgs+=(npm) ;; postgresql) pkgs+=(postgresql postgresql-contrib) ;; postgresql-client) pkgs+=(postgresql-client) ;; *) pkgs+=("$p") ;; esac done sudo_run apt-get install -y "${pkgs[@]}" ;; fedora|rhel|centos|rocky|almalinux) local pkgs=() for p in "${need_pkgs[@]}"; do case "$p" in golang-go) pkgs+=(golang) ;; python3-pip) pkgs+=(python3-pip) ;; python3-venv) pkgs+=(python3) ;; postgresql) pkgs+=(postgresql-server postgresql) ;; postgresql-client) pkgs+=(postgresql) ;; *) pkgs+=("$p") ;; esac done if have_cmd dnf; then sudo_run dnf install -y "${pkgs[@]}" else sudo_run yum install -y "${pkgs[@]}"; fi ;; arch|manjaro) local pkgs=() for p in "${need_pkgs[@]}"; do case "$p" in golang-go) pkgs+=(go) ;; python3) pkgs+=(python) ;; python3-pip) pkgs+=(python-pip) ;; python3-venv) ;; postgresql-client) pkgs+=(postgresql) ;; *) pkgs+=("$p") ;; esac done sudo_run pacman -Sy --noconfirm "${pkgs[@]}" ;; *) c_err "未识别发行版 $os,请手动安装: go python3 node npm postgresql curl" return 1 ;; esac } if ((${#need_pkgs[@]} > 0)); then install_pkgs else c_ok "系统依赖已满足" fi missing=() for c in go python3 curl; do have_cmd "$c" || missing+=("$c"); done have_cmd node || have_cmd nodejs || missing+=("node") have_cmd npm || missing+=("npm") if ((${#missing[@]} > 0)); then c_err "仍缺少命令: ${missing[*]}" exit 1 fi c_ok "$(go version)" c_info "配置 Python venv → $VENV_DIR" if [[ ! -d "$VENV_DIR" ]]; then python3 -m venv "$VENV_DIR" fi # shellcheck source=/dev/null source "$VENV_DIR/bin/activate" pip install -U pip wheel >/dev/null pip install -r "$ROOT/ai-service/requirements.txt" pip install -r "$ROOT/agent_sdk/requirements.txt" c_ok "venv 依赖已安装" c_info "安装前端依赖 → $ROOT/web/node_modules" if [[ ! -d "$ROOT/web/node_modules" ]]; then (cd "$ROOT/web" && npm install) else c_ok "web/node_modules 已存在" fi find_pg_bin() { local name="$1" if have_cmd "$name"; then command -v "$name"; return; fi local d for d in /usr/lib/postgresql/*/bin /usr/pgsql-*/bin; do if [[ -x "$d/$name" ]]; then echo "$d/$name"; return; fi done return 1 } INITDB="$(find_pg_bin initdb || true)" PG_CTL="$(find_pg_bin pg_ctl || true)" PSQL="$(find_pg_bin psql || true)" ensure_local_postgres() { if [[ -z "$INITDB" || -z "$PG_CTL" || -z "$PSQL" ]]; then c_warn "未找到 initdb/pg_ctl/psql,跳过本地库初始化(请自备 Postgres)" return 0 fi # 已有可连库则复用 if PGPASSWORD="$PG_PASS" "$PSQL" -h 127.0.0.1 -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" -c "SELECT 1" >/dev/null 2>&1; then c_ok "复用已有 Postgres $PG_USER@$PG_DB:$PG_PORT" PGPASSWORD="$PG_PASS" "$PSQL" -h 127.0.0.1 -p "$PG_PORT" -U "$PG_USER" -d "$PG_DB" \ -c "ALTER USER $PG_USER CREATEDB;" >/dev/null 2>&1 || true return 0 fi mkdir -p "$PGDATA" "$RUNTIME/pg_sockets" if [[ ! -f "$PGDATA/PG_VERSION" ]]; then c_info "initdb → $PGDATA (物理目录)" "$INITDB" -D "$PGDATA" --auth=trust -U postgres { echo "" echo "listen_addresses = '127.0.0.1'" echo "port = $PG_PORT" echo "unix_socket_directories = '$RUNTIME/pg_sockets'" } >> "$PGDATA/postgresql.conf" fi if ! "$PG_CTL" -D "$PGDATA" status >/dev/null 2>&1; then c_info "启动本地 Postgres" "$PG_CTL" -D "$PGDATA" -l "$LOG_DIR/postgres.log" -o "-k $RUNTIME/pg_sockets" start sleep 1 fi local sock="$RUNTIME/pg_sockets" "$PSQL" -h "$sock" -U postgres -d postgres -v ON_ERROR_STOP=1 </dev/null 2>&1; then # 补充密码认证 cat > "$PGDATA/pg_hba.conf" </dev/null c_ok "Postgres 就绪 (物理 data=$PGDATA)" } ensure_local_postgres c_info "编译 platform / gateway" (cd "$ROOT/platform" && go build -o platform .) (cd "$ROOT/gateway" && go build -o gateway .) c_ok "二进制已生成" if [[ ! -f "$ROOT/ai-service/sample_inventory.xlsx" ]]; then (cd "$ROOT/ai-service" && "$VENV_DIR/bin/python" make_sample_excel.py) || true fi date -Iseconds > "$RUNTIME/setup.ok" cat > "$RUNTIME/env.sh" <