56 lines
1.9 KiB
C#
56 lines
1.9 KiB
C#
|
|
using System.Diagnostics;
|
||
|
|
|
||
|
|
namespace w4c_workflows.Services.Execution;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Runs a language whose program is a single file executed by an interpreter
|
||
|
|
/// (shell → sh, python → python3, javascript → node). Input is written to stdin
|
||
|
|
/// as JSON; output follows the <see cref="ExecutionHelpers"/> stdout contract.
|
||
|
|
/// </summary>
|
||
|
|
public class SubprocessScriptExecutor : IScriptExecutor
|
||
|
|
{
|
||
|
|
private readonly string _language;
|
||
|
|
private readonly string _executable;
|
||
|
|
private readonly TimeSpan _timeout;
|
||
|
|
|
||
|
|
public SubprocessScriptExecutor(string language, string executable, IConfiguration config)
|
||
|
|
{
|
||
|
|
_language = language;
|
||
|
|
_executable = executable;
|
||
|
|
_timeout = TimeSpan.FromSeconds(ParseInt(config["Workflows:TaskTimeoutSeconds"], 60));
|
||
|
|
}
|
||
|
|
|
||
|
|
public string Language => _language;
|
||
|
|
|
||
|
|
public bool IsAvailable() => ProcessRunner.FindInPath(_executable) != null;
|
||
|
|
|
||
|
|
public async Task<ExecutionResult> ExecuteAsync(TaskInvocation invocation, CancellationToken ct)
|
||
|
|
{
|
||
|
|
var sw = Stopwatch.StartNew();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
var workingDir = ExecutionHelpers.ResolveWorkingDir(invocation);
|
||
|
|
var entryPath = Path.Combine(workingDir, invocation.EntryFile);
|
||
|
|
|
||
|
|
var output = await ProcessRunner.RunAsync(
|
||
|
|
_executable,
|
||
|
|
new[] { entryPath },
|
||
|
|
workingDir,
|
||
|
|
ExecutionHelpers.BuildEnvironment(invocation),
|
||
|
|
invocation.Input,
|
||
|
|
_timeout,
|
||
|
|
ct);
|
||
|
|
|
||
|
|
return ExecutionHelpers.ToResult(output, sw.Elapsed);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
sw.Stop();
|
||
|
|
return new ExecutionResult(false, -1, string.Empty, string.Empty, null, ex.Message, sw.Elapsed);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private static int ParseInt(string? text, int fallback)
|
||
|
|
=> int.TryParse(text, out var value) && value > 0 ? value : fallback;
|
||
|
|
}
|