|
|
name: Visual Studio shell
description: Set up Visual Studio paths and environment variables
inputs:
arch:
description: Target architecture
required: false
default: x64
runs:
using: composite
steps:
- run: |
function Locate-VSWhere {
$path = Get-Command 'vswhere' -ErrorAction SilentlyContinue
if ($path) {
$path.Path
} else {
Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio' 'Installer' 'vswhere'
}
}
function Locate-VS {
# vswhere doesn't search for Build Tools by default, God knows why.
# https://github.com/microsoft/vswhere/issues/22
$products = 'Community','Professional','Enterprise','BuildTools' | %{ "Microsoft.VisualStudio.Product.$_" }
$vswhere = Locate-VSWhere
& $vswhere -products $products -latest -format json | ConvertFrom-Json
}
function Import-PS {
# VS 2019 includes Microsoft.VisualStudio.DevShell.dll, which does
# what we want.
#
# It also includes Launch-VsDevShell.ps1, which sort of does the
# same thing this function does, but it always sets up 32-bit
# shell, which is stupid. I use the same workaround as in
# https://developercommunity.visualstudio.com/idea/943058/x64-developer-powershell-for-vs-2019.html
param(
[Parameter(Mandatory=$true)]
[object] $info
)
$tools_path = Join-Path $info.installationPath 'Common7' 'Tools'
$module_name = 'Microsoft.VisualStudio.DevShell.dll'
$module_path = Join-Path $tools_path $module_name
if (!(Test-Path $module_path -Type Leaf)) {
$module_path = Join-Path $tools_path 'vsdevshell' $module_name
}
if (!(Test-Path $module_path -Type Leaf)) {
throw "Couldn't find module '$module_name'"
}
Import-Module $module_path
Enter-VsDevShell -VsInstanceId $info.instanceId -SkipAutomaticLocation -DevCmdArguments '-arch=${{ inputs.arch }} -no_logo'
}
function Import-CMD {
# For Visual Studio 2017, there's no Microsoft.VisualStudio.DevShell.dll,
# so we have to work around that. One workaround I found here:
# https://github.com/microsoft/vswhere/issues/150
param(
[Parameter(Mandatory=$true)]
[object] $info
)
$tools_path = Join-Path $info.installationPath 'Common7' 'Tools'
$script_name = 'VsDevCmd.bat'
$script_path = Join-Path $tools_path $script_name
if (!(Test-Path $script_path -Type Leaf)) {
throw "Couldn't find script '$script_name'"
}
# OK, the following issue is royally stupid. At one point, I
# started getting errors like this:
#
# Conversion from JSON failed with error: Unexpected character encountered while parsing value: W.
#
# They appeared out of nowhere, without any changes in the code.
# Turns out, ConvertTo-Json is pretty much unusable by default.
# See, it has a `-Depth` parameter, which has a default value of 2,
# which is insanely low. I don't know what it does if the input
# exceeds the nesting depth of 2, but I do know that starting from
# Powershell 7.1, ConvertTo-Json prints a "helpful" warning in this
# case. The warning looks like this:
#
# WARNING: Resulting JSON is truncated as serialization has exceeded the set depth of 2.
#
# Apparently, PowerShell on windows-2016 images got upgraded, hence
# the failure to parse the letter W. I _accidentally_ fixed it by
# adding "Select-Object Name,Value" to the pipeline, cutting the
# nesting depth, so keeping that part in the pipeline is important.
#
# See also:
#
# * https://github.com/PowerShell/PowerShell/issues/8393
# * https://stackoverflow.com/q/53583677/514684
# * https://stackoverflow.com/q/53562942/514684
$json = $(& "${env:COMSPEC}" /s /c "`"$script_path`" -arch=${{ inputs.arch }} -no_logo && pwsh -Command `"Get-ChildItem env: | Select-Object Name,Value | ConvertTo-Json`"")
if ($LASTEXITCODE -ne 0) {
throw $json
} else {
try {
$json | ConvertFrom-Json | %{ Set-Content "env:$($_.Name)" $_.Value }
} catch {
echo 'There was a problem with the following JSON:'
echo $json
throw
}
}
}
if ('${{ runner.os }}' -ne 'Windows') {
echo 'Not going to set up a Visual Studio shell on ${{ runner.os }}'
} else {
$old_values = @{}
Get-ChildItem env: | %{ $old_values.Add($_.Name, $_.Value) }
$info = Locate-VS
try {
Import-PS $info
} catch {
echo $_
Import-CMD $info
}
$new_values = @{}
Get-ChildItem env: | %{ $new_values.Add($_.Name, $_.Value) }
# Some diagnostics as to which exact variables were modified follows:
echo '----------------------------------------------------------------'
echo 'New variables'
echo '----------------------------------------------------------------'
$new_values.GetEnumerator() | where { -not $old_values.ContainsKey($_.Name) } | Format-List
echo '----------------------------------------------------------------'
echo 'Modified variables'
echo '----------------------------------------------------------------'
$new_values.GetEnumerator() | where { $old_values.ContainsKey($_.Name) -and $old_values[$_.Name] -ne $_.Value } | Format-List
# Update the current environment:
Get-ChildItem env: | %{ echo "$($_.Name)=$($_.Value)" >> $env:GITHUB_ENV }
}
shell: pwsh
branding:
icon: star
color: green
|