Skip to content

Commit 65a7a79

Browse files
authored
Isolate PSES dependencies from PowerShell on load + make PSES a pure binary module (#1118)
* Move PSES startup to a binary module * Factor out startup into own assembly * Separate out dependencies to allow multiple versions of loaded assemblies * Improve netstandard coverage on older .NET Framework platforms
1 parent a450f12 commit 65a7a79

37 files changed

+2974
-1857
lines changed

.editorconfig

+3
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ trim_trailing_whitespace = true
2121

2222
[*.{ps1xml,props,xml,yaml}]
2323
indent_size = 2
24+
25+
# CA1303: Do not pass literals as localized parameters
26+
dotnet_diagnostic.CA1303.severity = none

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ docs/metadata/
3737
*.zip
3838

3939
# Generated build info file
40-
src/PowerShellEditorServices/Hosting/BuildInfo.cs
40+
src/PowerShellEditorServices.Hosting/BuildInfo.cs
4141

4242
# quickbuild.exe
4343
/VersionGeneratingLogs/

PowerShellEditorServices.build.ps1

+101-179
Original file line numberDiff line numberDiff line change
@@ -19,149 +19,23 @@ param(
1919
#Requires -Modules @{ModuleName="InvokeBuild";ModuleVersion="3.2.1"}
2020

2121
$script:IsUnix = $PSVersionTable.PSEdition -and $PSVersionTable.PSEdition -eq "Core" -and !$IsWindows
22-
$script:TargetPlatform = "netstandard2.0"
23-
$script:TargetFrameworksParam = "/p:TargetFrameworks=`"$script:TargetPlatform`""
2422
$script:RequiredSdkVersion = (Get-Content (Join-Path $PSScriptRoot 'global.json') | ConvertFrom-Json).sdk.version
25-
$script:NugetApiUriBase = 'https://www.nuget.org/api/v2/package'
26-
$script:ModuleBinPath = "$PSScriptRoot/module/PowerShellEditorServices/bin/"
27-
$script:VSCodeModuleBinPath = "$PSScriptRoot/module/PowerShellEditorServices.VSCode/bin/"
28-
$script:WindowsPowerShellFrameworkTarget = 'net461'
29-
$script:NetFrameworkPlatformId = 'win'
30-
$script:BuildInfoPath = [System.IO.Path]::Combine($PSScriptRoot, "src", "PowerShellEditorServices", "Hosting", "BuildInfo.cs")
31-
32-
$script:PSCoreModulePath = $null
33-
34-
$script:TestRuntime = @{
35-
'Core' = 'netcoreapp2.1'
36-
'Desktop' = 'net461'
37-
}
23+
$script:BuildInfoPath = [System.IO.Path]::Combine($PSScriptRoot, "src", "PowerShellEditorServices.Hosting", "BuildInfo.cs")
3824

39-
<#
40-
Declarative specification of binary assets produced
41-
in the build that need to be binplaced in the module.
42-
Schema is:
43-
{
44-
<Output Path>: {
45-
<Project Name>: [
46-
<FilePath From Project Build Folder>
47-
]
48-
}
25+
$script:NetRuntime = @{
26+
Core = 'netcoreapp2.1'
27+
Desktop = 'net461'
28+
Standard = 'netstandard2.0'
4929
}
50-
#>
51-
$script:RequiredBuildAssets = @{
52-
$script:ModuleBinPath = @{
53-
'PowerShellEditorServices' = @(
54-
'publish/Microsoft.Extensions.DependencyInjection.Abstractions.dll',
55-
'publish/Microsoft.Extensions.DependencyInjection.dll',
56-
'publish/Microsoft.Extensions.FileSystemGlobbing.dll',
57-
'publish/Microsoft.Extensions.Logging.Abstractions.dll',
58-
'publish/Microsoft.Extensions.Logging.dll',
59-
'publish/Microsoft.Extensions.Options.dll',
60-
'publish/Microsoft.Extensions.Primitives.dll',
61-
'publish/Microsoft.PowerShell.EditorServices.dll',
62-
'publish/Microsoft.PowerShell.EditorServices.pdb',
63-
'publish/Newtonsoft.Json.dll',
64-
'publish/OmniSharp.Extensions.JsonRpc.dll',
65-
'publish/OmniSharp.Extensions.LanguageProtocol.dll',
66-
'publish/OmniSharp.Extensions.LanguageServer.dll',
67-
'publish/OmniSharp.Extensions.DebugAdapter.dll',
68-
'publish/OmniSharp.Extensions.DebugAdapter.Server.dll',
69-
'publish/MediatR.dll',
70-
'publish/MediatR.Extensions.Microsoft.DependencyInjection.dll',
71-
'publish/runtimes/linux-64/native/libdisablekeyecho.so',
72-
'publish/runtimes/osx-64/native/libdisablekeyecho.dylib',
73-
'publish/Serilog.dll',
74-
'publish/Serilog.Extensions.Logging.dll',
75-
'publish/Serilog.Sinks.File.dll',
76-
'publish/System.Reactive.dll',
77-
'publish/UnixConsoleEcho.dll'
78-
)
79-
}
8030

81-
$script:VSCodeModuleBinPath = @{
82-
'PowerShellEditorServices.VSCode' = @(
83-
'Microsoft.PowerShell.EditorServices.VSCode.dll',
84-
'Microsoft.PowerShell.EditorServices.VSCode.pdb'
85-
)
86-
}
87-
}
88-
89-
<#
90-
Declares the binary shims we need to make the netstandard DLLs hook into .NET Framework.
91-
Schema is:
92-
{
93-
<Destination Bin Directory>: [{
94-
'PackageName': <Package Name>,
95-
'PackageVersion': <Package Version>,
96-
'TargetRuntime': <Target .NET Runtime>,
97-
'DllName'?: <Name of DLL to extract>
98-
}]
99-
}
100-
#>
101-
$script:RequiredNugetBinaries = @{
102-
'Desktop' = @(
103-
@{ PackageName = 'System.Security.Principal.Windows'; PackageVersion = '4.5.0'; TargetRuntime = 'net461' },
104-
@{ PackageName = 'System.Security.AccessControl'; PackageVersion = '4.5.0'; TargetRuntime = 'net461' },
105-
@{ PackageName = 'System.IO.Pipes.AccessControl'; PackageVersion = '4.5.1'; TargetRuntime = 'net461' }
106-
)
107-
}
31+
$script:HostCoreOutput = "$PSScriptRoot/src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetRuntime.Core)/publish"
32+
$script:HostDeskOutput = "$PSScriptRoot/src/PowerShellEditorServices.Hosting/bin/$Configuration/$($script:NetRuntime.Desktop)/publish"
33+
$script:PsesOutput = "$PSScriptRoot/src/PowerShellEditorServices/bin/$Configuration/$($script:NetRuntime.Standard)/publish"
34+
$script:VSCodeOutput = "$PSScriptRoot/src/PowerShellEditorServices.VSCode/bin/$Configuration/$($script:NetRuntime.Standard)/publish"
10835

10936
if (Get-Command git -ErrorAction SilentlyContinue) {
11037
# ignore changes to this file
111-
git update-index --assume-unchanged "$PSScriptRoot/src/PowerShellEditorServices.Host/BuildInfo/BuildInfo.cs"
112-
}
113-
114-
if ($PSVersionTable.PSEdition -ne "Core") {
115-
Add-Type -Assembly System.IO.Compression.FileSystem
116-
}
117-
118-
function Restore-NugetAsmForRuntime {
119-
param(
120-
[ValidateNotNull()][string]$PackageName,
121-
[ValidateNotNull()][string]$PackageVersion,
122-
[string]$DllName,
123-
[string]$DestinationPath,
124-
[string]$TargetPlatform = $script:NetFrameworkPlatformId,
125-
[string]$TargetRuntime = $script:WindowsPowerShellFrameworkTarget
126-
)
127-
128-
$tmpDir = Join-Path $PSScriptRoot '.tmp'
129-
if (-not (Test-Path $tmpDir)) {
130-
New-Item -ItemType Directory -Path $tmpDir
131-
}
132-
133-
if (-not $DllName) {
134-
$DllName = "$PackageName.dll"
135-
}
136-
137-
if ($DestinationPath -eq $null) {
138-
$DestinationPath = Join-Path $tmpDir $DllName
139-
} elseif (Test-Path $DestinationPath -PathType Container) {
140-
$DestinationPath = Join-Path $DestinationPath $DllName
141-
}
142-
143-
$packageDirPath = Join-Path $tmpDir "$PackageName.$PackageVersion"
144-
if (-not (Test-Path $packageDirPath)) {
145-
$guid = New-Guid
146-
$tmpNupkgPath = Join-Path $tmpDir "$guid.zip"
147-
if (Test-Path $tmpNupkgPath) {
148-
Remove-Item -Force $tmpNupkgPath
149-
}
150-
151-
try {
152-
$packageUri = "$script:NugetApiUriBase/$PackageName/$PackageVersion"
153-
Invoke-WebRequest -Uri $packageUri -OutFile $tmpNupkgPath
154-
Expand-Archive -Path $tmpNupkgPath -DestinationPath $packageDirPath
155-
} finally {
156-
Remove-Item -Force $tmpNupkgPath -ErrorAction SilentlyContinue
157-
}
158-
}
159-
160-
$internalPath = [System.IO.Path]::Combine($packageDirPath, 'runtimes', $TargetPlatform, 'lib', $TargetRuntime, $DllName)
161-
162-
Copy-Item -Path $internalPath -Destination $DestinationPath -Force
163-
164-
return $DestinationPath
38+
git update-index --assume-unchanged "$PSScriptRoot/src/PowerShellEditorServices.Hosting/BuildInfo.cs"
16539
}
16640

16741
function Invoke-WithCreateDefaultHook {
@@ -284,11 +158,17 @@ task CreateBuildInfo -Before Build {
284158
$buildVersion = "<development-build>"
285159
$buildOrigin = "<development>"
286160

161+
if ($propsBody.VersionSuffix)
162+
{
163+
$propsXml = [xml](Get-Content -Raw -LiteralPath "$PSScriptRoot/PowerShellEditorServices.Common.props")
164+
$propsBody = $propsXml.Project.PropertyGroup
165+
$buildVersion = $propsBody.VersionPrefix
166+
$buildVersion += '-' + $propsBody.VersionSuffix
167+
}
168+
287169
# Set build info fields on build platforms
288170
if ($env:TF_BUILD)
289171
{
290-
$psd1Path = [System.IO.Path]::Combine($PSScriptRoot, "module", "PowerShellEditorServices", "PowerShellEditorServices.psd1")
291-
$buildVersion = (Import-PowerShellDataFile -LiteralPath $psd1Path).Version
292172
$buildOrigin = "VSTS"
293173
}
294174

@@ -310,8 +190,8 @@ namespace Microsoft.PowerShell.EditorServices.Hosting
310190
{
311191
public static class BuildInfo
312192
{
313-
public const string BuildVersion = "$buildVersion";
314-
public const string BuildOrigin = "$buildOrigin";
193+
public static readonly string BuildVersion = "$buildVersion";
194+
public static readonly string BuildOrigin = "$buildOrigin";
315195
public static readonly System.DateTime? BuildTime = System.DateTime.Parse("$buildTime");
316196
}
317197
}
@@ -327,8 +207,15 @@ task SetupHelpForTests -Before Test {
327207
}
328208

329209
task Build {
330-
exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:TargetPlatform }
331-
exec { & $script:dotnetExe build -c $Configuration .\src\PowerShellEditorServices.VSCode\PowerShellEditorServices.VSCode.csproj $script:TargetFrameworksParam }
210+
exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices\PowerShellEditorServices.csproj -f $script:NetRuntime.Standard }
211+
exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.Core }
212+
if (-not $script:IsUnix)
213+
{
214+
exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.Hosting\PowerShellEditorServices.Hosting.csproj -f $script:NetRuntime.Desktop }
215+
}
216+
217+
# Build PowerShellEditorServices.VSCode module
218+
exec { & $script:dotnetExe publish -c $Configuration .\src\PowerShellEditorServices.VSCode\PowerShellEditorServices.VSCode.csproj -f $script:NetRuntime.Standard }
332219
}
333220

334221
function DotNetTestFilter {
@@ -343,80 +230,115 @@ task TestServer {
343230
Set-Location .\test\PowerShellEditorServices.Test\
344231

345232
if (-not $script:IsUnix) {
346-
exec { & $script:dotnetExe test --logger trx -f $script:TestRuntime.Desktop (DotNetTestFilter) }
233+
exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Desktop (DotNetTestFilter) }
347234
}
348235

349236
Invoke-WithCreateDefaultHook -NewModulePath $script:PSCoreModulePath {
350-
exec { & $script:dotnetExe test --logger trx -f $script:TestRuntime.Core (DotNetTestFilter) }
237+
exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Core (DotNetTestFilter) }
351238
}
352239
}
353240

354241
task TestProtocol {
355242
Set-Location .\test\PowerShellEditorServices.Test.Protocol\
356243

357244
if (-not $script:IsUnix) {
358-
exec { & $script:dotnetExe test --logger trx -f $script:TestRuntime.Desktop (DotNetTestFilter) }
245+
exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Desktop (DotNetTestFilter) }
359246
}
360247

361248
Invoke-WithCreateDefaultHook {
362-
exec { & $script:dotnetExe test --logger trx -f $script:TestRuntime.Core (DotNetTestFilter) }
249+
exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Core (DotNetTestFilter) }
363250
}
364251
}
365252

366253
task TestHost {
367254
Set-Location .\test\PowerShellEditorServices.Test.Host\
368255

369256
if (-not $script:IsUnix) {
370-
exec { & $script:dotnetExe build -f $script:TestRuntime.Desktop }
371-
exec { & $script:dotnetExe test -f $script:TestRuntime.Desktop (DotNetTestFilter) }
257+
exec { & $script:dotnetExe build -f $script:NetRuntime.Desktop }
258+
exec { & $script:dotnetExe test -f $script:NetRuntime.Desktop (DotNetTestFilter) }
372259
}
373260

374-
exec { & $script:dotnetExe build -c $Configuration -f $script:TestRuntime.Core }
375-
exec { & $script:dotnetExe test -f $script:TestRuntime.Core (DotNetTestFilter) }
261+
exec { & $script:dotnetExe build -c $Configuration -f $script:NetRuntime.Core }
262+
exec { & $script:dotnetExe test -f $script:NetRuntime.Core (DotNetTestFilter) }
376263
}
377264

378265
task TestE2E {
379266
Set-Location .\test\PowerShellEditorServices.Test.E2E\
380267

381268
$env:PWSH_EXE_NAME = if ($IsCoreCLR) { "pwsh" } else { "powershell" }
382-
exec { & $script:dotnetExe test --logger trx -f $script:TestRuntime.Core (DotNetTestFilter) }
269+
exec { & $script:dotnetExe test --logger trx -f $script:NetRuntime.Core (DotNetTestFilter) }
383270
}
384271

385272
task LayoutModule -After Build {
273+
$modulesDir = "$PSScriptRoot/module"
274+
$psesVSCodeBinOutputPath = "$modulesDir/PowerShellEditorServices.VSCode/bin"
275+
$psesOutputPath = "$modulesDir/PowerShellEditorServices"
276+
$psesBinOutputPath = "$PSScriptRoot/module/PowerShellEditorServices/bin"
277+
$psesDepsPath = "$psesBinOutputPath/Common"
278+
$psesCoreHostPath = "$psesBinOutputPath/Core"
279+
$psesDeskHostPath = "$psesBinOutputPath/Desktop"
280+
281+
foreach ($dir in $psesDepsPath,$psesCoreHostPath,$psesDeskHostPath,$psesVSCodeBinOutputPath)
282+
{
283+
New-Item -Force -Path $dir -ItemType Directory
284+
}
285+
386286
# Copy Third Party Notices.txt to module folder
387-
Copy-Item -Force -Path "$PSScriptRoot\Third Party Notices.txt" -Destination $PSScriptRoot\module\PowerShellEditorServices
388-
389-
# Lay out the PowerShellEditorServices module's binaries
390-
# For each binplace destination
391-
foreach ($destDir in $script:RequiredBuildAssets.Keys) {
392-
# Create the destination dir
393-
$null = New-Item -Force $destDir -Type Directory
394-
395-
# For each PSES subproject
396-
foreach ($projectName in $script:RequiredBuildAssets[$destDir].Keys) {
397-
# Get the project build dir path
398-
$basePath = [System.IO.Path]::Combine($PSScriptRoot, 'src', $projectName, 'bin', $Configuration, $script:TargetPlatform)
399-
400-
# For each asset in the subproject
401-
foreach ($bin in $script:RequiredBuildAssets[$destDir][$projectName]) {
402-
# Get the asset path
403-
$binPath = Join-Path $basePath $bin
404-
405-
# Binplace the asset
406-
Copy-Item -Force -Verbose $binPath $destDir
407-
}
287+
Copy-Item -Force -Path "$PSScriptRoot\Third Party Notices.txt" -Destination $psesOutputPath
288+
289+
# Copy UnixConsoleEcho native libraries
290+
Copy-Item -Path "$script:PsesOutput/runtimes/osx-64/native/*" -Destination $psesDepsPath
291+
Copy-Item -Path "$script:PsesOutput/runtimes/linux-64/native/*" -Destination $psesDepsPath
292+
293+
# Assemble PSES module
294+
295+
$includedDlls = [System.Collections.Generic.HashSet[string]]::new()
296+
[void]$includedDlls.Add('System.Management.Automation.dll')
297+
298+
# PSES/bin/Common
299+
foreach ($psesComponent in Get-ChildItem $script:PsesOutput)
300+
{
301+
if ($psesComponent.Name -eq 'System.Management.Automation.dll' -or
302+
$psesComponent.Name -eq 'System.Runtime.InteropServices.RuntimeInformation.dll')
303+
{
304+
continue
305+
}
306+
307+
if ($psesComponent.Extension)
308+
{
309+
[void]$includedDlls.Add($psesComponent.Name)
310+
Copy-Item -Path $psesComponent.FullName -Destination $psesDepsPath
311+
}
312+
}
313+
314+
# PSES/bin/Core
315+
foreach ($hostComponent in Get-ChildItem $script:HostCoreOutput)
316+
{
317+
if (-not $includedDlls.Contains($hostComponent.Name))
318+
{
319+
Copy-Item -Path $hostComponent.FullName -Destination $psesCoreHostPath
408320
}
409321
}
410322

411-
# Get and place the shim bins for net461
412-
foreach ($binDestinationDir in $script:RequiredNugetBinaries.Keys) {
413-
$binDestPath = Join-Path $script:ModuleBinPath $binDestinationDir
414-
if (-not (Test-Path $binDestPath)) {
415-
New-Item -Path $binDestPath -ItemType Directory
323+
# PSES/bin/Desktop
324+
if (-not $script:IsUnix)
325+
{
326+
foreach ($hostComponent in Get-ChildItem $script:HostDeskOutput)
327+
{
328+
if (-not $includedDlls.Contains($hostComponent.Name))
329+
{
330+
Copy-Item -Path $hostComponent.FullName -Destination $psesDeskHostPath
331+
}
416332
}
333+
}
417334

418-
foreach ($packageDetails in $script:RequiredNugetBinaries[$binDestinationDir]) {
419-
Restore-NugetAsmForRuntime -DestinationPath $binDestPath @packageDetails
335+
# Assemble the PowerShellEditorServices.VSCode module
336+
337+
foreach ($vscodeComponent in Get-ChildItem $script:VSCodeOutput)
338+
{
339+
if (-not $includedDlls.Contains($vscodeComponent.Name))
340+
{
341+
Copy-Item -Path $vscodeComponent.FullName -Destination $psesVSCodeBinOutputPath
420342
}
421343
}
422344
}

0 commit comments

Comments
 (0)