Skip to content

Use HostInfo.BundledModulePath to find PSScriptAnalyzer #1864

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

Merged
merged 3 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/PowerShellEditorServices/Hosting/HostStartupInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;

Expand Down Expand Up @@ -92,7 +93,7 @@ public sealed class HostStartupInfo
public string LogPath { get; }

/// <summary>
/// The InitialSessionState will be inherited from the orginal PowerShell process. This will
/// The InitialSessionState will be inherited from the original PowerShell process. This will
/// be used when creating runspaces so that we honor the same InitialSessionState.
/// </summary>
public InitialSessionState InitialSessionState { get; }
Expand Down Expand Up @@ -167,7 +168,15 @@ public HostStartupInfo(
LogLevel = logLevel;
ConsoleReplEnabled = consoleReplEnabled;
UsesLegacyReadLine = usesLegacyReadLine;
BundledModulePath = bundledModulePath;

// Respect a user provided bundled module path.
BundledModulePath = Directory.Exists(bundledModulePath)
? bundledModulePath
: Path.GetFullPath(Path.Combine(
Path.GetDirectoryName(typeof(HostStartupInfo).Assembly.Location),
"..",
"..",
".."));
}

#endregion
Expand Down
27 changes: 12 additions & 15 deletions src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.Hosting;
using Microsoft.PowerShell.EditorServices.Services.Analysis;
using Microsoft.PowerShell.EditorServices.Services.Configuration;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
Expand Down Expand Up @@ -52,8 +53,7 @@ internal static string GetUniqueIdFromDiagnostic(Diagnostic diagnostic)
.Append(':')
.Append(end.Character);

string id = sb.ToString();
return id;
return sb.ToString();
}

/// <summary>
Expand Down Expand Up @@ -96,20 +96,16 @@ internal static string GetUniqueIdFromDiagnostic(Diagnostic diagnostic)

private CancellationTokenSource _diagnosticsCancellationTokenSource;

private readonly string _pssaModulePath;

private string _pssaSettingsFilePath;

/// <summary>
/// Construct a new AnalysisService.
/// </summary>
/// <param name="loggerFactory">Logger factory to create logger instances with.</param>
/// <param name="languageServer">The LSP language server for notifications.</param>
/// <param name="configurationService">The configuration service to query for configurations.</param>
/// <param name="workspaceService">The workspace service for file handling within a workspace.</param>
public AnalysisService(
ILoggerFactory loggerFactory,
ILanguageServerFacade languageServer,
ConfigurationService configurationService,
WorkspaceService workspaceService)
WorkspaceService workspaceService,
HostStartupInfo hostInfo)
{
_loggerFactory = loggerFactory;
_logger = loggerFactory.CreateLogger<AnalysisService>();
Expand All @@ -119,6 +115,7 @@ public AnalysisService(
_analysisDelayMillis = 750;
_mostRecentCorrectionsByFile = new ConcurrentDictionary<ScriptFile, CorrectionTableEntry>();
_analysisEngineLazy = new Lazy<PssaCmdletAnalysisEngine>(InstantiateAnalysisEngine);
_pssaModulePath = Path.Combine(hostInfo.BundledModulePath, "PSScriptAnalyzer");
_pssaSettingsFilePath = null;
}

Expand Down Expand Up @@ -202,7 +199,7 @@ public async Task<string> GetCommentHelpText(string functionText, string helpLoc
return null;
}

Hashtable commentHelpSettings = AnalysisService.GetCommentHelpRuleSettings(helpLocation, forBlockComment);
Hashtable commentHelpSettings = GetCommentHelpRuleSettings(helpLocation, forBlockComment);

ScriptFileMarker[] analysisResults = await AnalysisEngine.AnalyzeScriptAsync(functionText, commentHelpSettings).ConfigureAwait(false);

Expand Down Expand Up @@ -285,7 +282,7 @@ private void InitializeAnalysisEngineToCurrentSettings()
_analysisEngineLazy = new Lazy<PssaCmdletAnalysisEngine>(() => RecreateAnalysisEngine(currentAnalysisEngine));
}

