Files
order_system/packaging/win7/install_env.ps1
T

144 lines
6.9 KiB
PowerShell

# Compatible with Windows PowerShell 2.0. Reuse a verified full Python install.
param([switch]$ProbeOnly)
$ErrorActionPreference = 'Stop'
$kitRoot = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
$logDirectory = Join-Path $kitRoot 'logs'
[void][IO.Directory]::CreateDirectory($logDirectory)
$runId = Get-Date -Format 'yyyyMMdd-HHmmss-fff'
$setupLog = Join-Path $logDirectory ('setup-' + $runId + '.log')
$utf8 = New-Object System.Text.UTF8Encoding($true)
[IO.File]::WriteAllText($setupLog, '', $utf8)
$env:PYTHONUTF8 = '1'
$env:PYTHONIOENCODING = 'utf-8'
$env:PYTHONHOME = $null
$env:PYTHONPATH = $null
[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
$targetBits = 32
if ($env:PROCESSOR_ARCHITECTURE -eq 'AMD64' -or $env:PROCESSOR_ARCHITEW6432 -eq 'AMD64') {
$targetBits = 64
}
function Write-Log([string]$message) {
Write-Host $message
[IO.File]::AppendAllText($setupLog, $message + [Environment]::NewLine, $utf8)
}
function Invoke-Logged([string]$executable, [string[]]$arguments) {
# PowerShell 2 treats native stderr as ErrorRecord; preserve it in the log
# without mistaking harmless warnings for a failed process.
$savedPreference = $ErrorActionPreference
$ErrorActionPreference = 'Continue'
try {
$global:LASTEXITCODE = $null
& $executable @arguments 2>&1 | ForEach-Object { Write-Log ([string]$_) }
$code = $global:LASTEXITCODE
} finally {
$ErrorActionPreference = $savedPreference
}
if ($null -eq $code) { return 1 }
return $code
}
function Test-Python([string]$candidate) {
if (-not (Test-Path -LiteralPath $candidate -PathType Leaf)) { return $false }
Write-Log ('Checking Python: ' + $candidate)
$probe = 'import sys, struct, venv, ensurepip, ssl, sqlite3; print(sys.version); print(sys.executable); sys.exit(0 if sys.version_info[:3] == (3,8,10) and struct.calcsize(''P'')*8 == ' + $targetBits + ' else 3)'
$code = Invoke-Logged $candidate @('-I', '-X', 'utf8', '-c', $probe)
if ($code -ne 0) { Write-Log ('Python rejected; exit code: ' + $code) }
return ($code -eq 0)
}
function Find-Python {
$manualFile = Join-Path $kitRoot 'python_path.txt'
if (Test-Path -LiteralPath $manualFile) {
$manualPath = [IO.File]::ReadAllText($manualFile).Trim().Trim('"')
if (Test-Python $manualPath) { return $manualPath }
throw 'python_path.txt must contain the full path to a working Python 3.8.10 of the required architecture.'
}
$candidates = New-Object System.Collections.ArrayList
[void]$candidates.Add((Join-Path $kitRoot '.python38\python.exe'))
# Python's official installer registers the full interpreter, even when
# its files live in an older source kit directory.
foreach ($registryRoot in @('HKCU:\Software\Python\PythonCore',
'HKCU:\Software\WOW6432Node\Python\PythonCore',
'HKLM:\Software\Python\PythonCore',
'HKLM:\Software\WOW6432Node\Python\PythonCore')) {
foreach ($tag in @('3.8', '3.8-32')) {
$keyPath = Join-Path $registryRoot ($tag + '\InstallPath')
try {
if (Test-Path -LiteralPath $keyPath) {
$key = Get-Item -LiteralPath $keyPath
$executable = [string]$key.GetValue('ExecutablePath')
$directory = [string]$key.GetValue('')
if ($executable) { [void]$candidates.Add($executable) }
if ($directory) { [void]$candidates.Add((Join-Path $directory 'python.exe')) }
}
} catch {
Write-Log ('Registry lookup skipped: ' + $keyPath + ' : ' + $_.Exception.Message)
}
}
}
foreach ($candidate in ($candidates | Select-Object -Unique)) {
if (Test-Python $candidate) { return $candidate }
}
return $null
}
try {
Write-Log ('Setup log: ' + $setupLog)
Write-Log ('Package: ' + $kitRoot)
Write-Log ('Windows: ' + [Environment]::OSVersion.VersionString)
Write-Log ('PowerShell: ' + $PSVersionTable.PSVersion.ToString())
Write-Log ('Required Python: 3.8.10, ' + $targetBits + '-bit')
$python = Find-Python
if ($ProbeOnly) {
if ($python) { Write-Log ('FOUND reusable Python: ' + $python) }
else { Write-Log 'No working matching Python was found. No installation was attempted.' }
Write-Log 'DIAGNOSTIC COMPLETE. No dependencies or system settings were changed.'
exit 0
}
if (-not $python) {
$installerName = 'python-3.8.10.exe'
if ($targetBits -eq 64) { $installerName = 'python-3.8.10-amd64.exe' }
$installer = Join-Path $kitRoot ('installers\' + $installerName)
if (-not (Test-Path -LiteralPath $installer)) { throw ('Installer missing: ' + $installer) }
$installerLog = Join-Path $logDirectory ('python-installer-' + $runId + '.log')
$targetDirectory = Join-Path $kitRoot '.python38'
Write-Log ('No reusable Python found. Starting installer: ' + $installer)
Write-Log ('Installer log: ' + $installerLog)
$installerArgs = @('/passive', '/log', ('"' + $installerLog + '"'),
'InstallAllUsers=0', ('TargetDir="' + $targetDirectory + '"'),
'Include_launcher=0', 'InstallLauncherAllUsers=0', 'PrependPath=0',
'Include_doc=0', 'Include_test=0', 'Include_tcltk=0', 'Shortcuts=0', 'AssociateFiles=0')
$process = Start-Process -FilePath $installer -ArgumentList $installerArgs -Wait -PassThru -WindowStyle Hidden
$installerCode = $process.ExitCode
Write-Log ('Python installer exit code: ' + $installerCode)
if ($installerCode -eq 3010 -or $installerCode -eq 1641) {
Write-Log 'Windows requested a restart. Restart the computer and run 01_install_env.cmd again.'
exit $installerCode
}
if ($installerCode -ne 0) {
throw ('Python installer failed with exit code ' + $installerCode + '. See ' + $installerLog)
}
# Maintenance mode may leave Python in its original registered folder.
$python = Find-Python
if (-not $python) {
throw 'Installer returned success but no matching Python was found. Keep logs; do not uninstall the old working environment.'
}
}
Write-Log ('Using existing Python: ' + $python)
Write-Log 'Keep this Python directory while using the build environment.'
$buildScript = Join-Path $kitRoot 'win7\build.py'
$code = Invoke-Logged $python @('-I', '-X', 'utf8', $buildScript, 'setup')
Write-Log ('Environment setup exit code: ' + $code)
if ($code -ne 0) { exit $code }
Write-Log 'SETUP COMPLETE. Run 02_build_exe.cmd next.'
exit 0
} catch {
Write-Log ('FAILED: ' + $_.Exception.Message)
Write-Log ('Details: ' + $_.ScriptStackTrace)
Write-Log ('Keep the logs folder. Setup log: ' + $setupLog)
exit 1
}