[libvirt] [PATCH v2 0/9] virsh: More intelligent auto-completion

Original series + some fixes/improvements. Tomas Meszaros (9): virsh: C99 style for info_domfstrim and opts_lxc_enter_namespace virsh: Add vshCmdCompleter and vshOptCompleter virsh: Improve readline generators and readline completion virsh: Add vshDomainCompleter virsh: Add vshSuspendTargetCompleter virsh: Add vshRebootShutdownModeCompleter virsh: Add completer functions to domManaggementCmds virsh: Add completer functions to snapshotCmds virsh: Add completer functions to domMonitoringCmds tools/virsh-domain-monitor.c | 32 ++- tools/virsh-domain.c | 248 ++++++++++++++++----- tools/virsh-snapshot.c | 45 +++- tools/virsh.c | 504 +++++++++++++++++++++++++++++++++++++++++-- tools/virsh.h | 11 + 5 files changed, 748 insertions(+), 92 deletions(-) -- 1.8.3.1

Change info_domfstrim and opts_lxc_enter_namespace initialization style to C99. --- tools/virsh-domain.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index b29f934..5d4913d 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -7903,10 +7903,21 @@ static const vshCmdInfo info_lxc_enter_namespace[] = { }; static const vshCmdOptDef opts_lxc_enter_namespace[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"noseclabel", VSH_OT_BOOL, 0, N_("Do not change process security label")}, - {"cmd", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("namespace")}, - {NULL, 0, 0, NULL} + {.name = "domain", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, + .help = N_("domain name, id or uuid") + }, + {.name = "noseclabel", + .type = VSH_OT_BOOL, + .help = N_("Do not change process security label") + }, + {.name = "cmd", + .type = VSH_OT_ARGV, + .flags = VSH_OFLAG_REQ, + .help = N_("namespace") + }, + {.name = NULL} }; static bool @@ -10290,7 +10301,7 @@ static const vshCmdOptDef opts_domfstrim[] = { .type = VSH_OT_DATA, .help = N_("which mount point to trim") }, - {NULL, 0, 0, NULL} + {.name = NULL} }; static bool cmdDomFSTrim(vshControl *ctl, const vshCmd *cmd) -- 1.8.3.1

On 08/20/2013 02:02 PM, Tomas Meszaros wrote:
Change info_domfstrim and opts_lxc_enter_namespace initialization style to C99. --- tools/virsh-domain.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
ACK. I wonder if it is worth adding a 'make syntax-check' test that enforces this style within virsh files, but don't have a good suggestion for a foolproof regex that would detect C89 initialization. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

