#!/usr/bin/env bash # crypto_okx_hub 一键环境部署(Ubuntu / root /opt/crypto_okx_hub) # # 用法: # bash deploy/setup_env.sh # bash deploy/setup_env.sh --skip-pm2 # bash deploy/setup_env.sh --recreate-venv # bash deploy/setup_env.sh --install-system-deps # set -e set -u if [ -n "${BASH_VERSION:-}" ]; then set -o pipefail fi DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" REQ_FILE="${REPO_ROOT}/requirements.txt" # shellcheck source=lib/common.sh source "${DEPLOY_DIR}/lib/common.sh" SKIP_PM2=0 SKIP_ENV_COPY=0 RECREATE_VENV=0 INSTALL_APT_DEPS=0 PY="" usage() { sed -n '2,10p' "$0" | sed 's/^# \?//' exit "${1:-0}" } while [[ $# -gt 0 ]]; do case "$1" in --skip-pm2) SKIP_PM2=1; shift ;; --skip-env-copy) SKIP_ENV_COPY=1; shift ;; --recreate-venv) RECREATE_VENV=1; shift ;; --install-system-deps) INSTALL_APT_DEPS=1; shift ;; -h|--help) usage 0 ;; *) echo "未知参数: $1" >&2; usage 1 ;; esac done find_python() { if command -v python3 >/dev/null 2>&1; then echo python3 return fi if command -v python >/dev/null 2>&1; then echo python return fi echo "未找到 python3/python,请先安装 Python 3.10+" >&2 exit 1 } check_python_version() { local py="$1" local ver ver="$("${py}" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" local major minor major="${ver%%.*}" minor="${ver#*.}" if [[ "${major}" -lt 3 ]] || [[ "${major}" -eq 3 && "${minor}" -lt 10 ]]; then echo "需要 Python 3.10+,当前: ${ver}" >&2 exit 1 fi echo "Python: $("${py}" --version 2>&1)" } python_minor_version() { local py="$1" "${py}" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' } check_venv_available() { local py="$1" local tmp tmp="$(mktemp -d 2>/dev/null || mktemp -d -t cmvenv)" if "${py}" -m venv "${tmp}" >/dev/null 2>&1 && [[ -x "${tmp}/bin/python" ]]; then rm -rf "${tmp}" return 0 fi rm -rf "${tmp}" 2>/dev/null || true return 1 } install_debian_venv_packages() { local py="$1" local ver ver="$(python_minor_version "${py}")" if ! command -v apt-get >/dev/null 2>&1; then echo " 未检测到 apt-get,请手动安装 python${ver}-venv 与 python3-pip" >&2 return 1 fi if [[ "$(id -u)" -ne 0 ]]; then echo " 需要 root 安装系统包,请执行:" >&2 echo " sudo apt update && sudo apt install -y python${ver}-venv python3-pip curl" >&2 echo " 或: sudo bash deploy/setup_env.sh --install-system-deps" >&2 return 1 fi step "安装系统依赖 (python${ver}-venv) ..." export DEBIAN_FRONTEND=noninteractive apt-get update -qq if ! apt-get install -y "python${ver}-venv" python3-pip curl ca-certificates git; then apt-get install -y python3-venv python3-pip curl ca-certificates git fi } ensure_venv_prereqs() { local py="$1" if check_venv_available "${py}"; then return 0 fi echo " 当前 Python 无法创建 venv(缺少 ensurepip,常见于未安装 python*-venv)" >&2 if [[ "${INSTALL_APT_DEPS}" -eq 1 ]] || [[ "$(id -u)" -eq 0 ]]; then install_debian_venv_packages "${py}" || exit 1 if check_venv_available "${py}"; then return 0 fi fi local ver ver="$(python_minor_version "${py}")" echo "请安装后重试:" >&2 echo " apt update && apt install -y python${ver}-venv python3-pip" >&2 echo " bash deploy/setup_env.sh" >&2 exit 1 } create_project_venv() { local py="$1" if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then echo " 删除旧 venv ..." rm -rf .venv fi if [[ -d .venv && ! -x .venv/bin/python ]]; then echo " 清理未完成的 venv ..." rm -rf .venv fi if [[ -x .venv/bin/python ]]; then return 0 fi echo " 创建 venv ..." if ! "${py}" -m venv .venv; then rm -rf .venv 2>/dev/null || true echo " venv 创建失败" >&2 exit 1 fi } ensure_flask_secret() { local env_file="${REPO_ROOT}/.env" [[ -f "${env_file}" ]] || return 0 local line val line="$(grep -E '^[[:space:]]*FLASK_SECRET_KEY=' "${env_file}" | tail -n1 || true)" val="${line#*=}" val="$(echo "${val}" | tr -d '"' | tr -d "'" | xargs)" if [[ -z "${val}" || "${val}" == "change-me-to-long-random" || "${val}" == "hub-dev-secret" ]]; then local secret secret="$(python3 -c 'import secrets; print(secrets.token_urlsafe(32))' 2>/dev/null || openssl rand -hex 24)" if grep -qE '^[[:space:]]*FLASK_SECRET_KEY=' "${env_file}"; then sed -i "s|^[[:space:]]*FLASK_SECRET_KEY=.*|FLASK_SECRET_KEY=${secret}|" "${env_file}" else echo "FLASK_SECRET_KEY=${secret}" >>"${env_file}" fi echo " 已生成 FLASK_SECRET_KEY" else echo " 保留已有 FLASK_SECRET_KEY" fi } setup_app() { step "crypto_okx_hub" cd "${REPO_ROOT}" create_project_venv "${PY}" pip_upgrade_tools ".venv/bin/pip" pip_install_requirements ".venv/bin/pip" "${REQ_FILE}" "crypto_okx_hub 依赖" if [[ "${SKIP_ENV_COPY}" -eq 0 ]]; then if [[ -f .env.example && ! -f .env ]]; then cp -n .env.example .env 2>/dev/null || cp .env.example .env echo " 已复制 .env.example -> .env" elif [[ -f .env ]]; then echo " 保留已有 .env" else echo " 无 .env.example,请手动配置 .env" fi fi ensure_flask_secret echo " 完成: ${REPO_ROOT}/.venv/bin/python" } install_pm2_optional() { if [[ "${SKIP_PM2}" -eq 1 ]]; then return fi step "PM2(可选)" if ! command -v node >/dev/null 2>&1; then echo " 未检测到 Node.js,跳过.安装后执行: npm install -g pm2" return fi if command -v pm2 >/dev/null 2>&1; then echo " PM2 已安装: $(pm2 -v)" return fi echo " 正在安装 pm2 ..." npm install -g pm2 } echo "crypto_okx_hub 环境部署" echo "仓库根目录: ${REPO_ROOT}" echo "远端仓库: ${GIT_URL}" [[ -f "${REQ_FILE}" ]] || { echo "缺少 ${REQ_FILE}" >&2; exit 1; } PY="$(find_python)" check_python_version "${PY}" ensure_venv_prereqs "${PY}" setup_app install_pm2_optional echo "" echo "部署完成.下一步:" echo " 1. 编辑 ${REPO_ROOT}/.env (默认账号 admin / admin123)" echo " 2. pm2 start ecosystem.config.cjs" echo " 或: bash deploy/manage.sh # 选 1" echo ""