Blob Blame History Raw
#!/usr/bin/perl

use strict;
use warnings;

my $USAGE = "Usage: $0 <local package> <project> [<package>]\n";

BEGIN {
	(my $path = $0) =~ s/^(.*?)[^\/]*$/$1/;
	if ($path !~ /^\//) {
		$path = "$ENV{'PWD'}/$path";
	}
	push @INC, "${path}lib";
	$ENV{PATH} = "$ENV{PATH}:$path";
}

use Getopt::Long;
use SUSE::MyBS;


my $api;
my $verbose = 1;
my $no_init;
my $ignore_kabi;
my $debuginfo;
my $enable_checks;
my $rebuild;
my $submit;
my @maintainers;
my @limit_packages;
my @package_links;
GetOptions(
	"A|apiurl=s" => \$api,
	"i|ignore-kabi" => \$ignore_kabi,
	"no-init" => \$no_init,
	"c|enable-checks" => \$enable_checks,
	"d|debuginfo" => \$debuginfo,
	"r|rebuild" => \$rebuild,
	"s|submit" => \$submit,
	"maintainer=s" => \@maintainers,
	"flavor=s" => \@limit_packages,
	"q|quiet" => sub { $verbose = 0 },
	"v|verbose" => \$verbose,
	"h|help" => sub { print $USAGE; exit },
) or die($USAGE);

if (scalar(@ARGV) < 2 || @ARGV > 3 || !-d $ARGV[0]) {
	die($USAGE);
}
my ($dir, $project, $package) = @ARGV[0..2];
$project =~ s/\//:/g;
if (!$package) {
	($package = $dir) =~ s:/+\.?$::;
	$package =~ s@.*/@@;
	if (! -e "$dir/$package.spec") {
		opendir(my $dh, $dir) or die;
		my @specfiles = sort grep { /\.spec$/ } readdir($dh);
		if (!@specfiles) {
			die "No specfiles found in $dir and no package name specified\n";
		}
		closedir($dh);
		($package = $specfiles[0]) =~ s/\.spec//;
	}
}
if (@limit_packages) {
	s/^kernel-// for @limit_packages;
	s/^/kernel-/ for @limit_packages;
	push(@limit_packages, $package);
}
my ($branch, $commit) = get_git_info($dir);
if ($commit) {
	$commit = "commit $commit";
} else {
	print STDERR "warning: $dir does not look like a kernel package\n";
	$commit = ".";
}

my $bs = SUSE::MyBS->new($api);

# hack for SLE12-SP1-ARM
my $BS_SUFFIX;

my %repos = get_repos($dir, $api);
die "Project not specified in config.sh\n" unless exists $repos{""};
my $qa;
if (glob("$dir/kernel-obs-*.spec")) {
	$qa = 1;
}
my @archs = get_archs($dir);
if (!scalar(@archs)) {
	warn "No ExclusiveArch: headers in $dir/*.spec\n";
}
if (!@limit_packages && !$BS_SUFFIX) {
	# Include currently disabled flavors and archs
	my @all_archs;
	get_all_archs_flavors($dir, \@all_archs, \@package_links);
	push(@archs, @all_archs);
	s/^/kernel-/ for @package_links;
}

my @add_packages = ();
my @macros = ("%is_kotd 1");
if ($ignore_kabi) {
	push(@macros, "%ignore_kabi_badness 1");
}
if (-e "$dir/klp-symbols") {
	push(@macros, "%klp_symbols 1");
}
my @remove_packages = qw(kernel-dummy);
if (!$enable_checks) {
	push(@remove_packages, "post-build-checks", "rpmlint-Factory",
		"post-build-checks-malwarescan");
}
my $prjconf = "";
if (!-e "$dir/_constraints") {
	my $need_gb = $debuginfo ? 14 : 4;
	my $need_gb_2 = $need_gb / 2;
	$prjconf =
"\%ifarch \%ix86 x86_64
Constraint: hardware:processors 8
\%endif
\%ifarch \%ix86 x86_64 ia64 ppc ppc64 ppc64le
Constraint: hardware:disk:size unit=G $need_gb
\%else
Constraint: hardware:disk:size unit=G $need_gb_2
\%endif
";
}

my $prj;
if ($no_init) {
	$prj = $project;
} else {
	$prj = $bs->create_project($project, {
		repos => \%repos,
		title => "Kernel builds for " . ($branch ? "branch $branch" : $commit),
		build => 1,
		publish => 1,
		qa => $qa,
		debuginfo => $debuginfo,
		remove_packages => \@remove_packages,
		add_packages => \@add_packages,
		prjconf => $prjconf,
		macros => \@macros,
		limit_archs => \@archs,
		maintainers => \@maintainers,
		rebuild => $rebuild,
	});
}

