diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..39a823d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Shell 脚本在仓库内统一 LF,避免 Linux 上 bash: pipefail: invalid option name(CRLF) +*.sh text eol=lf +deploy/** text eol=lf diff --git a/deploy/README.md b/deploy/README.md index df32684..c48e12c 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,68 +1,76 @@ -# 环境一键部署 - -为仓库内各子项目创建 Python 虚拟环境、安装依赖、初始化 `.env` 与静态目录。 - -## Windows(推荐) - -双击仓库根目录 **`一键部署.bat`**,或在 PowerShell 中: - -```powershell -cd C:\path\to\crypto_monitor -.\deploy\setup_env.ps1 -``` - -仅部署部分项目: - -```powershell -.\deploy\setup_env.ps1 -Only binance,gate_bot -``` - -重建虚拟环境: - -```powershell -.\deploy\setup_env.ps1 -RecreateVenv -``` - -跳过 PM2、跳过复制 `.env`: - -```powershell -.\deploy\setup_env.ps1 -SkipPm2 -SkipEnvCopy -``` - -## Linux / macOS - -```bash -cd /opt/crypto_monitor -bash deploy/setup_env.sh -bash deploy/setup_env.sh --only binance,gate -bash deploy/setup_env.sh --recreate-venv -``` - -## 脚本会做什么 - -| 步骤 | 说明 | -|------|------| -| 检查 Python | 需要 **3.10+** | -| `crypto_monitor_*` | 各目录 `.venv` + `pip install -r ../requirements.txt` | -| `manual_trading_hub` | 独立 `requirements.txt` | -| `.env` | 若不存在则从 `.env.example` 复制(**不覆盖**已有) | -| 目录 | 创建 `static/images`、`static/images/order_charts` | -| PM2 | 若已装 Node.js 且未 `-SkipPm2`,尝试 `npm install -g pm2` | - -## 部署之后 - -1. 编辑各子目录 **`.env`**(API、登录密码、SOCKS 代理等)。 -2. 本地试运行(以 Binance 为例): - - ```bash - cd crypto_monitor_binance - source .venv/bin/activate # Windows: .\.venv\Scripts\activate - python app.py - ``` - -3. 服务器长期运行见各目录 **《部署文档.md》**(SSH SOCKS、PM2)。 - -## 依赖说明 - -- 四个监控子项目共用仓库根目录 **[requirements.txt](../requirements.txt)**。 -- 走 SOCKS 代理时必须安装 **PySocks**(已包含在 requirements 中)。 +# 环境一键部署 + +为仓库内各子项目创建 Python 虚拟环境、安装依赖、初始化 `.env` 与静态目录。 + +## Windows(推荐) + +双击仓库根目录 **`一键部署.bat`**,或在 PowerShell 中: + +```powershell +cd C:\path\to\crypto_monitor +.\deploy\setup_env.ps1 +``` + +仅部署部分项目: + +```powershell +.\deploy\setup_env.ps1 -Only binance,gate_bot +``` + +重建虚拟环境: + +```powershell +.\deploy\setup_env.ps1 -RecreateVenv +``` + +跳过 PM2、跳过复制 `.env`: + +```powershell +.\deploy\setup_env.ps1 -SkipPm2 -SkipEnvCopy +``` + +## Linux / macOS + +```bash +cd /opt/crypto_monitor +bash deploy/setup_env.sh +bash deploy/setup_env.sh --only binance,gate +bash deploy/setup_env.sh --recreate-venv +``` + +若在 Windows 编辑过脚本后在 Linux 报错 `set: pipefail: invalid option name`,先去掉 CRLF 再执行: + +```bash +sed -i 's/\r$//' deploy/setup_env.sh +# 或: apt install -y dos2unix && dos2unix deploy/setup_env.sh +bash deploy/setup_env.sh +``` + +## 脚本会做什么 + +| 步骤 | 说明 | +|------|------| +| 检查 Python | 需要 **3.10+** | +| `crypto_monitor_*` | 各目录 `.venv` + `pip install -r ../requirements.txt` | +| `manual_trading_hub` | 独立 `requirements.txt` | +| `.env` | 若不存在则从 `.env.example` 复制(**不覆盖**已有) | +| 目录 | 创建 `static/images`、`static/images/order_charts` | +| PM2 | 若已装 Node.js 且未 `-SkipPm2`,尝试 `npm install -g pm2` | + +## 部署之后 + +1. 编辑各子目录 **`.env`**(API、登录密码、SOCKS 代理等)。 +2. 本地试运行(以 Binance 为例): + + ```bash + cd crypto_monitor_binance + source .venv/bin/activate # Windows: .\.venv\Scripts\activate + python app.py + ``` + +3. 服务器长期运行见各目录 **《部署文档.md》**(SSH SOCKS、PM2)。 + +## 依赖说明 + +- 四个监控子项目共用仓库根目录 **[requirements.txt](../requirements.txt)**。 +- 走 SOCKS 代理时必须安装 **PySocks**(已包含在 requirements 中)。 diff --git a/deploy/setup_env.sh b/deploy/setup_env.sh index 7c2bd15..79ba17d 100644 --- a/deploy/setup_env.sh +++ b/deploy/setup_env.sh @@ -1,184 +1,189 @@ -#!/usr/bin/env bash -# crypto_monitor 一键环境部署(Linux / macOS / Git Bash) -# -# 用法: -# bash deploy/setup_env.sh -# bash deploy/setup_env.sh --only binance,gate_bot -# bash deploy/setup_env.sh --skip-pm2 -# bash deploy/setup_env.sh --recreate-venv -# -set -euo pipefail - -DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "${DEPLOY_DIR}/.." && pwd)" -REQ_FILE="${REPO_ROOT}/requirements.txt" -HUB_REQ="${REPO_ROOT}/manual_trading_hub/requirements.txt" - -ONLY="all" -SKIP_PM2=0 -SKIP_ENV_COPY=0 -RECREATE_VENV=0 - -usage() { - sed -n '2,12p' "$0" | sed 's/^# \?//' - exit "${1:-0}" -} - -while [[ $# -gt 0 ]]; do - case "$1" in - --only) ONLY="${2:-all}"; shift 2 ;; - --skip-pm2) SKIP_PM2=1; shift ;; - --skip-env-copy) SKIP_ENV_COPY=1; shift ;; - --recreate-venv) RECREATE_VENV=1; shift ;; - -h|--help) usage 0 ;; - *) echo "未知参数: $1" >&2; usage 1 ;; - esac -done - -step() { echo ""; echo "==> $*"; } - -should_include() { - local key="$1" - if [[ "${ONLY}" == "all" ]]; then - return 0 - fi - local item - IFS=',' read -ra PARTS <<< "${ONLY}" - for item in "${PARTS[@]}"; do - item="$(echo "${item}" | tr '[:upper:]' '[:lower:]' | xargs)" - [[ "${item}" == "${key}" ]] && return 0 - done - return 1 -} - -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)" -} - -setup_monitor() { - local dir_name="$1" - local proj="${REPO_ROOT}/${dir_name}" - if [[ ! -d "${proj}" ]]; then - echo " 跳过(目录不存在): ${dir_name}" - return - fi - step "${dir_name}" - cd "${proj}" - local py - py="$(find_python)" - if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then - echo " 删除旧 venv ..." - rm -rf .venv - fi - if [[ ! -x .venv/bin/python ]]; then - echo " 创建 venv ..." - "${py}" -m venv .venv - fi - echo " 升级 pip ..." - .venv/bin/python -m pip install -U pip setuptools wheel -q - echo " 安装依赖 ..." - .venv/bin/pip install -r "${REQ_FILE}" -q - 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 - mkdir -p static/images/order_charts - echo " 完成: ${proj}/.venv/bin/python" -} - -setup_hub() { - local proj="${REPO_ROOT}/manual_trading_hub" - if [[ ! -d "${proj}" ]]; then - echo " 跳过 hub(目录不存在)" - return - fi - step "manual_trading_hub" - cd "${proj}" - local py - py="$(find_python)" - if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then - rm -rf .venv - fi - if [[ ! -x .venv/bin/python ]]; then - "${py}" -m venv .venv - fi - .venv/bin/python -m pip install -U pip setuptools wheel -q - if [[ -f "${HUB_REQ}" ]]; then - .venv/bin/pip install -r "${HUB_REQ}" -q - fi - if [[ "${SKIP_ENV_COPY}" -eq 0 && -f .env.example && ! -f .env ]]; then - cp -n .env.example .env 2>/dev/null || cp .env.example .env - echo " 已复制 .env.example -> .env" - fi - echo " 完成: ${proj}/.venv/bin/python" -} - -install_pm2() { - 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 " 各子目录: pm2 start ecosystem.config.cjs" -} - -echo "crypto_monitor 环境部署" -echo "仓库根目录: ${REPO_ROOT}" - -[[ -f "${REQ_FILE}" ]] || { echo "缺少 ${REQ_FILE}" >&2; exit 1; } - -PY="$(find_python)" -check_python_version "${PY}" - -should_include binance && setup_monitor crypto_monitor_binance -should_include gate && setup_monitor crypto_monitor_gate -should_include gate_bot && setup_monitor crypto_monitor_gate_bot -should_include okx && setup_monitor crypto_monitor_okx -should_include hub && setup_hub - -install_pm2 - -echo "" -echo "部署完成。下一步:" -echo " 1. 编辑各子目录 .env" -echo " 2. 启动示例: cd crypto_monitor_binance && source .venv/bin/activate && python app.py" -echo " 3. Windows 可用: powershell -File deploy/setup_env.ps1" -echo "" +#!/usr/bin/env bash +# crypto_monitor 一键环境部署(Linux / macOS / Git Bash) +# +# 用法: +# bash deploy/setup_env.sh +# bash deploy/setup_env.sh --only binance,gate_bot +# bash deploy/setup_env.sh --skip-pm2 +# bash deploy/setup_env.sh --recreate-venv +# +set -e +set -u +# 避免 Windows CRLF 导致 set -euo pipefail 一行报错;pipefail 仅 bash 支持 +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" +HUB_REQ="${REPO_ROOT}/manual_trading_hub/requirements.txt" + +ONLY="all" +SKIP_PM2=0 +SKIP_ENV_COPY=0 +RECREATE_VENV=0 + +usage() { + sed -n '2,12p' "$0" | sed 's/^# \?//' + exit "${1:-0}" +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --only) ONLY="${2:-all}"; shift 2 ;; + --skip-pm2) SKIP_PM2=1; shift ;; + --skip-env-copy) SKIP_ENV_COPY=1; shift ;; + --recreate-venv) RECREATE_VENV=1; shift ;; + -h|--help) usage 0 ;; + *) echo "未知参数: $1" >&2; usage 1 ;; + esac +done + +step() { echo ""; echo "==> $*"; } + +should_include() { + local key="$1" + if [[ "${ONLY}" == "all" ]]; then + return 0 + fi + local item + IFS=',' read -ra PARTS <<< "${ONLY}" + for item in "${PARTS[@]}"; do + item="$(echo "${item}" | tr '[:upper:]' '[:lower:]' | xargs)" + [[ "${item}" == "${key}" ]] && return 0 + done + return 1 +} + +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)" +} + +setup_monitor() { + local dir_name="$1" + local proj="${REPO_ROOT}/${dir_name}" + if [[ ! -d "${proj}" ]]; then + echo " 跳过(目录不存在): ${dir_name}" + return + fi + step "${dir_name}" + cd "${proj}" + local py + py="$(find_python)" + if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then + echo " 删除旧 venv ..." + rm -rf .venv + fi + if [[ ! -x .venv/bin/python ]]; then + echo " 创建 venv ..." + "${py}" -m venv .venv + fi + echo " 升级 pip ..." + .venv/bin/python -m pip install -U pip setuptools wheel -q + echo " 安装依赖 ..." + .venv/bin/pip install -r "${REQ_FILE}" -q + 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 + mkdir -p static/images/order_charts + echo " 完成: ${proj}/.venv/bin/python" +} + +setup_hub() { + local proj="${REPO_ROOT}/manual_trading_hub" + if [[ ! -d "${proj}" ]]; then + echo " 跳过 hub(目录不存在)" + return + fi + step "manual_trading_hub" + cd "${proj}" + local py + py="$(find_python)" + if [[ "${RECREATE_VENV}" -eq 1 && -d .venv ]]; then + rm -rf .venv + fi + if [[ ! -x .venv/bin/python ]]; then + "${py}" -m venv .venv + fi + .venv/bin/python -m pip install -U pip setuptools wheel -q + if [[ -f "${HUB_REQ}" ]]; then + .venv/bin/pip install -r "${HUB_REQ}" -q + fi + if [[ "${SKIP_ENV_COPY}" -eq 0 && -f .env.example && ! -f .env ]]; then + cp -n .env.example .env 2>/dev/null || cp .env.example .env + echo " 已复制 .env.example -> .env" + fi + echo " 完成: ${proj}/.venv/bin/python" +} + +install_pm2() { + 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 " 各子目录: pm2 start ecosystem.config.cjs" +} + +echo "crypto_monitor 环境部署" +echo "仓库根目录: ${REPO_ROOT}" + +[[ -f "${REQ_FILE}" ]] || { echo "缺少 ${REQ_FILE}" >&2; exit 1; } + +PY="$(find_python)" +check_python_version "${PY}" + +should_include binance && setup_monitor crypto_monitor_binance +should_include gate && setup_monitor crypto_monitor_gate +should_include gate_bot && setup_monitor crypto_monitor_gate_bot +should_include okx && setup_monitor crypto_monitor_okx +should_include hub && setup_hub + +install_pm2 + +echo "" +echo "部署完成。下一步:" +echo " 1. 编辑各子目录 .env" +echo " 2. 启动示例: cd crypto_monitor_binance && source .venv/bin/activate && python app.py" +echo " 3. Windows 可用: powershell -File deploy/setup_env.ps1" +echo ""