using System.CommandLine; using System.CommandLine.Builder; using System.CommandLine.Invocation; using System.CommandLine.NamingConventionBinder; using Microsoft.Extensions.DependencyInjection; using Wabbajack.Paths; namespace Wabbajack.CLI.Builder; public class CommandLineBuilder { private static IServiceProvider _provider = null!; public CommandLineBuilder(IServiceProvider provider) { _provider = provider; } public async Task Run(string[] args) { var root = new RootCommand(); foreach (var verb in _commands) { root.Add(MakeCommend(verb.Type, verb.Handler, verb.Definition)); } return await root.InvokeAsync(args); } private static Dictionary> _optionCtors = new() { { typeof(string), d => new Option(d.Aliases, description: d.Description) }, { typeof(AbsolutePath), d => new Option(d.Aliases, description: d.Description, parseArgument: d => d.Tokens.Single().Value.ToAbsolutePath()) }, { typeof(Uri), d => new Option(d.Aliases, description: d.Description) }, { typeof(bool), d => new Option(d.Aliases, description: d.Description) }, }; private Command MakeCommend(Type verbType, Func verbHandler, VerbDefinition definition) { var command = new Command(definition.Name, definition.Description); foreach (var option in definition.Options) { command.Add(_optionCtors[option.Type](option)); } command.Handler = new HandlerDelegate(_provider, verbType, verbHandler); return command; } private class HandlerDelegate : ICommandHandler { private IServiceProvider _provider; private Type _type; private readonly Func _delgate; public HandlerDelegate(IServiceProvider provider, Type type, Func inner) { _provider = provider; _type = type; _delgate = inner; } public int Invoke(InvocationContext context) { var service = _provider.GetRequiredService(_type); var handler = CommandHandler.Create(_delgate(service)); return handler.Invoke(context); } public Task InvokeAsync(InvocationContext context) { var service = _provider.GetRequiredService(_type); var handler = CommandHandler.Create(_delgate(service)); return handler.InvokeAsync(context); } } private static List<(Type Type, VerbDefinition Definition, Func Handler)> _commands { get; set; } = new(); public static IEnumerable Verbs => _commands.Select(c => c.Type); public static void RegisterCommand(VerbDefinition definition, Func handler) { _commands.Add((typeof(T), definition, handler)); } } public record OptionDefinition(Type Type, string ShortOption, string LongOption, string Description) { public string[] Aliases { get { return new[] { "-" + ShortOption, "--" + LongOption }; } } } public record VerbDefinition(string Name, string Description, OptionDefinition[] Options) { }