370 lines
12 KiB
Diff
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
|
||
|
|