Commandline: Support for commands

Created on 4 Nov 2017  路  5Comments  路  Source: commandlineparser/commandline

Issue by fleed
_Friday Mar 31, 2017 at 04:24 GMT_
_Originally opened as https://github.com/gsscoder/commandline/issues/434_


Is there any existing way to define commands, intended as classes to execute specific options? IF not, any plan to add support? I would expect something like this, removing lot of the ceremony required to configure the option and run the related logic:

Example:

class CommitCommand : Command<CommitOptions>
{
    public int Execute(CommitOptions options)
    {
        // execute
        return 0;
    }

    // alternative
    public int Execute()
    {
        // access options as property in AsyncCommand base
        var file = this.Options.File;

        // execute
        return 0;
    }
}

class UploadCommand : AsyncCommand<UploadOptions>
{
    public async Task<int> ExecuteAsync(CommitOptions options)
    {
        // execute
        return 0;
    }

    // alternative
    public async Task<int> ExecuteAsync()
    {
        // access options as property in AsyncCommand base
        var file = this.Options.File;

        // execute
        return 0;
    }
}

// Program.cs
var parser = new CommandParser();
var parserResult = parser.Parse(args);
var result = parserResult.ExecuteCommand();

In general I'd like the possibility to discover options and commands through reflection, something similar to ManyConsole.

Most helpful comment

@ericnewton76 sure, but no support for async :(
With async main support in C# 7.1, that's a very important feature.

All 5 comments

Comment by nemec
_Monday Apr 03, 2017 at 18:07 GMT_


There's no autodetection, but do verbs not do what you're asking?

https://github.com/gsscoder/commandline/blob/master/tests/CommandLine.Tests/Unit/ParserResultExtensionsTests.cs#L25

Parser.Default.ParseArguments<Add_Verb, Commit_Verb, Clone_Verb>(
    new[] { "clone", "https://value.org/user/file.git" })
  .WithParsed<Add_Verb>(opts => expected = "wrong1")
  .WithParsed<Commit_Verb>(opts => expected = "wrong2")
  .WithParsed<Clone_Verb>(opts => expected = opts.Urls.First());

@ericnewton76 sure, but no support for async :(
With async main support in C# 7.1, that's a very important feature.

I implemented this like this:

in main (using MEF for discovering):

        var handlers = container.GetExportedValues<ICommand>();

        var returnCode = Parser.Default.ParseArguments(args, handlers.Select(x => x.OptionType).ToArray())
            .MapResult<IOptions, int>(
                x =>
                {
                    var handler = handlers.First(h => h.OptionType == x.GetType());
                    // voodoo because I can't cast to Command<IOptions>
                    return (int)handler.GetType().GetMethod("Run").Invoke(handler, new object[] { x });
                },
                _ => 1
            );

Base classes and interfaces:

public interface IOptions
{

}

public interface ICommand
{
    Type OptionType { get; }
}

public abstract class Command<T> : ICommand where T : IOptions
{
    public abstract int Run(T options);

    public Type OptionType => typeof(T);
}

and a command would look like this:

[Export(typeof(ICommand))]
public class Search : Command<SearchOptions>
{
    public override int Run(SearchOptions opts)
    {
        ...
    }
}

you can easily change this to make these commands async.

You probably meant to direct that at nemec, these issues were imported from gsscoder/commandline

Please forward async comments onto an async specific issue please, otherwise this conversation gets lost in here.

this reply was directed to @fleed .

Was this page helpful?
0 / 5 - 0 ratings