command-line-api icon indicating copy to clipboard operation
command-line-api copied to clipboard

Adding '--verbosity' global option best practices

Open JobaDiniz opened this issue 1 year ago • 1 comments

I'm trying to add a global option named --verbosity with -v alias following these set of designs, specially this one:

If you define aliases, use -v for --verbosity and make -v without an argument an alias for --verbosity Diagnostic.

Also, I'm using the Middleware to intercept the --verbosity and set the console log accordingly (not sure whether my code is the best way to accomplish this - but it's the only way I've found)

internal class MyRootCommand : RootCommand
    {
        public const string CommandName = "myroot";
        public static readonly Option<Verbosity> VerbosityOption = CreateVerbosityOption();

        private static Option<Verbosity> CreateVerbosityOption()
        {
            var verbosity = new Option<Verbosity>("--verbosity", ParseVerbosity, isDefault: true, description: "Specifies how much output is sent to the console.")
               .FromAmong(Verbosity.Quiet, Verbosity.Normal, Verbosity.Diagnostic);
            verbosity.AddAlias("-v");
            verbosity.AddValidator(ValidateVerbosity);
            return verbosity;
        }

        private static Verbosity ParseVerbosity(ArgumentResult result)
        {
            if (result.Tokens.Count == 1)
                return new Verbosity(result.Tokens[0].Value);

            if (result.Tokens.Count == 1 && result.Tokens[0].Value == "-v")
                return Verbosity.Diagnostic;

            return Verbosity.Normal;
        }

        private static void ValidateVerbosity(OptionResult result)
        {
            //not called
        }

        public MyRootCommand() : base("blablabla")
        {
            AddGlobalOption(VerbosityOption);

Intercepting and adding LoggerFactory to the binding context, using the verbosity global.

private static async Task Middleware(InvocationContext context, Func<InvocationContext, Task> next)
        {
            var verbosity = new Verbosity(context.ParseResult.GetValueForOption(MyRootCommand.VerbosityOption));
            var loggerFactory = LoggerFactory.Create(builder =>
            {
               //will use 'verbosity' to set the level here
                builder.AddConsole().SetMinimumLevel(LogLevel.Information);
            });
            context.BindingContext.AddService(s => loggerFactory);

Now, the ValidateVerbosity(...) is not called when I issue myroot -v to the command line. Error: Required argument missing for option: '-v'.

JobaDiniz avatar Sep 19 '22 23:09 JobaDiniz

Try configuring the arity of the option to be zero-or-one:

verbosity.Arity = ArgumentArity.ZeroOrOne;

(The default arity for option arguments that are neither bool nor collections and don't have a default value assigned is ExactlyOne.)

elgonzo avatar Sep 21 '22 17:09 elgonzo