Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subcommand parameters in ArgGroup result in ArithmeticException #1213

Closed
LorenKeagle opened this issue Oct 13, 2020 · 4 comments
Closed

Subcommand parameters in ArgGroup result in ArithmeticException #1213

LorenKeagle opened this issue Oct 13, 2020 · 4 comments
Labels
theme: arg-group An issue or change related to argument groups type: bug 🐛
Milestone

Comments

@LorenKeagle
Copy link

If I define a parameter list in an ArgGroup in a subcommand class, PicoCLI always throws an exception when any parameters are provided. Here is how my ArgGroup is specified in my subcommand:

    @ArgGroup(exclusive = false, validate = false, heading = "scan source options%n")
    SourceOptions sourceOptions;

    static class SourceOptions {

        @Parameters(paramLabel = "FILE")
        List<File> reportFiles;

        @Option(names = {"-b", "--build-id"}, paramLabel = "Build ID")
        List<Integer> buildIds;

        @Option(names = {"-a", "--app-name"}, paramLabel = "App Name")
        List<String> appNames;
   }

The user can specify any number of files, but can also optionally specify inputs using some attributes (build-id and app-name above). The ArgGroup is only being used to group options in the Help/Usage output.

If any parameters are provided on the commandline, I get the following exception:

picocli.CommandLine$ParameterException: ArithmeticException: / by zero while processing argument at or before arg[0] 'analyze' in [analyze, x, y, z]: java.lang.ArithmeticException: / by zero
	at picocli.CommandLine$ParameterException.create(CommandLine.java:17091)
	at picocli.CommandLine$ParameterException.access$18500(CommandLine.java:17015)
	at picocli.CommandLine$Interpreter.parse(CommandLine.java:12367)
	at picocli.CommandLine$Interpreter.processSubcommand(CommandLine.java:12623)
	at picocli.CommandLine$Interpreter.processArguments(CommandLine.java:12537)
	at picocli.CommandLine$Interpreter.parse(CommandLine.java:12358)
	at picocli.CommandLine$Interpreter.parse(CommandLine.java:12243)
	at picocli.CommandLine.parseArgs(CommandLine.java:1458)
	at picocli.CommandLine.execute(CommandLine.java:2057)
	at com.imperva.AutoTune.AutoTune.main(AutoTune.java:150)
Caused by: java.lang.ArithmeticException: / by zero
	at picocli.CommandLine$ParseResult$GroupMatchContainer.canMatchPositionalParam(CommandLine.java:11962)
	at picocli.CommandLine$Interpreter.processPositionalParameter(CommandLine.java:12673)
	at picocli.CommandLine$Interpreter.processArguments(CommandLine.java:12600)
	at picocli.CommandLine$Interpreter.parse(CommandLine.java:12358)
	... 7 more

Here is some more detailed TRACE output:

