2026-10-21 20:40:13 +07:00
# Official Go archive bootstrap. URLs and install policy come from runtime config.
function Get-GoVersion([string]$Executable ) {
$output = & $Executable version 2 >& 1
if ( $LASTEXITCODE -ne 0 -or " $output " -notmatch '\bgo(\d+\.\d+(?:\.\d+)?)\b' ) { return $null }
return [ version ] $Matches [ 1 ]
}
2026-10-28 18:54:43 +07:00
function Confirm-GoToolchainInstall([version]$Minimum ) {
$answer = Read-Host "Go >= $Minimum is required to build. Download and install it now? [y/N]"
return $answer -match '^(?i:y|yes)$'
}
2026-10-21 20:40:13 +07:00
function Resolve-GoToolchain($Config ) {
$directive = Select-String -LiteralPath ( Resolve-ProjectPath 'go.mod' ) -Pattern '^go\s+(\d+\.\d+(?:\.\d+)?)\s*$' | Select-Object -First 1
if ( -not $directive ) { throw 'go.mod has no valid minimum Go version.' }
$minimum = [ version ] $directive . Matches [ 0 ]. Groups [ 1 ]. Value
$goName = $env:GAC_GO_COMMAND
if ([ string ]:: IsNullOrWhiteSpace ( $goName )) { $goName = $Config . go_command }
if ([ string ]:: IsNullOrWhiteSpace ( $goName )) { throw 'Set launcher.go_command or GAC_GO_COMMAND.' }
$found = Get-Command -Name $goName -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
if ( $found ) {
$version = Get-GoVersion $found . Source
if ( $version -and $version -ge $minimum ) { return $found . Source }
Write-Host "Configured Go is older than go.mod requires ( $minimum )."
}
$install = $Config . go_install
if ( -not $install -or $install . enabled -ne $true ) { throw "Go >= $minimum is required. Install it or enable launcher.go_install." }
$root = Resolve-ProjectPath $install . directory
$receiptPath = Join-Path $root 'toolchain.json'
if ( Test-Path -LiteralPath $receiptPath -PathType Leaf ) {
$receipt = Get-Content -LiteralPath $receiptPath -Raw | ConvertFrom-Json
$cached = [ IO.Path ]:: GetFullPath (( Join-Path $root $receipt . executable ))
if ( -not $cached . StartsWith ( $root . TrimEnd ( '\' ) + '\' , [ StringComparison ]:: OrdinalIgnoreCase )) { throw 'Managed Go receipt points outside its configured directory.' }
if ( Test-Path -LiteralPath $cached -PathType Leaf ) {
$version = Get-GoVersion $cached
if ( $version -and $version -ge $minimum ) { return $cached }
}
}
2026-10-28 18:54:43 +07:00
if ( -not ( Confirm-GoToolchainInstall $minimum )) { throw 'Go installation was declined. Install a compatible Go version, then run the build again.' }
2026-10-21 20:40:13 +07:00
$machineArch = $env:PROCESSOR_ARCHITEW6432
if ( -not $machineArch ) { $machineArch = $env:PROCESSOR_ARCHITECTURE }
$arch = switch ( $machineArch . ToUpperInvariant ()) { 'AMD64' { 'amd64' } 'ARM64' { 'arm64' } 'X86' { '386' } default { throw "Unsupported Windows architecture: $machineArch " } }
[ Net.ServicePointManager ]:: SecurityProtocol = [ Net.ServicePointManager ]:: SecurityProtocol -bor [ Net.SecurityProtocolType ]:: Tls12
Write-Host "Downloading Go release metadata ( $( $install . manifest_url ) )..."
$releases = Invoke-RestMethod -Uri $install . manifest_url
$release = $releases | Where-Object { $_ . stable -and $_ . version -match '^go\d+\.\d+\.\d+$' -and [ version ] $_ . version . Substring ( 2 ) -ge $minimum } | Sort-Object { [ version ] $_ . version . Substring ( 2 ) } -Descending | Select-Object -First 1
if ( -not $release ) { throw "No stable Go >= $minimum in the configured official manifest." }
$archive = $release . files | Where-Object { $_ . os -eq 'windows' -and $_ . arch -eq $arch -and $_ . kind -eq 'archive' -and $_ . filename -match '^[a-zA-Z0-9._-]+\.zip$' } | Select-Object -First 1
if ( -not $archive -or $archive . sha256 -notmatch '^[a-fA-F0-9]{64}$' ) { throw 'Official manifest has no valid Windows ZIP/checksum for this machine.' }
New-Item -ItemType Directory -Path $root -Force | Out-Null
# Always extract to a new directory; never overlay an older Go installation.
$folderName = [ Guid ]:: NewGuid (). ToString ( 'N' )
$folder = Join-Path $root $folderName
$zip = Join-Path $root ( $folderName + '.zip' )
$download = $install . download_url . TrimEnd ( '/' ) + '/' + $archive . filename
Write-Host "Installing $( $release . version ) ( $arch ), without administrator rights..."
Invoke-WebRequest -Uri $download -OutFile $zip -UseBasicParsing
if (( Get-FileHash -LiteralPath $zip -Algorithm SHA256 ). Hash -ine $archive . sha256 ) { throw "Go archive checksum mismatch: $zip " }
Expand-Archive -LiteralPath $zip -DestinationPath $folder
$relative = Join-Path $folderName 'go/bin/go.exe'
$executable = Join-Path $root $relative
$version = Get-GoVersion $executable
if ( -not $version -or $version -lt $minimum ) { throw 'Downloaded Go did not pass its version check.' }
@ { executable = $relative ; version = $release . version ; sha256 = $archive . sha256 } | ConvertTo-Json | Set-Content -LiteralPath $receiptPath -Encoding UTF8
Remove-Item -LiteralPath $zip
Write-Host "Go ready: $version "
return $executable
}