| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- using System.Diagnostics;
- using System.Diagnostics.CodeAnalysis;
- using System.Reflection;
- using System.Text.Json;
- using System.Text.RegularExpressions;
- namespace Terminal.Gui.Examples;
- /// <summary>
- /// Provides methods for running example applications in various execution modes.
- /// </summary>
- public static class ExampleRunner
- {
- /// <summary>
- /// Runs an example with the specified context.
- /// </summary>
- /// <param name="example">The example information.</param>
- /// <param name="context">The execution context.</param>
- /// <returns>The result of running the example.</returns>
- [RequiresUnreferencedCode ("Calls System.Reflection.Assembly.LoadFrom")]
- [RequiresDynamicCode ("Calls System.Reflection.Assembly.LoadFrom")]
- public static ExampleResult Run (ExampleInfo example, ExampleContext context)
- {
- return context.Mode == ExecutionMode.InProcess
- ? RunInProcess (example, context)
- : RunOutOfProcess (example, context);
- }
- private static ExampleMetrics? ExtractMetricsFromOutput (string output)
- {
- // Look for the metrics marker in the output
- Match match = Regex.Match (output, @"###TERMGUI_METRICS:(.+?)###");
- if (!match.Success)
- {
- return null;
- }
- try
- {
- return JsonSerializer.Deserialize<ExampleMetrics> (match.Groups [1].Value);
- }
- catch
- {
- return null;
- }
- }
- [RequiresUnreferencedCode ("Calls System.Reflection.Assembly.LoadFrom")]
- [RequiresDynamicCode ("Calls System.Reflection.Assembly.LoadFrom")]
- private static ExampleResult RunInProcess (ExampleInfo example, ExampleContext context)
- {
- Environment.SetEnvironmentVariable (
- ExampleContext.ENVIRONMENT_VARIABLE_NAME,
- context.ToJson ());
- try
- {
- Assembly asm = Assembly.LoadFrom (example.AssemblyPath);
- MethodInfo? entryPoint = asm.EntryPoint;
- if (entryPoint is null)
- {
- return new ()
- {
- Success = false,
- ErrorMessage = "Assembly does not have an entry point"
- };
- }
- ParameterInfo [] parameters = entryPoint.GetParameters ();
- object? result = null;
- if (parameters.Length == 0)
- {
- result = entryPoint.Invoke (null, null);
- }
- else if (parameters.Length == 1 && parameters [0].ParameterType == typeof (string []))
- {
- result = entryPoint.Invoke (null, [Array.Empty<string> ()]);
- }
- else
- {
- return new ()
- {
- Success = false,
- ErrorMessage = "Entry point has unsupported signature"
- };
- }
- // If entry point returns Task, wait for it
- if (result is Task task)
- {
- task.GetAwaiter ().GetResult ();
- }
- return new ()
- {
- Success = true
- };
- }
- catch (Exception ex)
- {
- return new ()
- {
- Success = false,
- ErrorMessage = ex.ToString ()
- };
- }
- finally
- {
- Environment.SetEnvironmentVariable (ExampleContext.ENVIRONMENT_VARIABLE_NAME, null);
- }
- }
- private static ExampleResult RunOutOfProcess (ExampleInfo example, ExampleContext context)
- {
- ProcessStartInfo psi = new ()
- {
- FileName = "dotnet",
- Arguments = $"\"{example.AssemblyPath}\"",
- UseShellExecute = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true
- };
- psi.Environment [ExampleContext.ENVIRONMENT_VARIABLE_NAME] = context.ToJson ();
- using Process? process = Process.Start (psi);
- if (process is null)
- {
- return new ()
- {
- Success = false,
- ErrorMessage = "Failed to start process"
- };
- }
- bool exited = process.WaitForExit (context.TimeoutMs);
- string stdout = process.StandardOutput.ReadToEnd ();
- string stderr = process.StandardError.ReadToEnd ();
- if (!exited)
- {
- try
- {
- const bool KILL_ENTIRE_PROCESS_TREE = true;
- process.Kill (KILL_ENTIRE_PROCESS_TREE);
- }
- catch
- {
- // Ignore errors killing the process
- }
- return new ()
- {
- Success = false,
- TimedOut = true,
- StandardOutput = stdout,
- StandardError = stderr
- };
- }
- ExampleMetrics? metrics = ExtractMetricsFromOutput (stdout);
- return new ()
- {
- Success = process.ExitCode == 0,
- ExitCode = process.ExitCode,
- StandardOutput = stdout,
- StandardError = stderr,
- Metrics = metrics
- };
- }
- }
|