using System; using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Builder; using System.CommandLine.Invocation; using System.CommandLine.Parsing; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Hosting; using Serilog; #pragma warning disable Serilog004 // ReSharper disable TemplateIsNotCompileTimeConstantProblem // ReSharper disable SuspiciousTypeConversion.Global namespace MfGames.ToolBuilder { /// /// Implements the command-line shell for generating the static site. /// public class ToolService : IHostedService { private readonly IList commands; private readonly ConfigToolService configService; private readonly IHostApplicationLifetime lifetime; private readonly ILogger logger; private readonly LoggingToolService loggingService; public ToolService( ILogger logger, IHostApplicationLifetime lifetime, IList commands, ConfigToolService configService, LoggingToolService loggingService) { this.lifetime = lifetime; this.commands = commands; this.configService = configService; this.loggingService = loggingService; this.logger = logger.ForContext(); } /// public Task StartAsync(CancellationToken cancellationToken) { this.lifetime.ApplicationStarted .Register( () => { Task.Run( async () => await this.RunAsync().ConfigureAwait(false), cancellationToken); }); return Task.CompletedTask; } /// public Task StopAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } private RootCommand CreateRootCommand() { // Create the root command and add in the top-level commands // underneath it. var root = new RootCommand(); foreach (var command in this.commands) { root.AddCommand((Command)command); } // Add the universal options. this.loggingService.AddOptions(root); this.configService.AddOptions(root); // Return the resulting container. return root; } private void OnException(Exception exception, InvocationContext context) { if (exception is ToolException toolException) { this.logger.Fatal(toolException.Message); foreach (var message in toolException.Messages) { this.logger.Fatal(message); } Environment.ExitCode = toolException.ExitCode; } else { this.logger.Fatal( exception, "Unhandled exception!"); } } private async Task RunAsync() { try { // Build the command tree. RootCommand root = this.CreateRootCommand(); string[] args = Environment.GetCommandLineArgs(); // Execute the command. this.logger.Verbose( "Running the command-line arguments: {Arguments}", args); Environment.ExitCode = await new CommandLineBuilder(root) .UseDefaults() .UseExceptionHandler(this.OnException) .Build() .InvokeAsync(args) .ConfigureAwait(false); } finally { // Stop the application once the work is done. this.lifetime.StopApplication(); } } } }