Skip to content

Commit 00c4523

Browse files
committed
Use HostInfo.BundledModulePath to find PSScriptAnalyzer
Also refactor a bit so we're not triplicating this logic.
1 parent c4f424f commit 00c4523

File tree

4 files changed

+35
-49
lines changed

4 files changed

+35
-49
lines changed

src/PowerShellEditorServices/Hosting/HostStartupInfo.cs

+11-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.IO;
67
using System.Management.Automation.Host;
78
using System.Management.Automation.Runspaces;
89

@@ -92,7 +93,7 @@ public sealed class HostStartupInfo
9293
public string LogPath { get; }
9394

9495
/// <summary>
95-
/// The InitialSessionState will be inherited from the orginal PowerShell process. This will
96+
/// The InitialSessionState will be inherited from the original PowerShell process. This will
9697
/// be used when creating runspaces so that we honor the same InitialSessionState.
9798
/// </summary>
9899
public InitialSessionState InitialSessionState { get; }
@@ -167,7 +168,15 @@ public HostStartupInfo(
167168
LogLevel = logLevel;
168169
ConsoleReplEnabled = consoleReplEnabled;
169170
UsesLegacyReadLine = usesLegacyReadLine;
170-
BundledModulePath = bundledModulePath;
171+
172+
// Respect a user provided bundled module path.
173+
BundledModulePath = Directory.Exists(bundledModulePath)
174+
? bundledModulePath
175+
: Path.GetFullPath(Path.Combine(
176+
Path.GetDirectoryName(typeof(HostStartupInfo).Assembly.Location),
177+
"..",
178+
"..",
179+
".."));
171180
}
172181

173182
#endregion

src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs

+8-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Threading;
1212
using System.Threading.Tasks;
1313
using Microsoft.Extensions.Logging;
14+
using Microsoft.PowerShell.EditorServices.Hosting;
1415
using Microsoft.PowerShell.EditorServices.Services.Analysis;
1516
using Microsoft.PowerShell.EditorServices.Services.Configuration;
1617
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
@@ -52,8 +53,7 @@ internal static string GetUniqueIdFromDiagnostic(Diagnostic diagnostic)
5253
.Append(':')
5354
.Append(end.Character);
5455

55-
string id = sb.ToString();
56-
return id;
56+
return sb.ToString();
5757
}
5858

5959
/// <summary>
@@ -96,20 +96,16 @@ internal static string GetUniqueIdFromDiagnostic(Diagnostic diagnostic)
9696

9797
private CancellationTokenSource _diagnosticsCancellationTokenSource;
9898

99+
private readonly string _pssaModulePath;
100+
99101
private string _pssaSettingsFilePath;
100102

101-
/// <summary>
102-
/// Construct a new AnalysisService.
103-
/// </summary>
104-
/// <param name="loggerFactory">Logger factory to create logger instances with.</param>
105-
/// <param name="languageServer">The LSP language server for notifications.</param>
106-
/// <param name="configurationService">The configuration service to query for configurations.</param>
107-
/// <param name="workspaceService">The workspace service for file handling within a workspace.</param>
108103
public AnalysisService(
109104
ILoggerFactory loggerFactory,
110105
ILanguageServerFacade languageServer,
111106
ConfigurationService configurationService,
112-
WorkspaceService workspaceService)
107+
WorkspaceService workspaceService,
108+
HostStartupInfo hostInfo)
113109
{
114110
_loggerFactory = loggerFactory;
115111
_logger = loggerFactory.CreateLogger<AnalysisService>();
@@ -119,6 +115,7 @@ public AnalysisService(
119115
_analysisDelayMillis = 750;
120116
_mostRecentCorrectionsByFile = new ConcurrentDictionary<ScriptFile, CorrectionTableEntry>();
121117
_analysisEngineLazy = new Lazy<PssaCmdletAnalysisEngine>(InstantiateAnalysisEngine);
118+
_pssaModulePath = Path.Combine(hostInfo.BundledModulePath, "PSScriptAnalyzer");
122119
_pssaSettingsFilePath = null;
123120
}
124121

@@ -302,7 +299,7 @@ private PssaCmdletAnalysisEngine InstantiateAnalysisEngine()
302299
pssaCmdletEngineBuilder.WithIncludedRules(s_defaultRules);
303300
}
304301

