mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-23 11:27:29 +00:00

The -Environment argument to Start-Process is essentially being treated as a delta; removing a particular variable from the argument's hash table does not indicate to delete. Instead we must set the value of each unwanted variable to $null. Updates https://github.com/tailscale/corp/issues/29940 Signed-off-by: Aaron Klotz <aaron@tailscale.com>
227 lines
8.3 KiB
PowerShell
227 lines
8.3 KiB
PowerShell
# Copyright (c) Tailscale Inc & AUTHORS
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
#Requires -Version 7.4
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version 3.0
|
|
|
|
if (($Env:CI -eq 'true') -and ($Env:NOPWSHDEBUG -ne 'true')) {
|
|
Set-PSDebug -Trace 1
|
|
}
|
|
|
|
<#
|
|
.DESCRIPTION
|
|
Copies the script's $args variable into an array, which is easier to work with
|
|
when preparing to start child processes.
|
|
#>
|
|
function Copy-ScriptArgs {
|
|
$list = [System.Collections.Generic.List[string]]::new($Script:args.Count)
|
|
foreach ($arg in $Script:args) {
|
|
$list.Add($arg)
|
|
}
|
|
return $list.ToArray()
|
|
}
|
|
|
|
<#
|
|
.DESCRIPTION
|
|
Copies the current environment into a hashtable, which is easier to work with
|
|
when preparing to start child processes.
|
|
#>
|
|
function Copy-Environment {
|
|
$result = @{}
|
|
foreach ($pair in (Get-Item -Path Env:)) {
|
|
$result[$pair.Key] = $pair.Value
|
|
}
|
|
return $result
|
|
}
|
|
|
|
<#
|
|
.DESCRIPTION
|
|
Outputs the fully-qualified path to the repository's root directory. This
|
|
function expects to be run from somewhere within a git repository.
|
|
The directory containing the git executable must be somewhere in the PATH.
|
|
#>
|
|
function Get-RepoRoot {
|
|
Get-Command -Name 'git' | Out-Null
|
|
$repoRoot = & git rev-parse --show-toplevel
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "failed obtaining repo root: git failed with code $LASTEXITCODE"
|
|
}
|
|
|
|
# Git outputs a path containing forward slashes. Canonicalize.
|
|
return [System.IO.Path]::GetFullPath($repoRoot)
|
|
}
|
|
|
|
<#
|
|
.DESCRIPTION
|
|
Runs the provided ScriptBlock in a child scope, restoring any changes to the
|
|
current working directory once the script block completes.
|
|
#>
|
|
function Start-ChildScope {
|
|
param (
|
|
[Parameter(Mandatory = $true)]
|
|
[ScriptBlock]$ScriptBlock
|
|
)
|
|
|
|
$initialLocation = Get-Location
|
|
try {
|
|
Invoke-Command -ScriptBlock $ScriptBlock
|
|
}
|
|
finally {
|
|
Set-Location -Path $initialLocation
|
|
}
|
|
}
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Write-Output with timestamps prepended to each line.
|
|
#>
|
|
function Write-Log {
|
|
param ($message)
|
|
$timestamp = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
|
|
Write-Output "$timestamp - $message"
|
|
}
|
|
|
|
$bootstrapScriptBlock = {
|
|
|
|
$repoRoot = Get-RepoRoot
|
|
|
|
Set-Location -LiteralPath $repoRoot
|
|
|
|
switch -Wildcard -File .\go.toolchain.rev {
|
|
"/*" { $toolchain = $_ }
|
|
default {
|
|
$rev = $_
|
|
$tsgo = Join-Path $Env:USERPROFILE '.cache' 'tsgo'
|
|
$toolchain = Join-Path $tsgo $rev
|
|
if (-not (Test-Path -LiteralPath "$toolchain.extracted" -PathType Leaf -ErrorAction SilentlyContinue)) {
|
|
New-Item -Force -Path $tsgo -ItemType Directory | Out-Null
|
|
Remove-Item -Force -Recurse -LiteralPath $toolchain -ErrorAction SilentlyContinue
|
|
Write-Log "Downloading Go toolchain $rev"
|
|
|
|
# Values from https://web.archive.org/web/20250227081443/https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.architecture?view=net-9.0
|
|
$cpuArch = ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture | Out-String -NoNewline)
|
|
# Comparison in switch is case-insensitive by default.
|
|
switch ($cpuArch) {
|
|
'x86' { $goArch = '386' }
|
|
'x64' { $goArch = 'amd64' }
|
|
default { $goArch = $cpuArch }
|
|
}
|
|
|
|
Invoke-WebRequest -Uri "https://github.com/tailscale/go/releases/download/build-$rev/windows-$goArch.tar.gz" -OutFile "$toolchain.tar.gz"
|
|
try {
|
|
New-Item -Force -Path $toolchain -ItemType Directory | Out-Null
|
|
Start-ChildScope -ScriptBlock {
|
|
Set-Location -LiteralPath $toolchain
|
|
tar --strip-components=1 -xf "$toolchain.tar.gz"
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "tar failed with exit code $LASTEXITCODE"
|
|
}
|
|
}
|
|
$rev | Out-File -FilePath "$toolchain.extracted"
|
|
}
|
|
finally {
|
|
Remove-Item -Force "$toolchain.tar.gz" -ErrorAction Continue
|
|
}
|
|
|
|
# Cleanup old toolchains.
|
|
$maxDays = 90
|
|
$oldFiles = Get-ChildItem -Path $tsgo -Filter '*.extracted' -File -Recurse -Depth 1 | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-$maxDays) }
|
|
foreach ($file in $oldFiles) {
|
|
Write-Log "Cleaning up old Go toolchain $($file.Basename)"
|
|
Remove-Item -LiteralPath $file.FullName -Force -ErrorAction Continue
|
|
$dirName = Join-Path $file.DirectoryName $file.Basename -Resolve -ErrorAction Continue
|
|
if ($dirName -and (Test-Path -LiteralPath $dirName -PathType Container -ErrorAction Continue)) {
|
|
Remove-Item -LiteralPath $dirName -Recurse -Force -ErrorAction Continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($Env:TS_USE_GOCROSS -ne '1') {
|
|
return
|
|
}
|
|
|
|
if (Test-Path -LiteralPath $toolchain -PathType Container -ErrorAction SilentlyContinue) {
|
|
$goMod = Join-Path $repoRoot 'go.mod' -Resolve
|
|
$goLine = Get-Content -LiteralPath $goMod | Select-String -Pattern '^go (.*)$' -List
|
|
$wantGoMinor = $goLine.Matches.Groups[1].Value.split('.')[1]
|
|
$versionFile = Join-Path $toolchain 'VERSION'
|
|
if (Test-Path -LiteralPath $versionFile -PathType Leaf -ErrorAction SilentlyContinue) {
|
|
try {
|
|
$haveGoMinor = ((Get-Content -LiteralPath $versionFile -TotalCount 1).split('.')[1]) -replace 'rc.*', ''
|
|
}
|
|
catch {
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrEmpty($haveGoMinor) -or ($haveGoMinor -lt $wantGoMinor)) {
|
|
Remove-Item -Force -Recurse -LiteralPath $toolchain -ErrorAction Continue
|
|
Remove-Item -Force -LiteralPath "$toolchain.extracted" -ErrorAction Continue
|
|
}
|
|
}
|
|
|
|
$wantVer = & git rev-parse HEAD
|
|
$gocrossOk = $false
|
|
$gocrossPath = '.\gocross.exe'
|
|
if (Get-Command -Name $gocrossPath -CommandType Application -ErrorAction SilentlyContinue) {
|
|
$gotVer = & $gocrossPath gocross-version 2> $null
|
|
if ($gotVer -eq $wantVer) {
|
|
$gocrossOk = $true
|
|
}
|
|
}
|
|
|
|
if (-not $gocrossOk) {
|
|
$goBuildEnv = Copy-Environment
|
|
$goBuildEnv['CGO_ENABLED'] = '0'
|
|
# Start-Process's -Environment arg applies diffs, so instead of removing
|
|
# these variables from $goBuildEnv, we must set them to $null to indicate
|
|
# that they should be cleared.
|
|
$goBuildEnv['GOOS'] = $null
|
|
$goBuildEnv['GOARCH'] = $null
|
|
$goBuildEnv['GO111MODULE'] = $null
|
|
$goBuildEnv['GOROOT'] = $null
|
|
|
|
$procExe = Join-Path $toolchain 'bin' 'go.exe' -Resolve
|
|
$proc = Start-Process -FilePath $procExe -WorkingDirectory $repoRoot -Environment $goBuildEnv -ArgumentList 'build', '-o', $gocrossPath, "-ldflags=-X=tailscale.com/version.gitCommitStamp=$wantVer", 'tailscale.com/tool/gocross' -NoNewWindow -Wait -PassThru
|
|
if ($proc.ExitCode -ne 0) {
|
|
throw 'error building gocross'
|
|
}
|
|
}
|
|
|
|
} # bootstrapScriptBlock
|
|
|
|
Start-ChildScope -ScriptBlock $bootstrapScriptBlock
|
|
|
|
$repoRoot = Get-RepoRoot
|
|
|
|
$execEnv = Copy-Environment
|
|
# Start-Process's -Environment arg applies diffs, so instead of removing
|
|
# these variables from $execEnv, we must set them to $null to indicate
|
|
# that they should be cleared.
|
|
$execEnv['GOROOT'] = $null
|
|
|
|
$argList = Copy-ScriptArgs
|
|
|
|
if ($Env:TS_USE_GOCROSS -ne '1') {
|
|
$revFile = Join-Path $repoRoot 'go.toolchain.rev' -Resolve
|
|
switch -Wildcard -File $revFile {
|
|
"/*" { $toolchain = $_ }
|
|
default {
|
|
$rev = $_
|
|
$tsgo = Join-Path $Env:USERPROFILE '.cache' 'tsgo'
|
|
$toolchain = Join-Path $tsgo $rev -Resolve
|
|
}
|
|
}
|
|
|
|
$procExe = Join-Path $toolchain 'bin' 'go.exe' -Resolve
|
|
$proc = Start-Process -FilePath $procExe -WorkingDirectory $repoRoot -Environment $execEnv -ArgumentList $argList -NoNewWindow -Wait -PassThru
|
|
exit $proc.ExitCode
|
|
}
|
|
|
|
$procExe = Join-Path $repoRoot 'gocross.exe' -Resolve
|
|
$proc = Start-Process -FilePath $procExe -WorkingDirectory $repoRoot -Environment $execEnv -ArgumentList $argList -NoNewWindow -Wait -PassThru
|
|
exit $proc.ExitCode
|