15
15
#
16
16
17
17
[CmdletBinding ()]
18
- param ([ switch ] $Install ,
19
- [ string ] $Configuration = (property Configuration Release))
18
+ param (
19
+ [ switch ] $Install ,
20
20
21
- # Final bits to release go here
22
- $targetDir = " bin/$Configuration /PSReadLine"
23
- if ($PSVersionTable.PSEdition -eq " Core" )
24
- {
25
- $target = " netcoreapp2.1"
26
- }
27
- else
28
- {
29
- $target = " net461"
30
- }
31
- Write-Verbose " Building for '$target '" - Verbose
21
+ [ValidateSet (" Debug" , " Release" )]
22
+ [string ]$Configuration = (property Configuration Release),
32
23
33
- $CLI_VERSION = " 2.1.300"
24
+ [ValidateSet (" net461" , " netcoreapp2.1" )]
25
+ [string ]$Framework
26
+ )
34
27
35
- function ConvertTo-CRLF ([string ] $text ) {
36
- $text.Replace (" `r`n " , " `n " ).Replace(" `n " , " `r`n " )
37
- }
38
-
39
- <#
40
- Synopsis: Ensure dotnet is installed
41
- #>
42
- task CheckDotnetInstalled `
43
- {
44
- $script :dotnet = (Get-Command dotnet - ErrorAction Ignore).Path
45
- if ($script :dotnet -eq $null )
46
- {
47
- $searchPaths = " ~/.dotnet/dotnet" , " ~\AppData\Local\Microsoft\dotnet\dotnet.exe"
48
- $foundDotnet = $false
49
- foreach ($path in $searchPaths )
50
- {
51
- if (Test-Path $path )
52
- {
53
- $foundDotnet = $true
54
- $script :dotnet = $path
55
- break
56
- }
57
- }
28
+ Import-Module " $PSScriptRoot /tools/helper.psm1"
58
29
59
- if (! $foundDotnet )
60
- {
61
- if ($env: APPVEYOR )
62
- {
63
- # Install dotnet to the default location, it will be cached via appveyor.yml
64
- $installScriptUri = " https://raw.githubusercontent.com/dotnet/cli/release/2.1/scripts/obtain/dotnet-install.ps1"
65
- $installDir = " ${env: LOCALAPPDATA} \Microsoft\dotnet"
66
- Invoke-WebRequest - Uri $installScriptUri - OutFile " ${env: TEMP} /dotnet-install.ps1"
67
- & " $env: TEMP /dotnet-install.ps1" - Version $CLI_VERSION - InstallDir $installDir
68
- $script :dotnet = Join-Path $installDir " dotnet.exe"
69
- }
70
- else
71
- {
72
- throw " Could not find 'dotnet' command. Install DotNetCore SDK and ensure it is in the path."
73
- }
74
- }
75
- }
76
- }
30
+ # Final bits to release go here
31
+ $targetDir = " bin/$Configuration /PSReadLine"
77
32
78
- <#
79
- Synopsis: Ensure nuget is installed
80
- #>
81
- task CheckNugetInstalled `
33
+ if (-not $Framework )
82
34
{
83
- $script :nugetExe = (Get-Command nuget.exe - ea Ignore).Path
84
- if ($null -eq $nugetExe )
85
- {
86
- $script :nugetExe = " ${env: TEMP} /nuget.exe"
87
- if (! (Test-Path $nugetExe ))
88
- {
89
- Invoke-WebRequest https:// dist.nuget.org/ win- x86- commandline/ latest/ nuget.exe - OutFile $nugetExe
90
- }
91
- }
35
+ $Framework = if ($PSVersionTable.PSEdition -eq " Core" ) { " netcoreapp2.1" } else { " net461" }
92
36
}
93
37
38
+ Write-Verbose " Building for '$Framework '" - Verbose
94
39
95
- <#
96
- Synopsis: Ensure platyPS is installed
97
- #>
98
- task CheckPlatyPSInstalled `
99
- {
100
- if ($null -eq (Get-Module - List platyPS))
101
- {
102
- Install-Module - Scope CurrentUser - Repository PSGallery - Name platyPS
103
- }
40
+ function ConvertTo-CRLF ([string ] $text ) {
41
+ $text.Replace (" `r`n " , " `n " ).Replace(" `n " , " `r`n " )
104
42
}
105
43
106
44
$buildMamlParams = @ {
@@ -118,9 +56,9 @@ task BuildMamlHelp @buildMamlParams {
118
56
$buildAboutTopicParams = @ {
119
57
Inputs = {
120
58
Get-ChildItem docs/ about_PSReadLine.help.txt
121
- " PSReadLine/bin/$Configuration /$target /Microsoft.PowerShell.PSReadLine2.dll"
122
- " $PSScriptRoot /GenerateFunctionHelp.ps1"
123
- " $PSScriptRoot /CheckHelp.ps1"
59
+ " PSReadLine/bin/$Configuration /$Framework /Microsoft.PowerShell.PSReadLine2.dll"
60
+ " $PSScriptRoot /tools/ GenerateFunctionHelp.ps1"
61
+ " $PSScriptRoot /tools/ CheckHelp.ps1"
124
62
}
125
63
Outputs = " $targetDir /en-US/about_PSReadLine.help.txt"
126
64
}
@@ -131,10 +69,10 @@ Synopsis: Generate about topic with function help
131
69
task BuildAboutTopic @buildAboutTopicParams {
132
70
# This step loads the dll that was just built, so only do that in another process
133
71
# so the file isn't locked in any way for the rest of the build.
72
+ $psExePath = Get-PSExePath
134
73
135
74
$generatedFunctionHelpFile = New-TemporaryFile
136
- $powershell = [System.Diagnostics.Process ]::GetCurrentProcess().MainModule.Filename
137
- & $powershell - NoProfile - NonInteractive - File $PSScriptRoot / GenerateFunctionHelp.ps1 $Configuration $generatedFunctionHelpFile.FullName
75
+ & $psExePath - NoProfile - NonInteractive - File $PSScriptRoot / tools/ GenerateFunctionHelp.ps1 $Configuration $generatedFunctionHelpFile.FullName
138
76
assert ($LASTEXITCODE -eq 0 ) " Generating function help failed"
139
77
140
78
$functionDescriptions = Get-Content - Raw $generatedFunctionHelpFile
@@ -143,20 +81,44 @@ task BuildAboutTopic @buildAboutTopicParams {
143
81
$newAboutTopic = $newAboutTopic -replace " `r`n " , " `n "
144
82
$newAboutTopic | Out-File - FilePath $targetDir \en- US\about_PSReadLine.help.txt - NoNewline - Encoding ascii
145
83
146
- & $powershell - NoProfile - NonInteractive - File $PSScriptRoot / CheckHelp.ps1 $Configuration
84
+ & $psExePath - NoProfile - NonInteractive - File $PSScriptRoot / tools / CheckHelp.ps1 $Configuration
147
85
assert ($LASTEXITCODE -eq 0 ) " Checking help and function signatures failed"
148
86
}
149
87
150
88
$binaryModuleParams = @ {
151
89
Inputs = { Get-ChildItem PSReadLine/* .cs, PSReadLine/ PSReadLine.csproj, PSReadLine/ PSReadLineResources.resx }
152
- Outputs = " PSReadLine/bin/$Configuration /$target /Microsoft.PowerShell.PSReadLine2.dll"
90
+ Outputs = " PSReadLine/bin/$Configuration /$Framework /Microsoft.PowerShell.PSReadLine2.dll"
91
+ }
92
+
93
+ $xUnitTestParams = @ {
94
+ Inputs = { Get-ChildItem test/* .cs, test/* .json, test/ PSReadLine.Tests.csproj }
95
+ Outputs = " test/bin/$Configuration /$Framework /PSReadLine.Tests.dll"
96
+ }
97
+
98
+ $mockPSConsoleParams = @ {
99
+ Inputs = { Get-ChildItem TestPSReadLine/* .cs, TestPSReadLine/ Program.manifest, TestPSReadLine/ TestPSReadLine.csproj }
100
+ Outputs = " TestPSReadLine/bin/$Configuration /$Framework /TestPSReadLine.dll"
153
101
}
154
102
155
103
<#
156
104
Synopsis: Build main binary module
157
105
#>
158
- task BuildMainModule @binaryModuleParams CheckDotnetInstalled, {
159
- exec { & $script :dotnet publish -f $target - c $Configuration PSReadLine }
106
+ task BuildMainModule @binaryModuleParams {
107
+ exec { dotnet publish -f $Framework - c $Configuration PSReadLine }
108
+ }
109
+
110
+ <#
111
+ Synopsis: Build xUnit tests
112
+ #>
113
+ task BuildXUnitTests @xUnitTestParams {
114
+ exec { dotnet publish -f $Framework - c $Configuration test }
115
+ }
116
+
117
+ <#
118
+ Synopsis: Build the mock powershell console.
119
+ #>
120
+ task BuildMockPSConsole @mockPSConsoleParams {
121
+ exec { dotnet publish -f $Framework - c $Configuration TestPSReadLine }
160
122
}
161
123
162
124
<#
@@ -171,150 +133,10 @@ task GenerateCatalog {
171
133
}
172
134
}
173
135
174
- $buildTestParams = @ {
175
- Inputs = { Get-ChildItem TestPSReadLine/* .cs, TestPSReadLine/ TestPSReadLine.csproj }
176
- Outputs = " TestPSReadLine/bin/$Configuration /TestPSReadLine.exe"
177
- }
178
-
179
-
180
136
<#
181
137
Synopsis: Run the unit tests
182
138
#>
183
- task RunTests BuildMainModule, {
184
- $env: PSREADLINE_TESTRUN = 1
185
-
186
- # need to copy implemented assemblies so test code can host powershell otherwise we have to build for a specific runtime
187
- if ($PSVersionTable.PSEdition -eq " Core" )
188
- {
189
- $psAssemblies = " System.Management.Automation.dll" , " Newtonsoft.Json.dll" , " System.Management.dll" , " System.DirectoryServices.dll"
190
- foreach ($assembly in $psAssemblies )
191
- {
192
- if (Test-Path " $PSHOME \$assembly " )
193
- {
194
- Copy-Item " $PSHOME \$assembly " " test\bin\$configuration \$target "
195
- }
196
- else
197
- {
198
- throw " Could not find '$PSHOME \$assembly '"
199
- }
200
- }
201
- }
202
-
203
- Push-Location test
204
- if ([System.Environment ]::OSVersion.Platform -eq [System.PlatformID ]::Win32NT)
205
- {
206
- Add-Type - Language CSharpVersion3 @'
207
- using System;
208
- using System.Collections.Generic;
209
- using System.Globalization;
210
- using System.Runtime.InteropServices;
211
- using System.Threading;
212
-
213
- public class KeyboardLayoutHelper
214
- {
215
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
216
- static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags);
217
-
218
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
219
- static extern IntPtr GetKeyboardLayout(uint idThread);
220
-
221
- [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
222
- static extern int GetKeyboardLayoutList(int nBuff, [Out] IntPtr[] lpList);
223
-
224
- // Used when setting the layout.
225
- [DllImport("user32.dll", CharSet = CharSet.Auto)]
226
- public static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
227
-
228
- // Used for getting the layout.
229
- [DllImport("user32.dll", SetLastError = true)]
230
- static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
231
-
232
- // Used in both getting and setting the layout
233
- [DllImport("user32.dll", SetLastError = true)]
234
- static extern IntPtr GetForegroundWindow();
235
-
236
- const int WM_INPUTLANGCHANGEREQUEST = 0x0050;
237
-
238
- private static string GetLayoutNameFromHKL(IntPtr hkl)
239
- {
240
- var lcid = (int)((uint)hkl & 0xffff);
241
- return (new CultureInfo(lcid)).Name;
242
- }
243
-
244
- public static IEnumerable<string> GetKeyboardLayouts()
245
- {
246
- int cnt = GetKeyboardLayoutList(0, null);
247
- var list = new IntPtr[cnt];
248
- GetKeyboardLayoutList(list.Length, list);
249
-
250
- foreach (var layout in list)
251
- {
252
- yield return GetLayoutNameFromHKL(layout);
253
- }
254
- }
255
-
256
- public static string GetCurrentKeyboardLayout()
257
- {
258
- uint processId;
259
- IntPtr layout = GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), out processId));
260
- return GetLayoutNameFromHKL(layout);
261
- }
262
-
263
- public static IntPtr SetKeyboardLayout(string lang)
264
- {
265
- var layoutId = (new CultureInfo(lang)).KeyboardLayoutId;
266
- var layout = LoadKeyboardLayout(layoutId.ToString("x8"), 0x80);
267
- // Hacky, but tests are probably running in a console app and the layout change
268
- // is ignored, so post the layout change to the foreground window.
269
- PostMessage(GetForegroundWindow(), WM_INPUTLANGCHANGEREQUEST, 0, layoutId);
270
- // Wait a bit until the layout has been changed.
271
- do {
272
- Thread.Sleep(100);
273
- } while (GetCurrentKeyboardLayout() != lang);
274
- return layout;
275
- }
276
- }
277
- '@
278
-
279
- # Remember the current keyboard layout, changes are system wide and restoring
280
- # is the nice thing to do.
281
- $savedLayout = [KeyboardLayoutHelper ]::GetCurrentKeyboardLayout()
282
-
283
- # We want to run tests in as many layouts as possible. We have key info
284
- # data for layouts that might not be installed, and tests would fail
285
- # if we don't set the system wide layout to match the key data we'll use.
286
- $layouts = [KeyboardLayoutHelper ]::GetKeyboardLayouts()
287
- Write-Output " Available layouts:" , $layouts
288
- foreach ($layout in $layouts )
289
- {
290
- if (Test-Path " KeyInfo-${layout} -windows.json" )
291
- {
292
- Write-Output " Testing $layout "
293
- $null = [KeyboardLayoutHelper ]::SetKeyboardLayout($layout )
294
- $os , $es = @ (New-TemporaryFile ; New-TemporaryFile )
295
- $filter = " FullyQualifiedName~Test.$ ( $layout -replace ' -' , ' _' ) _Windows"
296
- exec {
297
- # We have to use Start-Process so it creates a new window, because the keyboard
298
- # layout change won't be picked up by any processes running in the current conhost.
299
- $dnArgs = ' test' , ' --no-build' , ' -c' , $configuration , ' -f' , $target , ' --filter' , $filter , ' --logger' , ' trx'
300
- $p = Start-Process - FilePath $script :dotnet - Wait - PassThru - RedirectStandardOutput $os - RedirectStandardError $es - ArgumentList $dnArgs
301
- Get-Content $os , $es
302
- Remove-Item $os , $es
303
- # $global:LASTEXITCODE = $p.ExitCode
304
- }
305
- }
306
- }
307
- # Restore the original keyboard layout
308
- $null = [KeyboardLayoutHelper ]::SetKeyboardLayout($savedLayout )
309
- }
310
- else
311
- {
312
- exec { & $script :dotnet test -- no- build - c $configuration -f $target -- filter " FullyQualifiedName~Test.en_US_Linux" -- logger trx }
313
- }
314
- Pop-Location
315
-
316
- Remove-Item env:PSREADLINE_TESTRUN
317
- }
139
+ task RunTests BuildMainModule, BuildXUnitTests, { Start-TestRun - Configuration $Configuration - Framework $Framework }
318
140
319
141
<#
320
142
Synopsis: Copy all of the files that belong in the module to one place in the layout for installation
@@ -334,7 +156,7 @@ task LayoutModule BuildMainModule, BuildMamlHelp, {
334
156
Set-Content - Path (Join-Path $targetDir (Split-Path $file - Leaf)) - Value (ConvertTo-CRLF $content ) - Force
335
157
}
336
158
337
- $binPath = " PSReadLine/bin/$Configuration /$target /publish"
159
+ $binPath = " PSReadLine/bin/$Configuration /$Framework /publish"
338
160
Copy-Item $binPath / Microsoft.PowerShell.PSReadLine2.dll $targetDir
339
161
340
162
if (Test-Path $binPath / System.Runtime.InteropServices.RuntimeInformation.dll)
@@ -343,7 +165,7 @@ task LayoutModule BuildMainModule, BuildMamlHelp, {
343
165
}
344
166
else
345
167
{
346
- Write-Warning " Build using $target is not sufficient to be downlevel compatible"
168
+ Write-Warning " Build using $Framework is not sufficient to be downlevel compatible"
347
169
}
348
170
349
171
# Copy module manifest, but fix the version to match what we've specified in the binary module.
@@ -386,15 +208,13 @@ task LayoutModule BuildMainModule, BuildMamlHelp, {
386
208
}
387
209
}, BuildAboutTopic
388
210
389
-
390
211
<#
391
212
Synopsis: Zip up the binary for release.
392
213
#>
393
- task ZipRelease CheckDotNetInstalled , LayoutModule, {
214
+ task ZipRelease LayoutModule, {
394
215
Compress-Archive - Force - LiteralPath $targetDir - DestinationPath " bin/$Configuration /PSReadLine.zip"
395
216
}
396
217
397
-
398
218
<#
399
219
Synopsis: Install newly built PSReadLine
400
220
#>
@@ -497,4 +317,3 @@ task Clean {
497
317
Synopsis: Default build rule - build and create module layout
498
318
#>
499
319
task . LayoutModule, RunTests
500
-
0 commit comments