Files
proxy-god/scripts/_build_common.ps1
Dr Jones 08f9979cc6
Some checks failed
CI / Test Python 3.10 (push) Has been cancelled
CI / Test Python 3.11 (push) Has been cancelled
CI / Test Python 3.12 (push) Has been cancelled
Release Build / Build Windows release (push) Has been cancelled
fix: release build script; add releases README and v1.0.0 download links
2026-05-22 20:11:41 -07:00

222 lines
7.8 KiB
PowerShell

#Requires -Version 5.1
<#
Shared build helpers for Proxy God / ProxyChainManager.
Dot-sourced by setup_and_build.ps1 and release_build.ps1 — do not run directly.
#>
Set-StrictMode -Version Latest
function Get-RepoRoot {
# This file lives in scripts/ — parent is the repository root.
return (Split-Path -Parent $PSScriptRoot)
}
function Resolve-PythonExe {
if (Get-Command py -ErrorAction SilentlyContinue) {
try {
$out = (& py -3 -c "import sys; print(sys.executable)" 2>$null).Trim()
if ($out -and (Test-Path -LiteralPath $out)) { return $out }
} catch { }
}
$p = Get-Command python.exe -ErrorAction SilentlyContinue
if ($p) { return $p.Source }
throw @(
"Python 3.10+ not found (tried 'py -3' and 'python'). Install, then re-run:",
" winget install Python.Python.3.12 --accept-package-agreements --accept-source-agreements",
"Or https://www.python.org/downloads/ (enable 'Add python.exe to PATH')."
) -join "`n"
}
function Get-GitCommit {
try {
$c = (git -C (Get-RepoRoot) rev-parse --short HEAD 2>$null).Trim()
if ($c) { return $c }
} catch { }
return "unknown"
}
function Get-ReleaseVersion {
param([string]$Override = "")
if ($Override) { return $Override.Trim() }
$root = Get-RepoRoot
try {
$tag = (git -C $root describe --tags --exact-match 2>$null).Trim()
if ($tag) { return $tag.TrimStart("v") }
} catch { }
try {
$desc = (git -C $root describe --tags --always --dirty 2>$null).Trim()
if ($desc) { return ($desc -replace '^v', '') }
} catch { }
$py = Resolve-PythonExe
$v = (& $py -c "from proxy_chain_manager import __version__; print(__version__)" 2>$null).Trim()
if ($v) { return $v }
return "0.0.0-dev"
}
function Install-BuildDependencies {
param([string]$PythonExe, [string]$Root)
Write-Host "`n== pip (upgrade) =="
& $PythonExe -m pip install --upgrade pip
Write-Host "`n== runtime dependencies =="
& $PythonExe -m pip install -r (Join-Path $Root "requirements.txt")
Write-Host "`n== build dependencies =="
& $PythonExe -m pip install -r (Join-Path $Root "dev-requirements.txt")
}
function Invoke-UnitTests {
param([string]$PythonExe, [string]$Root)
Write-Host "`n== compileall =="
& $PythonExe -m compileall -q (Join-Path $Root "proxy_chain_manager")
if ($LASTEXITCODE -ne 0) { throw "compileall failed (exit $LASTEXITCODE)" }
Write-Host "`n== unittest discover =="
Push-Location $Root
try {
& $PythonExe -m unittest discover -s tests -v
if ($LASTEXITCODE -ne 0) { throw "unittest failed (exit $LASTEXITCODE)" }
} finally {
Pop-Location
}
}
function Invoke-StageBundledGost {
param([string]$Root)
Write-Host "`n== Stage bundled GOST =="
$prep = Join-Path $Root "scripts\prepare_bundled_gost.ps1"
& powershell -NoProfile -ExecutionPolicy Bypass -File $prep
if ($LASTEXITCODE -ne 0) { throw "prepare_bundled_gost.ps1 failed (exit $LASTEXITCODE)" }
}
function Invoke-GenerateVersionInfo {
param(
[string]$PythonExe,
[string]$Root,
[string]$Version,
[string]$Commit = ""
)
Write-Host "`n== Version metadata ($Version) =="
$gen = Join-Path $Root "scripts\generate_version_info.py"
$out = Join-Path $Root "build\version_info.txt"
$args = @($gen, "--version", $Version, "--out", $out)
if ($Commit) { $args += @("--commit", $Commit) }
& $PythonExe @args
if ($LASTEXITCODE -ne 0) { throw "generate_version_info.py failed (exit $LASTEXITCODE)" }
}
function Invoke-PyInstallerBuild {
param([string]$PythonExe, [string]$Root)
Write-Host "`n== PyInstaller (ProxyChainManager.spec) =="
$spec = Join-Path $Root "ProxyChainManager.spec"
if (-not (Test-Path $spec)) { throw "Spec not found: $spec" }
& $PythonExe -m PyInstaller --noconfirm --clean $spec
if ($LASTEXITCODE -ne 0) { throw "PyInstaller failed (exit $LASTEXITCODE)" }
$exe = Join-Path $Root "dist\ProxyChainManager.exe"
if (-not (Test-Path $exe)) { throw "Build failed: missing $exe" }
return $exe
}
function Invoke-CodeSign {
param([string]$ExePath)
$cert = $env:SIGN_CERT_PATH
if (-not $cert) {
Write-Host " (signing skipped - set SIGN_CERT_PATH to a .pfx to Authenticode-sign)"
return
}
if (-not (Test-Path $cert)) { throw "SIGN_CERT_PATH not found: $cert" }
$signtool = "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe"
if (-not (Test-Path $signtool)) {
$signtool = (Get-Command signtool.exe -ErrorAction SilentlyContinue).Source
}
if (-not $signtool) { throw "signtool.exe not found - install Windows SDK" }
Write-Host "`n== Authenticode sign =="
$args = @("sign", "/fd", "SHA256", "/f", $cert, "/tr", "http://timestamp.digicert.com", "/td", "SHA256")
if ($env:SIGN_CERT_PASSWORD) {
$args += @("/p", $env:SIGN_CERT_PASSWORD)
}
$args += $ExePath
& $signtool @args
if ($LASTEXITCODE -ne 0) { throw "signtool sign failed (exit $LASTEXITCODE)" }
}
function Write-ExeHashSidecar {
param([string]$ExePath)
$hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $ExePath).Hash.ToLower()
$sidecar = "$ExePath.sha256"
"$hash *$(Split-Path -Leaf $ExePath)" | Out-File -FilePath $sidecar -Encoding ascii -Force
Write-Host "SHA256: $hash -> $sidecar"
return @{ Hash = $hash; Sidecar = $sidecar }
}
function Write-Sbom {
param(
[string]$PythonExe,
[string]$OutDir,
[string]$Version
)
Write-Host "`n== SBOM =="
$freeze = Join-Path $OutDir "requirements-frozen.txt"
& $PythonExe -m pip freeze | Out-File -FilePath $freeze -Encoding utf8
$sbom = Join-Path $OutDir "SBOM.json"
$pkgs = @()
Get-Content $freeze | ForEach-Object {
if ($_ -match '^([^=]+)==(.+)$') {
$pkgs += @{ name = $Matches[1]; version = $Matches[2] }
}
}
$manifest = @{
product = "Proxy God"
version = $Version
generated = (Get-Date).ToUniversalTime().ToString("o")
python = (& $PythonExe -c "import sys; print(sys.version.split()[0])").Trim()
packages = $pkgs
}
($manifest | ConvertTo-Json -Depth 4) | Out-File -FilePath $sbom -Encoding utf8
Write-Host "Wrote $sbom and $freeze"
return @{ Sbom = $sbom; Freeze = $freeze }
}
function Write-ReleaseManifest {
param(
[string]$OutDir,
[string]$Version,
[string]$Commit,
[string]$ExePath,
[string]$Sha256,
[hashtable]$Extra = @{}
)
$manifest = @{
product = "Proxy God"
executable = "ProxyChainManager.exe"
version = $Version
git_commit = $Commit
built_at_utc = (Get-Date).ToUniversalTime().ToString("o")
platform = "windows-amd64"
sha256 = $Sha256
uac_admin = $true
bundled_gost = $true
pyinstaller = "6.10.0"
}
foreach ($k in $Extra.Keys) { $manifest[$k] = $Extra[$k] }
$path = Join-Path $OutDir "RELEASE_MANIFEST.json"
($manifest | ConvertTo-Json -Depth 4) | Out-File -FilePath $path -Encoding utf8
Write-Host "Wrote $path"
return $path
}
function New-ReleaseZip {
param(
[string]$ReleaseDir,
[string]$Version,
[string]$Root
)
$zipName = "ProxyGod-v$Version-windows-amd64.zip"
$zipPath = Join-Path $Root "releases\$zipName"
$releasesRoot = Split-Path $zipPath -Parent
if (-not (Test-Path $releasesRoot)) {
New-Item -ItemType Directory -Path $releasesRoot | Out-Null
}
if (Test-Path $zipPath) { Remove-Item -LiteralPath $zipPath -Force }
Compress-Archive -Path (Join-Path $ReleaseDir "*") -DestinationPath $zipPath -Force
Write-Host "Release zip: $zipPath"
return $zipPath
}