Repeating options with sub-options/arguments
See original GitHub issueI would like to add an option multiple times and add sub-options/parameters to it. In my scenario, I have a viewer application and, among other options and one positional argument, I would like to add datasets, somewhat like this:
viewer <positional-argument> \
--add-dataset --container=c1 --dataset=d1 \
--add-dataset --dataset=<d2 --type=label \
--fallback-container=fbc \ # use this as fallback, if no container is specified
[other options]
For this call, I would add two datasets to my container:
d1
in containerc1
(type is auto-detected from meta data)d2
in containerfbc
as label dataset
As far as I can tell, this is not (yet) supported in picocli (please correct me if I am wrong), and my - kind of hackish way - to achieve that, is to add an Option
@CommandLine.Option(names = arrayOf("--add-dataset"), arity = "+")
var addDatasetStrings: List<String> = mutableListOf()
that collects greedily all String
s that follow that option into a list. Users need to append a split-char after the last option of each --add-dataset
(I chose _
here). I then split the list at _
, and parse each of the sublists with a separate parser. This works well for me but it has a few downsides, as far as I can tell:
- I do not think it is possible to have overlapping arguments between the main arguments/options and the options/arguments for
--add-dataset
. - Need delimiter string (I used
_
) - help message for sub option (
--add-dataset
) not included automatically
I added my (kotlin) code and an invocation example at the very end of this comment for reference.
I think that this would be a useful addition. There are several issues that found that are related but not the same in my understanding:
Out of these, #454 seems to be the most closely related issues. For my real-world use case (viewer application with one positional argument, and more options), I could turn the one positional argument into an option and #454 could be a working solution for me. For anything that requires positional arguments, I would be concerned that the positional arguments might clash with the subcommands.
import org.apache.commons.lang3.builder.ToStringBuilder
import picocli.CommandLine
import java.util.concurrent.Callable
@CommandLine.Command
class AddDataset(val fallbackContainer: String?) : Callable<AddDataset> {
@CommandLine.Option(names = arrayOf("--container"))
var container: String? = null
@CommandLine.Option(names = arrayOf("--dataset"), required=true)
var dataset: String? = null
@CommandLine.Option(names = arrayOf("--help", "-h"), usageHelp = true)
var helpRequested = false
override fun call(): AddDataset {
return this
}
override fun toString(): String {
return ToStringBuilder(this)
.append("container", container?: fallbackContainer)
.append("dataset", dataset)
.toString()
}
}
class Args : Callable<List<AddDataset>> {
@CommandLine.Option(names = arrayOf("--default-container"))
var defaultContainer: String? = null
@CommandLine.Option(names = arrayOf("--add-dataset"), arity = "+")
var addDatasetStrings: List<String> = mutableListOf()
@CommandLine.Option(names = arrayOf("--help", "-h"), usageHelp = true)
var helpRequested = false
override fun call(): List<AddDataset> {
val indices = addDatasetStrings
.withIndex()
.filter { it.value.equals("_", ignoreCase = true) }
.map { it.index }
val subLists = mutableListOf<List<String>>()
var nextStartingIndex = 0
for (i in 0 until indices.size) {
subLists.add(addDatasetStrings.subList(nextStartingIndex, indices[i]))
nextStartingIndex = indices[i] + 1
}
return subLists.map { CommandLine.call(AddDataset(defaultContainer), *it.toTypedArray()) }
}
}
fun main(argv: Array<String>) {
val args = Args()
val datasets = CommandLine.call(args, *argv)
println(datasets)
}
$ Command --add-dataset --container=123 --dataset=456 _ --default-container=abracadabra --add-dataset --dataset=789 _
[AddDataset@5b87ed94[container=123,dataset=456], AddDataset@6e0e048a[container=abracadabra,dataset=789]]
Issue Analytics
- State:
- Created 5 years ago
- Comments:14 (9 by maintainers)
Picocli 4.0.0-alpha-1 has been released which includes support for repeating composite groups. See https://picocli.info/#_argument_groups for details.
Please try this and provide feedback. We can still make changes.
What do you think of the annotations API? What about the programmatic API? Does it work as expected? Are the input validation error messages correct and clear? Is the documentation clear and complete? Anything you want to change or improve? Any other feedback?
Thanks for raising this! I fixed one arg group validation bug in master, but found another one. Added a failing test but not able to fix it yet, I suspect the validation logic needs to be restructured.