1
1
// Copyright (c) Microsoft Corporation.
2
2
// Licensed under the MIT License.
3
3
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 ;
9
4
using System ;
10
5
using System . Collections . Generic ;
11
- using System . Collections . ObjectModel ;
6
+ using System . Linq ;
12
7
using System . Management . Automation ;
13
8
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 ;
17
13
using Microsoft . PowerShell . EditorServices . Services . PowerShell . Host ;
14
+ using Microsoft . PowerShell . EditorServices . Services . PowerShell . Runspace ;
18
15
19
16
namespace Microsoft . PowerShell . EditorServices . Services . PowerShell . Debugging
20
17
{
21
18
internal class DscBreakpointCapability
22
19
{
20
+ private static bool ? isDscInstalled ;
23
21
private string [ ] dscResourceRootPaths = Array . Empty < string > ( ) ;
22
+ private readonly Dictionary < string , int [ ] > breakpointsPerFile = new ( ) ;
24
23
25
- private readonly Dictionary < string , int [ ] > breakpointsPerFile =
26
- new ( ) ;
27
-
28
- public async Task < BreakpointDetails [ ] > SetLineBreakpointsAsync (
24
+ public async Task < IReadOnlyList < BreakpointDetails > > SetLineBreakpointsAsync (
29
25
IInternalPowerShellExecutionService executionService ,
30
26
string scriptPath ,
31
- BreakpointDetails [ ] breakpoints )
27
+ IReadOnlyList < BreakpointDetails > breakpoints )
32
28
{
33
- List < BreakpointDetails > resultBreakpointDetails =
34
- new ( ) ;
35
-
36
29
// We always get the latest array of breakpoint line numbers
37
30
// 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 )
39
33
{
40
34
// Set the breakpoints for this scriptPath
41
- breakpointsPerFile [ scriptPath ] =
42
- breakpoints . Select ( b => b . LineNumber ) . ToArray ( ) ;
35
+ breakpointsPerFile [ scriptPath ] = lineNumbers ;
43
36
}
44
37
else
45
38
{
@@ -72,7 +65,7 @@ await executionService.ExecutePSCommandAsync(
72
65
breakpoint . Verified = true ;
73
66
}
74
67
75
- return breakpoints . ToArray ( ) ;
68
+ return breakpoints ;
76
69
}
77
70
78
71
public bool IsDscResourcePath ( string scriptPath )
@@ -84,88 +77,57 @@ public bool IsDscResourcePath(string scriptPath)
84
77
StringComparison . CurrentCultureIgnoreCase ) ) ;
85
78
}
86
79
87
- public static Task < DscBreakpointCapability > GetDscCapabilityAsync (
80
+ public static async Task < DscBreakpointCapability > GetDscCapabilityAsync (
88
81
ILogger logger ,
89
82
IRunspaceInfo currentRunspace ,
90
- PsesInternalHost psesHost ,
91
- CancellationToken cancellationToken )
83
+ PsesInternalHost psesHost )
92
84
{
93
85
// DSC support is enabled only for Windows PowerShell.
94
86
if ( ( currentRunspace . PowerShellVersionDetails . Version . Major >= 6 ) &&
95
87
( currentRunspace . RunspaceOrigin != RunspaceOrigin . DebuggedRunspace ) )
96
88
{
97
- return Task . FromResult < DscBreakpointCapability > ( null ) ;
89
+ return null ;
98
90
}
99
91
100
- DscBreakpointCapability getDscBreakpointCapabilityFunc ( SMA . PowerShell pwsh , CancellationToken _ )
92
+ if ( ! isDscInstalled . HasValue )
101
93
{
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
+ }
156
108
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 ) ;
158
122
159
123
logger . LogTrace ( $ "DSC resources found: { resourcePaths . Count } ") ;
160
-
161
- return capability ;
124
+ return new DscBreakpointCapability
125
+ {
126
+ dscResourceRootPaths = resourcePaths . ToArray ( )
127
+ } ;
162
128
}
163
129
164
- return psesHost . ExecuteDelegateAsync (
165
- nameof ( getDscBreakpointCapabilityFunc ) ,
166
- executionOptions : null ,
167
- getDscBreakpointCapabilityFunc ,
168
- cancellationToken ) ;
130
+ return null ;
169
131
}
170
132
}
171
133
}
0 commit comments