]> git.donarmstrong.com Git - debbugs.git/blobdiff - Debbugs/Status.pm
get_bug_status can now accept a schema to pull from DB
[debbugs.git] / Debbugs / Status.pm
index 73506611a26d585da976a31576b1b7a9008cda8c..7af7fcf1dfd057dd5a5fa3311c8a0f0216bb6c4c 100644 (file)
@@ -34,7 +34,7 @@ use warnings;
 use strict;
 
 use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
-use base qw(Exporter);
+use Exporter qw(import);
 
 use Params::Validate qw(validate_with :types);
 use Debbugs::Common qw(:util :lock :quit :misc);
@@ -49,7 +49,8 @@ use File::Copy qw(copy);
 use Encode qw(decode encode is_utf8);
 
 use Storable qw(dclone);
-use List::Util qw(min max);
+use List::AllUtils qw(min max uniq);
+use DateTime::Format::Pg;
 
 use Carp qw(croak);
 
@@ -191,6 +192,7 @@ sub read_bug{
     my $status;
     my $log;
     my $location;
+    my $report;
     if (not defined $param{summary}) {
         my $lref;
         ($lref,$location) = @param{qw(bug location)};
@@ -200,13 +202,16 @@ sub read_bug{
         }
         $status = getbugcomponent($lref, 'summary', $location);
         $log    = getbugcomponent($lref, 'log'    , $location);
+        $report    = getbugcomponent($lref, 'report'    , $location);
         return undef unless defined $status;
         return undef if not -e $status;
     }
     else {
         $status = $param{summary};
         $log = $status;
+        $report = $status;
         $log =~ s/\.summary$/.log/;
+        $report =~ s/\.summary$/.report/;
         ($location) = $status =~ m/(db-h|db|archive)/;
          ($param{bug}) = $status =~ m/(\d+)\.summary$/;
     }
@@ -270,18 +275,34 @@ sub read_bug{
         # create the found/fixed hashes which indicate when a
         # particular version was marked found or marked fixed.
         @{$data{$field}}{@{$data{"${field}_versions"}}} =
-             (('') x (@{$data{"${field}_date"}} - @{$data{"${field}_versions"}}),
+             (('') x (@{$data{"${field}_versions"}} - @{$data{"${field}_date"}}),
               @{$data{"${field}_date"}});
     }
 
     my $status_modified = (stat($status))[9];
     # Add log last modified time
     $data{log_modified} = (stat($log))[9] // (stat("${log}.gz"))[9];
+    my $report_modified = (stat($report))[9] // $data{log_modified};
     $data{last_modified} = max($status_modified,$data{log_modified});
+    # if the date isn't set (ancient bug), use the smallest of any of the modified
+    if (not defined $data{date} or not length($data{date})) {
+        $data{date} = min($report_modified,$status_modified,$data{log_modified});
+    }
     $data{location} = $location;
     $data{archived} = (defined($location) and ($location eq 'archive'))?1:0;
     $data{bug_num} = $param{bug};
 
+    # mergedwith occasionally is sorted badly. Fix it to always be sorted by <=>
+    # and not include this bug
+    if (defined $data{mergedwith} and
+       $data{mergedwith}) {
+       $data{mergedwith} =
+           join(' ',
+                grep { $_ != $data{bug_num}}
+                sort { $a <=> $b }
+                split / /, $data{mergedwith}
+               );
+    }
     return \%data;
 }
 
@@ -303,20 +324,42 @@ our $ditch_empty = sub{
     return grep {length $_} map {split $splitter} @t;
 };
 
-my $ditch_empty_space = sub {return &{$ditch_empty}(' ',@_)};
+our $sort_and_unique = sub {
+    my @v;
+    my %u;
+    my $all_numeric = 1;
+    for my $v (@_) {
+        if ($all_numeric and $v =~ /\D/) {
+            $all_numeric = 0;
+        }
+        next if exists $u{$v};
+        $u{$v} = 1;
+        push @v, $v;
+    }
+    if ($all_numeric) {
+        return sort {$a <=> $b} @v;
+    } else {
+        return sort @v;
+    }
+};
+
+my $ditch_space_unique_and_sort = sub {return &{$sort_and_unique}(&{$ditch_empty}(' ',@_))};
 my %split_fields =
     (package        => \&splitpackages,
      affects        => \&splitpackages,
-     blocks         => $ditch_empty_space,
-     blockedby      => $ditch_empty_space,
+     # Ideally we won't have to split source, but because some consumers of
+     # get_bug_status cannot handle arrayref, we will split it here.
+     source         => \&splitpackages,
+     blocks         => $ditch_space_unique_and_sort,
+     blockedby      => $ditch_space_unique_and_sort,
      # this isn't strictly correct, but we'll split both of them for
      # the time being until we ditch all use of keywords everywhere
      # from the code
-     keywords       => $ditch_empty_space,
-     tags           => $ditch_empty_space,
-     found_versions => $ditch_empty_space,
-     fixed_versions => $ditch_empty_space,
-     mergedwith     => $ditch_empty_space,
+     keywords       => $ditch_space_unique_and_sort,
+     tags           => $ditch_space_unique_and_sort,
+     found_versions => $ditch_space_unique_and_sort,
+     fixed_versions => $ditch_space_unique_and_sort,
+     mergedwith     => $ditch_space_unique_and_sort,
     );
 
 sub split_status_fields {
@@ -416,7 +459,6 @@ data.
 =cut
 
 sub lockreadbugmerge {
-     my ($bug_num,$location) = @_;
      my $data = lockreadbug(@_);
      if (not defined $data) {
          return (0,undef);
@@ -514,7 +556,10 @@ sub lock_read_all_merged_bugs {
            # are all merged with eachother
         # We do a cmp sort instead of an <=> sort here, because that's
         # what merge does
-           my $expectmerge= join(' ',grep {$_ != $bug } sort @bugs);
+           my $expectmerge=
+               join(' ',grep {$_ != $bug }
+                    sort { $a <=> $b }
+                    @bugs);
            if ($newdata->{mergedwith} ne $expectmerge) {
                for (1..$locks) {
                    unfilelock(exists $param{locks}?$param{locks}:());
@@ -1204,6 +1249,9 @@ sub get_bug_status {
                                          indicatesource => {type => BOOLEAN,
                                                             default => 1,
                                                            },
+                                         schema => {type => OBJECT,
+                                                     optional => 1,
+                                                   },
                                         },
                              );
      my %status;
@@ -1216,7 +1264,64 @@ sub get_bug_status {
          return \%status;
      }
      if (defined $param{status}) {
-         %status = %{$param{status}};
+        %status = %{$param{status}};
+     }
+     elsif (defined $param{schema}) {
+        my $b = $param{schema}->resultset('Bug')->
+            search_rs({'me.id' => $param{bug}},
+                     {prefetch => [{'bug_tags'=>'tag'},
+                                   'severity',
+                                  {'bug_binpackages'=> 'bin_pkg'},
+                                  {'bug_srcpackages'=> 'src_pkg'},
+                                  {'bug_user_tags'=>{'user_tag'=>'correspondent'}},
+                                  {owner => 'correspondent_full_names'},
+                                  {submitter => 'correspondent_full_names'},
+                                    'bug_merged_bugs',
+                                    'bug_mergeds_merged',
+                                    'bug_blocks_blocks',
+                                    'bug_blocks_bugs',
+                                   {'bug_vers' => ['src_pkg','src_ver']},
+                                  ],
+                      '+columns' => [qw(subject log_modified creation last_modified)],
+                      collapse => 1,
+                      result_class => 'DBIx::Class::ResultClass::HashRefInflator',
+                     })->first();
+        $status{keywords} =
+            join(' ',map {$_->{tag}{tag}} @{$b->{bug_tags}});
+        $status{tags} = $status{keywords};
+        $status{subject} = $b->{subject};
+        $status{bug_num} = $b->{id};
+        $status{severity} = $b->{severity}{severity};
+        $status{package} =
+            join(' ',
+                 (map {$_->{bin_pkg}{pkg}} @{$b->{bug_binpackages}//[]}),
+                 (map {$_->{src_pkg}{pkg}} @{$b->{bug_srcpackages}//[]}));
+         $status{originator} = $b->{submitter_full};
+        $status{log_modified} =
+            DateTime::Format::Pg->parse_datetime($b->{log_modified})->epoch;
+        $status{date} =
+            DateTime::Format::Pg->parse_datetime($b->{creation})->epoch;
+        $status{last_modified} =
+            DateTime::Format::Pg->parse_datetime($b->{last_modified})->epoch;
+         $status{blocks} =
+             join(' ',
+                  uniq(sort(map {$_->{block}}
+                            @{$b->{bug_blocks_block}},
+                           )));
+         $status{blockedby} =
+             join(' ',
+                  uniq(sort(map {$_->{bug}}
+                            @{$b->{bug_blocks_bug}},
+                           )));
+         $status{mergedwith} =
+             join(' ',uniq(sort(map {$_->{bug},$_->{merged}}
+                                @{$b->{bug_merged_bugs}},
+                                @{$b->{bug_mergeds_merged}},
+                               )));
+         $status{fixed_versions} =
+             [map {$_->{found}?():$_->{ver_string}} @{$b->{bug_vers}}];
+         $status{found_versions} =
+             [map {$_->{found}?$_->{ver_string}:()} @{$b->{bug_vers}}];
      }
      else {
          my $location = getbuglocation($param{bug}, 'summary');