This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
mfgames-nitride-cil/src/MfGames.Nitride/NitrideBuilder.cs
D. Moonfire 9e93eb6ce6 refactor!: fixed missed namespaces
- reformatted code and cleaned up references
2023-01-14 18:19:42 -06:00

217 lines
6.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Autofac;
using MfGames.ToolBuilder;
using Serilog;
using Zio;
using Zio.FileSystems;
using Module = Autofac.Module;
namespace MfGames.Nitride;
/// <summary>
/// A class that implements a builder pattern for gathering all the
/// components of a static website. Once everything is build, then calling
/// `Build()` will generate the resulting website.
/// </summary>
public class NitrideBuilder
{
private readonly string[] arguments;
private readonly List<Action<ContainerBuilder>> configureContainerCallbacks;
/// <summary>
/// An event that is called after the container is built but before
/// the application runs.
/// </summary>
private readonly List<Action<NitrideBuilder, ILifetimeScope>>
configureSiteCallbacks;
private readonly NitrideModule nitrideModule;
public NitrideBuilder(string[] arguments)
{
this.arguments = arguments;
this.configureSiteCallbacks =
new List<Action<NitrideBuilder, ILifetimeScope>>();
this.configureContainerCallbacks = new List<Action<ContainerBuilder>>();
this.nitrideModule = new NitrideModule();
this.nitrideModule.ApplicationName = Assembly.GetExecutingAssembly()
.GetName()
.Name!;
}
/// <summary>
/// Gets or sets the input directory to automatically register as the
/// source of the files. If this is not set, then no Zio.IFileSystem
/// will be registered and it will have to be done manually.
/// </summary>
public DirectoryInfo? RootDirectory { get; set; }
/// <summary>
/// Allows for configuration of the Autofac container to register
/// additional types, pipelines, and modules.
/// </summary>
/// <param name="callback">The callback to configure the container.</param>
/// <returns>The builder to chain operations.</returns>
public NitrideBuilder ConfigureContainer(Action<ContainerBuilder> callback)
{
this.configureContainerCallbacks.Add(callback);
return this;
}
/// <summary>
/// Registers a callback to be called after the container is built but
/// before the application runs.
/// </summary>
/// <param name="callback">The callback to register.</param>
/// <returns>The builder for chaining.</returns>
public NitrideBuilder ConfigureSite(
Action<NitrideBuilder, ILifetimeScope> callback)
{
this.configureSiteCallbacks.Add(callback);
return this;
}
/// <summary>
/// Generates or builds the resulting website based on the given
/// command.
/// </summary>
/// <returns>The task once completed.</returns>
public async Task<int> RunAsync()
{
if (this.nitrideModule.ApplicationName == null)
{
throw new InvalidOperationException(
"Application name must be set, such as with the NitrideBuilder.WithApplicationName() to properly run.");
}
return await ToolBoxBuilder
.Create(this.nitrideModule.ApplicationName, this.arguments)
.ConfigureContainer(this.ConfigureContainer)
.Build()
.RunAsync();
}
/// <summary>
/// Initialize the builder with a given Autofac module.
/// </summary>
/// <typeparam name="TModule">The type of module to use.</typeparam>
/// <returns>The builder to chain operations.</returns>
public NitrideBuilder UseModule<TModule>()
where TModule : Module, new()
{
this.ConfigureContainer(x => x.RegisterModule<TModule>());
return this;
}
/// <summary>
/// Initialize the builder with a given Autofac module.
/// </summary>
/// <typeparam name="TModule">The type of module to use.</typeparam>
/// <returns>The builder to chain operations.</returns>
public NitrideBuilder UseModule(Module module)
{
this.ConfigureContainer(x => x.RegisterModule(module));
return this;
}
/// <summary>
/// Sets the description of the builder.
/// </summary>
public NitrideBuilder WithApplicationDescription(string value)
{
this.nitrideModule.Description = value;
return this;
}
/// <summary>
/// Sets the name of the application, which is displayed in the help screen.
/// </summary>
public NitrideBuilder WithApplicationName(string value)
{
this.nitrideModule.ApplicationName = value;
return this;
}
/// <summary>
/// Sets the root directory to a common value by creating a
/// IFileSystem (from Zio) of the root directory and registering it.
/// This will be used for both input and output.
/// </summary>
/// <param name="directory">
/// The path to the directory that represents "/" while
/// building.
/// </param>
/// <returns>The builder to chain calls.</returns>
public NitrideBuilder WithRootDirectory(DirectoryInfo directory)
{
this.RootDirectory = directory;
return this;
}
private void ConfigureContainer(ContainerBuilder builder)
{
// Hook up the rest of the modules.
builder.RegisterModule(this.nitrideModule);
// Set up our file system.
// TODO Wrong logger
this.RegisterRootDirectory(Log.Logger, builder);
// Finish up the registration by running our events.
foreach (Action<NitrideBuilder, ILifetimeScope>? callback in this
.configureSiteCallbacks)
{
builder.RegisterBuildCallback(scope => callback(this, scope));
}
foreach (Action<ContainerBuilder>? configureContainer in this
.configureContainerCallbacks)
{
configureContainer.Invoke(builder);
}
}
private void RegisterRootDirectory(
ILogger logger,
ContainerBuilder builder)
{
if (this.RootDirectory == null)
{
logger.Verbose("No root directory is registered");
return;
}
logger.Debug(
"Setting root directory to {Path}",
this.RootDirectory.FullName);
var rootFileSystem = new PhysicalFileSystem();
var subFileSystem = new SubFileSystem(
rootFileSystem,
this.RootDirectory.FullName);
builder.RegisterInstance(subFileSystem)
.As<IFileSystem>()
.SingleInstance();
}
}