diff --git a/Wabbajack.CLI/CommandLineBuilder.cs b/Wabbajack.CLI/CommandLineBuilder.cs index dbb3593a..0c0efa68 100644 --- a/Wabbajack.CLI/CommandLineBuilder.cs +++ b/Wabbajack.CLI/CommandLineBuilder.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; using System.CommandLine; +using System.CommandLine.Invocation; +using System.CommandLine.NamingConventionBinder; using System.ComponentModel.Design; using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Wabbajack.CLI.Verbs; +using Wabbajack.Paths; using Wabbajack.Services.OSIntegrated; namespace Wabbajack.CLI; @@ -14,11 +17,11 @@ public partial class CommandLineBuilder { private readonly IConsole _console; private readonly IEnumerable _verbs; + private static IServiceProvider _provider; - public CommandLineBuilder(IEnumerable verbs, IConsole console, LoggingRateLimiterReporter _) + public CommandLineBuilder(IServiceProvider provider, IConsole console, LoggingRateLimiterReporter _) { - _console = console; - _verbs = verbs; + _provider = provider; } static CommandLineBuilder() @@ -29,12 +32,73 @@ public partial class CommandLineBuilder public async Task Run(string[] args) { var root = new RootCommand(); - foreach (var verb in _verbs) - root.Add(verb.MakeCommand()); - + 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 = (IVerb)_provider.GetRequiredService(_type); + var handler = CommandHandler.Create(_delgate(service)); + return handler.Invoke(context); + } + + public Task InvokeAsync(InvocationContext context) + { + var service = (IVerb)_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) @@ -43,7 +107,17 @@ public partial class CommandLineBuilder } } -public record OptionDefinition(Type type, string ShortOption, string LongOption, string Description); + +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) { @@ -57,7 +131,7 @@ public static class CommandLineBuilderExtensions foreach (var verb in CommandLineBuilder.Verbs) { - services.AddSingleton(typeof(IVerb), verb); + services.AddSingleton(verb); } return services;