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 ;
94using System ;
105using System . Collections . Generic ;
11- using System . Collections . ObjectModel ;
6+ using System . Linq ;
127using System . Management . Automation ;
138using 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 ;
1713using Microsoft . PowerShell . EditorServices . Services . PowerShell . Host ;
14+ using Microsoft . PowerShell . EditorServices . Services . PowerShell . Runspace ;
1815
1916namespace Microsoft . PowerShell . EditorServices . Services . PowerShell . Debugging
2017{
2118 internal class DscBreakpointCapability
2219 {
20+ private static bool ? isDscInstalled ;
2321 private string [ ] dscResourceRootPaths = Array . Empty < string > ( ) ;
22+ private readonly Dictionary < string , int [ ] > breakpointsPerFile = new ( ) ;
2423
25- private readonly Dictionary < string , int [ ] > breakpointsPerFile =
26- new ( ) ;
27-
28- public async Task < BreakpointDetails [ ] > SetLineBreakpointsAsync (
24+ public async Task < IReadOnlyList < BreakpointDetails > > SetLineBreakpointsAsync (
2925 IInternalPowerShellExecutionService executionService ,
3026 string scriptPath ,
31- BreakpointDetails [ ] breakpoints )
27+ IReadOnlyList < BreakpointDetails > breakpoints )
3228 {
33- List < BreakpointDetails > resultBreakpointDetails =
34- new ( ) ;
35-
3629 // We always get the latest array of breakpoint line numbers
3730 // so store that for future use
38- if ( breakpoints . Length > 0 )
31+ int [ ] lineNumbers = breakpoints . Select ( b => b . LineNumber ) . ToArray ( ) ;
32+ if ( lineNumbers . Length > 0 )
3933 {
4034 // Set the breakpoints for this scriptPath
41- breakpointsPerFile [ scriptPath ] =
42- breakpoints . Select ( b => b . LineNumber ) . ToArray ( ) ;
35+ breakpointsPerFile [ scriptPath ] = lineNumbers ;
4336 }
4437 else
4538 {
@@ -72,7 +65,7 @@ await executionService.ExecutePSCommandAsync(
7265 breakpoint . Verified = true ;
7366 }
7467
75- return breakpoints . ToArray ( ) ;
68+ return breakpoints ;
7669 }
7770
7871 public bool IsDscResourcePath ( string scriptPath )
@@ -84,88 +77,57 @@ public bool IsDscResourcePath(string scriptPath)
8477 StringComparison . CurrentCultureIgnoreCase ) ) ;
8578 }
8679
87- public static Task < DscBreakpointCapability > GetDscCapabilityAsync (
80+ public static async Task < DscBreakpointCapability > GetDscCapabilityAsync (
8881 ILogger logger ,
8982 IRunspaceInfo currentRunspace ,
90- PsesInternalHost psesHost ,
91- CancellationToken cancellationToken )
83+ PsesInternalHost psesHost )
9284 {
9385 // DSC support is enabled only for Windows PowerShell.
9486 if ( ( currentRunspace . PowerShellVersionDetails . Version . Major >= 6 ) &&
9587 ( currentRunspace . RunspaceOrigin != RunspaceOrigin . DebuggedRunspace ) )
9688 {
97- return Task . FromResult < DscBreakpointCapability > ( null ) ;
89+ return null ;
9890 }
9991
100- DscBreakpointCapability getDscBreakpointCapabilityFunc ( SMA . PowerShell pwsh , CancellationToken _ )
92+ if ( ! isDscInstalled . HasValue )
10193 {
102- PSInvocationSettings invocationSettings = new ( )
103- {
104- AddToHistory = false ,
105- ErrorActionPreference = ActionPreference . Stop
106- } ;
107-
108- PSModuleInfo dscModule = null ;
109- try
110- {
111- dscModule = pwsh . AddCommand ( "Import-Module" )
112- . AddArgument ( @"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1" )
113- . AddParameter ( "PassThru" )
114- . InvokeAndClear < PSModuleInfo > ( invocationSettings )
115- . FirstOrDefault ( ) ;
116- }
117- catch ( RuntimeException e )
118- {
119- logger . LogException ( "Could not load the DSC module!" , e ) ;
120- }
121-
122- if ( dscModule == null )
123- {
124- logger . LogTrace ( "Side-by-side DSC module was not found." ) ;
125- return null ;
126- }
127-
128- logger . LogTrace ( "Side-by-side DSC module found, gathering DSC resource paths..." ) ;
129-
130- // The module was loaded, add the breakpoint capability
131- DscBreakpointCapability capability = new ( ) ;
132-
133- pwsh . AddCommand ( "Microsoft.PowerShell.Utility\\ Write-Host" )
134- . AddArgument ( "Gathering DSC resource paths, this may take a while..." )
135- . InvokeAndClear ( invocationSettings ) ;
136-
137- Collection < string > resourcePaths = null ;
138- try
139- {
140- // Get the list of DSC resource paths
141- resourcePaths = pwsh . AddCommand ( "Get-DscResource" )
142- . AddCommand ( "Select-Object" )
143- . AddParameter ( "ExpandProperty" , "ParentPath" )
144- . InvokeAndClear < string > ( invocationSettings ) ;
145- }
146- catch ( CmdletInvocationException e )
147- {
148- logger . LogException ( "Get-DscResource failed!" , e ) ;
149- }
150-
151- if ( resourcePaths == null )
152- {
153- logger . LogTrace ( "No DSC resources found." ) ;
154- return null ;
155- }
94+ PSCommand psCommand = new PSCommand ( )
95+ . AddCommand ( "Import-Module" )
96+ . AddArgument ( @"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1" )
97+ . AddParameter ( "PassThru" ) ;
98+
99+ IReadOnlyList < PSModuleInfo > dscModule =
100+ await psesHost . ExecutePSCommandAsync < PSModuleInfo > (
101+ psCommand ,
102+ CancellationToken . None ,
103+ new PowerShellExecutionOptions { ThrowOnError = false } ) . ConfigureAwait ( false ) ;
104+
105+ isDscInstalled = dscModule . Count > 0 ;
106+ logger . LogTrace ( "Side-by-side DSC module found: " + isDscInstalled . Value ) ;
107+ }
156108
157- capability . dscResourceRootPaths = resourcePaths . ToArray ( ) ;
109+ if ( isDscInstalled . Value )
110+ {
111+ PSCommand psCommand = new PSCommand ( )
112+ . AddCommand ( "Get-DscResource" )
113+ . AddCommand ( "Select-Object" )
114+ . AddParameter ( "ExpandProperty" , "ParentPath" ) ;
115+
116+ IReadOnlyList < string > resourcePaths =
117+ await psesHost . ExecutePSCommandAsync < string > (
118+ psCommand ,
119+ CancellationToken . None ,
120+ new PowerShellExecutionOptions { ThrowOnError = false }
121+ ) . ConfigureAwait ( false ) ;
158122
159123 logger . LogTrace ( $ "DSC resources found: { resourcePaths . Count } ") ;
160-
161- return capability ;
124+ return new DscBreakpointCapability
125+ {
126+ dscResourceRootPaths = resourcePaths . ToArray ( )
127+ } ;
162128 }
163129
164- return psesHost . ExecuteDelegateAsync (
165- nameof ( getDscBreakpointCapabilityFunc ) ,
166- executionOptions : null ,
167- getDscBreakpointCapabilityFunc ,
168- cancellationToken ) ;
130+ return null ;
169131 }
170132 }
171133}
0 commit comments