diff --git a/tools/vsh.c b/tools/vsh.c index a4235905dc..96d6a5c238 100644 --- a/tools/vsh.c +++ b/tools/vsh.c @@ -244,11 +244,13 @@ static int disconnected; /* we may have been disconnected */ static int vshCmddefCheckInternals(vshControl *ctl, const vshCmdDef *cmd, - bool missingCompleters) + bool missingCompleters, + int brokenPositionals) { size_t i; bool seenOptionalOption = false; g_auto(virBuffer) complbuf = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) posbuf = VIR_BUFFER_INITIALIZER; /* in order to perform the validation resolve the alias first */ if (cmd->alias) { @@ -325,6 +327,28 @@ vshCmddefCheckInternals(vshControl *ctl, } } + if (brokenPositionals >= 0) { + switch (opt->type) { + case VSH_OT_INT: + case VSH_OT_STRING: + case VSH_OT_ARGV: + if (brokenPositionals == 0 || + brokenPositionals == opt->type) { + if (!(opt->flags & VSH_OFLAG_REQ_OPT) && !opt->positional) + virBufferStrcat(&posbuf, opt->name, ", ", NULL); + } + break; + + case VSH_OT_BOOL: + /* only name is completed */ + /* no point in completing numbers */ + case VSH_OT_ALIAS: + /* alias is handled in the referenced command */ + case VSH_OT_NONE: + break; + } + } + /* require that positional non-argv options are required */ if (opt->positional && !opt->required && opt->type != VSH_OT_ARGV) { vshError(ctl, "positional argument '%s' of command '%s' must be required", @@ -427,10 +451,15 @@ vshCmddefCheckInternals(vshControl *ctl, } virBufferTrim(&complbuf, ", "); + virBufferTrim(&posbuf, ", "); if (missingCompleters && virBufferUse(&complbuf) > 0) vshPrintExtra(ctl, "%s: %s\n", cmd->name, virBufferCurrentContent(&complbuf)); + if (virBufferUse(&posbuf)) { + vshPrintExtra(ctl, "%s: %s\n", cmd->name, virBufferCurrentContent(&posbuf)); + } + return 0; } @@ -3336,6 +3365,11 @@ const vshCmdOptDef opts_selftest[] = { .type = VSH_OT_BOOL, .help = N_("output help for each command") }, + {.name = "broken-positionals", + .type = VSH_OT_INT, + .flags = VSH_OFLAG_REQ_OPT, + .help = N_("debug positional args") + }, {.name = NULL} }; const vshCmdInfo info_selftest = { @@ -3350,6 +3384,9 @@ cmdSelfTest(vshControl *ctl, const vshCmd *cmd) const vshCmdDef *def; bool completers = vshCommandOptBool(cmd, "completers-missing"); bool dumphelp = vshCommandOptBool(cmd, "dump-help"); + int brokenPositionals = -1; + + ignore_value(vshCommandOptInt(ctl, cmd, "broken-positionals", &brokenPositionals)); for (grp = cmdGroups; grp->name; grp++) { for (def = grp->commands; def->name; def++) { @@ -3357,7 +3394,7 @@ cmdSelfTest(vshControl *ctl, const vshCmd *cmd) if (dumphelp && !def->alias) vshCmddefHelp(def); - if (vshCmddefCheckInternals(ctl, def, completers) < 0) + if (vshCmddefCheckInternals(ctl, def, completers, brokenPositionals) < 0) return false; } }