[virt-tools-list] [virt-viewer][PATCH v3] Introduce bash completion

Michal Privoznik mprivozn at redhat.com
Thu May 9 12:40:34 UTC 2019


With this change one can get list of domains on the command line:

  $ virt-viewer -c qemu:///system <TAB><TAB>
  dom1   dom2   ... domN

The list of domains is fetched using virsh, hence the dependency
on libvirt-client recorded in the spec file. I think it's fair
to assume that Linux hosts with virt-viewer will have virsh
available too. If they don't, nothing breaks and no error message
is printed.

The completer script is inspired by libvirt.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
Reviewed-by: Fabiano Fidêncio <fidencio at redhat.com>
---

diff to v2:
- Fixed --display completer. Problem was that a colon is viewed by bash
as a delimiter and thus ":0 :1024" options were confusing it.

 Makefile.am                 |   2 +-
 bash-completion/Makefile.am |  20 +++++++
 bash-completion/virt-viewer | 109 ++++++++++++++++++++++++++++++++++++
 configure.ac                |   9 ++-
 m4/virt-bash-completion.m4  |  83 +++++++++++++++++++++++++++
 virt-viewer.spec.in         |  14 +++++
 6 files changed, 235 insertions(+), 2 deletions(-)
 create mode 100644 bash-completion/Makefile.am
 create mode 100644 bash-completion/virt-viewer
 create mode 100644 m4/virt-bash-completion.m4

diff --git a/Makefile.am b/Makefile.am
index 4cfdd59..9dda6a3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@ NULL =
 
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = icons src man po data tests
+SUBDIRS = bash-completion icons src man po data tests
 
 AM_DISTCHECK_CONFIGURE_FLAGS = --disable-update-mimedb
 EXTRA_DIST =					\
diff --git a/bash-completion/Makefile.am b/bash-completion/Makefile.am
new file mode 100644
index 0000000..be1fc3f
--- /dev/null
+++ b/bash-completion/Makefile.am
@@ -0,0 +1,20 @@
+EXTRA_DIST = \
+	$(PACKAGE)
+
+install-data-local: install-bash-completion
+
+uninstall-local: uninstall-bash-completion
+
+if WITH_BASH_COMPLETION
+install-bash-completion:
+	$(MKDIR_P) "$(DESTDIR)$(BASH_COMPLETIONS_DIR)"
+	$(INSTALL_SCRIPT) $(srcdir)/$(PACKAGE) \
+		"$(DESTDIR)$(BASH_COMPLETIONS_DIR)/$(PACKAGE)"
+
+uninstall-bash-completion:
+	rm -f $(DESTDIR)$(BASH_COMPLETIONS_DIR)/$(PACKAGE)
+	rmdir $(DESTDIR)$(BASH_COMPLETIONS_DIR) ||:
+else ! WITH_BASH_COMPLETION
+install-bash-completion:
+uninstall-bash-completion:
+endif ! WITH_BASH_COMPLETION
diff --git a/bash-completion/virt-viewer b/bash-completion/virt-viewer
new file mode 100644
index 0000000..27bdb30
--- /dev/null
+++ b/bash-completion/virt-viewer
@@ -0,0 +1,109 @@
+#
+# virt-viewer completer
+#
+
+_virt_viewer_complete()
+{
+    local words cword c w cur URI CMDLINE MODE DOMS
+
+    # Here, $COMP_WORDS is an array of words on the bash
+    # command line that user wants to complete. However, when
+    # parsing command line, the default set of word breaks is
+    # applied. This doesn't work for us as it mangles virt-viewer
+    # arguments, e.g. connection URI (with the default set it's
+    # split into multiple items within the array). Fortunately,
+    # there's a fixup function for the array.
+    _get_comp_words_by_ref -n "\"'><=;|&(:" -w words -i cword
+    COMP_WORDS=( "${words[@]}" )
+    COMP_CWORD=${cword}
+    cur=${COMP_WORDS[$COMP_CWORD]}
+
+    MODE="--name"
+    ALL="--all"
+    # See what URI is user trying to connect to. Honour that.
+    for ((c=1; c<=${COMP_CWORD}; c++)); do
+        case "${COMP_WORDS[c]}" in
+            -c|--connect)
+                if [[ -n "${COMP_WORDS[c+1]}" ]]; then
+                    URI="${COMP_WORDS[c+1]}"
+                    c=$((++c))
+                fi
+                ;;
+
+            --connect=*)
+                w=${COMP_WORDS[c]#*=}
+                if [[ -z "$w" ]] ; then
+                    return
+                fi
+                URI=$w
+                ;;
+
+            --domain-name)
+                # Generate list of domain names which is done below
+                MODE="--name"
+                ALL="--all"
+                ;;
+
+            --uuid)
+                # Generate list of domain UUIDs which is done below
+                MODE="--uuid"
+                ALL="--all"
+                ;;
+
+            --id)
+                # Generate list of domain IDs which is done below
+                MODE=""
+                ALL=""
+                ;;
+        esac
+    done
+
+    case "$cur" in
+        --connect=*)
+            # Nada
+            return
+            ;;
+
+        --display=*)
+            cur=${cur#*=}
+            DISPLAYS=$(cd /tmp/.X11-unix && for x in X*; do echo ":${x#X}"; done)
+            COMPREPLY=($(compgen -W '${DISPLAYS}' -- "$cur"))
+            __ltrim_colon_completions "$cur"
+            return
+            ;;
+
+        --kiosk-quit=*)
+            cur=${cur#*=}
+            COMPREPLY=($(compgen -W 'never on-disconnect' -- "$cur"))
+            return
+            ;;
+
+        -*)
+            # If the current option already ends with '=' then don't generate
+            # any more --options
+            if [[ $cur == *= ]] ; then
+                return
+            fi
+            COMPREPLY=($(compgen -W '$( _parse_help "$1" -h )' -- "$cur"))
+            if [[ $COMPREPLY == *= ]] ; then
+                compopt -o nospace
+            fi
+            return
+            ;;
+    esac
+
+    CMDLINE=
+    if [ -n "${URI}" ]; then
+        CMDLINE="${CMDLINE} -c ${URI}"
+    fi
+
+    DOMS=($(virsh -q -r ${CMDLINE} list ${ALL} ${MODE} 2>/dev/null | awk '{print $1;}' ))
+
+    COMPREPLY=($(compgen -W "${DOMS[*]%--}" -- ${cur}))
+
+    __ltrim_colon_completions "${cur}"
+    return
+} &&
+complete -F _virt_viewer_complete virt-viewer
+
+# vim: ft=sh:et:ts=4:sw=4:tw=80
diff --git a/configure.ac b/configure.ac
index 7b61821..b39c41e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,3 @@
-
 AC_INIT([virt-viewer],[9.0])
 AC_CONFIG_SRCDIR(src/virt-viewer-main.c)
 AC_CONFIG_MACRO_DIR([m4])
