| File: StreamForwarder.cs | Web Access |
| Project: src\sdk\src\Cli\Microsoft.DotNet.Cli.Utils\Microsoft.DotNet.Cli.Utils.csproj (Microsoft.DotNet.Cli.Utils) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. namespace Microsoft.DotNet.Cli.Utils; public sealed class StreamForwarder { private static readonly char[] s_ignoreCharacters = ['\r']; private static readonly char s_flushBuilderCharacter = '\n'; private StringBuilder? _builder; private StringWriter? _capture; private Action<string>? _writeLine; private bool _trimTrailingCapturedNewline; public string? CapturedOutput { get { var capture = _capture?.GetStringBuilder()?.ToString(); if (_trimTrailingCapturedNewline) { capture = capture?.TrimEnd('\r', '\n'); } return capture; } } public StreamForwarder Capture(bool trimTrailingNewline = false) { ThrowIfCaptureSet(); _capture = new StringWriter(); _trimTrailingCapturedNewline = trimTrailingNewline; return this; } public StreamForwarder ForwardTo(Action<string> writeLine) { ThrowIfNull(writeLine); ThrowIfForwarderSet(); _writeLine = writeLine; return this; } public Task BeginRead(TextReader reader) { return Task.Run(() => Read(reader)); } public void Read(TextReader reader) { var bufferSize = 1; int readCharacterCount; char currentCharacter; var buffer = new char[bufferSize]; _builder = new StringBuilder(); // Using Read with buffer size 1 to prevent looping endlessly // like we would when using Read() with no buffer while ((readCharacterCount = reader.Read(buffer, 0, bufferSize)) > 0) { currentCharacter = buffer[0]; if (currentCharacter == s_flushBuilderCharacter) { WriteBuilder(); } else if (!s_ignoreCharacters.Contains(currentCharacter)) { _builder.Append(currentCharacter); } } // Flush anything else when the stream is closed // Which should only happen if someone used console.Write if (_builder.Length > 0) { WriteBuilder(); } } private void WriteBuilder() { WriteLine(_builder?.ToString() ?? string.Empty); _builder?.Clear(); } private void WriteLine(string str) { if (_capture != null) { _capture.WriteLine(str); } _writeLine?.Invoke(str); } private void ThrowIfNull(object obj) { if (obj == null) { throw new ArgumentNullException(nameof(obj)); } } private void ThrowIfForwarderSet() { if (_writeLine != null) { throw new InvalidOperationException(LocalizableStrings.WriteLineForwarderSetPreviously); } } private void ThrowIfCaptureSet() { if (_capture != null) { throw new InvalidOperationException(LocalizableStrings.AlreadyCapturingStream); } } }