TeamCity.CSharpInteractive/BuildRunner.cs (89 lines of code) (raw):
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedType.Global
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable StringLiteralTypo
// ReSharper disable InvertIf
// ReSharper disable UseDeconstructionOnParameter
namespace TeamCity.CSharpInteractive;
using System.Diagnostics;
using HostApi;
internal class BuildRunner : IBuildRunner
{
private readonly IProcessRunner _processRunner;
private readonly IHost _host;
private readonly ITeamCityContext _teamCityContext;
private readonly Func<IBuildContext> _buildContextFactory;
private readonly IBuildOutputProcessor _buildOutputProcessor;
private readonly Func<IProcessMonitor> _monitorFactory;
private readonly IBuildMessagesProcessor _defaultBuildMessagesProcessor;
private readonly IBuildMessagesProcessor _customBuildMessagesProcessor;
private readonly IProcessResultHandler _processResultHandler;
public BuildRunner(
IProcessRunner processRunner,
IHost host,
ITeamCityContext teamCityContext,
Func<IBuildContext> buildContextFactory,
IBuildOutputProcessor buildOutputProcessor,
Func<IProcessMonitor> monitorFactory,
[Tag("default")] IBuildMessagesProcessor defaultBuildMessagesProcessor,
[Tag("custom")] IBuildMessagesProcessor customBuildMessagesProcessor,
IProcessResultHandler processResultHandler)
{
_processRunner = processRunner;
_host = host;
_teamCityContext = teamCityContext;
_buildContextFactory = buildContextFactory;
_buildOutputProcessor = buildOutputProcessor;
_monitorFactory = monitorFactory;
_defaultBuildMessagesProcessor = defaultBuildMessagesProcessor;
_customBuildMessagesProcessor = customBuildMessagesProcessor;
_processResultHandler = processResultHandler;
}
public IBuildResult Run(ICommandLine commandLine, Action<BuildMessage>? handler = default, TimeSpan timeout = default)
{
var buildContext = _buildContextFactory();
commandLine.PreRun(_host);
var startInfo = CreateStartInfo(commandLine);
var processInfo = new ProcessInfo(startInfo, _monitorFactory(), output => Handle(handler, output, buildContext));
var result = _processRunner.Run(processInfo, timeout);
foreach (var serviceMessage in commandLine.GetNonStdStreamsServiceMessages(_host))
{
buildContext.ProcessMessage(result.StartInfo, result.ProcessId ?? Process.GetCurrentProcess().Id, serviceMessage);
}
_processResultHandler.Handle(result, handler);
return buildContext.Create(startInfo, result.ExitCode);
}
public async Task<IBuildResult> RunAsync(ICommandLine commandLine, Action<BuildMessage>? handler = default, CancellationToken cancellationToken = default)
{
var buildContext = _buildContextFactory();
commandLine.PreRun(_host);
var startInfo = CreateStartInfo(commandLine);
var processInfo = new ProcessInfo(startInfo, _monitorFactory(), output => Handle(handler, output, buildContext));
var result = await _processRunner.RunAsync(processInfo, cancellationToken);
foreach (var serviceMessage in commandLine.GetNonStdStreamsServiceMessages(_host))
{
buildContext.ProcessMessage(result.StartInfo, result.ProcessId ?? Process.GetCurrentProcess().Id, serviceMessage);
}
_processResultHandler.Handle(result, handler);
return buildContext.Create(startInfo, result.ExitCode);
}
private IStartInfo CreateStartInfo(ICommandLine commandLine)
{
try
{
_teamCityContext.TeamCityIntegration = true;
return commandLine.GetStartInfo(_host);
}
finally
{
_teamCityContext.TeamCityIntegration = false;
}
}
private void Handle(Action<BuildMessage>? handler, in Output output, IBuildContext buildContext)
{
var messages = _buildOutputProcessor.Convert(output, buildContext);
if (handler != default)
{
_customBuildMessagesProcessor.ProcessMessages(output, messages, handler);
}
else
{
_defaultBuildMessagesProcessor.ProcessMessages(output, messages, EmptyHandler);
}
}
private static void EmptyHandler(BuildMessage obj) { }
}