]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
virsh: add option aliases
authorEric Blake <eblake@redhat.com>
Fri, 2 Mar 2012 18:01:15 +0000 (11:01 -0700)
committerEric Blake <eblake@redhat.com>
Thu, 8 Mar 2012 01:24:44 +0000 (18:24 -0700)
In the past, we have created some virsh options with less-than-stellar
names.  For back-compat reasons, those names must continue to parse,
but we don't want to document them in help output.  This introduces
a new option type, an alias, which points to a canonical option name
later in the option list.

I'm actually quite impressed that our code has already been factored
to do all option parsing through common entry points, such that I
got this added in relatively few lines of code!

* tools/virsh.c (VSH_OT_ALIAS): New option type.
(opts_echo): Hook up an alias, for easy testing.
(vshCmddefOptParse, vshCmddefHelp, vshCmddefGetOption): Allow for
aliases.
* tools/virsh.pod (NOTES): Document promise of back-compat.
* tests/virshtest.c (mymain): Test new feature.

tests/virshtest.c
tools/virsh.c
tools/virsh.pod

index 6474c192214b350f6731a939e96b022d3727638d..87b1336239974aae307ba4e4f52dcdc023646cd9 100644 (file)
@@ -386,6 +386,12 @@ mymain(void)
     DO_TEST(30, "--shell a\n",
             "echo \t '-'\"-\" \t --shell \t a");
 
+    /* Tests of alias handling.  */
+    DO_TEST(31, "hello\n", "echo", "--string", "hello");
+    DO_TEST(32, "hello\n", "echo --string hello");
+    DO_TEST(33, "hello\n", "echo", "--str", "hello");
+    DO_TEST(34, "hello\n", "echo --str hello");
+
 # undef DO_TEST
 
     VIR_FREE(custom_uri);
index 70a932bb1bd18fb75182e7883ca481d655bf7010..f4c5cfa4195a6e62705c39b1449ee75ec9a63d42 100644 (file)
@@ -138,7 +138,8 @@ typedef enum {
     VSH_OT_STRING,   /* optional string option */
     VSH_OT_INT,      /* optional or mandatory int option */
     VSH_OT_DATA,     /* string data (as non-option) */
-    VSH_OT_ARGV      /* remaining arguments */
+    VSH_OT_ARGV,     /* remaining arguments */
+    VSH_OT_ALIAS,    /* alternate spelling for a later argument */
 } vshCmdOptType;
 
 /*
@@ -190,7 +191,8 @@ typedef struct {
     const char *name;           /* the name of option, or NULL for list end */
     vshCmdOptType type;         /* option type */
     unsigned int flags;         /* flags */
-    const char *help;           /* non-NULL help string */
+    const char *help;           /* non-NULL help string; or for VSH_OT_ALIAS
+                                 * the name of a later public option */
 } vshCmdOptDef;
 
 /*
@@ -15363,6 +15365,7 @@ static const vshCmdInfo info_echo[] = {
 static const vshCmdOptDef opts_echo[] = {
     {"shell", VSH_OT_BOOL, 0, N_("escape for shell use")},
     {"xml", VSH_OT_BOOL, 0, N_("escape for XML use")},
+    {"str", VSH_OT_ALIAS, 0, "string"},
     {"string", VSH_OT_ARGV, 0, N_("arguments to echo")},
     {NULL, 0, 0, NULL}
 };
@@ -17411,6 +17414,18 @@ vshCmddefOptParse(const vshCmdDef *cmd, uint32_t *opts_need_arg,
                 return -1; /* bool options can't be mandatory */
             continue;
         }
+        if (opt->type == VSH_OT_ALIAS) {
+            int j;
+            if (opt->flags || !opt->help)
+                return -1; /* alias options are tracked by the original name */
+            for (j = i + 1; cmd->opts[j].name; j++) {
+                if (STREQ(opt->help, cmd->opts[j].name))
+                    break;
+            }
+            if (!cmd->opts[j].name)
+                return -1; /* alias option must map to a later option name */
+            continue;
+        }
         if (opt->flags & VSH_OFLAG_REQ_OPT) {
             if (opt->flags & VSH_OFLAG_REQ)
                 *opts_required |= 1 << i;
@@ -17442,6 +17457,10 @@ vshCmddefGetOption(vshControl *ctl, const vshCmdDef *cmd, const char *name,
         const vshCmdOptDef *opt = &cmd->opts[i];
 
         if (STREQ(opt->name, name)) {
+            if (opt->type == VSH_OT_ALIAS) {
+                name = opt->help;
+                continue;
+            }
             if ((*opts_seen & (1 << i)) && opt->type != VSH_OT_ARGV) {
                 vshError(ctl, _("option --%s already seen"), name);
                 return NULL;
@@ -17620,6 +17639,9 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
                             : _("[<%s>]...");
                     }
                     break;
+                case VSH_OT_ALIAS:
+                    /* aliases are intentionally undocumented */
+                    continue;
                 default:
                     assert(0);
                 }
@@ -17661,6 +17683,8 @@ vshCmddefHelp(vshControl *ctl, const char *cmdname)
                              shortopt ? _("[--%s] <string>") : _("<%s>"),
                              opt->name);
                     break;
+                case VSH_OT_ALIAS:
+                    continue;
                 default:
                     assert(0);
                 }
index 1eb9499e3c2086707932f42e389b699f9f965dfe..1e38680e7f857c4a735245126c01151f8551f35a 100644 (file)
@@ -115,6 +115,12 @@ program returned, may not mean the action is complete and you
 must poll periodically to detect that the guest completed the
 operation.
 
+B<virsh> strives for backward compatibility.  Although the B<help>
+command only lists the preferred usage of a command, if an older
+version of B<virsh> supported an alternate spelling of a command or
+option (such as I<--tunnelled> instead of I<--tunneled>), then
+scripts using that older spelling will continue to work.
+
 =head1 GENERIC COMMANDS
 
 The following commands are generic i.e. not specific to a domain.