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-toolbuilder-cil/src/MfGames.ToolBuilder/Globals/ConfigToolGlobalService.cs
2021-09-11 14:14:45 -05:00

171 lines
5.6 KiB
C#

using System;
using System.CommandLine;
using System.IO;
using MfGames.IO.Extensions;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
namespace MfGames.ToolBuilder.Globals
{
/// <summary>
/// A utility class for handling `--config` options.
/// </summary>
public class ConfigToolGlobalService
{
public ConfigToolGlobalService()
{
this.ConfigOption = new Option<string[]>(
"--config",
"Configuration file to use for settings, otherwise a default will be used.",
ArgumentArity.OneOrMore)
{
AllowMultipleArgumentsPerToken = false,
};
this.ConfigOption.AddAlias("-c");
}
/// <summary>
/// Gets the common option for setting configuration files.
/// </summary>
public Option<string[]> ConfigOption { get; }
/// <summary>
/// Gets the default configuration file.
/// </summary>
public FileInfo DefaultConfigFile => new(this.DefaultConfigPath);
/// <summary>
/// Gets the default configuration path.
/// </summary>
public string DefaultConfigPath
{
get
{
// If we don't have an internal name, blow up.
string? internalName = this.InternalName;
if (string.IsNullOrWhiteSpace(internalName))
{
throw new ApplicationException(
"Cannot determine the default configuration path unless internal name has been set.");
}
// Figure out the path to the default configuration. This is
// something like:
// $HOME/.config/ApplicationName/Settings.json
string configDirectory = Environment
.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string appDirectory = Path.Combine(
configDirectory,
internalName);
string configPath = Path.Combine(appDirectory, "Settings.json");
return configPath;
}
}
/// <summary>
/// Gets or sets the name of the application. This is used to figure out
/// the name of the configuration file and what is shown on the screen.
/// </summary>
public string? InternalName { get; set; }
/// <summary>
/// Adds the common options to the command.
/// </summary>
/// <param name="root"></param>
public void AddOptions(RootCommand root)
{
root.AddGlobalOption(this.ConfigOption);
}
/// <summary>
/// Sets up logging based on the global settings.
/// </summary>
/// <param name="builder">The configuration builder to use.</param>
/// <param name="arguments">The arguments to the command.</param>
public void Configure(IConfigurationBuilder builder, string[] arguments)
{
// In general, we don't use a local AppSettings.json automatically
// but prefer configuration in the $HOME/.config folder instead.
// However, if the user gives a configuration setting, we use that
// no matter where we want to put it.
string[] configs = GlobalOptionHelper.GetArgumentValue(
this.ConfigOption,
arguments,
Array.Empty<string>());
// If we don't have anything, then use the default.
if (configs.Length == 0)
{
builder.AddJsonFile(this.DefaultConfigPath, true, true);
return;
}
// Otherwise, use the default files.
foreach (var config in configs)
{
builder.AddJsonFile(config, true, true);
}
}
/// <summary>
/// Reads the default configuration file and returns it as a
/// deserialized object.
/// </summary>
/// <typeparam name="TType">A type that represents the configuration file.</typeparam>
/// <returns>The resulting file.</returns>
public TType? ReadDefaultConfigFile<TType>()
{
FileInfo? file = this.DefaultConfigFile;
if (!file.Exists)
{
return default;
}
var json = file.ReadAllText();
TType result = JsonConvert.DeserializeObject<TType>(json);
return result;
}
/// <summary>
/// Sets the internal name of the application, used for the
/// configuration path.
/// </summary>
/// <param name="internalName">
/// The internal name of the application.
/// </param>
/// <returns>The service for chaining operations.</returns>
public ConfigToolGlobalService WithInternalName(string internalName)
{
this.InternalName = internalName;
return this;
}
/// <summary>
/// Writes the given object to the default configuration file.
/// </summary>
/// <typeparam name="TType">A type that represents the configuration file.</typeparam>
public void WriteDefaultConfigFile<TType>(TType value)
{
// Get the file and make sure the directory containing it exists.
FileInfo file = this.DefaultConfigFile;
file.Directory?.CreateIfMissing();
// Write it out.
string json = JsonConvert.SerializeObject(
value,
Formatting.Indented);
file.WriteAllText(json);
}
}
}