Skip to content

Commit 11837b9

Browse files
committed
Only try to load DSC module once
Instead of trying repeatedly every time we set a breakpoint.
1 parent ec06e57 commit 11837b9

File tree

7 files changed

+58
-103
lines changed

7 files changed

+58
-103
lines changed

Diff for: src/PowerShellEditorServices/Services/DebugAdapter/DebugService.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ public async Task<IEnumerable<BreakpointDetails>> SetLineBreakpointsAsync(
135135
IEnumerable<BreakpointDetails> breakpoints,
136136
bool clearExisting = true)
137137
{
138-
DscBreakpointCapability dscBreakpoints = await _debugContext.GetDscBreakpointCapabilityAsync(CancellationToken.None).ConfigureAwait(false);
138+
DscBreakpointCapability dscBreakpoints = await _debugContext.GetDscBreakpointCapabilityAsync().ConfigureAwait(false);
139139

140140
string scriptPath = scriptFile.FilePath;
141141

Diff for: src/PowerShellEditorServices/Services/DebugAdapter/Handlers/BreakpointHandlers.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public async Task<SetBreakpointsResponse> Handle(SetBreakpointsArguments request
5252
if (!_workspaceService.TryGetFile(request.Source.Path, out ScriptFile scriptFile))
5353
{
5454
string message = _debugStateService.NoDebug ? string.Empty : "Source file could not be accessed, breakpoint not set.";
55-
System.Collections.Generic.IEnumerable<Breakpoint> srcBreakpoints = request.Breakpoints
55+
IEnumerable<Breakpoint> srcBreakpoints = request.Breakpoints
5656
.Select(srcBkpt => LspDebugUtils.CreateBreakpoint(
5757
srcBkpt, request.Source.Path, message, verified: _debugStateService.NoDebug));
5858

@@ -71,7 +71,7 @@ public async Task<SetBreakpointsResponse> Handle(SetBreakpointsArguments request
7171

7272
string message = _debugStateService.NoDebug ? string.Empty : "Source is not a PowerShell script, breakpoint not set.";
7373

74-
System.Collections.Generic.IEnumerable<Breakpoint> srcBreakpoints = request.Breakpoints
74+
IEnumerable<Breakpoint> srcBreakpoints = request.Breakpoints
7575
.Select(srcBkpt => LspDebugUtils.CreateBreakpoint(
7676
srcBkpt, request.Source.Path, message, verified: _debugStateService.NoDebug));
7777

Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
using System.Linq;
5-
using System.Threading.Tasks;
6-
using Microsoft.Extensions.Logging;
7-
using Microsoft.PowerShell.EditorServices.Logging;
8-
using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
94
using System;
105
using System.Collections.Generic;
11-
using System.Collections.ObjectModel;
6+
using System.Linq;
127
using System.Management.Automation;
138
using System.Threading;
14-
using SMA = System.Management.Automation;
15-
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Utility;
16-
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Runspace;
9+
using System.Threading.Tasks;
10+
using Microsoft.Extensions.Logging;
11+
using Microsoft.PowerShell.EditorServices.Services.DebugAdapter;
12+
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Execution;
1713
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
14+
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Runspace;
1815

1916
namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Debugging
2017
{
2118
internal class DscBreakpointCapability
2219
{
20+
private static bool? isDscInstalled;
2321
private string[] dscResourceRootPaths = Array.Empty<string>();
24-
2522
private readonly Dictionary<string, int[]> breakpointsPerFile = new();
2623

2724
public async Task<IEnumerable<BreakpointDetails>> SetLineBreakpointsAsync(
@@ -79,88 +76,57 @@ public bool IsDscResourcePath(string scriptPath)
7976
StringComparison.CurrentCultureIgnoreCase));
8077
}
8178

82-
public static Task<DscBreakpointCapability> GetDscCapabilityAsync(
79+
public static async Task<DscBreakpointCapability> GetDscCapabilityAsync(
8380
ILogger logger,
8481
IRunspaceInfo currentRunspace,
85-
PsesInternalHost psesHost,
86-
CancellationToken cancellationToken)
82+
PsesInternalHost psesHost)
8783
{
8884
// DSC support is enabled only for Windows PowerShell.
8985
if ((currentRunspace.PowerShellVersionDetails.Version.Major >= 6) &&
9086
(currentRunspace.RunspaceOrigin != RunspaceOrigin.DebuggedRunspace))
9187
{
92-
return Task.FromResult<DscBreakpointCapability>(null);
88+
return null;
9389
}
9490

95-
DscBreakpointCapability getDscBreakpointCapabilityFunc(SMA.PowerShell pwsh, CancellationToken _)
91+
if (!isDscInstalled.HasValue)
9692
{
97-
PSInvocationSettings invocationSettings = new()
98-
{
99-
AddToHistory = false,
100-
ErrorActionPreference = ActionPreference.Stop
101-
};
102-
103-
PSModuleInfo dscModule = null;
104-
try
105-
{
106-
dscModule = pwsh.AddCommand("Import-Module")
107-
.AddArgument(@"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1")
108-
.AddParameter("PassThru")
109-
.InvokeAndClear<PSModuleInfo>(invocationSettings)
110-
.FirstOrDefault();
111-
}
112-
catch (RuntimeException e)
113-
{
114-
logger.LogException("Could not load the DSC module!", e);
115-
}
116-
117-
if (dscModule == null)
118-
{
119-
logger.LogTrace("Side-by-side DSC module was not found.");
120-
return null;
121-
}
122-
123-
logger.LogTrace("Side-by-side DSC module found, gathering DSC resource paths...");
124-
125-
// The module was loaded, add the breakpoint capability
126-
DscBreakpointCapability capability = new();
127-
128-
pwsh.AddCommand("Microsoft.PowerShell.Utility\\Write-Host")
129-
.AddArgument("Gathering DSC resource paths, this may take a while...")
130-
.InvokeAndClear(invocationSettings);
131-
132-
Collection<string> resourcePaths = null;
133-
try
134-
{
135-
// Get the list of DSC resource paths
136-
resourcePaths = pwsh.AddCommand("Get-DscResource")
137-
.AddCommand("Select-Object")
138-
.AddParameter("ExpandProperty", "ParentPath")
139-
.InvokeAndClear<string>(invocationSettings);
140-
}
141-
catch (CmdletInvocationException e)
142-
{
143-
logger.LogException("Get-DscResource failed!", e);
144-
}
145-
146-
if (resourcePaths == null)
147-
{
148-
logger.LogTrace("No DSC resources found.");
149-
return null;
150-
}
93+
PSCommand psCommand = new PSCommand()
94+
.AddCommand("Import-Module")
95+
.AddArgument(@"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1")
96+
.AddParameter("PassThru");
97+
98+
IReadOnlyList<PSModuleInfo> dscModule =
99+
await psesHost.ExecutePSCommandAsync<PSModuleInfo>(
100+
psCommand,
101+
CancellationToken.None,
102+
new PowerShellExecutionOptions { ThrowOnError = false }).ConfigureAwait(false);
103+
104+
isDscInstalled = dscModule.Count > 0;
105+
logger.LogTrace("Side-by-side DSC module found: " + isDscInstalled.Value);
106+
}
151107

152-
capability.dscResourceRootPaths = resourcePaths.ToArray();
108+
if (isDscInstalled.Value)
109+
{
110+
PSCommand psCommand = new PSCommand()
111+
.AddCommand("Get-DscResource")
112+
.AddCommand("Select-Object")
113+
.AddParameter("ExpandProperty", "ParentPath");
114+
115+
IReadOnlyList<string> resourcePaths =
116+
await psesHost.ExecutePSCommandAsync<string>(
117+
psCommand,
118+
CancellationToken.None,
119+
new PowerShellExecutionOptions { ThrowOnError = false }
120+
).ConfigureAwait(false);
153121

154122
logger.LogTrace($"DSC resources found: {resourcePaths.Count}");
155-
156-
return capability;
123+
return new DscBreakpointCapability
124+
{
125+
dscResourceRootPaths = resourcePaths.ToArray()
126+
};
157127
}
158128

159-
return psesHost.ExecuteDelegateAsync(
160-
nameof(getDscBreakpointCapabilityFunc),
161-
executionOptions: null,
162-
getDscBreakpointCapabilityFunc,
163-
cancellationToken);
129+
return null;
164130
}
165131
}
166132
}

Diff for: src/PowerShellEditorServices/Services/PowerShell/Debugging/IPowerShellDebugContext.cs

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

44
using System;
55
using System.Management.Automation;
6-
using System.Threading;
76
using System.Threading.Tasks;
87

98
namespace Microsoft.PowerShell.EditorServices.Services.PowerShell.Debugging
@@ -34,6 +33,6 @@ internal interface IPowerShellDebugContext
3433

3534
void Abort();
3635

37-
Task<DscBreakpointCapability> GetDscBreakpointCapabilityAsync(CancellationToken cancellationToken);
36+
Task<DscBreakpointCapability> GetDscBreakpointCapabilityAsync();
3837
}
3938
}