305-
return pssaCmdletEngineBuilder.Build();
302+
return pssaCmdletEngineBuilder.Build(_pssaModulePath);
306303
}
307304

308305
private PssaCmdletAnalysisEngine RecreateAnalysisEngine(PssaCmdletAnalysisEngine oldAnalysisEngine)

src/PowerShellEditorServices/Services/Analysis/PssaCmdletAnalysisEngine.cs

+8-20
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using System.Collections;
66
using System.Collections.Generic;
77
using System.Collections.ObjectModel;
8-
using System.IO;
98
using System.Linq;
109
using System.Text;
1110
using System.Threading.Tasks;
@@ -67,35 +66,27 @@ public Builder WithIncludedRules(string[] rules)
6766
/// If PSScriptAnalyzer cannot be found, this will return null.
6867
/// </summary>
6968
/// <returns>A newly configured PssaCmdletAnalysisEngine, or null if PSScriptAnalyzer cannot be found.</returns>
70-
public PssaCmdletAnalysisEngine Build()
69+
public PssaCmdletAnalysisEngine Build(string pssaModulePath)
7170
{
7271
// RunspacePool takes care of queuing commands for us so we do not
7372
// need to worry about executing concurrent commands
7473
ILogger logger = _loggerFactory.CreateLogger<PssaCmdletAnalysisEngine>();
7574
try
7675
{
77-
RunspacePool pssaRunspacePool = CreatePssaRunspacePool();
78-
79-
PssaCmdletAnalysisEngine cmdletAnalysisEngine = _settingsParameter is not null
80-
? new PssaCmdletAnalysisEngine(logger, pssaRunspacePool, _settingsParameter)
81-
: new PssaCmdletAnalysisEngine(logger, pssaRunspacePool, _rules);
82-
76+
logger.LogDebug("Creating PSScriptAnalyzer runspace with module at: '{Path}'", pssaModulePath);
77+
RunspacePool pssaRunspacePool = CreatePssaRunspacePool(pssaModulePath);
78+
PssaCmdletAnalysisEngine cmdletAnalysisEngine = new(logger, pssaRunspacePool, _settingsParameter ?? _rules);
8379
cmdletAnalysisEngine.LogAvailablePssaFeatures();
8480
return cmdletAnalysisEngine;
8581
}
86-
catch (FileNotFoundException e)
82+
catch (Exception ex)
8783
{
88-
logger.LogError(e, $"Unable to find PSScriptAnalyzer. Disabling script analysis. PSModulePath: '{Environment.GetEnvironmentVariable("PSModulePath")}'");
84+
logger.LogError(ex, "Unable to load PSScriptAnalyzer, disabling script analysis!");
8985
return null;
9086
}
9187
}
9288
}
9389

