Skip to content

Commit f911ef1

Browse files
Respect BundledModulePath user option
This also simplifies our testing scenario where that path needs to be configured at runtime, too. Co-authored-by: Andrew Schwartzmeyer <[email protected]>
1 parent 773e8b6 commit f911ef1

File tree

6 files changed

+49
-42
lines changed

6 files changed

+49
-42
lines changed

src/PowerShellEditorServices.Hosting/Internal/EditorServicesRunner.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ private HostStartupInfo CreateHostStartupInfo()
292292
_config.LogPath,
293293
(int)_config.LogLevel,
294294
consoleReplEnabled: _config.ConsoleRepl != ConsoleReplKind.None,
295-
usesLegacyReadLine: _config.ConsoleRepl == ConsoleReplKind.LegacyReadLine);
295+
usesLegacyReadLine: _config.ConsoleRepl == ConsoleReplKind.LegacyReadLine,
296+
bundledModulePath: _config.BundledModulePath);
296297
}
297298

298299
private void WriteStartupBanner()

src/PowerShellEditorServices/Hosting/HostStartupInfo.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ public sealed class HostStartupInfo
107107
/// </remarks>
108108
public int LogLevel { get; }
109109

110+
/// <summary>
111+
/// The path to find the bundled modules. User configurable for advanced usage.
112+
/// </summary>
113+
public string BundledModulePath { get; }
114+
110115
#endregion
111116

