174 lines
4.9 KiB
PowerShell
174 lines
4.9 KiB
PowerShell
param(
|
|
[switch]$NoPause,
|
|
[string]$IndexUrl = "https://pypi.org/simple"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$Root = Split-Path -Parent $PSScriptRoot
|
|
$Venv = Join-Path $Root ".venv"
|
|
$VenvPython = Join-Path $Venv "Scripts\python.exe"
|
|
$WheelDir = Join-Path $Root "vendor\wheels"
|
|
$Req = Join-Path $Root "requirements.txt"
|
|
|
|
function Write-Step {
|
|
param([string]$Message)
|
|
Write-Host ""
|
|
Write-Host "==> $Message" -ForegroundColor Cyan
|
|
}
|
|
|
|
function Wait-BeforeExit {
|
|
if (-not $NoPause) {
|
|
Write-Host ""
|
|
Read-Host "Press Enter to exit"
|
|
}
|
|
}
|
|
|
|
function Get-PythonCandidate {
|
|
$candidates = @(
|
|
@{ Exe = "py"; Args = @("-3") },
|
|
@{ Exe = "python"; Args = @() },
|
|
@{ Exe = "python3"; Args = @() }
|
|
)
|
|
|
|
foreach ($candidate in $candidates) {
|
|
$command = Get-Command $candidate.Exe -ErrorAction SilentlyContinue
|
|
if (-not $command) {
|
|
continue
|
|
}
|
|
|
|
try {
|
|
$args = @($candidate.Args) + @("-c", "import sys; print(sys.executable); print(sys.version_info.major); print(sys.version_info.minor)")
|
|
$output = & $candidate.Exe @args 2>$null
|
|
if ($LASTEXITCODE -ne 0 -or $output.Count -lt 3) {
|
|
continue
|
|
}
|
|
$major = [int]$output[1]
|
|
$minor = [int]$output[2]
|
|
if ($major -gt 3 -or ($major -eq 3 -and $minor -ge 10)) {
|
|
return [pscustomobject]@{
|
|
Exe = $candidate.Exe
|
|
Args = $candidate.Args
|
|
Path = $output[0]
|
|
Version = "$major.$minor"
|
|
}
|
|
}
|
|
} catch {
|
|
continue
|
|
}
|
|
}
|
|
|
|
return $null
|
|
}
|
|
|
|
function Install-PythonWithWinget {
|
|
$winget = Get-Command winget -ErrorAction SilentlyContinue
|
|
if (-not $winget) {
|
|
throw "Python 3.10+ was not found, and winget is not available. Install Python 3.10+ manually and run this script again."
|
|
}
|
|
|
|
Write-Step "Python was not found. Installing Python 3.12 with winget"
|
|
& winget install --id Python.Python.3.12 -e --source winget --accept-package-agreements --accept-source-agreements
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "winget failed to install Python. Check network access or install Python 3.10+ manually."
|
|
}
|
|
}
|
|
|
|
function Ensure-Python {
|
|
$python = Get-PythonCandidate
|
|
if ($python) {
|
|
Write-Host "Python found: $($python.Path), version $($python.Version)"
|
|
return $python
|
|
}
|
|
|
|
Install-PythonWithWinget
|
|
$python = Get-PythonCandidate
|
|
if (-not $python) {
|
|
throw "Python is still unavailable after installation. Reopen PowerShell or check PATH."
|
|
}
|
|
Write-Host "Python ready: $($python.Path), version $($python.Version)"
|
|
return $python
|
|
}
|
|
|
|
function Invoke-Python {
|
|
param(
|
|
[object]$Python,
|
|
[string[]]$Arguments
|
|
)
|
|
$allArgs = @($Python.Args) + $Arguments
|
|
& $Python.Exe @allArgs
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Python command failed: $($Python.Exe) $($allArgs -join ' ')"
|
|
}
|
|
}
|
|
|
|
function Ensure-Venv {
|
|
param([object]$Python)
|
|
if (-not (Test-Path $VenvPython)) {
|
|
Write-Step "Creating virtual environment"
|
|
Invoke-Python -Python $Python -Arguments @("-m", "venv", $Venv)
|
|
} else {
|
|
Write-Host "Virtual environment already exists: $Venv"
|
|
}
|
|
|
|
if (-not (Test-Path $VenvPython)) {
|
|
throw "Failed to create virtual environment: $VenvPython does not exist."
|
|
}
|
|
}
|
|
|
|
function Install-Requirements {
|
|
if (-not (Test-Path $Req)) {
|
|
throw "requirements.txt was not found: $Req"
|
|
}
|
|
|
|
Write-Step "Installing dependencies"
|
|
$wheels = @()
|
|
if (Test-Path $WheelDir) {
|
|
$wheels = Get-ChildItem -Path $WheelDir -Filter *.whl -File -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
if ($wheels.Count -gt 0) {
|
|
Write-Host "Offline wheel directory found: $WheelDir"
|
|
& $VenvPython -m pip install --no-index --find-links $WheelDir -r $Req
|
|
} else {
|
|
Write-Host "No offline wheels found. Installing dependencies from the network."
|
|
& $VenvPython -m pip install `
|
|
--index-url $IndexUrl `
|
|
--trusted-host pypi.org `
|
|
--trusted-host files.pythonhosted.org `
|
|
--disable-pip-version-check `
|
|
--retries 3 `
|
|
--timeout 60 `
|
|
-r $Req
|
|
}
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Dependency installation failed. Check network access to $IndexUrl. If the server is offline, run scripts\download_wheels.ps1 on an online machine first and copy vendor\wheels to this server."
|
|
}
|
|
}
|
|
|
|
function Test-ApplicationImport {
|
|
Write-Step "Verifying environment"
|
|
& $VenvPython -c "import fastapi, uvicorn, xlrd, xlwt, xlutils, httpx, yaml; print('Dependency verification passed')"
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Dependency verification failed."
|
|
}
|
|
}
|
|
|
|
try {
|
|
Set-Location $Root
|
|
Write-Step "Preparing PCFAnalysis environment"
|
|
$python = Ensure-Python
|
|
Ensure-Venv -Python $python
|
|
Install-Requirements
|
|
Test-ApplicationImport
|
|
Write-Host ""
|
|
Write-Host "Environment installation completed. Run scripts\run.ps1 to start the service." -ForegroundColor Green
|
|
} catch {
|
|
Write-Host ""
|
|
Write-Host "Installation failed:" -ForegroundColor Red
|
|
Write-Host $_.Exception.Message -ForegroundColor Red
|
|
exit 1
|
|
} finally {
|
|
Wait-BeforeExit
|
|
}
|