-
Notifications
You must be signed in to change notification settings - Fork 240
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); | |
| } |