diff --git a/Documentation/developer-guide.md b/Documentation/developer-guide.md index b54710319..55f0c40b1 100644 --- a/Documentation/developer-guide.md +++ b/Documentation/developer-guide.md @@ -65,3 +65,6 @@ Each command's project root should contain a manpage-style Readme.md that descri #### Add command to packages - Update the `symlinks` property of `packaging/debian/debian_config.json` to include the new command - Update the `$Projects` property in `packaging/osx/scripts/postinstall` + +#### Things to Know +- Any added commands are usually invoked through `dotnet {command}`. As a result of this, stdout and stderr are redirected through the driver (`dotnet`) and buffered by line. As a result of this, child commands should use Console.WriteLine in any cases where they expect output to be written immediately. Any uses of Console.Write should be followed by Console.WriteLine to ensure the output is written. \ No newline at end of file diff --git a/src/Microsoft.DotNet.Cli.Utils/StreamForwarder.cs b/src/Microsoft.DotNet.Cli.Utils/StreamForwarder.cs index 4927426d1..0a4c70518 100644 --- a/src/Microsoft.DotNet.Cli.Utils/StreamForwarder.cs +++ b/src/Microsoft.DotNet.Cli.Utils/StreamForwarder.cs @@ -2,11 +2,15 @@ using System; using System.IO; using System.Text; using System.Threading; +using System.Linq; namespace Microsoft.DotNet.Cli.Utils { public sealed class StreamForwarder { + private static readonly char[] s_ignoreCharacters = new char[] { '\r' }; + private static readonly char s_flushBuilderCharacter = '\n'; + private StringBuilder _builder; private StringWriter _capture; private Action _write; @@ -22,10 +26,8 @@ namespace Microsoft.DotNet.Cli.Utils public StreamForwarder Capture() { - if (_capture != null) - { - throw new InvalidOperationException("Already capturing stream!"); - } + ThrowIfCaptureSet(); + _capture = new StringWriter(); return this; @@ -33,15 +35,9 @@ namespace Microsoft.DotNet.Cli.Utils public StreamForwarder ForwardTo(Action writeLine) { - if (writeLine == null) - { - throw new ArgumentNullException(nameof(writeLine)); - } + ThrowIfNull(writeLine); - if (_writeLine != null) - { - throw new InvalidOperationException("WriteLine forwarder set previously"); - } + ThrowIfForwarderSet(); _writeLine = writeLine; @@ -71,18 +67,13 @@ namespace Microsoft.DotNet.Cli.Utils { currentCharacter = buffer[0]; - // Flush per line - if (currentCharacter == '\n') + if (currentCharacter == s_flushBuilderCharacter) { WriteBuilder(); } - else + else if (! s_ignoreCharacters.Contains(currentCharacter)) { - // Ignore \r - if (currentCharacter != '\r') - { - _builder.Append(currentCharacter); - } + _builder.Append(currentCharacter); } } @@ -114,5 +105,29 @@ namespace Microsoft.DotNet.Cli.Utils _writeLine(str); } } + + private void ThrowIfNull(object obj) + { + if (obj == null) + { + throw new ArgumentNullException(nameof(obj)); + } + } + + private void ThrowIfForwarderSet() + { + if (_writeLine != null) + { + throw new InvalidOperationException("WriteLine forwarder set previously"); + } + } + + private void ThrowIfCaptureSet() + { + if (_capture != null) + { + throw new InvalidOperationException("Already capturing stream!"); + } + } } } \ No newline at end of file diff --git a/test/ArgumentForwardingTests/ArgumentForwardingTests/ArgumentForwardingTests.cs b/test/ArgumentForwardingTests/ArgumentForwardingTests/ArgumentForwardingTests.cs index 2a0794d1f..adde47bf9 100644 --- a/test/ArgumentForwardingTests/ArgumentForwardingTests/ArgumentForwardingTests.cs +++ b/test/ArgumentForwardingTests/ArgumentForwardingTests/ArgumentForwardingTests.cs @@ -206,7 +206,7 @@ namespace Microsoft.DotNet.Tests.ArgumentForwarding /// private string[] ParseReflectorOutput(string reflectorOutput) { - return reflectorOutput.Split(','); + return reflectorOutput.TrimEnd('\r', '\n').Split(','); } ///