|
Michal Marek |
bed3c7 |
package SUSE::MyBS;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
use strict;
|
|
Michal Marek |
bed3c7 |
use warnings;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
use Carp;
|
|
Michal Marek |
bed3c7 |
use LWP::UserAgent;
|
|
Michal Marek |
bed3c7 |
use URI;
|
|
Michal Marek |
bed3c7 |
use XML::Parser;
|
|
Michal Marek |
bed3c7 |
use XML::Writer;
|
|
Michal Marek |
bed3c7 |
use HTTP::Request;
|
|
Michal Marek |
bed3c7 |
use File::Temp qw(tempfile);
|
|
Michal Marek |
bed3c7 |
use Config::IniFiles;
|
|
Michal Marek |
bed3c7 |
use Digest::MD5;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
use SUSE::MyBS::Buildresults;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub new {
|
|
Michal Marek |
bed3c7 |
my ($class, $api_url) = @_;
|
|
Michal Marek |
bed3c7 |
my $self = { };
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$api_url ||= "https://api.opensuse.org";
|
|
Michal Marek |
bed3c7 |
$api_url =~ s:/*$::;
|
|
Michal Marek |
bed3c7 |
if ($api_url !~ m@^https?://@) {
|
|
Michal Marek |
bed3c7 |
$api_url = "https://$api_url";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$self->{url} = URI->new($api_url);
|
|
Michal Marek |
bed3c7 |
|
|
Jiri Slaby |
cd4eb9 |
my $cfgfile;
|
|
Jiri Slaby |
cd4eb9 |
foreach ("$ENV{HOME}/.oscrc", "$ENV{HOME}/.config/osc/oscrc") {
|
|
Jiri Slaby |
cd4eb9 |
if (-f) {
|
|
Jiri Slaby |
cd4eb9 |
$cfgfile = $_;
|
|
Jiri Slaby |
cd4eb9 |
last;
|
|
Jiri Slaby |
cd4eb9 |
}
|
|
Jiri Slaby |
cd4eb9 |
}
|
|
Jiri Slaby |
cd4eb9 |
|
|
Jiri Slaby |
cd4eb9 |
defined $cfgfile or die "oscrc not found";
|
|
Jiri Slaby |
cd4eb9 |
|
|
Michal Marek |
bed3c7 |
# replace name: value with name= value that Config::IniFiles can parse
|
|
Michal Marek |
bed3c7 |
open(my $fh, '<', $cfgfile) or die "$cfgfile: $!\n";
|
|
Michal Marek |
bed3c7 |
my $data = "";
|
|
Michal Marek |
bed3c7 |
my $changed = 0;
|
|
Michal Marek |
bed3c7 |
while (<$fh>) {
|
|
Michal Marek |
bed3c7 |
if (s/^([^[:=]+):/$1=/) {
|
|
Michal Marek |
bed3c7 |
$changed = 1;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$data .= $_;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
close($fh);
|
|
Michal Marek |
bed3c7 |
my $config;
|
|
Michal Marek |
bed3c7 |
if ($changed) {
|
|
Michal Marek |
bed3c7 |
(my $fh, $cfgfile) = tempfile();
|
|
Michal Marek |
bed3c7 |
print $fh $data;
|
|
Michal Marek |
bed3c7 |
close($fh);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
my %config;
|
|
Michal Marek |
bed3c7 |
tie %config, 'Config::IniFiles', (-file => $cfgfile);
|
|
Michal Marek |
bed3c7 |
if ($changed) {
|
|
Michal Marek |
bed3c7 |
unlink($cfgfile);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
if (!keys(%config)) {
|
|
Michal Marek |
bed3c7 |
die join("\n", @Config::IniFiles::errors), "\n";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
my %cred;
|
|
Michal Suchanek |
5f57bd |
for my $kw (qw(user pass passx keyring credentials_mgr_class)) {
|
|
Michal Marek |
bed3c7 |
for my $section ($api_url, "$api_url/", $self->{url}->host) {
|
|
Michal Marek |
bed3c7 |
if (exists($config{$section}) &&
|
|
Michal Marek |
bed3c7 |
exists($config{$section}{$kw})) {
|
|
Michal Marek |
bed3c7 |
$cred{$kw} = $config{$section}{$kw};
|
|
Michal Marek |
bed3c7 |
last;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Suchanek |
47ccb9 |
if (exists($cred{credentials_mgr_class})) {
|
|
Michal Suchanek |
47ccb9 |
if ($cred{credentials_mgr_class} eq "osc.credentials.ObfuscatedConfigFileCredentialsManager") {
|
|
Michal Suchanek |
47ccb9 |
$cred{passx}=$cred{pass};
|
|
Michal Suchanek |
47ccb9 |
}}
|
|
Michal Suchanek |
5f57bd |
if (exists($cred{passx})) {
|
|
Michal Marek |
bed3c7 |
# Not available on SLES10, hence the 'require'
|
|
Michal Marek |
bed3c7 |
require MIME::Base64;
|
|
Michal Marek |
bed3c7 |
require IO::Uncompress::Bunzip2;
|
|
Michal Marek |
bed3c7 |
my $bz2 = MIME::Base64::decode_base64($cred{passx});
|
|
Michal Marek |
bed3c7 |
$cred{pass} = "";
|
|
Michal Marek |
bed3c7 |
IO::Uncompress::Bunzip2::bunzip2(\$bz2 => \$cred{pass})
|
|
Michal Marek |
bed3c7 |
or die "Decoding password for $api_url failed: $IO::Uncompress::Bunzip2::Bunzip2Error\n";
|
|
Michal Marek |
bed3c7 |
}
|
|
|
4bafc0 |
if (!exists($cred{pass}) && exists($cred{keyring})) {
|
|
|
d2378a |
my $api = $api_url;
|
|
|
d2378a |
$api =~ s/^https?:\/\///;
|
|
|
d2378a |
open(my $secret, "secret-tool lookup service $api username $cred{user} |")
|
|
|
d2378a |
or die "Please install the \"secret-tool\" package to use a keyring\n";
|
|
|
4bafc0 |
$cred{pass} = <$secret>;
|
|
|
4bafc0 |
close($secret);
|
|
|
d2378a |
die "Failed to obtain secret from secret-tool\n"
|
|
|
4bafc0 |
if !$cred{pass};
|
|
|
4bafc0 |
chomp($cred{pass});
|
|
Michal Suchanek |
5f57bd |
}
|
|
Michal Suchanek |
5f57bd |
if (!exists($cred{user}) || !exists($cred{pass})) {
|
|
Michal Suchanek |
5f57bd |
die "Error: Username or password for $api_url not set in ~/.oscrc\n" .
|
|
Michal Suchanek |
5f57bd |
"Error: Run `osc -A $api_url ls' once\n";
|
|
|
4bafc0 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$self->{ua} = LWP::UserAgent->new;
|
|
Michal Suchanek |
3ae8f5 |
my $realm = "Use your developer account";
|
|
Jiri Slaby |
54326b |
$realm = "Use your SUSE developer account" if $api_url =~ /opensuse/;
|
|
Michal Suchanek |
3ae8f5 |
$self->{ua}->credentials($self->{url}->host_port, $realm,
|
|
Michal Marek |
bed3c7 |
$cred{user}, $cred{pass});
|
|
Michal Marek |
bed3c7 |
if ($self->{ua}->can('ssl_opts')) {
|
|
Michal Marek |
bed3c7 |
$self->{ua}->ssl_opts(verify_hostname => 1);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
bless($self, $class);
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
if ($self->{url}->scheme eq "https" &&
|
|
Michal Marek |
bed3c7 |
$self->{url}->host eq "api.suse.de" &&
|
|
Michal Marek |
bed3c7 |
$self->{ua}->can('ssl_opts')) {
|
|
Michal Marek |
bed3c7 |
eval {
|
|
Michal Marek |
bed3c7 |
$self->get("/about");
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
if ($@) {
|
|
Michal Marek |
bed3c7 |
# Use the canned certificate as a backup
|
|
Michal Marek |
bed3c7 |
# XXX: Check that we really got an unknown cert error
|
|
Michal Marek |
bed3c7 |
(my $pkg = __PACKAGE__) =~ s@::@/@g;
|
|
Michal Marek |
bed3c7 |
$pkg .= ".pm";
|
|
Michal Marek |
bed3c7 |
(my $cert = $INC{$pkg}) =~ s@[^/]*$@@;
|
|
Michal Marek |
bed3c7 |
$cert .= "SUSE_Trust_Root.pem";
|
|
Michal Marek |
bed3c7 |
$self->{ua}->ssl_opts(SSL_ca_file => $cert);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
return $self;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub api {
|
|
Michal Marek |
bed3c7 |
my ($self, $method, $path, $data) = @_;
|
|
Michal Marek |
bed3c7 |
my $url = $self->{url} . $path;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $req = HTTP::Request->new($method => $url);
|
|
Michal Marek |
bed3c7 |
if ($data) {
|
|
Michal Marek |
bed3c7 |
$req->add_content($data);
|
|
Michal Marek |
2cc93a |
$req->header("Content-type" => "application/octet-stream");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
4dbe92 |
#$self->{ua}->prepare_request($req);
|
|
Michal Marek |
4dbe92 |
#print STDERR "req: " . $req->as_string() . "\n";
|
|
Michal Suchanek |
3ae8f5 |
#$self->{ua}->add_handler(request_send => sub { my($req, $ua, $handler) = @_; print STDERR "req: " . $req->as_string() . "\n"; return; m_method => "GET"});
|
|
Michal Marek |
bed3c7 |
my $res = $self->{ua}->request($req);
|
|
Michal Marek |
bed3c7 |
if ($res->code != 200) {
|
|
Michal Marek |
4dbe92 |
#print STDERR $res->as_string();
|
|
Michal Marek |
4b77a5 |
die "$method $path: @{[$res->message()]} (HTTP @{[$res->code()]})\n";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
return $res->content();
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub get {
|
|
Michal Marek |
bed3c7 |
my $self = shift;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$self->api('GET', @_);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub post {
|
|
Michal Marek |
bed3c7 |
my $self = shift;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$self->api('POST', @_);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub put {
|
|
Michal Marek |
bed3c7 |
my $self = shift;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$self->api('PUT', @_);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub put_file {
|
|
Michal Marek |
bed3c7 |
my ($self, $file, $path) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
open(my $fh, '<', $file) or die "$file: $!\n";
|
|
Michal Marek |
bed3c7 |
local $/ = undef;
|
|
Michal Marek |
bed3c7 |
my $data = <$fh>;
|
|
Michal Marek |
bed3c7 |
close($fh);
|
|
Michal Marek |
bed3c7 |
$self->put($path, $data);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub delete {
|
|
Michal Marek |
bed3c7 |
my $self = shift;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$self->api('DELETE', @_);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub exists {
|
|
Michal Marek |
bed3c7 |
my ($self, $path) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
eval {
|
|
Michal Marek |
bed3c7 |
$self->get($path);
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
return 0 if $@;
|
|
Michal Marek |
bed3c7 |
return 1;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub project_exists {
|
|
Michal Marek |
bed3c7 |
my ($self, $project) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
return $self->exists("/source/$project/_meta");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub package_exists {
|
|
Michal Marek |
bed3c7 |
my ($self, $project, $package) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
return $self->exists("/source/$project/$package/_meta");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub readdir {
|
|
Michal Marek |
bed3c7 |
my ($self, $path) = @_;
|
|
Michal Marek |
bed3c7 |
my $xml = $self->get($path);
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $handle_start = sub {
|
|
Michal Marek |
bed3c7 |
my ($self, $element, %attr) = @_;
|
|
Michal Marek |
bed3c7 |
return unless $element eq "entry" || $element eq "binary";
|
|
Michal Marek |
bed3c7 |
my $name;
|
|
Michal Marek |
bed3c7 |
if ($attr{name}) {
|
|
Michal Marek |
bed3c7 |
$name = $attr{name};
|
|
Michal Marek |
bed3c7 |
delete($attr{name});
|
|
Michal Marek |
bed3c7 |
} elsif ($attr{filename}) {
|
|
Michal Marek |
bed3c7 |
$name = $attr{filename};
|
|
Michal Marek |
bed3c7 |
delete($attr{filename});
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$self->{res}->{$name} = \%attr;
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $p = XML::Parser->new(Handlers => {Start => $handle_start});
|
|
Michal Marek |
bed3c7 |
$p->{res} = {};
|
|
Michal Marek |
bed3c7 |
$p->parse($xml);
|
|
Michal Marek |
bed3c7 |
return $p->{res};
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
# Return list of architectures for given repository of given project
|
|
Michal Marek |
bed3c7 |
sub get_repo_archs {
|
|
Michal Marek |
bed3c7 |
my ($self, $project, $repository) = @_;
|
|
Michal Marek |
bed3c7 |
my $xml = $self->get("/source/$project/_meta");
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $handle_start = sub {
|
|
Michal Marek |
bed3c7 |
my ($self, $element, %attr) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
return if $element ne "repository";
|
|
Michal Marek |
bed3c7 |
if (defined($repository)) {
|
|
Michal Marek |
bed3c7 |
return if $attr{name} ne $repository;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
126229 |
if ($attr{name} eq "standard" ||
|
|
Michal Marek |
011b66 |
$attr{name} eq "ports" && $project !~ /\bopenSUSE:Factory\b/ ||
|
|
Michal Marek |
126229 |
$attr{name} =~ /^SUSE_.*_Update$/ && $project =~ /^SUSE:Maintenance:/) {
|
|
Michal Marek |
126229 |
$self->{has_match} = 1;
|
|
Michal Marek |
126229 |
$self->{repo_name} = $attr{name};
|
|
Michal Marek |
126229 |
$self->{res}{$attr{name}} ||= [];
|
|
Michal Marek |
126229 |
}
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
my $handle_char = sub {
|
|
Michal Marek |
bed3c7 |
my ($self, $string) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
if ($self->{has_match}) {
|
|
Michal Marek |
bed3c7 |
$string =~ s/\s//g;
|
|
Michal Marek |
bed3c7 |
$self->{cur_string} .= $string;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
my $handle_end = sub {
|
|
Michal Marek |
bed3c7 |
my ($self, $element) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
if ($element eq "repository") {
|
|
Michal Marek |
bed3c7 |
$self->{has_match} = 0;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
if ($element eq "arch" && $self->{has_match}) {
|
|
Michal Marek |
bed3c7 |
push(@{$self->{res}{$self->{repo_name}}}, $self->{cur_string});
|
|
Michal Marek |
bed3c7 |
$self->{cur_string} = "";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
my $p = XML::Parser->new(Handlers => {
|
|
Michal Marek |
bed3c7 |
Start => $handle_start,
|
|
Michal Marek |
bed3c7 |
Char => $handle_char,
|
|
Michal Marek |
bed3c7 |
End => $handle_end});
|
|
Michal Marek |
bed3c7 |
$p->{res} = {};
|
|
Michal Marek |
bed3c7 |
$p->parse($xml);
|
|
Michal Marek |
bed3c7 |
return %{$p->{res}};
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub create_project {
|
|
Michal Marek |
bed3c7 |
my ($self, $project, $options) = @_;
|
|
Michal Marek |
bed3c7 |
my %limit_archs;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$options->{title} ||= $project,
|
|
Michal Marek |
bed3c7 |
$options->{description} ||= "";
|
|
Michal Marek |
bed3c7 |
if (!exists($options->{build})) {
|
|
Michal Marek |
bed3c7 |
$options->{build} = 1;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
if (!exists($options->{publish})) {
|
|
Michal Marek |
bed3c7 |
$options->{publish} = 1;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$options->{limit_archs} ||= [];
|
|
Michal Marek |
bed3c7 |
if (scalar(@{$options->{limit_archs}})) {
|
|
Michal Marek |
bed3c7 |
$limit_archs{$_} = 1 for @{$options->{limit_archs}};
|
|
Michal Marek |
bed3c7 |
} else {
|
|
Michal Marek |
bed3c7 |
$options->{limit_archs} = undef;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $meta;
|
|
Michal Marek |
bed3c7 |
my $writer = XML::Writer->new(OUTPUT => \$meta);
|
|
Michal Marek |
bed3c7 |
$writer->startTag("project", name => $project);
|
|
Michal Marek |
bed3c7 |
$writer->dataElement("title", $options->{title});
|
|
Michal Marek |
bed3c7 |
$writer->dataElement("description", $options->{description});
|
|
Michal Marek |
bed3c7 |
$options->{maintainers} ||= [];
|
|
Michal Marek |
bed3c7 |
for my $m (@{$options->{maintainers}}) {
|
|
Michal Marek |
bed3c7 |
if ($self->exists("/group/$m")) {
|
|
Michal Marek |
bed3c7 |
$writer->emptyTag("group", groupid => $m,
|
|
Michal Marek |
bed3c7 |
role => "maintainer");
|
|
Michal Marek |
bed3c7 |
} elsif ($self->exists("/person/$m")) {
|
|
Michal Marek |
bed3c7 |
$writer->emptyTag("person", userid => $m,
|
|
Michal Marek |
bed3c7 |
role => "maintainer");
|
|
Michal Marek |
bed3c7 |
} else {
|
|
Michal Marek |
bed3c7 |
warn("User id $m does not exist at $self->{url}\n");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
if (!exists($options->{repos})) {
|
|
Michal Marek |
bed3c7 |
if (!exists($options->{base})) {
|
|
Michal Marek |
bed3c7 |
croak "Either 'base' or 'repos' must be specified";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$options->{repository} ||= "";
|
|
Michal Marek |
bed3c7 |
$options->{repos} = { $options->{repository} => $options->{base} };
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
my %seen_archs;
|
|
Michal Marek |
3b4784 |
my @qa_repos;
|
|
Michal Marek |
bed3c7 |
for my $repo (sort(keys(%{$options->{repos}}))) {
|
|
Michal Marek |
bed3c7 |
my $base = $options->{repos}{$repo};
|
|
Michal Marek |
bed3c7 |
my %repo_archs;
|
|
Michal Marek |
bed3c7 |
if ($repo eq "") {
|
|
Michal Marek |
bed3c7 |
# get all "default" repositories of a given project
|
|
Michal Marek |
bed3c7 |
%repo_archs = $self->get_repo_archs($base);
|
|
Michal Marek |
bed3c7 |
} else {
|
|
Michal Marek |
bed3c7 |
# get the "standard" repository of a given project
|
|
Michal Marek |
bed3c7 |
%repo_archs = $self->get_repo_archs($base, "standard");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
for my $r (sort(keys(%repo_archs))) {
|
|
Michal Marek |
3b4784 |
my $name = $repo ? $repo : $r;
|
|
Michal Marek |
3b4784 |
my @attrs = (name => $name);
|
|
Michal Marek |
2f6d58 |
if (!$options->{rebuild}) {
|
|
Michal Marek |
2f6d58 |
push(@attrs, rebuild => "local", block => "local");
|
|
Michal Marek |
2f6d58 |
}
|
|
Michal Marek |
3b4784 |
my @archs;
|
|
Michal Marek |
bed3c7 |
for my $arch (@{$repo_archs{$r}}) {
|
|
Michal Marek |
bed3c7 |
if ($options->{limit_archs} &&
|
|
Michal Marek |
bed3c7 |
!$limit_archs{$arch}) {
|
|
Michal Marek |
bed3c7 |
next;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
# only build each arch once
|
|
Michal Marek |
bed3c7 |
if ($seen_archs{$arch}) {
|
|
Michal Marek |
bed3c7 |
next;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$seen_archs{$arch} = 1;
|
|
Michal Marek |
3b4784 |
push(@archs, $arch);
|
|
Michal Marek |
3b4784 |
}
|
|
Michal Marek |
31029c |
if (!@archs) {
|
|
Michal Marek |
31029c |
# this repository is not needed
|
|
Michal Marek |
31029c |
next;
|
|
Michal Marek |
31029c |
}
|
|
Michal Marek |
3b4784 |
$writer->startTag("repository", @attrs);
|
|
Michal Marek |
3b4784 |
$writer->emptyTag("path", repository => $r,
|
|
Michal Marek |
3b4784 |
project => $base);
|
|
Michal Marek |
3b4784 |
for my $arch (@archs) {
|
|
Michal Marek |
bed3c7 |
$writer->dataElement("arch", $arch);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$writer->endTag("repository");
|
|
Michal Marek |
3b4784 |
if (!exists($options->{qa})) {
|
|
Michal Marek |
3b4784 |
next;
|
|
Michal Marek |
3b4784 |
}
|
|
Michal Marek |
3b4784 |
# For each regular repository foo, there is a
|
|
Michal Marek |
3b4784 |
# repository named QA_foo, building against foo
|
|
Michal Marek |
3b4784 |
my $qa_name = ($name eq "standard") ? "QA"
|
|
Michal Marek |
3b4784 |
: "QA_$name";
|
|
Michal Marek |
3b4784 |
$writer->startTag("repository", name => $qa_name);
|
|
Michal Marek |
3b4784 |
$writer->emptyTag("path", repository => $name,
|
|
Michal Marek |
bed3c7 |
project => $project);
|
|
Michal Marek |
3b4784 |
for my $arch (@archs) {
|
|
Michal Marek |
114d5b |
$writer->dataElement("arch", $arch);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
114d5b |
$writer->endTag("repository");
|
|
Michal Marek |
3b4784 |
push(@qa_repos, $qa_name);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
3b4784 |
for my $attr (qw(build publish debuginfo)) {
|
|
Michal Marek |
3b4784 |
$writer->startTag($attr);
|
|
Michal Marek |
3b4784 |
$writer->emptyTag($options->{$attr} ? "enable" : "disable");
|
|
Michal Marek |
3b4784 |
if ($attr =~ /^(publish|build)/) {
|
|
Michal Marek |
3b4784 |
for my $repo (@qa_repos) {
|
|
Michal Marek |
3b4784 |
$writer->emptyTag("disable", repository => $repo);
|
|
Michal Marek |
3b4784 |
}
|
|
Michal Marek |
3b4784 |
}
|
|
Michal Marek |
3b4784 |
$writer->endTag($attr);
|
|
Michal Marek |
3b4784 |
}
|
|
Michal Marek |
3b4784 |
|
|
Michal Marek |
bed3c7 |
$writer->endTag("project");
|
|
Michal Marek |
bed3c7 |
$writer->end();
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$self->put("/source/$project/_meta?force=1", $meta);
|
|
Michal Marek |
bed3c7 |
my $prjconf = "";
|
|
Michal Marek |
bed3c7 |
if ($options->{prjconf}) {
|
|
Michal Marek |
bed3c7 |
$prjconf .= $options->{prjconf};
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
for my $package (@{$options->{remove_packages} || []}) {
|
|
Michal Marek |
bed3c7 |
# OBS idiom: substitute the package by an empty set
|
|
Michal Marek |
bed3c7 |
$prjconf .= "Substitute: $package\n";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
for my $package (@{$options->{add_packages} || []}) {
|
|
Michal Marek |
bed3c7 |
$prjconf .= "Support: $package\n";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$prjconf .= "Macros:\n";
|
|
Michal Marek |
bed3c7 |
for my $macro (@{$options->{macros} || []}) {
|
|
Michal Marek |
bed3c7 |
$prjconf .= "$macro\n";
|
|
Michal Marek |
bed3c7 |
}
|
|
Olaf Hering |
965157 |
$prjconf .= ":Macros\n";
|
|
Michal Marek |
bed3c7 |
$self->put("/source/$project/_config", $prjconf);
|
|
Michal Marek |
3b4784 |
return { name => $project, qa_repos => \@qa_repos };
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub create_package {
|
|
Michal Marek |
3b4784 |
my ($self, $prj, $package, $title, $description) = @_;
|
|
Michal Marek |
bed3c7 |
$title ||= $package;
|
|
Michal Marek |
bed3c7 |
$description ||= "";
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $meta;
|
|
Michal Marek |
bed3c7 |
my $writer = XML::Writer->new(OUTPUT => \$meta);
|
|
Michal Marek |
3b4784 |
$writer->startTag("package", project => $prj->{name}, name => $package);
|
|
Michal Marek |
bed3c7 |
$writer->dataElement("title", $title);
|
|
Michal Marek |
bed3c7 |
$writer->dataElement("description", $description);
|
|
Michal Marek |
bed3c7 |
# XXX: HACK
|
|
Michal Marek |
a200b4 |
if ($package =~ /^kernel-obs-(qa|build)/) {
|
|
Michal Marek |
bed3c7 |
$writer->startTag("build");
|
|
Michal Marek |
bed3c7 |
$writer->emptyTag("disable");
|
|
Michal Marek |
3b4784 |
for my $repo (@{$prj->{qa_repos} || []}) {
|
|
Michal Marek |
3b4784 |
$writer->emptyTag("enable", repository => $repo);
|
|
Michal Marek |
3b4784 |
}
|
|
Michal Marek |
bed3c7 |
$writer->endTag("build");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$writer->endTag("package");
|
|
Michal Marek |
bed3c7 |
$writer->end();
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
3b4784 |
$self->put("/source/$prj->{name}/$package/_meta", $meta);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
# Get a list of links to this package within the same project
|
|
Michal Marek |
bed3c7 |
sub local_links {
|
|
Michal Marek |
bed3c7 |
my ($self, $project, $package) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $xml = $self->post("/source/$project/$package?cmd=showlinked");
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $handle_start = sub {
|
|
Michal Marek |
bed3c7 |
my ($self, $element, %attr) = @_;
|
|
Michal Marek |
bed3c7 |
return unless $element eq "package";
|
|
Michal Marek |
bed3c7 |
return unless exists($attr{project}) && exists($attr{name});
|
|
Michal Marek |
bed3c7 |
if ($attr{project} eq $project && $attr{name} ne $package) {
|
|
Michal Marek |
bed3c7 |
push(@{$self->{res}}, $attr{name});
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $p = XML::Parser->new(Handlers => {Start => $handle_start});
|
|
Michal Marek |
bed3c7 |
$p->{res} = [];
|
|
Michal Marek |
bed3c7 |
$p->parse($xml);
|
|
Michal Marek |
bed3c7 |
return @{$p->{res}};
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub get_directory_revision {
|
|
Michal Marek |
bed3c7 |
my ($self, $xml) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $handle_start = sub {
|
|
Michal Marek |
bed3c7 |
my ($self, $element, %attr) = @_;
|
|
Michal Marek |
bed3c7 |
return unless $element eq "directory";
|
|
Michal Marek |
bed3c7 |
$self->{res}[0] = $attr{rev};
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
my $p = XML::Parser->new(Handlers => {Start => $handle_start});
|
|
Michal Marek |
bed3c7 |
$p->{res} = [];
|
|
Michal Marek |
bed3c7 |
$p->parse($xml);
|
|
Michal Marek |
bed3c7 |
return $p->{res}[0];
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub upload_package {
|
|
Michal Marek |
3b4784 |
my ($self, $dir, $prj, $package, $commit, $options) = @_;
|
|
Michal Marek |
bed3c7 |
$options ||= {};
|
|
Michal Marek |
bed3c7 |
my $progresscb = $options->{progresscb} || sub { };
|
|
Michal Marek |
7f1a60 |
my $no_init = $options->{no_init};
|
|
Michal Marek |
bed3c7 |
my $remove_packages = $options->{remove_packages} || [];
|
|
Michal Marek |
bed3c7 |
my %remove_packages = map { $_ => 1 } @$remove_packages;
|
|
Michal Marek |
578383 |
my $limit_packages = $options->{limit_packages} || [];
|
|
Michal Marek |
578383 |
my %limit_packages = map { $_ => 1 } @$limit_packages;
|
|
Michal Marek |
578383 |
my $do_limit_packages = (scalar(@$limit_packages) > 0);
|
|
Michal Marek |
9e95b2 |
my $extra_links = $options->{extra_links} || [];
|
|
Michal Marek |
9e95b2 |
my %specfiles = map { $_ => 1 } @$extra_links;
|
|
Michal Marek |
bed3c7 |
my $revision;
|
|
Michal Marek |
3b4784 |
if (!ref($prj)) {
|
|
Michal Marek |
3b4784 |
$prj = { name => $prj };
|
|
Michal Marek |
3b4784 |
}
|
|
Michal Marek |
3b4784 |
my $project = $prj->{name};
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
if (!$self->project_exists($project)) {
|
|
Michal Marek |
bed3c7 |
die "Project $project does not exist\n";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
7f1a60 |
if (!$no_init) {
|
|
Michal Marek |
7f1a60 |
$self->create_package($prj, $package);
|
|
Michal Marek |
7f1a60 |
&$progresscb('CREATE', "$project/$package");
|
|
Michal Marek |
7f1a60 |
}
|
|
Michal Marek |
bed3c7 |
opendir(my $dh, $dir) or die "$dir: $!\n";
|
|
Michal Marek |
bed3c7 |
my $remote = $self->readdir("/source/$project/$package");
|
|
Michal Marek |
bed3c7 |
my $new_filelist = "";
|
|
Michal Marek |
bed3c7 |
my $filelist_writer = XML::Writer->new(OUTPUT => \$new_filelist);
|
|
Michal Marek |
bed3c7 |
$filelist_writer->startTag("directory");
|
|
Michal Marek |
bed3c7 |
my $changed = 0;
|
|
Michal Marek |
bed3c7 |
while ((my $name = CORE::readdir($dh))) {
|
|
Michal Marek |
bed3c7 |
my $local_path = "$dir/$name";
|
|
Michal Marek |
bed3c7 |
my $remote_path = "/source/$project/$package/$name?rev=repository";
|
|
Michal Marek |
bed3c7 |
next if $name =~ /^\./;
|
|
Michal Marek |
bed3c7 |
next if ! -f $local_path;
|
|
Michal Marek |
bed3c7 |
open(my $fh, '<', "$dir/$name") or die "$dir/$name: $!\n";
|
|
Michal Marek |
bed3c7 |
my $md5 = Digest::MD5->new->addfile($fh)->hexdigest;
|
|
Michal Marek |
bed3c7 |
$filelist_writer->emptyTag("entry", name => $name, md5 => $md5);
|
|
Michal Marek |
bed3c7 |
if (!$remote->{$name} || $md5 ne $remote->{$name}->{md5}) {
|
|
Michal Marek |
bed3c7 |
$self->put_file($local_path, $remote_path);
|
|
Michal Marek |
bed3c7 |
&$progresscb('PUT', $name);
|
|
Michal Marek |
bed3c7 |
$changed = 1;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
if ($remote->{$name}) {
|
|
Michal Marek |
bed3c7 |
delete $remote->{$name};
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
if ($name =~ /(.*)\.spec$/) {
|
|
Michal Marek |
bed3c7 |
if ($1 ne $package) {
|
|
Michal Marek |
bed3c7 |
$specfiles{$1} = 1;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
closedir($dh);
|
|
Michal Marek |
bed3c7 |
for my $name (keys(%$remote)) {
|
|
Michal Marek |
bed3c7 |
$self->delete("/source/$project/$package/$name");
|
|
Michal Marek |
bed3c7 |
&$progresscb('DELETE', $name);
|
|
Michal Marek |
bed3c7 |
$changed = 1;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
$filelist_writer->endTag("directory");
|
|
Michal Marek |
bed3c7 |
$filelist_writer->end();
|
|
Michal Marek |
bed3c7 |
if ($changed) {
|
|
Michal Marek |
bed3c7 |
my $xml = $self->post("/source/$project/$package?comment=$commit&cmd=commitfilelist", $new_filelist);
|
|
Michal Marek |
bed3c7 |
$revision = $self->get_directory_revision($xml);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
7f1a60 |
if ($no_init) {
|
|
Michal Marek |
7f1a60 |
return $revision;
|
|
Michal Marek |
7f1a60 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
# Create links for all specfiles in this package
|
|
Michal Marek |
bed3c7 |
my %links = map { $_ => 1 } $self->local_links($project, $package);
|
|
Michal Marek |
bed3c7 |
my $link_xml;
|
|
Michal Marek |
bed3c7 |
my $writer = XML::Writer->new(OUTPUT => \$link_xml);
|
|
Michal Marek |
bed3c7 |
$writer->emptyTag("link", project => $project, package => $package,
|
|
Michal Marek |
bed3c7 |
cicount => "copy");
|
|
Michal Marek |
bed3c7 |
$writer->end();
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
for my $spec (keys(%specfiles)) {
|
|
Michal Marek |
bed3c7 |
next if $remove_packages{$spec};
|
|
Michal Marek |
578383 |
next if $do_limit_packages && !$limit_packages{$spec};
|
|
Michal Marek |
3b4784 |
$self->create_package($prj, $spec);
|
|
Michal Marek |
bed3c7 |
$self->put("/source/$project/$spec/_link", $link_xml);
|
|
Michal Marek |
bed3c7 |
&$progresscb('LINK', "$project/$spec");
|
|
Michal Marek |
bed3c7 |
delete($links{$spec});
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
# delete stale links
|
|
Michal Marek |
bed3c7 |
for my $link (keys(%links)) {
|
|
Michal Marek |
bed3c7 |
$self->delete("/source/$project/$link");
|
|
Michal Marek |
bed3c7 |
&$progresscb('DELETE', "$project/$link");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Suchanek |
c5a310 |
# delete stale kernel-obs-build
|
|
Michal Suchanek |
c5a310 |
my $kob = "kernel-obs-build";
|
|
Michal Suchanek |
c5a310 |
$self->post("/build/$project?cmd=wipe&package=$kob");
|
|
Michal Suchanek |
c5a310 |
&$progresscb('WIPE', "$project $kob");
|
|
Michal Marek |
bed3c7 |
return $revision;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub submit_package {
|
|
Michal Marek |
bed3c7 |
my ($self, $project, $package, $revision, $target, $comment) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $request;
|
|
Michal Marek |
bed3c7 |
my $writer = XML::Writer->new(OUTPUT => \$request);
|
|
Michal Marek |
bed3c7 |
$writer->startTag("request", type => "submit");
|
|
Michal Marek |
bed3c7 |
$writer->startTag("submit");
|
|
Michal Marek |
bed3c7 |
$writer->emptyTag("source",
|
|
Michal Marek |
bed3c7 |
project => $project, package => $package,
|
|
Michal Marek |
bed3c7 |
rev => $revision);
|
|
Michal Marek |
bed3c7 |
$writer->emptyTag("target",
|
|
Michal Marek |
bed3c7 |
project => $target, package => $package);
|
|
Michal Marek |
bed3c7 |
$writer->endTag("submit");
|
|
Michal Marek |
bed3c7 |
$writer->emptyTag("state", name => "new");
|
|
Michal Marek |
bed3c7 |
$writer->dataElement("description", $comment);
|
|
Michal Marek |
bed3c7 |
$writer->endTag("request");
|
|
Michal Marek |
bed3c7 |
$writer->end();
|
|
Michal Marek |
bed3c7 |
$self->post("/request?cmd=create", $request);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub get_logfile {
|
|
Michal Marek |
bed3c7 |
my ($self, $project, $package, $repository, $arch) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
$repository ||= "standard";
|
|
Michal Marek |
bed3c7 |
return $self->get("/build/$project/$repository/$arch/$package/_log?nostream=1");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
7a4e6f |
sub get_make_stderr {
|
|
Michal Marek |
7a4e6f |
my ($self, $project, $package, $repository, $arch) = @_;
|
|
Michal Marek |
7a4e6f |
|
|
Michal Marek |
7a4e6f |
$repository ||= "standard";
|
|
Michal Marek |
7a4e6f |
return $self->get("/build/$project/$repository/$arch/$package/make-stderr.log");
|
|
Michal Marek |
7a4e6f |
}
|
|
Michal Marek |
7a4e6f |
|
|
Michal Marek |
7a4e6f |
|
|
Michal Marek |
bed3c7 |
sub get_kernel_commit {
|
|
Michal Marek |
bed3c7 |
my ($self, $project, $package, $revision) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my $content;
|
|
Michal Marek |
bed3c7 |
for my $file (qw(source-timestamp build-source-timestamp)) {
|
|
Michal Marek |
bed3c7 |
my $path = "/source/$project/$package/$file";
|
|
Michal Marek |
bed3c7 |
$path .= "?rev=$revision" if $revision;
|
|
Michal Marek |
bed3c7 |
eval {
|
|
Michal Marek |
bed3c7 |
$content = $self->get($path);
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
last unless $@;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
die "No timestamp file found in $project/$package\n" unless $content;
|
|
Michal Marek |
bed3c7 |
if ($content !~ /^GIT Revision: ([0-9a-f]+)$/m) {
|
|
Michal Marek |
bed3c7 |
die "Malformet timestamp file in $project/$package\n";
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
return $1;
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub get_results {
|
|
Michal Marek |
bed3c7 |
my ($self, $project, $repository, $arch) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
my @params;
|
|
Michal Marek |
bed3c7 |
push(@params, "repository=$repository") if $repository;
|
|
Michal Marek |
bed3c7 |
push(@params, "arch=$arch") if $arch;
|
|
Michal Marek |
bed3c7 |
my $xml = $self->get("/build/$project/_result?" . join("&", @params));
|
|
Michal Marek |
bed3c7 |
return SUSE::MyBS::Buildresults->new($xml);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub load_results {
|
|
Michal Marek |
bed3c7 |
my ($self, $file) = @_;
|
|
Michal Marek |
bed3c7 |
my $xml = "";
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
local $/ = undef;
|
|
Michal Marek |
bed3c7 |
if (open(my $fh, '<', $file)) {
|
|
Michal Marek |
bed3c7 |
$xml = <$fh>;
|
|
Michal Marek |
bed3c7 |
};
|
|
Michal Marek |
bed3c7 |
return SUSE::MyBS::Buildresults->new($xml);
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub list_projects {
|
|
Michal Marek |
bed3c7 |
my $self = shift;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
return keys(%{$self->readdir("/source")});
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
sub delete_project {
|
|
Michal Marek |
bed3c7 |
my ($self, $project) = @_;
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
return $self->delete("/source/$project?force=1");
|
|
Michal Marek |
bed3c7 |
}
|
|
Michal Marek |
bed3c7 |
|
|
Michal Marek |
bed3c7 |
1;
|