Replies: 5 comments
-
This is probably why things looked confusing. |
Beta Was this translation helpful? Give feedback.
-
Thanks indeed jvalkeal. I switched to the new model with @command and @option, but I am still unable to get my desired results: @Command(command = "create-key",
description = "Create a new pair of private and public keys"
)
public String createKey(
@Option(required = true, arity = CommandRegistration.OptionArity.EXACTLY_ONE) String id,
@Option(longNames = "pass", required = false) String passphrase,
@Option(longNames = "duration", required = false) String duration
) {
return MessageFormat.format("id: {0}, passphrase: {1}, duration: {2}", id, passphrase, duration);
} Now this works: shell:>create-key x --pass pass --duration 30
id: x, passphrase: pass, duration: 30 But passing the option before the arguments does not:
Can the shell accept both options and positional arguments like the Unix shell, or is it limited to options? Is there any way to capture only options and receive the positional arguments apart as a string array? Separating options (prefixed by --keyword) from arguments (positional) would also be less confusing to users. As is, if the user by mistake types extra text it is interpreted and executed as a different option. Thanks again in antecipation. |
Beta Was this translation helpful? Give feedback.
-
I added this to @Command(command = "positional-args-3")
public String testPositionalArgs3(
@Option(longNames = "id", required = true, arity = OptionArity.EXACTLY_ONE) String arg1,
@Option(longNames = "pass", required = false, arity = OptionArity.ZERO_OR_ONE) String arg2,
@Option(longNames = "duration", required = false, arity = OptionArity.ZERO_OR_ONE) String arg3
) {
return String.format("Hi arg1='%s' arg2='%s' arg3='%s'", arg1, arg2, arg3);
} my-shell:>e2e annox positional-args-3
Missing mandatory option '--id'
my-shell:>e2e annox positional-args-3 a1
Hi arg1='a1' arg2='null' arg3='null'
my-shell:>e2e annox positional-args-3 a1 --pass a2 --duration a3
Hi arg1='a1' arg2='a2' arg3='a3'
my-shell:>e2e annox positional-args-3 --pass a2 --duration a3 a1
Hi arg1='a1' arg2='a2' arg3='a3'
my-shell:>e2e annox positional-args-3 --pass a2 a1 --duration a3
Too many arguments for option 'pass', requires at most '1'
my-shell:> That's as close I was able to go. This at least gives you a way to get the positional argument if it's last one give. If it's in a middle an error is given and I'm not sure if that's a bug or missing feature. Going forward we probably need to add customisation options to a parser so that use can fine tune behaviour. Positional parameters makes this a bit complicated as there's always cases where things feel a bit confusing what comes for those belonging to positional vs. passed option. |
Beta Was this translation helpful? Give feedback.
-
Hi Janne, Again, thanks very much indeed! My example was very simple, but I wish for a more generic solution very similar to how the Unix or other shell work. Here is a short description. First a distinction between options and parameters. Parameters are positional while options are named; this is preceded by a flag. The flag is usually one or two hyphens followed by a name, and synonyms can be assigned to the same option (for example --short or -s) The tokenizer (or lexical analyzer) produces a list of tokens. We scan the list, token by token. If the token is a flag, we assign the next token to the preceding option, with a few exceptions (see below). Otherwise, we collect the token as an argument. We probably need an extra annotation (@Args for example) to annotate the function argument that will get the collected arguments. The project code I see on Github reads: /**
* Parse given arguments into a {@link ParseResult}.
*
* @param arguments the command line arguments
* @return a parsed results
*/
ParseResult parse(List<String> arguments);
/**
* Results from a {@link Parser} containing needed information like resolved
* {@link CommandRegistration}, list of {@link CommandOption} instances, errors
* and directive.
*
* @param commandRegistration command registration
* @param optionResults option results
* @param argumentResults argument results
* @param messageResults message results
* @param directiveResults directive result
*/
public record ParseResult(CommandRegistration commandRegistration, List<OptionResult> optionResults,
List<ArgumentResult> argumentResults, List<MessageResult> messageResults,
List<DirectiveResult> directiveResults) { I see that the parser is already defined to collect the options and the arguments and also the directives (no idea of what directives they are). Anyway, writing an alternative parser should not be difficult. What is not clear to me is how the arguments can be collected with annotations. Now let's see how I would like to assign values to options. We can distinguish three cases: Case 1: boolean options - By default, they are initialized as false, and we negate their current value whenever we encounter a label. No subsequent value token is expected. For example (with a boolean option --enabled):
Result: option[enabled] = true, arguments = [arg1, arg2]
Result: option[enabled] = false, arguments = [arg1, arg2, arg3] Case 2: single value options - This is the most simple and usual case. We assign the token following the label to the value. Let's say we have the integer --count option and the String --text option. Here are some examples:
Will all result in: option[count] = 5, arguments = [arg1, arg2, arg3] Case 3: multiple value options - This is a little tricky. Such options in many shells are discouraged. There are anyway two usual alternatives: (3A) the user can repeat the label for each value. Let's say we have an option labelled as --list:
Will result in: option[list] = [l1, l2], arguments = arg1, arg2, arg3, arg4 (3B) the user can use some agreed-upon start and end indicator, for example a square brace:
Will result in: option[list] = [l1, l2, l3], arguments = arg1, arg2, arg3 Implementing such a parser is relatively simple. I will try to do it after my vacation, but I shall still to understand how to return the arguments with annotations and how to replace the defaut parser (through code injection if possible). I will be glad to contribute to the project if somebody finds it useful. Thanks again and anl king of correction or suggestion is welcome. |
Beta Was this translation helpful? Give feedback.
-
A lot of influence came from dotnet's commandline lib https://learn.microsoft.com/en-us/dotnet/standard/commandline/. They define In spring-shell the lowest level is a Directives are not currently used while format exists in a parser. This idea is also coming from a dotnet https://learn.microsoft.com/en-us/dotnet/standard/commandline/use-middleware. What I i.e. wanted to do with it was similar to this https://github.com/dotnet/command-line-api/blob/803d8598f98fb4efd94604b32627ee9407f246db/src/System.CommandLine/ParseDiagramDirective.cs#L10 to help user understand command line parsing. |
Beta Was this translation helpful? Give feedback.
-
I'm trying to use the Shell, but I'm confused by the documentation and how to specify command arguments and options. Here is a really simple example.
I need a "generate-key" command that receives:
As you can see, the code does nothing, simply echoes the argument and parameters. So you can quickly reproduce the case.
Maybe am I doing something wrong? Please let me know. Let's see some cases:
First attempt: command only:
This is wrong:
So I make a second test supplying only the positional argument:
shell:>create-key zorro id: zorro, passphrase: null, duration: null
Perfect! worked as expected. Now let's try an option:
shell:>create-key zorro --pass garcia id: zorro, passphrase: --pass, duration: garcia
Wrong! I would expect:
Now let's try all options:
Wrong again: the passphrase is "garcia", not "--pass".
And finally, if I precede the options (as usual in Unix):
I get the unrecognized option "--pass".
I can't find a simple guide that explains how to code for this specific case, so I must be doing something wrong.
Can you kindly explain how options and arguments are recognized and parsed?
Thanks indeed.
Beta Was this translation helpful? Give feedback.
All reactions