X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Debbugs%2FBugs.pm;h=5150d11c3c34565c4e7ed59bf0da4e3ce1e78652;hb=0ea01c001c3e07722958665acc783baec2759651;hp=6e579818288262e63445fce3c057e2a84facf49a;hpb=52d262bbeb30b727950bf143532460e6552469cf;p=debbugs.git diff --git a/Debbugs/Bugs.pm b/Debbugs/Bugs.pm index 6e57981..5150d11 100644 --- a/Debbugs/Bugs.pm +++ b/Debbugs/Bugs.pm @@ -37,6 +37,7 @@ incomplete) to slowest (and most complete).] use warnings; use strict; +use feature 'state'; use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT); use Exporter qw(import); @@ -58,7 +59,7 @@ use Debbugs::Packages qw(getsrcpkgs getpkgsrc); use Debbugs::Common qw(getparsedaddrs package_maintainer getmaintainers make_list hash_slice); use Fcntl qw(O_RDONLY); use MLDBM qw(DB_File Storable); -use List::Util qw(first); +use List::AllUtils qw(first max); use Carp; =head2 get_bugs @@ -152,7 +153,7 @@ bug should not. =cut -my $_non_search_key_regex = qr/^(bugs|archive|usertags|schema)$/; +state $_non_search_key_regex = qr/^(bugs|archive|usertags|schema)$/; my %_get_bugs_common_options = (package => {type => SCALAR|ARRAYREF, @@ -200,13 +201,16 @@ my %_get_bugs_common_options = usertags => {type => HASHREF, optional => 1, }, + newest => {type => SCALAR|ARRAYREF, + optional => 1, + }, schema => {type => OBJECT, optional => 1, }, ); -my $_get_bugs_options = {%_get_bugs_common_options}; +state $_get_bugs_options = {%_get_bugs_common_options}; sub get_bugs{ my %param = validate_with(params => \@_, spec => $_get_bugs_options, @@ -399,11 +403,11 @@ searches. =cut -my $_get_bugs_by_idx_options = +state $_get_bugs_by_idx_options = {hash_slice(%_get_bugs_common_options, (qw(package submitter severity tag archive), qw(owner src maint bugs correspondent), - qw(affects usertags)) + qw(affects usertags newest)) ) }; sub get_bugs_by_idx{ @@ -419,7 +423,13 @@ sub get_bugs_by_idx{ die "Can't handle empty maint (unmaintained packages) in get_bugs_by_idx"; } } - + if ($param{newest}) { + my $newest_bug = newest_bug(); + my @bugs = ($newest_bug - max(make_list($param{newest})) + 1) .. $newest_bug; + $param{bugs} = [exists $param{bugs}?make_list($param{bugs}):(), + @bugs, + ]; + } # We handle src packages, maint and maintenc by mapping to the # appropriate binary packages, then removing all packages which # don't match all queries @@ -487,11 +497,11 @@ searches. =cut -my $_get_bugs_by_db_options = +state $_get_bugs_by_db_options = {hash_slice(%_get_bugs_common_options, (qw(package submitter severity tag archive), qw(owner src maint bugs correspondent), - qw(affects usertags)) + qw(affects usertags newest)) ), schema => {type => OBJECT, }, @@ -502,52 +512,62 @@ sub get_bugs_by_db{ ); my %bugs = (); - # If we're given an empty maint (unmaintained packages), we can't - # handle it, so bail out here - for my $maint (make_list(exists $param{maint}?$param{maint}:[])) { - if (defined $maint and $maint eq '') { - die "Can't handle empty maint (unmaintained packages) in get_bugs_by_db"; - } - } - - # We handle src packages, maint and maintenc by mapping to the - # appropriate binary packages, then removing all packages which - # don't match all queries - my @packages = __handle_pkg_src_and_maint(map {exists $param{$_}?($_,$param{$_}):()} - qw(package src maint) - ); - if (exists $param{package} or - exists $param{src} or - exists $param{maint}) { - delete @param{qw(maint src)}; - $param{package} = [@packages]; - } + my $s = $param{schema}; my $keys = grep {$_ !~ $_non_search_key_regex} keys(%param); die "Need at least 1 key to search by" unless $keys; - my $rs = $param{schema}->resultset('Bug'); + my $rs = $s->resultset('Bug'); if (exists $param{severity}) { - $rs = $rs->search([map {('severity.severity' => $_)} make_list($param{severity})], + $rs = $rs->search({'severity.severity' => + [make_list($param{severity})], + }, {join => 'severity'}, ); } for my $key (qw(owner submitter done)) { if (exists $param{$key}) { - $rs = $rs->search([map {("${key}.addr" => $_)} make_list($param{$key})], + $rs = $rs->search({"${key}.addr" => + [make_list($param{$key})], + }, {join => $key}, ); } } + if (exists $param{newest}) { + $rs = + $rs->search({}, + {order_by => {-desc => 'me.creation'}, + rows => max(make_list($param{newest})), + }, + ); + } if (exists $param{correspondent}) { - $rs = $rs->search([map {('message_correspondents.addr' => $_)} make_list($param{correspondent})], - {join => {correspondent => - {bug_messages => - {message => 'message_correspondents'}}}}, + my $message_rs = + $s->resultset('Message')-> + search({'correspondent.addr' => + [make_list($param{correspondent})], + }, + {join => {message_correspondents => 'correspondent'}, + columns => ['id'], + group_by => ['me.id'], + }, + ); + $rs = $rs->search({'bug_messages.message' => + {-in => $message_rs->get_column('id')->as_query()}, + }, + {join => 'bug_messages', + }, ); } if (exists $param{affects}) { - $rs = $rs->search([map {('bin_pkg.pkg' => $_)} make_list($param{affects}), - map {('src_pkg.pkg' => $_)} make_list($param{affects}), - ], + my @aff_list = make_list($param{affects}); + $rs = $rs->search({-or => {'bin_pkg.pkg' => + [@aff_list], + 'src_pkg.pkg' => + [@aff_list], + 'me.unknown_affects' => + [@aff_list] + }, + }, {join => [{bug_affects_binpackages => 'bin_pkg'}, {bug_affects_srcpackages => 'src_pkg'}, ], @@ -555,34 +575,108 @@ sub get_bugs_by_db{ ); } if (exists $param{package}) { - $rs = $rs->search([map {('bin_pkg.pkg' => $_)} make_list($param{package})], + $rs = $rs->search({-or => {'bin_pkg.pkg' => + [make_list($param{package})], + 'me.unknown.package' => + [make_list($param{package})]}, + }, {join => {bug_binpackages => 'bin_pkg'}}); } + if (exists $param{maint}) { + my @maint_list = + map {$_ eq '' ? undef : $_} + make_list($param{maint}); + my $bin_pkgs_rs = + $s->resultset('BinPkg')-> + search({'correspondent.addr' => [@maint_list]}, + {join => {bin_vers => + {src_ver => + {maintainer => 'correspondent'}}}, + columns => ['id'], + group_by => ['me.id'], + }, + ); + my $src_pkgs_rs = + $s->resultset('SrcPkg')-> + search({'correspondent.addr' => [@maint_list]}, + {join => {src_vers => + {maintainer => 'correspondent'}}, + columns => ['id'], + group_by => ['me.id'], + }, + ); + $rs = $rs->search({-or => {'bug_binpackages.bin_pkg' => + { -in => $bin_pkgs_rs->get_column('id')->as_query}, + 'bug_srcpackages.src_pkg' => + { -in => $bin_pkgs_rs->get_column('id')->as_query}, + }, + }, + {join => ['bug_binpackages', + 'bug_srcpackages', + ]} + ); + } if (exists $param{src}) { - $rs = $rs->search([map {('src_pkg.pkg' => $_)} make_list($param{src})], - {join => {bug_srcpackages => 'src_pkg'}}); + # identify all of the srcpackages and binpackages that match first + my $src_pkgs_rs = + $s->resultset('SrcPkg')-> + search({-or => [map {('me.pkg' => $_, + )} + make_list($param{src})], + columns => ['id'], + group_by => ['me.id'], + }, + ); + my $bin_pkgs_rs = + $s->resultset('BinPkg')-> + search({-or => [map {('src_pkg.pkg' => $_, + )} + make_list($param{src})], + }, + {join => {bin_vers => {src_ver => 'src_pkg'}}, + columns => ['id'], + group_by => ['me.id'], + }); + $rs = $rs->search({-or => {'bug_binpackages.bin_pkg' => + { -in => $bin_pkgs_rs->get_column('id')->as_query}, + 'bug_srcpackages.src_pkg' => + { -in => $bin_pkgs_rs->get_column('id')->as_query}, + 'me.unknown_package' => + [make_list($param{src})], + }, + }, + {join => ['bug_binpackages', + 'bug_srcpackages', + ]} + ); } # tags are very odd, because we must handle usertags. if (exists $param{tag}) { # bugs from usertags which matter my %bugs_matching_usertags; - for my $bug (make_list(grep {defined $_ } @{$param{usertags}}{make_list($param{tag})})) { + for my $bug (make_list(grep {defined $_ } + @{$param{usertags}}{make_list($param{tag})})) { $bugs_matching_usertags{$bug} = 1; } # we want all bugs which either match the tag name given in # param, or have a usertag set which matches one of the tag # names given in param. - $rs = $rs->search([map {('tag.tag' => $_)} make_list($param{tag}), - map {('me.id' => $_)} keys %bugs_matching_usertags - ], + $rs = $rs->search({-or => {map {('tag.tag' => $_)} + make_list($param{tag}), + map {('me.id' => $_)} + keys %bugs_matching_usertags + }, + }, {join => {bug_tags => 'tag'}}); } if (exists $param{bugs}) { - $rs = $rs->search([map {('me.id' => $_)} make_list($param{bugs})]); + $rs = $rs->search({-or => {map {('me.id' => $_)} + make_list($param{bugs})} + }); } # handle archive if (defined $param{archive} and $param{archive} ne 'both') { - $rs = $rs->search(['me.archived' => $param{archive}]); + $rs = $rs->search({'me.archived' => $param{archive}}); } return $rs->get_column('id')->all(); } @@ -595,7 +689,7 @@ searches. [Or at least, that's the idea.] =cut -my $_get_bugs_flatfile_options = +state $_get_bugs_flatfile_options = {hash_slice(%_get_bugs_common_options, map {$_ eq 'dist'?():($_)} keys %_get_bugs_common_options ) @@ -606,6 +700,13 @@ sub get_bugs_flatfile{ spec => $_get_bugs_flatfile_options ); my $flatfile; + if ($param{newest}) { + my $newest_bug = newest_bug(); + my @bugs = ($newest_bug - max(make_list($param{newest})) + 1) .. $newest_bug; + $param{bugs} = [exists $param{bugs}?make_list($param{bugs}):(), + @bugs, + ]; + } if ($param{archive}) { $flatfile = IO::File->new("$config{spool_dir}/index.archive", 'r') or die "Unable to open $config{spool_dir}/index.archive for reading: $!"; @@ -804,7 +905,7 @@ sub __handle_pkg_src_and_maint{ return grep {$packages{$_} >= $package_keys} keys %packages; } -my %field_match = ( +state $field_match = { 'subject' => \&__contains_field_match, 'tags' => sub { my ($field, $values, $status) = @_; @@ -820,14 +921,14 @@ my %field_match = ( 'originator' => \&__contains_field_match, 'forwarded' => \&__contains_field_match, 'owner' => \&__contains_field_match, -); +}; sub __bug_matches { my ($hash, $status) = @_; foreach my $key( keys( %$hash ) ) { my $value = $hash->{$key}; - next unless exists $field_match{$key}; - my $sub = $field_match{$key}; + next unless exists $field_match->{$key}; + my $sub = $field_match->{$key}; if (not defined $sub) { die "No defined subroutine for key: $key"; }