]> git.donarmstrong.com Git - debbugs.git/blobdiff - Debbugs/Status.pm
Merge remote-tracking branch 'origin/master' into database
[debbugs.git] / Debbugs / Status.pm
index 76dab7454c4f6da65bda29f7f6e96a4415e210f6..62cba343dce6183553b59ec8fe4976b69a0d10bc 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,7 @@ 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);
 
 use Carp qw(croak);
 
@@ -191,6 +191,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,14 +201,18 @@ 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$/;
     }
     if ($param{lock}) {
        filelock("$config{spool_dir}/lock/$param{bug}",exists $param{locks}?$param{locks}:());
@@ -269,18 +274,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];
+    $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;
 }
 
@@ -302,20 +323,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 {
@@ -415,7 +458,6 @@ data.
 =cut
 
 sub lockreadbugmerge {
-     my ($bug_num,$location) = @_;
      my $data = lockreadbug(@_);
      if (not defined $data) {
          return (0,undef);
@@ -511,12 +553,17 @@ sub lock_read_all_merged_bugs {
            push @data,$newdata;
            # perform a sanity check to make sure that the merged bugs
            # are all merged with eachother
-           my $expectmerge= join(' ',grep {$_ != $bug } sort { $a <=> $b } @bugs);
+        # We do a cmp sort instead of an <=> sort here, because that's
+        # what merge does
+           my $expectmerge=
+               join(' ',grep {$_ != $bug }
+                    sort { $a <=> $b }
+                    @bugs);
            if ($newdata->{mergedwith} ne $expectmerge) {
                for (1..$locks) {
                    unfilelock(exists $param{locks}?$param{locks}:());
                }
-               die "Bug $param{bug} differs from bug $bug: ($newdata->{bug_num}: '$newdata->{mergedwith}') vs. ('$expectmerge') (".join(' ',@bugs).")";
+               die "Bug $param{bug} mergedwith differs from bug $bug: ($newdata->{bug_num}: '$newdata->{mergedwith}') vs. ('$expectmerge') (".join(' ',@bugs).")";
            }
        }
     }
@@ -656,7 +703,7 @@ sub makestatus {
 
 Writes the bug status and summary files out.
 
-Skips writting out a status file if minversion is 2
+Skips writing out a status file if minversion is 2
 
 Does not call bughook if disablebughook is true.
 
@@ -729,9 +776,9 @@ sub addfoundversions {
     my $version = shift;
     my $isbinary = shift;
     return unless defined $version;
-    undef $package if $package =~ m[(?:\s|/)];
+    undef $package if defined $package and $package =~ m[(?:\s|/)];
     my $source = $package;
-    if ($package =~ s/^src://) {
+    if (defined $package and $package =~ s/^src://) {
        $isbinary = 0;
        $source = $package;
     }
@@ -774,7 +821,7 @@ exactly are removed. Otherwise, all versions matching the version
 number are removed.
 
 Currently $package and $isbinary are entirely ignored, but accepted
-for backwards compatibilty.
+for backwards compatibility.
 
 =cut
 
@@ -1614,7 +1661,7 @@ Returns a line for a bug suitable to be written out to index.db.
 =cut
 
 sub generate_index_db_line {
-    my ($data) = @_;
+    my ($data,$bug) = @_;
 
     # just in case someone has given us a split out data
     $data = join_status_fields($data);
@@ -1627,9 +1674,8 @@ sub generate_index_db_line {
     $whendone = "forwarded" if defined $data->{forwarded} and length $data->{forwarded};
     $whendone = "done" if defined $data->{done} and length $data->{done};
     $severity = $data->{severity} if length $data->{severity};
-
     return sprintf "%s %d %d %s [%s] %s %s\n",
-        $pkglist, $data->{bug_num}, $data->{date}, $whendone,
+        $pkglist, $data->{bug_num}//$bug, $data->{date}, $whendone,
             $data->{originator}, $severity, $data->{keywords};
 }
 
@@ -1716,7 +1762,7 @@ sub bughook {
             my $data = $bugs_temp{$bug};
             appendfile("$config{spool_dir}/debbugs.trace","$type $bug\n",makestatus($data, 1));
 
-            $bugs{$bug} = generate_index_db_line($data);
+            $bugs{$bug} = generate_index_db_line($data,$bug);
        }
        update_realtime("$config{spool_dir}/index.db.realtime", %bugs);