nbdkit/0002-Add-simple-bash-comple...

370 lines
12 KiB
Diff

From 772cfefad72f4c2ec5a72bc73f75a2921fe6054b Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Sat, 9 Jun 2018 17:01:06 +0100
Subject: [PATCH 2/2] Add simple bash completion script.
So far this can complete plugin names:
$ nbdkit <TAB>
curl example4 libvirt perl ruby vddk
example1 file memory python split xz
example2 guestfs nbd python2 streaming
example3 gzip null python3 tar
Plugin parameters:
$ nbdkit curl <TAB>
password= sslverify= timeout= url= user=
Filter names:
$ nbdkit --filter=<TAB>
cache cow delay offset partition
General options (short or long or both):
$ nbdkit -<TAB>
--dump-config --new-style --single
--dump-plugin --newstyle --stdin
-e --no-fork -t
--exit-with-parent -o --threads
--export --old-style --tls
--export-name --oldstyle --tls-certificates
--exportname -p --tls-verify-peer
-f -P -u
--filter --pid-file -U
--foreground --pidfile --unix
-g --port --user
--group -r -v
--help --read-only -V
-i --readonly --verbose
--ip-addr --run --version
--ipaddr -s
-n --selinux-label
And --tls options:
$ nbdkit --tls=<TAB>
off on require
There is still quite a lot more which it doesn't do, such as
completing filter parameters, and smarter completion for options.
---
Makefile.am | 1 +
README | 4 ++
TODO | 2 -
bash/Makefile.am | 40 ++++++++++++++++++++
bash/README | 8 ++++
bash/nbdkit | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
configure.ac | 15 ++++++++
src/main.c | 17 +++++++++
8 files changed, 198 insertions(+), 2 deletions(-)
create mode 100644 bash/Makefile.am
create mode 100644 bash/README
create mode 100644 bash/nbdkit
diff --git a/Makefile.am b/Makefile.am
index 9c5b4c3..9d097f5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -44,6 +44,7 @@ EXTRA_DIST = \
noinst_SCRIPTS = nbdkit
SUBDIRS = \
+ bash \
docs \
include \
src
diff --git a/README b/README
index e58df8b..a589d77 100644
--- a/README
+++ b/README
@@ -91,6 +91,10 @@ For the OCaml plugin:
- OCaml >= 4.02.2 which has support for shared libraries, see:
http://caml.inria.fr/mantis/view.php?id=6693
+For bash tab completion:
+
+ - bash-completion >= 1.99
+
To run the test suite:
- bash
diff --git a/TODO b/TODO
index fe0af0c..07f40cc 100644
--- a/TODO
+++ b/TODO
@@ -10,8 +10,6 @@ General ideas for improvements
* Performance - measure and improve it.
-* Bash tab completion.
-
* Exit on last connection (the default behaviour of qemu-nbd unless
you use -t).
diff --git a/bash/Makefile.am b/bash/Makefile.am
new file mode 100644
index 0000000..2a2799a
--- /dev/null
+++ b/bash/Makefile.am
@@ -0,0 +1,40 @@
+# nbdkit
+# Copyright (C) 2018 Red Hat Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+EXTRA_DIST = README
+
+if HAVE_BASH_COMPLETION
+
+bashcompdir = @bashcompdir@
+dist_bashcomp_DATA = nbdkit
+
+endif
diff --git a/bash/README b/bash/README
new file mode 100644
index 0000000..21a4f71
--- /dev/null
+++ b/bash/README
@@ -0,0 +1,8 @@
+This directory contains the scripts for tab-completing commands in
+bash. Note these new-style demand-loaded scripts require
+bash-completion >= 1.99.
+
+Tip: To test the bash completions without having to install them,
+simply start a new shell and do:
+
+ source ./bash/nbdkit; PATH=$PWD:$PATH
diff --git a/bash/nbdkit b/bash/nbdkit
new file mode 100644
index 0000000..3db531d
--- /dev/null
+++ b/bash/nbdkit
@@ -0,0 +1,113 @@
+# nbdkit bash completion script -*- shell-script -*-
+# Copyright (C) 2010-2018 Red Hat Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Red Hat nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+_nbdkit_list_plugins ()
+{
+ local plugindir
+ plugindir="$(
+ nbdkit --dump-config | grep ^plugindir= | sed 's/^plugindir=//'
+ )"
+ ls -1 "$plugindir" | sed 's/^nbdkit-//' | sed 's/-plugin.*//'
+}
+
+_nbdkit_list_filters ()
+{
+ local filterdir
+ filterdir="$(
+ nbdkit --dump-config | grep ^filterdir= | sed 's/^filterdir=//'
+ )"
+ ls -1 "$filterdir" | sed 's/^nbdkit-//' | sed 's/-filter.*//'
+}
+
+# This handler function is called when the user presses tab.
+_nbdkit ()
+{
+ local cur prev words cword split
+ local shortopts longopts plugin plugins filters args i
+
+ _init_completion -s || return
+
+ # Did we get the plugin name yet?
+ # This is only a heuristic because it can be confused by
+ # long opt parameters with an arguments. XXX
+ plugin=
+ for (( i=1; i < ${#words[@]}; ++i)) ; do
+ if [[ "${words[i]}" =~ ^[a-zA-Z0-9]+$ ]]; then
+ plugin="${words[i]}"
+ break
+ fi
+ done
+
+ # Previous item on the current line is a completable flag or plugin name?
+ case "$prev" in
+ --filter)
+ filters="$(_nbdkit_list_filters)"
+ COMPREPLY=( $(compgen -W "$filters" "$cur") )
+ return ;;
+ --tls)
+ COMPREPLY=( $(compgen -W "off on require" "$cur") )
+ return ;;
+ # Could complete -u and -g options too. XXX
+ esac
+
+ # Current item is an option we can expand?
+ case "$cur" in
+ --*)
+ longopts="$(nbdkit --long-options)"
+ COMPREPLY=( $(compgen -W "$longopts" -- "$cur") )
+ return ;;
+ -*)
+ shortopts="$(nbdkit --short-options)"
+ longopts="$(nbdkit --long-options)"
+ COMPREPLY=( $(compgen -W "$shortopts $longopts" -- "$cur") )
+ return ;;
+ *)
+ if [ "$plugin" = "" ]; then
+ # Complete plugin name.
+ plugins="$(_nbdkit_list_plugins)"
+ COMPREPLY=( $(compgen -W "$plugins" "$cur") )
+ return
+ else
+ # Complete plugin args.
+ args="$(
+ nbdkit $plugin --help 2>/dev/null |
+ grep -E '^[a-z0-9]+=' | sed 's/=.*/=/'
+ )"
+ COMPREPLY=( $(compgen -W "$args" "$cur") )
+ return
+ fi
+ ;;
+ esac
+}
+
+# Install the handler function.
+complete -o default -F _nbdkit nbdkit
diff --git a/configure.ac b/configure.ac
index 0ef9673..abf7048 100644
--- a/configure.ac
+++ b/configure.ac
@@ -164,6 +164,20 @@ AS_IF([test "$GNUTLS_LIBS" != ""],[
dnl Check for valgrind.
AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind],[no])
+dnl Bash completion.
+PKG_CHECK_MODULES([BASH_COMPLETION], [bash-completion >= 2.0], [
+ bash_completion=yes
+ AC_MSG_CHECKING([for bash-completions directory])
+ PKG_CHECK_VAR(bashcompdir, [bash-completion], [completionsdir], ,
+ bashcompdir="${sysconfdir}/bash_completion.d")
+ AC_MSG_RESULT([$bashcompdir])
+ AC_SUBST([bashcompdir])
+],[
+ bash_completion=no
+ AC_MSG_WARN([bash-completion not installed])
+])
+AM_CONDITIONAL([HAVE_BASH_COMPLETION],[test "x$bash_completion" = "xyes"])
+
dnl Check for Perl POD.
AC_CHECK_PROG([POD2MAN], [pod2man], [pod2man], [no])
AS_IF([test "x$POD2MAN" != "xno"],[
@@ -526,6 +540,7 @@ AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([nbdkit],
[chmod +x,-w nbdkit])
AC_CONFIG_FILES([Makefile
+ bash/Makefile
docs/Makefile
include/Makefile
plugins/Makefile
diff --git a/src/main.c b/src/main.c
index d2e5674..660d036 100644
--- a/src/main.c
+++ b/src/main.c
@@ -126,6 +126,7 @@ static const struct option long_options[] = {
{ "group", 1, NULL, 'g' },
{ "ip-addr", 1, NULL, 'i' },
{ "ipaddr", 1, NULL, 'i' },
+ { "long-options", 0, NULL, 0 },
{ "new-style", 0, NULL, 'n' },
{ "newstyle", 0, NULL, 'n' },
{ "old-style", 0, NULL, 'o' },
@@ -137,6 +138,7 @@ static const struct option long_options[] = {
{ "readonly", 0, NULL, 'r' },
{ "run", 1, NULL, 0 },
{ "selinux-label", 1, NULL, 0 },
+ { "short-options", 0, NULL, 0 },
{ "single", 0, NULL, 's' },
{ "stdin", 0, NULL, 's' },
{ "threads", 1, NULL, 't' },
@@ -263,6 +265,14 @@ main (int argc, char *argv[])
t->filename = optarg;
filter_filenames = t;
}
+ else if (strcmp (long_options[option_index].name, "long-options") == 0) {
+ for (i = 0; long_options[i].name != NULL; ++i) {
+ if (strcmp (long_options[i].name, "long-options") != 0 &&
+ strcmp (long_options[i].name, "short-options") != 0)
+ printf ("--%s\n", long_options[i].name);
+ }
+ exit (EXIT_SUCCESS);
+ }
else if (strcmp (long_options[option_index].name, "run") == 0) {
if (socket_activation) {
fprintf (stderr, "%s: cannot use socket activation with --run flag\n",
@@ -276,6 +286,13 @@ main (int argc, char *argv[])
selinux_label = optarg;
break;
}
+ else if (strcmp (long_options[option_index].name, "short-options") == 0) {
+ for (i = 0; short_options[i]; ++i) {
+ if (short_options[i] != ':')
+ printf ("-%c\n", short_options[i]);
+ }
+ exit (EXIT_SUCCESS);
+ }
else if (strcmp (long_options[option_index].name, "tls") == 0) {
tls_set_on_cli = 1;
if (strcmp (optarg, "off") == 0 || strcmp (optarg, "0") == 0)
--
2.16.2