Merge pull request #2336 from lzybkr/stdin_fixes

Fix some issues with `powershell -Command -`
This commit is contained in:
Dongbo Wang
2016-09-27 11:20:43 -07:00
committed by GitHub
5 changed files with 49 additions and 8 deletions
@@ -3467,6 +3467,9 @@ namespace Microsoft.PowerShell
[DllImport(PinvokeDllNames.GetLargestConsoleWindowSizeDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern COORD GetLargestConsoleWindowSize(NakedWin32Handle consoleOutput);
[DllImport(PinvokeDllNames.GetStdHandleDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr GetStdHandle(int handleId);
[DllImport(PinvokeDllNames.ReadConsoleDllName, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool ReadConsole
(
@@ -2868,6 +2868,25 @@ namespace Microsoft.PowerShell
private System.Threading.Thread _breakHandlerThread;
private bool _isDisposed;
internal ConsoleHostUserInterface ui;
#if CORECLR
internal Lazy<TextReader> ConsoleIn { get; } = new Lazy<TextReader>(() => Console.In);
#else
internal Lazy<TextReader> ConsoleIn { get; } = new Lazy<TextReader>(() =>
{
// This is a workaround for a full clr issue that causes a hang when calling PowerShell from ruby.
// They use named pipes instead of anonymous pipes, and for some reason that triggers a hang
// reading from Console.In.
var inputHandle = ConsoleControl.NativeMethods.GetStdHandle(-10);
var s = new FileStream(new ConsoleHandle(inputHandle, false), FileAccess.Read);
uint codePage = (uint) ConsoleControl.NativeMethods.GetConsoleCP();
Encoding encoding = Encoding.GetEncoding((int) codePage);
return TextReader.Synchronized(new StreamReader(s, encoding, false));
});
#endif
private string _savedWindowTitle = "";
private Version _ver = PSVersionInfo.PSVersion;
private int _exitCodeFromRunspace;
@@ -1554,19 +1554,22 @@ namespace Microsoft.PowerShell
private string ReadLineFromFile(string initialContent)
{
var sb = new StringBuilder();
if (initialContent != null)
if (!string.IsNullOrEmpty(initialContent))
{
sb.Append(initialContent);
sb.Append('\n');
}
var consoleIn = _parent.ConsoleIn.Value;
while (true)
{
var inC = Console.In.Read();
var inC = consoleIn.Read();
if (inC == -1)
{
// EOF - we return null which tells our caller to exit
return null;
// but only if we don't have any input, we could have
// input and then stdin was closed, but never saw a newline.
return sb.Length == 0 ? null : sb.ToString();
}
var c = unchecked((char)inC);
@@ -1575,10 +1578,10 @@ namespace Microsoft.PowerShell
if (c == '\r')
{
// Treat as newline, but consume \n if there is one.
if (Console.In.Peek() == '\n')
if (consoleIn.Peek() == '\n')
{
if (!NoPrompt) Console.Out.Write('\n');
Console.In.Read();
consoleIn.Read();
}
break;
}
@@ -1588,7 +1591,9 @@ namespace Microsoft.PowerShell
break;
}
if (c == '\b')
// If NoPrompt is true, we are in a sort of server mode where we shouldn't
// do anything like edit the command line - every character is part of the input.
if (c == '\b' && !NoPrompt)
{
sb.Remove(sb.Length - 1, 1);
}
@@ -212,8 +212,7 @@ namespace Microsoft.PowerShell
if ((options & ExecutionOptions.ReadInputObjects) > 0 && Console.IsInputRedirected)
{
// read input objects from stdin
WrappedDeserializer des = new WrappedDeserializer(_parent.InputFormat, "Input", Console.In);
WrappedDeserializer des = new WrappedDeserializer(_parent.InputFormat, "Input", _parent.ConsoleIn.Value);
while (!des.AtEnd)
{
object o = des.Deserialize();
@@ -227,6 +227,12 @@ Describe "ConsoleHost unit tests" -tags "Feature" {
$process.StandardInput.Write("1+2`n")
$process.StandardOutput.ReadLine() | Should Be "PS> 1+2"
$process.StandardOutput.ReadLine() | Should Be "3"
# Backspace should work as expected
$process.StandardInput.Write("1+2`b3`n")
# A real console should render 2`b3 as just 3, but we're just capturing exactly what is written
$process.StandardOutput.ReadLine() | Should Be "PS> 1+2`b3"
$process.StandardOutput.ReadLine() | Should Be "4"
$process.StandardInput.Close()
$process.StandardOutput.ReadToEnd() | Should Be "PS> "
EnsureChildHasExited $process
@@ -279,7 +285,16 @@ foo
"@)
$process.StandardOutput.ReadLine() | Should Be "in foo"
# Backspace sent through stdin should be in the final string
$process.StandardInput.Write("`"a`bc`".Length`n")
$process.StandardOutput.ReadLine() | Should Be "3"
# Last command with no newline - should be accepted and
# produce output after closing stdin.
$process.StandardInput.Write('22 + 22')
$process.StandardInput.Close()
$process.StandardOutput.ReadLine() | Should Be "44"
EnsureChildHasExited $process
}