94-
// This is a default that can be overriden at runtime by the user or tests.
95-
// TODO: Deduplicate this logic with PsesInternalHost.
96-
private static readonly string s_pssaModulePath = Path.GetFullPath(Path.Combine(
97-
Path.GetDirectoryName(typeof(PssaCmdletAnalysisEngine).Assembly.Location), "..", "..", "..", "PSScriptAnalyzer"));
98-
9990
/// <summary>
10091
/// The indentation to add when the logger lists errors.
10192
/// </summary>
@@ -365,7 +356,7 @@ private IEnumerable<string> GetPSScriptAnalyzerRules()
365356
/// This looks for the latest version of PSScriptAnalyzer on the path and loads that.
366357
/// </summary>
367358
/// <returns>A runspace pool with PSScriptAnalyzer loaded for running script analysis tasks.</returns>
368-
private static RunspacePool CreatePssaRunspacePool()
359+
private static RunspacePool CreatePssaRunspacePool(string pssaModulePath)
369360
{
370361
using PowerShell pwsh = PowerShell.Create(RunspaceMode.NewRunspace);
371362

@@ -375,10 +366,7 @@ private static RunspacePool CreatePssaRunspacePool()
375366
// We intentionally use `CreateDefault2()` as it loads `Microsoft.PowerShell.Core`
376367
// only, which is a more minimal and therefore safer state.
377368
InitialSessionState sessionState = InitialSessionState.CreateDefault2();
378-
379-
sessionState.ImportPSModulesFromPath(s_pssaModulePath);
380-
// pwsh.ImportModule(s_pssaModulePath);
381-
// sessionState.ImportPSModule(new[] { pssaModuleInfo.ModuleBase });
369+
sessionState.ImportPSModulesFromPath(pssaModulePath);
382370

383371
RunspacePool runspacePool = RunspaceFactory.CreateRunspacePool(sessionState);
384372

src/PowerShellEditorServices/Services/PowerShell/Host/PsesInternalHost.cs

+8-16
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,6 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Host
3232
internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRunspaceContext, IInternalPowerShellExecutionService
3333
{
3434
private const string DefaultPrompt = "> ";
35-
// This is a default that can be overriden at runtime by the user or tests.
36-
private static string s_bundledModulePath = Path.GetFullPath(Path.Combine(
37-
Path.GetDirectoryName(typeof(PsesInternalHost).Assembly.Location), "..", "..", ".."));
38-
39-
private static string CommandsModulePath => Path.GetFullPath(Path.Combine(
40-
s_bundledModulePath, "PowerShellEditorServices", "Commands", "PowerShellEditorServices.Commands.psd1"));
4135

4236
private static readonly PropertyInfo s_scriptDebuggerTriggerObjectProperty;
4337

@@ -115,14 +109,6 @@ public PsesInternalHost(
115109
_logger = loggerFactory.CreateLogger<PsesInternalHost>();
116110
_languageServer = languageServer;
117111
_hostInfo = hostInfo;
118-
119-
// Respect a user provided bundled module path.
120-
if (Directory.Exists(hostInfo.BundledModulePath))
121-
{
122-
_logger.LogTrace($"Using new bundled module path: {hostInfo.BundledModulePath}");
123-
s_bundledModulePath = hostInfo.BundledModulePath;
124-
}
125-
126112
_readLineProvider = new ReadLineProvider(loggerFactory);
127113
_taskQueue = new BlockingConcurrentDeque<ISynchronousTask>();
128114
_psFrameStack = new Stack<PowerShellContextFrame>();
@@ -1012,7 +998,13 @@ private static PowerShell CreatePowerShellForRunspace(Runspace runspace)
1012998
pwsh.SetCorrectExecutionPolicy(_logger);
1013999
}
10141000

1015-
pwsh.ImportModule(CommandsModulePath);
1001+
string commandsModulePath = Path.Combine(
1002+
_hostInfo.BundledModulePath,
1003+
"PowerShellEditorServices",
1004+
"Commands",
1005+
"PowerShellEditorServices.Commands.psd1");
1006+
1007+
pwsh.ImportModule(commandsModulePath);
10161008

10171009
if (hostStartupInfo.AdditionalModules?.Count > 0)
10181010
{
@@ -1311,7 +1303,7 @@ internal bool TryLoadPSReadLine(PowerShell pwsh, EngineIntrinsics engineIntrinsi
13111303
psrlReadLine = null;
13121304
try
13131305
{
1314-
PSReadLineProxy psrlProxy = PSReadLineProxy.LoadAndCreate(_loggerFactory, s_bundledModulePath, pwsh);
1306+
PSReadLineProxy psrlProxy = PSReadLineProxy.LoadAndCreate(_loggerFactory, _hostInfo.BundledModulePath, pwsh);
13151307
psrlReadLine = new PsrlReadLine(psrlProxy, this, engineIntrinsics, ReadKey, OnPowerShellIdle);
13161308
return true;
13171309
}

0 commit comments

Comments
 (0)