1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
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 Normalize-Arch {
param(
[Parameter(Mandatory=$true)]
[string] $Arch
)
if ($Arch -eq 'Win32') {
# 'Win32' is a common name for x86, and the scripts seem to
# only support 'x86'.
'x86'
} else {
# Default to the user-provided value, in case something like
# 'ARM' is supported.
$arch
}
}
New-Variable arch -Value (Normalize-Arch '${{ inputs.arch }}') -Option Constant
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,
[Parameter(Mandatory=$true)]
[string] $Arch
)
$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=$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,
[Parameter(Mandatory=$true)]
[string] $Arch
)
$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=$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 $arch
} catch {
echo $_
Import-CMD $info $arch
}
$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
|