112117
#region Constructors
@@ -135,6 +140,7 @@ public sealed class HostStartupInfo
135140
/// <param name="logLevel">The minimum log event level.</param>
136141
/// <param name="consoleReplEnabled">Enable console if true.</param>
137142
/// <param name="usesLegacyReadLine">Use PSReadLine if false, otherwise use the legacy readline implementation.</param>
143+
/// <param name="bundledModulePath">A custom path to the expected bundled modules.</param>
138144
public HostStartupInfo(
139145
string name,
140146
string profileId,
@@ -147,7 +153,8 @@ public HostStartupInfo(
147153
string logPath,
148154
int logLevel,
149155
bool consoleReplEnabled,
150-
bool usesLegacyReadLine)
156+
bool usesLegacyReadLine,
157+
string bundledModulePath)
151158
{
152159
Name = name ?? DefaultHostName;
153160
ProfileId = profileId ?? DefaultHostProfileId;
@@ -161,6 +168,7 @@ public HostStartupInfo(
161168
LogLevel = logLevel;
162169
ConsoleReplEnabled = consoleReplEnabled;
163170
UsesLegacyReadLine = usesLegacyReadLine;
171+
BundledModulePath = bundledModulePath;
164172
}
165173

166174
#endregion

src/PowerShellEditorServices/Services/PowerShellContext/PowerShellContextService.cs

+24-11
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,18 @@ namespace Microsoft.PowerShell.EditorServices.Services
3333
/// </summary>
3434
internal class PowerShellContextService : IHostSupportsInteractiveSession
3535
{
36-
private static readonly string s_commandsModulePath = Path.GetFullPath(
37-
Path.Combine(
38-
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
39-
"../../Commands/PowerShellEditorServices.Commands.psd1"));
36+
// This is a default that can be overriden at runtime by the user or tests.
37+
private static string s_bundledModulePath = Path.GetFullPath(Path.Combine(
38+
Path.GetDirectoryName(typeof(PowerShellContextService).Assembly.Location),
39+
"..",
40+
"..",
41+
".."));
42+
43+
private static string s_commandsModulePath => Path.GetFullPath(Path.Combine(
44+
s_bundledModulePath,
45+
"PowerShellEditorServices",
46+
"Commands",
47+
"PowerShellEditorServices.Commands.psd1"));
4048

4149
private static readonly Action<Runspace, ApartmentState> s_runspaceApartmentStateSetter;
4250
private static readonly PropertyInfo s_writeStreamProperty;
@@ -190,9 +198,16 @@ public static PowerShellContextService Create(
190198
OmniSharp.Extensions.LanguageServer.Protocol.Server.ILanguageServerFacade languageServer,
191199
HostStartupInfo hostStartupInfo)
192200
{
201+
var logger = factory.CreateLogger<PowerShellContextService>();
202+
193203
Validate.IsNotNull(nameof(hostStartupInfo), hostStartupInfo);
194204

195-
var logger = factory.CreateLogger<PowerShellContextService>();
205+
// Respect a user provided bundled module path.
206+
if (Directory.Exists(hostStartupInfo.BundledModulePath))
207+
{
208+
logger.LogTrace($"Using new bundled module path: {hostStartupInfo.BundledModulePath}");
209+
s_bundledModulePath = hostStartupInfo.BundledModulePath;
210+
}
196211

197212
bool shouldUsePSReadLine = hostStartupInfo.ConsoleReplEnabled
198213
&& !hostStartupInfo.UsesLegacyReadLine;
@@ -406,7 +421,7 @@ public void Initialize(
406421

407422
if (powerShellVersion.Major >= 5 &&
408423
this.isPSReadLineEnabled &&
409-
PSReadLinePromptContext.TryGetPSReadLineProxy(logger, initialRunspace, out PSReadLineProxy proxy))
424+
PSReadLinePromptContext.TryGetPSReadLineProxy(logger, initialRunspace, s_bundledModulePath, out PSReadLineProxy proxy))
410425
{
411426
this.PromptContext = new PSReadLinePromptContext(
412427
this,
@@ -430,15 +445,13 @@ public void Initialize(
430445
/// the runspace. This method will be moved somewhere else soon.
431446
/// </summary>
432447
/// <returns></returns>
433-
public Task ImportCommandsModuleAsync() => ImportCommandsModuleAsync(s_commandsModulePath);
434-
435-
public Task ImportCommandsModuleAsync(string path)
448+
public Task ImportCommandsModuleAsync()
436449
{
437-
this.logger.LogTrace($"Importing PowershellEditorServices commands from {path}");
450+
this.logger.LogTrace($"Importing PowershellEditorServices commands from {s_commandsModulePath}");
438451

439452
PSCommand importCommand = new PSCommand()
440453
.AddCommand("Import-Module")
441-
.AddArgument(path);
454+
.AddArgument(s_commandsModulePath);
442455

443456
return this.ExecuteCommandAsync<PSObject>(importCommand, sendOutputToHost: false, sendErrorToHost: false);
444457
}

src/PowerShellEditorServices/Services/PowerShellContext/Session/PSReadLinePromptContext.cs

+3-22
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,6 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShellContext
1717

1818
internal class PSReadLinePromptContext : IPromptContext
1919
{
20-
private static readonly string _psReadLineModulePath = Path.Combine(
21-
Path.GetDirectoryName(typeof(PSReadLinePromptContext).Assembly.Location),
22-
"..",
23-
"..",
24-
"..",
25-
"PSReadLine");
26-
27-
// When using xUnit (dotnet test) the assemblies are deployed to the
28-
// test project folder, invalidating our relative path assumption.
29-
private static readonly string _psReadLineTestModulePath = Path.Combine(
30-
Path.GetDirectoryName(typeof(PSReadLinePromptContext).Assembly.Location),
31-
"..",
32-
"..",
33-
"..",
34-
"..",
35-
"..",
36-
"module",
37-
"PSReadLine");
38-
3920
private static readonly Lazy<CmdletInfo> s_lazyInvokeReadLineForEditorServicesCmdletInfo = new Lazy<CmdletInfo>(() =>
4021
{
4122
var type = Type.GetType("Microsoft.PowerShell.EditorServices.Commands.InvokeReadLineForEditorServicesCommand, Microsoft.PowerShell.EditorServices.Hosting");
@@ -84,16 +65,16 @@ internal PSReadLinePromptContext(
8465
internal static bool TryGetPSReadLineProxy(
8566
ILogger logger,
8667
Runspace runspace,
87-
out PSReadLineProxy readLineProxy,
88-
bool testing = false)
68+
string bundledModulePath,
69+
out PSReadLineProxy readLineProxy)
8970
{
9071
readLineProxy = null;
9172
logger.LogTrace("Attempting to load PSReadLine");
9273
using (var pwsh = PowerShell.Create())
9374
{
9475
pwsh.Runspace = runspace;
9576
pwsh.AddCommand("Microsoft.PowerShell.Core\\Import-Module")
96-
.AddParameter("Name", testing ? _psReadLineTestModulePath : _psReadLineModulePath)
77+
.AddParameter("Name", Path.Combine(bundledModulePath, "PSReadLine"))
9778
.Invoke();
9879

9980
if (pwsh.HadErrors)

test/PowerShellEditorServices.Test/PowerShellContextFactory.cs

+8-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ internal static class PowerShellContextFactory
3232
Path.GetFullPath(
3333
TestUtilities.NormalizePath("../../../../PowerShellEditorServices.Test.Shared/ProfileTest.ps1")));
3434

35-
public static System.Management.Automation.Runspaces.Runspace initialRunspace;
35+
public static readonly string BundledModulePath = Path.GetFullPath(
36+
TestUtilities.NormalizePath("../../../../../module"));
37+
38+
public static System.Management.Automation.Runspaces.Runspace InitialRunspace;
3639

3740
public static PowerShellContextService Create(ILogger logger)
3841
{
@@ -52,17 +55,18 @@ public static PowerShellContextService Create(ILogger logger)
5255
null,
5356
0,
5457
consoleReplEnabled: false,
55-
usesLegacyReadLine: false);
58+
usesLegacyReadLine: false,
59+
bundledModulePath: BundledModulePath);
5660

57-
initialRunspace = PowerShellContextService.CreateRunspace(
61+
InitialRunspace = PowerShellContextService.CreateRunspace(
5862
testHostDetails,
5963
powerShellContext,
6064
new TestPSHostUserInterface(powerShellContext, logger),
6165
logger);
6266

6367
powerShellContext.Initialize(
6468
TestProfilePaths,
65-
initialRunspace,
69+
InitialRunspace,
6670
ownsInitialRunspace: true,
6771
consoleHost: null);
6872

test/PowerShellEditorServices.Test/Session/PowerShellContextTests.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,9 @@ public void CanGetPSReadLineProxy()
152152
{
153153
Assert.True(PSReadLinePromptContext.TryGetPSReadLineProxy(
154154
NullLogger.Instance,
155-
PowerShellContextFactory.initialRunspace,
156-
out PSReadLineProxy proxy,
157-
true));
155+
PowerShellContextFactory.InitialRunspace,
156+
PowerShellContextFactory.BundledModulePath,
157+
out PSReadLineProxy proxy));
158158
}
159159

160160
#region Helper Methods

0 commit comments

Comments
 (0)