@@ -12,6 +11,8 @@ AC_CANONICAL_HOST
 m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])
 AM_SILENT_RULES([yes])
 
+BASH_COMPLETION_REQUIRED="2.0"
+
 # Keep these two definitions in agreement.
 GLIB2_REQUIRED="2.40"
 GLIB2_ENCODED_VERSION="GLIB_VERSION_2_40"
@@ -29,6 +30,7 @@ SPICE_PROTOCOL_REQUIRED="0.12.7"
 GOVIRT_REQUIRED="0.3.3"
 REST_REQUIRED="0.8"
 
+AC_SUBST([BASH_COMPLETION_REQUIRED])
 AC_SUBST([GLIB2_REQUIRED])
 AC_SUBST([LIBXML2_REQUIRED])
 AC_SUBST([LIBVIRT_REQUIRED])
@@ -99,6 +101,9 @@ AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],"$GETTEXT_PACKAGE", [GETTEXT package name])
 VIRT_VIEWER_ARG_NLS
 VIRT_VIEWER_CHECK_NLS
 
+VIRT_VIEWER_ARG_BASH_COMPLETION
+VIRT_VIEWER_CHECK_BASH_COMPLETION
+
 PKG_PROG_PKG_CONFIG
 GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
 AC_SUBST(GLIB_MKENUMS)
