You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The sample classes given below demonstrate the issue. As the code below is written now, it works as expected, when I run a nested-subcommand with options:
dkelkhoff@mac:> top middle1 bottom1b -v
In bottom1b.call. verbose: true
However, if I add helpCommand = true to the @Command annotation on the NestingTop class, then I get this unexpected behavior from the same command-line run
dkelkhoff@mac:> top middle1 bottom1b -v
In top.call
Usage: top [-hV] [COMMAND]
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
Commands:
middle1
middle2
Now, I agree it was wrong of me to use helpCommand where I did, but it was fairly hard to trace it down. Also, if I only used 1-level of sub-commands, then everything always worked as expected - it was only when I added the nested sub-commands that i couldn't get them to run.
import java.util.concurrent.Callable;
import picocli.CommandLine;
import picocli.CommandLine.Command;
/*******************************************************************************
** Hierarchy of sub-commands looks like this:
**
** top
** middle1
** bottom1a
** bottom1b
** middle2
** bottom2a
** bottom2b
**
*******************************************************************************/
@Command(name = "top", subcommands = { NestingTop.Middle1.class, NestingTop.Middle2.class }, mixinStandardHelpOptions = true, version = "0")
public class NestingTop implements Callable<Void>
{
public static void main(String[] args)
{
new CommandLine(new NestingTop()).execute(args);
}
public Void call()
{
System.out.println("In top.call");
new CommandLine(this).usage(System.out);
return (null);
}
@Command(name = "middle1", subcommands = { Bottom1A.class, Bottom1B.class })
public static class Middle1 implements Callable<Void>
{
public Void call()
{
System.out.println("In middle1.call");
new CommandLine(this).usage(System.out);
return (null);
}
}
@Command(name = "middle2", subcommands = { Bottom2A.class, Bottom2B.class })
public static class Middle2 implements Callable<Void>
{
public Void call()
{
System.out.println("In middle2.call");
new CommandLine(this).usage(System.out);
return (null);
}
}
@Command(name = "bottom1a", subcommands = {})
public static class Bottom1A implements Callable<Void>
{
public Void call()
{
System.out.println("In bottom1a.call");
return (null);
}
}
@Command(name = "bottom1b", subcommands = {})
public static class Bottom1B implements Callable<Void>
{
@CommandLine.Option(names = { "-v", "--verbose" })
private boolean verbose;
public Void call()
{
System.out.println("In bottom1b.call. verbose: " verbose);
return (null);
}
}
@Command(name = "bottom2a", subcommands = {})
public static class Bottom2A implements Callable<Void>
{
public Void call()
{
System.out.println("In bottom2a.call");
return (null);
}
}
@Command(name = "bottom2b", subcommands = {})
public static class Bottom2B implements Callable<Void>
{
public Void call()
{
System.out.println("In bottom2b.call");
return (null);
}
}
}
The text was updated successfully, but these errors were encountered:
dkelkhoff
changed the title
helpCommand attribute causes deeply-nested sub-command to behave differently than expected
helpCommand attribute causes deeply-nested sub-command to behave differently than expected (in 4.0.0-beta-2)
Jul 5, 2019
One idea to deal with this is to introduce a rule that commands with helpCommand = true should not have subcommands.
(Can anyone think of other situations that should be prevented in a similar way? It would be good if we can formulate rules in a similar way to prevent such situations.)
The CommandLine constructor can throw an InitializationException if it detects a command that violates the rule(s), and the annotation processor can be enhanced to emit a compilation error if the annotation processor detects a command that violates them.
@dkelkhoff Revisiting this ticket after a long while...
Stepping through the code with your example, I did notice that the picocli parser does not expect the top-level command to be a help command, so internally this is not registered, and validation for missing required args is still happening, which shouldn't be happening. So that is one thing that I'll fix.
On the topic of preventing unintended usage:
I'm thinking to improve the javadoc for the @Command(helpCommand = ...) annotation.
Current:
Set this attribute to true if this subcommand is a help command, and required options and positional parameters of the parent command should not be validated. (...)
Proposed:
Set this attribute to true only if this subcommand is a help command that prints a usage help message, and therefore required options and positional parameters of the parent command should not be validated. (...)
The sample classes given below demonstrate the issue. As the code below is written now, it works as expected, when I run a nested-subcommand with options:
However, if I add
helpCommand = true
to the@Command
annotation on theNestingTop
class, then I get this unexpected behavior from the same command-line runNow, I agree it was wrong of me to use
helpCommand
where I did, but it was fairly hard to trace it down. Also, if I only used 1-level of sub-commands, then everything always worked as expected - it was only when I added the nested sub-commands that i couldn't get them to run.The text was updated successfully, but these errors were encountered: