Code Monkey home page Code Monkey logo

commandlineparser.core's Introduction

.NET Core Issues CodeCov CodeFactor License Nuget

CommandLineParser

A simple, light-weight and strongly typed commandline parser made in .NET Standard!

Installation

PM> Install-Package MatthiWare.CommandLineParser

Quick Start

Example of configuring the port option using the Fluent API.

static void Main(string[] args)
{
   // create the parser
   var parser = new CommandLineParser<ServerOptions>();
   
   // configure the options using the Fluent API
   parser.Configure(options => options.Port)
      .Name("p", "port")
      .Description("The port of the server")
      .Required();

   // parse
   var parserResult = parser.Parse(args);

   // check for parsing errors
   if (parserResult.HasErrors)
   {
      Console.ReadKey();

      return -1;
   }

   var serverOptions = parserResult.Result;

   Console.WriteLine($"Parsed port is {serverOptions.Port}");
}

private class ServerOptions
{
   // options
   public int Port { get; set; }
}

Run command line

dotnet myapp --port 2551

For more advanced configuration options see the wiki.

Contributors

commandlineparser.core's People

Contributors

dependabot[bot] avatar matthiee avatar moetelo avatar vookimedlo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

commandlineparser.core's Issues

Add attributes for option model

Allow to specify attributes on the fields in the model class.

  • [Required(bool)]
  • [Default(...)]
  • [OptionName(shortName, longName)]
  • [HelpText(...)]

Support NO_COLOR

This library should honor systems where console color output has explicitly been requested to be turned off. See more information about this initiative at https://no-color.org.

Usage is printed when all options have default values

Description

I have an option specified as

[Name("c", "check")]
[Description("Reports the amount of duplicates without changing anything")]
[DefaultValue(true)] // Note defaults to true and not required
public bool OnlyCheck { get; set; }

But still it prints the usages when it should not print them in this case.

Run without specifying the "check" option as CLI argument.

Workaround

Current workaround: setting AutoPrintUsageAndErrors = false.

Todo

Problem is caused by CommandLineParser`TOption.cs#L255-L265.

We wrongly assume noArgsSupplied means we should print the usage.
This is mostly correct but there is a scenario where this shouldn't.

A scenario where we only have optional options that have at least one with DefaultValue specified.

Command discovery

Load and register all of the Command<>'s defined in a assembly marked with a custom attribute.
This is an opt-in option that should be called before the Parse method.

TBD: Attribute name.

Usage/Help commands

I'm currently in favor of the EF.Core CLI help/usage style.

Example

PM> dotnet ef

                     _/\__       
               ---==/    \\      
         ___  ___   |.    \|\    
        | __|| __|  |  )   \\\   
        | _| | _|   \_/ |  //|\\ 
        |___||_|       /   \\\/\\

Entity Framework Core .NET Command-line Tools 2.2.0-preview2-35157

Usage: dotnet ef [options] [command]

Options:
  --version        Show version information
  -h|--help        Show help information
  -v|--verbose     Show verbose output.
  --no-color       Don't colorize output.
  --prefix-output  Prefix output with level.

Commands:
  database    Commands to manage the database.
  dbcontext   Commands to manage DbContext types.
  migrations  Commands to manage migrations.

Use "dotnet ef [command] --help" for more information about a command.
PM> dotnet ef database --help


Usage: dotnet ef database [options] [command]

Options:
  -h|--help        Show help information
  -v|--verbose     Show verbose output.
  --no-color       Don't colorize output.
  --prefix-output  Prefix output with level.

Commands:
  drop    Drops the database.
  update  Updates the database to a specified migration.

Use "database [command] --help" for more information about a command.

Todo

  • #11 Create Command
  • Description output
  • Format usage
  • Setup default convention

Create Command

Create Commands

Allow to use commands with custom options or no options at all.

Usage

  • myapp -param1 "something" -Add -A -m "Message"
  • myapp -Add -A -m "Message"
  • myapp -Add

Naming

  • ICommand, ICommand<T> where T : class

Behavior

Unmapped arguments by the ICommand will fall back to the global options if any exist.

Discovery

We can automatically discover the commands or they can be manually added.

  • Auto discover if class implements ICommand
  • Manually
    • parser.ConfigureCommand<ICommand>()
    • parser.ConfigureCommand<ICommand<Option>>(Expression<Func<Option>>)

Execution

Executing the command can be sync or async

  • ICommand.Execute()
  • ICommand.ExecuteAsync()
  • ICommand<Options>.Execute(Options)
  • ICommand<Options>.ExecuteAsync(Options)

Progress

  • Commands
  • #11
  • Async commands
  • Command chaining

IUsagePrinter doesn't have overload for IArgument

When the user wants to manually print usage for a requested option/command there currently is no easy way to do it.

Extending IUsagePrinter.PrintUsage(IArgument argument);

would allow the following scenario.

var parser = new CommandLineParser<Options>();

var parsed = parser.Parse(args);

if (parsed.HelpRequested)
{
    parser.Printer.PrintUsage(parsed.HelpRequestedFor);
}

Wiki: Configuration: Error in demo code

Hi Matthi!

The Configuration page on the project wiki contains following code:

var parseResult = parser.Parse(args);

if (result.HasErrors)
{
	Console.Error.WriteLine(result.Error);
	Console.ReadKey();

	return -1;
}

I suppose result should be parseResult there.
The issue is present in the demo code for Fluent API and Attributes config.

Auto executed commands that throw exceptions should still produce an error result

   at MatthiWare.CommandLine.Core.Command.CommandLineCommand`2.Execute() in D:\Source\Repos\CommandLineParser\CommandLineParser\Core\Command\CommandLineCommand`TOption`TCommandOption.cs:line 72
   at MatthiWare.CommandLine.CommandLineParser`1.ExecuteCommandParserResults(IEnumerable`1 results) in D:\Source\Repos\CommandLineParser\CommandLineParser\CommandLineParser`TOption.cs:line 296
   at MatthiWare.CommandLine.CommandLineParser`1.Parse(String[] args) in D:\Source\Repos\CommandLineParser\CommandLineParser\CommandLineParser`TOption.cs:line 210

Positional parameters

INFO

We should support positional arguments.

Example:

app.exe move "path/to/file" "move/to/path"

Where the move command contains

public class Model
{
     [OptionOrder(1)]
     public string SourcePath { get; set; }

     [OptionOrder(2)]
     public string MovePath { get; set; }
}

TODO

  • Add attribute support
  • Add Fluent API support
  • Add support in argument parser
  • Add Tests

Fix 2 Duplication issues in multiple files

Improve DI

Use Microsoft.Extensions.DependencyInjection instead of our own container resolver.

Bool option is not parsed properly

There is an issue with parsing the bool option without an explicit value.

    internal abstract class CommandOptions
    {
        [Name("v", "verb"), Description("Print usage"), DefaultValue(false)]
        public bool VerbA { get; set; }
    }

prog -v command
prog command -v

CommandOptions.VerrbA should be set to true (due to the -v), but is set to false.

Bool resolver is correct and have the null value in a list of the expected 'true' values, but the code in upper layers is wrong.

namespace MatthiWare.CommandLine.Core.Parsing.Resolvers
{
    internal class BoolResolver : ArgumentResolver<bool>
    {
        private static readonly string[] recognisedFalseArgs = new[] { "off", "0", "false", "no" };
        private static readonly string[] recognisedTrueArgs = new[] { "on", "1", "true", "yes", string.Empty, null };

The main problem is in CommandLineCommandTOptionTCommandOption.cs and CommandLineParser`TOption.cs.

                else if (!model.HasValue && option.HasDefault)
                {
                    option.UseDefault();

                    continue;
                }

and should be modified to something like this

                else if (!found && !model.HasValue && option.HasDefault)
                {
                    option.UseDefault();

                    continue;
                }

But that means, other resolvers shall be updated to cope with such situation and provide default value in such case.

DI: How to register Service, that needs parsed argument as parameter

Hi, i want to build a cli wrapper around an existing API. The API is instantiated with a static factory method which has a parameter called environment (PROD or TEST). This environment should be an option for the cli. How do i register the service properly to use it in Commands with DI?

Register Non Generic Command using Model property

Extension of #77

public class ModelWithCommands
{
    public NonGenericCommand NonGenericCommand { get; set; } // doesn't register
    public GenericCommandWithParentOptions GenericCommandWithParentOptions { get; set; }
    public GenericCommandWithOwnOptions GenericCommandWithOwnOptions { get; set; }
}

Add value transformers

Just like we have ArgumentResolver.cs (v0.2.2)'s we should also allow user defined value transformers that can be plugged into the option builders.

   // configure the options using the Fluent API
   parser.Configure(options => options.Port)
      .Name("p", "port")
      .Description("The port of the server")
      .Transform(value => Utils.UrlDecode(value)) // new api
      .Required();

Signature

IOptionBuilder<T> Transform(Expression<Func<T, T>> tranformation); 

Refactor command builder

