]> git.donarmstrong.com Git - debbugs.git/commitdiff
Merge branch 'database'
authorDon Armstrong <don@donarmstrong.com>
Fri, 16 Mar 2018 00:14:56 +0000 (17:14 -0700)
committerDon Armstrong <don@donarmstrong.com>
Fri, 16 Mar 2018 00:14:56 +0000 (17:14 -0700)
1  2 
Debbugs/CGI/Pkgreport.pm
Debbugs/Status.pm
debian/control
t/lib/DebbugsTest.pm

diff --combined Debbugs/CGI/Pkgreport.pm
index b7bd6a94974561a7a56553ed7ce0f475afa3e59d,078fecaa69844f0fe3fbcd5ea803d14be7eb2c2c..060e980a9088cec144ef3fdb1e00d8c90550d67f
@@@ -103,7 -103,7 +103,7 @@@ sub generate_package_info
          print {$output} '<p>';
          print {$output} (($maint =~ /,/)? "Maintainer for $showpkg is "
                           : "Maintainers for $showpkg are ") .
 -                              package_links(maint => $maint);
 +                              package_links(maintainer => $maint);
          print {$output} ".</p>\n";
       }
       else {
               push @references, sprintf "to the <a href=\"%s\">%s package page</a>",
                    html_escape("$config{package_pages}/$package"), html_escape("$package");
          }
