Skip to content

Improve detection of session changes when debugging ScriptBlocks #371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PowerShellEditorServices.build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ if ($PSVersionTable.PSEdition -ne "Core") {
task SetupDotNet -Before Restore, Clean, Build, BuildHost, Test, TestPowerShellApi, PackageNuGet {

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

$needsInstall = $true
$dotnetPath = "$PSScriptRoot/.dotnet"
Expand Down
162 changes: 89 additions & 73 deletions src/PowerShellEditorServices/Debugging/DebugService.cs

Large diffs are not rendered by default.

5 changes: 1 addition & 4 deletions src/PowerShellEditorServices/PowerShellEditorServices.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@
</PropertyGroup>

<Target Name="PowerShellVersionOutput" BeforeTargets="Compile">
<Message
Condition=" '$(TargetFramework)' == 'net451' And '$(PowerShellVersion)' != '' "
Text="Target PowerShell Version: $(PowerShellVersion) -- Constants: $(DefineConstants)"
Importance="High" />
<Message Condition=" '$(TargetFramework)' == 'net451' And '$(PowerShellVersion)' != '' " Text="Target PowerShell Version: $(PowerShellVersion) -- Constants: $(DefineConstants)" Importance="High" />
</Target>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' And '$(PowerShellVersion)' == 'v3' ">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

using System.Linq;
using System.Threading.Tasks;

namespace Microsoft.PowerShell.EditorServices.Session.Capabilities
{
using Microsoft.PowerShell.EditorServices.Utility;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;

internal class DscBreakpointCapability : IRunspaceCapability
{
private string[] dscResourceRootPaths = new string[0];

private Dictionary<string, int[]> breakpointsPerFile =
new Dictionary<string, int[]>();

public async Task<List<BreakpointDetails>> SetLineBreakpoints(
PowerShellContext 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 Breakpoints parameter has not
// been passed.
await powerShellContext.ExecuteScriptString(
hashtableString.Length > 0
? $"Enable-DscDebug -Breakpoints {hashtableString}"
: "Disable-DscDebug",
false,
false);

// Verify all the breakpoints and return them
foreach (var breakpoint in breakpoints)
{
breakpoint.Verified = true;
}

return breakpoints.ToList();
}

public bool IsDscResourcePath(string scriptPath)
{
return dscResourceRootPaths.Any(
dscResourceRootPath =>
scriptPath.StartsWith(
dscResourceRootPath,
StringComparison.CurrentCultureIgnoreCase));
}

public static DscBreakpointCapability CheckForCapability(
RunspaceDetails runspaceDetails,
PowerShellContext powerShellContext)
{
DscBreakpointCapability capability = null;

if (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", "SilentlyContinue");

PSObject moduleInfo = null;

try
{
moduleInfo = powerShell.Invoke().FirstOrDefault();
}
catch (CmdletInvocationException e)
{
Logger.WriteException("Could not load the DSC module!", e);
}

if (moduleInfo != null)
{
Logger.Write(LogLevel.Verbose, "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.AddScript("Write-Host \"Gathering DSC resource paths, this may take a while...\"");
powerShell.Invoke();

// Get the list of DSC resource paths
powerShell.Commands.Clear();
powerShell.AddCommand("Get-DscResource");
powerShell.AddCommand("Select-Object");
powerShell.AddParameter("ExpandProperty", "ParentPath");

Collection<PSObject> resourcePaths = null;

try
{
resourcePaths = powerShell.Invoke();
}
catch (CmdletInvocationException e)
{
Logger.WriteException("Get-DscResource failed!", e);
}

if (resourcePaths != null)
{
capability.dscResourceRootPaths =
resourcePaths
.Select(o => (string)o.BaseObject)
.ToArray();

Logger.Write(LogLevel.Verbose, $"DSC resources found: {resourcePaths.Count}");
}
else
{
Logger.Write(LogLevel.Verbose, $"No DSC resources found.");
}
}
else
{
Logger.Write(LogLevel.Verbose, $"Side-by-side DSC module was not found.");
}
}
}

return capability;
}
}
}
12 changes: 12 additions & 0 deletions src/PowerShellEditorServices/Session/IRunspaceCapability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

namespace Microsoft.PowerShell.EditorServices.Session
{
internal interface IRunspaceCapability
{
// NOTE: This interface is intentionally empty for now.
}
}
Loading