summaryrefslogtreecommitdiffstats
path: root/lib/Devscripts/Debbugs.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Devscripts/Debbugs.pm')
-rw-r--r--lib/Devscripts/Debbugs.pm481
1 files changed, 481 insertions, 0 deletions
diff --git a/lib/Devscripts/Debbugs.pm b/lib/Devscripts/Debbugs.pm
new file mode 100644
index 0000000..355adc3
--- /dev/null
+++ b/lib/Devscripts/Debbugs.pm
@@ -0,0 +1,481 @@
+# This is Debbugs.pm from the Debian devscripts package
+#
+# Copyright (C) 2008 Adam D. Barratt
+# select() is Copyright (C) 2007 Don Armstrong
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+package Devscripts::Debbugs;
+
+=head1 OPTIONS
+
+=over
+
+=item select [key:value ...]
+
+Uses the SOAP interface to output a list of bugs which match the given
+selection requirements.
+
+The following keys are allowed, and may be given multiple times.
+
+=over 8
+
+=item package
+
+Binary package name.
+
+=item source
+
+Source package name.
+
+=item maintainer
+
+E-mail address of the maintainer.
+
+=item submitter
+
+E-mail address of the submitter.
+
+=item severity
+
+Bug severity.
+
+=item status
+
+Status of the bug.
+
+=item tag
+
+Tags applied to the bug. If I<users> is specified, may include
+usertags in addition to the standard tags.
+
+=item owner
+
+Bug's owner.
+
+=item correspondent
+
+Address of someone who sent mail to the log.
+
+=item affects
+
+Bugs which affect this package.
+
+=item bugs
+
+List of bugs to search within.
+
+=item users
+
+Users to use when looking up usertags.
+
+=item archive
+
+Whether to search archived bugs or normal bugs; defaults to 0
+(i.e. only search normal bugs). As a special case, if archive is
+'both', both archived and unarchived bugs are returned.
+
+=back
+
+For example, to select the set of bugs submitted by
+jrandomdeveloper@example.com and tagged wontfix, one would use
+
+select("submitter:jrandomdeveloper@example.com", "tag:wontfix")
+
+=back
+
+=cut
+
+use strict;
+use warnings;
+
+my $soapurl = 'Debbugs/SOAP/1';
+our $btsurl = 'http://bugs.debian.org/';
+my @errors;
+
+our $soap_timeout;
+
+sub soap_timeout {
+ my $timeout_arg = shift;
+ if (defined $timeout_arg and $timeout_arg =~ m{^[1-9]\d*$}) {
+ $soap_timeout = $timeout_arg;
+ }
+}
+
+sub init_soap {
+ my $soapproxyurl;
+ if ($btsurl =~ m%^https?://(.*)/?$%) {
+ $soapproxyurl = $btsurl . '/';
+ } else {
+ $soapproxyurl = 'http://' . $btsurl . '/';
+ }
+ $soapproxyurl =~ s%//$%/%;
+ $soapproxyurl .= 'cgi-bin/soap.cgi';
+ my %options;
+ if ($soap_timeout) {
+ $options{timeout} = $soap_timeout;
+ }
+ my $soap = SOAP::Lite->uri($soapurl)->proxy($soapproxyurl, %options);
+
+ $soap->transport->env_proxy();
+ $soap->on_fault(\&getSOAPError);
+
+ return $soap;
+}
+
+my $soap_broken;
+
+sub have_soap {
+ return ($soap_broken ? 0 : 1) if defined $soap_broken;
+ eval { require SOAP::Lite; };
+
+ if ($@) {
+ if ($@ =~ m%^Can't locate SOAP/%) {
+ $soap_broken = "the libsoap-lite-perl package is not installed";
+ } else {
+ $soap_broken = "couldn't load SOAP::Lite: $@";
+ }
+ } else {
+ $soap_broken = 0;
+ }
+ return ($soap_broken ? 0 : 1);
+}
+
+sub getSOAPError {
+ my ($soap, $result) = @_;
+ my $err;
+ if (ref($result)) {
+ $err = $result->faultstring;
+ } else {
+ $err = $soap->transport->status;
+ }
+ chomp $err;
+ push @errors, $err;
+
+ return new SOAP::SOM;
+}
+
+sub usertags {
+ die "Couldn't run usertags: $soap_broken\n" unless have_soap();
+
+ my @args = @_;
+
+ my $soap = init_soap();
+ my $usertags = $soap->get_usertag(@_);
+
+ if (@errors or not defined $usertags) {
+ my $error = join("\n", @errors);
+ die "Error retrieving usertags from SOAP server: $error\n";
+ }
+
+ my $result = $usertags->result();
+
+ if (@errors or not defined $result) {
+ my $error = join("\n", @errors);
+ die "Error retrieving usertags from SOAP server: $error\n";
+ }
+
+ return $result;
+}
+
+sub select {
+ die "Couldn't run select: $soap_broken\n" unless have_soap();
+ my @args = @_;
+ my %valid_keys = (
+ package => 'package',
+ pkg => 'package',
+ src => 'src',
+ source => 'src',
+ maint => 'maint',
+ maintainer => 'maint',
+ submitter => 'submitter',
+ from => 'submitter',
+ status => 'status',
+ tag => 'tag',
+ tags => 'tag',
+ usertag => 'tag',
+ usertags => 'tag',
+ owner => 'owner',
+ dist => 'dist',
+ distribution => 'dist',
+ bugs => 'bugs',
+ archive => 'archive',
+ severity => 'severity',
+ correspondent => 'correspondent',
+ affects => 'affects',
+ );
+ my %users;
+ my %search_parameters;
+ my $soap = init_soap();
+ for my $arg (@args) {
+ my ($key, $value) = split /:/, $arg, 2;
+ next unless $key;
+ if (exists $valid_keys{$key}) {
+ if ($valid_keys{$key} eq 'archive') {
+ $search_parameters{ $valid_keys{$key} } = $value
+ if $value;
+ } else {
+ push @{ $search_parameters{ $valid_keys{$key} } }, $value
+ if $value;
+ }
+ } elsif ($key =~ /users?$/) {
+ $users{$value} = 1 if $value;
+ } else {
+ warn "select(): Unrecognised key: $key\n";
+ }
+ }
+ my %usertags;
+ for my $user (keys %users) {
+ my $ut = usertags($user);
+ next unless defined $ut and $ut ne "";
+ for my $tag (keys %{$ut}) {
+ push @{ $usertags{$tag} }, @{ $ut->{$tag} };
+ }
+ }
+ my $bugs = $soap->get_bugs(%search_parameters,
+ (keys %usertags) ? (usertags => \%usertags) : ());
+
+ if (@errors or not defined $bugs) {
+ my $error = join("\n", @errors);
+ die "Error while retrieving bugs from SOAP server: $error\n";
+ }
+
+ my $result = $bugs->result();
+ if (@errors or not defined $result) {
+ my $error = join("\n", @errors);
+ die "Error while retrieving bugs from SOAP server: $error\n";
+ }
+
+ return $result;
+}
+
+sub status {
+ die "Couldn't run status: $soap_broken\n" unless have_soap();
+ my @args = @_;
+
+ my $soap = init_soap();
+
+ my $result = {};
+ while (my @slice = splice(@args, 0, 500)) {
+ my $bugs = $soap->get_status(@slice);
+
+ if (@errors or not defined $bugs) {
+ my $error = join("\n", @errors);
+ die
+ "Error while retrieving bug statuses from SOAP server: $error\n";
+ }
+
+ my $tmp = $bugs->result();
+
+ if (@errors or not defined $tmp) {
+ my $error = join("\n", @errors);
+ die
+ "Error while retrieving bug statuses from SOAP server: $error\n";
+ }
+
+ %$result = (%$result, %$tmp);
+ }
+
+ return $result;
+}
+
+sub versions {
+ die "Couldn't run versions: $soap_broken\n" unless have_soap();
+
+ my @args = @_;
+ my %valid_keys = (
+ package => 'package',
+ pkg => 'package',
+ src => 'source',
+ source => 'source',
+ time => 'time',
+ binary => 'no_source_arch',
+ notsource => 'no_source_arch',
+ archs => 'return_archs',
+ displayarch => 'return_archs',
+ );
+
+ my %search_parameters;
+ my @archs = ();
+ my @dists = ();
+
+ for my $arg (@args) {
+ my ($key, $value) = split /:/, $arg, 2;
+ $value ||= "1";
+ if ($key =~ /^arch(itecture)?$/) {
+ push @archs, $value;
+ } elsif ($key =~ /^dist(ribution)?$/) {
+ push @dists, $value;
+ } elsif (exists $valid_keys{$key}) {
+ $search_parameters{ $valid_keys{$key} } = $value;
+ }
+ }
+
+ $search_parameters{arch} = \@archs if @archs;
+ $search_parameters{dist} = \@dists if @dists;
+
+ my $soap = init_soap();
+
+ my $versions = $soap->get_versions(%search_parameters);
+
+ if (@errors or not defined $versions) {
+ my $error = join("\n", @errors);
+ die
+ "Error while retrieving package versions from SOAP server: $error\n";
+ }
+
+ my $result = $versions->result();
+
+ if (@errors or not defined $result) {
+ my $error = join("\n", @errors);
+ die "Error while retrieivng package versions from SOAP server: $error";
+ }
+
+ return $result;
+}
+
+sub versions_with_arch {
+ die "Couldn't run versions_with_arch: $soap_broken\n" unless have_soap();
+ my @args = @_;
+
+ my $versions = versions(@args, 'displayarch:1');
+
+ if (not defined $versions) {
+ die "Error while retrieivng package versions from SOAP server: $@";
+ }
+
+ return $versions;
+}
+
+sub newest_bugs {
+ die "Couldn't run newest_bugs: $soap_broken\n" unless have_soap();
+ my $count = shift || '';
+
+ return if $count !~ /^\d+$/;
+
+ my $soap = init_soap();
+
+ my $bugs = $soap->newest_bugs($count);
+
+ if (@errors or not defined $bugs) {
+ my $error = join("\n", @errors);
+ die "Error while retrieving newest bug list from SOAP server: $error";
+ }
+
+ my $result = $bugs->result();
+
+ if (@errors or not defined $result) {
+ my $error = join("\n", @errors);
+ die "Error while retrieving newest bug list from SOAP server: $error";
+ }
+
+ return $result;
+}
+
+# debbugs currently ignores the $msg_num parameter
+# but eventually it might not, so we support passing it
+
+sub bug_log {
+ die "Couldn't run bug_log: $soap_broken\n" unless have_soap();
+
+ my $bug = shift || '';
+ my $message = shift;
+
+ return if $bug !~ /^\d+$/;
+
+ my $soap = init_soap();
+
+ my $log = $soap->get_bug_log($bug, $message);
+
+ if (@errors or not defined $log) {
+ my $error = join("\n", @errors);
+ die "Error while retrieving bug log from SOAP server: $error\n";
+ }
+
+ my $result = $log->result();
+
+ if (@errors or not defined $result) {
+ my $error = join("\n", @errors);
+ die "Error while retrieving bug log from SOAP server: $error\n";
+ }
+
+ return $result;
+}
+
+sub binary_to_source {
+ die "Couldn't run binary_to_source: $soap_broken\n"
+ unless have_soap();
+
+ my $soap = init_soap();
+
+ my $binpkg = shift;
+ my $binver = shift;
+ my $arch = shift;
+
+ return if not defined $binpkg or not defined $binver;
+
+ my $mapping = $soap->binary_to_source($binpkg, $binver, $arch);
+
+ if (@errors or not defined $mapping) {
+ my $error = join("\n", @errors);
+ die
+"Error while retrieving binary to source mapping from SOAP server: $error\n";
+ }
+
+ my $result = $mapping->result();
+
+ if (@errors or not defined $result) {
+ my $error = join("\n", @errors);
+ die
+"Error while retrieving binary to source mapping from SOAP server: $error\n";
+ }
+
+ return $result;
+}
+
+sub source_to_binary {
+ die "Couldn't run source_to_binary: $soap_broken\n"
+ unless have_soap();
+
+ my $soap = init_soap();
+
+ my $srcpkg = shift;
+ my $srcver = shift;
+
+ return if not defined $srcpkg or not defined $srcver;
+
+ my $mapping = $soap->source_to_binary($srcpkg, $srcver);
+
+ if (@errors or not defined $mapping) {
+ my $error = join("\n", @errors);
+ die
+"Error while retrieving source to binary mapping from SOAP server: $error\n";
+ }
+
+ my $result = $mapping->result();
+
+ if (@errors or not defined $result) {
+ my $error = join("\n", @errors);
+ die
+"Error while retrieving source to binary mapping from SOAP server: $error\n";
+ }
+
+ return $result;
+}
+
+1;
+
+__END__
+