Diff for: src/PowerShellEditorServices/Services/PowerShell/Debugging/PowerShellDebugContext.cs

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

44
using System;
55
using System.Management.Automation;
6-
using System.Threading;
76
using System.Threading.Tasks;
87
using Microsoft.Extensions.Logging;
98
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Context;
@@ -81,10 +80,10 @@ public PowerShellDebugContext(
8180
public event Action<object, DebuggerResumingEventArgs> DebuggerResuming;
8281
public event Action<object, BreakpointUpdatedEventArgs> BreakpointUpdated;
8382

84-
public Task<DscBreakpointCapability> GetDscBreakpointCapabilityAsync(CancellationToken cancellationToken)
83+
public Task<DscBreakpointCapability> GetDscBreakpointCapabilityAsync()
8584
{
8685
_psesHost.Runspace.ThrowCancelledIfUnusable();
87-
return _psesHost.CurrentRunspace.GetDscBreakpointCapabilityAsync(_logger, _psesHost, cancellationToken);
86+
return _psesHost.CurrentRunspace.GetDscBreakpointCapabilityAsync(_logger, _psesHost);
8887
}
8988

9089
// This is required by the PowerShell API so that remote debugging works. Without it, a

Diff for: src/PowerShellEditorServices/Services/PowerShell/Runspace/RunspaceInfo.cs

+2-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Debugging;
66
using Microsoft.Extensions.Logging;
77
using System.Threading.Tasks;
8-
using System.Threading;
98
using System;
109
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
1110

@@ -86,14 +85,12 @@ public RunspaceInfo(
8685

8786
public async Task<DscBreakpointCapability> GetDscBreakpointCapabilityAsync(
8887
ILogger logger,
89-
PsesInternalHost psesHost,
90-
CancellationToken cancellationToken)
88+
PsesInternalHost psesHost)
9189
{
9290
return _dscBreakpointCapability ??= await DscBreakpointCapability.GetDscCapabilityAsync(
9391
logger,
9492
this,
95-
psesHost,
96-
cancellationToken)
93+
psesHost)
9794
.ConfigureAwait(false);
9895
}
9996
}

