summaryrefslogtreecommitdiffstats
path: root/RPM4/bin/hrpmreb
diff options
context:
space:
mode:
Diffstat (limited to 'RPM4/bin/hrpmreb')
-rwxr-xr-xRPM4/bin/hrpmreb671
1 files changed, 671 insertions, 0 deletions
diff --git a/RPM4/bin/hrpmreb b/RPM4/bin/hrpmreb
new file mode 100755
index 0000000..a5ea8ce
--- /dev/null
+++ b/RPM4/bin/hrpmreb
@@ -0,0 +1,671 @@
+#!/usr/bin/perl
+
+##- Nanar <nanardon@mandrake.org>
+##-
+##- 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# $Id$
+
+use strict;
+use warnings;
+
+use Getopt::Long;
+use POSIX (qw/nice O_WRONLY O_CREAT O_APPEND/);
+my $ipcstat;
+
+if (($ARGV[0] || "") eq '--trap') {
+ shift @ARGV;
+ my $trap = shift(@ARGV) or die "No log file specified\n";
+ $0 = "hrpmreb [trapping]";
+ open (my $t, ">>", $trap) or exit(1);
+ printf $t "\n\nRunning: %s\n\n", join(" ", @ARGV);
+ my $cmd = join(" ", @ARGV);
+ open(my $htrap, '-|', "$cmd 2>&1") or do {
+ print $t "Can't run cmd $cmd: $!\n";
+ exit(1);
+ };
+ { $| = 1; my $oldfh = select($t); $| =1; select($oldfh); }
+
+ while(<$htrap>) {
+ print $_;
+ print $t $_;
+ }
+ close($t);
+ exit(!close($htrap));
+}
+
+if (($ARGV[0] || '') eq '--stat') {
+ require IPC::ShareLite;
+ foreach my $k (1000 .. 1020) {
+ $ipcstat = new IPC::ShareLite (
+ -key => $k,
+ -create => 'no',
+ -destroy => 'no',
+ ) or last;
+ $ipcstat->lock();
+ my @ipcs = map { pack("h*", $_) } split(/ /, $ipcstat->fetch());
+ printf "Building: %s for %ds\n", shift(@ipcs), time - shift(@ipcs);
+ $ipcstat->unlock();
+ show_stat(@ipcs);
+ }
+ exit(0);
+}
+
+=head1 NAME
+
+hrpmreb
+
+=head1 DESCRIPTION
+
+A very powerful rpm rebuilder using perl-Hdlist
+
+=head1 SYNOPSYS
+
+hrpmreb -m macros rpm.src.rpm
+
+=head1 OPTIONS
+
+=head2 -m|--macros macrosfile
+
+Read a rpm macros file and add it to rpm configuration.
+
+To read several macros files, use -m macro1 -m macro2 ...
+
+=head2 -D|--define "macro value"
+
+Add a new macro to rpm configuration:
+
+example: -D "_sourcedir /tmp"
+
+This option can be used several time.
+
+=head2 -b|--batch
+
+Rebuild rpms found in L<%bindir> instead of the one given on command line
+
+=head2 -v|--verbose LEVEL
+
+Set rpm verbosity level to LEVEL.
+
+LEVEL can be an integer value (0 to 8) or a string value like "ERR", "DEBUG" or "INFO".
+
+=head2 --noupload
+
+Don't upload rpm after build.
+
+This option has the same effect than defining L<%upload> to 0.
+
+=head2 --nochkbin
+
+Don't check if binary already exist
+
+This option has the same effect that defining L<%checkbinary> to 0.
+
+=head2 --noinstdep
+
+Don't install dependancies needed to build the rpm
+
+This option has the same effect than defining L<%installdep> to 0.
+
+=head2 --keepalllog
+
+Don't delete log if build was successful.
+
+This option has the same effect than defining L<%keepalllog> to 1.
+
+=head2 --nobuild
+
+Skip build (and upload) stage, usefull for testing
+
+=head2 --nosort
+
+Do not sort srpms by builddate.
+
+This option has the same effect than defining L<%sortbybuilddate> to 0.
+
+=head2 --livestat
+
+Enable livestat functionnalities, see L<%livestat>, L<--stat>.
+
+=head2 --stat
+
+Give the statistics of current hrpmreb running on the current computer if
+they has been started with livestat functionnality.
+
+=cut
+
+my (@define, @with, @without);
+
+GetOptions(
+ 'm|macros=s' => \my @macros,
+ 'D|define=s' => \@define,
+ 'b|batch' => \my $batch,
+ 'v|verbose=s' => \my $verbose,
+ 'nobuild' => \my $nobuild,
+ 'nosort' => sub { push @define, "sortbybuilddate 0"; },
+ 'noupload' => sub { push @define, "upload 0"; },
+ 'nochkbin' => sub { push @define, "checkbinary 0"; },
+ 'noinstdep' => sub { push @define, "installdep 0"; },
+ 'keepalllog' => sub { push @define, "keepalllog 1"; },
+ 'trap=s' => sub { die "--trap should be first arg and you don't have to use it...\n" },
+ 'livestat' => sub { push @define, "livestat 1"; },
+ 'with=s' => \@with,
+ 'without=s' => \@without,
+ 'nofork' => \my $nofork,
+ 'dump' => \my $dumpconfig,
+);
+
+push @define, "_with_$_ --with-$_" foreach (@with);
+push @define, "_without_$_ --without-$_" foreach (@without);
+
+=head1 MACROS
+
+=head2 %myself
+
+The program itself ($0)
+
+=head2 %checkbinary
+
+If set, check if binary does not exists in L<%bindir>
+
+=head2 %srcdir
+
+A list of path separated by ':' where src.rpm should be found
+
+=head2 %bindir
+
+A list of path separated by ':' where binary rpm should be found
+
+=head2 %installdep
+
+If set, try to install dependancies (see L<%installrpmcmd>)
+
+=head2 %installdepcmd
+
+The command to run to install dependancies (urpmi ...)
+
+=head2 %upload
+
+If set, run the L<%uploadcmd> command
+
+=head2 %uploadcmd
+
+The upload command to run to upload binary rpms
+
+=head2 %logdir
+
+Where logfile should be put
+
+=head2 %keepalllog
+
+Don't delete log even on build success
+
+=head2 %nice
+
+Renice the build process
+
+=head2 %createrpmsdir
+
+If set, it will try to create rpms build directory
+
+=head2 %sortbybuilddate
+
+If define, sort srpms by builddate before build
+
+=head2 %livestat
+
+if set, hrpmreb use IPC to store his status, then you'll be able
+to use hrpmreb --stat to immediatelly get status of the current build.
+
+=cut
+
+require Hdlist;
+Hdlist::setverbosity($verbose || "INFO");
+
+my $hlog = undef;
+
+Hdlist::setlogcallback(
+ sub {
+ my %arg = @_;
+ loging("%s", $arg{msg});
+ }
+);
+
+sub loging {
+ my ($fmt, @var) = @_;
+ printf STDERR $fmt, @var;
+ if ($hlog) {
+ printf $hlog $fmt, @var;
+ }
+}
+
+config_macros();
+
+if (Hdlist::expandnumeric("%livestat")) {
+ require IPC::ShareLite;
+ foreach my $k (1000 .. 1020) {
+ $ipcstat = new IPC::ShareLite (
+ -key => $k,
+ -create => 'yes',
+ -destroy => 'no',
+ -mode => 0644,
+ ) and last;
+ }
+ $ipcstat or die "no IPC availlable\n";
+}
+
+my %status = (
+ srpmdone => 0,
+ srpmfailure => 0,
+ srpmtotal => 0,
+ steptime => time,
+ currentsrpms => 'Preparing build',
+ currentstep => '',
+);
+
+my $passphrase = Hdlist::expand('%{?gpgpass}');
+
+my @srcdir = split(':', Hdlist::expand('%{?srcdir}'));
+print Hdlist::expand("Source dir: %{?srcdir}%{?!srcdir:(none)}\n") if ($batch);
+
+!@srcdir && $batch and die "No src dir, please define \%srcdir\n";
+
+my @bindir = split(':', Hdlist::expand('%{?bindir}'));
+if (Hdlist::expandnumeric('%checkbinary')) {
+ if (@bindir) {
+ print Hdlist::expand("Using binary dir: %{?bindir}%{?!bindir:(none)}\n");
+ } else {
+ die "No bin dir, please define \%bindir or unset \%checkbinary\n";
+ }
+}
+
+if ($dumpconfig) {
+ Hdlist::dumprc(\*STDOUT);
+ exit 0;
+}
+
+-d Hdlist::expand("%{?logdir}%{!?logdir:.}") or mkdir Hdlist::expand("%{?logdir}%{!?logdir:.}")
+ or die "Can't create logdir ". Hdlist::expand("%{?logdir}%{!?logdir:.}") . " $!\n";
+
+if (Hdlist::expandnumeric('%createrpmsdir')) {
+ foreach my $macro (qw(%_topdir %_sourcedir %_builddir %_srpmdir %_rpmdir %_rpmdir/noarch %_rpmdir/%_target_cpu %_specdir %_tmppath)) {
+ -d Hdlist::expand($macro) or mkdir Hdlist::expand($macro)
+ or die "Can't create dir " . Hdlist::expand($macro) . "($macro): $!";
+ }
+}
+
+set_ipc_status(currentstep => "searching srpms");
+
+my @srpmstobuild;
+my @specstobuild;
+
+if($batch) {
+ @srpmstobuild = map { glob("$_/*.src.rpm") } @srcdir;
+}
+
+foreach my $arg (@ARGV) {
+ -f $arg or do {
+ push(@srpmstobuild, map { glob("$_/$arg") } @srcdir);
+ next;
+ };
+ if ($arg =~ /\.src\.rpm$/) {
+ push @srpmstobuild, $arg;
+ } else {
+ push @specstobuild, $arg;
+ };
+}
+
+$status{srpmtotal} = scalar(@srpmstobuild) + scalar(@specstobuild);
+
+if (! $status{srpmtotal}) {
+ die sprintf("Nothing to do, %s\n", $batch ? "check \%srcdir value" : "give src.rpm too rebuild or use -b");
+}
+
+if (Hdlist::expandnumeric("%sortbybuilddate")) {
+ loging("Sorting srpms by buildate\n");
+ set_ipc_status(currentstep => "sorting srpms");
+ @srpmstobuild = sort_srpms(@srpmstobuild);
+}
+
+# readjusting
+$status{srpmtotal} = scalar(@srpmstobuild) + scalar(@specstobuild);
+
+foreach my $specfile (@specstobuild) {
+ my $pid = fork();
+
+ if ($pid) {
+ parent_wait_child($pid);
+ $? and $status{srpmfailure}++;
+
+ show_stat($status{srpmtotal}, ++$status{srpmdone}, $status{srpmfailure});
+
+ config_macros();
+ } else {
+ my $oldcmd = Hdlist::expand("%___build_cmd");
+ Hdlist::add_macro("___build_cmd %myself --trap %_tmppath/%name-%version-%release.build.log $oldcmd");
+ exit(build_specfile($specfile));
+ }
+}
+
+foreach my $srpm (@srpmstobuild) {
+ my $pid = fork();
+
+ if ($pid) {
+ parent_wait_child($pid);
+ $? and $status{srpmfailure}++;
+
+ show_stat($status{srpmtotal}, ++$status{srpmdone}, $status{srpmfailure});
+
+ config_macros();
+ } else {
+ my $oldcmd = Hdlist::expand("%___build_cmd");
+ Hdlist::add_macro("___build_cmd %myself --trap %_tmppath/%name-%version-%release.build.log $oldcmd");
+ exit(build_srcrpm($srpm));
+ }
+}
+
+sub parent_wait_child {
+ my ($pid) = @_;
+ my $subdie = sub {
+ kill 15, $pid;
+ waitpid $pid, 0;
+ exit(1);
+ };
+ local $SIG{'TERM'} = $subdie;
+ local $SIG{'INT'} = $subdie;
+ waitpid $pid, 0;
+}
+
+sub show_advance {
+ my ($end, $total, $done) = @_;
+ printf(" %5d / %5d [%-50s] %3d %%%s", $done, $total,
+ '#' x ($total ? ($done * 50 / $total) : 0),
+ ($total ? ($done * 100 / $total) : 0), $end);
+}
+
+sub show_stat {
+ my ($total, $done, $failure) = @_;
+ print "\nDone:\n";
+ show_advance("\n", $total, $done);
+ print "Failed:\n";
+ show_advance("\n\n", $done, $failure);
+}
+
+sub set_ipc_status {
+ my (%val) = @_;
+ foreach (keys %val) {
+ $status{$_} = $val{$_};
+ /currentsrpms/ and do {
+ $status{steptime} = time;
+ $status{currentstep} = '';
+ };
+ }
+ $ipcstat or return;
+ $ipcstat->lock();
+ $ipcstat->store(sprintf(
+ "%s %s %s %s %s",
+ unpack("h*", "$status{currentsrpms} ($status{currentstep})"),
+ unpack("h*", $status{steptime}),
+ unpack("h*", $status{srpmtotal}), unpack("h*", $status{srpmdone}), unpack("h*", $status{srpmfailure})
+ ));
+ $ipcstat->unlock();
+}
+
+sub sort_srpms {
+ my %s;
+ my $db = Hdlist::newdb();
+ $db->vsflags([ qw(NOSIGNATURES NOPAYLOAD NODIGESTS) ]);
+ my $done = 0;
+ my @specs;
+ foreach my $src (@_) {
+ my $h = $db->rpm2header($src) or next;
+ $s{$src} = $h->tag("BUILDTIME") || 0;
+ show_advance("\r", scalar(@_), ++$done);
+
+ }
+ print "\n";
+ return sort { $s{$a} <=> $s{$b} } keys %s;
+}
+
+sub config_macros {
+ Hdlist::resetmacros();
+
+ Hdlist::add_macro("logfileformat %name.log");
+
+ Hdlist::readconfig();
+
+ Hdlist::loadmacrosfile($_) foreach (@macros);
+ Hdlist::add_macro($_) foreach(@define);
+
+ Hdlist::add_macro("myself $0");
+}
+
+sub checkbinary {
+ my ($spec) = @_;
+ Hdlist::expandnumeric('%checkbinary') or return 1;
+ my $missing = 0;
+ my @bin = $spec->binrpm();
+ foreach my $r (@bin) {
+ $r =~ s!^.*/!!;
+ my @rfake;
+ if (my ($rp) = $r =~ /^(.*)(?:amd64|x86_64)\.rpm/) {
+ push @rfake, $rp."x86_64.rpm", $rp."amd64.rpm";
+ } else {
+ push @rfake, $r;
+ }
+ my $ok = 0;
+ foreach my $rp (@rfake) {
+ if (grep { -f "$_/$rp" } @bindir) {
+ loging("$rp found\n");
+ $ok = 1;
+ last;
+ }
+ }
+ if (!$ok) {
+ loging("$r not found (need build)\n");
+ $missing++;
+ }
+ }
+ return 0 if ($missing == 0);
+ return Hdlist::expandnumeric('%checkbinary') <= ($missing == scalar(@bin) ? 2 : 1);
+}
+
+sub build_srcrpm {
+ my ($srpm) = @_;
+ my ($specf, $cookies) = Hdlist::installsrpm($srpm) or return 1;
+ my $rc = 0;
+
+ my $spec;
+ if ($spec = Hdlist::specnew($specf, $passphrase, "/", $cookies, 0, 0)) {
+ open($hlog, ">", Hdlist::expand('%{?logdir:%{logdir}/}%{logfileformat}'));
+ $0 = Hdlist::expand("hrpmreb [%name-%version-%release]");
+ set_ipc_status(currentsrpms => Hdlist::expand("%name-%version-%release"));
+ $SIG{'TERM'} = sub {
+ $spec && $spec->build(["RMSOURCE", "RMSPEC", "RMBUILD"]);
+ $spec && $spec->build(["CLEAN"]);
+ };
+
+ if (checkbinary($spec)) {
+ $rc = build_spec($spec, $srpm);
+ upload_build($spec, 0) unless($rc);
+ } else {
+ loging("Found binary, skipping build\n");
+ }
+
+ if ($rc || Hdlist::expandnumeric('%keepalllog')) {
+ if (open(my $buildlog, "<", Hdlist::expand("%_tmppath/%name-%version-%release.build.log"))) {
+ while (<$buildlog>) {
+ print $hlog $_;
+ }
+ close($buildlog);
+ }
+ } else {
+ unlink(Hdlist::expand("\%{?logdir:%{logdir}/}%{logfileformat}"));
+ }
+
+ close($hlog); $hlog = undef;
+ } else {
+ $rc = 1;
+ }
+
+ $spec ||= Hdlist::specnew($specf, $passphrase, "/", $cookies, 1, 1);
+
+ if ($spec) {
+ set_ipc_status(currentstep => "cleaning");
+ loging("cleaning sources, spec\n");
+ $spec && $spec->build(["RMSOURCE", "RMSPEC", "RMBUILD"]);
+ }
+
+ unlink(Hdlist::expand("%_tmppath/%name-%version-%release.build.log"));
+ return $rc;
+}
+
+sub build_specfile {
+ my ($specf) = @_;
+ my $rc = 0;
+
+ my $spec;
+ if ($spec = Hdlist::specnew($specf, $passphrase, "/", undef, 0, 0)) {
+ open($hlog, ">", Hdlist::expand('%{?logdir:%{logdir}/}%{logfileformat}'));
+ $0 = Hdlist::expand("hrpmreb [%name-%version-%release]");
+ set_ipc_status(currentsrpms => Hdlist::expand("%name-%version-%release"));
+ $SIG{'TERM'} = sub {
+ $spec && $spec->build(["RMBUILD"]);
+ };
+
+ $spec->build(["PACKAGESOURCE"]);
+ my $srpm = $spec->srcrpm();
+
+ if (checkbinary($spec)) {
+ $rc = build_spec($spec, $srpm);
+ upload_build($spec, 1) unless($rc);
+ } else {
+ loging("Found binary, skipping build\n");
+ }
+
+ if ($rc || Hdlist::expandnumeric('%keepalllog')) {
+ if (open(my $buildlog, "<", Hdlist::expand("%_tmppath/%name-%version-%release.build.log"))) {
+ while (<$buildlog>) {
+ print $hlog $_;
+ }
+ close($buildlog);
+ }
+ } else {
+ unlink(Hdlist::expand("\%{?logdir:%{logdir}/}%{logfileformat}"));
+ }
+
+ close($hlog); $hlog = undef;
+ } else {
+ $rc = 1;
+ }
+
+ $spec ||= Hdlist::specnew($specf, $passphrase, "/", undef, 1, 1);
+
+ if ($spec) {
+ set_ipc_status(currentstep => "cleaning");
+ loging("cleaning sources, spec\n");
+ $spec && $spec->build(["RMBUILD"]);
+ }
+
+ unlink(Hdlist::expand("%_tmppath/%name-%version-%release.build.log"));
+ return $rc;
+}
+
+
+sub build_spec {
+ my ($spec, $srpm) = @_;
+ my ($rc, $starttime, $chkdeptime, $installdeptime, $uploadtime, $buildtime, $endtime) = (0);
+
+ $starttime = time;
+
+ if (Hdlist::expandnumeric('%installdep') && $srpm) {
+ set_ipc_status(currentstep => "installing dep");
+ runmacro("%installdepcmd", $srpm);
+ $installdeptime = time;
+ }
+
+ nice(Hdlist::expand("%{?nice}")) if (Hdlist::expandnumeric("%{?nice:1}"));
+ set_ipc_status(currentstep => "checking dep");
+ my @pb;
+ {
+ my $db = Hdlist::newdb();
+ my $sh = $spec->srcheader();
+
+ $db->transadd($sh, "", 0);
+ $db->transcheck;
+ @pb = $db->transpb();
+ }
+ $chkdeptime = time;
+
+ if (@pb) {
+ loging("\nMissing dependancies:\n");
+ loging("$_\n") foreach(Hdlist::format_rpmpb(@pb));
+ $rc = 1;
+ } elsif(! $nobuild) {
+ set_ipc_status(currentstep => "compiling");
+ $rc = $spec->build([ qw/PREP BUILD INSTALL CHECK FILECHECK PACKAGEBINARY/ ]);
+ $spec->build([ qw/CLEAN/ ]);
+ $buildtime = time;
+ }
+ $endtime = time;
+
+ loging("\nBuild time in sec:\n");
+ loging("%20s %5s\n", 'installdepcmd: ', defined($installdeptime) ? $installdeptime - $starttime : "N/A");
+ loging("%20s %5s\n", 'check dep: ', $chkdeptime - ($installdeptime || $starttime));
+ loging("%20s %5s\n", 'build: ', defined($buildtime) ? $buildtime - $chkdeptime : "N/A");
+ loging("%20s %5s\n", 'Total: ', $endtime - $starttime);
+
+ loging("Build exit code: $rc\n");
+
+ return $rc;
+}
+
+sub upload_build {
+ my ($spec, $uploadsrc) = @_;
+ my @buildrpms = $spec->binrpm;
+ unshift @buildrpms, $spec->srcrpm if($uploadsrc);
+
+ my $noexist = 0;
+ foreach (@buildrpms) {
+ if(-f $_) {
+ loging("%s has been built\n", $_);
+ } else {
+ loging("%s has not been built\n", $_);
+ $noexist++;
+ }
+ }
+ $noexist and return 1;
+ if (Hdlist::expandnumeric('%upload')) {
+ set_ipc_status(currentstep => "uploading");
+ !runmacro("%uploadcmd", @buildrpms) and unlink @buildrpms;
+ }
+ return 0;
+}
+
+sub runmacro {
+ my ($macro, @args) = @_;
+ my $cmd = Hdlist::expand($macro. " " . join(' ', @args));
+ $cmd =~ /^\Q$macro/ and return 1;
+ loging("Executing(%%%s) %s\n", $macro, $cmd);
+ system($cmd)
+}
+
+__END__
+
+=head1 AUTHOR
+
+Olivier Thauvin <nanardon@mandrake.org>
+
+=cut