Files
PCFAnalysis/scripts/install_offline.ps1
T

174 lines
4.9 KiB
PowerShell
Raw Normal View History

2026-07-02 15:30:18 +08:00
param(
[switch]$NoPause,
[string]$IndexUrl = "https://pypi.org/simple"
2026-07-02 15:30:18 +08:00
)
2026-06-30 14:29:02 +08:00
$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"
2026-07-02 15:30:18 +08:00
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 ' ')"
}
2026-06-30 14:29:02 +08:00
}
2026-07-02 15:30:18 +08:00
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
2026-07-02 15:30:18 +08:00
}
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."
2026-07-02 15:30:18 +08:00
}
}
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
}