Skip to content

Commit 2aa8087

Browse files
authored
Merge pull request #371 from PowerShell/daviwil/push-detect
Improve detection of session changes when debugging ScriptBlocks
2 parents 6807e9d + 2cecbd5 commit 2aa8087

File tree

7 files changed

+383
-184
lines changed

7 files changed

+383
-184
lines changed

PowerShellEditorServices.build.ps1

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ if ($PSVersionTable.PSEdition -ne "Core") {
2121
task SetupDotNet -Before Restore, Clean, Build, BuildHost, Test, TestPowerShellApi, PackageNuGet {
2222

2323
# Fetch the SDK version from global.json
24-
$requiredSdkVersion = "1.0.0-rc3-004530"
24+
$requiredSdkVersion = "1.0.0-rc4-004771"
2525

2626
$needsInstall = $true
2727
$dotnetPath = "$PSScriptRoot/.dotnet"

src/PowerShellEditorServices/Debugging/DebugService.cs

+89-73
Large diffs are not rendered by default.

src/PowerShellEditorServices/PowerShellEditorServices.csproj

+1-4
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,7 @@
3434
</PropertyGroup>
3535

3636
<Target Name="PowerShellVersionOutput" BeforeTargets="Compile">
37-
<Message
38-
Condition=" '$(TargetFramework)' == 'net451' And '$(PowerShellVersion)' != '' "
39-
Text="Target PowerShell Version: $(PowerShellVersion) -- Constants: $(DefineConstants)"
40-
Importance="High" />
37+
<Message Condition=" '$(TargetFramework)' == 'net451' And '$(PowerShellVersion)' != '' " Text="Target PowerShell Version: $(PowerShellVersion) -- Constants: $(DefineConstants)" Importance="High" />
4138
</Target>
4239

4340
<ItemGroup Condition=" '$(TargetFramework)' == 'net451' And '$(PowerShellVersion)' == 'v3' ">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
using System.Linq;
7+
using System.Threading.Tasks;
8+
9+
namespace Microsoft.PowerShell.EditorServices.Session.Capabilities
10+
{
11+
using Microsoft.PowerShell.EditorServices.Utility;
12+
using System;
13+
using System.Collections.Generic;
14+
using System.Collections.ObjectModel;
15+
using System.Management.Automation;
16+
17+
internal class DscBreakpointCapability : IRunspaceCapability
18+
{
19+
private string[] dscResourceRootPaths = new string[0];
20+
21+
private Dictionary<string, int[]> breakpointsPerFile =
22+
new Dictionary<string, int[]>();
23+
24+
public async Task<List<BreakpointDetails>> SetLineBreakpoints(
25+
PowerShellContext powerShellContext,
26+
string scriptPath,
27+
BreakpointDetails[] breakpoints)
28+
{
29+
List<BreakpointDetails> resultBreakpointDetails =
30+
new List<BreakpointDetails>();
31+
32+
// We always get the latest array of breakpoint line numbers
33+
// so store that for future use
34+
if (breakpoints.Length > 0)
35+
{
36+
// Set the breakpoints for this scriptPath
37+
this.breakpointsPerFile[scriptPath] =
38+
breakpoints.Select(b => b.LineNumber).ToArray();
39+
}
40+
else
41+
{
42+
// No more breakpoints for this scriptPath, remove it
43+
this.breakpointsPerFile.Remove(scriptPath);
44+
}
45+
46+
string hashtableString =
47+
string.Join(
48+
", ",
49+
this.breakpointsPerFile
50+
.Select(file => $"@{{Path=\"{file.Key}\";Line=@({string.Join(",", file.Value)})}}"));
51+
52+
// Run Enable-DscDebug as a script because running it as a PSCommand
53+
// causes an error which states that the Breakpoints parameter has not
54+
// been passed.
55+
await powerShellContext.ExecuteScriptString(
56+
hashtableString.Length > 0
57+
? $"Enable-DscDebug -Breakpoints {hashtableString}"
58+
: "Disable-DscDebug",
59+
false,
60+
false);
61+
62+
// Verify all the breakpoints and return them
63+
foreach (var breakpoint in breakpoints)
64+
{
65+
breakpoint.Verified = true;
66+
}
67+
68+
return breakpoints.ToList();
69+
}
70+
71+
public bool IsDscResourcePath(string scriptPath)
72+
{
73+
return dscResourceRootPaths.Any(
74+
dscResourceRootPath =>
75+
scriptPath.StartsWith(
76+
dscResourceRootPath,
77+
StringComparison.CurrentCultureIgnoreCase));
78+
}
79+
80+
public static DscBreakpointCapability CheckForCapability(
81+
RunspaceDetails runspaceDetails,
82+
PowerShellContext powerShellContext)
83+
{
84+
DscBreakpointCapability capability = null;
85+
86+
if (runspaceDetails.Context != RunspaceContext.DebuggedRunspace)
87+
{
88+
using (PowerShell powerShell = PowerShell.Create())
89+
{
90+
powerShell.Runspace = runspaceDetails.Runspace;
91+
92+
// Attempt to import the updated DSC module
93+
powerShell.AddCommand("Import-Module");
94+
powerShell.AddArgument(@"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1");
95+
powerShell.AddParameter("PassThru");
96+
powerShell.AddParameter("ErrorAction", "SilentlyContinue");
97+
98+
PSObject moduleInfo = null;
99+
100+
try
101+
{
102+
moduleInfo = powerShell.Invoke().FirstOrDefault();
103+
}
104+
catch (CmdletInvocationException e)
105+
{
106+
Logger.WriteException("Could not load the DSC module!", e);
107+
}
108+
109+
if (moduleInfo != null)
110+
{
111+
Logger.Write(LogLevel.Verbose, "Side-by-side DSC module found, gathering DSC resource paths...");
112+
113+
// The module was loaded, add the breakpoint capability
114+
capability = new DscBreakpointCapability();
115+
runspaceDetails.AddCapability(capability);
116+
117+
powerShell.Commands.Clear();
118+
powerShell.AddScript("Write-Host \"Gathering DSC resource paths, this may take a while...\"");
119+
powerShell.Invoke();
120+
121+
// Get the list of DSC resource paths
122+
powerShell.Commands.Clear();
123+
powerShell.AddCommand("Get-DscResource");
124+
powerShell.AddCommand("Select-Object");
125+
powerShell.AddParameter("ExpandProperty", "ParentPath");
126+
127+
Collection<PSObject> resourcePaths = null;
128+
129+
try
130+
{
131+
resourcePaths = powerShell.Invoke();
132+
}
133+
catch (CmdletInvocationException e)
134+
{
135+
Logger.WriteException("Get-DscResource failed!", e);
136+
}
137+
138+
if (resourcePaths != null)
139+
{
140+
capability.dscResourceRootPaths =
141+
resourcePaths
142+
.Select(o => (string)o.BaseObject)
143+
.ToArray();
144+
145+
Logger.Write(LogLevel.Verbose, $"DSC resources found: {resourcePaths.Count}");
146+
}
147+
else
148+
{
149+
Logger.Write(LogLevel.Verbose, $"No DSC resources found.");
150+
}
151+
}
152+
else
153+
{
154+
Logger.Write(LogLevel.Verbose, $"Side-by-side DSC module was not found.");
155+
}
156+
}
157+
}
158+
159+
return capability;
160+
}
161+
}
162+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// Copyright (c) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace Microsoft.PowerShell.EditorServices.Session
7+
{
8+
internal interface IRunspaceCapability
9+
{
10+
// NOTE: This interface is intentionally empty for now.
11+
}
12+
}

0 commit comments

Comments
 (0)