We currently have a lot of classes/interfaces related to command configuration.

  • ICommandConfigurationBuilder
  • ICommandConfigurationBuilder<TSource>
  • ICommandBuilder<TOption>
  • ICommandBuilder<TOption, TCommandOption>

A lot of properties and methods are being duplicated. This has been done to not expose unwanted methods/properties in the public API.

Refactor of those interfaces/classes are needed for the 0.3 release.

Fix 2 Duplication, 2 Style issues in multiple files

Postfix for options

I want to define doc=dcebab66-49b6-4bb8-84d7-7401858d9667 as argument.

To allow this we need the following:

  • Allow adding postfix values to the names of options.
  • Don't require space between key (with postfix value) and actual value

How can use default arguments

For example;

If i want call a command without options:

server "localhost"

i need the first argument "localhost", without any option like --port.

Thanks !

Provide proper DI extension method

void AddCommandLineParser<T>(this IServiceCollection services, CommandLineParserOptions options);

This should register the ICommandLineParser<T> interface.

Running with *no* parameters at all crashes the command line parser

Starting the console app without any parameters, the command line parser crashes:

System.ArgumentOutOfRangeException
HResult=0x80131502
Message=Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
Source=mscorlib
StackTrace:
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at System.Collections.Generic.List1.get_Item(Int32 index) at MatthiWare.CommandLine.Core.Parsing.ArgumentManager.SetArgumentUsed(Int32 idx, ICommandLineCommand cmd) at MatthiWare.CommandLine.Core.Parsing.ArgumentManager.Parse(IEnumerable1 list)
at MatthiWare.CommandLine.Core.Parsing.ArgumentManager..ctor(String[] args, ICollection1 commands, ICollection1 options)
at MatthiWare.CommandLine.CommandLineParser`1.Parse(String[] args)

Usage: Command descriptions are not aligned properly

Hi there,
In usage output, command descriptions are not aligned properly. Shift shall be based on the longest command.

Usage: ck550-cli [commands]

Commands:
  effect-breathing              Set a breathing effect
  effect-color-cycle            Set a color-cycle effect
  effect-circle-spectrum                Set a circle-spectrum effect
  effect-crosshair              Set a crosshair effect
  effect-fireball               Set a fireball effect
  effect-heartbeat              Set a heartbeat effect
  effect-off            Set an off effect
  effect-reactive-punch         Set a reactive-punch effect
  effect-reactive-tornado               Set a reactive-tornado effect
  effect-ripple         Set a ripple effect
  effect-single-key             Set a single-key effect
  effect-snowing                Set a snowing effect
  effect-stars          Set a stars effect
  effect-static         Set a static effect
  effect-water-ripple           Set a water-ripple effect
  effect-wave-ripple            Set a wave effect

Fix nuget package in CI/CD

Enhances #4 Nuget package from CI is not usable at the moment. Automate it further so it auto increases build version and adds correct binaries.

Create command without options

For the moment it is now mandatory to provide a generic parameter that represents the command options.
Some command don't require options so this is not mandatory but rather optional.

Unable to register non-generic command

Assume you have the following command:

public class MyCommand : Abstractions.Command.Command
{
   // ...
}

In this case it is impossible to use the following commands

var parser = new CommandLineParser();

parser.RegisterCommand<MyCommand>();

// or

parser.RegisterCommand(typeof(MyCommand));

// or

parser.DiscoverCommands(typeof(MyCommand).Assembly);

Types with string ctor should be resolvable by default

No need to create a custom resolver when the type has a constructor that takes in a string.

We should create a DefaultResolver that is able to resolve the following types:

  • .ctor(String)
  • bool TryParse(String, IFormatProvider, out T result)
  • T Parse(String, IFormatProvider)

Make UsagePrinter easier to work with

Description

When using your own custom usage printer there currently is no way to know the generate usage text.

PrintUsage() Should take in an already formatted string that is ready to be outputted (stdout, messagebox, ...)

Tasks

  • Rework API
  • Add error printing here as well

Strongly typed argument validations

Create an abstract layer for parsed argument validations.
I'm not planning to build an argument validator framework on top of this one so I'm only going to expose an abstract API so we can plug-in already existing frameworks.

This means we will introduce a second package in this repo. MatthiWare.CommandLineParser.Core.Extensions.FluentValidations

Will be hosted in an Extensions\... folder.

Work to do

  • Create public abstract validation API
  • Create an nuget extension package "MatthiWare.CommandLineParser.Core.Extensions.FluentValidations"
  • Update example and wiki

Support all standard datatypes

Currently there are some datatypes that are not supported

Mostly looking at the array and collection types.

  • Add test for all data types

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.