From 61477abba696150e4d7b32ac4e94791096571996 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Mon, 29 Nov 2021 16:17:19 -0800 Subject: [PATCH] Fix `BundledModulePath` and PSReadLine loading (redux) This redoes prior work that was lost during the rewrite. Specifically this actually respects the user configuration of `BundledModulePath` (also used by unit tests to provide compatibililty with xUnit), and forces the use of only our bundled PSReadLine dependency. Essentially this redoes #1514 and #1522. --- .../PowerShell/Console/PSReadLineProxy.cs | 31 ++----------- .../PowerShell/Host/PsesInternalHost.cs | 43 +++++++++++-------- 2 files changed, 29 insertions(+), 45 deletions(-) diff --git a/src/PowerShellEditorServices/Services/PowerShell/Console/PSReadLineProxy.cs b/src/PowerShellEditorServices/Services/PowerShell/Console/PSReadLineProxy.cs index a9b95b031..8f8c12ced 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Console/PSReadLineProxy.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Console/PSReadLineProxy.cs @@ -44,37 +44,14 @@ internal class PSReadLineProxy private static readonly Type[] s_addToHistoryTypes = { typeof(string) }; - private static readonly string _psReadLineModulePath = Path.GetFullPath( - Path.Combine( - Path.GetDirectoryName(typeof(PSReadLineProxy).Assembly.Location), - "..", - "..", - "..", - "PSReadLine")); - - private static readonly string ReadLineInitScript = $@" - [System.Diagnostics.DebuggerHidden()] - [System.Diagnostics.DebuggerStepThrough()] - param() - end {{ - $module = Get-Module -ListAvailable PSReadLine | - Where-Object {{ $_.Version -ge '2.2.1' }} | - Sort-Object -Descending Version | - Select-Object -First 1 - if (-not $module) {{ - Import-Module '{_psReadLineModulePath.Replace("'", "''")}' - return [Microsoft.PowerShell.PSConsoleReadLine] - }} - - Import-Module -ModuleInfo $module - return [Microsoft.PowerShell.PSConsoleReadLine] - }}"; - public static PSReadLineProxy LoadAndCreate( ILoggerFactory loggerFactory, + string bundledModulePath, SMA.PowerShell pwsh) { - Type psConsoleReadLineType = pwsh.AddScript(ReadLineInitScript).InvokeAndClear().FirstOrDefault(); + pwsh.ImportModule(Path.Combine(bundledModulePath, "PSReadLine")); + Type psConsoleReadLineType = pwsh.AddScript("return [Microsoft.PowerShell.PSConsoleReadLine]") + .InvokeAndClear().FirstOrDefault(); RuntimeHelpers.RunClassConstructor(psConsoleReadLineType.TypeHandle); diff --git a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs index fffed9891..a2635a90c 100644 --- a/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs +++ b/src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs @@ -1,25 +1,24 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Microsoft.Extensions.Logging; -using Microsoft.PowerShell.EditorServices.Hosting; -using Microsoft.PowerShell.EditorServices.Services.PowerShell.Console; -using Microsoft.PowerShell.EditorServices.Services.PowerShell.Context; -using Microsoft.PowerShell.EditorServices.Services.PowerShell.Runspace; -using OmniSharp.Extensions.LanguageServer.Protocol.Server; using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Management.Automation.Host; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.PowerShell.EditorServices.Hosting; +using Microsoft.PowerShell.EditorServices.Services.PowerShell.Console; +using Microsoft.PowerShell.EditorServices.Services.PowerShell.Context; using Microsoft.PowerShell.EditorServices.Services.PowerShell.Debugging; using Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution; +using Microsoft.PowerShell.EditorServices.Services.PowerShell.Runspace; using Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility; using Microsoft.PowerShell.EditorServices.Utility; -using System.IO; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Threading.Tasks; +using OmniSharp.Extensions.LanguageServer.Protocol.Server; namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Host { @@ -29,11 +28,12 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Host internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRunspaceContext, IInternalPowerShellExecutionService { private const string DefaultPrompt = "PSIC> "; + // This is a default that can be overriden at runtime by the user or tests. + private static string s_bundledModulePath = Path.GetFullPath(Path.Combine( + Path.GetDirectoryName(typeof(PsesInternalHost).Assembly.Location), "..", "..", "..")); - private static readonly string s_commandsModulePath = Path.GetFullPath( - Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), - "../../Commands/PowerShellEditorServices.Commands.psd1")); + private static string s_commandsModulePath => Path.GetFullPath(Path.Combine( + s_bundledModulePath, "PowerShellEditorServices", "Commands", "PowerShellEditorServices.Commands.psd1")); private readonly ILoggerFactory _loggerFactory; @@ -85,6 +85,13 @@ public PsesInternalHost( _languageServer = languageServer; _hostInfo = hostInfo; + // Respect a user provided bundled module path. + if (Directory.Exists(hostInfo.BundledModulePath)) + { + _logger.LogTrace("Using new bundled module path: {}", hostInfo.BundledModulePath); + s_bundledModulePath = hostInfo.BundledModulePath; + } + _readLineProvider = new ReadLineProvider(loggerFactory); _taskQueue = new BlockingConcurrentDeque(); _psFrameStack = new Stack(); @@ -212,7 +219,7 @@ public async Task TryStartAsync(HostStartOptions startOptions, Cancellatio await ExecuteDelegateAsync( "LoadProfiles", new PowerShellExecutionOptions { MustRunInForeground = true, ThrowOnError = false }, - (pwsh, delegateCancellation) => pwsh.LoadProfiles(_hostInfo.ProfilePaths), + (pwsh, _) => pwsh.LoadProfiles(_hostInfo.ProfilePaths), cancellationToken).ConfigureAwait(false); _logger.LogInformation("Profiles loaded"); @@ -747,7 +754,7 @@ private static PowerShell CreatePowerShellForRunspace(Runspace runspace) pwsh.ImportModule(s_commandsModulePath); - if (hostStartupInfo.AdditionalModules != null && hostStartupInfo.AdditionalModules.Count > 0) + if (hostStartupInfo.AdditionalModules?.Count > 0) { foreach (string module in hostStartupInfo.AdditionalModules) { @@ -931,7 +938,7 @@ private bool TryLoadPSReadLine(PowerShell pwsh, EngineIntrinsics engineIntrinsic psrlReadLine = null; try { - var psrlProxy = PSReadLineProxy.LoadAndCreate(_loggerFactory, pwsh); + var psrlProxy = PSReadLineProxy.LoadAndCreate(_loggerFactory, s_bundledModulePath, pwsh); psrlReadLine = new PsrlReadLine(psrlProxy, this, engineIntrinsics, ReadKey, OnPowerShellIdle); return true; }