-         if (defined $config{subscription_domain} and
-             length $config{subscription_domain}) {
+         if (defined $config{package_tracking_domain} and
+             length $config{package_tracking_domain}) {
               my $ptslink = $param{binary} ? $srcforpkg : $package;
               # the pts only wants the source, and doesn't care about src: (#566089)
               $ptslink =~ s/^src://;
@@@ -301,6 -301,9 +301,9 @@@ sub pkg_htmlizebugs 
                                          dist     => {type => SCALAR,
                                                       optional => 1,
                                                      },
+                                         schema   => {type => OBJECT,
+                                                      optional => 1,
+                                                     },
                                         }
                              );
       my @bugs = @{$param{bugs}};
          push @{$exclude{$key}}, split /\s*,\s*/, $value;
       }
  
 +     my $binary_to_source_cache = {};
       foreach my $bug (@bugs) {
-         my %status = %{get_bug_status(bug=>$bug,
-                                       (exists $param{dist}?(dist => $param{dist}):()),
-                                       bugusertags => $param{bugusertags},
-                                       (exists $param{version}?(version => $param{version}):()),
+        my %status = %{get_bug_status(bug=>$bug,
+                                      (map {exists $param{$_}?($_,$param{$_}):()}
+                                       qw(dist version schema bugusertags)
+                                      ),
                                        (exists $param{arch}?(arch => $param{arch}):(arch => $config{default_architectures})),
 +                                      binary_to_source_cache => $binary_to_source_cache,
                                       )};
          next unless %status;
          next if bug_filter(bug => $bug,
diff --combined Debbugs/Status.pm
index 2c6ce209e9c07dccbcde3335e0da25803c5dc544,7af7fcf1dfd057dd5a5fa3311c8a0f0216bb6c4c..9d047a40b053a6867d4b10b24d0486c88e6c8a1e
@@@ -33,8 -33,6 +33,8 @@@ status of a particular bu
  use warnings;
  use strict;
  
 +use feature 'state';
 +
  use vars qw($VERSION $DEBUG %EXPORT_TAGS @EXPORT_OK @EXPORT);
  use Exporter qw(import);
  
@@@ -51,7 -49,8 +51,8 @@@ use File::Copy qw(copy)
  use Encode qw(decode encode is_utf8);
  
  use Storable qw(dclone);
- use List::AllUtils qw(min max);
+ use List::AllUtils qw(min max uniq);
+ use DateTime::Format::Pg;
  
  use Carp qw(croak);
  
@@@ -166,33 -165,34 +167,34 @@@ sub read_bug
      if (@_ == 1) {
         unshift @_, 'bug';
      }
 +    state $spec =
 +       {bug => {type => SCALAR,
 +              optional => 1,
 +              # something really stupid passes negative bugnumbers
 +              regex    => qr/^-?\d+/,
 +             },
 +      location => {type => SCALAR|UNDEF,
 +                   optional => 1,
 +                  },
 +      summary  => {type => SCALAR,
 +                   optional => 1,
 +                  },
 +      lock     => {type => BOOLEAN,
 +                   optional => 1,
 +                  },
 +      locks    => {type => HASHREF,
 +                   optional => 1,
 +                  },
 +       };
      my %param = validate_with(params => \@_,
 -                            spec   => {bug => {type => SCALAR,
 -                                               optional => 1,
 -                                               # something really
 -                                               # stupid passes
 -                                               # negative bugnumbers
 -                                               regex    => qr/^-?\d+/,
 -                                              },
 -                                       location => {type => SCALAR|UNDEF,
 -                                                    optional => 1,
 -                                                   },
 -                                       summary  => {type => SCALAR,
 -                                                    optional => 1,
 -                                                   },
 -                                       lock     => {type => BOOLEAN,
 -                                                    optional => 1,
 -                                                   },
 -                                       locks    => {type => HASHREF,
 -                                                    optional => 1,
 -                                                   },
 -                                      },
 +                            spec   => $spec,
                             );
      die "One of bug or summary must be passed to read_bug"
         if not exists $param{bug} and not exists $param{summary};
      my $status;
      my $log;
      my $location;
+     my $report;
      if (not defined $param{summary}) {
         my $lref;
         ($lref,$location) = @param{qw(bug location)};
         }
         $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$/;
      }
  
      my %data;
      my @lines;
 -    my $version = 2;
 +    my $version;
      local $_;
  
      while (<$status_fh>) {
          chomp;
          push @lines, $_;
 -        $version = $1 if /^Format-Version: ([0-9]+)/i;
 +      if (not defined $version and
 +          /^Format-Version: ([0-9]+)/i
 +         ) {
 +          $version = $1;
 +      }
      }
 -
 +    $version = 2 if not defined $version;
      # Version 3 is the latest format version currently supported.
      if ($version > 3) {
         warn "Unsupported status version '$version'";
         return undef;
      }
  
 -    my %namemap = reverse %fields;
 +    state $namemap = {reverse %fields};
      for my $line (@lines) {
          if ($line =~ /(\S+?): (.*)/) {
              my ($name, $value) = (lc $1, $2);
            # or \n in the fields of status. Kill them off here.
            # [Eventually, this should be superfluous.]
            $value =~ s/[\r\n]//g;
 -          $data{$namemap{$name}} = $value if exists $namemap{$name};
 +          $data{$namemap->{$name}} = $value if exists $namemap->{$name};
          }
      }
      for my $field (keys %fields) {
      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};
@@@ -320,23 -324,42 +330,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,
       # 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_empty_space,
-      blockedby      => $ditch_empty_space,
+      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 {
@@@ -1198,40 -1221,38 +1227,43 @@@ sub get_bug_status 
       if (@_ == 1) {
          unshift @_, 'bug';
       }
 +     state $spec =
 +      {bug       => {type => SCALAR,
 +                     regex => qr/^\d+$/,
 +                    },
 +       status    => {type => HASHREF,
 +                     optional => 1,
 +                    },
 +       bug_index => {type => OBJECT,
 +                     optional => 1,
 +                    },
 +       version   => {type => SCALAR|ARRAYREF,
 +                     optional => 1,
 +                    },
 +       dist       => {type => SCALAR|ARRAYREF,
 +                      optional => 1,
 +                     },
 +       arch       => {type => SCALAR|ARRAYREF,
 +                      optional => 1,
 +                     },
 +       bugusertags   => {type => HASHREF,
 +                         optional => 1,
 +                        },
 +       sourceversions => {type => ARRAYREF,
 +                          optional => 1,
 +                         },
 +       indicatesource => {type => BOOLEAN,
 +                          default => 1,
 +                         },
 +       binary_to_source_cache => {type => HASHREF,
 +                                  optional => 1,
 +                                 },
++       schema => {type => OBJECT,
++                  optional => 1,
++                 },
 +      };
       my %param = validate_with(params => \@_,
 -                             spec   => {bug       => {type => SCALAR,
 -                                                      regex => qr/^\d+$/,
 -                                                     },
 -                                        status    => {type => HASHREF,
 -                                                      optional => 1,
 -                                                     },
 -                                        bug_index => {type => OBJECT,
 -                                                      optional => 1,
 -                                                     },
 -                                        version   => {type => SCALAR|ARRAYREF,
 -                                                      optional => 1,
 -                                                     },
 -                                        dist       => {type => SCALAR|ARRAYREF,
 -                                                       optional => 1,
 -                                                      },
 -                                        arch       => {type => SCALAR|ARRAYREF,
 -                                                       optional => 1,
 -                                                      },
 -                                        bugusertags   => {type => HASHREF,
 -                                                          optional => 1,
 -                                                         },
 -                                        sourceversions => {type => ARRAYREF,
 -                                                           optional => 1,
 -                                                          },
 -                                        indicatesource => {type => BOOLEAN,
 -                                                           default => 1,
 -                                                          },
 -                                        schema => {type => OBJECT,
 -                                                     optional => 1,
 -                                                  },
 -                                       },
 +                             spec   => $spec,
                              );
       my %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');
  
       $status{source} = binary_to_source(binary=>[split /\s*,\s*/, $status{package}],
                                        source_only => 1,
 +                                      exists $param{binary_to_source_cache}?
 +                                      (cache =>$param{binary_to_source_cache}):(),
                                       );
  
       $status{"package"} = 'unknown' if ($status{"package"} eq '');
diff --combined debian/control
index cdf4fd2ab1d8a71e266f95e88e5cc3693e989014,772915351d2d347d01d198f62b5594c97c864a0a..0226f703ca7f17b40413d66c03ea31b6c0c4b796
@@@ -1,25 -1,24 +1,26 @@@
  Source: debbugs
  Section: misc
 -Priority: extra
 +Priority: optional
  Maintainer: Debbugs developers <debian-debbugs@lists.debian.org>
  Uploaders: Colin Watson <cjwatson@debian.org>, Don Armstrong <don@debian.org>
 -Standards-Version: 3.9.4
 -Vcs-Browser: http://bugs.debian.org/debbugs-source/mainline
 -Vcs-Git: http://bugs.debian.org/debbugs-source/debbugs.git
 +Standards-Version: 4.1.3
 +Vcs-Browser: https://salsa.debian.org/debbugs-team/debbugs
 +Vcs-Git: https://salsa.debian.org/debbugs-team/debbugs.git
  Build-Depends: debhelper (>= 9)
  Build-Depends-Indep: libparams-validate-perl,
   libmailtools-perl, libmime-tools-perl, libio-stringy-perl, libmldbm-perl,
   liburi-perl, libsoap-lite-perl, libcgi-simple-perl,
   libhttp-server-simple-perl, libtest-www-mechanize-perl,
 - libmail-rfc822-address-perl, libsafe-hole-perl, libuser-perl,
 + libmail-rfc822-address-perl, libuser-perl,
   libconfig-simple-perl, libtest-pod-perl, liblist-allutils-perl,
- # used by Debbugs::Libravatar and libravatar.cgi
   libfile-libmagic-perl, libgravatar-url-perl, libwww-perl, imagemagick,
 - libdbix-class-perl, libdatetime-format-pg-perl,
++ libdbix-class-perl, libdatetime-format-pg-perl, libtest-postgresql-perl,
+  libdatetime-format-mail-perl,
 - libtext-template-perl, graphviz, libtext-iconv-perl, libnet-server-perl,
 - libtest-postgresql-perl
 -Homepage: http://wiki.debian.org/Teams/Debbugs
 + libtext-xslate-perl, graphviz, libtext-iconv-perl, libnet-server-perl,
 +# used to make the logo
 + inkscape
 +Homepage: https://salsa.debian.org/debbugs-team
 +Testsuite: autopkgtest-pkg-perl
  
  Package: debbugs
  Architecture: all
@@@ -44,14 -43,16 +45,15 @@@ Description: bug tracking system based 
  Package: libdebbugs-perl
  Architecture: all
  Depends:
-  ${misc:Depends},
-  ${perl:Depends}, libmailtools-perl, ed, libmime-tools-perl,
+  ${misc:Depends}, ${perl:Depends}, libmailtools-perl, ed, libmime-tools-perl,
   libio-stringy-perl, libmldbm-perl, liburi-perl, libsoap-lite-perl,
 - libcgi-simple-perl, libparams-validate-perl, libtext-template-perl,
 - libsafe-hole-perl, libmail-rfc822-address-perl, liblist-moreutils-perl,
 - libtext-template-perl,
 - # used by Debbugs::Libravatar and libravatar.cgi
 - libfile-libmagic-perl,
 - libgravatar-url-perl, libwww-perl, imagemagick,
 + libcgi-simple-perl, libparams-validate-perl, libtext-xslate-perl,
 + libmail-rfc822-address-perl, liblist-allutils-perl,
 + graphviz, libtext-iconv-perl, libuser-perl,
 +# used by Debbugs::Libravatar and libravatar.cgi
 + libfile-libmagic-perl, libgravatar-url-perl, libwww-perl, imagemagick
+  # used by the database
+  libdatetime-format-mail-perl, libdbix-class-perl, libdatetime-format-pg-perl
  Section: perl
  Description: modules used by the active Debian BTS
   Debian has a bug tracking system which files details of bugs reported by
diff --combined t/lib/DebbugsTest.pm
index a336bc695af985f1b350745fb03e0f58f3875ade,fcc0dc04b31bb8f6e9d8e5a21ffcefa712804815..a23fdd4d7a0f56dd4e10df34b79ba1ffbb052dbf
@@@ -32,6 -32,7 +32,7 @@@ use File::Basename qw(dirname basename)
  use IPC::Open3;
  use IO::Handle;
  use Test::More;
+ use Test::PostgreSQL;
  
  use Params::Validate qw(validate_with :types);
  
@@@ -42,10 -43,10 +43,11 @@@ BEGIN
       @EXPORT = ();
       %EXPORT_TAGS = (configuration => [qw(dirsize create_debbugs_configuration send_message)],
                     mail          => [qw(num_messages_sent)],
 +                   control       => [qw(test_control_commands)],
+                    database => [qw(create_postgresql_database update_postgresql_database)]
                    );
       @EXPORT_OK = ();
-      Exporter::export_ok_tags(qw(configuration mail control));
+      Exporter::export_ok_tags(keys %EXPORT_TAGS);
       $EXPORT_TAGS{all} = [@EXPORT_OK];
  }
  
@@@ -206,82 -207,6 +208,80 @@@ sub send_message
       }
  }
  
- $SIG{CHLD} = sub {};
 +=item test_control_commands
 +
 + test_control_commands(\%config,
 +                       forcemerge => {command => 'forcemerge',
 +                                      value   => '1 2',
 +                                      status_key => 'mergedwith',
 +                                      status_value => '2',
 +                                      expect_error => 0,
 +                                     });
 +
 +Test a set of control commands to see if they will fail or not. Takes
 +SCALAR/HASHREF pairs, where the scalar should be unique, and the HASHREF
 +contains the following keys:
 +
 +=over
 +
 +=item command -- control command to issue
 +
 +=item value -- value to pass to control command
 +
 +=item status_key -- bug status key to check
 +
 +=item status_value -- value of status key
 +
 +=item expect_error -- whether to expect the control command to error or not
 +
 +=back
 +
 +=cut
 +
 +sub test_control_commands {
 +    my ($config,@commands) = @_;
 +
 +    # now we need to check to make sure that the control message actually did anything
 +    # This is an eval because $ENV{DEBBUGS_CONFIG_FILE} isn't set at BEGIN{} time
 +    eval "use Debbugs::Status qw(read_bug writebug);";
 +    while (my ($command,$control_command) = splice(@commands,0,2)) {
 +      # just check to see that control doesn't explode
 +      $control_command->{value} = " $control_command->{value}" if length $control_command->{value}
 +          and $control_command->{value} !~ /^\s/;
 +      send_message(to => 'control@bugs.something',
 +                   headers => [To   => 'control@bugs.something',
 +                               From => 'foo@bugs.something',
 +                               Subject => "Munging a bug with $command",
 +                              ],
 +                   body => <<EOF) or fail 'message to control@bugs.something failed';
 +debug 10
 +$control_command->{command} $control_command->{value}
 +thanks
 +EOF
 +      ;
 +      # now we need to check to make sure the control message was processed without errors
 +      if (not ($control_command->{expect_error} // 0)) {
 +          ok(system('sh','-c','find '.$config->{sendmail_dir}.
 +                    q( -type f | xargs grep -q "Subject: Processed: Munging a bug with $command")
 +                   ) == 0,
 +             'control@bugs.something'. "$command message was parsed without errors");
 +      }
 +      # now we need to check to make sure that the control message actually did anything
 +      my $status;
 +      $status = read_bug(exists $control_command->{bug}?(bug => $control_command->{bug}):(bug=>1),
 +                         exists $control_command->{location}?(location => $control_command->{location}):(),
 +                        );
 +      is_deeply($status->{$control_command->{status_key}},
 +                $control_command->{status_value},
 +                "bug " .
 +                (exists $control_command->{bug}?$control_command->{bug}:1).
 +                " $command"
 +               )
 +          or fail(Data::Dumper->Dump([$status],[qw(status)]));
 +    }
 +}
 +
 +
  {
       package DebbugsTest::HTTPServer;
       use base qw(HTTP::Server::Simple::CGI HTTP::Server::Simple::CGI::Environment);
@@@ -352,6 -277,98 +352,98 @@@ sub num_messages_sent 
      return $cur_size;
  }
  
+ =head2 create_postgresql_database
+ C<my $pgsql = create_postgresql_database();>
+ Create a postgresql database for testing; when the L<Test::PostgreSQL> object it
+ returns is destroyed (or goes out of scope) the database will be removed.
+ =cut
+ sub create_postgresql_database {
+     my $pgsql = Test::PostgreSQL->new(use_socket => 1) or
+       return undef;
+     my $installsql =
+       File::Spec->rel2abs(dirname(__FILE__).'/../..').
+           '/bin/debbugs-installsql';
+     # create the debversion extension
+     my $dbh = DBI->connect($pgsql->dsn);
+     $dbh->do(<<END) or die "Unable to create extension";
+ CREATE EXTENSION IF NOT EXISTS debversion;
+ END
+     # create the schema for the bug tracking system
+     my $dep_dir = File::Temp::tempdir(CLEANUP=>1);
+     system($installsql,
+          '--dsn',$pgsql->dsn,
+          '--install',
+          '--deployment-dir',$dep_dir);
+     initialize_postgresql_database($pgsql,@_);
+     return $pgsql;
+ }
+ =item iniitalize_postgresql_database
+ C<initialize_postgresql_database();>
+ Initialize postgresql database by calling debbugs-loadsql appropriately.
+ =cut
+ sub initialize_postgresql_database {
+     my ($pgsql,@options) = @_;
+     my $loadsql =
+       File::Spec->rel2abs(dirname(__FILE__).'/../..').
+           '/bin/debbugs-loadsql';
+     my $ftpdists =
+       File::Spec->rel2abs(dirname(__FILE__).'/../debian/dist');
+     my $debinfo_dir =
+       File::Spec->rel2abs(dirname(__FILE__).'/../debian/debinfo');
+     my %loadsql_commands =
+       (configuration => [],
+        suites => ['--ftpdists',$ftpdists],
+        debinfo => ['--debinfo-dir',$debinfo_dir],
+        packages => ['--ftpdists',$ftpdists],
+        maintainers => [],
+       );
+     for my $command (keys %loadsql_commands) {
+       system($loadsql,$command,
+              '--dsn',$pgsql->dsn,
+              @options,
+              @{$loadsql_commands{$command}}) == 0 or
+                  die "Unable to load $command";
+     }
+ }
+ =item update_postgresql_database
+ C<update_postgresql_database();>
+ Update the postgresql database by calling debbugs-loadsql appropriately.
+ =cut
+ sub update_postgresql_database {
+     my ($pgsql,@options) = @_;
+     my $loadsql =
+       File::Spec->rel2abs(dirname(__FILE__).'/../..').
+           '/bin/debbugs-loadsql';
+     my %loadsql_commands =
+       (bugs_and_logs => [],
+       );
+     for my $command (keys %loadsql_commands) {
+       system($loadsql,$command,
+              '--dsn',$pgsql->dsn,
+              @options,
+              @{$loadsql_commands{$command}}) == 0 or
+                  die "Unable to load $command";
+     }
+ }
  
  1;