-
Notifications
You must be signed in to change notification settings - Fork 237
Closed
Labels
Description
Today the extension has support for DSC breakpoints:
Lines 20 to 170 in 4fa0346
internal class DscBreakpointCapability : IRunspaceCapability | |
{ | |
private string[] dscResourceRootPaths = Array.Empty<string>(); | |
private Dictionary<string, int[]> breakpointsPerFile = | |
new Dictionary<string, int[]>(); | |
public async Task<BreakpointDetails[]> SetLineBreakpointsAsync( | |
PowerShellContextService powerShellContext, | |
string scriptPath, | |
BreakpointDetails[] breakpoints) | |
{ | |
List<BreakpointDetails> resultBreakpointDetails = | |
new List<BreakpointDetails>(); | |
// We always get the latest array of breakpoint line numbers | |
// so store that for future use | |
if (breakpoints.Length > 0) | |
{ | |
// Set the breakpoints for this scriptPath | |
this.breakpointsPerFile[scriptPath] = | |
breakpoints.Select(b => b.LineNumber).ToArray(); | |
} | |
else | |
{ | |
// No more breakpoints for this scriptPath, remove it | |
this.breakpointsPerFile.Remove(scriptPath); | |
} | |
string hashtableString = | |
string.Join( | |
", ", | |
this.breakpointsPerFile | |
.Select(file => $"@{{Path=\"{file.Key}\";Line=@({string.Join(",", file.Value)})}}")); | |
// Run Enable-DscDebug as a script because running it as a PSCommand | |
// causes an error which states that the Breakpoint parameter has not | |
// been passed. | |
await powerShellContext.ExecuteScriptStringAsync( | |
hashtableString.Length > 0 | |
? $"Enable-DscDebug -Breakpoint {hashtableString}" | |
: "Disable-DscDebug", | |
false, | |
false).ConfigureAwait(false); | |
// Verify all the breakpoints and return them | |
foreach (var breakpoint in breakpoints) | |
{ | |
breakpoint.Verified = true; | |
} | |
return breakpoints.ToArray(); | |
} | |
public bool IsDscResourcePath(string scriptPath) | |
{ | |
return dscResourceRootPaths.Any( | |
dscResourceRootPath => | |
scriptPath.StartsWith( | |
dscResourceRootPath, | |
StringComparison.CurrentCultureIgnoreCase)); | |
} | |
public static DscBreakpointCapability CheckForCapability( | |
RunspaceDetails runspaceDetails, | |
PowerShellContextService powerShellContext, | |
ILogger logger) | |
{ | |
DscBreakpointCapability capability = null; | |
// DSC support is enabled only for Windows PowerShell. | |
if ((runspaceDetails.PowerShellVersion.Version.Major < 6) && | |
(runspaceDetails.Context != RunspaceContext.DebuggedRunspace)) | |
{ | |
using (PowerShell powerShell = PowerShell.Create()) | |
{ | |
powerShell.Runspace = runspaceDetails.Runspace; | |
// Attempt to import the updated DSC module | |
powerShell.AddCommand("Import-Module"); | |
powerShell.AddArgument(@"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1"); | |
powerShell.AddParameter("PassThru"); | |
powerShell.AddParameter("ErrorAction", "Ignore"); | |
PSObject moduleInfo = null; | |
try | |
{ | |
moduleInfo = powerShell.Invoke().FirstOrDefault(); | |
} | |
catch (RuntimeException e) | |
{ | |
logger.LogException("Could not load the DSC module!", e); | |
} | |
if (moduleInfo != null) | |
{ | |
logger.LogTrace("Side-by-side DSC module found, gathering DSC resource paths..."); | |
// The module was loaded, add the breakpoint capability | |
capability = new DscBreakpointCapability(); | |
runspaceDetails.AddCapability(capability); | |
powerShell.Commands.Clear(); | |
powerShell | |
.AddCommand("Microsoft.PowerShell.Utility\\Write-Host") | |
.AddArgument("Gathering DSC resource paths, this may take a while...") | |
.Invoke(); | |
// Get the list of DSC resource paths | |
powerShell.Commands.Clear(); | |
powerShell | |
.AddCommand("Get-DscResource") | |
.AddCommand("Select-Object") | |
.AddParameter("ExpandProperty", "ParentPath"); | |
Collection<PSObject> resourcePaths = null; | |
try | |
{ | |
resourcePaths = powerShell.Invoke(); | |
} | |
catch (CmdletInvocationException e) | |
{ | |
logger.LogException("Get-DscResource failed!", e); | |
} | |
if (resourcePaths != null) | |
{ | |
capability.dscResourceRootPaths = | |
resourcePaths | |
.Select(o => (string)o.BaseObject) | |
.ToArray(); | |
logger.LogTrace($"DSC resources found: {resourcePaths.Count}"); | |
} | |
else | |
{ | |
logger.LogTrace($"No DSC resources found."); | |
} | |
} | |
else | |
{ | |
logger.LogTrace($"Side-by-side DSC module was not found."); | |
} | |
} | |
} | |
return capability; | |
} | |
} |
The new pipeline thread consumer's debugger needs to also support these.
The capability has been migrated here:
Lines 25 to 169 in a0a8df1
internal class DscBreakpointCapability | |
{ | |
private string[] dscResourceRootPaths = Array.Empty<string>(); | |
private Dictionary<string, int[]> breakpointsPerFile = | |
new Dictionary<string, int[]>(); | |
public async Task<BreakpointDetails[]> SetLineBreakpointsAsync( | |
PowerShellExecutionService executionService, | |
string scriptPath, | |
BreakpointDetails[] breakpoints) | |
{ | |
List<BreakpointDetails> resultBreakpointDetails = | |
new List<BreakpointDetails>(); | |
// We always get the latest array of breakpoint line numbers | |
// so store that for future use | |
if (breakpoints.Length > 0) | |
{ | |
// Set the breakpoints for this scriptPath | |
this.breakpointsPerFile[scriptPath] = | |
breakpoints.Select(b => b.LineNumber).ToArray(); | |
} | |
else | |
{ | |
// No more breakpoints for this scriptPath, remove it | |
this.breakpointsPerFile.Remove(scriptPath); | |
} | |
string hashtableString = | |
string.Join( | |
", ", | |
this.breakpointsPerFile | |
.Select(file => $"@{{Path=\"{file.Key}\";Line=@({string.Join(",", file.Value)})}}")); | |
// Run Enable-DscDebug as a script because running it as a PSCommand | |
// causes an error which states that the Breakpoint parameter has not | |
// been passed. | |
var dscCommand = new PSCommand().AddScript( | |
hashtableString.Length > 0 | |
? $"Enable-DscDebug -Breakpoint {hashtableString}" | |
: "Disable-DscDebug"); | |
await executionService.ExecutePSCommandAsync( | |
dscCommand, | |
new PowerShellExecutionOptions(), | |
CancellationToken.None); | |
// Verify all the breakpoints and return them | |
foreach (var breakpoint in breakpoints) | |
{ | |
breakpoint.Verified = true; | |
} | |
return breakpoints.ToArray(); | |
} | |
public bool IsDscResourcePath(string scriptPath) | |
{ | |
return dscResourceRootPaths.Any( | |
dscResourceRootPath => | |
scriptPath.StartsWith( | |
dscResourceRootPath, | |
StringComparison.CurrentCultureIgnoreCase)); | |
} | |
public static async Task<DscBreakpointCapability> GetDscCapabilityAsync( | |
ILogger logger, | |
IRunspaceInfo currentRunspace, | |
PowerShellExecutionService executionService, | |
CancellationToken cancellationToken) | |
{ | |
// DSC support is enabled only for Windows PowerShell. | |
if ((currentRunspace.PowerShellVersionDetails.Version.Major >= 6) && | |
(currentRunspace.RunspaceOrigin != RunspaceOrigin.DebuggedRunspace)) | |
{ | |
return null; | |
} | |
Func<SMA.PowerShell, CancellationToken, DscBreakpointCapability> getDscBreakpointCapabilityFunc = (pwsh, cancellationToken) => | |
{ | |
PSModuleInfo dscModule = null; | |
try | |
{ | |
dscModule = pwsh.AddCommand("Import-Module") | |
.AddArgument(@"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1") | |
.AddParameter("PassThru") | |
.AddParameter("ErrorAction", "Ignore") | |
.InvokeAndClear<PSModuleInfo>() | |
.FirstOrDefault(); | |
} | |
catch (RuntimeException e) | |
{ | |
logger.LogException("Could not load the DSC module!", e); | |
} | |
if (dscModule == null) | |
{ | |
logger.LogTrace($"Side-by-side DSC module was not found."); | |
return null; | |
} | |
logger.LogTrace("Side-by-side DSC module found, gathering DSC resource paths..."); | |
// The module was loaded, add the breakpoint capability | |
var capability = new DscBreakpointCapability(); | |
pwsh.AddCommand("Microsoft.PowerShell.Utility\\Write-Host") | |
.AddArgument("Gathering DSC resource paths, this may take a while...") | |
.InvokeAndClear(); | |
Collection<string> resourcePaths = null; | |
try | |
{ | |
// Get the list of DSC resource paths | |
resourcePaths = pwsh.AddCommand("Get-DscResource") | |
.AddCommand("Select-Object") | |
.AddParameter("ExpandProperty", "ParentPath") | |
.InvokeAndClear<string>(); | |
} | |
catch (CmdletInvocationException e) | |
{ | |
logger.LogException("Get-DscResource failed!", e); | |
} | |
if (resourcePaths == null) | |
{ | |
logger.LogTrace($"No DSC resources found."); | |
return null; | |
} | |
capability.dscResourceRootPaths = resourcePaths.ToArray(); | |
logger.LogTrace($"DSC resources found: {resourcePaths.Count}"); | |
return capability; | |
}; | |
return await executionService.ExecuteDelegateAsync<DscBreakpointCapability>( | |
getDscBreakpointCapabilityFunc, | |
nameof(getDscBreakpointCapabilityFunc), | |
cancellationToken); | |
} | |
} |
But we need an equivalent of this still:
Lines 2569 to 2572 in 4fa0346
private void ConfigureRunspaceCapabilities(RunspaceDetails runspaceDetails) | |
{ | |
DscBreakpointCapability.CheckForCapability(this.CurrentRunspace, this, this.logger); | |
} |