-
Notifications
You must be signed in to change notification settings - Fork 235
Honor BundledModulesPath when loading modules in PowerShellContextService #1516
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
26818b3
2888045
d0bc52d
e590fad
52b16ca
d8738f0
ee154b0
b91382b
77186f0
48d1a96
7037115
a0fa3c5
1443baa
bda11be
bda40ea
01957e6
9a045d9
e1e70cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,10 +32,18 @@ namespace Microsoft.PowerShell.EditorServices.Services | |
/// </summary> | ||
internal class PowerShellContextService : IHostSupportsInteractiveSession | ||
{ | ||
private static readonly string s_commandsModulePath = Path.GetFullPath( | ||
private static string s_bundledModulesPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "..", ".."); | ||
|
||
private static string s_commandsModulePath => Path.GetFullPath( | ||
Path.Combine( | ||
s_bundledModulesPath, | ||
"PowerShellEditorServices", | ||
"Commands", | ||
"PowerShellEditorServices.Commands.psd1")); | ||
private static string _psReadLineModulePath => Path.GetFullPath( | ||
Path.Combine( | ||
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), | ||
"../../Commands/PowerShellEditorServices.Commands.psd1")); | ||
s_bundledModulesPath, | ||
"PSReadLine")); | ||
|
||
private static readonly Action<Runspace, ApartmentState> s_runspaceApartmentStateSetter; | ||
private static readonly PropertyInfo s_writeStreamProperty; | ||
|
@@ -190,7 +198,10 @@ public static PowerShellContextService Create( | |
HostStartupInfo hostStartupInfo) | ||
{ | ||
Validate.IsNotNull(nameof(hostStartupInfo), hostStartupInfo); | ||
|
||
s_bundledModulesPath = !string.IsNullOrEmpty(hostStartupInfo.BundledModulePath) && Directory.Exists(hostStartupInfo.BundledModulePath) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here if a valid path was specified, we use it, otherwise we fallback to the previous logic. |
||
? hostStartupInfo.BundledModulePath | ||
: s_bundledModulesPath; | ||
|
||
var logger = factory.CreateLogger<PowerShellContextService>(); | ||
|
||
bool shouldUsePSReadLine = hostStartupInfo.ConsoleReplEnabled | ||
|
@@ -215,12 +226,18 @@ public static PowerShellContextService Create( | |
|
||
logger.LogTrace("Creating initial PowerShell runspace"); | ||
Runspace initialRunspace = PowerShellContextService.CreateRunspace(psHost, hostStartupInfo.LanguageMode); | ||
powerShellContext.Initialize(hostStartupInfo.ProfilePaths, initialRunspace, true, hostUserInterface); | ||
powerShellContext.Initialize(hostStartupInfo, initialRunspace, true, hostUserInterface); | ||
powerShellContext.ImportCommandsModuleAsync(); | ||
|
||
// TODO: This can be moved to the point after the $psEditor object | ||
// gets initialized when that is done earlier than LanguageServer.Initialize | ||
foreach (string module in hostStartupInfo.AdditionalModules) | ||
var modulesToImport = new List<string>(); | ||
if(hostStartupInfo.ConsoleReplEnabled) | ||
{ | ||
modulesToImport.Add(_psReadLineModulePath); | ||
} | ||
modulesToImport.AddRange(hostStartupInfo.AdditionalModules); | ||
foreach (string module in modulesToImport) | ||
{ | ||
var command = | ||
new PSCommand() | ||
|
@@ -305,7 +322,7 @@ public static Runspace CreateRunspace(PSHost psHost, PSLanguageMode languageMode | |
/// <param name="ownsInitialRunspace">If true, the PowerShellContext owns this runspace.</param> | ||
/// <param name="consoleHost">An IHostOutput implementation. Optional.</param> | ||
public void Initialize( | ||
ProfilePathInfo profilePaths, | ||
HostStartupInfo hostStartupInfo, | ||
Runspace initialRunspace, | ||
bool ownsInitialRunspace, | ||
IHostOutput consoleHost) | ||
|
@@ -359,7 +376,7 @@ public void Initialize( | |
this.ConfigureRunspaceCapabilities(this.CurrentRunspace); | ||
|
||
// Set the $profile variable in the runspace | ||
this.profilePaths = profilePaths; | ||
this.profilePaths = hostStartupInfo.ProfilePaths; | ||
if (profilePaths != null) | ||
{ | ||
this.SetProfileVariableInCurrentRunspace(profilePaths); | ||
|
@@ -394,9 +411,14 @@ public void Initialize( | |
this.versionSpecificOperations); | ||
this.InvocationEventQueue = InvocationEventQueue.Create(this, this.PromptNest); | ||
|
||
if (VersionUtils.IsWindows) | ||
{ | ||
this.SetExecutionPolicy(); | ||
} | ||
|
||
if (powerShellVersion.Major >= 5 && | ||
this.isPSReadLineEnabled && | ||
PSReadLinePromptContext.TryGetPSReadLineProxy(logger, initialRunspace, out PSReadLineProxy proxy)) | ||
PSReadLinePromptContext.TryGetPSReadLineProxy(logger, initialRunspace, hostStartupInfo.BundledModulePath, out PSReadLineProxy proxy)) | ||
{ | ||
this.PromptContext = new PSReadLinePromptContext( | ||
this, | ||
|
@@ -409,10 +431,6 @@ public void Initialize( | |
this.PromptContext = new LegacyReadLineContext(this); | ||
} | ||
|
||
if (VersionUtils.IsWindows) | ||
{ | ||
this.SetExecutionPolicy(); | ||
} | ||
} | ||
|
||
/// <summary> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,20 +17,6 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShellContext | |
|
||
internal class PSReadLinePromptContext : IPromptContext | ||
{ | ||
private static readonly string _psReadLineModulePath = Path.Combine( | ||
Path.GetDirectoryName(typeof(PSReadLinePromptContext).Assembly.Location), | ||
"..", | ||
"..", | ||
"..", | ||
#if TEST | ||
// When using xUnit (dotnet test) the assemblies are deployed to the | ||
// test project folder, invalidating our relative path assumption. | ||
"..", | ||
"..", | ||
"module", | ||
#endif | ||
"PSReadLine"); | ||
|
||
private static readonly Lazy<CmdletInfo> s_lazyInvokeReadLineForEditorServicesCmdletInfo = new Lazy<CmdletInfo>(() => | ||
{ | ||
var type = Type.GetType("Microsoft.PowerShell.EditorServices.Commands.InvokeReadLineForEditorServicesCommand, Microsoft.PowerShell.EditorServices.Hosting"); | ||
|
@@ -79,9 +65,11 @@ internal PSReadLinePromptContext( | |
internal static bool TryGetPSReadLineProxy( | ||
ILogger logger, | ||
Runspace runspace, | ||
string bundledModulePath, | ||
out PSReadLineProxy readLineProxy) | ||
{ | ||
readLineProxy = null; | ||
string _psReadLineModulePath = Path.Combine(bundledModulePath, "PSReadLine"); | ||
logger.LogTrace("Attempting to load PSReadLine"); | ||
using (var pwsh = PowerShell.Create()) | ||
{ | ||
|
@@ -94,10 +82,24 @@ internal static bool TryGetPSReadLineProxy( | |
|
||
if (psReadLineType == null) | ||
{ | ||
logger.LogWarning("PSConsoleReadline type not found: {Reason}", pwsh.HadErrors ? pwsh.Streams.Error[0].ToString() : "<Unknown reason>"); | ||
return false; | ||
logger.LogWarning("PSConsoleReadline type not found using Type.GetType(): {Reason}", pwsh.HadErrors ? pwsh.Streams.Error[0].ToString() : "<Unknown reason>"); | ||
logger.LogWarning("Searching loaded assemblies..."); | ||
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies(); | ||
var assemblies = allAssemblies.FirstOrDefault(a => a.FullName.Contains("Microsoft.PowerShell.PSReadLine2")); | ||
var type = assemblies?.ExportedTypes?.FirstOrDefault(a => a.FullName == "Microsoft.PowerShell.PSConsoleReadLine"); | ||
if(type is not null) | ||
{ | ||
logger.LogInformation("Found PSConsoleReadLine in loaded assemblies."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In your testing has it ever been found in the loaded assemblies? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like it. Hmm... |
||
psReadLineType = type; | ||
} | ||
else | ||
{ | ||
logger.LogError("Unable to find PSConsoleReadLine in loaded assembles."); | ||
return false; | ||
} | ||
} | ||
|
||
|
||
try | ||
{ | ||
readLineProxy = new PSReadLineProxy(psReadLineType, logger); | ||
|
@@ -108,6 +110,7 @@ internal static bool TryGetPSReadLineProxy( | |
// Could be an older version, a custom build, or something a newer version with | ||
// breaking changes. | ||
logger.LogWarning("PSReadLineProxy unable to be initialized: {Reason}", e); | ||
System.Console.WriteLine("PSReadLineProxy unable to be initialized"); | ||
return false; | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is impetus for the change. We are referencing a path relative to the executing assembly instead of honoring the BundledModulePath parameter.