using System; using System.CommandLine; using System.IO; using Microsoft.Extensions.Configuration; namespace MfGames.ToolBuilder { /// /// A utility class for handling `--config` options. /// public class ConfigToolService { public ConfigToolService() { this.ConfigOption = new Option( "--config", "Configuration file to use for settings, otherwise a default will be used.", ArgumentArity.OneOrMore) { AllowMultipleArgumentsPerToken = false, }; this.ConfigOption.AddAlias("-c"); } /// /// Gets the common option for setting configuration files. /// public Option ConfigOption { get; } /// /// Gets the default configuration file. /// public FileInfo DefaultConfigFile => new(this.DefaultConfigPath); /// /// Gets the default configuration path. /// public string DefaultConfigPath { get { // If we don't have an internal name, blow up. string? internalName = this.InternalName; if (internalName == null) { 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; } } /// /// 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. /// public string? InternalName { get; set; } /// /// Adds the common options to the command. /// /// public void AddOptions(RootCommand root) { root.AddGlobalOption(this.ConfigOption); } /// /// Sets up logging based on the global settings. /// /// The configuration builder to use. /// The arguments to the command. 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()); // 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); } } /// /// Sets the internal name of the application, used for the /// configuration path. /// /// /// The internal name of the application. /// /// The service for chaining operations. public ConfigToolService WithInternalName(string internalName) { this.InternalName = internalName; return this; } } }