How about a tool to search in the BTS database?
Julien VAUBOURG <[email protected]>
| Newsgroups | gmane.linux.debian.devel.debbugs,gmane.linux.debian.devel.devscripts |
|---|---|
| Message-ID | <[email protected]> |
Hi, With Lucas Nussbaum, we thought that the BTS needs a tool to search in the database. So, I started to code something that may interest you, with a Xapian[0] database. To have an overview, you can see the attached manpage bunny.1, with less. If you would to see the project progress I've attached the client bunny, the server side bunny-server.pl and the indexer bunny-indexer.pl. [0] http://xapian.org/features To try it: * Download a bts-spool-db version (with 01/ 02/ 03/ etc) * Configure some paths in the header of the three scripts * Launch ./bunny-index.pl to create the Xapian db version * Install bunny-server.pl on a web server * Use ./bunny as a client (less bunny.1) Currently, all is implemented and the searcher works fine. It only remains to find a solution to update the xapian db when bts-spool-db change. A web front end will also be added quickly. And there is still some bugs to fix before to release it. How about add it in the devscripts and host the server side & the web front end on a debian server? Cheers, ju. -- Envoyé via un serveur personnel, hébergé dans mon appartement et relié au réseau par un FAI participatif. Je suis le seul à pouvoir consulter mon courrier ; et vous ? * http://julien.vaubourg.com * [email protected] * +33(0)6 71 555 141
bunny-indexer.pl
(text/x-pascal, 5.8 KB)
#!/usr/bin/perl # bunny-indexer - Index a bts-spool-db mirror (Debian bugs) in a Xapian db # # Copyright (C) 2011 Julien Vaubourg <[email protected]> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. use strict; use Search::Xapian (':all'); use POSIX; use WWW::Mechanize; use JSON -support_by_pp; ########## CONFIGURE:BEGIN ########## # Path of the bts-spool-db mirror directory (with 01/ 02/ 03/ etc) my $textdb_path = "./simpledb"; # Path and name of the Xapian db to create my $database_path = "./simpledb-xap"; ########### CONFIGURE:END ########### # Slots used for the sorting my $SLOT_DATE = 0; my $SLOT_SEVERITY = 1; my $SLOT_WNPP = 2; my $SLOT_PACKAGE = 3; my ($database, $indexer); eval { # Create or open the Xapian db $database = Search::Xapian::WritableDatabase->new( $database_path, DB_CREATE_OR_OPEN ); $indexer = Search::Xapian::TermGenerator->new(); my $stemmer = Search::Xapian::Stem->new("english"); $indexer->set_stemmer($stemmer); # Fill the Xapian db with .log and .summary files index_bugs($textdb_path); }; if($@) { print STDERR "Exception: $@\n"; exit 1; } # Index all bugs from bugs_dir/nn/ID.{summary,log} sub index_bugs { my $bugs_dir = shift @_; opendir(my $BUGS_DIR, $bugs_dir) or die "Couldn't open $bugs_dir!"; # Sub-directories 01/ 02/ 03/ etc while (my $ndir = readdir($BUGS_DIR)) { # It's not a wrong file if(-d "$bugs_dir/$ndir" && "$bugs_dir/$ndir" =~ /\d+/) { opendir(my $BUGS_NDIR, "$bugs_dir/$ndir") or die "Couldn't open $bugs_dir/$ndir!"; # For each file .log .report .summary .status while (my $file = readdir($BUGS_NDIR)) { # We use the .summary and the .log files for # index the bug if($file =~ /(\d+)\.summary$/) { my ( $bug_id, $bug_package_version, $bug_doneby, $bug_date, $bug_fixed, $bug_tags, $bug_severity, $bug_submitter, $bug_subject, $bug_wnpp, $bug_package, $bug_log ); $bug_fixed = 0; $bug_log = ""; $bug_id = $1; # Open the ID.summary open(my $SUMMARY, "$bugs_dir/$ndir/$file") or die "Couldn't open $bugs_dir/$ndir/$file!"; # For each line, extract the field while(<$SUMMARY>) { chomp; if(/^Found-In:\s+(.*)/) { $bug_package_version = $1; } elsif(/^Done:\s+(.*)/) { $bug_doneby = $1; } elsif(/^Date:\s+(.*)/) { $bug_date = $1; } elsif(/^Fixed-In:\s+(.*)/) { $bug_fixed = 1; } elsif(/^Tags:\s+(.*)/) { if($1 eq "fixed") { $bug_fixed = 1; } else { $bug_tags = $1; } } elsif(/^Severity:\s+(.*)/) { # Old severity fixed, # before the tag if($1 eq "fixed") { $bug_fixed = 1; } else { $bug_severity = $1; } } elsif(/^Submitter:\s+(.*)/) { $bug_submitter = $1; } elsif(/^Subject:\s+(.*)/) { $bug_subject = $1; if($1 =~ /^(ITA|ITP|O|RFA|RFH|RFP):\s+/) { $bug_wnpp = $1; } } elsif(/^Package:\s+(.*)/) { $bug_package = $1; } } close $SUMMARY; # Open the log version for index it open(my $LOG, "$bugs_dir/$ndir/$bug_id.log") or die "Couldn't open $bugs_dir/$ndir/$bug_id.log!"; $bug_log .= "$_ " while(<$LOG>); close $LOG; # Index all informations index_bug( $bug_id, $bug_package_version, $bug_doneby, $bug_date, $bug_fixed, $bug_tags, $bug_severity, $bug_submitter, $bug_subject, $bug_wnpp, $bug_package, $bug_log ); }; } closedir $BUGS_NDIR; } } closedir $BUGS_DIR; } # Index a bug in the Xapian db sub index_bug { my ( $bug_id, $bug_package_version, $bug_doneby, $bug_date, $bug_fixed, $bug_tags, $bug_severity, $bug_submitter, $bug_subject, $bug_wnpp, $bug_package, $bug_log ) = @_; eval { my $bug = Search::Xapian::Document->new(); $indexer->set_document($bug); # Booleans filters $bug->add_term('I' . $bug_id); $bug->add_term('F' . $bug_fixed); $bug->add_term('S' . $bug_severity); $bug->add_term('W' . $bug_wnpp); my @tags = split(/\s+/, $bug_tags); $bug->add_term('T' . $_) for (@tags); # Free text fields $indexer->index_text($bug_log); $indexer->index_text($bug_package, 1, 'P'); $indexer->index_text($bug_doneby, 1, 'D'); $indexer->index_text($bug_subject, 1, 'S'); my @versions = split(/\s+/, $bug_package_version); $indexer->index_text($_, 1, 'V') for (@versions); my @submitters = split(/\s*,\s*/, $bug_submitter); $indexer->index_text($_, 1, 'A') for (@submitters); # Date in human format my ($sec,$min,$hour,$mday,$mon,$year) = gmtime($bug_date); my $date = sprintf("%4d/%02d/%02d", $year + 1900, $mon + 1, $mday); # Data includes some informations, which will be extracted $bug->set_data("[$bug_id] [$date] [$bug_severity] [$bug_fixed] $bug_subject"); # Date in Xapian format $date = sprintf("%d%d%d", $year + 1900, $mon + 1, $mday); # Sort $bug->add_value($SLOT_DATE, $date); $bug->add_value($SLOT_SEVERITY, $bug_severity); $bug->add_value($SLOT_WNPP, $bug_wnpp); $bug->add_value($SLOT_PACKAGE, $bug_package); # Indexing $database->add_document($bug); }; if($@) { print STDERR "Exception: $@\n"; exit 1; } }
bunny-server.pl
(text/plain, 4.3 KB)
#!/usr/bin/perl # bunny-server - Backend and web frontend for searching in the Debian bugs # database # # Copyright (C) 2011 Julien Vaubourg <[email protected]> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. use strict; use Search::Xapian (':all'); use JSON -support_by_pp; use Data::Dumper::Simple; ########## CONFIGURE:BEGIN ########## # Path of the Xapian db my $database_path = "./simpledb-xap"; ########### CONFIGURE:END ########### my $flags = 0; my $max = 10; my $query_string = ""; my $sort_by = undef; my $rsort = 0; # Xapian options available my %flags_values = ( "boolean" => FLAG_BOOLEAN, "phrase" => FLAG_PHRASE, "lovehate" => FLAG_LOVEHATE, "anycase" => FLAG_BOOLEAN_ANY_CASE, "wildcard" => FLAG_WILDCARD, "not" => FLAG_PURE_NOT, "partial" => FLAG_PARTIAL ); # Slots used for the sorting my %slot_values = ( "date" => 0, "severity" => 1, "wnpp" => 2, "package" => 3 ); print "Content-type: text/plain\r\n\r\n"; eval { # Separation of the GET params for (split /\&/, $ENV{QUERY_STRING}) { # URL decode s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg; my ($key, $value) = split /=/; # This params corresponds to a Xapian option if(defined $flags_values{$key}) { $flags |= $flags_values{$key}; # Sort param } elsif($key eq "sort" && length($value) > 1 && (defined $slot_values{$value} || defined $slot_values{substr($value, 1)})) { # Case of a reverse value (e.g. rdate) if($value =~ /^r(\w+)/) { $sort_by = $slot_values{$1}; $rsort = 1; # Standard value } else { $sort_by = $slot_values{$value}; } # Max param } elsif($key eq "max" && $value =~ /\d+/) { $max = $value; # This is not an option is a query part } elsif($key eq "q") { $query_string = $value; } } # If no Xapian option $flags = FLAG_DEFAULT if !$flags; my $database = Search::Xapian::Database->new($database_path); my $enquire = Search::Xapian::Enquire->new($database); my $qp = Search::Xapian::QueryParser->new(); $qp->set_database($database); $qp->set_stemmer(Search::Xapian::Stem->new("english")); $qp->set_stemming_strategy(STEM_SOME); # Boolean filters $qp->add_boolean_prefix("id", 'I'); $qp->add_boolean_prefix("fixed", 'F'); $qp->add_boolean_prefix("severity", 'S'); $qp->add_boolean_prefix("wnpp", 'W'); $qp->add_boolean_prefix("tag", 'T'); # Free text fields $qp->add_prefix("author", 'A'); $qp->add_prefix("doneby", 'D'); $qp->add_prefix("package", 'P'); $qp->add_prefix("subject", 'S'); $qp->add_prefix("version", 'V'); # Set the date slot my $vrpdate = new Search::Xapian::DateValueRangeProcessor( $slot_values{"date"}, 1, 1920); $qp->add_valuerangeprocessor($vrpdate); # Request on the db and sorting my $query = $qp->parse_query($query_string, $flags); $enquire->set_query($query); $enquire->set_sort_by_value($sort_by, $rsort) if defined $sort_by; # Retrieve the $max first results my $mset = $enquire->get_mset(0, $max); my $msize = $mset->size(); my %result; $result{"count"} = $mset->get_matches_estimated(); $result{"about"} = $mset->get_matches_lower_bound() != $mset->get_matches_upper_bound(); # For each bug found foreach my $m ($mset->items()) { my $data = $m->get_document()->get_data(); # Data format: [ID] [DATE] [SEVERITY] [FIXED] Subject my ($id, $date, $severity, $fixed, $subject) = $data =~ /^\[(\w*)\] \[([\w\/]*)\] \[([\w-]*)\] \[(\w*)\] (.+)$/; # Inject the result in the final hash push(@{$result{"results"}}, { "percent" => $m->get_percent(), "date" => $date, "id" => $id, "severity" => $severity, "fixed" => $fixed, "subject" => $subject }); } # JSON encoding my $json = JSON->new->allow_nonref; my $json_string = $json->encode(\%result); print $json_string; exit 0; }; if($@) { print STDERR "Exception: $@\n"; exit 1; }
bunny
(text/plain, 9.3 KB)
#!/usr/bin/perl # bunny - Search in the Debian bugs database # # Copyright (C) 2011 Julien Vaubourg <[email protected]> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. use strict; use WWW::Mechanize; use JSON -support_by_pp; use Getopt::Long; ########## CONFIGURE:BEGIN ########## # URL of the bunny-server my $bunny_server = "http://localhost/cgi-bin/bunny-server.pl"; ########### CONFIGURE:END ########### # Encode strings to URL format sub urlencode { my $txt = shift @_; $txt =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg; return $txt; } # Options available my %opt = ( "fixed" => undef, "sort" => undef, "wnpp" => [], "tag" => [], "severity" => [], "max" => 10, "id" => [], "report" => undef, "display" => undef, "boolean" => 1, "phrase" => 1, "lovehate" => 1, "anycase" => undef, "wildcard" => 1, "not" => undef, "partial" => undef ); # Options format GetOptions( 'fixed!' => \$opt{"fixed"}, 'use-sort=s' => \$opt{"sort"}, 'wnpp=s' => \@{$opt{"wnpp"}}, 'tag=s' => \@{$opt{"tag"}}, 'severity=s' => \@{$opt{"tag"}}, 'max=i' => \$opt{"max"}, 'id=i' => \@{$opt{"id"}}, 'report=i' => \$opt{"report"}, 'display=s' => \$opt{"display"}, 'x-boolean!' => \$opt{"boolean"}, 'x-quoted-phrase!' => \$opt{"phrase"}, 'x-lovehate!' => \$opt{"lovehate"}, 'x-any-case-boolean!' => \$opt{"anycase"}, 'x-wildcard!' => \$opt{"wildcard"}, 'x-not!' => \$opt{"not"}, 'x-partial!' => \$opt{"partial"} ); my $browser = WWW::Mechanize->new(); # With --report option, the user just wants see a single bug report if($opt{"report"}) { eval { my $url = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=".$opt{"report"}; # Download the bug report $browser->get($url.";mbox=yes"); my $content = $browser->content(); # Remove all mail headers except From: To: Subject: and Date: $content =~ s/^(From|To|Subject|Date):/[\1]/gm; $content =~ s/^[^ :]+:[^\n]*\n(\h+[^\n]+\n)*//gsm; $content =~ s/^\n*From [^@]+@[^\n]+\n\[(From|To|Subject|Date)\]/"\n\n".('=' x 80)."\n\n[${1}]"/gsme; # Displays the report print "BUG #".$opt{"report"}; print $content; print "".('=' x 80)."\n$url\n"; }; if($@) { print STDERR "Bug ID not found.\n"; exit 2; } # The user wants a research (no -r) } else { my @query; # Form the query_string with options (&option=value) foreach (keys(%opt)) { if($_ !~ /id|fixed|wnpp|tag|severity|display/ && $opt{$_}) { push(@query, urlencode($_)."=".urlencode($opt{$_})); } } # Booleans filters are added on the Xapian syntax (option:value), # directly in the Xapian query, for each value. for (qw(id wnpp tag severity)) { if(@{$opt{$_}} > 0) { for my $value (@{$opt{$_}}) { push(@ARGV, $_.":".$value) } } } # Fixed is the only boolean filter who can have just a single value push(@ARGV, "fixed:".$opt{"fixed"}) if defined $opt{"fixed"}; # Complete url, with options and Xapian query my $url = sprintf( $bunny_server."?%s&q=%s", join('&', @query), urlencode(join(' ', @ARGV)) ); eval { # Send the request $browser->get($url); my $content = $browser->content(); # Retrieve the json response my $json = new JSON; my %result = %{ $json->allow_nonref->utf8->relaxed->escape_slash->loose->allow_singlequote->allow_barekey->decode($content) }; # If any bugs were found if($result{"count"}) { # Displays the counter header only if -d contains 'c' # This is by default if($opt{"display"} =~ /(c|^$)/) { print "About " if $result{"about"}; print $result{"count"}." matching bugs found.\n"; print "--\n" if length($opt{"display"}) != 1; } # If the user doesn't want only the counter if($opt{"display"} ne 'c') { my $date_e = $opt{"display"} =~ /e/; $opt{"display"} =~ s/[ce]//g; # For each bug found for (@{$result{"results"}}) { # European date format (-d de) if($date_e) { %$_->{"date"} =~ s/(\d{4})\/(\d\d)\/(\d\d)/\3\/\2\/\1/; } # Shows percents (-d p) - default printf( length($opt{"display"}) != 1 ? "%3u\% - " : "%u", %$_->{"percent"} ) if $opt{"display"} =~ /(p|^$)/; # Shows dates (-d d) printf( length($opt{"display"}) != 1 ? "[%10s] " : "%s", %$_->{"date"} ) if $opt{"display"} =~ /d/; # Shows severities (-d s) printf( length($opt{"display"}) != 1 ? "[%9s] " : "%s", %$_->{"severity"} ) if $opt{"display"} =~ /s/; # Shows fixed flags (-d f) printf( length($opt{"display"}) != 1 ? "[%5s] " : "%s", %$_->{"fixed"} ? "FIXED" : "" ) if $opt{"display"} =~ /f/; # Shows IDs (-d i) - default printf( length($opt{"display"}) != 1 ? "[#%-7u] " : "%u", %$_->{"id"} ) if $opt{"display"} =~ /(i|^$)/; # Shows topics (-d t) - default print %$_->{"subject"} if $opt{"display"} =~ /(t|^$)/; print "\n"; } } # No bug found } else { exit 1; } }; if($@) { print STDERR "Database access error!\n"; exit 2; } } exit 0; __END__ =head1 NAME bunny - Search in the Debian bugs database =head1 SYNOPSIS bunny [I<OPTIONS>] [I<QUERY>] =head1 QUERY I<QUERY> use the Xapian syntax. See the B<EXAMPLES> section. =head2 Free text fields B<author:*> - Bug's author B<doneby:*> - Who fixed the bug B<package:*> - Package concerned B<subject:*> - Topic B<version:*> - Package's version =head1 OPTIONS All booleans filters and xapian options can be negated (e.g. B<--fixed> and B<--nofixed>). =head2 Booleans filters =over =item -f, --fixed Only fixed bugs. Same as C<fixed:1>. =item B<[>-id IDB<]...> Only the bug #ID. Same as C<id:*>. =item B<[>-w|--wnpp I<ITA|ITP|O|RFA|RFH|RFP>B<]...> Only specifics wnpp bugs. Same as C<wnpp:*>. =item B<[>-t|--tag I<TAG>B<]...> Only I<TAG> related. See B<http://www.debian.org/Bugs/Developer#tags>. Same as C<tag:*>. =item B<[>-s|--severity I<critical|grave|serious|important|normal|minor|wishlist>B<]...> Only specific severity related. Same as C<severity:*>. =back =head2 Format =over =item -r, --report I<ID> View the bug report #I<ID>. =item -u, --use-sort I<date|severity|wnpp|package> Sort results. To have reverse order: I<rdate|rseverity|rwnpp|rpackage> =item -m, --max I<LIMIT> Max results. Default 10. =item -d, --display I<DISPLAY> B<c> - Shows counter header B<d> - Shows dates B<e> - Shows date with DD/MM/YYYY format B<f> - Shows the fixed tag B<i> - Shows IDs B<p> - Shows percents B<s> - Shows severity tags B<t> - Shows topics Example: C<-d fistdepc> By default if empty: B<pict> =back =head2 Xapian options =over =item -x-b, --x-boolean Support C<AND>, C<OR>, etc and bracketed subexpressions. =item -x-q, --x-quoted-phrase B<(default)> Support quoted phrases. =item -x-l, --x-lovehate B<(default)> Support C<+> and C<->. =item -x-a, --x-any-case-boolean Support C<AND>, C<OR>, etc even if they aren't in ALLCAPS. =item -x-w, --x-wildcard B<(default)> Support right truncation (not on B<Booleans filters>). =item -x-n, --x-not Allow queries such as C<NOT debian>. These require the use of a list of all bugs in the database which is expensive, so this feature isn't enabled by default. =item -x-p, --x-partial Enable partial matching. Partial matching causes the parser to treat the query as a "partially entered" search. This will automatically treat the final word as a wildcarded match, unless it is followed by whitespace, to produce more stable results from interactive searches. Currently B<--x-partial> doesn't do anything if the final word in the query has a boolean filter prefix, or if it is in a phrase (either an explicitly quoted one, or one implicitly generated by hyphens or other punctuation). It also doesn't do anything if if the final word is part of a value range. =back =head1 EXAMPLES bunny author:john severity:grave tag:sid version:3.5.13 bunny -x-n --nofixed package:iceweasel AND NOT author:john bunny doneby:'john doe' 25/12/01..31/12/01 bunny package:'iceweasel*' it\'s embarassing bunny -w ITP -w RFP -w O bunny -r 421337 | less =head1 EXIT STATUS B<0> - Matching bugs found B<1> - No matching bugs found B<Others> - Error =head1 AUTHOR Julien Vaubourg E<lt>[email protected]<gt> =head1 COPYRIGHT Copyright (C) 2011 Julien Vaubourg <[email protected]> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. =cut
bunny.1
(text/plain, 5.3 KB)
BUNNY(1) User Contributed Perl Documentation BUNNY(1)
NNAAMMEE
bunny - Search in the Debian bugs database
SSYYNNOOPPSSIISS
bunny [_O_P_T_I_O_N_S] [_Q_U_E_R_Y]
QQUUEERRYY
_Q_U_E_R_Y use the Xapian syntax. See the EEXXAAMMPPLLEESS section.
FFrreeee tteexxtt ffiieellddss
aauutthhoorr::** - Bug's author
ddoonneebbyy::** - Who fixed the bug
ppaacckkaaggee::** - Package concerned
ssuubbjjeecctt::** - Topic
vveerrssiioonn::** - Package's version
OOPPTTIIOONNSS
All booleans filters and xapian options can be negated (e.g. ----ffiixxeedd
and ----nnooffiixxeedd).
BBoooolleeaannss ffiilltteerrss
-f, --fixed
Only fixed bugs.
Same as "fixed:1".
[[-id ID]]......
Only the bug #ID.
Same as "id:*".
[[-w|--wnpp _I_T_A_|_I_T_P_|_O_|_R_F_A_|_R_F_H_|_R_F_P]]......
Only specifics wnpp bugs.
Same as "wnpp:*".
[[-t|--tag _T_A_G]]......
Only _T_A_G related.
See hhttttpp::////wwwwww..ddeebbiiaann..oorrgg//BBuuggss//DDeevveellooppeerr##ttaaggss.
Same as "tag:*".
[[-s|--severity
_c_r_i_t_i_c_a_l_|_g_r_a_v_e_|_s_e_r_i_o_u_s_|_i_m_p_o_r_t_a_n_t_|_n_o_r_m_a_l_|_m_i_n_o_r_|_w_i_s_h_l_i_s_t]]......
Only specific severity related.
Same as "severity:*".
FFoorrmmaatt
-r, --report _I_D
View the bug report #_I_D.
-u, --use-sort _d_a_t_e_|_s_e_v_e_r_i_t_y_|_w_n_p_p_|_p_a_c_k_a_g_e
Sort results.
To have reverse order: _r_d_a_t_e_|_r_s_e_v_e_r_i_t_y_|_r_w_n_p_p_|_r_p_a_c_k_a_g_e
-m, --max _L_I_M_I_T
Max results. Default 10.
-d, --display _D_I_S_P_L_A_Y
cc - Shows counter header
dd - Shows dates
ee - Shows date with DD/MM/YYYY format
ff - Shows the fixed tag
ii - Shows IDs
pp - Shows percents
ss - Shows severity tags
tt - Shows topics
Example: "-d fistdepc"
By default if empty: ppiicctt
XXaappiiaann ooppttiioonnss
-x-b, --x-boolean
Support "AND", "OR", etc and bracketed subexpressions.
-x-q, --x-quoted-phrase ((ddeeffaauulltt))
Support quoted phrases.
-x-l, --x-lovehate ((ddeeffaauulltt))
Support "+" and "-".
-x-a, --x-any-case-boolean
Support "AND", "OR", etc even if they aren't in ALLCAPS.
-x-w, --x-wildcard ((ddeeffaauulltt))
Support right truncation (not on BBoooolleeaannss ffiilltteerrss).
-x-n, --x-not
Allow queries such as "NOT debian".
These require the use of a list of all bugs in the database which
is expensive, so this feature isn't enabled by default.
-x-p, --x-partial
Enable partial matching.
Partial matching causes the parser to treat the query as a
"partially entered" search. This will automatically treat the final
word as a wildcarded match, unless it is followed by whitespace, to
produce more stable results from interactive searches.
Currently ----xx--ppaarrttiiaall doesn't do anything if the final word in the
query has a boolean filter prefix, or if it is in a phrase (either
an explicitly quoted one, or one implicitly generated by hyphens or
other punctuation). It also doesn't do anything if if the final
word is part of a value range.
EEXXAAMMPPLLEESS
bunny author:john severity:grave tag:sid version:3.5.13
bunny -x-n --nofixed package:iceweasel AND NOT author:john
bunny doneby:'john doe' 25/12/01..31/12/01
bunny package:'iceweasel*' it\'s embarassing
bunny -w ITP -w RFP -w O
bunny -r 421337 | less
EEXXIITT SSTTAATTUUSS
00 - Matching bugs found
11 - No matching bugs found
OOtthheerrss - Error
AAUUTTHHOORR
Julien Vaubourg <[email protected]>
CCOOPPYYRRIIGGHHTT
Copyright (C) 2011 Julien Vaubourg <[email protected]>
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
perl v5.10.1 2011-08-01 BUNNY(1)