6 Debbugs::Bugs -- Bug selection routines for debbugs
10 use Debbugs::Bugs qw(get_bugs);
15 This module is a replacement for all of the various methods of
16 selecting different types of bugs.
18 It implements a single function, get_bugs, which defines the master
19 interface for selecting bugs.
21 It attempts to use subsidiary functions to actually do the selection,
22 in the order specified in the configuration files. [Unless you're
23 insane, they should be in order from fastest (and often most
24 incomplete) to slowest (and most complete).]
34 use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
35 use base qw(Exporter);
39 $DEBUG = 0 unless defined $DEBUG;
43 @EXPORT_OK = (qw(get_bugs));
44 $EXPORT_TAGS{all} = [@EXPORT_OK];
47 use Debbugs::Config qw(:config);
48 use Params::Validate qw(validate_with :types);
51 use Debbugs::Packages qw(getsrcpkgs);
59 The following parameters can either be a single scalar or a reference
60 to an array. The parameters are ANDed together, and the elements of
61 arrayrefs are a parameter are ORed. Future versions of this may allow
62 for limited regular expressions.
66 =item package -- name of the binary package
68 =item src -- name of the source package
70 =item maint -- address of the maintainer
72 =item maintenc -- encoded address of the maintainer
74 =item submitter -- address of the submitter
76 =item severity -- severity of the bug
78 =item status -- status of the bug
82 =item owner -- owner of the bug
84 =item dist -- distribution (I don't know about this one yet)
86 =item bugs -- list of bugs to search within
90 =head3 Special options
92 The following options are special options used to modulate how the
93 searches are performed.
97 =item archive -- whether to search archived bugs or normal bugs;
100 =item usertags -- set of usertags and the bugs they are applied to
105 =head3 Subsidiary routines
107 All subsidiary routines get passed exactly the same set of options as
108 get_bugs. If for some reason they are unable to handle the options
109 passed (for example, they don't have the right type of index for the
110 type of selection) they should die as early as possible. [Using
111 Params::Validate and/or die when files don't exist makes this fairly
114 This function will then immediately move on to the next subroutine,
115 giving it the same arguments.
120 my %param = validate_with(params => \@_,
121 spec => {package => {type => SCALAR|ARRAYREF,
124 src => {type => SCALAR|ARRAYREF,
127 maint => {type => SCALAR|ARRAYREF,
130 maintenc => {type => SCALAR|ARRAYREF,
133 submitter => {type => SCALAR|ARRAYREF,
136 severity => {type => SCALAR|ARRAYREF,
139 status => {type => SCALAR|ARRAYREF,
142 tag => {type => SCALAR|ARRAYREF,
145 owner => {type => SCALAR|ARRAYREF,
148 dist => {type => SCALAR|ARRAYREF,
151 bugs => {type => SCALAR|ARRAYREF,
154 archive => {type => BOOLEAN,
157 usertags => {type => HASHREF,
164 my %options = %param;
166 # A configuration option will set an array that we'll use here instead.
167 for my $routine (qw(Debbugs::Bugs::get_bugs_flatfile)) {
168 my ($package) = $routine =~ m/^(.+)\:\:/;
169 eval "use $package;";
171 # We output errors here because using an invalid function
172 # in the configuration file isn't something that should
174 warn "use $package failed with $@";
177 @bugs = eval "${routine}(\%options)";
180 # We don't output errors here, because failure here
181 # via die may be a perfectly normal thing.
182 print STDERR "$@" if $DEBUG;
187 # If no one succeeded, die
194 sub get_bugs_flatfile{
195 my %param = validate_with(params => \@_,
196 spec => {package => {type => SCALAR|ARRAYREF,
199 src => {type => SCALAR|ARRAYREF,
202 maint => {type => SCALAR|ARRAYREF,
205 maintenc => {type => SCALAR|ARRAYREF,
208 submitter => {type => SCALAR|ARRAYREF,
211 severity => {type => SCALAR|ARRAYREF,
214 status => {type => SCALAR|ARRAYREF,
217 tag => {type => SCALAR|ARRAYREF,
221 # owner => {type => SCALAR|ARRAYREF,
224 # dist => {type => SCALAR|ARRAYREF,
227 archive => {type => BOOLEAN,
230 usertags => {type => HASHREF,
236 if ($param{archive}) {
237 $flatfile = new IO::File "$debbugs::gSpoolDir/index.archive", 'r'
238 or die "Unable to open $debbugs::gSpoolDir/index.archive for reading: $!";
241 $flatfile = new IO::File "$debbugs::gSpoolDir/index.db", 'r'
242 or die "Unable to open $debbugs::gSpoolDir/index.db for reading: $!";
245 if (exists $param{tag} and exists $param{usertags}) {
247 # This complex slice makes a hash with the bugs which have the
248 # usertags passed in $param{tag} set.
249 @usertag_bugs{map {@{$_}}
250 @{$param{usertags}}{__make_list($param{tag})}
251 } = (1) x @{$param{usertags}}{__make_list($param{tag})}
254 while (<$flatfile>) {
255 next unless m/^(\S+)\s+(\d+)\s+(\d+)\s+(\S+)\s+\[\s*([^]]*)\s*\]\s+(\w+)\s+(.*)$/;
256 my ($pkg,$bug,$status,$submitter,$severity,$tags) = ($1,$2,$3,$4,$5,$6,$7);
257 next if exists $param{bug} and not grep {$bug == $_} __make_list($param{bugs});
258 if (exists $param{pkg}) {
259 my @packages = splitpackages($pkg);
260 next unless grep { my $pkg_list = $_;
261 grep {$pkg_list eq $_} __make_list($param{pkg})
264 if (exists $param{src}) {
265 my @src_packages = map { getsrcpkgs($_)} __make_list($param{src});
266 my @packages = splitpackages($pkg);
267 next unless grep { my $pkg_list = $_;
268 grep {$pkg_list eq $_} @packages
271 if (exists $param{submitter}) {
272 my @p_addrs = map {$_->address}
273 map {lc(getparsedaddrs($_))}
274 __make_list($param{submitter});
275 my @f_addrs = map {$_->address}
276 getparsedaddrs($submitter||'');
277 next unless grep { my $f_addr = $_;
278 grep {$f_addr eq $_} @p_addrs
281 next if exists $param{severity} and not grep {$severity eq $_} __make_list($param{severity});
282 next if exists $param{status} and not grep {$status eq $_} __make_list($param{status});
283 if (exists $param{tag}) {
285 # either a normal tag, or a usertag must be set
286 $bug_ok = 1 if exists $param{usertags} and $usertag_bugs{$bug};
287 my @bug_tags = split ' ', $tags;
288 $bug_ok = 1 if grep {my $bug_tag = $_;
289 grep {$bug_tag eq $_} __make_list($param{tag});
299 # This private subroutine takes a scalar and turns it
300 # into a list; transforming arrayrefs into their contents
303 return map {ref($_) eq 'ARRAY'?@{$_}:$_} @_;