Files
cmbuyer/init.ps1
T

150 lines
6.3 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env pwsh
# cmbuyer Windows 统一安装、验证与启动入口。
# 这个入口只处理开发环境和离线门禁,不连接设备,也不触发采购、下单或付款动作。
$ErrorActionPreference = "Stop"
Set-Location -Path $PSScriptRoot
# Go 工具链固定用本机版本,避免自动下载造成不可复现的环境漂移。
$env:GOTOOLCHAIN = "local"
$AdminDir = Join-Path $PSScriptRoot "admin"
$ClientDir = Join-Path $PSScriptRoot "client"
$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)"
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 不是目录。不会覆盖该路径,请人工处理后重试。"
}
Require-File $ClientPython "既有 client/.venv Python"
Confirm-Python311OrNewer $ClientPython "既有 client/.venv"
} else {
# 默认 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"
}
# 后续所有采购工具检查与仓库 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
}
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 ""
Write-Host "==> 基线验证通过。启动命令:"
Write-Host " 采购服务:cd admin; go run ./cmd/server"
Write-Host " 采购工具:cd client; .\.venv\Scripts\python.exe -m cmbuyer_client"
Write-Host ""
Write-Host "真机连接与设备验收只能由人工完成;本入口不执行任何采购、下单或付款动作。"