Make sure both stdout and stderr can be redirected from a native executable (#20997) (#23911)

This commit is contained in:
Aditya Patwardhan
2024-06-11 10:03:26 -07:00
committed by GitHub
parent 81ebe1ef59
commit 3ce794d1e4
3 changed files with 44 additions and 30 deletions
@@ -815,12 +815,6 @@ namespace System.Management.Automation
{
if (blocking)
{
if (_stdOutByteTransfer is not null)
{
_stdOutByteTransfer.EOF.GetAwaiter().GetResult();
return null;
}
// If adding was completed and collection is empty (IsCompleted == true)
// there is no need to do a blocking Take(), we should just return.
if (!_nativeProcessOutputQueue.IsCompleted)
@@ -842,17 +836,9 @@ namespace System.Management.Automation
return null;
}
else
{
if (_stdOutByteTransfer is not null)
{
return null;
}
ProcessOutputObject record = null;
_nativeProcessOutputQueue.TryTake(out record);
return record;
}
_nativeProcessOutputQueue.TryTake(out ProcessOutputObject record);
return record;
}
/// <summary>
@@ -860,21 +846,38 @@ namespace System.Management.Automation
/// </summary>
private void ConsumeAvailableNativeProcessOutput(bool blocking)
{
if (!_isRunningInBackground)
if (_isRunningInBackground)
{
if (_nativeProcess.StartInfo.RedirectStandardOutput || _nativeProcess.StartInfo.RedirectStandardError)
{
ProcessOutputObject record;
while ((record = DequeueProcessOutput(blocking)) != null)
{
if (this.Command.Context.CurrentPipelineStopping)
{
this.StopProcessing();
return;
}
return;
}
ProcessOutputRecord(record);
bool stdOutRedirected = _nativeProcess.StartInfo.RedirectStandardOutput;
bool stdErrRedirected = _nativeProcess.StartInfo.RedirectStandardError;
if (stdOutRedirected && _stdOutByteTransfer is not null)
{
if (blocking)
{
_stdOutByteTransfer.EOF.GetAwaiter().GetResult();
}
if (!stdErrRedirected)
{
return;
}
}
if (stdOutRedirected || stdErrRedirected)
{
ProcessOutputObject record;
while ((record = DequeueProcessOutput(blocking)) != null)
{
if (this.Command.Context.CurrentPipelineStopping)
{
this.StopProcessing();
return;
}
ProcessOutputRecord(record);
}
}
}
@@ -887,7 +890,7 @@ namespace System.Management.Automation
if (!_isRunningInBackground)
{
// Wait for input writer to finish.
if (!UpstreamIsNativeCommand)
if (!UpstreamIsNativeCommand || _nativeProcess.StartInfo.RedirectStandardError)
{
_inputWriter.Done();
}
@@ -1772,7 +1775,7 @@ namespace System.Management.Automation
// we incrementing refCount on the same thread and before running any processing
// so it's safe to do it without Interlocked.
if (process.StartInfo.RedirectStandardOutput)
if (process.StartInfo.RedirectStandardOutput && stdOutDestination is null)
{
_refCount++;
}
@@ -213,6 +213,12 @@ Describe "Native Command Processor" -tags "Feature" {
Wait-UntilTrue -sb { (Get-Process mmc).Count -gt 0 } -TimeoutInMilliseconds 5000 -IntervalInMilliseconds 1000 | Should -BeTrue
Get-Process mmc | Stop-Process
}
It 'Can redirect stdout and stderr to different files' {
testexe -stderrandout testing > $TestDrive/stdout.txt 2> $TestDrive/stderr.txt
Get-Content $TestDrive/stdout.txt | Should -Be testing
Get-Content $TestDrive/stderr.txt | Should -Be gnitset
}
}
Describe "Open a text file with NativeCommandProcessor" -tags @("Feature", "RequireAdminOnWindows") {
+5
View File
@@ -8,6 +8,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.IO;
using System.Globalization;
using System.Linq;
namespace TestExe
{
@@ -36,6 +37,10 @@ namespace TestExe
case "-stderr":
Console.Error.WriteLine(args[1]);
break;
case "-stderrandout":
Console.WriteLine(args[1]);
Console.Error.WriteLine(new string(args[1].ToCharArray().Reverse().ToArray()));
break;
case "-readbytes":
ReadBytes();
break;