private PssaCmdletAnalysisEngine InstantiateAnalysisEngine()
internal PssaCmdletAnalysisEngine InstantiateAnalysisEngine()
{
PssaCmdletAnalysisEngine.Builder pssaCmdletEngineBuilder = new(_loggerFactory);

Expand All @@ -302,7 +299,7 @@ private PssaCmdletAnalysisEngine InstantiateAnalysisEngine()
pssaCmdletEngineBuilder.WithIncludedRules(s_defaultRules);
}

return pssaCmdletEngineBuilder.Build();
return pssaCmdletEngineBuilder.Build(_pssaModulePath);
}

private PssaCmdletAnalysisEngine RecreateAnalysisEngine(PssaCmdletAnalysisEngine oldAnalysisEngine)
Expand All @@ -320,15 +317,15 @@ private PssaCmdletAnalysisEngine RecreateAnalysisEngine(PssaCmdletAnalysisEngine

private bool TryFindSettingsFile(out string settingsFilePath)
{
string configuredPath = _configurationService.CurrentSettings.ScriptAnalysis.SettingsPath;
string configuredPath = _configurationService?.CurrentSettings.ScriptAnalysis.SettingsPath;

if (string.IsNullOrEmpty(configuredPath))
{
settingsFilePath = null;
return false;
}

settingsFilePath = _workspaceService.ResolveWorkspacePath(configuredPath);
settingsFilePath = _workspaceService?.ResolveWorkspacePath(configuredPath);

if (settingsFilePath == null
|| !File.Exists(settingsFilePath))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -67,35 +66,27 @@ public Builder WithIncludedRules(string[] rules)
/// If PSScriptAnalyzer cannot be found, this will return null.
/// </summary>
/// <returns>A newly configured PssaCmdletAnalysisEngine, or null if PSScriptAnalyzer cannot be found.</returns>
public PssaCmdletAnalysisEngine Build()
public PssaCmdletAnalysisEngine Build(string pssaModulePath)
{
// RunspacePool takes care of queuing commands for us so we do not
// need to worry about executing concurrent commands
ILogger logger = _loggerFactory.CreateLogger<PssaCmdletAnalysisEngine>();
try
{
RunspacePool pssaRunspacePool = CreatePssaRunspacePool();

PssaCmdletAnalysisEngine cmdletAnalysisEngine = _settingsParameter is not null
? new PssaCmdletAnalysisEngine(logger, pssaRunspacePool, _settingsParameter)
: new PssaCmdletAnalysisEngine(logger, pssaRunspacePool, _rules);

logger.LogDebug("Creating PSScriptAnalyzer runspace with module at: '{Path}'", pssaModulePath);
RunspacePool pssaRunspacePool = CreatePssaRunspacePool(pssaModulePath);
PssaCmdletAnalysisEngine cmdletAnalysisEngine = new(logger, pssaRunspacePool, _settingsParameter ?? _rules);
cmdletAnalysisEngine.LogAvailablePssaFeatures();
return cmdletAnalysisEngine;
}
catch (FileNotFoundException e)
catch (Exception ex)
{
logger.LogError(e, $"Unable to find PSScriptAnalyzer. Disabling script analysis. PSModulePath: '{Environment.GetEnvironmentVariable("PSModulePath")}'");
logger.LogError(ex, "Unable to load PSScriptAnalyzer, disabling script analysis!");
return null;
}
}
}

// This is a default that can be overriden at runtime by the user or tests.
// TODO: Deduplicate this logic with PsesInternalHost.
private static readonly string s_pssaModulePath = Path.GetFullPath(Path.Combine(
Path.GetDirectoryName(typeof(PssaCmdletAnalysisEngine).Assembly.Location), "..", "..", "..", "PSScriptAnalyzer"));

/// <summary>
/// The indentation to add when the logger lists errors.
/// </summary>
Expand Down Expand Up @@ -365,7 +356,7 @@ private IEnumerable<string> GetPSScriptAnalyzerRules()
/// This looks for the latest version of PSScriptAnalyzer on the path and loads that.
/// </summary>
/// <returns>A runspace pool with PSScriptAnalyzer loaded for running script analysis tasks.</returns>
private static RunspacePool CreatePssaRunspacePool()
private static RunspacePool CreatePssaRunspacePool(string pssaModulePath)
{
using PowerShell pwsh = PowerShell.Create(RunspaceMode.NewRunspace);

Expand All @@ -375,10 +366,7 @@ private static RunspacePool CreatePssaRunspacePool()
// We intentionally use `CreateDefault2()` as it loads `Microsoft.PowerShell.Core`
// only, which is a more minimal and therefore safer state.
InitialSessionState sessionState = InitialSessionState.CreateDefault2();

sessionState.ImportPSModulesFromPath(s_pssaModulePath);
// pwsh.ImportModule(s_pssaModulePath);
// sessionState.ImportPSModule(new[] { pssaModuleInfo.ModuleBase });
sessionState.ImportPSModulesFromPath(pssaModulePath);

RunspacePool runspacePool = RunspaceFactory.CreateRunspacePool(sessionState);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Host
internal class PsesInternalHost : PSHost, IHostSupportsInteractiveSession, IRunspaceContext, IInternalPowerShellExecutionService
{
private const string DefaultPrompt = "> ";
// 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 string CommandsModulePath => Path.GetFullPath(Path.Combine(
s_bundledModulePath, "PowerShellEditorServices", "Commands", "PowerShellEditorServices.Commands.psd1"));

private static readonly PropertyInfo s_scriptDebuggerTriggerObjectProperty;

Expand Down Expand Up @@ -115,14 +109,6 @@ public PsesInternalHost(
_logger = loggerFactory.CreateLogger<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<ISynchronousTask>();
_psFrameStack = new Stack<PowerShellContextFrame>();
Expand Down Expand Up @@ -1012,7 +998,13 @@ private static PowerShell CreatePowerShellForRunspace(Runspace runspace)
pwsh.SetCorrectExecutionPolicy(_logger);
}

pwsh.ImportModule(CommandsModulePath);
string commandsModulePath = Path.Combine(
_hostInfo.BundledModulePath,
"PowerShellEditorServices",
"Commands",
"PowerShellEditorServices.Commands.psd1");

pwsh.ImportModule(commandsModulePath);

if (hostStartupInfo.AdditionalModules?.Count > 0)
{
Expand Down Expand Up @@ -1311,7 +1303,7 @@ internal bool TryLoadPSReadLine(PowerShell pwsh, EngineIntrinsics engineIntrinsi
psrlReadLine = null;
try
{
PSReadLineProxy psrlProxy = PSReadLineProxy.LoadAndCreate(_loggerFactory, s_bundledModulePath, pwsh);
PSReadLineProxy psrlProxy = PSReadLineProxy.LoadAndCreate(_loggerFactory, _hostInfo.BundledModulePath, pwsh);
psrlReadLine = new PsrlReadLine(psrlProxy, this, engineIntrinsics, ReadKey, OnPowerShellIdle);
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@
using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Test;
using Microsoft.PowerShell.EditorServices.Test.Shared;
using Microsoft.PowerShell.EditorServices.Utility;
using Xunit;
namespace Microsoft.PowerShell.EditorServices.Test.Debugging

namespace PowerShellEditorServices.Test.Debugging
{
[Trait("Category", "DebugService")]
public class DebugServiceTests : IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
using Microsoft.PowerShell.EditorServices.Services.Extension;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Test;
using Microsoft.PowerShell.EditorServices.Test.Shared;
using Xunit;

namespace Microsoft.PowerShell.EditorServices.Test.Extensions
namespace PowerShellEditorServices.Test.Extensions
{
[Trait("Category", "Extensions")]
public class ExtensionCommandTests : IDisposable
Expand Down Expand Up @@ -59,7 +60,7 @@ public async Task CanRegisterAndInvokeCommandWithCmdletName()
BufferRange.None);

EditorCommand commandAdded = null;
extensionCommandService.CommandAdded += (object _, EditorCommand command) => commandAdded = command;
extensionCommandService.CommandAdded += (_, command) => commandAdded = command;

const string commandName = "test.function";
const string commandDisplayName = "Function extension";
Expand Down Expand Up @@ -95,7 +96,7 @@ public async Task CanRegisterAndInvokeCommandWithScriptBlock()
BufferRange.None);

EditorCommand commandAdded = null;
extensionCommandService.CommandAdded += (object _, EditorCommand command) => commandAdded = command;
extensionCommandService.CommandAdded += (_, command) => commandAdded = command;

const string commandName = "test.scriptblock";
const string commandDisplayName = "ScriptBlock extension";
Expand Down Expand Up @@ -126,7 +127,7 @@ await psesHost.ExecutePSCommandAsync(
public async Task CanUpdateRegisteredCommand()
{
EditorCommand updatedCommand = null;
extensionCommandService.CommandUpdated += (object _, EditorCommand command) => updatedCommand = command;
extensionCommandService.CommandUpdated += (_, command) => updatedCommand = command;

const string commandName = "test.function";
const string commandDisplayName = "Updated function extension";
Expand Down Expand Up @@ -160,7 +161,7 @@ public async Task CanUnregisterCommand()
const string commandDisplayName = "ScriptBlock extension";

EditorCommand removedCommand = null;
extensionCommandService.CommandRemoved += (object _, EditorCommand command) => removedCommand = command;
extensionCommandService.CommandRemoved += (_, command) => removedCommand = command;

// Add the command and wait for the add event
await psesHost.ExecutePSCommandAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Test;
using Microsoft.PowerShell.EditorServices.Test.Shared;
using Microsoft.PowerShell.EditorServices.Test.Shared.Completion;
using Microsoft.PowerShell.EditorServices.Utility;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Xunit;

namespace Microsoft.PowerShell.EditorServices.Test.Language
namespace PowerShellEditorServices.Test.Language
{
[Trait("Category", "Completions")]
public class CompletionHandlerTests : IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
using System.Collections.Generic;
using System.IO;
using System.Management.Automation.Language;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Handlers;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Xunit;

namespace Microsoft.PowerShell.EditorServices.Test.Language
namespace PowerShellEditorServices.Test.Language
{
public class SemanticTokenTest
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility;
using Microsoft.PowerShell.EditorServices.Services.Symbols;
using Microsoft.PowerShell.EditorServices.Services.TextDocument;
using Microsoft.PowerShell.EditorServices.Test;
using Microsoft.PowerShell.EditorServices.Test.Shared;
using Microsoft.PowerShell.EditorServices.Test.Shared.Definition;
using Microsoft.PowerShell.EditorServices.Test.Shared.Occurrences;
Expand All @@ -23,7 +24,7 @@
using Microsoft.PowerShell.EditorServices.Test.Shared.Symbols;
using Xunit;

namespace Microsoft.PowerShell.EditorServices.Test.Language
namespace PowerShellEditorServices.Test.Language
{
[Trait("Category", "Symbols")]
public class SymbolsServiceTests : IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Xunit;

namespace Microsoft.PowerShell.EditorServices.Test.Language
namespace PowerShellEditorServices.Test.Language
{
public class TokenOperationsTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using Xunit;

namespace Microsoft.PowerShell.EditorServices.Test.Services.Symbols
namespace PowerShellEditorServices.Test.Services.Symbols
{
[Trait("Category", "AstOperations")]
public class AstOperationsTests
Expand Down
Loading