Skip to content

Commit

Permalink
fix: Fixed deadlocks due to redirected outputs from child dotnet proc…
Browse files Browse the repository at this point in the history
…esses.
  • Loading branch information
hennadiilu authored Feb 2, 2024
1 parent 670485b commit d87a8ff
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 55 deletions.
36 changes: 9 additions & 27 deletions src/Heleonix.Build/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ namespace Heleonix.Build;
using System.Text;

/// <summary>
/// Thr entry class of the tool.
/// The entry class of the tool.
/// </summary>
/// <exclude/>
public static class Program
{
/// <summary>
Expand Down Expand Up @@ -82,42 +83,23 @@ public static int Main(string[] args)
{
process.StartInfo.FileName = dotnetExePath;
process.StartInfo.Arguments = $"msbuild \"{mainProjFile}\" -noLogo -t:Hx_Initialize {argsBuilder}";
process.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WorkingDirectory = Environment.CurrentDirectory;

process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;

process.OutputDataReceived += Process_OutputDataReceived;
process.ErrorDataReceived += Process_ErrorDataReceived;

process.Start();

process.BeginErrorReadLine();
process.BeginOutputReadLine();
var pout = new StreamPipe(process.StandardOutput, Console.Out);
var perr = new StreamPipe(process.StandardError, Console.Error);

pout.Connect();
perr.Connect();

process.WaitForExit();

return process.ExitCode;
}
}

private static void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Console.ForegroundColor = ConsoleColor.Red;

Console.Error.WriteLine(e.Data);

Console.Error.Flush();

Console.ResetColor();
}

private static void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.Out.WriteLine(e.Data);

Console.Out.Flush();
}
}
}
18 changes: 0 additions & 18 deletions src/Heleonix.Build/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 0 additions & 6 deletions src/Heleonix.Build/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,6 @@
<data name="TaskFailed" xml:space="preserve">
<value>Task failed: '{0}'.</value>
</data>
<data name="TaskFailedWithExitCode" xml:space="preserve">
<value>{0} failed. Exit code: {1}.</value>
</data>
<data name="FileCopy_FileNotFound" xml:space="preserve">
<value>The file to copy '{0}' not found.</value>
</data>
Expand Down Expand Up @@ -183,9 +180,6 @@
<data name="FileRazorGenerate_TemplateNotFound" xml:space="preserve">
<value>The template file '{0}' not found.</value>
</data>
<data name="FileUpdate_NumberOfRegExpsAndReplacementsMismatch" xml:space="preserve">
<value>Number of regular expressions {0} does not match number of replacements {1}.</value>
</data>
<data name="NetSetupTool_InstallationFailed" xml:space="preserve">
<value>Installation of the {0} tool, package {1}, version {2} failed with exit code {3}.</value>
</data>
Expand Down
54 changes: 54 additions & 0 deletions src/Heleonix.Build/StreamPipe.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// <copyright file="StreamPipe.cs" company="Heleonix - Hennadii Lutsyshyn">
// Copyright (c) Heleonix - Hennadii Lutsyshyn. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the repository root for full license information.
// </copyright>

namespace Heleonix.Build;

/// <summary>
/// The pipe to read redirected output.
/// </summary>
internal sealed class StreamPipe
{
private const int BufferSize = 2048;

private readonly TextReader source;

private readonly TextWriter destination;

/// <summary>
/// Initializes a new instance of the <see cref="StreamPipe"/> class.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
public StreamPipe(TextReader source, TextWriter destination)
{
this.source = source;
this.destination = destination;
}

/// <summary>
/// Connects the pipe.
/// </summary>
public void Connect()
{
System.Threading.Tasks.Task.Run(
async () =>
{
var buffer = new char[StreamPipe.BufferSize];
while (true)
{
var count = await this.source.ReadAsync(buffer, 0, BufferSize);
if (count <= 0)
{
break;
}
await this.destination.WriteAsync(buffer, 0, count);
await this.destination.FlushAsync();
}
});
}
}
2 changes: 1 addition & 1 deletion src/Heleonix.Build/Targets/Hx_NetTest.targets
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<Hx_NetTest_RunSettingsFile Condition="'$(Hx_NetTest_RunSettingsFile)' == ''">@(_Hx_NetTest_RunSettingsFile)</Hx_NetTest_RunSettingsFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Hx_NetTest_VerifyCoverage)' == 'true' and '$(Hx_NetTest_Collect)' == '' and '$(Hx_NetTest_RunSettingsFile)' == ''">
<Hx_NetTest_Collect>XPlat Code Coverage</Hx_NetTest_Collect>
<Hx_NetTest_Collect>XPlat Code Coverage;ExcludeByAttribute=Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute</Hx_NetTest_Collect>
</PropertyGroup>
<PropertyGroup>
<Hx_NetTest_SourcePathRegExpOptions Condition="'$(Hx_NetTest_SourcePathRegExpOptions)' == ''">MultiLine</Hx_NetTest_SourcePathRegExpOptions>
Expand Down
2 changes: 1 addition & 1 deletion src/Heleonix.Build/Tasks/BaseTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Heleonix.Build.Tasks;
/// <summary>
/// The <c>base</c> task.
/// </summary>
/// <seealso cref="Task" />
/// <exclude/>
public abstract class BaseTask : Task
{
/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions test/Heleonix.Build.Tests/ProgramTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static void MainTests()
{
args = new string[] { "--exe" };
Should("retun the error code: 1", () =>
Should("fail", () =>
{
Assert.That(returnValue, Is.EqualTo(1));
Assert.That(
Expand All @@ -99,7 +99,7 @@ public static void MainTests()
{
args = new string[] { "-p:Hx_WS_RepositoryUrl=https://example.com" };
Should("run the provided dotnet executable with passed command-line arguments", () =>
Should("run the default dotnet executable with passed command-line arguments", () =>
{
Assert.That(returnValue, Is.Zero);
Assert.That(outptut, Contains.Substring("https://example.com"));
Expand Down

0 comments on commit d87a8ff

Please sign in to comment.