#Requires -Version 5.1 <# .SYNOPSIS crypto_monitor_user 一键环境部署(Windows PowerShell) .DESCRIPTION - 为各子项目创建 Python venv 并安装依赖 - 从 .env.example 复制 .env(不覆盖已有) - 创建 static/images 等运行时目录 - 可选安装 PM2(需已安装 Node.js) .EXAMPLE .\deploy\setup_env.ps1 .\deploy\setup_env.ps1 -Only binance,gate_bot .\deploy\setup_env.ps1 -SkipPm2 #> param( [string]$Only = "all", [switch]$SkipPm2, [switch]$SkipEnvCopy, [switch]$RecreateVenv ) $ErrorActionPreference = "Stop" [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $DeployDir = $PSScriptRoot $RepoRoot = (Resolve-Path (Join-Path $DeployDir "..")).Path $ReqFile = Join-Path $RepoRoot "requirements.txt" $HubReqFile = Join-Path $RepoRoot "manual_trading_hub\requirements.txt" $MonitorProjects = @( @{ Key = "binance"; Dir = "crypto_monitor_binance" }, @{ Key = "gate"; Dir = "crypto_monitor_gate" }, @{ Key = "gate_bot"; Dir = "crypto_monitor_gate_bot" }, @{ Key = "okx"; Dir = "crypto_monitor_okx" } ) $HubProject = @{ Key = "hub"; Dir = "manual_trading_hub" } function Write-Step([string]$Msg) { Write-Host "" Write-Host "==> $Msg" -ForegroundColor Cyan } function Test-Python310 { $py = Get-Command python -ErrorAction SilentlyContinue if (-not $py) { throw "未找到 python。请安装 Python 3.10+ 并加入 PATH:https://www.python.org/downloads/" } $verText = & python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" $parts = $verText.Trim() -split "\." $major = [int]$parts[0] $minor = [int]$parts[1] if ($major -lt 3 -or ($major -eq 3 -and $minor -lt 10)) { throw "需要 Python 3.10+,当前: $verText" } Write-Host "Python: $(python --version 2>&1)" -ForegroundColor DarkGray } function Should-Include([string]$Key, [string[]]$Selected) { if ($Selected -contains "all") { return $true } return $Selected -contains $Key } function Setup-MonitorProject([hashtable]$Proj) { $projPath = Join-Path $RepoRoot $Proj.Dir if (-not (Test-Path $projPath)) { Write-Host " 跳过(目录不存在): $($Proj.Dir)" -ForegroundColor Yellow return } Write-Step "$($Proj.Dir)" Push-Location $projPath try { $venvDir = Join-Path $projPath ".venv" $venvPy = Join-Path $venvDir "Scripts\python.exe" $venvPip = Join-Path $venvDir "Scripts\pip.exe" if ($RecreateVenv -and (Test-Path $venvDir)) { Write-Host " 删除旧 venv ..." Remove-Item -Recurse -Force $venvDir } if (-not (Test-Path $venvPy)) { Write-Host " 创建 venv ..." & python -m venv .venv } Write-Host " 升级 pip ..." & $venvPy -m pip install -U pip setuptools wheel -q Write-Host " 安装依赖 (requirements.txt) ..." & $venvPip install -r $ReqFile -q if (-not $SkipEnvCopy) { $envExample = Join-Path $projPath ".env.example" $envFile = Join-Path $projPath ".env" if ((Test-Path $envExample) -and -not (Test-Path $envFile)) { Copy-Item $envExample $envFile Write-Host " 已复制 .env.example -> .env" -ForegroundColor Green } elseif (Test-Path $envFile) { Write-Host " 保留已有 .env" -ForegroundColor DarkGray } else { Write-Host " 无 .env.example,请手动配置 .env" -ForegroundColor Yellow } } $staticDirs = @( "static\images", "static\images\order_charts" ) foreach ($d in $staticDirs) { $full = Join-Path $projPath $d if (-not (Test-Path $full)) { New-Item -ItemType Directory -Path $full -Force | Out-Null } } Write-Host " 完成: $venvPy" -ForegroundColor Green } finally { Pop-Location } } function Setup-HubProject() { $projPath = Join-Path $RepoRoot $HubProject.Dir if (-not (Test-Path $projPath)) { Write-Host " 跳过 hub(目录不存在)" -ForegroundColor Yellow return } Write-Step $HubProject.Dir Push-Location $projPath try { $venvDir = Join-Path $projPath ".venv" $venvPy = Join-Path $venvDir "Scripts\python.exe" $venvPip = Join-Path $venvDir "Scripts\pip.exe" if ($RecreateVenv -and (Test-Path $venvDir)) { Remove-Item -Recurse -Force $venvDir } if (-not (Test-Path $venvPy)) { & python -m venv .venv } & $venvPy -m pip install -U pip setuptools wheel -q if (Test-Path $HubReqFile) { & $venvPip install -r $HubReqFile -q } if (-not $SkipEnvCopy) { $envExample = Join-Path $projPath ".env.example" $envFile = Join-Path $projPath ".env" if ((Test-Path $envExample) -and -not (Test-Path $envFile)) { Copy-Item $envExample $envFile Write-Host " 已复制 .env.example -> .env" -ForegroundColor Green } } Write-Host " 完成: $venvPy" -ForegroundColor Green } finally { Pop-Location } } function Install-Pm2IfNeeded() { if ($SkipPm2) { return } $node = Get-Command node -ErrorAction SilentlyContinue if (-not $node) { Write-Host "未检测到 Node.js,跳过 PM2。安装 Node 后执行: npm install -g pm2" -ForegroundColor Yellow return } Write-Step "PM2(可选进程托管)" $pm2 = Get-Command pm2 -ErrorAction SilentlyContinue if ($pm2) { Write-Host " PM2 已安装: $(pm2 -v)" -ForegroundColor Green return } Write-Host " 正在全局安装 pm2 ..." & npm install -g pm2 Write-Host " PM2 安装完成。在各子目录执行: pm2 start ecosystem.config.cjs" -ForegroundColor Green } # --- main --- Write-Host "crypto_monitor_user 环境部署" -ForegroundColor White Write-Host "仓库根目录: $RepoRoot" -ForegroundColor DarkGray if (-not (Test-Path $ReqFile)) { throw "缺少 $ReqFile" } Test-Python310 $selected = ($Only -split "[,;\s]+" | ForEach-Object { $_.Trim().ToLower() } | Where-Object { $_ }) if (-not $selected -or $selected.Count -eq 0) { $selected = @("all") } foreach ($p in $MonitorProjects) { if (Should-Include $p.Key $selected) { Setup-MonitorProject $p } } if (Should-Include $HubProject.Key $selected) { Setup-HubProject } Install-Pm2IfNeeded Write-Host "" Write-Host "部署完成。下一步:" -ForegroundColor Green Write-Host " 1. 编辑各子目录 .env(API Key、密码、代理等)" Write-Host " 2. 启动示例(Binance):" Write-Host " cd crypto_monitor_binance" Write-Host " .\.venv\Scripts\activate" Write-Host " python app.py" Write-Host " 3. Linux 服务器可用: bash deploy/setup_env.sh" Write-Host ""