Skip to content

Commit 60cc61a

Browse files
authored
ensure lineout does not mix stderr and stdout (#8)
1 parent f9283ad commit 60cc61a

File tree

4 files changed

+56
-40
lines changed

4 files changed

+56
-40
lines changed

src/Proc/BufferedObservableProcess.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics;
23
using System.Reactive.Disposables;
34
using System.Reactive.Linq;
45
using System.Threading;
@@ -16,9 +17,7 @@ namespace ProcNet
1617
///
1718
/// This catches all cases where <see cref="EventBasedObservableProcess"/> would fall short to capture all the process output.
1819
///
19-
#pragma warning disable 1574
20-
/// <see cref="CharactersOut"/> contains the current char[] buffer which could be fed to <see cref="Console.Write"/> directly.
21-
#pragma warning restore 1574
20+
/// <see cref="CharactersOut"/> contains the current char[] buffer which could be fed to <see cref="Console.Write(string,object)"/> directly.
2221
///
2322
/// Note that there is a subclass <use cref="ObservableProcess"/> that allows you to subscribe console output per line
2423
/// instead whilst still reading the actual process output using asynchronous stream readers.
@@ -36,11 +35,11 @@ public BufferedObservableProcess(StartArguments startArguments) : base(startArgu
3635
private TimeSpan? WaitForStreamReadersTimeout => StartArguments.WaitForStreamReadersTimeout;
3736

3837
/// <summary>
39-
/// Expert level setting: the maximum number of characters to read per itteration. Defaults to 256
38+
/// Expert level setting: the maximum number of characters to read per iteration. Defaults to 1024
4039
/// </summary>
41-
public int BufferSize { get; set; } = 256;
40+
public int BufferSize { get; set; } = 1024;
4241

43-
private CancellationTokenSource _ctx = new CancellationTokenSource();
42+
private CancellationTokenSource _ctx = new();
4443
private Task _stdOutSubscription;
4544
private Task _stdErrSubscription;
4645
private IObserver<CharactersOut> _observer;

src/Proc/ObservableProcess.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Diagnostics;
34
using System.IO;
45
using System.Linq;
@@ -89,11 +90,25 @@ public IDisposable Subscribe(IObserver<LineOut> observerLines, IObserver<Charact
8990
.Where(o => o.EndsWithNewLine || o.StartsWithCarriage || BufferBoundary(_bufferStdOutRemainder, _bufferStdErrRemainder));
9091
var buffered = published.Buffer(boundaries);
9192
var newlines = buffered
92-
.Select(c =>
93+
.SelectMany(c =>
9394
{
94-
if (c.Count == 0) return null;
95-
var line = new string(c.SelectMany(o => o.Characters).ToArray());
96-
return new LineOut(c.First().Error, line.TrimEnd(NewlineChars));
95+
if (c == null || c.Count == 0)
96+
return Array.Empty<LineOut>();
97+
if (c.Count == 1)
98+
{
99+
var cOut = c.First();
100+
var chars = new string(cOut.Characters).TrimEnd(NewlineChars);
101+
return new[] { new LineOut(cOut.Error, chars) };
102+
}
103+
104+
return c
105+
.GroupBy(l => l.Error)
106+
.Select(g => (g.Key, new string(g.SelectMany(o => o.Characters).ToArray())))
107+
.SelectMany(kv =>
108+
kv.Item2.TrimEnd(NewlineChars).Split(NewlineChars)
109+
.Select(line => new LineOut(kv.Key, line.TrimEnd(NewlineChars)))
110+
)
111+
.ToArray();
97112
})
98113
.TakeWhile(KeepBufferingLines)
99114
.Where(l => l != null)

src/Proc/Proc.Start.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ public static ProcessCaptureResult Start(StartArguments arguments, TimeSpan time
9292
var consoleOut = new List<LineOut>();
9393
composite.Add(process);
9494
composite.Add(process.SubscribeLinesAndCharacters(
95-
consoleOut.Add,
95+
l =>
96+
{
97+
consoleOut.Add(l);
98+
},
9699
e => seenException = e,
97100
consoleOutWriter.Write,
98101
consoleOutWriter.Write
Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,43 @@
11
using System;
22

3-
namespace ProcNet.Std
3+
namespace ProcNet.Std;
4+
5+
public class ConsoleOutColorWriter : ConsoleOutWriter
46
{
5-
public class ConsoleOutColorWriter : ConsoleOutWriter
6-
{
7-
public static ConsoleOutColorWriter Default { get; } = new ConsoleOutColorWriter();
7+
public static ConsoleOutColorWriter Default { get; } = new();
88

9-
private readonly object _lock = new object();
10-
public override void Write(ConsoleOut consoleOut)
9+
private readonly object _lock = new();
10+
public override void Write(ConsoleOut consoleOut)
11+
{
12+
lock (_lock)
1113
{
12-
lock (_lock)
14+
Console.ResetColor();
15+
if (consoleOut.Error)
1316
{
14-
if (consoleOut.Error)
15-
{
16-
Console.ForegroundColor = ConsoleColor.Red;
17-
consoleOut.CharsOrString(ErrorCharacters, ErrorLine);
18-
}
19-
else
20-
{
21-
Console.ResetColor();
22-
consoleOut.CharsOrString(OutCharacters, OutLine);
23-
}
24-
Console.ResetColor();
17+
Console.ForegroundColor = ConsoleColor.Yellow;
18+
consoleOut.CharsOrString(ErrorCharacters, ErrorLine);
2519
}
20+
else
21+
consoleOut.CharsOrString(OutCharacters, OutLine);
22+
23+
Console.ResetColor();
2624
}
25+
}
2726

28-
public override void Write(Exception e)
27+
public override void Write(Exception e)
28+
{
29+
if (!(e is CleanExitExceptionBase ee)) throw e;
30+
lock (_lock)
2931
{
30-
if (!(e is CleanExitExceptionBase ee)) throw e;
31-
lock (_lock)
32+
Console.ResetColor();
33+
Console.ForegroundColor = ConsoleColor.Red;
34+
Console.Write(e.Message);
35+
if (!string.IsNullOrEmpty(ee.HelpText))
3236
{
33-
Console.ForegroundColor = ConsoleColor.Red;
34-
Console.Write(e.Message);
35-
if (!string.IsNullOrEmpty(ee.HelpText))
36-
{
37-
Console.ForegroundColor = ConsoleColor.DarkRed;
38-
Console.Write(ee.HelpText);
39-
}
40-
Console.ResetColor();
37+
Console.ForegroundColor = ConsoleColor.DarkRed;
38+
Console.Write(ee.HelpText);
4139
}
40+
Console.ResetColor();
4241
}
4342
}
4443
}

0 commit comments

Comments
 (0)