Fix for Linux remote script debugging hang (#2213)
* Fix for Linux remote debugging hang bug. * Removing dependency in PSReadLine on new engine helper API since it needs to be compatible with V3.
This commit is contained in:
parent
fd4552bfb8
commit
79ddafcc85
|
@ -881,6 +881,9 @@ namespace Microsoft.PowerShell
|
|||
_singleton.Render();
|
||||
}
|
||||
|
||||
private const string PromptCommand = "prompt";
|
||||
private const string DefaultPrompt = "PS>";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current prompt as possibly defined by the user through the
|
||||
/// prompt function, and returns a default prompt if no other is
|
||||
|
@ -888,23 +891,45 @@ namespace Microsoft.PowerShell
|
|||
/// </summary>
|
||||
public static string GetPrompt()
|
||||
{
|
||||
string newPrompt;
|
||||
var runspaceIsRemote = _singleton._mockableMethods.RunspaceIsRemote(_singleton._runspace);
|
||||
System.Management.Automation.PowerShell ps;
|
||||
if (!runspaceIsRemote)
|
||||
|
||||
if ((_singleton._runspace.Debugger != null) && _singleton._runspace.Debugger.InBreakpoint)
|
||||
{
|
||||
ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
// Run prompt command in debugger API to ensure it is run correctly on the runspace.
|
||||
// This handles remote runspace debugging and nested debugger scenarios.
|
||||
PSDataCollection<PSObject> results = new PSDataCollection<PSObject>();
|
||||
var command = new PSCommand();
|
||||
command.AddCommand(PromptCommand);
|
||||
_singleton._runspace.Debugger.ProcessCommand(
|
||||
command,
|
||||
results);
|
||||
|
||||
newPrompt = (results.Count == 1) ? (results[0].BaseObject as string) : DefaultPrompt;
|
||||
}
|
||||
else
|
||||
{
|
||||
ps = System.Management.Automation.PowerShell.Create();
|
||||
ps.Runspace = _singleton._runspace;
|
||||
System.Management.Automation.PowerShell ps;
|
||||
if (!runspaceIsRemote)
|
||||
{
|
||||
ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
}
|
||||
else
|
||||
{
|
||||
ps = System.Management.Automation.PowerShell.Create();
|
||||
ps.Runspace = _singleton._runspace;
|
||||
}
|
||||
using (ps)
|
||||
{
|
||||
ps.AddCommand(PromptCommand);
|
||||
var result = ps.Invoke<string>();
|
||||
newPrompt = result.Count == 1 ? result[0] : DefaultPrompt;
|
||||
}
|
||||
}
|
||||
string newPrompt;
|
||||
using (ps)
|
||||
|
||||
if (string.IsNullOrEmpty(newPrompt))
|
||||
{
|
||||
ps.AddCommand("prompt");
|
||||
var result = ps.Invoke<string>();
|
||||
newPrompt = result.Count == 1 ? result[0] : "PS>";
|
||||
newPrompt = DefaultPrompt;
|
||||
}
|
||||
|
||||
if (runspaceIsRemote)
|
||||
|
@ -915,6 +940,7 @@ namespace Microsoft.PowerShell
|
|||
newPrompt = string.Format(CultureInfo.InvariantCulture, "[{0}]: {1}", connectionInfo.ComputerName, newPrompt);
|
||||
}
|
||||
}
|
||||
|
||||
return newPrompt;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.PowerShell.Commands;
|
||||
using System.Management.Automation.Host;
|
||||
|
@ -863,6 +864,65 @@ namespace System.Management.Automation
|
|||
|
||||
#region Public Access
|
||||
|
||||
#region Runspace Invoke
|
||||
|
||||
/// <summary>
|
||||
/// Helper method to invoke a PSCommand on a given runspace. This method correctly invokes the command for
|
||||
/// these runspace cases:
|
||||
/// 1. Local runspace. If the local runspace is busy it will invoke as a nested command.
|
||||
/// 2. Remote runspace.
|
||||
/// 3. Runspace that is stopped in the debugger at a breakpoint.
|
||||
///
|
||||
/// Error and information streams are ignored and only the command result output is returned.
|
||||
///
|
||||
/// This method is NOT thread safe. It does not support running commands from different threads on the
|
||||
/// provided runspace. It assumes the thread invoking this method is the same that runs all other
|
||||
/// commands on the provided runspace.
|
||||
/// </summary>
|
||||
/// <param name="runspace">Runspace to invoke the command on</param>
|
||||
/// <param name="command">Command to invoke</param>
|
||||
/// <returns>Collection of command output result objects</returns>
|
||||
public static Collection<PSObject> InvokeOnRunspace(PSCommand command, Runspace runspace)
|
||||
{
|
||||
if (command == null)
|
||||
{
|
||||
throw new PSArgumentNullException("command");
|
||||
}
|
||||
|
||||
if (runspace == null)
|
||||
{
|
||||
throw new PSArgumentNullException("runspace");
|
||||
}
|
||||
|
||||
if ((runspace.Debugger != null) && runspace.Debugger.InBreakpoint)
|
||||
{
|
||||
// Use the Debugger API to run the command when a runspace is stopped in the debugger.
|
||||
PSDataCollection<PSObject> output = new PSDataCollection<PSObject>();
|
||||
runspace.Debugger.ProcessCommand(
|
||||
command,
|
||||
output);
|
||||
|
||||
return new Collection<PSObject>(output);
|
||||
}
|
||||
|
||||
// Otherwise run command directly in runspace.
|
||||
PowerShell ps = PowerShell.Create();
|
||||
ps.Runspace = runspace;
|
||||
ps.IsRunspaceOwner = false;
|
||||
if (runspace.ConnectionInfo == null)
|
||||
{
|
||||
// Local runspace. Make a nested PowerShell object as needed.
|
||||
ps.SetIsNested(runspace.GetCurrentlyRunningPipeline() != null);
|
||||
}
|
||||
using (ps)
|
||||
{
|
||||
ps.Commands = command;
|
||||
return ps.Invoke<PSObject>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PSEdit Support
|
||||
|
||||
/// <summary>
|
||||
|
@ -878,10 +938,10 @@ namespace System.Management.Automation
|
|||
dir $file -File | foreach {
|
||||
$filePathName = $_.FullName
|
||||
|
||||
# Get file contents
|
||||
# Get file contents
|
||||
$contentBytes = Get-Content -Path $filePathName -Raw -Encoding Byte
|
||||
|
||||
# Notify client for file open.
|
||||
# Notify client for file open.
|
||||
New-Event -SourceIdentifier PSISERemoteSessionOpenFile -EventArguments @($filePathName, $contentBytes) > $null
|
||||
}
|
||||
}
|
||||
|
|
70
test/powershell/Host/HostUtilities.Tests.ps1
Normal file
70
test/powershell/Host/HostUtilities.Tests.ps1
Normal file
|
@ -0,0 +1,70 @@
|
|||
Describe "InvokeOnRunspace method argument error handling" -tags "Feature" {
|
||||
|
||||
BeforeAll {
|
||||
$command = [System.Management.Automation.PSCommand]::new()
|
||||
$localRunspace = $host.Runspace
|
||||
}
|
||||
|
||||
It "Null argument exception should be thrown for null PSCommand argument" {
|
||||
|
||||
try
|
||||
{
|
||||
[System.Management.Automation.HostUtilities]::InvokeOnRunspace($null, $localRunspace)
|
||||
throw "InvokeOnRunspace method did not throw expected PSArgumentNullException exception"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.FullyQualifiedErrorId | Should Be "PSArgumentNullException"
|
||||
}
|
||||
}
|
||||
|
||||
It "Null argument exception should be thrown for null Runspace argument" {
|
||||
|
||||
try
|
||||
{
|
||||
[System.Management.Automation.HostUtilities]::InvokeOnRunspace($command, $null)
|
||||
throw "InvokeOnRunspace method did not throw expected PSArgumentNullException exception"
|
||||
}
|
||||
catch
|
||||
{
|
||||
$_.FullyQualifiedErrorId | Should Be "PSArgumentNullException"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "InvokeOnRunspace method as nested command" -tags "Feature" {
|
||||
|
||||
It "Method should successfully invoke command as nested on busy runspace" {
|
||||
|
||||
$command = [System.Management.Automation.PSCommand]::new()
|
||||
$command.AddScript('"Hello!"')
|
||||
$currentRunspace = $host.Runspace
|
||||
|
||||
$results = [System.Management.Automation.HostUtilities]::InvokeOnRunspace($command, $currentRunspace)
|
||||
|
||||
$results[0] | Should Be "Hello!"
|
||||
}
|
||||
}
|
||||
|
||||
Describe "InvokeOnRunspace method on remote runspace" -tags "Feature" {
|
||||
|
||||
BeforeAll {
|
||||
$wc = [System.Management.Automation.Runspaces.WSManConnectionInfo]::new()
|
||||
$remoteRunspace = [runspacefactory]::CreateRunspace($host, $wc)
|
||||
$remoteRunspace.Open()
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
$remoteRunspace.Dispose();
|
||||
}
|
||||
|
||||
It "Method should successfully invoke command on remote runspace" {
|
||||
|
||||
$command = [System.Management.Automation.PSCommand]::new()
|
||||
$command.AddScript('"Hello!"')
|
||||
|
||||
$results = [System.Management.Automation.HostUtilities]::InvokeOnRunspace($command, $remoteRunspace)
|
||||
|
||||
$results[0] | Should Be "Hello!"
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue