Open kdubau opened 5 years ago
I am able to do this with the following
Program.cs
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Args.InvokeAction
Subcmd1.cs
public class Subsubcmd1Args
{
[ArgRequired, ArgDescription("The first operand to process"), ArgPosition(1)]
public string message { get; set; }
}
public class Subsubcmd1
{
//public string[] Args { get; set; }
[ArgActionMethod, ArgDescription("Adds the two operands")]
public void SubSubCmd1(Subsubcmd1Args args)
{
Console.WriteLine($"{args.message}");
}
}
[ArgExceptionBehavior(ArgExceptionPolicy.StandardExceptionHandling)]
public class Subcmd1
{
[HelpHook, ArgShortcut("-?"), ArgDescription("Shows this help")]
public bool Help { get; set; }
[ArgActionMethod, ArgDescription("Adds the two operands")]
public void SubCmd1(string[] args)
{
Args.InvokeAction<Subsubcmd1>(args);
//Console.WriteLine($"{args.message}");
}
}
So with this code in place and if we build and run as following
CMD> dotnet OptionParser.dll SubCmd1 subsubcmd1 "My message Here"
This works good for positional parameter. The problem here is we cannot pass the message as named parameter something like following
CMD> dotnet OptionParser.dll SubCmd1 subsubcmd1 -message "My message Here"
I am getting error like
Unexpected named argument: message
I thing there is something to improve here for powerarg library..
Not currently supported and it would be a fairly big change. I'll leave the issue open and if I have time in the future maybe I'll add this. You could try to fake it by using a positional arg, but there would be side effects.
@adamabdelhamed what would your thoughts be on something like
ArgSubAction
, this would then be set with all args passed in excluding the current actionArgs.InvokeAction<SubAction>(args.SubActionArgs)
not sure how the args documentation portion of this would get flushed out 🤔 just an initial thought 🤷♂️
@adamabdelhamed / @vnekatesharao / @kdubau: would love to get your feedback on this 😄
so this is the working solution I have, I did borrow some ideas from how kubernet is changing passing args to pods using --
as a separator.
so my "tricks" here were to
[ArgShortcut("--")]
as the shortcut for my "sub args" string[]
:
)string[]
for the Args property of the "first level" actionSubAction
and Args
being populatedthe following commands have been tested (yes is exe) and worked as expected
util hs -h
(help for hello sign actions printed)util hs -- ls -h
(help for sub actions printed)util hs ls -- :f
(ran the sub action for ls
and IncludeFields
was set to true
this does only seem to solve for one level but I suppose you could repeat the concept with new separators for each level but I am not sure that will be fun 😢 quick app as a test so be gentle :)
static void Main(string[] args)
{
try
{
Args.InvokeAction<UtilActions>(args);
}
catch (DbEntityValidationException dbEx)
{
var sdSb = new StringBuilder();
foreach (var eve in dbEx.EntityValidationErrors)
{
sdSb.AppendLine(
$"Entity of type {eve.Entry.Entity.GetType().Name} in state {eve.Entry.State} has the following validation errors:");
foreach (var ve in eve.ValidationErrors)
{
sdSb.AppendLine(
$"- Property: {ve.PropertyName}, Value: {eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName)}, Error: {ve.ErrorMessage}");
}
}
sdSb.ToString()
.ToConsoleString(ConsoleColor.Red)
.ToConsole();
}
catch (Exception e)
{
e.ToConsoleString(ConsoleColor.Red)
.ToConsole();
}
}
then My tope level action looks like so
public partial class UtilActions
{
[ArgShortcut("hs")]
[ArgActionMethod, ArgDescription("create md5 hash of all values")]
public void HelloSign(HelloSignArgs action)
{
action.SubAction.ToConsole();
try
{
var args = new List<string>();
if (action.SubAction.IsNotNullOrWhiteSpace())
{
args.Add(action.SubAction);
}
if (action.Args.IsNotNull())
{
args.AddRange(action.Args
.Select(a => a.Replace(":", "--"))
.ToList());
}
Args.InvokeAction<HelloSignSubActions>(args.ToArray());
}
catch (Exception e)
{
e.ToConsole();
}
}
}
and here is the related Args Class
public class HelloSignArgs
{
[ArgPosition(1)]
public string SubAction {get; set;}
[ArgShortcut("--")]
[ArgDescription("separator for arguments intended to be passed to the sub action")]
public string[] Args {get; set;}
}
given the test I used was running with hs ls -f
I do get the -f properly set in the sub actions
public class HelloSignSubActions
{
[HelpHook]
[ArgShortcut("?")]
[ArgShortcut("h")]
[ArgShortcut("--?")]
[ArgShortcut("--h")]
[ArgShortcut("--help")]
[ArgDescription("Shows this help")]
public bool Help {get; set;}
[ArgShortcut("ls")]
[ArgActionMethod, ArgDescription("create md5 hash of all values")]
public void List(HelloSignSubActionArgs args)
{
args.IncludeFields.ToConsole();
}
}
with the Args Class as so:
public class HelloSignSubActionArgs
{
[ArgShortcut("f")]
[ArgDescription("include fields with template output")]
public bool IncludeFields {get; set;}
}
by using a diff prefix it solved the second issue with parsing I was running into @adamabdelhamed funny but custom prefix attr here would help to solve this "cleanly" but not required
asking for [ArgPrefix("-", "--")]
@adamabdelhamed might be interesting to do something like [ArgActions("git")]
where git would be the "action prefix" for the method
kinda like .net attr routing, set the "root" path for the "controller" (action class) and then each action
if that seems like something worth doing I can start another ticket
If I were to PR #67 would you approve it?
I am looking to be able to have sub-action methods. Something like
mytool.exe secret set {ArgPosition0} {ArgPosition1}
andmytool.exe secret get {ArgPosition0}
.I wasn't able to figure out how to achieve this so perhaps it's not supported? If it is can you please describe and I can PR an update to the README.md.
If not, feel free to close this or leave it open to track feature implementation (depending on complexity I can likely help).