[sheepdog] [PATCH] script: auto-generate bash_completion_dog

MORITA Kazutaka morita.kazutaka at gmail.com
Thu Aug 15 13:58:49 CEST 2013


From: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>

The current bash_completion_dog is too out-of-date.  Rather than
updating the file, this patch adds a perl script to auto-generate the
file from dog help information like man/collie.8.

Signed-off-by: MORITA Kazutaka <morita.kazutaka at lab.ntt.co.jp>
---
 script/Makefile.am            |   19 ++-
 script/bash_completion_dog    |  303 -----------------------------------------
 script/gen_bash_completion.pl |  199 +++++++++++++++++++++++++++
 3 files changed, 214 insertions(+), 307 deletions(-)
 delete mode 100644 script/bash_completion_dog
 create mode 100755 script/gen_bash_completion.pl

diff --git a/script/Makefile.am b/script/Makefile.am
index 8fccd53..0ff5e62 100644
--- a/script/Makefile.am
+++ b/script/Makefile.am
@@ -2,10 +2,18 @@ MAINTAINERCLEANFILES    = Makefile.in
 
 EXTRA_DIST		= generic.in
 
-noinst_HEADERS		= bash_completion_dog checkarch.sh vditest gen_man.pl
+noinst_HEADERS		= bash_completion_dog checkarch.sh vditest gen_man.pl \
+			  gen_bash_completion.pl
 
 target_INIT             = generic
 
+target_BASH_COMPLETION  = bash_completion_dog
+
+bash_completion_dog: $(top_srcdir)/dog/dog gen_bash_completion.pl Makefile
+	rm -f $@-t $@
+	$(top_srcdir)/script/gen_bash_completion.pl $(top_builddir)/dog/dog > $@-t
+	mv $@-t $@
+
 %: %.in Makefile
 	rm -f $@-t $@
 	sed \
@@ -17,15 +25,18 @@ target_INIT             = generic
 	chmod 0755 $@-t
 	mv $@-t $@
 
-all-local: $(target_INIT)
+all-local: $(target_INIT) $(target_BASH_COMPLETION)
 
 clean-local:
 	rm -rf $(target_INIT)
+	rm -rf $(target_BASH_COMPLETION)
 
 install-exec-local:
 	$(INSTALL) -d $(DESTDIR)/$(INITDDIR)
 	$(INSTALL) -m 755 generic $(DESTDIR)/$(INITDDIR)/sheepdog
+	$(INSTALL) -d $(DESTDIR)/$(sysconfdir)/bash_completion.d
+	$(INSTALL) bash_completion_dog $(DESTDIR)/$(sysconfdir)/bash_completion.d/dog
 
 uninstall-local:
