如何支持所有(或部分)命令和子命令的共享选项?例如,如果最终用户在命令行参数的任何位置提供
--stacktrace
,则打印的任何错误都将包括堆栈跟踪。
我们可以使用 Mixin 来定义一个布尔值
--stacktrace
选项,并将此 Mixin 包含在所有(子)命令中,或者使用继承并让所有命令子类化一个定义布尔值 --stacktrace
选项的类,但无论哪种方式,将为每个命令定义一个单独的布尔选项。哪个选项为真取决于用户在 args 中放置 --stacktrace
的位置,因此确定是否提供了 --stacktrace
将意味着遍历所有父命令并查看是否有任何为真。
如果有更方便的方法来检测用户是否指定了这样的共享选项,那就太好了
更新:使用 picocli 4.3 有两种方法可以完成此操作:
实现此目的的一种方法是使布尔字段静态:
class Shared {
@Option(names = "--stacktrace")
static boolean stacktrace;
}
您仍然需要子类化或使用 mixin 在每个命令和子命令中定义此选项:
@Command(subcommands = {Subcommand1.class, Subcommand2.class /*, ...*/}
class MyCommand {
@Mixin
Shared shared = new Shared();
// ...
}
@Command(name = "subcommand1")
class Subcommand1 {
@Mixin
Shared shared = new Shared();
// ...
}
这种设计的好处是现在应用程序可以在一个地方检测最终用户是否指定了
--stacktrace
:静态布尔字段:
public static void main(String... args) {
assert Shared.stacktrace == false;
MyCommand myCommand = new MyCommand();
CommandLine.parseArgs(myCommand, "subcommand1", "--stacktrace");
assert Shared.stacktrace == true;
}
我通过没有运气的继承选项尝试了这个,也没有运气。与此 Mixin 技术相同的错误:“缺少必需的子命令”
internal class SharedGroup {
var mixin: SharedMixin? = null
@CommandLine.Option(
names = ["-m", "--markerFile"],
required = true,
description = [
"marker files",
],
defaultValue = "something",
showDefaultValue = CommandLine.Help.Visibility.ALWAYS,
scope = CommandLine.ScopeType.INHERIT,
)
fun setMarkerFile(value: String) {
mixin?.markerFiles = value.split(",")
}
}
@CommandLine.Command(mixinStandardHelpOptions = true) // add --help and --version to all commands that have this mixin
internal class SharedMixin {
@CommandLine.Spec(MIXEE)
var mixee: CommandLine.Model.CommandSpec? = null
private var group: SharedGroup? = null
@CommandLine.ArgGroup(heading = "%nShared options that work on every command:%n", validate = false)
fun setGroup(group: SharedGroup) {
this.group = group
group.mixin = this
}
var markerFiles: List<String>
get() = rootMixin().markerFiles
set(value) {
rootMixin().markerFiles = value
}
private fun rootMixin(): SharedMixin {
for (mixinCommand in mixee?.root()?.mixins()?.values!!) {
val obj: Any = mixinCommand.userObject()
if (obj is SharedMixin) {
return obj
}
}
error("Root command does not have a @Mixin of type SharedMixin")
}
}```