]> git.donarmstrong.com Git - debbugs.git/blobdiff - Debbugs/Bugs.pm
OR is the default for multiple values; remove useless or
[debbugs.git] / Debbugs / Bugs.pm
index 1ace4b186b83f05b25c9c4a036d81bf62609f570..127e4727248b11457a021c987cb74b83377e6a2e 100644 (file)
@@ -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,63 @@ 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_idx";
-         }
-     }
-
-     # 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});
+        s/^src:// foreach @aff_list;
+         $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 +576,105 @@ 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_packages' =>
+                                   [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 => $src_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({'pkg' => [make_list($param{src})],
+                   },
+                  { columns => ['id'],
+                    group_by => ['me.id'],
+                   },
+                  );
+        my $bin_pkgs_rs =
+            $s->resultset('BinPkgSrcPkg')->
+            search({'src_pkg.pkg' => [make_list($param{src})],
+                   },
+                  {columns => ['bin_pkg'],
+                   join => ['src_pkg'],
+                   group_by => ['bin_pkg'],
+                  });
+         $rs = $rs->search({-or => {'bug_binpackages.bin_pkg' =>
+                                  { -in => $bin_pkgs_rs->get_column('bin_pkg')->as_query},
+                                   'bug_srcpackages.src_pkg' =>
+                                  { -in => $src_pkgs_rs->get_column('id')->as_query},
+                                   'me.unknown_packages' =>
+                                   [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 +687,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 +698,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 +903,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 +919,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";
        }