Add #region's and minor cleanup

This commit is contained in:
Ladi Prosek 2023-03-31 16:30:14 +02:00
Родитель 24fc018a5b
Коммит b0542f37f6
2 изменённых файлов: 124 добавлений и 107 удалений

Просмотреть файл

@ -11,12 +11,12 @@ namespace Microsoft.Build.Logging.LiveLogger;
internal interface ITerminal : IDisposable
{
/// <summary>
/// Width of terminal buffer
/// Width of the terminal buffer.
/// </summary>
int Width { get; }
/// <summary>
/// Height of terminal buffer
/// Height of the terminal buffer.
/// </summary>
int Height { get; }

Просмотреть файл

@ -59,11 +59,6 @@ internal sealed class LiveLogger : INodeLogger
/// </summary>
private readonly CancellationTokenSource _cts = new();
/// <summary>
/// Tracks the work currently being done by build nodes. Null means the node is not doing any work worth reporting.
/// </summary>
private NodeStatus?[] _nodes = Array.Empty<NodeStatus>();
/// <summary>
/// Tracks the status of all relevant projects seen so far.
/// </summary>
@ -72,6 +67,11 @@ internal sealed class LiveLogger : INodeLogger
/// </remarks>
private readonly Dictionary<ProjectContext, Project> _projects = new();
/// <summary>
/// Tracks the work currently being done by build nodes. Null means the node is not doing any work worth reporting.
/// </summary>
private NodeStatus?[] _nodes = Array.Empty<NodeStatus>();
/// <summary>
/// The timestamp of the <see cref="IEventSource.BuildStarted"/> event.
/// </summary>
@ -108,12 +108,6 @@ internal sealed class LiveLogger : INodeLogger
/// </summary>
private ITerminal Terminal { get; }
/// <inheritdoc/>
public LoggerVerbosity Verbosity { get => LoggerVerbosity.Minimal; set { } }
/// <inheritdoc/>
public string Parameters { get => ""; set { } }
/// <summary>
/// List of events the logger needs as parameters to the <see cref="ConfigurableForwardingLogger"/>.
/// </summary>
@ -153,6 +147,14 @@ internal sealed class LiveLogger : INodeLogger
Terminal = terminal;
}
#region INodeLogger implementation
/// <inheritdoc/>
public LoggerVerbosity Verbosity { get => LoggerVerbosity.Minimal; set { } }
/// <inheritdoc/>
public string Parameters { get => ""; set { } }
/// <inheritdoc/>
public void Initialize(IEventSource eventSource, int nodeCount)
{
@ -177,24 +179,16 @@ internal sealed class LiveLogger : INodeLogger
eventSource.ErrorRaised += ErrorRaised;
}
/// <summary>
/// The <see cref="_refresher"/> thread proc.
/// </summary>
private void ThreadProc()
/// <inheritdoc/>
public void Shutdown()
{
while (!_cts.IsCancellationRequested)
{
Thread.Sleep(1_000 / 30); // poor approx of 30Hz
lock (_lock)
{
DisplayNodes();
}
}
EraseNodes();
Terminal.Dispose();
}
#endregion
#region Logger callbacks
/// <summary>
/// The <see cref="IEventSource.BuildStarted"/> callback.
/// </summary>
@ -266,35 +260,6 @@ internal sealed class LiveLogger : INodeLogger
}
}
/// <summary>
/// Print a build result summary to the output.
/// </summary>
/// <param name="succeeded">True if the build completed with success.</param>
/// <param name="hasError">True if the build has logged at least one error.</param>
/// <param name="hasWarning">True if the build has logged at least one warning.</param>
private void PrintBuildResult(bool succeeded, bool hasError, bool hasWarning)
{
if (!succeeded)
{
// If the build failed, we print one of three red strings.
string text = (hasError, hasWarning) switch
{
(true, _) => "failed with errors",
(false, true) => "failed with warnings",
_ => "failed",
};
Terminal.WriteColor(TerminalColor.Red, text);
}
else if (hasWarning)
{
Terminal.WriteColor(TerminalColor.Yellow, "succeeded with warnings");
}
else
{
Terminal.WriteColor(TerminalColor.Green, "succeeded");
}
}
/// <summary>
/// The <see cref="IEventSource.ProjectFinished"/> callback.
/// </summary>
@ -414,43 +379,6 @@ internal sealed class LiveLogger : INodeLogger
}
}
/// <summary>
/// Render Nodes section.
/// It shows what all build nodes do.
/// </summary>
private void DisplayNodes()
{
NodesFrame newFrame = new NodesFrame(_nodes, width: Terminal.Width, height: Terminal.Height);
// Do not render delta but clear everything is Terminal width or height have changed
if (newFrame.Width != _currentFrame.Width || newFrame.Height != _currentFrame.Height)
{
EraseNodes();
}
string rendered = newFrame.Render(_currentFrame);
// Move cursor back to 1st line of nodes
Terminal.WriteLine($"\x1b[{_currentFrame.NodesCount + 1}F");
Terminal.Write(rendered);
_currentFrame = newFrame;
}
/// <summary>
/// Erases the previously printed live node output.
/// </summary>
private void EraseNodes()
{
if (_currentFrame.NodesCount == 0)
{
return;
}
Terminal.WriteLine($"\x1b[{_currentFrame.NodesCount + 1}F");
Terminal.Write($"\x1b[0J");
_currentFrame.Clear();
}
/// <summary>
/// The <see cref="IEventSource.TargetStarted"/> callback.
/// </summary>
@ -470,15 +398,6 @@ internal sealed class LiveLogger : INodeLogger
}
}
/// <summary>
/// Returns the <see cref="_nodes"/> index corresponding to the given <see cref="BuildEventContext"/>.
/// </summary>
private int NodeIndexForContext(BuildEventContext context)
{
// Node IDs reported by the build are 1-based.
return context.NodeId - 1;
}
/// <summary>
/// The <see cref="IEventSource.TargetFinished"/> callback. Unused.
/// </summary>
@ -564,16 +483,69 @@ internal sealed class LiveLogger : INodeLogger
}
}
/// <inheritdoc/>
public void Shutdown()
#endregion
#region Refresher thread implementation
/// <summary>
/// The <see cref="_refresher"/> thread proc.
/// </summary>
private void ThreadProc()
{
Terminal.Dispose();
while (!_cts.IsCancellationRequested)
{
Thread.Sleep(1_000 / 30); // poor approx of 30Hz
lock (_lock)
{
DisplayNodes();
}
}
EraseNodes();
}
/// <summary>
/// Render Nodes section.
/// It shows what all build nodes do.
/// </summary>
private void DisplayNodes()
{
NodesFrame newFrame = new NodesFrame(_nodes, width: Terminal.Width, height: Terminal.Height);
// Do not render delta but clear everything is Terminal width or height have changed
if (newFrame.Width != _currentFrame.Width || newFrame.Height != _currentFrame.Height)
{
EraseNodes();
}
string rendered = newFrame.Render(_currentFrame);
// Move cursor back to 1st line of nodes
Terminal.WriteLine($"\x1b[{_currentFrame.NodesCount + 1}F");
Terminal.Write(rendered);
_currentFrame = newFrame;
}
/// <summary>
/// Erases the previously printed live node output.
/// </summary>
private void EraseNodes()
{
if (_currentFrame.NodesCount == 0)
{
return;
}
Terminal.WriteLine($"\x1b[{_currentFrame.NodesCount + 1}F");
Terminal.Write($"\x1b[0J");
_currentFrame.Clear();
}
/// <summary>
/// Capture states on nodes to be rendered on display.
/// </summary>
private class NodesFrame
private sealed class NodesFrame
{
private readonly List<string> _nodeStrings = new();
private readonly StringBuilder _renderBuilder = new();
@ -699,6 +671,51 @@ internal sealed class LiveLogger : INodeLogger
NodesCount = 0;
}
}
#endregion
#region Helpers
/// <summary>
/// Print a build result summary to the output.
/// </summary>
/// <param name="succeeded">True if the build completed with success.</param>
/// <param name="hasError">True if the build has logged at least one error.</param>
/// <param name="hasWarning">True if the build has logged at least one warning.</param>
private void PrintBuildResult(bool succeeded, bool hasError, bool hasWarning)
{
if (!succeeded)
{
// If the build failed, we print one of three red strings.
string text = (hasError, hasWarning) switch
{
(true, _) => "failed with errors",
(false, true) => "failed with warnings",
_ => "failed",
};
Terminal.WriteColor(TerminalColor.Red, text);
}
else if (hasWarning)
{
Terminal.WriteColor(TerminalColor.Yellow, "succeeded with warnings");
}
else
{
Terminal.WriteColor(TerminalColor.Green, "succeeded");
}
}
/// <summary>
/// Returns the <see cref="_nodes"/> index corresponding to the given <see cref="BuildEventContext"/>.
/// </summary>
private int NodeIndexForContext(BuildEventContext context)
{
// Node IDs reported by the build are 1-based.
return context.NodeId - 1;
}
#endregion
}
internal record ProjectContext(int Id)