152 lines
4.9 KiB
C#
152 lines
4.9 KiB
C#
|
using System;
|
||
|
using System.IO;
|
||
|
using System.Threading.Tasks;
|
||
|
|
||
|
using Autofac;
|
||
|
using Autofac.Extensions.DependencyInjection;
|
||
|
|
||
|
using Microsoft.Extensions.Configuration;
|
||
|
using Microsoft.Extensions.DependencyInjection;
|
||
|
using Microsoft.Extensions.Hosting;
|
||
|
|
||
|
using Serilog;
|
||
|
|
||
|
namespace MfGames.ToolBuilder
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// A builder pattern for creating the tool. This wraps much of the hosting
|
||
|
/// infrastructure with some opinionated decisions and reduces the amount of
|
||
|
/// boilerplate needed to configure the tool.
|
||
|
/// </summary>
|
||
|
public class ToolBuilder
|
||
|
{
|
||
|
private readonly string[] arguments;
|
||
|
|
||
|
private readonly ConfigToolService configService;
|
||
|
|
||
|
private readonly IHostBuilder hostBuilder;
|
||
|
|
||
|
private readonly LoggingToolService loggingService;
|
||
|
|
||
|
public ToolBuilder(
|
||
|
string applicationName,
|
||
|
string internalName,
|
||
|
string[] arguments)
|
||
|
{
|
||
|
// Create our various services.
|
||
|
this.arguments = arguments;
|
||
|
this.ApplicationName = applicationName;
|
||
|
this.InternalName = internalName;
|
||
|
this.configService = new ConfigToolService()
|
||
|
.WithInternalName(this.InternalName);
|
||
|
this.loggingService = new LoggingToolService();
|
||
|
|
||
|
// Set up logging first so we can report the loading process. This
|
||
|
// sets up the Serilog.Log.Logger which means we can use that for
|
||
|
// everything beyond this point.
|
||
|
this.loggingService.Configure(arguments);
|
||
|
|
||
|
// Start up the basic configuration.
|
||
|
this.hostBuilder = Host
|
||
|
.CreateDefaultBuilder(arguments)
|
||
|
.UseConsoleLifetime()
|
||
|
.ConfigureAppConfiguration(this.ConfigureAppConfiguration)
|
||
|
.UseSerilog()
|
||
|
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||
|
.ConfigureServices(this.ConfigureServices)
|
||
|
.ConfigureContainer<ContainerBuilder>(this.ConfigureContainer);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the human-readable name of the application.
|
||
|
/// </summary>
|
||
|
public string ApplicationName { get; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the internal name of the application.
|
||
|
/// </summary>
|
||
|
public string InternalName { get; }
|
||
|
|
||
|
public static ToolBuilder Create(
|
||
|
string applicationName,
|
||
|
string internalName,
|
||
|
string[] arguments)
|
||
|
{
|
||
|
return new ToolBuilder(applicationName, internalName, arguments);
|
||
|
}
|
||
|
|
||
|
public ToolBuilder ConfigureContainer(
|
||
|
Action<ContainerBuilder> configure)
|
||
|
{
|
||
|
this.hostBuilder.ConfigureContainer(configure);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
public ToolBuilder ConfigureServices(
|
||
|
Action<IServiceCollection> configure)
|
||
|
{
|
||
|
this.hostBuilder.ConfigureServices(configure);
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Finishes building the tool, parses the arguments, and runs the
|
||
|
/// command.
|
||
|
/// </summary>
|
||
|
/// <returns>An error code, 0 for successful, otherwise false.</returns>
|
||
|
public async Task<int> RunAsync()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
await this.hostBuilder
|
||
|
.RunConsoleAsync()
|
||
|
.ConfigureAwait(false);
|
||
|
}
|
||
|
catch (Exception exception)
|
||
|
{
|
||
|
Log.Fatal(
|
||
|
exception,
|
||
|
"There was a problem running the command: {Arguments}",
|
||
|
this.arguments);
|
||
|
|
||
|
return Environment.ExitCode == 0 ? 1 : Environment.ExitCode;
|
||
|
}
|
||
|
|
||
|
// Get the exit code and return it.
|
||
|
return Environment.ExitCode;
|
||
|
}
|
||
|
|
||
|
private void ConfigureAppConfiguration(
|
||
|
HostBuilderContext context,
|
||
|
IConfigurationBuilder builder)
|
||
|
{
|
||
|
builder.SetBasePath(Directory.GetCurrentDirectory());
|
||
|
this.configService.Configure(builder, this.arguments);
|
||
|
}
|
||
|
|
||
|
private void ConfigureContainer(
|
||
|
HostBuilderContext context,
|
||
|
ContainerBuilder builder)
|
||
|
{
|
||
|
// We want to get logging up and running as soon as possible. We
|
||
|
// also hook up the logging to the process exit in an attempt to
|
||
|
// make sure the logger is properly flushed before exiting.
|
||
|
builder.RegisterInstance(Log.Logger).As<ILogger>().SingleInstance();
|
||
|
|
||
|
AppDomain.CurrentDomain.ProcessExit +=
|
||
|
(_, _) => Log.CloseAndFlush();
|
||
|
|
||
|
// Register the components required to make the CLI work.
|
||
|
builder.RegisterModule<ToolBuilderModule>();
|
||
|
}
|
||
|
|
||
|
private void ConfigureServices(
|
||
|
HostBuilderContext context,
|
||
|
IServiceCollection services)
|
||
|
{
|
||
|
services.AddAutofac();
|
||
|
services.AddHostedService<ToolService>();
|
||
|
}
|
||
|
}
|
||
|
}
|