[devscripts] 01/03: Added custom bash completion support for bts (Closes: #499886)

Nicholas Bamber periapt at moszumanska.debian.org
Sun Nov 15 15:35:32 UTC 2015


This is an automated email from the git hooks/post-receive script.

periapt pushed a commit to branch master
in repository devscripts.

commit 313e9fe14cd370071cce98dcf46d77f85bcf7e95
Author: Nicholas Bamber <nicholas at periapt.co.uk>
Date:   Sat Nov 14 15:57:24 2015 +0000

    Added custom bash completion support for bts (Closes: #499886)
    
    * Added custom bash completion support for bts (Closes: #499886)
      - Added --soap-timeout option to bts
      - Added listcachedbugs command to bts
      - Split out bts bash completion handling into its own script
---
 debian/changelog                 |   4 +
 debian/links                     |   1 -
 lib/Devscripts/Debbugs.pm        |  14 +-
 scripts/bts.bash_completion      | 309 +++++++++++++++++++++++++++++++++++++++
 scripts/bts.pl                   |  41 ++++++
 scripts/pkgnames.bash_completion |   2 +-
 6 files changed, 368 insertions(+), 3 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index a5ff9ce..886efd3 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -15,6 +15,10 @@ devscripts (2.15.10) UNRELEASED; urgency=medium
     - Removed undefined "$filenames" from chdist.bash_completion
     - Split debi.bash_completion off from pkgnames.bash_completion
       and added links for both debi/debc and corrected complete commands
+  * Added custom bash completion support for bts (Closes: #499886)
+    - Added --soap-timeout option to bts
+    - Added listcachedbugs command to bts
+    - Split out bts bash completion handling into its own script
 
   [ Dominique Dumont ]
   * licensecheck: parse file matching -c regex whatever its mime
diff --git a/debian/links b/debian/links
index 863ec89..44d8bfa 100644
--- a/debian/links
+++ b/debian/links
@@ -25,7 +25,6 @@
 /usr/share/bash-completion/completions/pkgnames  /usr/share/bash-completion/completions/dcontrol
 /usr/share/bash-completion/completions/pkgnames  /usr/share/bash-completion/completions/grep-excuses
 /usr/share/bash-completion/completions/pkgnames  /usr/share/bash-completion/completions/rc-alert
-/usr/share/bash-completion/completions/pkgnames  /usr/share/bash-completion/completions/bts
 /usr/share/bash-completion/completions/pkgnames  /usr/share/bash-completion/completions/whodepends
 /usr/share/bash-completion/completions/pkgnames  /usr/share/bash-completion/completions/dget
 /usr/share/bash-completion/completions/pkgnames  /usr/share/bash-completion/completions/pts-subscribe
diff --git a/lib/Devscripts/Debbugs.pm b/lib/Devscripts/Debbugs.pm
index ee4ecdf..cb078e2 100644
--- a/lib/Devscripts/Debbugs.pm
+++ b/lib/Devscripts/Debbugs.pm
@@ -101,6 +101,14 @@ my $soapurl='Debbugs/SOAP/1';
 our $btsurl='http://bugs.debian.org/';
 my @errors;
 
+our $soap_timeout;
+sub soap_timeout {
+    my $timeout_arg = shift;
+    if (defined $timeout_arg and $timeout_arg =~ m{^[1-9]\d*$}) {
+        $soap_timeout = $timeout_arg;
+    }
+}
+
 sub init_soap {
     my $soapproxyurl;
     if ($btsurl =~ m%^https?://(.*)/?$%) {
@@ -110,7 +118,11 @@ sub init_soap {
     }
     $soapproxyurl =~ s%//$%/%;
     $soapproxyurl .= 'cgi-bin/soap.cgi';
-    my $soap = SOAP::Lite->uri($soapurl)->proxy($soapproxyurl);
+    my %options;
+    if ($soap_timeout) {
+        $options{timeout} = $soap_timeout;
+    }
+    my $soap = SOAP::Lite->uri($soapurl)->proxy($soapproxyurl, %options);
 
     $soap->transport->env_proxy();
     $soap->on_fault(\&getSOAPError);
diff --git a/scripts/bts.bash_completion b/scripts/bts.bash_completion
new file mode 100644
index 0000000..a272764
--- /dev/null
+++ b/scripts/bts.bash_completion
@@ -0,0 +1,309 @@
+# Debian bts(1) completion                             -*- shell-script -*-
+
+_get_version_from_package()
+{
+    local _pkg=$1
+    [[ -n $_pkg ]] || return 
+    apt-cache madison $_pkg 2> /dev/null | cut -d'|' -f2 | sort | uniq | paste -s -d' '
+}
+
+# This works really well unless someone sets up nasty firewall rules like:
+# sudo iptables -A OUTPUT -d 206.12.19.140 -j DROP
+# sudo iptables -A OUTPUT -d 140.211.166.26 -j DROP
+# These block access to the Debian bugs SOAP interface.
+# Hence we need a timeout.
+# Of course if the SOAP interface is blocked then so is the caching interface.
+# So really this would only affect someone who only accidentally hit the TAB key.
+_get_version_from_bug()
+{
+    local -i _bug=$1
+    _get_version_from_package $( bts --soap-timeout=2 status $_bug fields:package 2> /dev/null | cut -f2 )
+}
+
+_suggest_packages()
+{
+    apt-cache --no-generate pkgnames "$1" 2> /dev/null
+}
+
+_suggest_bugs()
+{
+    bts --offline listcachedbugs "$1" 2> /dev/null
+}
+
+_bts()
+{
+    local cur prev words cword
+    _init_completion -n = || return
+
+    # Note:
+    # The long lists of subcommands are not the same and not necessarily to be kept in sync.
+    # The first is used to suggest commands after a '.' or ','.
+    # The second is to hook in special handling (which may be as little as admitting we 
+    # we can't handle it further) or the default special handling (list of bug ids).
+    # This also includes "by" and "with" which are not even subcommands.
+    # The third is similar to the first - what to suggest after the bts command (and options).
+    # but this includes the "help" and "version" commands.
+
+    # A sequence of bts commands can be on one command line separated by "." or ",". 
+    if [[ $prev == @(.|,) ]]; then
+        COMPREPLY=( $( compgen -W 'show bugs unmerge select status clone done reopen archive unarchive retitle summary submitter reassign found notfound fixed notfixed block unblock merge forcemerge tags affects user usertags claim unclaim severity forwarded notforwarded package limit owner noowner subscribe unsubscribe reportspam spamreport' -- "$cur" ) )
+        return 0
+    fi
+
+    # Identify the last command in the command line.
+    local special punctuation i
+    for (( i=${#words[@]}-1; i > 0; i-- )); do
+        if [[ ${words[i]} == @(show|bugs|select|limit|unmerge|status|clone|done|reopen|archive|unarchive|retitle|summary|submitter|reassign|found|notfound|fixed|notfixed|block|unblock|merge|forcemerge|tags|affects|user|usertags|claim|unclaim|severity|forwarded|notforwarded|package|owner|noowner|subscribe|unsubscribe|reportspam|spamreport|cache|cleancache|by|with) ]]; then
+            special=${words[i]}
+            break
+        fi
+        if [[ ${words[i]} == @(+|-|=) ]]; then
+            punctuation=${words[i]}
+        fi
+    done
+
+    if [[ -n $special ]]; then
+
+    # The command separator must be surrounded by white space.
+    if [[ "$cur" == @(,|.) ]]; then
+        COMPREPLY=( $cur )
+        return 0
+    fi
+
+    case $special in
+        show|bugs)
+            # bugs/show supports a few limited options
+            # but as args we accept bug ids, package names and release-critical
+            if [[ "$cur" == -* ]]; then
+                COMPREPLY=( $( compgen -W '-o --offline --online -m --mbox \
+                    --no-cache --cache' -- "$cur" ) )
+            elif [[ "$cur" == release-critical/* ]]; then
+                local _pkg=${cur#release-critical/}
+                COMPREPLY=( $( _suggest_packages "$_pkg" | sed -e's!^!release-critical/!' ) )
+            else
+                COMPREPLY=( $( compgen -W 'release-critical RC' -- "$cur" ) \
+                    $( _suggest_bugs "$cur" ) \
+                    $( _suggest_packages "$cur" ) )
+            fi
+            return 0
+            ;;
+        status)
+            # we accept "verbose" and bug ids
+            COMPREPLY=( $( compgen -W 'verbose' -- "$cur" ) \
+                $( _suggest_bugs "$cur" ) )
+            return 0
+            ;;
+        clone)
+            # we accept 1 bug id and then generate new clone ids
+            if [[ "$prev" == +([0-9]) ]]; then
+                COMPREPLY=( $( compgen -W '-1' -- "$cur" ) )
+            elif [[ "$prev" == -+([0-9]) ]]; then
+                local -i j
+                (( j=$prev-1 ))
+                COMPREPLY=( $( compgen -W $j -- "$cur" ) )
+            else
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            fi
+            return 0
+            ;;
+        done|found|notfound|fixed|notfixed)
+            # Try to guess the version 
+            if [[ "$prev" == +([0-9]) ]]; then
+                local _versions=$( _get_version_from_bug $prev )
+                if [[ -n $_versions ]]; then
+                    COMPREPLY=( $( compgen -W $_versions -- "$cur" ) )
+                else
+                    COMPREPLY=( )
+                fi
+            else
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            fi
+            return 0
+            ;;
+        reopen|claim|unclaim|owner|subscribe|unsubscribe)
+            if [[ "$prev" == +([0-9]) && -n $DEBEMAIL ]]; then
+                COMPREPLY=( $( compgen -W $DEBEMAIL -- "$cur" ) )
+            else
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            fi
+            return 0
+            ;;
+        reassign)
+            # Must have at least one bug id.
+            # Once we have a package name, all that remains is an optional version.
+            if [[ "$prev" == $special ]]; then
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            elif [[ "$prev" == +([0-9]) ]]; then
+                COMPREPLY=( $( _suggest_bugs "$cur" ) \
+                $( _suggest_packages "$cur" ) )
+            else
+                local _versions=$( _get_version_from_package $prev )
+                COMPREPLY=( $( compgen -W $_versions -- "$cur" ) )
+            fi
+            return 0
+            ;;
+        block|unblock)
+            # Must have at least one bug id.
+            if [[ "$prev" == $special ]]; then
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            elif [[ "$prev" == +([0-9]) ]]; then
+                COMPREPLY=( $( compgen -W 'by with' -- "$cur" ) )
+            else
+                COMPREPLY=( )
+            fi
+            return 0
+            ;;
+        unmerge|forwarded|notforwarded|noowner)
+            # Must have at most one bug id.
+            if [[ "$prev" == $special ]]; then
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            else
+                COMPREPLY=( )
+            fi
+            return 0
+            ;;
+        tags)
+            # Must have one bug id.
+            if [[ "$prev" == $special ]]; then
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            elif [[ -n $punctuation ]]; then
+                # The official list is mirrored
+                # https://www.debian.org/Bugs/server-control#tag
+                # in the variable @gTags; we copy it verbatim here.
+                COMPREPLY=( $( compgen -W 'patch wontfix moreinfo unreproducible help pending security upstream confirmed fixed fixed-upstream fixed-in-experimental d-i ipv6 lfs l10n potato woody sarge sarge-ignore etch etch-ignore lenny lenny-ignore squeeze squeeze-ignore wheezy wheezy-ignore jessie jessie-ignore sid experimental' -- "$cur" ) )
+            else
+                COMPREPLY=()
+                COMPREPLY[0]='= '
+                COMPREPLY[1]='+ '
+                COMPREPLY[2]='- '
+            fi
+            return 0
+            ;;
+        affects)
+            # Must have one bug id.
+            if [[ "$prev" == $special ]]; then
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            elif [[ -n $punctuation ]]; then
+                COMPREPLY=( $( _suggest_packages "$cur" ) )
+            else
+                COMPREPLY=()
+                COMPREPLY[0]='= '
+                COMPREPLY[1]='+ '
+                COMPREPLY[2]='- '
+            fi
+            return 0
+            ;;
+        user)
+            if [[ "$prev" == $special && -n $DEBEMAIL ]]; then
+                COMPREPLY=( $( compgen -W $DEBEMAIL -- "$cur" ) )
+            else
+                COMPREPLY=( )
+            fi
+            return 0
+            ;;
+        usertags)
+            # Must have one bug id.
+            if [[ "$prev" == $special ]]; then
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            elif [[ -z $punctuation ]]; then
+                COMPREPLY=()
+                COMPREPLY[0]='= '
+                COMPREPLY[1]='+ '
+                COMPREPLY[2]='- '
+            else 
+                COMPREPLY=()
+            fi
+            return 0
+            ;;
+        severity)
+            if [[ "$prev" == $special ]]; then
+                COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            elif [[ "$prev" == +([0-9]) ]]; then
+                COMPREPLY=( $( compgen -W 'wishlist minor normal important serious \
+                    grave critical' -- "$cur" ) )
+            else
+                COMPREPLY=()
+            fi
+            return 0
+            ;;
+        select|limit)
+            # can't handle ":". Give up for now.
+            COMPREPLY=( )
+            return 0
+            ;;
+        package)
+            COMPREPLY=( $( _suggest_packages "$cur" ) )
+            return 0
+            ;;
+        cache)
+            # cache supports a few limited options
+            # but as args we accept bug ids, package names and release-critical
+            if [[ "$prev" == --cache-mode ]]; then
+                COMPREPLY=( $( compgen -W 'min mbox full' -- "$cur" ) )
+            elif [[ "$cur" == release-critical/* ]]; then
+                local _pkg=${cur#release-critical/}
+                COMPREPLY=( $( _suggest_packages "$_pkg" | sed -e's!^!release-critical/!' ) )
+            elif [[ "$cur" == -* ]]; then
+                COMPREPLY=( $( compgen -W '--cache-mode --force-refresh -f \
+                    --include-resolved -q --quiet' -- "$cur" ) )
+            else
+                COMPREPLY=( $( compgen -W 'release-critical RC' -- "$cur" ) \
+                    $( _suggest_packages "$cur" ) )
+            fi
+            return 0
+            ;;
+        cleancache)
+            if [[ "$prev" == $special ]]; then
+                COMPREPLY=( $( compgen -W 'ALL' -- "$cur" ) \
+                    $( _suggest_bugs "$cur" ) \
+                    $( _suggest_packages "$cur" ) )
+            else
+                COMPREPLY=( )
+            fi
+            return 0
+            ;;
+        *)
+            COMPREPLY=( $( _suggest_bugs "$cur" ) )
+            return 0
+            ;;
+        esac
+    fi
+        
+    case $prev in
+        --cache-mode)
+             COMPREPLY=( $( compgen -W 'min mbox full' -- "$cur" ) )
+             return 0
+             ;;
+        --cache-delay)
+             COMPREPLY=( $( compgen -W '5 60 120 240 600' -- "$cur" ) )
+             return 0
+             ;;
+    esac
+
+    if [[ "$cur" == -* ]]; then
+        COMPREPLY=( $( compgen -W '-o --offline --online -n --no-action --cache --no-cache --cache-mode --cache-delay --mbox --no-use-default-cc --mutt --no-mutt -f --force-refresh --no-force-refresh --only-new --include-resolved --no-include-resolved --no-ack --ack -i --interactive --force-interactivei --no-interactive -q --quiet' -- "$cur" ) )
+    else
+        COMPREPLY=( $( compgen -W 'show bugs unmerge select status clone done reopen archive unarchive retitle summary submitter reassign found notfound fixed notfixed block unblock merge forcemerge tags affects user usertags claim unclaim severity forwarded notforwarded package limit owner noowner subscribe unsubscribe reportspam spamreport cache cleancache version help' -- "$cur" ) )
+    fi
+
+    # !!! not handled !!!
+    # --mailreader=READER
+    # --cc-addr=CC_EMAIL_ADDRESS
+    # --use-default-cc
+    # --sendmail=SENDMAILCMD
+    # --smtp-host=SMTPHOST
+    # --smtp-username=USERNAME
+    # --smtp-password=PASSWORD
+    # --smtp-helo=HELO
+    # --bts-server
+    # --no-conf, --noconf
+    #
+    # anything with colons for now
+    # for similar reasons having issues with tags XXXX = 
+    # no special handling for select
+
+    return 0
+} &&
+complete -F _bts bts
+        
+# ex: ts=4 sw=4 et filetype=sh
diff --git a/scripts/bts.pl b/scripts/bts.pl
index 55bb83a..c1d7da7 100755
--- a/scripts/bts.pl
+++ b/scripts/bts.pl
@@ -335,6 +335,10 @@ to use B<mutt> to send emails.
 
 Don't use B<mutt> for sending of mails.
 
+=item B<--soap-timeout=>I<SECONDS>
+
+Specify a timeout for SOAP calls as used by the B<select> and B<status> commands.
+
 =item B<--smtp-host=>I<SMTPHOST>
 
 Specify an SMTP host.  If given, B<bts> will send mail by talking directly to
@@ -582,6 +586,7 @@ my ($opt_cachemode, $opt_mailreader, $opt_sendmail, $opt_smtphost);
 my ($opt_smtpuser, $opt_smtppass, $opt_smtphelo);
 my $opt_cachedelay=5;
 my $opt_mutt;
+my $opt_soap_timeout;
 my $mboxmode = 0;
 my $quiet=0;
 my $opt_ccemail = "";
@@ -620,6 +625,7 @@ GetOptions("help|h" => \$opt_help,
 	   "toolname=s" => \$toolname,
 	   "bts-server=s" => \$btsserver,
 	   "mutt!" => \$opt_mutt,
+       "soap-timeout:i" => \$opt_soap_timeout,
 	   )
     or die "Usage: $progname [options]\nRun $progname --help for more details\n";
 
@@ -650,6 +656,10 @@ if ($opt_mutt) {
     $use_mutt = 1;
 }
 
+if ($opt_soap_timeout) {
+    Devscripts::Debbugs::soap_timeout($opt_soap_timeout);
+}
+
 if ($opt_sendmail and $opt_smtphost) {
     die "$progname: --sendmail and --smtp-host mutually exclusive\n";
 } elsif ($opt_mutt and $opt_sendmail) {
@@ -2333,6 +2343,37 @@ sub bts_cleancache {
     untie %timestamp;
 }
 
+=item B<listcachedbugs> [I<number>]
+
+List cached bug ids (intended to support bash completion). The optional number argument
+restricts the list to those bug ids that start with that number.
+
+=cut
+
+sub bts_listcachedbugs {
+    my $number = shift;
+    if (not defined $number) {
+	$number = '';
+    }
+    if ($number =~ m{\D}) {
+	return;
+    }
+    my $untie=0;
+    if (not tied %timestamp) {
+        tie (%timestamp, "Devscripts::DB_File_Lock", $timestampdb,
+             O_RDONLY(), 0600, $DB_HASH, "read")
+            or die "$progname: couldn't open DB file $timestampdb for reading: $!\n";
+	$untie=1;
+    }
+
+    print join "\n", grep { $_ =~ m{^$number\d+$} } sort keys %timestamp;
+    print "\n";
+
+    if ($untie) {
+        untie %timestamp;
+    }
+}
+
 # Add any new commands here.
 
 =item B<version>
diff --git a/scripts/pkgnames.bash_completion b/scripts/pkgnames.bash_completion
index 4f6cc93..c867015 100644
--- a/scripts/pkgnames.bash_completion
+++ b/scripts/pkgnames.bash_completion
@@ -9,4 +9,4 @@ _pkg_names()
     return 0
 }
 
-complete -F _pkg_names wnpp-alert wnpp-check mk-build-deps rmadison mass-bug debsnap dd-list build-rdeps who-uploads transition-check getbuildlog dcontrol grep-excuses rc-alert bts whodepends dget pts-subscribe pts-unsubscribe
+complete -F _pkg_names wnpp-alert wnpp-check mk-build-deps rmadison mass-bug debsnap dd-list build-rdeps who-uploads transition-check getbuildlog dcontrol grep-excuses rc-alert whodepends dget pts-subscribe pts-unsubscribe

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/devscripts.git



More information about the devscripts-devel mailing list