Files
cmbuyer/init.ps1
T

150 lines
6.3 KiB
PowerShell
Raw Normal View History

#!/usr/bin/env pwsh
2026-08-03 18:55:32 +08:00
# cmbuyer Windows 统一安装、验证与启动入口。
# 这个入口只处理开发环境和离线门禁,不连接设备,也不触发采购、下单或付款动作。
$ErrorActionPreference = "Stop"
Set-Location -Path $PSScriptRoot
2026-08-03 18:55:32 +08:00
# Go 工具链固定用本机版本,避免自动下载造成不可复现的环境漂移。
$env:GOTOOLCHAIN = "local"
2026-08-03 18:55:32 +08:00
$AdminDir = Join-Path $PSScriptRoot "admin"
$ClientDir = Join-Path $PSScriptRoot "client"
2026-08-03 18:55:32 +08:00
$ClientVenv = Join-Path $ClientDir ".venv"
$ClientPython = Join-Path $ClientVenv "Scripts\python.exe"
function Fail([string]$Message) {
throw $Message
}
function Require-Directory([string]$Path, [string]$Name) {
if (-not (Test-Path -LiteralPath $Path -PathType Container)) {
Fail "$Name 目录不存在:$Path。请先完成对应初始化任务。"
}
}
function Require-File([string]$Path, [string]$Name) {
if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) {
Fail "$Name 不存在:$Path。请先完成对应初始化任务。"
}
}
function Require-Command([string]$Name, [string]$Hint) {
if (-not (Get-Command $Name -ErrorAction SilentlyContinue)) {
Fail "缺少 $Name。$Hint"
}
}
function Invoke-Step([string]$Description, [scriptblock]$Action) {
Write-Host "==> $Description"
& $Action
if ($LASTEXITCODE -ne 0) {
Fail "$Description 失败,退出码:$LASTEXITCODE"
}
}
function Confirm-Python311OrNewer([string]$PythonExecutable, [string]$Context) {
& $PythonExecutable -c "import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)"
if ($LASTEXITCODE -ne 0) {
Fail "$Context 必须使用 Python 3.11+。不会自动覆盖既有虚拟环境;请手工删除 client/.venv 后重试。"
}
}
function Select-PythonLauncherSelector() {
$launcherLines = @(& py -0p)
if ($LASTEXITCODE -ne 0) {
Fail "无法从 Python Launcher 枚举已安装版本。请安装 Python 3.11+ 并确认 py -0p 可运行。"
}
$minimumVersion = [version]::new(3, 11)
$candidates = @()
foreach ($line in $launcherLines) {
$selectorMatch = [regex]::Match([string]$line, '^\s*-V:(?<selector>\S+)(?:\s+\*)?\s+(?<path>.+?)\s*$')
if (-not $selectorMatch.Success) {
continue
}
$selector = $selectorMatch.Groups['selector'].Value
$pythonPath = $selectorMatch.Groups['path'].Value
$versionMatch = [regex]::Match($selector, '(?<major>\d+)\.(?<minor>\d+)(?:\.(?<patch>\d+))?')
if (-not $versionMatch.Success) {
continue
}
$patch = if ($versionMatch.Groups['patch'].Success) { [int]$versionMatch.Groups['patch'].Value } else { 0 }
$version = [version]::new(
[int]$versionMatch.Groups['major'].Value,
[int]$versionMatch.Groups['minor'].Value,
$patch
)
if ($version -ge $minimumVersion) {
$candidates += [PSCustomObject]@{ Selector = $selector; Version = $version; Path = $pythonPath }
}
}
if ($candidates.Count -eq 0) {
Fail "Python Launcher 未发现 Python 3.11+。当前默认 python 不会作为回退;请安装合规版本后重试。"
}
$selected = $candidates | Sort-Object @{ Expression = 'Version'; Descending = $true }, @{ Expression = 'Selector'; Descending = $false } | Select-Object -First 1
Write-Host "==> 选择 Python Launcher 解释器:-V:$($selected.Selector)($($selected.Version))"
return $selected
}
Write-Host "==> 当前目录: $($PWD.Path)"
2026-08-03 18:55:32 +08:00
Require-Directory $AdminDir "采购服务 admin"
Require-File (Join-Path $AdminDir "go.mod") "采购服务哨兵 admin/go.mod"
Require-Directory $ClientDir "采购工具 client"
Require-File (Join-Path $ClientDir "requirements.txt") "采购工具哨兵 client/requirements.txt"
Require-File (Join-Path $ClientDir "pyproject.toml") "采购工具打包配置 client/pyproject.toml"
Require-Command "go" "请安装 Go 1.23+ 并重新打开 PowerShell。"
if (Test-Path -LiteralPath $ClientVenv) {
if (-not (Test-Path -LiteralPath $ClientVenv -PathType Container)) {
Fail "client/.venv 不是目录。不会覆盖该路径,请人工处理后重试。"
}
2026-08-03 18:55:32 +08:00
Require-File $ClientPython "既有 client/.venv Python"
Confirm-Python311OrNewer $ClientPython "既有 client/.venv"
} else {
2026-08-03 18:55:32 +08:00
# 默认 python 在本机可能仍指向 3.10;仅在需要新建 venv 时,从 Launcher 中确定性选择最高的合规版本。
Require-Command "py" "请安装 Python Launcher 和 Python 3.11+。"
$PythonRuntime = Select-PythonLauncherSelector
Require-File $PythonRuntime.Path "Python Launcher 选择的解释器"
Invoke-Step "验证所选 Python Launcher 解释器" { & $PythonRuntime.Path -c "import sys; print(sys.version); raise SystemExit(0 if sys.version_info >= (3, 11) else 1)" }
Invoke-Step "创建所选 Python 3.11+ 采购工具虚拟环境" { & $PythonRuntime.Path -m venv $ClientVenv }
Require-File $ClientPython "新建 client/.venv Python"
Confirm-Python311OrNewer $ClientPython "新建 client/.venv"
}
2026-08-03 18:55:32 +08:00
# 后续所有采购工具检查与仓库 validator 均使用同一个合规 venv 解释器,避免混用宿主 Python。
Invoke-Step "验证采购工具虚拟环境 Python" { & $ClientPython -c "import sys; print(sys.version); raise SystemExit(0 if sys.version_info >= (3, 11) else 1)" }
Push-Location $AdminDir
try {
Invoke-Step "采购服务:admin/ 同步依赖" { go mod download }
Invoke-Step "采购服务:admin/ 测试" { go test ./... }
Invoke-Step "采购服务:admin/ 静态检查" { go vet ./... }
Invoke-Step "采购服务:admin/ 构建" { go build ./... }
} finally {
Pop-Location
}
2026-08-03 18:55:32 +08:00
Push-Location $ClientDir
try {
Invoke-Step "采购工具:以 editable 方式安装" { & $ClientPython -m pip install -e . }
Invoke-Step "采购工具:验证已安装包" { & $ClientPython -c "import cmbuyer_client; print(cmbuyer_client.__version__)" }
Invoke-Step "采购工具:测试" { & $ClientPython -m unittest discover -s tests -t . }
Invoke-Step "采购工具:语法检查" { & $ClientPython -m compileall -q src tests scripts }
} finally {
Pop-Location
}
Invoke-Step "校验 agent 上下文清单" { & $ClientPython scripts/validate_agent_context.py }
Write-Host ""
2026-08-03 18:55:32 +08:00
Write-Host "==> 基线验证通过。启动命令:"
Write-Host " 采购服务:cd admin; go run ./cmd/server"
Write-Host " 采购工具:cd client; .\.venv\Scripts\python.exe -m cmbuyer_client"
Write-Host ""
2026-08-03 18:55:32 +08:00
Write-Host "真机连接与设备验收只能由人工完成;本入口不执行任何采购、下单或付款动作。"