[CmdletBinding()] param([string]$GoExecutable = 'go') # From a fresh clone: powershell -ExecutionPolicy Bypass -File scripts/build-web-arm64.ps1 # Requires Go 1.26.4+; the first frontend build downloads modules declared in go.sum. # Builds only the frontend/backend. Does not deploy, sign, or modify release/latest. $ErrorActionPreference = 'Stop' $projectRoot = [IO.Path]::GetFullPath((Split-Path -Parent $PSScriptRoot)) $outputRoot = Join-Path $projectRoot 'build\linux-arm64' $goCommand = Get-Command $GoExecutable -CommandType Application -ErrorAction Stop $goVersion = (& $goCommand.Source version) -join ' ' if ($LASTEXITCODE -ne 0 -or $goVersion -notmatch 'go(\d+\.\d+(?:\.\d+)?)') { throw 'Unable to read Go version' } if ([version]$Matches[1] -lt [version]'1.26.4') { throw 'Go 1.26.4 or newer is required' } foreach ($path in @((Join-Path $projectRoot 'build'), $outputRoot)) { if ((Test-Path -LiteralPath $path) -and ((Get-Item -LiteralPath $path).Attributes -band [IO.FileAttributes]::ReparsePoint)) { throw "Output directory link rejected: $path" } } $null = New-Item -ItemType Directory -Path $outputRoot -Force $targets = @( @{Module='backend'; Package='./cmd/tera-api'; Name='tera-clone-demo-api'; Vendor=$true}, @{Module='frontend'; Package='./cmd/server'; Name='tera-clone-demo-web'; Vendor=$false} ) foreach ($target in $targets) { $path = Join-Path $outputRoot $target.Name if (Test-Path -LiteralPath $path) { $item = Get-Item -LiteralPath $path if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) { throw "Output is not a regular file: $path" } } } $savedEnvironment = @{} foreach ($name in @('GOOS', 'GOARCH', 'CGO_ENABLED', 'GOWORK')) { $savedEnvironment[$name] = [Environment]::GetEnvironmentVariable($name, 'Process') } try { $env:GOOS = 'linux' $env:GOARCH = 'arm64' $env:CGO_ENABLED = '0' $env:GOWORK = 'off' foreach ($target in $targets) { Push-Location (Join-Path $projectRoot $target.Module) try { $buildArguments = @('build', '-buildvcs=false', '-trimpath') if ($target.Vendor) { $buildArguments += '-mod=vendor' } else { $buildArguments += '-mod=readonly' } $buildArguments += @('-o', (Join-Path $outputRoot $target.Name), $target.Package) & $goCommand.Source @buildArguments if ($LASTEXITCODE -ne 0) { throw "Build failed: $($target.Name)" } } finally { Pop-Location } } } finally { foreach ($name in $savedEnvironment.Keys) { [Environment]::SetEnvironmentVariable($name, $savedEnvironment[$name], 'Process') } } foreach ($target in $targets) { $path = Join-Path $outputRoot $target.Name if ((Get-Item -LiteralPath $path).Length -le 0) { throw "Empty build output: $path" } Write-Output "BUILT $path" Write-Output ("SHA256 " + (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant()) }