completer and completer_flags added to the _vshCmdDef and _vshCmdOptDef structures so it will be possible for completion generators to conveniently call completer functions with desired flags. --- tools/virsh.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/virsh.h b/tools/virsh.h index 466ca2d..064acde 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -147,6 +147,9 @@ typedef struct _vshCmdOptDef vshCmdOptDef; typedef struct _vshControl vshControl; typedef struct _vshCtrlData vshCtrlData; +typedef char **(*vshCmdCompleter)(unsigned int flags); +typedef char **(*vshOptCompleter)(unsigned int flags); + /* * vshCmdInfo -- name/value pair for information about command * @@ -168,6 +171,8 @@ struct _vshCmdOptDef { unsigned int flags; /* flags */ const char *help; /* non-NULL help string; or for VSH_OT_ALIAS * the name of a later public option */ + vshOptCompleter completer; /* option completer */ + unsigned int completer_flags; /* option completer flags */ }; /* @@ -199,6 +204,8 @@ struct _vshCmdDef { const vshCmdOptDef *opts; /* definition of command options */ const vshCmdInfo *info; /* details about command */ unsigned int flags; /* bitwise OR of VSH_CMD_FLAG */ + vshCmdCompleter completer; /* command completer */ + unsigned int completer_flags; /* command completer flags */ }; /* -- 1.8.3.1

* vshMalloc is now used in vshDetermineCommandName * vshStrdup instead of vshMalloc + snprintf * joined if's in vshReadlineOptionsCompletionGenerator --- tools/virsh.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 373 insertions(+), 22 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 15f529e..af6e939 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2508,6 +2508,25 @@ vshCloseLogFile(vshControl *ctl) * ----------------- */ +static const vshCmdDef * +vshDetermineCommandName(void) +{ + const vshCmdDef *cmd = NULL; + char *p; + char *cmdname; + + if (!(p = strchr(rl_line_buffer, ' '))) + return NULL; + + cmdname = vshMalloc(NULL, (p - rl_line_buffer) + 1); + memcpy(cmdname, rl_line_buffer, p - rl_line_buffer); + + cmd = vshCmddefSearch(cmdname); + VIR_FREE(cmdname); + + return cmd; +} + /* * Generator function for command completion. STATE lets us * know whether to start from scratch; without any state @@ -2555,25 +2574,14 @@ vshReadlineCommandGenerator(const char *text, int state) static char * vshReadlineOptionsGenerator(const char *text, int state) { - static int list_index, len; static const vshCmdDef *cmd = NULL; + static int list_index, len; const char *name; if (!state) { - /* determine command name */ - char *p; - char *cmdname; - - if (!(p = strchr(rl_line_buffer, ' '))) - return NULL; - - cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1); - memcpy(cmdname, rl_line_buffer, p - rl_line_buffer); - - cmd = vshCmddefSearch(cmdname); + cmd = vshDetermineCommandName(); list_index = 0; len = strlen(text); - VIR_FREE(cmdname); } if (!cmd) @@ -2605,22 +2613,365 @@ vshReadlineOptionsGenerator(const char *text, int state) return NULL; } +/* + * Generator function for command completion, but unlike + * the vshRaadlineCommandGenerator which completes command name, this function + * provides more advanced completion for commands by calling specific command + * completers (e.g. vshDomainCompleter). + */ +static char * +vshReadlineCommandCompletionGenerator(const char *text, int state) +{ + static const vshCmdDef *cmd = NULL; + static int list_index, len; + char **completed_names = NULL; + char *name; + + if (!state) { + cmd = vshDetermineCommandName(); + list_index = 0; + len = strlen(text); + } + + if (!cmd) + return NULL; + + if (!cmd->completer) + return NULL; + + completed_names = cmd->completer(cmd->completer_flags); + + if (!completed_names) + return NULL; + + while ((name = completed_names[list_index])) { + char *res; + list_index++; + + if (STRNEQLEN(name, text, len)) + /* Skip irrelevant names */ + continue; + + res = vshStrdup(NULL, name); + VIR_FREE(name); + return res; + } + VIR_FREE(completed_names); + + return NULL; +} + +/* + * Generator function for command option completion. Provides advances + * completion for command options. + */ +static char * +vshReadlineOptionsCompletionGenerator(const char *text ATTRIBUTE_UNUSED, + int state ATTRIBUTE_UNUSED) +{ + static const vshCmdDef *cmd = NULL; + static const vshCmdOptDef *opt = NULL; + static int list_index, len; + unsigned long int opt_index = 0; + size_t i; + char **completed_names = NULL; + char *name; + char *ptr = NULL; + + if (!state) { + cmd = vshDetermineCommandName(); + list_index = 0; + len = strlen(text); + } + + if (!cmd) + return NULL; + + if (!cmd->opts) + return NULL; + + for (i = 0; cmd->opts[i].name; i++) { + if ((ptr = strstr(rl_line_buffer, cmd->opts[i].name)) && + (opt_index < (ptr - rl_line_buffer))) { + opt_index = ptr - rl_line_buffer; + opt = &cmd->opts[i]; + } + } + + if (!opt) + return NULL; + + if (!opt->completer) + return NULL; + + completed_names = opt->completer(opt->completer_flags); + + if (!completed_names) + return NULL; + + while ((name = completed_names[list_index])) { + char *res; + list_index++; + + if (STRNEQLEN(name, text, len)) + /* Skip irrelevant names */ + continue; + + res = vshStrdup(NULL, name); + VIR_FREE(name); + return res; + } + VIR_FREE(completed_names); + + return NULL; +} + +/* + * Returns current valid command name present in the rl_line_buffer. + */ +static char * +vshCurrentCmd(void) +{ + const char *name; + const vshCmdGrp *grp; + const vshCmdDef *cmds; + size_t grp_list_index, cmd_list_index; + char *found_cmd = NULL; + char *rl_copy = NULL; + char *pch; + + grp_list_index = 0; + cmd_list_index = 0; + grp = cmdGroups; + + while (grp[grp_list_index].name) { + cmds = grp[grp_list_index].commands; + + if (cmds[cmd_list_index].name) { + while ((name = cmds[cmd_list_index].name)) { + cmd_list_index++; + + if (VIR_STRDUP(rl_copy, rl_line_buffer) < 0) + return NULL; + + char *saveptr; + pch = strtok_r(rl_copy, " ", &saveptr); + + while (pch != NULL) { + if (STREQ(pch, name)) + if (VIR_STRDUP(found_cmd, name) < 0) + goto cleanup; + pch = strtok_r(NULL, " ", &saveptr); + } + } + } else { + cmd_list_index = 0; + grp_list_index++; + } + } + + if (!found_cmd) + goto cleanup; + + return found_cmd; + +cleanup: + VIR_FREE(rl_copy); + return NULL; +} + +/* + * Returns current valid command option name present in the rl_line_buffer. + */ +static char * +vshCurrentOpt(const char *cmd_name) +{ + const vshCmdDef *cmd = NULL; + const char *name; + unsigned long int opt_index = 0; + size_t cmd_opt_list_index; + char *found_opt = NULL; + char *ptr = NULL; + + if (!cmd_name) + return NULL; + + cmd = vshCmddefSearch(cmd_name); + + if (!cmd) + return NULL; + + if (!cmd->opts) + return NULL; + + cmd_opt_list_index = 0; + + while ((name = cmd->opts[cmd_opt_list_index].name)) { + cmd_opt_list_index++; + + if ((ptr = strstr(rl_line_buffer, name))) { + if (opt_index < (ptr - rl_line_buffer)) { + opt_index = ptr - rl_line_buffer; + if (VIR_STRDUP(found_opt, name) < 0) + return NULL; + } + } + } + + if (!found_opt) + return NULL; + + return found_opt; +} + +/* + * Returns name of the command completion currently present in the rl_line_buffer. + */ +static char* +vshCurrentCmdCom(const char *cmd_name) +{ + const vshCmdDef *cmd = NULL; + size_t i; + char **completed_names = NULL; + char *found_cmd_com = NULL; + + if (!cmd_name) + return NULL; + + cmd = vshCmddefSearch(cmd_name); + + if (!cmd) + return NULL; + + if (!cmd->completer) + return NULL; + + completed_names = cmd->completer(cmd->completer_flags); + + if (!completed_names) + return NULL; + + for (i = 0; completed_names[i]; i++) { + if (strstr(rl_line_buffer, completed_names[i])) { + if (VIR_STRDUP(found_cmd_com, completed_names[i]) < 0) + return NULL; + } + } + + if (!found_cmd_com) + return NULL; + + return found_cmd_com; +} + +/* + * Returns name of the option completion currently present in the rl_line_buffer. + */ +static char * +vshCurrentOptCom(const char *cmd_name) +{ + const vshCmdDef *cmd = NULL; + const vshCmdOptDef *opt = NULL; + unsigned long int opt_index = 0; + size_t i; + char **completed_names = NULL; + char *found_opt_com = NULL; + char *ptr = NULL; + + if (!cmd_name) + return NULL; + + cmd = vshCmddefSearch(cmd_name); + + if (!cmd) + return NULL; + + if (!cmd->opts) + return NULL; + + for (i = 0; cmd->opts[i].name; i++) { + if ((ptr = strstr(rl_line_buffer, cmd->opts[i].name))) { + if (opt_index < (ptr - rl_line_buffer)) { + opt_index = ptr - rl_line_buffer; + opt = &cmd->opts[i]; + } + } + } + + if (!opt) + return NULL; + + if (!opt->completer) + return NULL; + + completed_names = opt->completer(opt->completer_flags); + + if (!completed_names) + return NULL; + + for (i = 0; completed_names[i]; i++) { + if (strstr(rl_line_buffer, completed_names[i])) { + if (VIR_STRDUP(found_opt_com, completed_names[i]) < 0) + return NULL; + } + } + + if (!found_opt_com) + return NULL; + + return found_opt_com; +} + static char ** -vshReadlineCompletion(const char *text, int start, - int end ATTRIBUTE_UNUSED) +vshReadlineCompletion(const char *text, int start, int end ATTRIBUTE_UNUSED) { - char **matches = (char **) NULL; + const char *cmd = vshCurrentCmd(); + const char *cmd_com = vshCurrentCmdCom(cmd); + const char *opt = vshCurrentOpt(cmd); + const char *opt_com = vshCurrentOptCom(cmd); + char **matches = (char **)NULL; - if (start == 0) - /* command name generator */ + if (start == 0) { + /* Command name generator. */ matches = rl_completion_matches(text, vshReadlineCommandGenerator); - else - /* commands options */ - matches = rl_completion_matches(text, vshReadlineOptionsGenerator); + } else { + /* Command completer, commands options and commands options completer + * generators. + */ + if (strstr(text, "-")) { + /* When user wants to see options. */ + matches = rl_completion_matches(text, vshReadlineOptionsGenerator); + } else if (!cmd_com && !opt && !opt_com) { + matches = rl_completion_matches(text, vshReadlineCommandCompletionGenerator); + if (!matches) + matches = rl_completion_matches(text, vshReadlineOptionsGenerator); + } else if (cmd_com && !opt && !opt_com) { + matches = rl_completion_matches(text, vshReadlineOptionsGenerator); + } else if (cmd_com && opt && !opt_com) { + matches = rl_completion_matches(text, vshReadlineOptionsCompletionGenerator); + if (!matches) + matches = rl_completion_matches(text, vshReadlineOptionsGenerator); + } else if (!cmd_com && opt && !opt_com) { + matches = rl_completion_matches(text, vshReadlineCommandCompletionGenerator); + if (!matches) + matches = rl_completion_matches(text, vshReadlineOptionsCompletionGenerator); + if (!matches) + matches = rl_completion_matches(text, vshReadlineOptionsGenerator); + } else if (!cmd_com && opt && opt_com) { + matches = rl_completion_matches(text, vshReadlineOptionsGenerator); + } else if (cmd_com && opt && opt_com) { + matches = rl_completion_matches(text, vshReadlineOptionsGenerator); + } + } + + VIR_FREE(cmd); + VIR_FREE(cmd_com); + VIR_FREE(opt); + VIR_FREE(opt_com); + return matches; } - static int vshReadlineInit(vshControl *ctl) { -- 1.8.3.1

On 20.08.2013 22:02, Tomas Meszaros wrote:
* vshMalloc is now used in vshDetermineCommandName * vshStrdup instead of vshMalloc + snprintf * joined if's in vshReadlineOptionsCompletionGenerator --- tools/virsh.c | 395 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 373 insertions(+), 22 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index 15f529e..af6e939 100644 --- a/tools/virsh.c +++ b/tools/virsh.c
@@ -2605,22 +2613,365 @@ vshReadlineOptionsGenerator(const char *text, int state) return NULL; }
+/* + * Generator function for command completion, but unlike + * the vshRaadlineCommandGenerator which completes command name, this function
s/vshRaadlineCommandGenerator/tools/vshReadlineCommandGenerator/ (Raad vs Read).
+ * provides more advanced completion for commands by calling specific command + * completers (e.g. vshDomainCompleter). + */ +static char * +vshReadlineCommandCompletionGenerator(const char *text, int state) +{ + static const vshCmdDef *cmd = NULL;
+/* + * Returns current valid command option name present in the rl_line_buffer. + */ +static char * +vshCurrentOpt(const char *cmd_name) +{ + const vshCmdDef *cmd = NULL; + const char *name; + unsigned long int opt_index = 0; + size_t cmd_opt_list_index; + char *found_opt = NULL; + char *ptr = NULL; + + if (!cmd_name) + return NULL; + + cmd = vshCmddefSearch(cmd_name); + + if (!cmd) + return NULL; + + if (!cmd->opts) + return NULL; + + cmd_opt_list_index = 0; + + while ((name = cmd->opts[cmd_opt_list_index].name)) { + cmd_opt_list_index++; + + if ((ptr = strstr(rl_line_buffer, name))) { + if (opt_index < (ptr - rl_line_buffer)) { + opt_index = ptr - rl_line_buffer; + if (VIR_STRDUP(found_opt, name) < 0) + return NULL; + } + } + } + + if (!found_opt) + return NULL;
this if is useless.
+ + return found_opt; +} +
Michal

* global variable __my_conn renamed to vshConn * @name is now const char * * label cleanup renamed to error --- tools/virsh.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.h | 2 ++ 2 files changed, 55 insertions(+) diff --git a/tools/virsh.c b/tools/virsh.c index af6e939..13c27df 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -88,6 +88,8 @@ static char *progname; static const vshCmdGrp cmdGroups[]; +virConnectPtr *vshConn; + /* Bypass header poison */ #undef strdup @@ -2503,6 +2505,51 @@ vshCloseLogFile(vshControl *ctl) #ifdef USE_READLINE +/* ------------- + * Completers + * ------------- + */ + +char ** +vshDomainCompleter(unsigned int flags) +{ + virDomainPtr *domains; + size_t i; + char **names = NULL; + int ndomains; + + if (!*vshConn) + return NULL; + + ndomains = virConnectListAllDomains(*vshConn, &domains, flags); + + if (ndomains < 0) + return NULL; + + names = vshMalloc(NULL, sizeof(char *) * (ndomains + 1)); + + if (!names) + return NULL; + + for (i = 0; i < ndomains; i++) { + const char *name = virDomainGetName(domains[i]); + if (VIR_STRDUP(names[i], name) < 0) { + virDomainFree(domains[i]); + goto error; + } + virDomainFree(domains[i]); + } + names[i] = NULL; + VIR_FREE(domains); + return names; + +error: + for (i = 0; names[i]; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + return NULL; +} + /* ----------------- * Readline stuff * ----------------- @@ -3510,6 +3557,7 @@ main(int argc, char **argv) ctl->debug = VSH_DEBUG_DEFAULT; ctl->escapeChar = "^]"; /* Same default as telnet */ + vshConn = &ctl->conn; if (!setlocale(LC_ALL, "")) { perror("setlocale"); @@ -3571,6 +3619,11 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } + /* Need to connect immediately after start in order to provide + * autocompletion for the very first command. + */ + vshReconnect(ctl); + do { const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW; ctl->cmdstr = diff --git a/tools/virsh.h b/tools/virsh.h index 064acde..68414e4 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -255,6 +255,8 @@ struct _vshCmdGrp { const vshCmdDef *commands; }; +char **vshDomainCompleter(unsigned int flags); + void vshError(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3); void vshOpenLogFile(vshControl *ctl); -- 1.8.3.1

On 08/20/2013 02:02 PM, Tomas Meszaros wrote: Your commit message should give a brief summary of your change and why it is important ("Add vshDomainCompleter" is the what, but you didn't spell out the why - something along the lines of "future patches will use this to improve readline completion").
* global variable __my_conn renamed to vshConn * @name is now const char * * label cleanup renamed to error
These three lines are a changelog from your v1 patch, and not the "why" you are making the change. In fact, since this patch does not mention "__my_conn", no one will understand why you mentioned it at all in the commit message. It is information that belongs better...
---
...here, after the --- separator, which is where 'git am' interprets the break between the "why" of the commit message that belongs in git history, vs. the "help" that is useful to list reviewers now, but has no bearing on a future person reading git history.
+ + names = vshMalloc(NULL, sizeof(char *) * (ndomains + 1)); + + if (!names) + return NULL;
Dead code. names is non-null, thanks to vshMalloc.
+error: + for (i = 0; names[i]; i++) + VIR_FREE(names[i]); + VIR_FREE(names);
Simpler to use virStringFreeList(names) here, instead of inlining the iteration.
@@ -3510,6 +3557,7 @@ main(int argc, char **argv) ctl->debug = VSH_DEBUG_DEFAULT; ctl->escapeChar = "^]"; /* Same default as telnet */
+ vshConn = &ctl->conn;
if (!setlocale(LC_ALL, "")) { perror("setlocale"); @@ -3571,6 +3619,11 @@ main(int argc, char **argv) exit(EXIT_FAILURE); }
+ /* Need to connect immediately after start in order to provide + * autocompletion for the very first command. + */ + vshReconnect(ctl); +
I'm not a fan of this. We worked hard to get some commands (like 'virsh echo') to NOT need a connection, and this would be undoing that work. I think we should NOT autoconnect UNTIL we reach the point that completion is being attempted on something where a connection is needed to get the completer list, rather than this code which autoconnects regardless of whether we need completion. Having 'virsh echo' avoid an autoconnect is useful - it can be used to prove whether virsh itself is working or has a problem such as a missing .so, without complicating the diagnosis with a question of whether it is a bad default connection to blame. Also, at some point in your series, you will want to introduce a new virsh command whose job is to perform the completion of its arguments. That way, we can have auto-completion both within the virsh interactive shell, and from bash, while only having to maintain it in one place. That is, if I type: $ virsh virsh> start a<TAB> I'm using the interactive virsh completion to list domains starting with a; meanwhile, if I type: $ virsh start a<TAB> then the bash completion handler would call: $ virsh complete start a under the hood, so that virsh outputs the list of names that can be fed back to the bash completion hooks. The bash completion routine is then dead simple - forward all completions to virsh itself. I don't want to have to teach bash completion routines which commands expect a domain, nor how to generate its own domain listing, when virsh already has that code. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 08/20/2013 02:30 PM, Eric Blake wrote:
I'm not a fan of this. We worked hard to get some commands (like 'virsh echo') to NOT need a connection, and this would be undoing that work. I think we should NOT autoconnect UNTIL we reach the point that completion is being attempted on something where a connection is needed to get the completer list, rather than this code which autoconnects regardless of whether we need completion. Having 'virsh echo' avoid an autoconnect is useful - it can be used to prove whether virsh itself is working or has a problem such as a missing .so, without complicating the diagnosis with a question of whether it is a bad default connection to blame.
More along that line of thought: If I type: $ virsh virsh> e<TAB> I want a completion to list all commands that start with 'e'; one of those commands is 'echo', which does not need a connection. Therefore, if I use the shell: $ virsh e<TAB> and the shell uses, under the hood, $ virsh complete e that particular completion attempt should NOT attempt an autoconnect, because it is not completing on any information that requires a connection. autoconnect to qemu:///session can be noticeably time-consuming on the first time it is attempted. Although the session server tends to stick around for a few seconds after the last connection, so that future connection attempts in a short timeframe are serviced faster, you still don't want to pay the penalty for a delay for the first autoconnect until it is mandatory for the completion at hand. Whereas an interactive virsh keeps one connection open across multiple uses, the bash completion routines will be invoking a different instance of 'virsh' for every <TAB> hit on the shell command line, where we want each instance to be as fast as possible. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 08/20/13 22:40, Eric Blake wrote:
On 08/20/2013 02:30 PM, Eric Blake wrote:
I'm not a fan of this. We worked hard to get some commands (like 'virsh echo') to NOT need a connection, and this would be undoing that work. I think we should NOT autoconnect UNTIL we reach the point that completion is being attempted on something where a connection is needed to get the completer list, rather than this code which autoconnects regardless of whether we need completion. Having 'virsh echo' avoid an autoconnect is useful - it can be used to prove whether virsh itself is working or has a problem such as a missing .so, without complicating the diagnosis with a question of whether it is a bad default connection to blame.
More along that line of thought:
If I type:
$ virsh virsh> e<TAB>
I want a completion to list all commands that start with 'e'; one of those commands is 'echo', which does not need a connection.
Therefore, if I use the shell:
$ virsh e<TAB>
and the shell uses, under the hood,
$ virsh complete e
that particular completion attempt should NOT attempt an autoconnect, because it is not completing on any information that requires a connection. autoconnect to qemu:///session can be noticeably time-consuming on the first time it is attempted. Although the session server tends to stick around for a few seconds after the last connection, so that future connection attempts in a short timeframe are serviced faster, you still don't want to pay the penalty for a delay for the first autoconnect until it is mandatory for the completion at hand. Whereas an interactive virsh keeps one connection open across multiple uses, the bash completion routines will be invoking a different instance of 'virsh' for every <TAB> hit on the shell command line, where we want each instance to be as fast as possible.
Also if a user decides to use a ssh-tunneled connection as default but will not use ssh keys for authentication each completion attempt will request the password from the user, which might get annoying. Peter

On 20.08.2013 22:02, Tomas Meszaros wrote:
* global variable __my_conn renamed to vshConn * @name is now const char * * label cleanup renamed to error --- tools/virsh.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.h | 2 ++ 2 files changed, 55 insertions(+)
You can be adding .copleter = vshDomainCompleter in this patch as well. That is squash parts of 7/9, 8/9 and 9/9 which add the vshDomainCompleter into this patch. In the end, They will probably end up being empty, but that is okay.
diff --git a/tools/virsh.c b/tools/virsh.c index af6e939..13c27df 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -88,6 +88,8 @@ static char *progname;
static const vshCmdGrp cmdGroups[];
+virConnectPtr *vshConn; + /* Bypass header poison */ #undef strdup
@@ -2503,6 +2505,51 @@ vshCloseLogFile(vshControl *ctl)
#ifdef USE_READLINE
+/* ------------- + * Completers + * ------------- + */ + +char ** +vshDomainCompleter(unsigned int flags) +{ + virDomainPtr *domains; + size_t i; + char **names = NULL; + int ndomains; + + if (!*vshConn) + return NULL; + + ndomains = virConnectListAllDomains(*vshConn, &domains, flags); + + if (ndomains < 0) + return NULL; + + names = vshMalloc(NULL, sizeof(char *) * (ndomains + 1)); + + if (!names) + return NULL;
Well, we should never get to this situation. vshMalloc either fails and exit() or return a valid pointer.
+ + for (i = 0; i < ndomains; i++) { + const char *name = virDomainGetName(domains[i]); + if (VIR_STRDUP(names[i], name) < 0) { + virDomainFree(domains[i]); + goto error; + } + virDomainFree(domains[i]); + } + names[i] = NULL; + VIR_FREE(domains); + return names; + +error: + for (i = 0; names[i]; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + return NULL; +} + /* ----------------- * Readline stuff * ----------------- @@ -3510,6 +3557,7 @@ main(int argc, char **argv) ctl->debug = VSH_DEBUG_DEFAULT; ctl->escapeChar = "^]"; /* Same default as telnet */
+ vshConn = &ctl->conn;
if (!setlocale(LC_ALL, "")) { perror("setlocale"); @@ -3571,6 +3619,11 @@ main(int argc, char **argv) exit(EXIT_FAILURE); }
+ /* Need to connect immediately after start in order to provide + * autocompletion for the very first command. + */ + vshReconnect(ctl); +
This has been discussed so see Eric's and Peter's replies.
do { const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW; ctl->cmdstr = diff --git a/tools/virsh.h b/tools/virsh.h index 064acde..68414e4 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -255,6 +255,8 @@ struct _vshCmdGrp { const vshCmdDef *commands; };
+char **vshDomainCompleter(unsigned int flags); + void vshError(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3); void vshOpenLogFile(vshControl *ctl);
Michal

* label cleanup renamed to error * vshSuspendTargetCompleter added to opts_dom_pm_suspend --- tools/virsh-domain.c | 3 ++- tools/virsh.c | 28 ++++++++++++++++++++++++++++ tools/virsh.h | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 5d4913d..a2002c5 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -2756,7 +2756,8 @@ static const vshCmdOptDef opts_dom_pm_suspend[] = { .flags = VSH_OFLAG_REQ, .help = N_("mem(Suspend-to-RAM), " "disk(Suspend-to-Disk), " - "hybrid(Hybrid-Suspend)") + "hybrid(Hybrid-Suspend)"), + .completer = vshSuspendTargetCompleter }, {.name = NULL} }; diff --git a/tools/virsh.c b/tools/virsh.c index 13c27df..85d74ad 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2550,6 +2550,34 @@ error: return NULL; } +char ** +vshSuspendTargetCompleter(unsigned int unused_flags ATTRIBUTE_UNUSED) +{ + const char *targets[] = {"mem", "disk", "hybrid"}; + const unsigned int targets_size = ARRAY_CARDINALITY(targets); + char **names = NULL; + size_t i; + + names = vshMalloc(NULL, sizeof(char *) * (targets_size + 1)); + + if (!names) + return NULL; + + for (i = 0; i < targets_size; i++) { + if (VIR_STRDUP(names[i], targets[i]) < 0) + goto error; + } + + names[i] = NULL; + return names; + +error: + for (i = 0; names[i]; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + return NULL; +} + /* ----------------- * Readline stuff * ----------------- diff --git a/tools/virsh.h b/tools/virsh.h index 68414e4..6767e65 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -256,6 +256,7 @@ struct _vshCmdGrp { }; char **vshDomainCompleter(unsigned int flags); +char **vshSuspendTargetCompleter(unsigned int unused_flags); void vshError(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3); -- 1.8.3.1

On 20.08.2013 22:02, Tomas Meszaros wrote:
* label cleanup renamed to error * vshSuspendTargetCompleter added to opts_dom_pm_suspend --- tools/virsh-domain.c | 3 ++- tools/virsh.c | 28 ++++++++++++++++++++++++++++ tools/virsh.h | 1 + 3 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index 5d4913d..a2002c5 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -2756,7 +2756,8 @@ static const vshCmdOptDef opts_dom_pm_suspend[] = { .flags = VSH_OFLAG_REQ, .help = N_("mem(Suspend-to-RAM), " "disk(Suspend-to-Disk), " - "hybrid(Hybrid-Suspend)") + "hybrid(Hybrid-Suspend)"), + .completer = vshSuspendTargetCompleter
This is what I had on my mind in 4/9.
}, {.name = NULL} }; diff --git a/tools/virsh.c b/tools/virsh.c index 13c27df..85d74ad 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2550,6 +2550,34 @@ error: return NULL; }
+char ** +vshSuspendTargetCompleter(unsigned int unused_flags ATTRIBUTE_UNUSED) +{ + const char *targets[] = {"mem", "disk", "hybrid"}; + const unsigned int targets_size = ARRAY_CARDINALITY(targets); + char **names = NULL; + size_t i; + + names = vshMalloc(NULL, sizeof(char *) * (targets_size + 1)); + + if (!names) + return NULL; + + for (i = 0; i < targets_size; i++) { + if (VIR_STRDUP(names[i], targets[i]) < 0) + goto error; + } + + names[i] = NULL; + return names; + +error: + for (i = 0; names[i]; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + return NULL; +} + /* ----------------- * Readline stuff * ----------------- diff --git a/tools/virsh.h b/tools/virsh.h index 68414e4..6767e65 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -256,6 +256,7 @@ struct _vshCmdGrp { };
char **vshDomainCompleter(unsigned int flags); +char **vshSuspendTargetCompleter(unsigned int unused_flags);
void vshError(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3);
Michal

vshRebootShutdownModeCompleter returns available modes for reboot/shutdown commands. --- tools/virsh.c | 28 ++++++++++++++++++++++++++++ tools/virsh.h | 1 + 2 files changed, 29 insertions(+) diff --git a/tools/virsh.c b/tools/virsh.c index 85d74ad..965b141 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2578,6 +2578,34 @@ error: return NULL; } +char ** +vshRebootShutdownModeCompleter(unsigned int unused_flags ATTRIBUTE_UNUSED) +{ + const char *modes[] = {"acpi", "agent", "initctl", "signal"}; + const unsigned int modes_size = ARRAY_CARDINALITY(modes); + char **names = NULL; + size_t i; + + names = vshMalloc(NULL, sizeof(char *) * (modes_size + 1)); + + if (!names) + return NULL; + + for (i = 0; i < modes_size; i++) { + if (VIR_STRDUP(names[i], modes[i]) < 0) + goto cleanup; + } + + names[i] = NULL; + return names; + +cleanup: + for (i = 0; names[i]; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + return NULL; +} + /* ----------------- * Readline stuff * ----------------- diff --git a/tools/virsh.h b/tools/virsh.h index 6767e65..61510b0 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -257,6 +257,7 @@ struct _vshCmdGrp { char **vshDomainCompleter(unsigned int flags); char **vshSuspendTargetCompleter(unsigned int unused_flags); +char **vshRebootShutdownModeCompleter(unsigned int unused_flags); void vshError(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3); -- 1.8.3.1

On 20.08.2013 22:02, Tomas Meszaros wrote:
vshRebootShutdownModeCompleter returns available modes for reboot/shutdown commands. --- tools/virsh.c | 28 ++++++++++++++++++++++++++++ tools/virsh.h | 1 + 2 files changed, 29 insertions(+)
Again, you should add .completer = vshRebootShutdownModeCompleter in this patch.
diff --git a/tools/virsh.c b/tools/virsh.c index 85d74ad..965b141 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2578,6 +2578,34 @@ error: return NULL; }
+char ** +vshRebootShutdownModeCompleter(unsigned int unused_flags ATTRIBUTE_UNUSED) +{ + const char *modes[] = {"acpi", "agent", "initctl", "signal"}; + const unsigned int modes_size = ARRAY_CARDINALITY(modes); + char **names = NULL; + size_t i; + + names = vshMalloc(NULL, sizeof(char *) * (modes_size + 1)); + + if (!names) + return NULL;
Again useless if.
+ + for (i = 0; i < modes_size; i++) { + if (VIR_STRDUP(names[i], modes[i]) < 0) + goto cleanup; + } + + names[i] = NULL; + return names; + +cleanup: + for (i = 0; names[i]; i++) + VIR_FREE(names[i]); + VIR_FREE(names); + return NULL; +} + /* ----------------- * Readline stuff * ----------------- diff --git a/tools/virsh.h b/tools/virsh.h index 6767e65..61510b0 100644 --- a/tools/virsh.h +++ b/tools/virsh.h @@ -257,6 +257,7 @@ struct _vshCmdGrp {
char **vshDomainCompleter(unsigned int flags); char **vshSuspendTargetCompleter(unsigned int unused_flags); +char **vshRebootShutdownModeCompleter(unsigned int unused_flags);
void vshError(vshControl *ctl, const char *format, ...) ATTRIBUTE_FMT_PRINTF(2, 3);
Michal

* opts_dom_pm_suspend completer initialization for "target" removed (moved to another patch) --- tools/virsh-domain.c | 230 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 179 insertions(+), 51 deletions(-) diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index a2002c5..ff7a6e3 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -2756,8 +2756,7 @@ static const vshCmdOptDef opts_dom_pm_suspend[] = { .flags = VSH_OFLAG_REQ, .help = N_("mem(Suspend-to-RAM), " "disk(Suspend-to-Disk), " - "hybrid(Hybrid-Suspend)"), - .completer = vshSuspendTargetCompleter + "hybrid(Hybrid-Suspend)") }, {.name = NULL} }; @@ -4714,7 +4713,8 @@ static const vshCmdOptDef opts_shutdown[] = { }, {.name = "mode", .type = VSH_OT_STRING, - .help = N_("shutdown mode: acpi|agent|initctl|signal") + .help = N_("shutdown mode: acpi|agent|initctl|signal"), + .completer = vshRebootShutdownModeCompleter }, {.name = NULL} }; @@ -4800,7 +4800,8 @@ static const vshCmdOptDef opts_reboot[] = { }, {.name = "mode", .type = VSH_OT_STRING, - .help = N_("shutdown mode: acpi|agent|initctl|signal") + .help = N_("shutdown mode: acpi|agent|initctl|signal"), + .completer = vshRebootShutdownModeCompleter }, {.name = NULL} }; @@ -10359,7 +10360,10 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdAutostart, .opts = opts_autostart, .info = info_autostart, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "blkdeviotune", .handler = cmdBlkdeviotune, @@ -10371,7 +10375,10 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdBlkiotune, .opts = opts_blkiotune, .info = info_blkiotune, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "blockcommit", .handler = cmdBlockCommit, @@ -10414,7 +10421,10 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdConsole, .opts = opts_console, .info = info_console, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, #endif {.name = "cpu-baseline", @@ -10451,13 +10461,18 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdDesc, .opts = opts_desc, .info = info_desc, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "destroy", .handler = cmdDestroy, .opts = opts_destroy, .info = info_destroy, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "detach-device", .handler = cmdDetachDevice, @@ -10481,25 +10496,37 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdDomDisplay, .opts = opts_domdisplay, .info = info_domdisplay, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "domfstrim", .handler = cmdDomFSTrim, .opts = opts_domfstrim, .info = info_domfstrim, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "domhostname", .handler = cmdDomHostname, .opts = opts_domhostname, .info = info_domhostname, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "domid", .handler = cmdDomid, .opts = opts_domid, .info = info_domid, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "domif-setlink", .handler = cmdDomIfSetLink, @@ -10517,13 +10544,17 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdDomjobabort, .opts = opts_domjobabort, .info = info_domjobabort, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "domjobinfo", .handler = cmdDomjobinfo, .opts = opts_domjobinfo, .info = info_domjobinfo, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "domname", .handler = cmdDomname, @@ -10535,19 +10566,27 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdDomPMSuspend, .opts = opts_dom_pm_suspend, .info = info_dom_pm_suspend, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_RUNNING }, {.name = "dompmwakeup", .handler = cmdDomPMWakeup, .opts = opts_dom_pm_wakeup, .info = info_dom_pm_wakeup, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "domuuid", .handler = cmdDomuuid, .opts = opts_domuuid, .info = info_domuuid, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "domxml-from-native", .handler = cmdDomXMLFromNative, @@ -10565,31 +10604,46 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdDump, .opts = opts_dump, .info = info_dump, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_RUNNING }, {.name = "dumpxml", .handler = cmdDumpXML, .opts = opts_dumpxml, .info = info_dumpxml, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "edit", .handler = cmdEdit, .opts = opts_edit, .info = info_edit, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "inject-nmi", .handler = cmdInjectNMI, .opts = opts_inject_nmi, .info = info_inject_nmi, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_RUNNING }, {.name = "send-key", .handler = cmdSendKey, .opts = opts_send_key, .info = info_send_key, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_RUNNING }, {.name = "send-process-signal", .handler = cmdSendProcessSignal, @@ -10601,19 +10655,29 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdLxcEnterNamespace, .opts = opts_lxc_enter_namespace, .info = info_lxc_enter_namespace, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "managedsave", .handler = cmdManagedSave, .opts = opts_managedsave, .info = info_managedsave, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_RUNNING | + VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE }, {.name = "managedsave-remove", .handler = cmdManagedSaveRemove, .opts = opts_managedsaveremove, .info = info_managedsaveremove, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE | + VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE }, {.name = "maxvcpus", .handler = cmdMaxvcpus, @@ -10625,7 +10689,10 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdMemtune, .opts = opts_memtune, .info = info_memtune, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "migrate", .handler = cmdMigrate, @@ -10637,31 +10704,46 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdMigrateSetMaxDowntime, .opts = opts_migrate_setmaxdowntime, .info = info_migrate_setmaxdowntime, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "migrate-compcache", .handler = cmdMigrateCompCache, .opts = opts_migrate_compcache, .info = info_migrate_compcache, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_RUNNING }, {.name = "migrate-setspeed", .handler = cmdMigrateSetMaxSpeed, .opts = opts_migrate_setspeed, .info = info_migrate_setspeed, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "migrate-getspeed", .handler = cmdMigrateGetMaxSpeed, .opts = opts_migrate_getspeed, .info = info_migrate_getspeed, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "numatune", .handler = cmdNumatune, .opts = opts_numatune, .info = info_numatune, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "qemu-attach", .handler = cmdQemuAttach, @@ -10673,25 +10755,35 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdQemuMonitorCommand, .opts = opts_qemu_monitor_command, .info = info_qemu_monitor_command, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "qemu-agent-command", .handler = cmdQemuAgentCommand, .opts = opts_qemu_agent_command, .info = info_qemu_agent_command, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "reboot", .handler = cmdReboot, .opts = opts_reboot, .info = info_reboot, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "reset", .handler = cmdReset, .opts = opts_reset, .info = info_reset, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "restore", .handler = cmdRestore, @@ -10703,7 +10795,10 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdResume, .opts = opts_resume, .info = info_resume, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_PAUSED }, {.name = "save", .handler = cmdSave, @@ -10733,61 +10828,83 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdSchedinfo, .opts = opts_schedinfo, .info = info_schedinfo, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "screenshot", .handler = cmdScreenshot, .opts = opts_screenshot, .info = info_screenshot, - .flags = 0 + .flags = 0, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "setmaxmem", .handler = cmdSetmaxmem, .opts = opts_setmaxmem, .info = info_setmaxmem, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "setmem", .handler = cmdSetmem, .opts = opts_setmem, .info = info_setmem, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "setvcpus", .handler = cmdSetvcpus, .opts = opts_setvcpus, .info = info_setvcpus, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "shutdown", .handler = cmdShutdown, .opts = opts_shutdown, .info = info_shutdown, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "start", .handler = cmdStart, .opts = opts_start, .info = info_start, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE | + VIR_CONNECT_LIST_DOMAINS_PERSISTENT, }, {.name = "suspend", .handler = cmdSuspend, .opts = opts_suspend, .info = info_suspend, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "ttyconsole", .handler = cmdTTYConsole, .opts = opts_ttyconsole, .info = info_ttyconsole, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "undefine", .handler = cmdUndefine, .opts = opts_undefine, .info = info_undefine, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "update-device", .handler = cmdUpdateDevice, @@ -10805,25 +10922,36 @@ const vshCmdDef domManagementCmds[] = { .handler = cmdVcpuinfo, .opts = opts_vcpuinfo, .info = info_vcpuinfo, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "vcpupin", .handler = cmdVcpuPin, .opts = opts_vcpupin, .info = info_vcpupin, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "emulatorpin", .handler = cmdEmulatorPin, .opts = opts_emulatorpin, .info = info_emulatorpin, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "vncdisplay", .handler = cmdVNCDisplay, .opts = opts_vncdisplay, .info = info_vncdisplay, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = NULL} }; -- 1.8.3.1

Add .completer and .completer_flags to snapshotCmds. Provides domain completion for most of the snapshotCmds commands. --- tools/virsh-snapshot.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/tools/virsh-snapshot.c b/tools/virsh-snapshot.c index e37a5b3..77f9273 100644 --- a/tools/virsh-snapshot.c +++ b/tools/virsh-snapshot.c @@ -2006,25 +2006,37 @@ const vshCmdDef snapshotCmds[] = { .handler = cmdSnapshotCreate, .opts = opts_snapshot_create, .info = info_snapshot_create, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "snapshot-create-as", .handler = cmdSnapshotCreateAs, .opts = opts_snapshot_create_as, .info = info_snapshot_create_as, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "snapshot-current", .handler = cmdSnapshotCurrent, .opts = opts_snapshot_current, .info = info_snapshot_current, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "snapshot-delete", .handler = cmdSnapshotDelete, .opts = opts_snapshot_delete, .info = info_snapshot_delete, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "snapshot-dumpxml", .handler = cmdSnapshotDumpXML, @@ -2036,31 +2048,46 @@ const vshCmdDef snapshotCmds[] = { .handler = cmdSnapshotEdit, .opts = opts_snapshot_edit, .info = info_snapshot_edit, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "snapshot-info", .handler = cmdSnapshotInfo, .opts = opts_snapshot_info, .info = info_snapshot_info, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "snapshot-list", .handler = cmdSnapshotList, .opts = opts_snapshot_list, .info = info_snapshot_list, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "snapshot-parent", .handler = cmdSnapshotParent, .opts = opts_snapshot_parent, .info = info_snapshot_parent, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "snapshot-revert", .handler = cmdDomainSnapshotRevert, .opts = opts_snapshot_revert, .info = info_snapshot_revert, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = NULL} }; -- 1.8.3.1

Add .completer and .completer_flags to domMonitoringCmds. Provides domain completion for domMonitoringCmds commands. --- tools/virsh-domain-monitor.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c index b29b82a..0f30902 100644 --- a/tools/virsh-domain-monitor.c +++ b/tools/virsh-domain-monitor.c @@ -1876,7 +1876,9 @@ const vshCmdDef domMonitoringCmds[] = { .handler = cmdDomBlkError, .opts = opts_domblkerror, .info = info_domblkerror, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "domblkinfo", .handler = cmdDomblkinfo, @@ -1888,7 +1890,10 @@ const vshCmdDef domMonitoringCmds[] = { .handler = cmdDomblklist, .opts = opts_domblklist, .info = info_domblklist, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "domblkstat", .handler = cmdDomblkstat, @@ -1900,7 +1905,9 @@ const vshCmdDef domMonitoringCmds[] = { .handler = cmdDomControl, .opts = opts_domcontrol, .info = info_domcontrol, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "domif-getlink", .handler = cmdDomIfGetLink, @@ -1912,7 +1919,10 @@ const vshCmdDef domMonitoringCmds[] = { .handler = cmdDomiflist, .opts = opts_domiflist, .info = info_domiflist, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "domifstat", .handler = cmdDomIfstat, @@ -1924,19 +1934,27 @@ const vshCmdDef domMonitoringCmds[] = { .handler = cmdDominfo, .opts = opts_dominfo, .info = info_dominfo, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "dommemstat", .handler = cmdDomMemStat, .opts = opts_dommemstat, .info = info_dommemstat, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE }, {.name = "domstate", .handler = cmdDomstate, .opts = opts_domstate, .info = info_domstate, - .flags = 0 + .flags = 0, + .completer = vshDomainCompleter, + .completer_flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE }, {.name = "list", .handler = cmdList, -- 1.8.3.1
participants (4)
-
Eric Blake
-
Michal Privoznik
-
Peter Krempa
-
Tomas Meszaros