$ java -Dpicocli.trace=DEBUG -jar build/libs/AutoTune-0.5.0.jar analyze x y z
[picocli DEBUG] Creating CommandSpec for com.foo.AutoTune.AutoTune@1c655221 with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Creating CommandSpec for class com.foo.AutoTune.AnalyzeEvents with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Getting a com.foo.AutoTune.AnalyzeEvents instance from factory picocli.CommandLine$DefaultFactory@5594a1b5
[picocli DEBUG] Factory returned a com.foo.AutoTune.AnalyzeEvents instance (6a5fc7f7)
[picocli DEBUG] Adding subcommand 'analyze-events' to 'AutoTune'
[picocli DEBUG] Adding alias 'events' for 'AutoTune'
[picocli DEBUG] Adding alias 'ev' for 'AutoTune'
[picocli DEBUG] Creating CommandSpec for class com.foo.AutoTune.Process with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Getting a com.foo.AutoTune.Process instance from factory picocli.CommandLine$DefaultFactory@5594a1b5
[picocli DEBUG] Factory returned a com.foo.AutoTune.Process instance (21bcffb5)
[picocli DEBUG] Adding subcommand 'analyze-scan' to 'AutoTune'
[picocli DEBUG] Adding alias 'analyze' for 'AutoTune'
[picocli DEBUG] Adding alias 'as' for 'AutoTune'
[picocli DEBUG] Creating CommandSpec for class picocli.CommandLine$HelpCommand with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] Adding subcommand 'help' to 'AutoTune'
[picocli INFO] Setting exclusive=false because [[-s=FILE] [--generate-settings=FILE]] is a non-validating group.
[picocli DEBUG] Creating CommandSpec for picocli.CommandLine$AutoHelpMixin@531be3c5 with factory picocli.CommandLine$DefaultFactory
[picocli DEBUG] getTerminalWidth() executing command [tput, cols]
[picocli DEBUG] getTerminalWidth() parsing output:  238
[picocli DEBUG] getTerminalWidth() returning: 238 in 27.4ms
[picocli INFO] Picocli version: 4.5.1, JVM: 14.0.1 (N/A OpenJDK 64-Bit Server VM 14.0.1+14), OS: Mac OS X 10.15.7 x86_64
[picocli INFO] Parsing 4 command line args [analyze, x, y, z]
[picocli DEBUG] Parser configuration: optionsCaseInsensitive=false, subcommandsCaseInsensitive=false, abbreviatedOptionsAllowed=false, abbreviatedSubcommandsAllowed=false, aritySatisfiedByAttachedOptionParam=false, atFileCommentChar=#, caseInsensitiveEnumValuesAllowed=false, collectErrors=false, endOfOptionsDelimiter=--, expandAtFiles=true, limitSplit=false, overwrittenOptionsAllowed=false, posixClusteredShortOptionsAllowed=true, separator=null, splitQuotedStrings=false, stopAtPositional=false, stopAtUnmatched=false, toggleBooleanFlags=false, trimQuotes=false, unmatchedArgumentsAllowed=false, unmatchedOptionsAllowedAsOptionParameters=true, unmatchedOptionsArePositionalParams=false, useSimplifiedAtFiles=false
[picocli DEBUG] (ANSI is enabled by default: systemproperty[picocli.ansi]=null, isatty=true, TERM=xterm-256color, OSTYPE=null, isWindows=false, JansiConsoleInstalled=false, ANSICON=null, ConEmuANSI=null, NO_COLOR=null, CLICOLOR=null, CLICOLOR_FORCE=null)
[picocli DEBUG] Initializing command 'AutoTune' (user object: com.foo.AutoTune.AutoTune@1c655221): 9 options, 0 positional parameters, 0 required, 2 groups, 7 subcommands.
[picocli DEBUG] Set initial value for field java.io.File com.foo.AutoTune.AutoTune.configFile of type class java.io.File to null.
[picocli DEBUG] Set initial value for field String com.foo.AutoTune.AutoTune.configVersion of type class java.lang.String to null.
[picocli DEBUG] Initial value not available for method void com.foo.AutoTune.AutoTune.setVerbose(boolean[])
[picocli DEBUG] Set initial value for field boolean picocli.CommandLine$AutoHelpMixin.helpRequested of type boolean to false.
[picocli DEBUG] Set initial value for field boolean picocli.CommandLine$AutoHelpMixin.versionRequested of type boolean to false.
[picocli DEBUG] [0] Processing argument 'analyze'. Remainder=[x, y, z]
[picocli DEBUG] Found subcommand 'analyze' (command 'analyze-scan' (user object: com.foo.AutoTune.Process@21bcffb5))
[picocli DEBUG] Checking required args for parent command 'AutoTune' (user object: com.foo.AutoTune.AutoTune@1c655221)...
[picocli DEBUG] Initializing command 'analyze-scan' (user object: com.foo.AutoTune.Process@21bcffb5): 13 options, 1 positional parameters, 0 required, 2 groups, 0 subcommands.
[picocli DEBUG] Set initial value for field boolean com.foo.AutoTune.Process.analyzeAutoMitigate of type boolean to false.
[picocli DEBUG] Not applying initial value for inherited option '--config'
[picocli DEBUG] Not applying initial value for inherited option '--edit-in-place'
[picocli DEBUG] Not applying initial value for inherited option '--output-config'
[picocli DEBUG] Not applying initial value for inherited option '--config-version'
[picocli DEBUG] Not applying initial value for inherited option '--settings'
[picocli DEBUG] Not applying initial value for inherited option '--generate-settings'
[picocli DEBUG] Not applying initial value for inherited option '--verbose'
[picocli DEBUG] [1] Processing argument 'x'. Remainder=[y, z]
[picocli DEBUG] 'x' cannot be separated into <option>=<option-parameter>
[picocli DEBUG] Could not find option 'x', deciding whether to treat as unmatched option or positional parameter...
[picocli DEBUG] No option named 'x' found. Processing as positional parameter
[picocli DEBUG] Single-character arguments that don't match known options are considered positional parameters
[picocli DEBUG] [1] Processing next arg as a positional parameter. Command-local position=0. Remainder=[x, y, z]
[picocli INFO] Adding match to GroupMatchContainer [[FILE...] [-b=Build ID]... [-a=App Name]...]={} (group=1 [[FILE...] [-b=Build ID]... [-a=App Name]...]).
[picocli DEBUG] Creating new user object of type class com.foo.AutoTune.Process$SourceOptions for group [[FILE...] [-b=Build ID]... [-a=App Name]...]
[picocli DEBUG] Created com.foo.AutoTune.Process$SourceOptions@48eff760, invoking setter FieldBinding(com.foo.AutoTune.Process$SourceOptions com.foo.AutoTune.Process.analyzeSource) with scope com.foo.AutoTune.Process@21bcffb5
[picocli DEBUG] Initializing params[0..*] in group [[FILE...] [-b=Build ID]... [-a=App Name]...]: setting scope to user object com.foo.AutoTune.Process$SourceOptions@48eff760 and initializing initial and default values
[picocli DEBUG] Set initial value for field java.io.File[] com.foo.AutoTune.Process$SourceOptions.analyzeReportFiles of type class [Ljava.io.File; to null.
[picocli DEBUG] defaultValue not defined for field java.io.File[] com.foo.AutoTune.Process$SourceOptions.analyzeReportFiles
[picocli DEBUG] Initializing --build-id=Build ID in group [[FILE...] [-b=Build ID]... [-a=App Name]...]: setting scope to user object com.foo.AutoTune.Process$SourceOptions@48eff760 and initializing initial and default values
[picocli DEBUG] Set initial value for field java.util.List<Integer> com.foo.AutoTune.Process$SourceOptions.analyzeBuildIds of type interface java.util.List to null.
[picocli DEBUG] defaultValue not defined for field java.util.List<Integer> com.foo.AutoTune.Process$SourceOptions.analyzeBuildIds
[picocli DEBUG] Initializing --app-name=App Name in group [[FILE...] [-b=Build ID]... [-a=App Name]...]: setting scope to user object com.foo.AutoTune.Process$SourceOptions@48eff760 and initializing initial and default values
[picocli DEBUG] Set initial value for field java.util.List<String> com.foo.AutoTune.Process$SourceOptions.analyzeAppNames of type interface java.util.List to null.
[picocli DEBUG] defaultValue not defined for field java.util.List<String> com.foo.AutoTune.Process$SourceOptions.analyzeAppNames
[picocli DEBUG] Initialization complete for group [[FILE...] [-b=Build ID]... [-a=App Name]...]
ArithmeticException: / by zero while processing argument at or before arg[0] 'analyze' in [analyze, x, y, z]: java.lang.ArithmeticException: / by zero
[picocli DEBUG] getTerminalWidth() executing command [tput, cols]
[picocli DEBUG] getTerminalWidth() parsing output:  238
[picocli DEBUG] getTerminalWidth() returning: 238 in 26.1ms

I resolved the exception by removing the ArgGroup from the subcommand. It would be nice to know if there is a way to make this work.

@LorenKeagle
Copy link
Author

In a previous ticket, we discussed a scenario for defining Help/Usage groupings separately from logical/validating groupings for exclusivity, etc. I wonder if this issue supports that idea.

@remkop remkop added theme: arg-group An issue or change related to argument groups type: bug 🐛 labels Oct 14, 2020
@remkop remkop added this to the 4.6 milestone Oct 14, 2020
remkop added a commit that referenced this issue Oct 14, 2020
@remkop
Copy link
Owner

remkop commented Oct 14, 2020

Thank you for raising this and thank you for the detailed report!
This allowed me to quickly reproduce the issue and fix it.

I pushed a fix to master.
This is quite a serious bug so I will probably roll out a bugfix release soon.
Many thanks!

@remkop remkop closed this as completed Oct 14, 2020
@remkop
Copy link
Owner

remkop commented Oct 14, 2020

In a previous ticket, we discussed a scenario for defining Help/Usage groupings separately from logical/validating groupings for exclusivity, etc. I wonder if this issue supports that idea.

Are you referring to #1147, specifically this comment?
Sorry, I closed that ticket after adding a section on Validation to the user manual, I thought that was what the ticket was about.

To reply to your comment, there is a trade-off. An arg group can be used for validation or for organizing/grouping options in the usage message, or for both if they match. But if the options you want to group in the usage message are not the same set of options you want to do validation on, then you cannot do both with a single group. In that case, my first idea would be to do the validation manually and do the usage message layout with the arg group.

If you want to explore this further I recommend opening a separate ticket for this.

@remkop
Copy link
Owner

remkop commented Oct 14, 2020

Picocli 4.5.2, which contains the fix for this issue, has been released.
Enjoy!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme: arg-group An issue or change related to argument groups type: bug 🐛
Projects
None yet
Development

No branches or pull requests

2 participants