[libvirt] virsh bash completion file

Serge Hallyn serge.hallyn at canonical.com
Thu Feb 9 05:43:53 UTC 2012


Quoting Daniel P. Berrange (berrange at redhat.com):
> On Thu, Oct 06, 2011 at 08:30:55AM -0500, Serge E. Hallyn wrote:
> > Quoting Daniel P. Berrange (berrange at redhat.com):
> > > On Wed, Oct 05, 2011 at 03:17:47PM -0500, Serge E. Hallyn wrote:
> > > > Hi,
> > > > 
> > > > I've been trying out a bash autocompletion file by Geoff Low (slight hack
> > > > by me, don't blame him for my hack), and it's working pretty nicely.
> > > > I'm not sure where to put it in the git tree, but it seems like it'd be
> > > > nice to have upstream?
> > > 
> > > David Lutterkort previously suggested this
> > > 
> > >    https://www.redhat.com/archives/libvir-list/2007-October/msg00231.html
> > > 
> > > And I didn't ever notice that and so wrote one myself
> > > 
> > >    https://www.redhat.com/archives/libvir-list/2008-July/msg00175.html
> > >    https://www.redhat.com/archives/libvir-list/2008-July/msg00177.html
> > > 
> > > Neither ever got committed. There were some things I didn't much like
> > > about mine, but I can't really remember now.
> > > 
> > > Third time lucky perhaps :-)
> > 
> > So the things you didn't much like must not have been *too* bad?  :)
> > Are you going to make some changes and resubmit, or would you like
> > me to test (and port as needed) the above patches first?
> 
> I don't have time right now to update my own patches. You, or anyone
> else, are free to take them forward as desired...

Well I've got the patch ported so that it mostly works - autocompletes
for commands and vm names at least.  (ugly patch against 0.9.8 attached
just for conversation) But I can't figure out how one should do uri
completion.  Any hints on where to get such a list now?

thanks,
-serge

Index: libvirt-0.9.8/include/libvirt/libvirt.h
===================================================================
--- libvirt-0.9.8.orig/include/libvirt/libvirt.h	2011-12-08 06:58:49.000000000 +0000
+++ libvirt-0.9.8/include/libvirt/libvirt.h	2012-02-08 03:52:16.008232120 +0000
@@ -1065,6 +1065,7 @@
                                                  unsigned int flags);
 int                     virConnectRef           (virConnectPtr conn);
 int                     virConnectClose         (virConnectPtr conn);
+char **                 virConnectURIs          (int *nuris);
 const char *            virConnectGetType       (virConnectPtr conn);
 int                     virConnectGetVersion    (virConnectPtr conn,
                                                  unsigned long *hvVer);
Index: libvirt-0.9.8/include/libvirt/libvirt.h.in
===================================================================
--- libvirt-0.9.8.orig/include/libvirt/libvirt.h.in	2011-12-06 08:38:51.000000000 +0000
+++ libvirt-0.9.8/include/libvirt/libvirt.h.in	2012-02-08 03:52:35.132225305 +0000
@@ -1065,6 +1065,7 @@
                                                  unsigned int flags);
 int                     virConnectRef           (virConnectPtr conn);
 int                     virConnectClose         (virConnectPtr conn);
+char **                 virConnectURIs          (int *nuris);
 const char *            virConnectGetType       (virConnectPtr conn);
 int                     virConnectGetVersion    (virConnectPtr conn,
                                                  unsigned long *hvVer);
Index: libvirt-0.9.8/libvirt.spec.in
===================================================================
--- libvirt-0.9.8.orig/libvirt.spec.in	2011-12-08 06:54:48.000000000 +0000
+++ libvirt-0.9.8/libvirt.spec.in	2012-02-08 03:54:03.300230906 +0000
@@ -1050,6 +1050,7 @@
 %{_unitdir}/libvirtd.service
 %endif
 %doc daemon/libvirtd.upstart
+%{_sysconfdir}/bash_completion.d/virsh
 %config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
 %config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
 %if 0%{?fedora} >= 14 || 0%{?rhel} >= 6
Index: libvirt-0.9.8/src/Makefile.am
===================================================================
--- libvirt-0.9.8.orig/src/Makefile.am	2012-02-08 03:46:38.000000000 +0000
+++ libvirt-0.9.8/src/Makefile.am	2012-02-08 20:51:04.340232096 +0000
@@ -22,7 +22,9 @@
 		$(COVERAGE_CFLAGS)
 AM_LDFLAGS = $(COVERAGE_LDFLAGS)
 
