shared/verbs: add flag VERB_OPTION_REQUIRED

This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2026-08-28 09:29:04 +02:00
parent 3cfe456323
commit 84d19dc8f9
3 changed files with 20 additions and 7 deletions
+9 -3
View File
@@ -175,10 +175,11 @@ static int verb_add_help_one(Table *table, const Verb *verb) {
assert(table);
assert(verb);
bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT);
_cleanup_free_ char *cell = NULL;
int r;
bool is_default = FLAGS_SET(verb->flags, VERB_DEFAULT);
/* The synopsis cell contains one line per entry in the argspec nulstr. An unset argspec is
* equivalent to a single empty specification. */
for (const char *spec = empty_to_null(verb->argspec);;) {
@@ -190,7 +191,8 @@ static int verb_add_help_one(Table *table, const Verb *verb) {
verb->verb,
spec ? " " : "",
strempty(spec),
is_default ? "]" : "");
is_default ? "]" : "",
FLAGS_SET(verb->flags, VERB_OPTION_REQUIRED) ? " OPTION" : "");
if (!s)
return log_oom();
@@ -588,12 +590,16 @@ int _command_print_verb_help(
if (cmd->pager_flags)
pager_open(*cmd->pager_flags);
const char *optionspec =
FLAGS_SET(verb->flags, VERB_OPTION_REQUIRED) ?
" OPTION…" : verb->option_namespace ? " [OPTION…]" : "";
/* If argspec is empty, print one line with no argspec. Use " " as placeholder for the empty spec. */
NULSTR_FOREACH(spec, verb->argspec ?: " \0") {
bool some = !streq(spec, " ");
_cleanup_free_ char *line = strjoin(
"[OPTION…] ", verb->verb,
verb->option_namespace ? " [OPTION…]" : "",
optionspec,
some ? " " : NULL,
some ? spec : NULL);
if (!line)
+5 -4
View File
@@ -28,10 +28,11 @@ typedef struct CommandDescription {
} CommandDescription;
typedef enum VerbFlags {
VERB_DEFAULT = 1 << 0, /* The verb to run if no verb is specified */
VERB_ONLINE_ONLY = 1 << 1, /* Just do nothing when running in chroot or offline */
VERB_COMMAND_MARKER = 1 << 2, /* Header entry with command description */
VERB_GROUP_MARKER = 1 << 3, /* Fake verb entry to separate groups */
VERB_DEFAULT = 1 << 0, /* The verb to run if no verb is specified */
VERB_ONLINE_ONLY = 1 << 1, /* Just do nothing when running in chroot or offline */
VERB_OPTION_REQUIRED = 1 << 2, /* The verb always requires an option to be present */
VERB_COMMAND_MARKER = 1 << 3, /* Header entry with command description */
VERB_GROUP_MARKER = 1 << 4, /* Fake verb entry to separate groups */
} VerbFlags;
/* Note: see the comment on struct Option in options.h for why _alignptr_ is required here. */
+6
View File
@@ -99,6 +99,9 @@ static const Verb introspect_verbs[] = {
.argspec = "FORM1\0FORM2…\0", .help = "Alpha verb", .option_namespace = "test-verbs-alpha" },
{ .verb = "beta", .min_args = VERB_ANY, .max_args = VERB_ANY, .dispatch = noop_dispatcher,
.help = "Beta verb" },
{ .verb = "gamma", .flags = VERB_OPTION_REQUIRED,
.min_args = VERB_ANY, .max_args = VERB_ANY, .dispatch = noop_dispatcher,
.help = "Gamma verb" },
{}
};
@@ -121,6 +124,9 @@ TEST(command_print_verb_help) {
ASSERT_OK(_command_print_verb_help(introspect_verbs, introspect_verbs + ELEMENTSOF(introspect_verbs) - 1,
introspect_options, introspect_options + ELEMENTSOF(introspect_options) - 1,
"beta"));
ASSERT_OK(_command_print_verb_help(introspect_verbs, introspect_verbs + ELEMENTSOF(introspect_verbs) - 1,
introspect_options, introspect_options + ELEMENTSOF(introspect_options) - 1,
"gamma"));
}
DEFINE_TEST_MAIN(LOG_INFO);