Diff for: src/PowerShellEditorServices/Services/Template/TemplateService.cs

+7-13
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,12 @@ public async Task<bool> ImportPlasterIfInstalledAsync()
7272

7373
_logger.LogTrace("Checking if Plaster is installed...");
7474

75-
PSObject moduleObject = (await _executionService.ExecutePSCommandAsync<PSObject>(psCommand, CancellationToken.None).ConfigureAwait(false))[0];
75+
IReadOnlyList<PSObject> moduleObject =
76+
await _executionService.ExecutePSCommandAsync<PSObject>(
77+
psCommand, CancellationToken.None).ConfigureAwait(false);
7678

77-
isPlasterInstalled = moduleObject != null;
78-
string installedQualifier =
79-
isPlasterInstalled.Value
80-
? string.Empty : "not ";
81-
82-
_logger.LogTrace($"Plaster is {installedQualifier}installed!");
79+
isPlasterInstalled = moduleObject.Count > 0;
80+
_logger.LogTrace("Plaster installed: " + isPlasterInstalled.Value);
8381

8482
// Attempt to load plaster
8583
if (isPlasterInstalled.Value && !isPlasterLoaded)
@@ -89,17 +87,13 @@ public async Task<bool> ImportPlasterIfInstalledAsync()
8987
psCommand = new PSCommand();
9088
psCommand
9189
.AddCommand("Import-Module")
92-
.AddParameter("ModuleInfo", (PSModuleInfo)moduleObject.ImmediateBaseObject)
90+
.AddParameter("ModuleInfo", (PSModuleInfo)moduleObject[0].ImmediateBaseObject)
9391
.AddParameter("PassThru");
9492

9593
IReadOnlyList<PSModuleInfo> importResult = await _executionService.ExecutePSCommandAsync<PSModuleInfo>(psCommand, CancellationToken.None).ConfigureAwait(false);
9694

9795
isPlasterLoaded = importResult.Count > 0;
98-
string loadedQualifier =
99-
isPlasterInstalled.Value
100-
? "was" : "could not be";
101-
102-
_logger.LogTrace($"Plaster {loadedQualifier} loaded successfully!");
96+
_logger.LogTrace("Plaster loaded: " + isPlasterLoaded);
10397
}
10498
}
10599

0 commit comments

Comments
 (0)