-EXTRA_DIST = $(conf_DATA) util/keymaps.csv
+bashdir = $(sysconfdir)/bash_completion.d
+
+EXTRA_DIST = $(conf_DATA) util/keymaps.csv virsh.bash
 
 BUILT_SOURCES =
 CLEANFILES =
@@ -1584,6 +1586,8 @@
 	      $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml && \
 	    rm $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml.t; }
 endif
+	$(MKDIR_P) "$(DESTDIR)$(bashdir)"
+	$(INSTALL_DATA) "$(srcdir)/virsh.bash" "$(DESTDIR)$(bashdir)/virsh"
 
 uninstall-local::
 	rmdir "$(DESTDIR)$(localstatedir)/cache/libvirt" ||:
@@ -1621,6 +1625,7 @@
 	rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/network" ||:
 endif
 	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt" ||:
+	rm -f "$(DESTDIR)$(bashdir)/virsh" ||:
 
 CLEANFILES += *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda *.i *.s
 DISTCLEANFILES += $(GENERATED_SYM_FILES)
Index: libvirt-0.9.8/src/libvirt.c
===================================================================
--- libvirt-0.9.8.orig/src/libvirt.c	2011-12-08 02:26:59.000000000 +0000
+++ libvirt-0.9.8/src/libvirt.c	2012-02-09 04:13:30.168233577 +0000
@@ -1317,6 +1317,77 @@
 }
 
 /**
+ * virConnectURIs:
+ * @nuris: pointer to an integer in which to store the number of URIS
+ *
+ * This functions returns the list of available connection
+ * URIs. The caller is responsible for freeing the returned
+ * strings, and the array they're stored in.
+ *
+ * Returns the URIs in case of success or NULL case of error.
+ */
+char **
+virConnectURIs(int *nuris)
+{
+    char **ret = NULL;
+    int i;
+    int n = 0;
+
+    if (!initialized)
+        if (virInitialize() < 0)
+            return NULL;
+
+    for (i = 0; i < virDriverTabCount; i++) {
+        virConnectPtr conn;
+        int res;
+
+        printf("URI %d: 1, name %s\n", i, virDriverTab[i]->name);
+        conn = virGetConnect();
+        if (!conn)
+            goto no_memory;
+        printf("URI %d: 2\n", i);
+        res = virDriverTab[i]->open (conn, NULL, 0);
+        printf("URI %d: 3\n", i);
+        if (res != VIR_DRV_OPEN_SUCCESS)
+            goto next;
+        printf("URI %d: 4\n", i);
+        if (!conn->uri)
+            goto next;
+        printf("URI %d: 5\n", i);
+        if (VIR_REALLOC_N(ret, n+1) < 0) {
+            printf("URI %d: 6\n", i);
+            virConnectClose(conn);
+            goto no_memory;
+        }
+        printf("URI %d: 7, conn->uri is\n", i, conn->uri);
+        if ((ret[n++] = strdup(conn->uri)) == NULL) {
+            printf("URI %d: 8\n", i);
+            virConnectClose(conn);
+            goto no_memory;
+        }
+        printf("URI %d: 9\n", i);
+next:
+        printf("URI %d: 10\n", i);
+        virConnectClose(conn);
+    }
+
+    *nuris = n;
+    printf("URI %d: 11\n", *nuris);
+    for (i=0; i<n; i++)
+        printf("uri %d: %s\n", i, ret[i]);
+    return ret;
+
+no_memory:
+    printf("URI %d: 12\n", *nuris);
+    for (i = 0 ; i < n ; i++)
+        VIR_FREE(ret[i]);
+    VIR_FREE(ret);
+    *nuris = 0;
+    virLibConnError(VIR_ERR_NO_MEMORY, __FUNCTION__);
+    return NULL;
+}
+
+/**
  * virConnectOpen:
  * @name: URI of the hypervisor
  *
Index: libvirt-0.9.8/src/libvirt_public.syms
===================================================================
--- libvirt-0.9.8.orig/src/libvirt_public.syms	2011-12-02 03:59:50.000000000 +0000
+++ libvirt-0.9.8/src/libvirt_public.syms	2012-02-08 04:03:52.360265205 +0000
@@ -506,6 +506,7 @@
         virDomainGetBlockIoTune;
         virDomainSetBlockIoTune;
         virNodeSuspendForDuration;
+        virConnectURIs;
 } LIBVIRT_0.9.7;
 
 # .... define new API here using predicted next version number ....
Index: libvirt-0.9.8/src/virsh.bash
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ libvirt-0.9.8/src/virsh.bash	2012-02-08 22:56:26.536232538 +0000
@@ -0,0 +1,83 @@
+_virsh()
+{
+    local cur prev cmd cmd_index arg arg_index i results skipconn
+    local virsh="$1"
+    local canonical=0
+
+    COMPREPLY=()
+    cur="$2"
+    prev="$3"
+
+    if [[ $COMP_CWORD > 1 && ${COMP_WORDS[COMP_CWORD-1]} = '--connect' ]]; then
+        results="$($virsh _complete-uri)" || nets=""
+    fi
+
+    skipconn=0
+    if [ -z "$results" ]; then
+        # searching for the command name
+        for ((i=1; $i<=$COMP_CWORD; i++)); do
+            if [[ ${COMP_WORDS[i]} != -* ]]; then
+                if [[ ${COMP_WORDS[i-1]} = '--connect' ]]; then
+                    echo "${COMP_WORDS[i]}" | grep '///' >/dev/null 2>&1
+                    test "$?" = 1 && skipconn=1
+                    test "$skipconn" = 0 && virsh="$virsh ${COMP_WORDS[i-1]} ${COMP_WORDS[i]}"
+                else
+                    if [[ $i < $COMP_CWORD ]]; then
+                       cmd="${COMP_WORDS[i]}"
+                       cmd_index=$i
+                       arg_index=`expr $COMP_CWORD - $cmd_index`
+                       break
+                    fi
+                fi
+            fi
+        done
+
+        if [[ "$cur" == -* ]]; then
+            # Generate args - global or command specific
+            results="$($virsh _complete-command options "$cmd")"
+        else
+            if [ -z "$cmd" ]; then
+                # No command set, so generate list of all commands
+                results="$($virsh _complete-command commands)" || commands=""
+            else
+                # Command set, to generate command specific args
+                n=0
+                for i in "$($virsh _complete-command arguments "$cmd")"
+                do
+                    n=`expr $n + 1`
+                    if [ $n = $arg_index ]; then
+                        arg=$i
+                        break
+                    fi
+                done
+
+                case $arg in
+                  file)
+                    COMPREPLY=(${COMPREPLY[@]:-} $(compgen -o "default" -- "$cur"))
+                    ;;
+
+                  domain)
+                    test "$skipconn" = 0 && results="$($virsh _complete-domain)" || doms=""
+                    ;;
+
+                  network)
+                    test "$skipconn" = 0 && results="$($virsh _complete-network)" || nets=""
+                    ;;
+
+                  pool)
+                    test "$skipconn" = 0 && results="$($virsh _complete-pool)" || nets=""
+                    ;;
+
+                  uri)
+                    results="$($virsh _complete-uri)" || nets=""
+                    ;;
+                esac
+            fi
+        fi
+    fi
+    if [ ! -z "$results" ]; then
+        COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$results' -- "$cur"))
+    fi
+}
+
+complete -F _virsh virsh
Index: libvirt-0.9.8/tools/virsh.c
===================================================================
--- libvirt-0.9.8.orig/tools/virsh.c	2012-02-08 03:46:38.000000000 +0000
+++ libvirt-0.9.8/tools/virsh.c	2012-02-08 22:31:14.928233016 +0000
@@ -623,6 +623,414 @@
  */
 
 /*
+ * "_compcmds" command
+ */
+static vshCmdInfo info_compcommand[] = {
+    {"syntax", "_complete-command [commands|arguments|options] [<command>]"},
+    {"help", gettext_noop("print shell completion data")},
+    {"desc", gettext_noop("Prints data useful for shell autocompletion of commands.")},
+
+    {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compcommand[] = {
+    {"type", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("type of data")},
+    {"cmd", VSH_OT_DATA, 0, gettext_noop("command name")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdCompCommand(vshControl * ctl, const vshCmd * cmd)
+{
+    const char *type;
+    const char *name;
+
+    if (vshCommandOptString(cmd, "type", &type) <= 0)
+        type = "commands";
+    if (vshCommandOptString(cmd, "cmd", &name) <= 0)
+        name = NULL;
+
+    if (STREQ(type, "commands")) {
+        const vshCmdGrp *grp;
+        const vshCmdDef *def;
+        for (grp = cmdGroups; grp->name; grp++) {
+            for (def = grp->commands; def->name; def++)
+                if (def->name[0] != '_')
+                    vshPrint(ctl, "%s\n", def->name);
+        }
+    } else if (STREQ(type, "options")) {
+        if (name) {
+            const vshCmdDef *def = vshCmddefSearch(name);
+            if (!def) {
+                vshError(ctl, _("command '%s' doesn't exist"), name);
+                return false;
+            } else if (def->opts) {
+                const vshCmdOptDef *opt;
+                for (opt = def->opts; opt->name; opt++)
+                    if (opt->type == VSH_OT_BOOL ||
+                        opt->type == VSH_OT_INT ||
+                        opt->type == VSH_OT_STRING)
+                        vshPrint(ctl, "--%s\n", opt->name);
+            }
+        } else {
+            vshPrint(ctl,
+                     "-c\n--connect\n"
+                     "-r\n--readonly\n"
+                     "-d\n--debug\n"
+                     "-h\n--help\n"
+                     "-q\n--quiet\n"
+                     "-t\n--timing\n"
+                     "-l\n--log\n"
+                     "-v\n--version\n");
+        }
+    } else if (STREQ(type, "arguments")) {
+        if (!name) {
+            vshError(ctl, "%s", _("no command specified"));
+            return false;
+        } else {
+            const vshCmdDef *def = vshCmddefSearch(name);
+            if (!def) {
+                vshError(ctl, _("command '%s' doesn't exist"), name);
+                return false;
+            } else if (def->opts) {
+                const vshCmdOptDef *opt;
+                for (opt = def->opts; opt->name; opt++)
+                    if (opt->type == VSH_OT_DATA)
+                        vshPrint(ctl, "%s\n", opt->name);
+            }
+        }
+    }
+    return true;
+}
+
+/*
+ * "_compuris" command
+ */
+static vshCmdInfo info_compuri[] = {
+    {"syntax", "_complete-uri"},
+    {"help", gettext_noop("print shell completion data for URIs")},
+    {"desc", gettext_noop("Prints data useful for shell autocompletion of URIs.")},
+
+    {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compuri[] = {
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdCompUri(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+    char **uris = NULL;
+    int nuris, i;
+
+    uris = virConnectURIs(&nuris);
+    if (!uris) {
+        vshError(ctl, "%s", _("Failed to list connection URIs"));
+        return false;
+    }
+    for (i = 0 ; i < nuris ; i++) {
+        vshPrint(ctl, "%s\n", uris[i]);
+        free(uris[i]);
+    }
+
+    free(uris);
+    return true;
+}
+/*
+ * "_compdomains" command
+ */
+static vshCmdInfo info_compdomain[] = {
+    {"syntax", "_complete-domain"},
+    {"help", gettext_noop("print shell completion data for domains")},
+    {"desc", gettext_noop("Prints data useful for shell autocompletion of domains.")},
+
+    {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compdomain[] = {
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdCompDomain(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+    int *ids = NULL;
+    char **names = NULL;
+    int maxname = 0, maxid = 0, i;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    maxid = virConnectNumOfDomains(ctl->conn);
+    if (maxid < 0) {
+        vshError(ctl, "%s", _("Failed to list active domains"));
+        return false;
+    }
+    if (maxid) {
+        ids = vshMalloc(ctl, sizeof(int) * maxid);
+
+        if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
+            vshError(ctl, "%s", _("Failed to list active domains"));
+            free(ids);
+            return false;
+        }
+
+        qsort(&ids[0], maxid, sizeof(int), idsorter);
+    }
+    maxname = virConnectNumOfDefinedDomains(ctl->conn);
+    if (maxname < 0) {
+        vshError(ctl, "%s", _("Failed to list inactive domains"));
+        free(ids);
+        return false;
+    }
+    if (maxname) {
+        names = vshMalloc(ctl, sizeof(char *) * maxname);
+
+        if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) {
+            vshError(ctl, "%s", _("Failed to list inactive domains"));
+            free(ids);
+            free(names);
+            return false;
+        }
+
+        qsort(&names[0], maxname, sizeof(char*), namesorter);
+    }
+
+    for (i = 0; i < maxid; i++) {
+        char uuid[VIR_UUID_STRING_BUFLEN];
+        virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
+        /* this kind of work with domains is not atomic operation */
+        if (!dom)
+            continue;
+        virDomainGetUUIDString(dom, uuid);
+        vshPrint(ctl, "%d\n%s\n%s\n",
+                 virDomainGetID(dom),
+                 virDomainGetName(dom),
+                 uuid);
+        virDomainFree(dom);
+    }
+    for (i = 0; i < maxname; i++) {
+        char uuid[VIR_UUID_STRING_BUFLEN];
+        virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);
+
+        /* this kind of work with domains is not atomic operation */
+        if (!dom) {
+            free(names[i]);
+            continue;
+        }
+        virDomainGetUUIDString(dom, uuid);
+        vshPrint(ctl, "%s\n%s\n",
+                 virDomainGetName(dom),
+                 uuid);
+        virDomainFree(dom);
+        free(names[i]);
+    }
+    free(ids);
+    free(names);
+    return true;
+}
+
+/*
+ * "_compnetworks" command
+ */
+static vshCmdInfo info_compnetwork[] = {
+    {"syntax", "_complete-network"},
+    {"help", gettext_noop("print shell completion data for networks")},
+    {"desc", gettext_noop("Prints data useful for shell autocompletion of networks.")},
+
+    {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compnetwork[] = {
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdCompNetwork(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+    char **activeNames = NULL, **inactiveNames = NULL;
+    int maxactive = 0, maxinactive = 0, i;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    maxactive = virConnectNumOfNetworks(ctl->conn);
+    if (maxactive < 0) {
+        vshError(ctl, "%s", _("Failed to list active networks"));
+        return false;
+    }
+    if (maxactive) {
+        activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
+
+        if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
+                                                maxactive)) < 0) {
+            vshError(ctl, "%s", _("Failed to list active networks"));
+            free(activeNames);
+            return false;
+        }
+
+        qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
+    }
+    maxinactive = virConnectNumOfDefinedNetworks(ctl->conn);
+    if (maxinactive < 0) {
+        vshError(ctl, "%s", _("Failed to list inactive networks"));
+        free(activeNames);
+        return false;
+    }
+    if (maxinactive) {
+        inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
+
+        if ((maxinactive = virConnectListDefinedNetworks(ctl->conn, inactiveNames, maxinactive)) < 0) {
+            vshError(ctl, "%s", _("Failed to list inactive networks"));
+            free(activeNames);
+            free(inactiveNames);
+            return false;
+        }
+
+        qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
+    }
+
+    for (i = 0; i < maxactive; i++) {
+        char uuid[VIR_UUID_STRING_BUFLEN];
+        virNetworkPtr network = virNetworkLookupByName(ctl->conn, activeNames[i]);
+
+        /* this kind of work with networks is not atomic operation */
+        if (!network) {
+            free(activeNames[i]);
+            continue;
+        }
+        virNetworkGetUUIDString(network, uuid);
+        vshPrint(ctl, "%s\n%s\n",
+                 virNetworkGetName(network),
+                 uuid);
+        virNetworkFree(network);
+        free(activeNames[i]);
+    }
+    for (i = 0; i < maxinactive; i++) {
+        char uuid[VIR_UUID_STRING_BUFLEN];
+        virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]);
+
+        /* this kind of work with networks is not atomic operation */
+        if (!network) {
+            free(inactiveNames[i]);
+            continue;
+        }
+        virNetworkGetUUIDString(network, uuid);
+        vshPrint(ctl, "%s\n%s\n",
+                 virNetworkGetName(network),
+                 uuid);
+
+        virNetworkFree(network);
+        free(inactiveNames[i]);
+    }
+    free(activeNames);
+    free(inactiveNames);
+
+    return true;
+}
+
+
+/*
+ * "_comppools" command
+ */
+static vshCmdInfo info_comppool[] = {
+    {"syntax", "_complete-pool"},
+    {"help", gettext_noop("print shell completion data for pools")},
+    {"desc", gettext_noop("Prints data useful for shell autocompletion of pools.")},
+
+    {NULL, NULL}
+};
+
+static vshCmdOptDef opts_comppool[] = {
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdCompPool(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+    char **activeNames = NULL, **inactiveNames = NULL;
+    int maxactive = 0, maxinactive = 0, i;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    maxactive = virConnectNumOfStoragePools(ctl->conn);
+    if (maxactive < 0) {
+        vshError(ctl, "%s", _("Failed to list active pools"));
+        return false;
+    }
+    if (maxactive) {
+        activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
+
+        if ((maxactive = virConnectListStoragePools(ctl->conn, activeNames,
+                                                maxactive)) < 0) {
+            vshError(ctl, "%s", _("Failed to list active pools"));
+            free(activeNames);
+            return false;
+        }
+
+        qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
+    }
+    maxinactive = virConnectNumOfDefinedStoragePools(ctl->conn);
+    if (maxinactive < 0) {
+        vshError(ctl, "%s", _("Failed to list inactive pools"));
+        free(activeNames);
+        return false;
+    }
+    if (maxinactive) {
+        inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
+
+        if ((maxinactive = virConnectListDefinedStoragePools(ctl->conn, inactiveNames, maxinactive)) < 0) {
+            vshError(ctl, "%s", _("Failed to list inactive pools"));
+            free(activeNames);
+            free(inactiveNames);
+            return false;
+        }
+
+        qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
+    }
+
+    for (i = 0; i < maxactive; i++) {
+        char uuid[VIR_UUID_STRING_BUFLEN];
+        virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, activeNames[i]);
+
+        /* this kind of work with pools is not atomic operation */
+        if (!pool) {
+            free(activeNames[i]);
+            continue;
+        }
+        virStoragePoolGetUUIDString(pool, uuid);
+        vshPrint(ctl, "%s\n%s\n",
+                 virStoragePoolGetName(pool),
+                 uuid);
+        virStoragePoolFree(pool);
+        free(activeNames[i]);
+    }
+    for (i = 0; i < maxinactive; i++) {
+        char uuid[VIR_UUID_STRING_BUFLEN];
+        virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn, inactiveNames[i]);
+
+        /* this kind of work with pools is not atomic operation */
+        if (!pool) {
+            free(inactiveNames[i]);
+            continue;
+        }
+        virStoragePoolGetUUIDString(pool, uuid);
+        vshPrint(ctl, "%s\n%s\n",
+                 virStoragePoolGetName(pool),
+                 uuid);
+
+        virStoragePoolFree(pool);
+        free(inactiveNames[i]);
+    }
+    free(activeNames);
+    free(inactiveNames);
+
+    return true;
+}
+
+/*
  * "help" command
  */
 static const vshCmdInfo info_help[] = {
@@ -654,7 +1062,8 @@
                      grp->keyword);
 
             for (def = grp->commands; def->name; def++)
-                vshPrint(ctl, "    %-30s %s\n", def->name,
+                if (def->name[0] != '_')
+                    vshPrint(ctl, "    %-30s %s\n", def->name,
                          _(vshCmddefGetInfo(def, "help")));
 
             vshPrint(ctl, "\n");
@@ -15335,6 +15744,11 @@
 };
 
 static const vshCmdDef virshCmds[] = {
+    {"_complete-command", cmdCompCommand, opts_compcommand, info_compcommand, VSH_CMD_FLAG_NOCONNECT},
+    {"_complete-uri", cmdCompUri, opts_compuri, info_compuri, VSH_CMD_FLAG_NOCONNECT},
+    {"_complete-domain", cmdCompDomain, opts_compdomain, info_compdomain, VSH_CMD_FLAG_NOCONNECT},
+    {"_complete-network", cmdCompNetwork, opts_compnetwork, info_compnetwork, VSH_CMD_FLAG_NOCONNECT},
+    {"_complete-pool", cmdCompPool, opts_comppool, info_comppool, VSH_CMD_FLAG_NOCONNECT},
     {"cd", cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT},
     {"echo", cmdEcho, opts_echo, info_echo, VSH_CMD_FLAG_NOCONNECT},
     {"exit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT},
@@ -16606,6 +17020,7 @@
 vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
 {
     vshCommandParser parser;
+    bool ret;
 
     if (nargs <= 0)
         return false;
@@ -16613,7 +17028,20 @@
     parser.arg_pos = argv;
     parser.arg_end = argv + nargs;
     parser.getNextArg = vshCommandArgvGetArg;
-    return vshCommandParse(ctl, &parser);
+    ret = vshCommandParse(ctl, &parser);
+
+    /* Special case 'help' to avoid virConnectOpen */
+    if (ctl->cmd &&
+        ctl->cmd->def &&
+        ctl->cmd->def->name &&
+        (STREQ(ctl->cmd->def->name, "help") ||
+         STREQ(ctl->cmd->def->name, "_complete-command") ||
+         STREQ(ctl->cmd->def->name, "_complete-uri"))) {
+        ret = vshCommandRun(ctl, ctl->cmd);
+        exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
+    }
+
+    return ret;
 }
 
 /* ----------------------
Index: libvirt-0.9.8/python/generator.py
===================================================================
--- libvirt-0.9.8.orig/python/generator.py	2011-12-02 03:59:49.000000000 +0000
+++ libvirt-0.9.8/python/generator.py	2012-02-08 20:01:59.268229464 +0000
@@ -224,6 +224,7 @@
 qemu_functions_failed = []
 functions_skipped = [
     "virConnectListDomains",
+    "virConnectURIs",
 ]
 qemu_functions_skipped = []
 
@@ -340,6 +341,7 @@
     'virConnectGetVersion',
     'virConnectGetLibVersion',
     'virConnectListDomainsID',
+    'virConnectURIs',
     'virConnectListDefinedDomains',
     'virConnectListNetworks',
     'virConnectListDefinedNetworks',
@@ -428,6 +430,7 @@
 # functions than those already listed
 skip_function = (
     'virConnectListDomains', # Python API is called virConectListDomainsID for unknown reasons
+    'virConnectURIs',
     'virConnSetErrorFunc', # Not used in Python API  XXX is this a bug ?
     'virResetError', # Not used in Python API  XXX is this a bug ?
     'virGetVersion', # Python C code is manually written
Index: libvirt-0.9.8/src/Makefile.in
===================================================================
--- libvirt-0.9.8.orig/src/Makefile.in	2012-02-08 03:46:38.000000000 +0000
+++ libvirt-0.9.8/src/Makefile.in	2012-02-08 20:51:29.580231787 +0000
@@ -2548,6 +2548,8 @@
 
 AM_LDFLAGS = $(COVERAGE_LDFLAGS)
 
+bashdir = $(sysconfdir)/bash_completion.d
+
 # Add all conditional sources just in case...
 EXTRA_DIST = $(conf_DATA) util/keymaps.csv $(srcdir)/util/virkeymaps.h \
 	$(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py \
@@ -2586,7 +2588,7 @@
 	rpc/gensystemtap.pl rpc/virnetprotocol.x \
 	rpc/virkeepaliveprotocol.x $(am__append_137) $(am__append_139) \
 	$(STORAGE_HELPER_DISK_SOURCES) $(LXC_CONTROLLER_SOURCES) \
-	$(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES)
+	$(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES) virsh.bash
 BUILT_SOURCES = $(ESX_DRIVER_GENERATED) $(HYPERV_DRIVER_GENERATED) \
 	$(GENERATED_SYM_FILES) $(am__append_128) $(am__append_133) \
 	$(VIR_NET_RPC_GENERATED)
@@ -7016,6 +7018,8 @@
 @WITH_NETWORK_TRUE@	    cp $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml.t \
 @WITH_NETWORK_TRUE@	      $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml && \
 @WITH_NETWORK_TRUE@	    rm $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml.t; }
+	$(MKDIR_P) "$(DESTDIR)$(bashdir)"
+	$(INSTALL_DATA) "$(srcdir)/virsh.bash" "$(DESTDIR)$(bashdir)/virsh"
 
 uninstall-local::
 	rmdir "$(DESTDIR)$(localstatedir)/cache/libvirt" ||:
@@ -7041,6 +7045,7 @@
 @WITH_NETWORK_TRUE@	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/network" ||:
 @WITH_NETWORK_TRUE@	rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/network" ||:
 	rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt" ||:
+	rm -f "$(DESTDIR)$(bashdir)/virsh" ||:
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.




More information about the libvir-list mailing list