|
| 1 | +# Initialize variables if they aren't already defined |
| 2 | + |
| 3 | +$ci = if (Test-Path variable:ci) { $ci } else { $false } |
| 4 | +$configuration = if (Test-Path variable:configuration) { $configuration } else { "Debug" } |
| 5 | +$nodereuse = if (Test-Path variable:nodereuse) { $nodereuse } else { !$ci } |
| 6 | +$prepareMachine = if (Test-Path variable:prepareMachine) { $prepareMachine } else { $false } |
| 7 | +$restore = if (Test-Path variable:restore) { $restore } else { $true } |
| 8 | +$verbosity = if (Test-Path variable:verbosity) { $verbosity } else { "minimal" } |
| 9 | +$warnaserror = if (Test-Path variable:warnaserror) { $warnaserror } else { $true } |
| 10 | +$msbuildEngine = if (Test-Path variable:msbuildEngine) { $msbuildEngine } else { $null } |
| 11 | +$useInstalledDotNetCli = if (Test-Path variable:useInstalledDotNetCli) { $useInstalledDotNetCli } else { $true } |
| 12 | + |
| 13 | +set-strictmode -version 2.0 |
| 14 | +$ErrorActionPreference = "Stop" |
| 15 | +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 |
| 16 | + |
| 17 | +function Create-Directory([string[]] $path) { |
| 18 | + if (!(Test-Path $path)) { |
| 19 | + New-Item -path $path -force -itemType "Directory" | Out-Null |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +function InitializeDotNetCli([bool]$install) { |
| 24 | + # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism |
| 25 | + $env:DOTNET_MULTILEVEL_LOOKUP=0 |
| 26 | + |
| 27 | + # Disable first run since we do not need all ASP.NET packages restored. |
| 28 | + $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 |
| 29 | + |
| 30 | + # Source Build uses DotNetCoreSdkDir variable |
| 31 | + if ($env:DotNetCoreSdkDir -ne $null) { |
| 32 | + $env:DOTNET_INSTALL_DIR = $env:DotNetCoreSdkDir |
| 33 | + } |
| 34 | + |
| 35 | + # Find the first path on %PATH% that contains the dotnet.exe |
| 36 | + if ($useInstalledDotNetCli -and ($env:DOTNET_INSTALL_DIR -eq $null)) { |
| 37 | + $env:DOTNET_INSTALL_DIR = ${env:PATH}.Split(';') | where { ($_ -ne "") -and (Test-Path (Join-Path $_ "dotnet.exe")) } |
| 38 | + } |
| 39 | + |
| 40 | + $dotnetSdkVersion = $GlobalJson.tools.dotnet |
| 41 | + |
| 42 | + # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version, |
| 43 | + # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues. |
| 44 | + if (($env:DOTNET_INSTALL_DIR -ne $null) -and (Test-Path(Join-Path $env:DOTNET_INSTALL_DIR "sdk\$dotnetSdkVersion"))) { |
| 45 | + $dotnetRoot = $env:DOTNET_INSTALL_DIR |
| 46 | + } else { |
| 47 | + $dotnetRoot = Join-Path $RepoRoot ".dotnet" |
| 48 | + $env:DOTNET_INSTALL_DIR = $dotnetRoot |
| 49 | + |
| 50 | + if (-not (Test-Path(Join-Path $env:DOTNET_INSTALL_DIR "sdk\$dotnetSdkVersion"))) { |
| 51 | + if ($install) { |
| 52 | + InstallDotNetSdk $dotnetRoot $dotnetSdkVersion |
| 53 | + } else { |
| 54 | + Write-Host "Unable to find dotnet with SDK version '$dotnetSdkVersion'" -ForegroundColor Red |
| 55 | + ExitWithExitCode 1 |
| 56 | + } |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + return $dotnetRoot |
| 61 | +} |
| 62 | + |
| 63 | +function GetDotNetInstallScript([string] $dotnetRoot) { |
| 64 | + $installScript = "$dotnetRoot\dotnet-install.ps1" |
| 65 | + if (!(Test-Path $installScript)) { |
| 66 | + Create-Directory $dotnetRoot |
| 67 | + Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile $installScript |
| 68 | + } |
| 69 | + |
| 70 | + return $installScript |
| 71 | +} |
| 72 | + |
| 73 | +function InstallDotNetSdk([string] $dotnetRoot, [string] $version) { |
| 74 | + $installScript = GetDotNetInstallScript $dotnetRoot |
| 75 | + & $installScript -Version $version -InstallDir $dotnetRoot |
| 76 | + if ($lastExitCode -ne 0) { |
| 77 | + Write-Host "Failed to install dotnet cli (exit code '$lastExitCode')." -ForegroundColor Red |
| 78 | + ExitWithExitCode $lastExitCode |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +function InitializeVisualStudioBuild { |
| 83 | + $vsToolsPath = $env:VS150COMNTOOLS |
| 84 | + if ($vsToolsPath -eq $null) { |
| 85 | + $vsToolsPath = $env:VS160COMNTOOLS |
| 86 | + } |
| 87 | + |
| 88 | + if (($vsToolsPath -ne $null) -and (Test-Path $vsToolsPath)) { |
| 89 | + $vsInstallDir = [System.IO.Path]::GetFullPath((Join-Path $vsToolsPath "..\..")) |
| 90 | + } else { |
| 91 | + $vsInfo = LocateVisualStudio |
| 92 | + |
| 93 | + $vsInstallDir = $vsInfo.installationPath |
| 94 | + $vsSdkInstallDir = Join-Path $vsInstallDir "VSSDK\" |
| 95 | + $vsVersion = $vsInfo.installationVersion.Split('.')[0] + "0" |
| 96 | + |
| 97 | + Set-Item "env:VS$($vsVersion)COMNTOOLS" (Join-Path $vsInstallDir "Common7\Tools\") |
| 98 | + Set-Item "env:VSSDK$($vsVersion)Install" $vsSdkInstallDir |
| 99 | + $env:VSSDKInstall = $vsSdkInstallDir |
| 100 | + } |
| 101 | + |
| 102 | + return $vsInstallDir |
| 103 | +} |
| 104 | + |
| 105 | +function LocateVisualStudio { |
| 106 | + $vswhereVersion = $GlobalJson.tools.vswhere |
| 107 | + |
| 108 | + if (!$vsWhereVersion) { |
| 109 | + Write-Host "vswhere version must be specified in /global.json." -ForegroundColor Red |
| 110 | + ExitWithExitCode 1 |
| 111 | + } |
| 112 | + |
| 113 | + $toolsRoot = Join-Path $RepoRoot ".tools" |
| 114 | + $vsWhereDir = Join-Path $toolsRoot "vswhere\$vswhereVersion" |
| 115 | + $vsWhereExe = Join-Path $vsWhereDir "vswhere.exe" |
| 116 | + |
| 117 | + if (!(Test-Path $vsWhereExe)) { |
| 118 | + Create-Directory $vsWhereDir |
| 119 | + Write-Host "Downloading vswhere" |
| 120 | + Invoke-WebRequest "https://github.com/Microsoft/vswhere/releases/download/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe |
| 121 | + } |
| 122 | + |
| 123 | + $vsInfo = & $vsWhereExe ` |
| 124 | + -latest ` |
| 125 | + -prerelease ` |
| 126 | + -format json ` |
| 127 | + -requires Microsoft.Component.MSBuild ` |
| 128 | + -requires Microsoft.VisualStudio.Component.VSSDK ` |
| 129 | + -requires Microsoft.VisualStudio.Component.Roslyn.Compiler | ConvertFrom-Json |
| 130 | + |
| 131 | + if ($lastExitCode -ne 0) { |
| 132 | + Write-Host "Failed to locate Visual Studio (exit code '$lastExitCode')." -ForegroundColor Red |
| 133 | + ExitWithExitCode $lastExitCode |
| 134 | + } |
| 135 | + |
| 136 | + # use first matching instance |
| 137 | + return $vsInfo[0] |
| 138 | +} |
| 139 | + |
| 140 | +function ConfigureTools { |
| 141 | + # Include custom tools configuration |
| 142 | + $script = Join-Path $EngRoot "configure-toolset.ps1" |
| 143 | + |
| 144 | + if (Test-Path $script) { |
| 145 | + . $script |
| 146 | + } |
| 147 | +} |
| 148 | + |
| 149 | +function InitializeTools() { |
| 150 | + ConfigureTools |
| 151 | + |
| 152 | + $tools = $GlobalJson.tools |
| 153 | + |
| 154 | + # Initialize dotnet cli if listed in 'tools' |
| 155 | + $dotnetRoot = $null |
| 156 | + if ((Get-Member -InputObject $tools -Name "dotnet") -ne $null) { |
| 157 | + $dotnetRoot = InitializeDotNetCli -install:$restore |
| 158 | + } |
| 159 | + |
| 160 | + if (-not $msbuildEngine) { |
| 161 | + # Presence of vswhere.version indicates the repo needs to build using VS msbuild. |
| 162 | + if ((Get-Member -InputObject $tools -Name "vswhere") -ne $null) { |
| 163 | + $msbuildEngine = "vs" |
| 164 | + } elseif ($dotnetRoot -ne $null) { |
| 165 | + $msbuildEngine = "dotnet" |
| 166 | + } else { |
| 167 | + Write-Host "-msbuildEngine must be specified, or /global.json must specify 'tools.dotnet' or 'tools.vswhere'." -ForegroundColor Red |
| 168 | + ExitWithExitCode 1 |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + if ($msbuildEngine -eq "dotnet") { |
| 173 | + if (!$dotnetRoot) { |
| 174 | + Write-Host "/global.json must specify 'tools.dotnet'." -ForegroundColor Red |
| 175 | + ExitWithExitCode 1 |
| 176 | + } |
| 177 | + |
| 178 | + $script:buildDriver = Join-Path $dotnetRoot "dotnet.exe" |
| 179 | + $script:buildArgs = "msbuild" |
| 180 | + } elseif ($msbuildEngine -eq "vs") { |
| 181 | + $vsInstallDir = InitializeVisualStudioBuild |
| 182 | + |
| 183 | + $script:buildDriver = Join-Path $vsInstallDir "MSBuild\15.0\Bin\msbuild.exe" |
| 184 | + $script:buildArgs = "" |
| 185 | + } else { |
| 186 | + Write-Host "Unexpected value of -msbuildEngine: '$msbuildEngine'." -ForegroundColor Red |
| 187 | + ExitWithExitCode 1 |
| 188 | + } |
| 189 | + |
| 190 | + InitializeToolSet $script:buildDriver $script:buildArgs |
| 191 | + InitializeCustomToolset |
| 192 | +} |
| 193 | + |
| 194 | +function InitializeToolset([string] $buildDriver, [string]$buildArgs) { |
| 195 | + $toolsetVersion = $GlobalJson.'msbuild-sdks'.'Microsoft.DotNet.Arcade.Sdk' |
| 196 | + $toolsetLocationFile = Join-Path $ToolsetDir "$toolsetVersion.txt" |
| 197 | + |
| 198 | + if (Test-Path $toolsetLocationFile) { |
| 199 | + $path = Get-Content $toolsetLocationFile -TotalCount 1 |
| 200 | + if (Test-Path $path) { |
| 201 | + $script:ToolsetBuildProj = $path |
| 202 | + return |
| 203 | + } |
| 204 | + } |
| 205 | + |
| 206 | + if (-not $restore) { |
| 207 | + Write-Host "Toolset version $toolsetVersion has not been restored." |
| 208 | + ExitWithExitCode 1 |
| 209 | + } |
| 210 | + |
| 211 | + $ToolsetRestoreLog = Join-Path $LogDir "ToolsetRestore.binlog" |
| 212 | + $proj = Join-Path $ToolsetDir "restore.proj" |
| 213 | + |
| 214 | + '<Project Sdk="Microsoft.DotNet.Arcade.Sdk"/>' | Set-Content $proj |
| 215 | + MSBuild $proj /t:__WriteToolsetLocation /clp:None /bl:$ToolsetRestoreLog /p:__ToolsetLocationOutputFile=$toolsetLocationFile |
| 216 | + |
| 217 | + if ($lastExitCode -ne 0) { |
| 218 | + Write-Host "Failed to restore toolset (exit code '$lastExitCode'). See log: $ToolsetRestoreLog" -ForegroundColor Red |
| 219 | + ExitWithExitCode $lastExitCode |
| 220 | + } |
| 221 | + |
| 222 | + $path = Get-Content $toolsetLocationFile -TotalCount 1 |
| 223 | + if (!(Test-Path $path)) { |
| 224 | + throw "Invalid toolset path: $path" |
| 225 | + } |
| 226 | + |
| 227 | + $script:ToolsetBuildProj = $path |
| 228 | +} |
| 229 | + |
| 230 | +function InitializeCustomToolset { |
| 231 | + if (-not $restore) { |
| 232 | + return |
| 233 | + } |
| 234 | + |
| 235 | + $script = Join-Path $EngRoot "restore-toolset.ps1" |
| 236 | + |
| 237 | + if (Test-Path $script) { |
| 238 | + . $script |
| 239 | + } |
| 240 | +} |
| 241 | + |
| 242 | +function ExitWithExitCode([int] $exitCode) { |
| 243 | + if ($ci -and $prepareMachine) { |
| 244 | + Stop-Processes |
| 245 | + } |
| 246 | + exit $exitCode |
| 247 | +} |
| 248 | + |
| 249 | +function Stop-Processes() { |
| 250 | + Write-Host "Killing running build processes..." |
| 251 | + Get-Process -Name "msbuild" -ErrorAction SilentlyContinue | Stop-Process |
| 252 | + Get-Process -Name "dotnet" -ErrorAction SilentlyContinue | Stop-Process |
| 253 | + Get-Process -Name "vbcscompiler" -ErrorAction SilentlyContinue | Stop-Process |
| 254 | +} |
| 255 | + |
| 256 | +function MsBuild() { |
| 257 | + $warnaserrorSwitch = if ($warnaserror) { "/warnaserror" } else { "" } |
| 258 | + & $buildDriver $buildArgs $warnaserrorSwitch /m /nologo /clp:Summary /v:$verbosity /nr:$nodereuse $args |
| 259 | +} |
| 260 | + |
| 261 | +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot "..\..") |
| 262 | +$EngRoot = Resolve-Path (Join-Path $PSScriptRoot "..") |
| 263 | +$ArtifactsDir = Join-Path $RepoRoot "artifacts" |
| 264 | +$ToolsetDir = Join-Path $ArtifactsDir "toolset" |
| 265 | +$LogDir = Join-Path (Join-Path $ArtifactsDir "log") $configuration |
| 266 | +$TempDir = Join-Path (Join-Path $ArtifactsDir "tmp") $configuration |
| 267 | +$GlobalJson = Get-Content -Raw -Path (Join-Path $RepoRoot "global.json") | ConvertFrom-Json |
| 268 | + |
| 269 | +if ($env:NUGET_PACKAGES -eq $null) { |
| 270 | + # Use local cache on CI to ensure deterministic build, |
| 271 | + # use global cache in dev builds to avoid cost of downloading packages. |
| 272 | + $env:NUGET_PACKAGES = if ($ci) { Join-Path $RepoRoot ".packages" } |
| 273 | + else { Join-Path $env:UserProfile ".nuget\packages" } |
| 274 | +} |
| 275 | + |
| 276 | +Create-Directory $ToolsetDir |
| 277 | +Create-Directory $LogDir |
| 278 | + |
| 279 | +if ($ci) { |
| 280 | + Create-Directory $TempDir |
| 281 | + $env:TEMP = $TempDir |
| 282 | + $env:TMP = $TempDir |
| 283 | +} |
0 commit comments