-	cd $(DESTDIR)/$(INITDDIR) && \
-		rm -f sheepdog
+	cd $(DESTDIR)/$(INITDDIR) && rm -f sheepdog
+	cd $(DESTDIR)/$(sysconfdir)/bash_completion.d && rm -f dog
diff --git a/script/bash_completion_dog b/script/bash_completion_dog
deleted file mode 100644
index 89c9544..0000000
--- a/script/bash_completion_dog
+++ /dev/null
@@ -1,303 +0,0 @@
-#!bash
-
-_dog_cluster_format()
-{
-    local cur
-    cur="${COMP_WORDS[COMP_CWORD]}"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-c --copies" \
-                -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_cluster_recover()
-{
-    local cur
-    cur="${COMP_WORDS[COMP_CWORD]}"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-f --force" \
-                -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_vdi_create()
-{
-    local cur
-    cur="${COMP_WORDS[COMP_CWORD]}"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-P --prealloc" \
-                -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_vdi_snapshot()
-{
-    local cur
-    cur="${COMP_WORDS[COMP_CWORD]}"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-s --snapshot" \
-                -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_vdi_clone()
-{
-    local cur
-    cur="${COMP_WORDS[COMP_CWORD]}"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-P --prealloc -s --snapshot" \
-                -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_vdi_read()
-{
-    local cur
-    cur="${COMP_WORDS[COMP_CWORD]}"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-s --snapshot" \
-                -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_vdi_delete()
-{
-    local cur dog vdilist
-    cur="${COMP_WORDS[COMP_CWORD]}"
-    dog="${COMP_WORDS[0]}"
-    vdilist="$(${dog} vdi list | tail -n+3 | grep '^  ' | awk '{print $1}')"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-s --snapshot" \
-                -- ${cur} ))
-            ;;
-        *)
-            COMPREPLY=($( compgen -W "${vdilist}" -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_vdi_object()
-{
-    local cur dog vdilist
-    cur="${COMP_WORDS[COMP_CWORD]}"
-    dog="${COMP_WORDS[0]}"
-    vdilist="$(${dog} vdi list | tail -n+3 | grep '^  ' | awk '{print $1}')"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-i --index -s --snapshot" \
-                -- ${cur} ))
-            ;;
-        *)
-            COMPREPLY=($( compgen -W "${vdilist}" -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_vdi_setattr()
-{
-    local cur
-    cur="${COMP_WORDS[COMP_CWORD]}"
-
-    case "$cur" in
-        -*)
-            COMPREPLY=(${COMPREPLY[@]} \
-                $( compgen \
-                -W "-d --delete -x --exclusive" \
-                -- ${cur} ))
-            ;;
-    esac
-}
-
-_dog_cluster()
-{
-    local opts
-    opts="info format shutdown recover snapshot"
-
-    case "$1" in
-        info)
-            ;;
-        format)
-            _dog_cluster_format
-            ;;
-        shutdown)
-            ;;
-        recover)
-            _dog_cluster_recover
-            ;;
-        snapshot)
-            ;;
-        "")
-            COMPREPLY=($( compgen \
-                -W "${opts}" \
-                -- "${COMP_WORDS[COMP_CWORD]}" ))
-            ;;
-        *)
-            COMPREPLY=()
-            ;;
-    esac
-}
-
-_dog_node()
-{
-    local opts
-    opts="info list recovery kill cache"
-
-    case "$1" in
-        info)
-            ;;
-        list)
-            ;;
-        recovery)
-            ;;
-        kill)
-            ;;
-        cache)
-            ;;
-        "")
-            COMPREPLY=($( compgen \
-                -W "${opts}" \
-                -- "${COMP_WORDS[COMP_CWORD]}" ))
-            ;;
-        *)
-            COMPREPLY=()
-            ;;
-    esac
-}
-
-_dog_vdi()
-{
-    local opts
-    opts="create snapshot clone resize read write \
-list tree graph delete object setattr getattr track check \
-rollback flush backup restore"
-
-    case "$1" in
-	create)
-	    _dog_vdi_create
-	    ;;
-	snapshot)
-	    _dog_vdi_snapshot
-	    ;;
-	clone)
-	    _dog_vdi_clone
-	    ;;
-	resize)
-	    ;;
-	read)
-	    _dog_vdi_read
-	    ;;
-	write)
-	    ;;
-        list)
-            ;;
-        tree)
-            ;;
-        graph)
-            ;;
-        delete)
-            _dog_vdi_delete
-            ;;
-        object)
-            _dog_vdi_object
-            ;;
-        setattr)
-            _dog_vdi_setattr
-            ;;
-        getattr)
-            ;;
-        track)
-            ;;
-        check)
-            ;;
-	rollback)
-	    ;;
-	flush)
-	    ;;
-	backup)
-	    ;;
-	restore)
-	    ;;
-        "")
-            COMPREPLY=($( compgen \
-                -W "${opts}" \
-                -- "${COMP_WORDS[COMP_CWORD]}" ))
-            ;;
-        *)
-            COMPREPLY=()
-            ;;
-    esac
-}
-
-_dog()
-{
-    local opts cur cmd subcmd i
-    opts="cluster node vdi"
-    cur="${COMP_WORDS[COMP_CWORD]}"
-
-    if [ $COMP_CWORD -gt 1 ]; then
-        cmd=${COMP_WORDS[1]}
-    fi
-
-    if [ $COMP_CWORD -gt 2 ]; then
-        subcmd=${COMP_WORDS[2]}
-    fi
-
-    COMPREPLY=($( compgen -W "-a --address -p --port -h --help" -- ${cur} ))
-
-    case "${cmd}" in
-        cluster)
-            _dog_cluster ${subcmd}
-            ;;
-        node)
-            _dog_node ${subcmd}
-            ;;
-        vdi)
-            _dog_vdi ${subcmd}
-            ;;
-        "")
-            COMPREPLY=($( compgen -W "${opts}" -- ${cur} ))
-            ;;
-        *)
-            COMPREPLY=()
-            ;;
-    esac
-}
-
-complete -F _dog dog
diff --git a/script/gen_bash_completion.pl b/script/gen_bash_completion.pl
new file mode 100755
index 0000000..070130c
--- /dev/null
+++ b/script/gen_bash_completion.pl
@@ -0,0 +1,199 @@
+#!/usr/bin/perl
+#
+# Genrate bash_completion_dog
+#
+
+use strict;
+
+my ($program) = @ARGV;
+
+print "#!bash\n";
+print "\n";
+
+open IN, "$program -h |" or die "cannot find $program\n";
+my @help = <IN>;
+close IN;
+
+# Hash of sub command arrays.
+# E.g. $subcmds{'node'} = [kill, list, info, recovery, md]
+my %subcmds;
+
+# Hash of sub sub command arrays.
+# E.g. $subsubcmds{'trace graph'} = [cat, stat]
+my %subsubcmds;
+
+# Hash of option arrays.
+# E.g. $opts{'node list'} = [-a, --address, -p, --port, -r, --raw, -h, --help]
+my %opts;
+
+foreach (@help) {
+    if (/^  (\S+) (\S+)/) {
+	my ($cmd, $subcmd) = ($1, $2);
+
+	$subcmds{$cmd} = []  if (!defined($subcmds{$cmd}));
+
+	push $subcmds{$cmd}, $subcmd;
+	$opts{"$cmd $subcmd"} = [];
+	$subsubcmds{"$cmd $subcmd"} = [];
+
+	# run sub command to get more detailed usage
+	open IN, "$program $cmd $subcmd -h |";
+	while (<IN>) {
+	    if (/^  (-.), (--\S+)/) {
+		# get options
+		push $opts{"$cmd $subcmd"}, $1;
+		push $opts{"$cmd $subcmd"}, $2;
+	    } elsif (/^  ([a-z]+)/) {
+		# get available subcommands
+		push $subsubcmds{"$cmd $subcmd"}, $1;
+	    }
+	}
+	close IN;
+    }
+}
+
+foreach my $cmd (keys %subcmds) {
+    my @subcmds = @{$subcmds{$cmd}};
+
+    print command($cmd, @subcmds);
+
+    foreach my $subcmd (@subcmds) {
+	print subcommand($cmd, $subcmd);
+    }
+}
+
+print <<__EOB__;
+_dog()
+{
+    local opts cur cmd subcmd
+    opts="@{[keys %subcmds]}"
+    cur="\${COMP_WORDS[COMP_CWORD]}"
+
+    if [ \$COMP_CWORD -gt 1 ]; then
+        cmd=\${COMP_WORDS[1]}
+    fi
+
+    if [ \$COMP_CWORD -gt 2 ]; then
+        subcmd=\${COMP_WORDS[2]}
+    fi
+
+    case "\${cmd}" in
+__EOB__
+
+    foreach my $cmd (keys %subcmds) {
+	print <<__EOB__;
+        $cmd)
+            _dog_$cmd \${subcmd}
+            ;;
+__EOB__
+    }
+
+print <<__EOB__;
+        "")
+            COMPREPLY=(\$( compgen -W "\${opts}" -- \${cur} ))
+            ;;
+        *)
+            COMPREPLY=()
+            ;;
+    esac
+}
+
+complete -F _dog dog
+__EOB__
+
+exit 0;
+
+# get a completion function for dog command (e.g. _dog_vdi())
+sub command {
+    my ($cmd, @subcmds) = @_;
+    my $output;
+
+    $output = <<__EOB__;
+    _dog_${cmd}()
+    {
+	local opts
+	opts="@subcmds"
+
+	case "\$1" in
+__EOB__
+
+    foreach my $subcmd (@subcmds) {
+	$output .= <<__EOB__;
+	    $subcmd)
+	        _dog_${cmd}_${subcmd}
+	        ;;
+__EOB__
+    }
+
+    $output .= <<__EOB__;
+	    "")
+	        COMPREPLY=(\$( compgen \\
+	            -W "\${opts}" \\
+	            -- "\${COMP_WORDS[COMP_CWORD]}" ))
+	        ;;
+	    *)
+	        COMPREPLY=()
+	        ;;
+        esac
+    }
+
+__EOB__
+
+    $output =~ s/\t/        /g;
+    $output =~ s/^    //gm;
+
+    return $output;
+}
+
+# get a completion function for dog subcommands (e.g. _dog_vdi_create())
+sub subcommand {
+    my ($cmd, $subcmd) = @_;
+    my $output;
+    my @opts = @{$opts{"$cmd $subcmd"}};
+    my @subsubcmds = @{$subsubcmds{"$cmd $subcmd"}};
+
+    $output = <<__EOB__;
+    _dog_${cmd}_${subcmd}()
+    {
+        local cur
+        cur="\${COMP_WORDS[COMP_CWORD]}"
+
+        case "\$cur" in
+            -*)
+                COMPREPLY=(\${COMPREPLY[@]} \\
+                    \$( compgen \\
+                    -W "@opts" \\
+__EOB__
+
+    $output .= <<__EOB__;
+                    -- \${cur} ))
+                ;;
+__EOB__
+
+    if ($cmd eq 'vdi' && $subcmd ne 'create') {
+	$output .= <<__EOB__;
+            *)
+                local dog="\${COMP_WORDS[0]}"
+		local vdilist="\$(\${dog} vdi list -r 2>/dev/null | awk '{print \$2}')"
+		COMPREPLY=(\$( compgen -W "@subsubcmds \${vdilist}" -- \${cur} ))
+                ;;
+__EOB__
+    } else {
+	$output .= <<__EOB__;
+            *)
+		COMPREPLY=(\$( compgen -W "@subsubcmds" -- \${cur} ))
+                ;;
+__EOB__
+    }
+
+    $output .= <<__EOB__;
+        esac
+    }
+
+__EOB__
+
+    $output =~ s/\t/        /g;
+    $output =~ s/^    //gm;
+
+    return $output;
+}
-- 
1.7.9.5




More information about the sheepdog mailing list