my $progress_cb;
if ($verbose) {
	$progress_cb = \&progress_verbose;
} else {
	$progress_cb = \&progress_silent;
}
my $rev = $bs->upload_package($dir, $prj, $package, $commit, {
		no_init => $no_init,
		progresscb => $progress_cb,
		remove_packages => [qw(kernel-dummy)],
		limit_packages => \@limit_packages,
		extra_links => \@package_links,
});
if ($submit) {
	if (!exists($repos{""})) {
		die "No default submit target found in config.sh\n";
	}
	if (!$rev) {
		exit 0;
	}
	&$progress_cb('SUBMIT', "$project/$package($rev)");
	$bs->submit_package($project, $package, $rev, $repos{""}, $commit);
}

exit 0;

sub progress_verbose {
	print join(" ", @_), "\n";
}

sub progress_silent {};

sub get_git_info {
	my $dir = shift;
	my $file = "$dir/source-timestamp";

	if (! -f $file) {
		$file = "$dir/build-source-timestamp"
	}
	if (! -f $file) {
		return;
	}
	open(my $fh, '<', $file) or die "$file: $!\n";
	my ($branch, $commit);
	while (<$fh>) {
		chomp;
		if (s/^GIT Revision: //) {
			$commit = $_;
		}
		if (s/^GIT Branch: //) {
			$branch = $_;
		}
	}
	close($fh);
	return ($branch, $commit);
}

sub get_repos {
	my ($dir, $api) = @_;
	my $file = "$dir/config.sh";
	my $want_ibs = ($api && $api =~ /\.suse\.de/);
	my (%obs, %ibs);

	open(my $fh, '<', $file) or die "$file: $!\n";
	while (<$fh>) {
		chomp;
		if (/^BS_SUFFIX=(.*)/) {
			$BS_SUFFIX = $1;
		}
		next unless /^(OBS|IBS)_PROJECT(_\w+)?=(.*)/;
		my ($api, $repo, $project) = ($1, $2, $3);
		next unless $project;
		$repo ||= "";
		$repo =~ s/^_//;
		if ($api eq "OBS") {
			$obs{$repo} = $project;
			if (!exists($ibs{$repo})) {
				$ibs{$repo} = "openSUSE.org:$project";
			}
		} else {
			$ibs{$repo} = $project;
		}
	}
	close($fh);
	return %ibs if $want_ibs;
	return %obs;
}

sub bs_arch {
	my @res;

	for my $a (@_) {
		if ($a =~ /^%?i.86$/) {
			push(@res, "i586");
		} elsif ($a =~ /^armv(\d)h?l/) {
			push (@res, "armv$1l", "armv$1hl");
		} elsif ($a eq "arm64") {
			push (@res, "aarch64");
		} else {
			push(@res, $a);
		}
	}
	return @res;
}

sub get_archs {
	my $dir = shift;
	my %archs;
	my %limit_specs;
	$limit_specs{"$_.spec"} = 1 for @limit_packages;

	opendir(my $dh, $dir) or return;
	while (my $de = readdir($dh)) {
		next unless $de =~ /\.spec$/;
		next unless !@limit_packages || $limit_specs{$de};
		my $f = "$dir/$de";
		my $fh;
		if (!open($fh, '<', "$f")) {
			warn "warning: could not open $f: $!\n";
			next;
		}
		while (<$fh>) {
			chomp;
			next unless s/^exclusivearch://i;
			$archs{$_} = 1 for bs_arch(split);
			last;
		}
		close($fh);
	}
	return sort(keys(%archs));
}

sub get_all_archs_flavors {
	my ($dir, $archs, $flavors) = @_;
	my (%archs, %flavors);
	my $pipe;

	return unless -e "$dir/config.conf";
	if (!open($pipe, '-|', "guards", "--list", "--config", "$dir/config.conf")) {
		warn "error running guards: $!\n";
		return;
	}
	while (<$pipe>) {
		chomp;
		my ($arch, $flavor) = split(/\//);
		$archs{$_} = 1 for bs_arch($arch);
		$flavors{$flavor} = 1;
	}
	if (!close($pipe)) {
		warn "guards returned an error\n";
	}
	@$archs = sort(keys(%archs));
	@$flavors = sort(keys(%flavors));
}