@@ -250,6 +255,7 @@ AM_CONDITIONAL(ENABLE_UPDATE_MIMEDB, test x$enable_update_mimedb = xyes)
 
 AC_CONFIG_FILES([
     Makefile
+    bash-completion/Makefile
     data/Makefile
     data/virt-viewer.wxs
     icons/Makefile
@@ -291,3 +297,4 @@ AC_MSG_NOTICE([     LIBVIRT: $LIBVIRT_CFLAGS $LIBVIRT_LIBS])
 AC_MSG_NOTICE([])
 AC_MSG_NOTICE([       OVIRT: $OVIRT_CFLAGS $OVIRT_LIBS])
 AC_MSG_NOTICE([])
+VIRT_VIEWER_RESULT_BASH_COMPLETION
diff --git a/m4/virt-bash-completion.m4 b/m4/virt-bash-completion.m4
new file mode 100644
index 0000000..6a7267c
--- /dev/null
+++ b/m4/virt-bash-completion.m4
@@ -0,0 +1,83 @@
+dnl Bash completion support
+dnl
+dnl Copyright (C) 2017 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library.  If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+dnl Inspired by libvirt code.
+dnl
+
+AC_DEFUN([VIRT_VIEWER_ARG_BASH_COMPLETION],[
+  m4_divert_text([DEFAULTS], [[enable_bash_completion=check]])
+  AC_ARG_ENABLE([bash_completion],
+                [AS_HELP_STRING([--enable-bash-completion],
+                                [bash completion @<:@default=check@:>@])])
+  m4_divert_text([DEFAULTS], [[with_bash_completions_dir=check]])
+  AC_ARG_WITH([bash_completions_dir],
+              [AS_HELP_STRING([--with-bash-completions-dir=DIR],
+                              [directory containing bash completions scripts @<:@default=check@:>@])])
+])
+
+
+AC_DEFUN([VIRT_VIEWER_CHECK_BASH_COMPLETION], [
+  if test "x$enable_bash_completion" != "xno" ; then
+    PKG_CHECK_MODULES(BASH_COMPLETION, bash-completion >= $BASH_COMPLETION_REQUIRED,
+                      [with_bash_completion=yes],
+                      [with_bash_completion=no])
+    if test "x$enable_bash_completion:x$with_bash_completion" = "yes:no"; then
+      m4_default(fail_action,
+        [AC_MSG_ERROR([You must install the ]pc_name[ >= ]pc_version[ pkg-config module to compile virt-viewer])])
+    fi
+    enable_bash_completion=$with_bash_completion
+  fi
+
+  if test "x$with_bash_completion" = "xyes" ; then
+    if test "x$with_bash_completions_dir" = "xcheck"; then
+      AC_MSG_CHECKING([for bash-completions directory])
+      BASH_COMPLETIONS_DIR="$($PKG_CONFIG --variable=completionsdir bash-completion)"
+      AC_MSG_RESULT([$BASH_COMPLETIONS_DIR])
+      with_bash_completions_dir=$BASH_COMPLETIONS_DIR
+
+      dnl Replace bash completions's exec_prefix with our own.
+      dnl Note that ${exec_prefix} is kept verbatim at this point in time,
+      dnl and will only be expanded later, when make is called: this makes
+      dnl it possible to override such prefix at compilation or installation
+      dnl time
+      bash_completions_prefix="$($PKG_CONFIG --variable=prefix bash-completion)"
+      if test "x$bash_completions_prefix" = "x" ; then
+        bash_completions_prefix="/usr"
+      fi
+
+      BASH_COMPLETIONS_DIR='${exec_prefix}'"${BASH_COMPLETIONS_DIR#$bash_completions_prefix}"
+    elif test "x$with_bash_completions_dir" = "xno" || test "x$with_bash_completions_dir" = "xyes"; then
+      AC_MSG_ERROR([bash-completions-dir must be used only with valid path])
+    else
+      BASH_COMPLETIONS_DIR=$with_bash_completions_dir
+    fi
+    AC_SUBST([BASH_COMPLETIONS_DIR])
+  fi
+
+  AM_CONDITIONAL([WITH_BASH_COMPLETION], [test "x$enable_bash_completion" = "xyes"])
+])
+
+
+AC_DEFUN([VIRT_VIEWER_RESULT_BASH_COMPLETION],[
+  if test "x$enable_bash_completion" = "xyes" ; then
+    AC_MSG_NOTICE([bash completion: $enable_bash_completion DIR: [$with_bash_completions_dir]])
+  else
+    AC_MSG_NOTICE([bash completion: $enable_bash_completion])
+  fi
+  AC_MSG_NOTICE([])
+])
diff --git a/virt-viewer.spec.in b/virt-viewer.spec.in
index eea5a74..56a3a8a 100644
--- a/virt-viewer.spec.in
+++ b/virt-viewer.spec.in
@@ -11,8 +11,10 @@
 %endif
 
 %define with_govirt 0
+%define with_bash_completion 0
 %if 0%{?fedora} > 19 || 0%{?rhel} >= 7
 %define with_govirt 1
+%define with_bash_completion 1
 %endif
 
 Name: @PACKAGE@
@@ -28,6 +30,12 @@ Requires(postun): %{_sbindir}/update-alternatives
 Requires(post): desktop-file-utils
 Requires(postun): desktop-file-utils
 
+%if %{with_bash_completion}
+# Our bash completion script uses virsh to list domains
+Requires: libvirt-client
+%endif
+
+
 %if 0%{?enable_autotools}
 BuildRequires: autoconf
 BuildRequires: automake
@@ -51,6 +59,9 @@ BuildRequires: gettext
 %if %{with_govirt}
 BuildRequires: pkgconfig(govirt-1.0) >= @GOVIRT_REQUIRED@
 %endif
+%if %{with_bash_completion}
+BuildRequires: pkgconfig(bash-completion) >= @BASH_COMPLETION_REQUIRED@
+%endif
 
 %if 0%{?fedora} >= 20
 Obsoletes: spice-client < 0.12.3-2
@@ -102,5 +113,8 @@ rm -rf $RPM_BUILD_ROOT
 %{_datadir}/mime/packages/virt-viewer-mime.xml
 %{_mandir}/man1/virt-viewer.1*
 %{_mandir}/man1/remote-viewer.1*
+%if %{with_bash_completion}
+%{_datadir}/bash-completion/completions/virt-viewer
+%endif
 
 %changelog
-- 
2.21.0




More information about the virt-tools-list mailing list