summaryrefslogtreecommitdiffstats
path: root/RPM4
diff options
context:
space:
mode:
Diffstat (limited to 'RPM4')
-rw-r--r--RPM4/MANIFEST58
-rw-r--r--RPM4/Makefile.PL36
-rw-r--r--RPM4/README10
-rwxr-xr-xRPM4/bin/hrpmreb671
-rwxr-xr-xRPM4/bin/rpm_produced77
-rwxr-xr-xRPM4/bin/rpmresign65
-rwxr-xr-xRPM4/bin/urpm_interactive149
-rwxr-xr-xRPM4/examples/checkhdr13
-rwxr-xr-xRPM4/examples/hbuildspec40
-rwxr-xr-xRPM4/examples/hdinfo31
-rwxr-xr-xRPM4/examples/hdlist2sdb68
-rwxr-xr-xRPM4/examples/hdlistq68
-rwxr-xr-xRPM4/examples/hdrpmq44
-rw-r--r--RPM4/examples/hinfo42
-rw-r--r--RPM4/examples/hrpmreb-macros31
-rwxr-xr-xRPM4/examples/rpminstall96
-rwxr-xr-xRPM4/examples/specwillbuild42
-rw-r--r--RPM4/lib/RPM4.pm422
-rw-r--r--RPM4/lib/RPM4/Header.pm335
-rw-r--r--RPM4/lib/RPM4/Header/Changelogs.pm73
-rw-r--r--RPM4/lib/RPM4/Header/Checks.pm98
-rw-r--r--RPM4/lib/RPM4/Header/Dependencies.pm118
-rw-r--r--RPM4/lib/RPM4/Header/Files.pm61
-rw-r--r--RPM4/lib/RPM4/Index.pm163
-rw-r--r--RPM4/lib/RPM4/Media.pm193
-rw-r--r--RPM4/lib/RPM4/Spec.pm195
-rw-r--r--RPM4/lib/RPM4/Transaction.pm195
-rw-r--r--RPM4/lib/RPM4/Transaction/Problems.pm115
-rw-r--r--RPM4/patches/Makefile.PL.staticrpm.patch17
-rw-r--r--RPM4/src/Makefile.PL48
-rw-r--r--RPM4/src/RPM4.h119
-rw-r--r--RPM4/src/RPM4.xs2832
-rw-r--r--RPM4/src/RPM4sign.c28
-rw-r--r--RPM4/src/typemap21
-rw-r--r--RPM4/t/01compile.t12
-rw-r--r--RPM4/t/02header.t78
-rwxr-xr-xRPM4/t/03rpmlib.t86
-rw-r--r--RPM4/t/04spec.t62
-rw-r--r--RPM4/t/05transaction.t147
-rw-r--r--RPM4/t/06sign.t33
-rw-r--r--RPM4/t/07changelogs.t18
-rw-r--r--RPM4/t/07dep.t97
-rw-r--r--RPM4/t/07files.t37
-rw-r--r--RPM4/t/09hdlist.t27
-rw-r--r--RPM4/t/11media.t11
-rw-r--r--RPM4/t/gnupg/passphrase6
-rw-r--r--RPM4/t/gnupg/pubring.gpgbin0 -> 1233 bytes
-rw-r--r--RPM4/t/gnupg/secring.gpgbin0 -> 1371 bytes
-rw-r--r--RPM4/t/gnupg/test-key.gpg26
-rw-r--r--RPM4/t/gnupg/trustdb.gpgbin0 -> 1320 bytes
-rw-r--r--RPM4/t/rpmmacros8
-rw-r--r--RPM4/t/rpmrc369
-rw-r--r--RPM4/t/test-dep-1.0-1mdk.noarch.rpmbin0 -> 2285 bytes
-rw-r--r--RPM4/t/test-dep-1.0-1mdk.src.rpmbin0 -> 2213 bytes
-rw-r--r--RPM4/t/test-dep.spec38
-rw-r--r--RPM4/t/test-rpm-1.0-1mdk.noarch.rpmbin0 -> 2036 bytes
-rw-r--r--RPM4/t/test-rpm-1.0-1mdk.src.rpmbin0 -> 2137 bytes
-rw-r--r--RPM4/t/test-rpm.spec35
58 files changed, 7664 insertions, 0 deletions
diff --git a/RPM4/MANIFEST b/RPM4/MANIFEST
new file mode 100644
index 0000000..9acee7e
--- /dev/null
+++ b/RPM4/MANIFEST
@@ -0,0 +1,58 @@
+MANIFEST
+Makefile.PL
+README
+ChangeLog
+src/Makefile.PL
+src/RPM4.h
+src/RPM4.xs
+src/RPM4sign.c
+src/constant.c
+src/rpmconstant.c
+src/rpmconstant.h
+src/rpmconstant_internal.c
+src/rpmh2tbl
+lib/RPM4.pm
+lib/RPM4/Index.pm
+lib/RPM4/Header.pm
+lib/RPM4/Header/Dependencies.pm
+lib/RPM4/Header/Files.pm
+lib/RPM4/Header/Changelogs.pm
+lib/RPM4/Transaction.pm
+lib/RPM4/Transaction/Problems.pm
+lib/RPM4/Spec.pm
+lib/RPM4/Media.pm
+t/test-rpm-1.0-1mdk.noarch.rpm
+t/test-rpm-1.0-1mdk.src.rpm
+t/test-rpm.spec
+t/test-dep-1.0-1mdk.noarch.rpm
+t/test-dep-1.0-1mdk.src.rpm
+t/test-dep.spec
+t/rpmmacros
+t/rpmrc
+src/typemap
+t/01compile.t
+t/02header.t
+t/03rpmlib.t
+t/04spec.t
+t/05transaction.t
+t/06sign.t
+t/07dep.t
+t/07files.t
+t/07changelogs.t
+t/09hdlist.t
+t/11media.t
+t/gnupg/passphrase
+t/gnupg/pubring.gpg
+t/gnupg/secring.gpg
+t/gnupg/trustdb.gpg
+t/gnupg/test-key.gpg
+bin/hrpmreb
+bin/rpm_produced
+bin/rpmresign
+examples/hdinfo
+examples/hdlistq
+examples/hdrpmq
+examples/specwillbuild
+examples/hdlist2sdb
+examples/hrpmreb-macros
+META.yml Module meta-data (added by MakeMaker)
diff --git a/RPM4/Makefile.PL b/RPM4/Makefile.PL
new file mode 100644
index 0000000..95d5d33
--- /dev/null
+++ b/RPM4/Makefile.PL
@@ -0,0 +1,36 @@
+# $Id$
+
+# use 5.008;
+use ExtUtils::MakeMaker;
+use Getopt::Long;
+
+#- require at least rpm 4.2
+my $rpm_version = `rpm --version`;
+$rpm_version =~ s/RPM version //;
+$rpm_version =~ /^(?:[5-9]|\d{2}|4\.[2-9])/
+ or die <<BARF;
+Unable to build Hdlist with too old (or undetected) rpm version $rpm_version
+BARF
+
+sub MY::postamble {
+ <<MAKECHANGELOG;
+.PHONY: ChangeLog
+
+ChangeLog:
+ svn update && svn log --verbose > \$@
+
+rpm: dist
+ rpm --rmsource --define "_sourcedir `pwd`" -ba perl-Hdlist.spec
+MAKECHANGELOG
+}
+
+WriteMakefile(
+ NAME => 'RPM4',
+ VERSION_FROM => 'lib/RPM4.pm',
+ DIR => [ 'src' ],
+ 'EXE_FILES' => [ qw(bin/rpm_produced bin/rpmresign bin/hrpmreb) ],
+ dist => {
+ COMPRESS => 'bzip2 --best',
+ SUFFIX => '.bz2',
+ },
+);
diff --git a/RPM4/README b/RPM4/README
new file mode 100644
index 0000000..df93b5d
--- /dev/null
+++ b/RPM4/README
@@ -0,0 +1,10 @@
+RPM4 v0.01
+============
+
+A module to manipulate hdlist and synthesis files.
+
+COPYRIGHT AND LICENCE
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
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
diff --git a/RPM4/bin/rpm_produced b/RPM4/bin/rpm_produced
new file mode 100755
index 0000000..e9fe67b
--- /dev/null
+++ b/RPM4/bin/rpm_produced
@@ -0,0 +1,77 @@
+#!/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 RPM4;
+use Getopt::Long;
+
+my ($showsrc, $tmp, @macros) = (1, $ENV{TMP} || '/tmp');
+
+GetOptions(
+ 'define=s' => \@macros,
+ 'src!' => \$showsrc,
+);
+
+(@ARGV) or die
+"$0 file1 [file2 [...]]
+Give rpms filename produce by a specfile or a src.rpm
+
+Options:
+ --define \"macro value\" define a macro into rpm land
+ --no-src do not show the src.rpm
+";
+
+Hdlist::add_macro("_sourcedir $tmp");
+Hdlist::add_macro("_specdir $tmp");
+
+sub set_config {
+ Hdlist::readconfig();
+ foreach (@macros) {
+ Hdlist::add_macro($_);
+ }
+}
+
+sub specquery {
+ my ($spec) = @_;
+ $showsrc and print $spec->srcrpm ."\n";
+ foreach my $bin ($spec->binrpm) {
+ print "$bin\n";
+ }
+}
+
+foreach my $file (@ARGV) {
+ set_config();
+ $file =~ m/\.src\.rpm$/ and do {
+ if(my ($specfile) = Hdlist::installsrpm($file)) {
+ if (my $spec = Hdlist::specnew($specfile, undef, undef, undef, 1, 1)) {
+ specquery($spec);
+ $spec->build([qw(RMSOURCE RMSPEC)]);
+ }
+ }
+ next;
+ };
+ $file =~ m/\.spec$/ and do {
+ if (my $spec = Hdlist::specnew($file, undef, undef, undef, 1, 1)) {
+ specquery($spec);
+ }
+ next;
+ }
+}
diff --git a/RPM4/bin/rpmresign b/RPM4/bin/rpmresign
new file mode 100755
index 0000000..4cce105
--- /dev/null
+++ b/RPM4/bin/rpmresign
@@ -0,0 +1,65 @@
+#!/usr/bin/perl
+
+##- 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 Hdlist::Sign;
+
+my ($configfile, $batch, $sigtype, $passfile, $macrofile, $fastmode, $path, $name, $keyid, $pass);
+my @defines;
+
+GetOptions(
+ 'p|path=s' => \$path,
+ 'n|name=s' => \$name,
+ 'c|config=s' => \$configfile,
+ 'b|batch' => \$batch,
+ 'd|define=s' => \@defines,
+ 'f|fastmode' => \$fastmode,
+ 'passwordfile|sig-pass-file=s' => \$passfile,
+ 'm|macros=s' => \$macrofile,
+);
+
+foreach (@defines) {
+ Hdlist::add_macro($_);
+}
+
+if (!$passfile) {
+ $pass = <STDIN>;
+ chomp($pass);
+}
+
+my $sign = Hdlist::Sign->new(
+ passphrase => $pass,
+ _signature => $sigtype,
+ path => $path,
+ name => $name,
+ checkrpms => $fastmode ? 0 : 1,
+ password_file => $passfile,
+);
+
+my @files;
+
+while (my $f = shift(@ARGV)) {
+ -d $f and do {
+ push(@files, glob("$f/*.rpm"));
+ next;
+ };
+ push(@files, $f);
+}
+
+$sign->rpmssign(@files);
diff --git a/RPM4/bin/urpm_interactive b/RPM4/bin/urpm_interactive
new file mode 100755
index 0000000..7756fea
--- /dev/null
+++ b/RPM4/bin/urpm_interactive
@@ -0,0 +1,149 @@
+#!/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 Hdlist::Media;
+use Hdlist::Media::Solve;
+use Term::ReadLine;
+use Text::ParseWords;
+use urpm;
+use Getopt::Long;
+
+#Hdlist::setverbosity('DEBUG');
+
+my $dbpath;
+
+GetOptions(
+ "dbpath=s" => \$dbpath,
+);
+
+
+Hdlist::add_macro("_dbpath $dbpath") if ($dbpath);
+
+my $s = Hdlist::Media::Solve->new(
+);
+
+{
+ my $u = urpm->new();
+ $u->read_config;
+ foreach my $m (@{$u->{media}}) {
+ $m->{virtual} or next;
+ my $dir = $m->{url};
+ $dir =~ s!file:/+!/!;
+ $s->addmedia(
+ Hdlist::Media->new(
+ hdlist => $m->{with_hdlist},
+ rpmsdir => $dir,
+ ),
+ );
+ }
+}
+
+$s->add_system_dep('REQUIRE', "basesystem");
+
+$s->load();
+
+my $term = new Term::ReadLine 'Hdlist';
+
+my $prompt = "urpm > ";
+
+while (defined (my $cmdline = $term->readline($prompt))) {
+ chomp($cmdline);
+ my $cmd; local @ARGV;
+ ($cmd, @ARGV) = &parse_line('\s+', 0, $cmdline);
+
+ $cmd or next;
+ $term->addhistory($cmdline);
+
+ $cmd =~ /^quit$/ and last;
+
+ $cmd =~ /^(q|query)$/ and do {
+ my $tag;
+ my $qf;
+ GetOptions(
+ "t|tag=s" => \$tag,
+ "qf|queryformat=s" => \$qf,
+ );
+ $s->traverse(db => 1, medium => undef, callback => sub {
+ my ($header, $id, $media) = @_;
+ print "$media: " . $header->queryformat($qf || $s->{short_fmt}) ."\n";
+ 1;
+ }, tag => $tag || ($ARGV[0] ? 'NAME' : ""), tagvalue => $ARGV[0]);
+ next;
+ };
+
+ $cmd =~ /^sysdep$/ and do {
+ my $tag = 'REQUIRE';
+ GetOptions(
+ 'c' => sub { $tag = 'CONFLICT'; },
+ );
+ $ARGV[0] or next;
+ $s->add_system_dep($tag, @ARGV);
+ next;
+ };
+
+ $cmd =~ /^(\+|add)$/ and do {
+ $s->find_and_add($ARGV[0]);
+ next;
+ };
+
+ $cmd =~ /^(-|remove)$/ and do {
+ $s->find_and_remove($ARGV[0]);
+ next;
+ };
+
+ $cmd =~ /^a(utoselect)?$/ and do {
+ $s->autoselect();
+ next;
+ };
+
+ $cmd =~ /^c(heck)?$/ and do {
+ $s->check();
+ next;
+ };
+
+ $cmd =~ /^r(un)?$/ and do {
+ $s->run();
+ next;
+ };
+
+ $cmd =~ /^l(ist)?$/ and do {
+ $s->list_trans();
+ next;
+ };
+
+ $cmd =~ /^d$/ and do {
+ $s->add_from_require(@ARGV);
+ next;
+ };
+
+ $cmd =~ /^clean$/ and do {
+ foreach (@ARGV) {
+ m/trans/ and $s->clean_trans();
+ m/request/ and $s->clean_request();
+ }
+ next;
+ };
+
+ print "unknow command '$cmd'\n";
+};
+
diff --git a/RPM4/examples/checkhdr b/RPM4/examples/checkhdr
new file mode 100755
index 0000000..c2006cb
--- /dev/null
+++ b/RPM4/examples/checkhdr
@@ -0,0 +1,13 @@
+#!/usr/bin/perl
+
+# $Id$
+
+use strict;
+use warnings;
+use RPM4;
+use RPM4::Header::Checks;
+
+foreach (@ARGV) {
+ my $h = rpm2header($_);
+ RPM4::Header::Checks::check($h);
+}
diff --git a/RPM4/examples/hbuildspec b/RPM4/examples/hbuildspec
new file mode 100755
index 0000000..d0204db
--- /dev/null
+++ b/RPM4/examples/hbuildspec
@@ -0,0 +1,40 @@
+#!/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 Hdlist;
+use Getopt::Long;
+
+(@ARGV) or die
+"$0 specfile1.spec [specfile2.spec [...]]
+Give rpms filename produce by a specfile
+";
+
+foreach (@ARGV) {
+ my $spec = Hdlist::specnew($_);
+ my @err = $spec->check();
+ if (@err) {
+ foreach (Hdlist::print_rpmpb(@err)) {
+ print "\t$_\n";
+ }
+ } else {
+
+ }
+}
diff --git a/RPM4/examples/hdinfo b/RPM4/examples/hdinfo
new file mode 100755
index 0000000..3d3de25
--- /dev/null
+++ b/RPM4/examples/hdinfo
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+##- trem <trem@zarb.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 Hdlist;
+
+my $arch = Hdlist::getarchname();
+print "arch = " . $arch . "\n";
+
+my $os = Hdlist::getosname();
+print "os = " . $os . "\n";
+
+my $host = Hdlist::buildhost();
+print "host = " . $host . "\n";
diff --git a/RPM4/examples/hdlist2sdb b/RPM4/examples/hdlist2sdb
new file mode 100755
index 0000000..e1fe387
--- /dev/null
+++ b/RPM4/examples/hdlist2sdb
@@ -0,0 +1,68 @@
+#!/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 Hdlist;
+use Getopt::Long;
+
+GetOptions (
+ 'dbpath=s' => \my $dbpath,
+ 'v' => \my $verbose,
+) && @ARGV or die "
+Usage $0 [--dbpath path] hdlist.cz [hdlist2.cz [...]]
+Synch rpm found into given hdlist into a database.
+Usefull to create a solve rpm database.
+";
+
+$dbpath ||= Hdlist::expand("%_solve_dbpath");
+
+Hdlist::add_macro("_dbpath $dbpath");
+
+my $db = Hdlist::newdb(1) or die "Can't open DB";
+
+my %rpmlist;
+my %indb;
+
+$db->traverse_headers( sub {
+ my ($hdr, $id) = @_;
+ $indb{$hdr->queryformat("%{PKGID}")} = 1;
+ });
+
+foreach my $arg (@ARGV) {
+ print "Reading $arg\n";
+ open(my $hdfh, "zcat '$arg' |") or die "Can't open $_";
+ while (my $hdr = stream2header($hdfh)) {
+ $rpmlist{$hdr->queryformat("%{PKGID}")} = 1;
+ defined($indb{$hdr->queryformat("%{PKGID}")}) and next;
+ print "Adding " . $hdr->queryformat("%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}") . "\n";
+ $db->injectheader($hdr);
+ }
+}
+
+my @id2remove;
+
+$db->traverse_headers( sub {
+ my ($hdr, $id) = @_;
+ defined($rpmlist{$hdr->queryformat("%{PKGID}")}) or push(@id2remove, $id);
+ });
+
+foreach (@id2remove) {
+ $db->deleteheader($_);
+}
diff --git a/RPM4/examples/hdlistq b/RPM4/examples/hdlistq
new file mode 100755
index 0000000..1e2489a
--- /dev/null
+++ b/RPM4/examples/hdlistq
@@ -0,0 +1,68 @@
+#!/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 Hdlist;
+use Getopt::Long;
+
+my $qf = "%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n";
+my $cond = undef;
+
+my $go_res = GetOptions (
+ "qf|queryformat=s" => \$qf,
+ "c|cond=s" => \$cond,
+ "qi" => sub {
+ $qf =
+'Name : %-27{NAME} Relocations: %|PREFIXES?{[%{PREFIXES} ]}:{(not relocatable)}|
+Version : %-27{VERSION} Vendor: %{VENDOR}
+Release : %-27{RELEASE} Build Date: %{BUILDTIME:date}
+Install Date: %|INSTALLTIME?{%-27{INSTALLTIME:date}}:{(not installed) }| Build Host: %{BUILDHOST}
+Group : %-27{GROUP} Source RPM: %{SOURCERPM}
+Size : %-27{SIZE}%|LICENSE?{ License: %{LICENSE}}|
+Signature : %|DSAHEADER?{%{DSAHEADER:pgpsig}}:{%|RSAHEADER?{%{RSAHEADER:pgpsig}}:{%|SIGGPG?{%{SIGGPG:pgpsig}}:{%|SIGPGP?{%{SIGPGP:pgpsig}}:{(none)}|}|}|}|
+%|PACKAGER?{Packager : %{PACKAGER}\n}|%|URL?{URL : %{URL}\n}|\Summary : %{SUMMARY}
+Description :\n%{DESCRIPTION}
+';
+ },
+);
+my ($type, $name, $flag, $ENV, $dep);
+if ($cond) {
+ my @d = split(/ +/, $cond);
+ $dep = Hdlist::newdep(@d);
+}
+
+($go_res && @ARGV) or die
+"$0 [--qf|--queryformat rpm_query] [--cond cond] hdlist.cz [hdlist2.cz [...]]
+Do something like `rpm -q --queryformat' on each header contains in hdlist archive
+--cond: show only rpm which apply to this condition:
+ R|C NAME [<=> VERSION], ex C rpm = 4.2.1 will show rpm providing rpm-4.2.1
+example: $0 --qf '%{NAME}\\n' hdlist.cz
+";
+
+foreach (@ARGV) {
+ open(my $hdfh, "zcat '$_' |") or die "Can't open $_";
+ while (my $hdr = stream2header($hdfh)) {
+ if ($cond) {
+ $hdr->matchdep($dep, "PROVIDE") or next;
+ }
+ print $hdr->queryformat($qf);
+ }
+ close($hdfh);
+}
diff --git a/RPM4/examples/hdrpmq b/RPM4/examples/hdrpmq
new file mode 100755
index 0000000..5d9c91e
--- /dev/null
+++ b/RPM4/examples/hdrpmq
@@ -0,0 +1,44 @@
+#!/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 Hdlist;
+use Getopt::Long;
+
+my $qf = "%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n";
+
+my $go_res = GetOptions (
+ "qf|queryformat=s" => \$qf,
+);
+
+($go_res && @ARGV) or die
+"$0 [--qf|--queryformat rpm_query] rpm1 [rpm2 [...]]
+Do something like `rpm -qp --queryformat' using perl-Hdlist
+example: $0 --qf '%{NAME}\\n' test-rpm-1.0-1mdk.noarch.rpm
+";
+
+foreach (@ARGV) {
+ my $hdr = rpm2header($_);
+ if ($hdr) {
+ print $hdr->queryformat($qf);
+ } else {
+ warn "Can't read $_\n";
+ }
+}
diff --git a/RPM4/examples/hinfo b/RPM4/examples/hinfo
new file mode 100644
index 0000000..29e1f77
--- /dev/null
+++ b/RPM4/examples/hinfo
@@ -0,0 +1,42 @@
+#!/usr/bin/perl
+
+##- trem <trem@zarb.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 Hdlist;
+
+(@ARGV) or die("$0 <rpmfilename>");
+
+foreach (@ARGV) {
+ my $header = rpm2header($_);
+ if($header) {
+ print "tag\tnom\t\texiste\tvaleur\n";
+ foreach ($header->listtag) {
+ print "$_\t" . Hdlist::tagName($_) . "\t\t";
+ my $e;
+ $e = $header->hastag("$_");
+ print "$e\t";
+ eval {
+ print $header->tag($_) if($e);
+ };
+ print "SOUCI: $@" if($@);
+ print "\n";
+ }
+ }
+}
diff --git a/RPM4/examples/hrpmreb-macros b/RPM4/examples/hrpmreb-macros
new file mode 100644
index 0000000..26346b5
--- /dev/null
+++ b/RPM4/examples/hrpmreb-macros
@@ -0,0 +1,31 @@
+# $id$
+
+%media contrib
+%basedistrib /home/root/mandrake/mdk/Mandrakelinux/
+
+# A way to install dependancies, with this you need a sudo
+%installdep 1
+%installdepcmd sudo -H /usr/sbin/urpmi --auto --no-verify-rpm
+
+# I have script to upload, made it
+%upload 0
+%uploadcmd /home/users/olivier/bin/upload -d %media
+
+# Where are source
+%srcdir %basedistrib/devel/cooker/SRPMS/%media
+
+# Where are binary
+%checkbinary 1
+%bindir %basedistrib/devel/cooker/%_target_cpu/media/%media
+
+# Where to put log
+%keepalllog 0
+%logdir ./%{_target_cpu}-%{media}-log
+
+# for speed up
+%_sourcedir /tmp/
+
+# If you want the build process to be niced
+# %nice 10
+
+%_signature %nil
diff --git a/RPM4/examples/rpminstall b/RPM4/examples/rpminstall
new file mode 100755
index 0000000..fef5caf
--- /dev/null
+++ b/RPM4/examples/rpminstall
@@ -0,0 +1,96 @@
+#!/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 Hdlist;
+use Getopt::Long qw(:config pass_through);
+
+sub help {
+ die "
+Usage $0 [options] [-i rpm_to_install.rpm] [-e rpm_name_to_remove]
+This script mimic a simple rpm programs for installing or removing packages
+options:
+ --dbpath path alternate path to rpmdb
+ --root root set rootdir for installation
+ --test only test, do not install pkg
+ --justdb only install package in the db, not on filesystem
+
+Notice it permit to install and to remove package in same time ! :)
+";
+}
+
+my (@rpmi, @rpme);
+my @installflags;
+my ($root, $dbpath) =
+ (undef, undef );
+
+GetOptions(
+ 'root=s' => \$root,
+ 'dbpath=s' => \$dbpath,
+ 'test' => sub { push(@installflags, 'TEST') },
+ 'justdb' => sub { push(@installflags, 'JUSTDB') },
+ 'h|help' => sub { help() },
+);
+
+{
+ my $install = 1;
+
+ while (my $arg = shift(@ARGV)) {
+ $arg =~ /^-i$/ and do {
+ $install = 1;
+ next;
+ };
+ $arg =~ m/^-e$/ and do {
+ $install = 0;
+ next;
+ };
+ if ($install) {
+ push(@rpmi, $arg);
+ } else {
+ push(@rpme, $arg);
+ }
+ }
+}
+
+(@rpmi || @rpme) or help();
+
+if (defined($dbpath)) {
+ Hdlist::add_macro("_dbpath $dbpath");
+}
+my $db = newdb(0, $root);
+
+foreach my $rpm (@rpmi) {
+ my $hdr = rpm2header($rpm) or do {
+ warn "Can't get header from $rpm, skipping";
+ next;
+ };
+ $db->transadd($hdr, $rpm, 1);
+}
+
+foreach my $rpm (@rpme) {
+ $db->transremove($rpm) or warn "Can't remove unknown package $rpm, skipping";
+}
+
+$db->transcheck();
+
+my @pb = $db->transpb();
+if (@pb) { die(join('\n', map { s/^/\t/ } format_rpmpb(@pb))); }
+
+$db->transrun(undef, @installflags);
diff --git a/RPM4/examples/specwillbuild b/RPM4/examples/specwillbuild
new file mode 100755
index 0000000..7ccbbf9
--- /dev/null
+++ b/RPM4/examples/specwillbuild
@@ -0,0 +1,42 @@
+#!/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 Hdlist;
+use Getopt::Long;
+
+(@ARGV) or die
+"$0 specfile1.spec [specfile2.spec [...]]
+Give rpms filename produce by a specfile
+";
+
+foreach (@ARGV) {
+ Hdlist::readconfig();
+ my $spec = Hdlist::specnew($_, undef, undef, undef, 1, 1);
+ defined $spec or do {
+ warn "unable to parse $_\n";
+ next;
+ };
+ print "$_:\n";
+ print $spec->srcrpm . "\n";
+ foreach my $bin ($spec->binrpm) {
+ print "$bin\n";
+ }
+}
diff --git a/RPM4/lib/RPM4.pm b/RPM4/lib/RPM4.pm
new file mode 100644
index 0000000..beac297
--- /dev/null
+++ b/RPM4/lib/RPM4.pm
@@ -0,0 +1,422 @@
+##- 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$
+
+package RPM4;
+
+use strict;
+use warnings;
+
+use DynaLoader;
+use Exporter;
+
+use RPM4::Header;
+use RPM4::Transaction;
+use RPM4::Header::Dependencies;
+use RPM4::Header::Files;
+use RPM4::Spec;
+
+our $VERSION = '0.08';
+our @ISA = qw(DynaLoader Exporter);
+our @EXPORT = qw(moduleinfo
+ readconfig querytag tagName tagValue expand rpmvercmp
+ stream2header rpm2header
+ installsrpm
+ setverbosity setlogcallback format_rpmpb
+ rpmresign
+ newdb parserpms);
+our %EXPORT_TAGS = (
+ rpmlib => [qw(getosname getarchname dumprc dumpmacros rpmvercmp setverbosity setlogcallback
+ rpmlog)],
+ macros => [qw(add_macros del_macros loadmacrosfile resetmacros)],
+ build => [qw(headernew)],
+ rpmdb => [qw(rpmdbverify rpmdbrebuild)],
+);
+
+bootstrap RPM4;
+
+# I18N:
+sub N {
+ my ($msg, @args) = @_;
+ sprintf($msg, @args)
+}
+
+sub compare_evr {
+ my ($ae, $av, $ar) = $_[0] =~ /^(?:([^:]*):)?([^-]*)(?:-(.*))?$/;
+ my ($be, $bv, $br) = $_[1] =~ /^(?:([^:]*):)?([^-]*)(?:-(.*))?$/;
+
+ my $rc = 0;
+ if(defined($ae) && ! defined($be)) {
+ return 1;
+ } elsif(!defined($ae) && defined($be)) {
+ return -1;
+ } else {
+ $rc = RPM4::rpmvercmp($ae, $be) if (defined($ae) && defined($be));
+ if ($rc == 0) {
+ $rc = RPM4::rpmvercmp($av, $bv);
+ if ($rc == 0) {
+ if(defined($ar) && !defined($br)) {
+ return 1;
+ } elsif(!defined($ar) && defined($br)) {
+ return -1;
+ } elsif (!defined($ar) && !defined($br)) {
+ return 0;
+ } else {
+ return RPM4::rpmvercmp($ar, $br);
+ }
+ } else {
+ return $rc;
+ }
+ } else {
+ return $rc;
+ }
+ }
+}
+
+# parse* function
+# callback => function
+# (
+# header => the header (undef on error)
+# file => actual source
+# )
+# files => []
+# flags => ??
+
+sub parserpms {
+ my (%options) = @_;
+ my $db = newdb();
+ $db->vsflags($options{checkrpms} ? [ "NOSIGNATURES" ] : [ qw(NOSIGNATURES NOPAYLOAD NODIGESTS) ]);
+ foreach my $rpm (@{$options{rpms} || []}) {
+ my $header = $db->rpm2header($options{path} ? "$options{path}/$rpm" : $rpm);
+ defined($options{callback}) and
+ $options{callback}->(
+ header => $header,
+ dir => $options{path} ? "$options{path}/" : "",
+ rpm => $rpm,
+ );
+ }
+}
+
+sub format_rpmpb {
+ my (@msgs) = @_;
+ my @ret;
+ foreach my $p (@msgs) {
+ $p->{pb} eq "BADARCH" and do {
+ push @ret, N('package %s is intended for a different architecture', $p->{pkg});
+ next;
+ };
+ $p->{pb} eq "BADOS" and do {
+ push @ret, N('package %s is intended for a different operating system', $p->{pkg});
+ next;
+ };
+ $p->{pb} eq "PKG_INSTALLED" and do {
+ push @ret, N('package %s is allready installed', $p->{pkg});
+ next;
+ };
+ $p->{pb} eq "BADRELOCATE" and do {
+ push @ret, N('path %s in package %s is not relocatable', $p->{path}, $p->{pkg});
+ next;
+ };
+ $p->{pb} eq "NEW_FILE_CONFLICT" and do {
+ push @ret, N('file %s conflicts between attempted installs of %s and %s', $p->{file}, $p->{pkg}, $p->{pkg2});
+ next;
+ };
+ $p->{pb} eq "FILE_CONFLICT" and do {
+ push @ret, N('file %s from install of %s conflicts with file from package %s', $p->{file}, $p->{pkg}, $p->{pkg2});
+ next;
+ };
+ $p->{pb} eq "OLDPACKAGE" and do {
+ push @ret, N('package %s (which is newer than %s) is already installed', $p->{pkg2}, $p->{pkg});
+ next;
+ };
+ $p->{pb} eq "DISKSPACE" and do {
+ push @ret, N('installing package %s needs %sB on the %s filesystem', $p->{pkg},
+ ($p->{size} > 1024 * 1024
+ ? ($p->{size} + 1024 * 1024 - 1) / (1024 * 1024)
+ : ($p->{size} + 1023) / 1024 ) .
+ ($p->{size} > 1024 * 1024 ? 'M' : 'K'),
+ $p->{filesystem});
+ next;
+ };
+ $p->{pb} eq "DISKNODES" and do {
+ push @ret, N('installing package %s needs %ld inodes on the %s filesystem', $p->{pkg}, $p->{nodes}, $p->{filesystem});
+ next;
+ };
+ $p->{pb} eq "BADPRETRANS" and do {
+ push @ret, N('package %s pre-transaction syscall(s): %s failed: %s', $p->{pkg}, $p->{'syscall'}, $p->{error});
+ next;
+ };
+ $p->{pb} eq "REQUIRES" and do {
+ push @ret, N('%s is needed by %s%s', $p->{pkg2},
+ defined($p->{installed}) ? N("(installed) ") : "",
+ $p->{pkg});
+ next;
+ };
+ $p->{pb} eq "CONFLICT" and do {
+ push @ret, N('%s conflicts with %s%s', $p->{pkg2},
+ defined($p->{val2}) ? N("(installed) ") : "",
+ $p->{pkg});
+ next;
+ };
+ };
+ @ret
+}
+
+##########################
+# Alias for compatiblity #
+##########################
+
+sub specnew {
+ newspec(@_);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+RPM4 - perl module to handle hdlist and synthesis files
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+This module allow to use API functions from rpmlib, directly or trough
+perl objects.
+
+=head1 FUNCTIONS
+
+=head2 readconfig($rpmrc, $target)
+
+Force rpmlib to re-read configuration files. If defined, $rpmrc is read.
+If $target is defined, rpmlib will read config for this target. $target has
+the form "CPU-VENDOR-OS".
+
+ readconfig(); # Reread default configuration
+ readconfig(undef, "i386-mandrake-linux"); # Read configuration for i386
+
+=head2 setverbosity($level)
+
+Set the rpmlib verbosity level. $level can be an integer (0 to 7) or a
+verbosity level name.
+
+ - EMERG (0)
+ - ALERT (1)
+ - CRIT (2)
+ - ERR (3)
+ - WARNING (4)
+ - NOTICE (5)
+ - INFO (6)
+ - DEBUG (7)
+
+=head2 setlogcallback(sub {})
+
+Set a perl callback code for rpm logging/output system. When the callback is
+set, rpm lets your code print error/information messages. The parameter passed
+to the callback is a hash with log value:
+ C<locode> => the rpm log code (integer),
+ C<priority> => priority of the message (0 to 7),
+ C<msg> => the formated string message.
+
+To unset the callback function, passed an undef value as code reference.
+
+Ex:
+ setlogcallback( sub {
+ my %log = @_;
+ print "$log{priority}: $log{msg}\n";
+ });
+
+=head2 setlogfile(filename)
+
+Redirect all rpm message into this file. Data will be append to the end of the
+file, the file is created if it don't already exists. The old loging file is close.
+
+To unset (and close) a pending loging file, passed an undef value.
+
+=head2 lastlogmsg
+
+Return an array about latest rpm log message information:
+ - rpm log code,
+ - rpm priority (0 to 7),
+ - string message.
+
+=head2 rpmlog($codelevel, $msg)
+
+Send a message trougth the rpmlib logging system.
+ - $codelevel is either an integer value between 0 and 7, or a level code string,
+see setverbosity(),
+ - $msg is the message to send.
+
+=head2 format_rpmpb(@pb)
+
+Some functions return an array of rpm transaction problem
+(RPM4::Db->transpb()), this function return an array of human readable
+string for each problem.
+
+=head2 querytag
+
+Returns a hash containing the tags known by rpmlib. The hash has the form
+C< TAGNAME => tagvalue >. Note that some tags are virtual and do not have
+any tag value, and that some tags are alias to already existing tags, so
+they have the same value.
+
+=head2 tagtypevalue($tagtypename)
+
+Return the type value of a tag type. $tagtypename can be CHAR, INT8, INT16
+INT32, STRING, ARRAY_STRING or I18NSTRING. This return value is usefull with
+RPM4::Header::addtag() function.
+
+=head2 tagName($tagvalue)
+
+Returns the tag name for a given internal value.
+
+ tagName(1000); return "NAME".
+
+See: L<tagValue>.
+
+=head2 tagValue($tagname)
+
+Returns the internal tag value for C<$tagname>.
+
+ tagValue("NAME"); return 1000.
+
+See: L<tagName>.
+
+=head2 expand($string)
+
+Evaluate macros contained in C<$string>, like C<rpm --eval>.
+
+ expand("%_var") return "/var".
+
+=head2 add_macro("_macro value")
+
+Define a macro into rpmlib. The macro is defined for the whole script. Ex:
+C<add_macro("_macro value")>. Note that the macro name does have the prefix
+"%", to prevent rpm from evaluating it.
+
+=head2 del_macro("_macro")
+
+Delete a macro from rpmlib. Exactly the reverse of add_macro().
+
+=head2 loadmacrosfile($filename)
+
+Read a macro configuration file and load macros defined within.
+Unfortunately, the function returns nothing, even when file loading failed.
+
+To reset macros loaded from file you have to re-read the rpm config file
+with L<readconfig>.
+
+=head2 resetmacros
+
+Reset all macros defined with add_macro() functions.
+
+This function does not reset macros loaded with loadmacrosfile().
+
+=head2 getosname
+
+Returns the operating system name of current rpm configuration.
+Rpmlib auto-detects the system name, but you can force rpm to use
+another system name with macros or using readconfig().
+
+=head2 getarchname
+
+Returns the arch name of current rpm configuration.
+Rpmlib auto-detects the architecture, but you can force rpm to use
+another architecture with macros or by using readconfig().
+
+=head2 buildhost
+
+Returns the BuildHost name of the current system, ie the value rpm will use
+to set BuilHost tag in built rpm.
+
+=head2 dumprc(*FILE)
+
+Dump rpm configuration into file handle.
+Ex:
+ dumprc(*STDOUT);
+
+=head2 dumpmacros(*FILE)
+
+Dump rpm macros into file handle.
+Ex:
+ dumpmacros(*STDOUT);
+
+=head2 rpmresign($passphrase, $rpmfile)
+
+Resign a rpm using user settings. C<$passphrase> is the key's gpg/pgp
+pass phrase.
+
+Return 0 on success.
+
+=head2 rpmvercmp(version1, version2)
+
+Compare two version and return 1 if left argument is highter, -1 if
+rigth argument is highter, 0 if equal.
+Ex:
+ rpmvercmp("1.1mdk", "2.1mdk"); # return -1.
+
+=head2 compare_evr(version1, version2)
+
+COmpare two rpm version in forms [epoch:]version[-release] and return
+1 if left argument is highter, -1 if rigth argument is highter, 0 if
+equal.
+Ex:
+ compare_evr("1:1-1mdk", "2-2mdk"); # return 1
+
+=head2 installsrpm($filename)
+
+Install a source rpm and return spec file path and its cookies.
+Returns undef if install is impossible.
+
+see L<RPM4::Spec>->new() for more information about cookies.
+
+=head2 rpmdbinit(rootdir, permissions)
+
+Create an empty rpm database located into I<%{_dbpath}> (useally /var/lib/rpm).
+If set, rootdir is the root directory of system where rpm db should be
+create, if set, theses permissions will be applied to files, default is 0644.
+
+Directory I<%{_dbpath}> should exist.
+
+Returns 0 on success.
+
+Ex:
+ rpmdbinit(); # Create rpm database on the system
+ rpmdbinit("/chroot"); # Create rpm database for system located into /chroot.
+
+=head2 rpmdbverify($rootdir)
+
+Verify rpm database located into I<%{_dbpath}> (useally /var/lib/rpm).
+If set, $rootdir is root directory of system to check.
+
+Returns 0 on success.
+
+=head2 rpmdbrebuild($rootdir)
+
+Rebuild the rpm database located into I<%{_dbpath}> (useally /var/lib/rpm).
+If set, $rootdir is the root directory of system.
+
+Returns 0 on success.
+
+=head1 SEE ALSO
+
+L<rpm(8)>,
+
+This aims at replacing part of the functionality provided by URPM.
+
+=cut
diff --git a/RPM4/lib/RPM4/Header.pm b/RPM4/lib/RPM4/Header.pm
new file mode 100644
index 0000000..21f80e2
--- /dev/null
+++ b/RPM4/lib/RPM4/Header.pm
@@ -0,0 +1,335 @@
+##- 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$
+
+package RPM4::Header;
+
+use strict;
+use warnings;
+use vars qw($AUTOLOAD);
+
+use RPM4;
+use Digest::SHA1;
+use Carp;
+
+sub new {
+ my ($class, $arg) = @_;
+
+ if ($arg) {
+ if (ref $arg eq 'GLOB') {
+ return RPM4::stream2header($arg);
+ } elsif (-f $arg) {
+ return RPM4::rpm2header($arg);
+ } else {
+ croak("Invalid argument $arg");
+ }
+ } else {
+ return RPM4::headernew();
+ }
+}
+
+# proxify calls to $header->tag()
+sub AUTOLOAD {
+ my ($header) = @_;
+
+ my $tag = $AUTOLOAD;
+ $tag =~ s/.*:://;
+ return $header->tag($tag);
+}
+
+sub writesynthesis {
+ my ($header, $handle, $filestoprovides) = @_;
+ $handle ||= *STDOUT;
+
+ my $sinfo = $header->synthesisinfo($filestoprovides);
+
+ foreach my $deptag (qw(provide conflict obsolete require)) {
+ printf($handle '@%ss@%s'."\n",
+ $deptag,
+ join('@', @{$sinfo->{$deptag}})) if (@{$sinfo->{$deptag} || []});
+ }
+
+ printf($handle '@summary@%s'. "\n",
+ $sinfo->{summary},
+ );
+ printf($handle '@info@%s@%d@%d@%s'."\n",
+ $sinfo->{fullname},
+ $sinfo->{epoch},
+ $sinfo->{size},
+ $sinfo->{group},
+ );
+ return 1;
+}
+
+sub synthesisinfo {
+ my ($header, $filestoprovides) = @_;
+ my $synthinfo = {
+ fullname => scalar($header->fullname()),
+ summary => $header->tag(1004),
+ epoch => $header->tag(1003) || 0,
+ size => $header->tag(1009),
+ group => $header->tag(1016),
+ os => $header->tag('OS'),
+ hdrid => pack("H*",$header->tag('HDRID')),
+ };
+
+
+ my @pkgfiles;
+ if (my $files = $header->files()) {
+ $files->init();
+ while($files->next() >= 0) {
+ my $f = $files->filename();
+ foreach(@{$filestoprovides}) {
+ $_ eq $f and do {
+ push @pkgfiles, "$f";
+ last;
+ };
+ }
+ }
+ }
+ foreach my $deptag (qw(provide conflict obsolete require)) {
+ my @deps;
+ $deptag eq 'provide' and push(@deps, @pkgfiles);
+ if (my $dep = $header->dep(uc($deptag . "name")) || undef) {
+ $dep->init();
+ while ($dep->next() >= 0) {
+ ($dep->flags() & (1 << 24)) and next;
+ my @d = $dep->info();
+ #$d[1] =~ /^rpmlib\(\S*\)$/ and next;
+ push(@deps, sprintf(
+ "%s%s%s",
+ "$d[1]",
+ ($dep->flags() & RPM4::flagvalue('sense', [ 'PREREQ' ])) ? '[*]' : '',
+ $d[2] ? '[' . ($d[2] eq '=' ? '==' : $d[2]) . " $d[3]\]" : '' ));
+ }
+ }
+
+ { my %uniq; @uniq{@deps} = (); @deps = keys(%uniq); }
+ push(@{$synthinfo->{$deptag}}, @deps) if(@deps);
+ }
+
+ $synthinfo;
+}
+
+# return an array of required files
+sub requiredfiles {
+ my ($header) = @_;
+ grep { m:^/: } $header->tag(1049);
+}
+
+# is this usefull
+# @keeptags can/should be reworks
+sub buildlight {
+ my ($header, $hinfo) = @_;
+
+ {
+ my @n = $hinfo->{fullname} =~ m/^(.*)-([^-]*)-([^-]*)\.([^.]*)/;
+
+ $header->addtag(1000, 6, $n[0]); # Name
+ $header->addtag(1001, 6, $n[1]); # Version
+ $header->addtag(1002, 6, $n[2]); # Release
+ if ($n[3] eq 'src') {
+ $header->addtag(1022, 6, RPM4::getarchname()); # Arch
+ } else {
+ $header->addtag(1022, 6, $n[3]);
+ $header->addtag(1044, 6, "RPM4-Fake-1-1mdk.src.rpm");
+ }
+ }
+ $header->addtag(1004, 6, $hinfo->{summary});
+ $header->addtag(1003, 4, $hinfo->{epoch}) if ($hinfo->{epoch});
+ $header->addtag(1009, 4, $hinfo->{size});
+ $header->addtag(1016, 6, $hinfo->{group});
+ $header->addtag("OS", 6, $hinfo->{os} ? $hinfo->{os} : RPM4::getosname());
+
+ foreach my $dep (qw(provide require conflict obsolete)) {
+ my $deptag = $dep; $deptag = uc($deptag);
+ foreach my $entry (@{$hinfo->{$dep} || []}) {
+ my ($name, $pre, $fl, $version) = $entry =~ m/([^\[]*)(\[\*\])?(?:\[(\S*)(?:\s*(\S*))?\])?/;
+ $fl ||= '';
+ $dep eq 'provide' && substr($name, 0, 1) eq '/' and do {
+ $header->addtag('OLDFILENAMES', 8, $name);
+ next;
+ };
+ #print "$deptag . 'NAME', 8, $name\n";
+ $header->addtag($deptag . 'NAME', 8, $name);
+ $header->addtag($deptag . 'FLAGS', 'INT32', RPM4::flagvalue("sense", $fl || "") | ($pre ? RPM4::flagvalue("sense", [ 'PREREQ' ]) : 0));
+ $header->addtag($deptag . 'VERSION', 8, $version || "");
+ }
+ }
+
+ if (!$hinfo->{hdrid}) {
+ my $sha = Digest::SHA1->new;
+
+ foreach my $tag ($header->listtag()) {
+ $sha->add(join('', $header->tag($tag)));
+ }
+
+ $hinfo->{hdrid} = $sha->digest;
+ }
+
+ $header->addtag("HDRID", "BIN", $hinfo->{hdrid});
+}
+
+sub getlight {
+ my ($header, $reqfiles) = @_;
+ my $hi = RPM4::headernew();
+ $hi->buildlight($header->synthesisinfo($reqfiles));
+ $hi
+}
+
+sub osscore {
+ my ($header) = @_;
+ my $os = $header->tag("OS");
+ defined $os ? RPM4::osscore($os) : 1;
+}
+
+sub archscore {
+ my ($header) = @_;
+ $header->issrc and return 0;
+ my $arch = $header->tag("ARCH");
+ defined($arch) ? RPM4::archscore($arch) : 1;
+}
+
+sub is_better_than {
+ my ($header, $h) = @_;
+
+ if ($header->tag(1000) eq $h->tag(1000)) {
+ my $c = $header->compare($h);
+ $c != 0 and return $c;
+ return 1 if $header->osscore < $h->osscore;
+ return 1 if $header->archscore < $h->archscore;
+ } elsif (my $obs = $header->dep('OBSOLETENAME')) {
+ $obs->init();
+ while ($obs->next >= 0) {
+ $obs->name eq $h->tag(1000) or next;
+ return 1 if ($obs->matchheadername($h));
+ }
+ }
+ 0;
+}
+
+sub sourcerpmname {
+ $_[0]->queryformat('%|SOURCERPM?{%{SOURCERPM}}:{%{NAME}-%{VERSION}-%{RELEASE}.src.rpm}|')
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+RPM4::Header
+
+=head1 DESCRIPTION
+
+The header contains informations about a rpms, this object give methods
+to manipulate its.
+
+=head1 METHODS
+
+=head2 RPM4::Header->new($item)
+
+Create a new C<RPM4::Header> instance from:
+
+=over 4
+
+=item a file
+
+if $item is an rpm file, returns the corresponding object.
+
+=item a file handler
+
+if $item is a file handler, returns an object corresponding to the next header there.
+
+=item nothing
+
+if $item is omitted, returns an empty object.
+
+=back
+
+If data are unreadable for whatever reason, returns undef.
+
+=head2 RPM4::Header->write(*FILE)
+
+Dump header data into file handle.
+
+Warning: Perl modifier (like PerlIO::Gzip) won't works.
+
+=head2 RPM4::Header->hsize()
+
+Returns the on-disk size of header data, in bytes.
+
+=head2 RPM4::Header->copy()
+
+Returns a RPM4::Header object copy.
+
+=head2 RPM4::Header->removetag(tagid)
+
+Remove tag 'tagid' from header.
+
+=head2 RPM4::Header->addtag(tagid, tagtype, value1, value2...)
+
+Add a tag into the header:
+- tagid is the integervalue of tag
+- tagtype is an integer, it identify the tag type to add (see rpmlib headers
+files). Other argument are value to put in tag.
+
+=head2 RPM4::Header->listtag()
+
+Returns a list of tag id present in header.
+
+=head2 RPM4::Header->hastag(tagid)
+
+Returns true if tag 'tagid' is present in header.
+
+Ex:
+ $header->hastag(1000); # Returns true if tag 'NAME' is present.
+
+=head2 RPM4::Header->tagtype(tagid)
+
+Returns the tagtype value of tagid. Returns 0 if tagid is not found.
+
+=head2 RPM4::Header->tag(tagid)
+
+Returns array of tag value for tag 'tagid'.
+
+ $header->tag(1000); # return the name of rpm header.
+
+=head2 RPM4::Header->queryformat($query)
+
+Make a formated query on the header, macros in I<$query> are evaluated.
+This function works like C<rpm --queryformat ...>
+
+ $header->queryformat("%{NAME}-%{VERSION}-%{RELEASE}");
+
+=head2 RPM4::Header->fullname
+
+In scalar context return the "name-version-version.arch" of package.
+In array context return (name, version, release, arch) of package.
+
+=head2 RPM4::Header->issrc()
+
+Returns true if package is a source package.
+
+=head2 RPM4::Header->compare(header)
+
+Compare the header to another, return 1 if the object is higher, -1 if
+header passed as argument is better, 0 if update is not possible.
+
+=head1 SEE ALSO
+
+L<RPM4>
diff --git a/RPM4/lib/RPM4/Header/Changelogs.pm b/RPM4/lib/RPM4/Header/Changelogs.pm
new file mode 100644
index 0000000..be614c0
--- /dev/null
+++ b/RPM4/lib/RPM4/Header/Changelogs.pm
@@ -0,0 +1,73 @@
+##- 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$
+
+package RPM4::Header::Changelogs;
+
+sub new {
+ my ($class, $header) = @_;
+
+ my $changelogs = {
+ changelogtext => [ $header->tag("changelogtext") ],
+ changelogname => [ $header->tag("changelogname") ],
+ changelogtime => [ $header->tag("changelogtime") ],
+ _counter => -1,
+ };
+ bless($changelogs, $class);
+}
+
+sub init {
+ my ($self) = @_;
+ $self->{_counter} = -1;
+}
+
+sub hasnext {
+ my ($self) = @_;
+ $self->{_counter}++;
+ return $self->{_counter} <= $#{$self->{changelogname}};
+}
+
+sub text {
+ my ($self) = @_;
+ return ${$self->{changelogtext}}[$self->{_counter}];
+}
+
+sub name {
+ my ($self) = @_;
+ return ${$self->{changelogname}}[$self->{_counter}];
+}
+
+sub time {
+ my ($self) = @_;
+ return ${$self->{changelogtime}}[$self->{_counter}];
+}
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+Hdlist::Header::Changelogs - A set of changelogs
+
+=head1 METHODS
+
+=head1 SEE ALSO
+
+L<Hdlist>
+
diff --git a/RPM4/lib/RPM4/Header/Checks.pm b/RPM4/lib/RPM4/Header/Checks.pm
new file mode 100644
index 0000000..0a4b0d7
--- /dev/null
+++ b/RPM4/lib/RPM4/Header/Checks.pm
@@ -0,0 +1,98 @@
+# $Id$
+
+package RPM4::Header::Checks;
+
+use strict;
+use warnings;
+
+my @tagstocheck = (
+ {
+ tag => 'NAME',
+ type => 'STRING',
+ count => 1,
+ mandatory => 1,
+ },
+ {
+ tag => 'VERSION',
+ type => 'STRING',
+ count => 1,
+ mandatory => 1,
+ },
+ {
+ tag => 'RELEASE',
+ type => 'STRING',
+ count => 1,
+ mandatory => 1,
+ },
+ { tag => 'EPOCH', type => 'INT32', count => 1, },
+ {
+ tag => 'CHANGELOGTEXT', type => 'STRING_ARRAY',
+ countof => [ qw(CHANGELOGNAME CHANGELOGTIME) ],
+ },
+ { tag => 'CHANGELOGNAME', type => 'STRING_ARRAY', },
+ { tag => 'CHANGELOGTIME', type => 'INT32', },
+ { tag => 'PACKAGER', type => 'STRING', },
+ { tag => 'DISTRIBUTION', type => 'STRING', },
+ { tag => 'SUMMARY', type => 'STRING', count => 1, mandatory => 1, },
+ { tag => 'DESCRIPTION', type => 'STRING', count => 1, mandatory => 1, },
+
+);
+
+sub reporterror {
+ printf(@_);
+ print "\n";
+}
+
+sub check {
+ my ($header) = @_;
+ foreach my $check (@tagstocheck) {
+ $check->{tag} or next; # buggy check
+
+ if (!$header->hastag($check->{tag})) {
+ reporterror(
+ "tag %s not found",
+ $check->{tag},
+ ) if($check->{mandatory});
+ } elsif (defined($check->{count})) {
+ my @t = $header->tag($check->{tag});
+ if(scalar(@t) != $check->{count}) {
+ reporterror(
+ "Wrong count for tag %s: %d, %d is expected",
+ $check->{tag},
+ scalar(@t),
+ $check->{count},
+ );
+ }
+ }
+
+ if ($check->{countof}) {
+ my @t = $header->tag($check->{tag});
+ foreach my $co (@{$check->{countof}}) {
+ my @t2 = $header->tag($co);
+ if (scalar(@t) != scalar(@t2)) {
+ reporterror(
+ "count of tag %s is not the same than %s, %d vs %d",
+ $check->{tag},
+ $co,
+ scalar(@t),
+ scalar(@t2),
+ );
+ }
+ }
+ }
+
+ $header->hastag($check->{tag}) or next;
+
+ if ($check->{type}) {
+ if ($header->tagtype($check->{tag}) != RPM4::tagtypevalue($check->{type})) {
+ reporterror(
+ "Wrong tagtype for tag %s: %d, %d is expected",
+ $check->{tag},
+ $header->tagtype($check->{tag}),
+ RPM4::tagtypevalue($check->{type})
+ );
+ }
+ }
+ }
+}
+
diff --git a/RPM4/lib/RPM4/Header/Dependencies.pm b/RPM4/lib/RPM4/Header/Dependencies.pm
new file mode 100644
index 0000000..f9a0198
--- /dev/null
+++ b/RPM4/lib/RPM4/Header/Dependencies.pm
@@ -0,0 +1,118 @@
+##- 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$
+
+package RPM4::Header::Dependencies;
+
+sub new {
+ my ($class, $deptag, $initdep, @depdesc) = @_;
+ print "$deptag, $initdep\n";
+ my $dep = RPM4::Header::Dependencies->newsingle($deptag, @$initdep) or return;
+ foreach (@depdesc) {
+ print "$_\n";
+ $dep->add(@$_);
+ }
+ return $dep;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Hdlist::Header::Dependencies - A set of dependencies
+
+=head1 METHODS
+
+=head2 Hdlist::Header::Dependencies->new($tagtype, $dep1, [$dep2, ...])
+
+Create a new arbitrary dependencies set.
+$tagtype is the rpm tag {PROVIDE/REQUIRE/CONFLICT/OBSOLETE/TRIGGER}NAME.
+
+Next arguments are array ref for each dependancy to add in the dependencies set,
+in form a name and optionnaly as sense flags and a version.
+
+For example:
+
+ $d = Hdlist::Header::Dependencies->new(
+ "REQUIRENAME"
+ [ "rpm" ],
+ [ "rpm", 2, "4.0" ],
+ [ "rpm", [ qw/LESS/ ], "4.0" ]
+ );
+
+=head2 $deps->count
+
+Return the number of dependencies contained by this set.
+
+=head2 $deps->move($index)
+
+Move internal index to $index (0 by default).
+
+=head2 $deps->init
+
+Reset internal index and set it to -1, see L<$deps-\\>next()>
+
+=head2 $deps->hasnext
+
+Advance to next dependency in the set.
+Return FALSE if no further dependency available, TRUE otherwise.
+
+=head2 $deps->next
+
+Advance to next dependency in the set.
+Return -1 if no further dependency available, next index otherwise.
+
+=head2 $deps->color
+
+Return the 'color' of the current dependency in the depencies set.
+
+=head2 $deps->overlap($depb)
+
+Compare two dependency from two dependencies set and return TRUE if match.
+
+=head2 $deps->info
+
+Return information about current dependency from dependencies set.
+
+=head2 $deps->tag
+
+Return the type of the dependencies set as a rpmtag (PROVIDENAME, REQUIRENAME,
+PROVIDENAME, OBSOLETENAME of TRIGGERNAME).
+
+=head2 $deps->name
+
+Return the name of dependency from dependencies set.
+
+=head2 $deps->flags
+
+Return the sense flag of dependency from dependencies set.
+
+=head2 $deps->evr
+
+Return the version of dependency from dependencies set.
+
+=head2 $deps->nopromote($nopromote)
+
+Set or return the nopromote flags of the dependencies set.
+
+=head1 SEE ALSO
+
+L<Hdlist>
+L<Hdlist::Header>
+
diff --git a/RPM4/lib/RPM4/Header/Files.pm b/RPM4/lib/RPM4/Header/Files.pm
new file mode 100644
index 0000000..dd315d8
--- /dev/null
+++ b/RPM4/lib/RPM4/Header/Files.pm
@@ -0,0 +1,61 @@
+##- 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$
+
+package RPM4::Header::Files;
+
+sub dircount {
+ $_[0]->countdir();
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Hdlist::Header::Files - A set of files and directories
+
+=head1 METHODS
+
+=head2 $files->count()
+
+Return the number of files contained by this set.
+
+=head2 $files->countdir()
+
+Return the number of directories contained by this set.
+
+=head2 $files->init()
+
+Reset internal files index and set it to -1.
+
+=head2 $files->initdir()
+
+Reset internal directories index and set it to -1.
+
+=head2 $deps->next()
+
+Set current file to the next one in the set.
+
+=head2 $deps->nextdir()
+
+Set current directory to the next one in the set.
+
+=head2 $files->move($index)
+
+Move internal file index to $index (0 by default).
diff --git a/RPM4/lib/RPM4/Index.pm b/RPM4/lib/RPM4/Index.pm
new file mode 100644
index 0000000..c94d0aa
--- /dev/null
+++ b/RPM4/lib/RPM4/Index.pm
@@ -0,0 +1,163 @@
+##- 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$
+
+package RPM4::Index;
+
+use strict;
+use warnings;
+
+use RPM4;
+use RPM4::Header;
+use Packdrakeng;
+
+use File::Temp qw(tempfile);
+
+sub buildindex {
+ my (%options) = @_;
+
+ my ($pid, $pack, $h_synthesis, $h_list);
+ if ($options{synthesis}) {
+ $pid = open($h_synthesis, "| gzip --best > '$options{synthesis}'") or return 0;
+ }
+ if ($options{hdlist}) {
+ $pack = Packdrakeng->new(
+ archive => $options{hdlist},
+ comp_level => $options{complevel},
+ ) or return 0;
+ }
+ if ($options{list}) {
+ open($h_list, ">", $options{list}) or return 0;
+ }
+
+ RPM4::parserpms(
+ rpms => $options{rpms},
+ callback => sub {
+ my (%res) = @_;
+ if(defined($options{callback})) {
+ $options{callback}->(%res) or return;
+ }
+ defined($res{header}) or return;
+
+ if ($options{synthesis}) {
+ $res{header}->writesynthesis($h_synthesis, $options{filestoprovides});
+ }
+
+ if ($options{hdlist}) {
+ $res{header} or return;
+ # Hacking perl-URPM
+ my $h = $res{header}->copy(); # Get a copy to not alter original header
+ $h->addtag(1000000, 6, scalar($res{header}->fullname()) . '.rpm');
+ $h->addtag(1000001, 4, (stat("$res{dir}$res{rpm}"))[7]);
+ my $fh = new File::Temp( UNLINK => 1, SUFFIX => '.header');
+ $h->write($fh);
+ sysseek($fh, 0, 0);
+ $pack->add_virtual('f', scalar($res{header}->fullname()), $fh);
+ close($fh);
+ }
+
+ if ($options{list}) {
+ print $h_list "$res{rpm}\n";
+ }
+
+ },
+ checkrpms => $options{checkrpms},
+ path => $options{path},
+
+ );
+
+ if ($options{synthesis}) {
+ close($h_synthesis);
+ waitpid $pid, 0;
+ }
+
+ if($options{list}) {
+ close($h_list);
+ }
+ 1;
+}
+
+sub buildsynthesis {
+ my (%options) = @_;
+ buildindex(%options);
+}
+
+# Build only an hdlist file
+sub buildhdlist {
+ my (%options) = @_;
+ buildindex(%options);
+}
+
+sub parsehdlist {
+ my (%options) = @_;
+ my $pack = Packdrakeng->open(archive => $options{hdlist}) or return 0;
+
+ my (undef, $files, undef) = $pack->getcontent();
+ pipe(my $in, my $out);
+ if (my $pid = fork()) {
+ close($out);
+ stream2header($in, 0, sub {
+ #printf STDERR $header->fullname ."\n";
+ $options{callback}->(
+ header => $_[0],
+ );
+ });
+ close($in);
+ waitpid($pid, 0);
+ } else {
+ close($in);
+ foreach my $h (@{$options{files} || $files || []}) {
+ $pack->extract_virtual($out, $h) >= 0 or die;
+ }
+ close($out);
+ exit;
+ }
+ 1;
+}
+
+sub parsesynthesis {
+ my (%options) = @_;
+
+ open(my $h, "cat '$options{synthesis}' | gunzip |") or return 0;
+
+ my %hinfo = ();
+ while (my $line = <$h>) {
+ chomp($line);
+ my (undef, $type, $info) = split('@', $line, 3);
+ my @infos = split('@', $info);
+ if ($type =~ m/^(provides|requires|conflict|obsoletes)$/) {
+ @{$hinfo{$type}} = @infos;
+ } elsif ($type eq 'summary') {
+ $hinfo{summary} = $info;
+ } elsif ($type eq 'info') {
+ @hinfo{qw(fullname epoch size group)} = @infos;
+
+ my $header = RPM4::headernew();
+ $header->buildlight(\%hinfo);
+ $options{callback}->(
+ header => $header,
+ );
+
+ %hinfo = ();
+ } else {
+ }
+ }
+ close($h);
+ 1;
+}
+
+1;
diff --git a/RPM4/lib/RPM4/Media.pm b/RPM4/lib/RPM4/Media.pm
new file mode 100644
index 0000000..5096e2b
--- /dev/null
+++ b/RPM4/lib/RPM4/Media.pm
@@ -0,0 +1,193 @@
+##- 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$
+
+package RPM4::Media;
+
+use strict;
+use RPM4::Index;
+use RPM4::Header;
+
+# $options = {
+# prefixurl if need, ie real rpms locations
+# type => rpms, hdlist, headers
+# source => $ (hdlist,dir) or @ (rpms, headers)
+sub new {
+ my ($class, %options) = @_;
+ my $media = {
+ hdlist => undef,
+ synthesis => undef,
+ list => 'list',
+ rpmsdir => undef,
+
+ rpms => [],
+
+ rpmn2path => {},
+ id2path => {},
+
+ info => undef,
+
+ hdr => [],
+
+ use_light_header => 1,
+ };
+
+ foreach (keys %$media) {
+ defined($options{$_}) and $media->{$_} = $options{$_};
+ }
+
+ bless($media, $class);
+}
+
+sub init {
+ my ($self, $callback) = @_;
+
+ $self->{hdr} = [];
+ $self->{hdrid} = [];
+ my %reqfiles;
+ $self->{selectedhdrid} = {};
+ $self->{reqfiles} = [];
+
+ $callback ||= sub {
+ my (%arg) = @_;
+ @reqfiles{$arg{header}->requiredfiles()} = ();
+ 1;
+ };
+
+ if (defined(my $synthesis = $self->get_indexfile('synthesis'))) {
+ RPM4::Index::parsesynthesis(
+ synthesis => $synthesis,
+ callback => sub {
+ my %arg = @_;
+ $callback->(%arg) or return;
+ push(@{$self->{hdr}}, $arg{header});
+ },
+ );
+ } elsif (defined(my $hdlist = $self->get_indexfile('hdlist'))) {
+ RPM4::Index::parsehdlist(
+ hdlist => $hdlist,
+ callback => sub {
+ my %arg = @_;
+ $callback->(%arg) or return;
+ $self->{selectedhdrid}{$arg{header}->tag('HDRID')} = 1;
+ },
+ );
+ } elsif (defined($self->{rpms})) {
+ my @rpms = grep { defined($_) } map { $self->get_rpm($_) } @{$self->{rpms}};
+ RPM4::parserpms(
+ rpms => \@rpms,
+ callback => sub {
+ my %arg = @_;
+ $callback->(%arg) or return;
+ $self->{selectedhdrid}{$arg{header}->tag('HDRID')} = 1;
+ },
+ );
+ }
+ $self->{reqfiles} = [ keys %reqfiles ];
+}
+
+sub load {
+ my ($self, $reqfiles) = @_;
+ $reqfiles ||= $self->{reqfiles};
+
+ if (defined($self->get_indexfile('synthesis'))) {
+ # populate is done during first pass
+ } elsif (defined(my $hdlist = $self->get_indexfile('hdlist'))) {
+ RPM4::Index::parsehdlist(
+ hdlist => $hdlist,
+ callback => sub {
+ my %arg = @_;
+ $self->{selectedhdrid}{$arg{header}->tag('HDRID')} or return;
+ if ($self->{use_light_header}) {
+ my $h = $arg{header}->getlight($reqfiles);
+ push(@{$self->{hdr}}, $h);
+ } else {
+ push(@{$self->{hdr}}, $arg{header});
+ }
+ },
+ );
+ } elsif (defined($self->{rpms})) {
+ my @rpms = grep { defined($_) } map { $self->get_rpm($_) } @{$self->{rpms}};
+ RPM4::parserpms(
+ rpms => \@rpms,
+ callback => sub {
+ my %arg = @_;
+ $self->{selectedhdrid}{$arg{header}->tag('HDRID')} or return;
+ if ($self->{use_light_header}) {
+ my $h = $arg{header}->getlight($reqfiles);
+ push(@{$self->{hdr}}, $h);
+ } else {
+ push(@{$self->{hdr}}, $arg{header});
+ }
+ $self->{id2path}{$#{$self->{hdr}}} = $arg{rpm};
+ },
+ );
+ }
+ delete($self->{reqfiles});
+ delete($self->{selectedhdrid});
+
+ if (my $listf = $self->get_indexfile('list')) {
+ if (open(my $lh, "<", $listf)) {
+ while (my $line = <$lh>) {
+ chomp($line);
+ my ($fullname) = $line =~ m,^(?:.*/)?(.*)\.rpm$,;
+ $self->{rpmn2path}{$fullname} = $line;
+ }
+ close($lh);
+ }
+ }
+}
+
+sub traverse {
+ my ($self, $callback) = @_;
+
+ foreach my $id (0 .. $#{$self->{hdr} || []}) {
+ my $header = $self->{hdr}[$id];
+ $callback->($header, $id) or return;
+ }
+}
+
+sub get_header {
+ my ($self, $id) = @_;
+ return $self->{hdr}[$id];
+}
+
+sub get_indexfile {
+ my ($self, $file) = @_;
+ defined($self->{$file}) or return undef;
+ my $f =
+ (substr($self->{$file}, 0, 1) ne '/' && defined($self->{rpmsdir}) ? "$self->{rpmsdir}/" : "") .
+ $self->{$file};
+ -e $f ? $f : undef;
+}
+
+sub id2rpm {
+ my ($self, $id) = @_;
+ my $rpm = $self->get_header($id)->fullname;
+ return exists($self->{rpmn2path}{$rpm}) ? $self->{rpmn2path}{$rpm} :
+ (exists($self->{id2path}{$id}) ? $self->{id2path}{$id} : "$rpm.rpm");
+}
+
+sub get_rpm {
+ my ($self, $rpm) = @_;
+ my $file =
+ (substr($rpm, 0, 1) ne '/' && defined($self->{rpmsdir}) ? "$self->{rpmsdir}/" : "") .
+ $rpm;
+ -e $file ? $file : undef;
+}
+
+1;
diff --git a/RPM4/lib/RPM4/Spec.pm b/RPM4/lib/RPM4/Spec.pm
new file mode 100644
index 0000000..d6c5b29
--- /dev/null
+++ b/RPM4/lib/RPM4/Spec.pm
@@ -0,0 +1,195 @@
+##- 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$
+
+package RPM4::Spec;
+
+use strict;
+use warnings;
+
+use RPM4;
+use RPM4::Transaction::Problems;
+
+sub rpmbuild {
+ my ($spec, $flags, %options) = @_;
+
+ $options{db} ||= RPM4::newdb();
+
+ my ($f) = $flags =~ /^(?:-)?b([pcibas])/;
+ $f or die "Unknown build options '$flags', should be b[pciabs]\n";
+ my @buildflags;
+ for (qw/p c i/) {
+ $options{shortcircuit} && $f ne $_ and next;
+ /^p$/ and push (@buildflags, "PREP");
+ /^c$/ and push (@buildflags, "BUILD");
+ /^l$/ and push (@buildflags, "FILECHECK");
+ /^i$/ and push (@buildflags, qw/INSTALL CHECK/);
+ $f eq $_ and last;
+ }
+ for ($f) {
+ /^a$/ and push(@buildflags, qw/PACKAGESOURCE PACKAGEBINARY/);
+ /^b$/ and push(@buildflags, qw/PACKAGEBINARY/);
+ /^s$/ and push(@buildflags, qw/PACKAGESOURCE/);
+ }
+ $options{clean} and push(@buildflags, qw/RMBUILD RMSOURCE/);
+ $options{rmspec} and push(@buildflags, qw/RMSPEC/);
+
+
+ if (!$options{nodeps}) {
+ my $sh = $spec->srcheader() or die "Can't get source header from spec object"; # Can't happend
+ $options{db}->transadd($sh, "", 0);
+ $options{db}->transcheck;
+ my $pbs = RPM4::Transaction::Problems->new($options{db});
+ $options{db}->transreset();
+ if ($pbs) {
+ $pbs->print_all(\*STDERR);
+ return 1;
+ }
+ }
+ return $options{db}->specbuild($spec, [ @buildflags ]);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+RPM4::Spec
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+Extend method availlable on RPM4::Spec objects
+
+=head1 METHODS
+
+=head2 new(file, var => value, ...)
+
+Create a C<RPM4::Spec> instance, only the file values is mandatory.
+
+=over 4
+
+=item file
+
+The spec file from wich to create the object
+
+=item passphrase
+
+If specified, the passphrase will be used for gpg signing after build.
+
+=item rootdir
+
+If specified, root dir will be use root instead '/'.
+
+=item cookies
+
+the cookies is string rpm will put into RPMCOOKIES tag, a way to know if a rpm
+has been built from a specific src. You get this value from L<installsrpm>.
+
+=item anyarch
+
+If set, you'll get a spec object even the spec can't be build on the
+current %_target_cpu. Notice if you set this value, starting a build over
+the spec object will works !
+
+=item force
+
+Normally, source analyze is done during spec parsing, getting a spec object
+failed if a source file is missing, else you set force value.
+
+TAKE CARE: if force is set, rpm will not check source type, so patch will NOT
+be gunzip/bunzip... If you want to compile the spec, don't set it to 1, if you
+just want run clean/packagesource stage, setting force to 1 is ok.
+
+=back
+
+By default anyarch and force are set to 0.
+
+=head2 RPM4::Spec->srcheader()
+
+Returns a RPM4::Header object like source rpm will be.
+Please notice that the header is not finish and header information you'll
+get can be incomplete, it depend if you call the function before or after
+RPM4::Spec->build().
+
+=head2 RPM4::Spec->srcrpm()
+
+Returns the source filename spec file will build. The function take care
+about rpmlib configuration (build dir path).
+
+=head2 RPM4::Spec->binrpm()
+
+Returns files names of binaries rpms that spec will build. The function take
+care about rpmlib configuration (build dir path).
+
+=head2 RPM4::Spec->build([ @actions ])
+
+Run build process on spec file.
+Each value in @actions is one or more actions to do:
+
+ - PACKAGESOURCE: build source package,
+ - PREP: run prep stage,
+ - BUILD: run build stage,
+ - INSTALL: run install stage,
+ - CHECK: check installed files,
+ - FILECHECK: check installed files,
+ - PACKAGEBINARY: build binaries packages,
+ - CLEAN: run clean stage,
+ - RMSPEC: delete spec file,
+ - RMSOURCE: delete sources files,
+ - RMBUILD: delete build files,
+
+=head2 rpmbuild($flags, %options)
+
+Build a spec using rpm same rpm options.
+
+$flags should be -b[abspci]
+
+%options is a list of optionnal options:
+
+=over 4
+
+=item db
+
+reuse an already existing RPM4::Db object (else a new one is created)
+
+=item clean
+
+if set, clean source and build tre (like rpmbuild --clean
+
+=item rmspec
+
+if set, delete the spec after build (like rpmbuild --rmspec)
+
+=item nodeps
+
+If set, don't check dependancies before build
+
+=item shortcircuit
+
+if set, run only the build stage asked, not all preceding (like rpmbuild
+--short-circuit)
+
+=back
+
+=head1 SEE ALSO
+
+L<RPM4>
+
+=cut
diff --git a/RPM4/lib/RPM4/Transaction.pm b/RPM4/lib/RPM4/Transaction.pm
new file mode 100644
index 0000000..a62be4d
--- /dev/null
+++ b/RPM4/lib/RPM4/Transaction.pm
@@ -0,0 +1,195 @@
+##- 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 RPM4::Transaction::Problems;
+
+package RPM4::Transaction;
+
+sub newspec {
+ my ($self, $filename, %options) = @_;
+ $options{transaction} = $self;
+ RPM4::Spec->new(
+ $filename,
+ %options
+ );
+}
+
+sub transpbs {
+ my ($self) = @_;
+ return RPM4::Transaction::Problems->new($self);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Hdlist::Db
+
+=head1 DESCRIPTION
+
+This object allow to access to the rpm datadase and installing rpms on the
+system.
+
+=head1 METHODS
+
+=head2 Hdlist::Db->traverse_headers(sub)
+
+Go through the rpm database and for each header run the callback passed as
+argument.
+
+Argument passed to the callback function is the current header as a Hdlist::Header object.
+
+Ex:
+ $db->traverse_headers( sub {
+ my ($h) = @_;
+ print $h->queryformat("%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}");
+ });
+
+
+=head2 Hdlist::Db->injectheader($header)
+
+Add the header into rpmdb. This is not installing a package, the function
+only fill information into the rpmdb.
+
+Return 0 on success.
+
+=head2 Hdlist::Db->deleteheader($index)
+
+Remove header from rpmdb locate at $index. This is not uninstalling a package,
+this function only delete information from rpmdb.
+
+Return 0 on success
+
+=head2 Hdlist::Db->transadd(header, filename, upgrade, relocation, force)
+
+Add rpm headers for next transaction. This means this rpm are going to be
+installed on the system.
+
+- header is an Hdlist::Header object,
+
+- filename, if given, is the rpm file you want to install, and should
+of course match the header,
+
+- upgrade is a boolean flag to indicate whether the rpm is going to be upgraded
+(1 by default).
+
+Returns 0 on success.
+
+See: $Hdlist::Db->transcheck(), $Hdlist::Db->transrun().
+
+=head2 Hdlist::Db->transremove(rpm_name)
+
+Add rpm to remove for next transaction. This mean the rpm will be uninstalled
+from the system.
+
+Argument is the exact rpm name (%{NAME}) or a string as NAME(EPOCH:VERSION-RELEASE).
+
+Returns the number of selected rpms for this transaction.
+
+=head2 Hdlist::Db->transcheck()
+
+Check current transaction is possible.
+
+Returns 0 on success, 1 on error during check.
+
+=head2 Hdlist::Db->transorder()
+
+Call to rpmlib to order the transaction, aka sort rpm installation /
+desintallation.
+
+Returns 0 on success.
+
+=head2 Hdlist::Db->transpb
+
+Return an array of problem found during L<Hdlist::Db->transcheck> or
+L<Hdlist::Db->transrun>
+
+=head2 Hdlist::Db->transrun($callback, $flags...)
+
+Really run transaction and install/uninstall packages.
+
+$callback can be:
+
+- undef value, let rpm show progression with some default value.
+
+- array ref: each value represent a rpm command line options:
+
+ PERCENT: show percentage of progress (--percent)
+ HASH: print '#' during progression (--hash)
+ LABEL: show rpm name (--verbose)
+
+- code ref: rpm is fully silent, the perl sub is called instead. Arguments
+passed to the subroutine are in a hash:
+
+ filename => opened filename
+ header => current header in transaction
+ what => current transaction process
+ amount => amount of transaction
+ total => number of transaction to do
+
+flags: list of flags to set for transaction (see rpm man page):
+
+I<From rpm Transaction flag>:
+
+ - NOSCRIPTS: --noscripts
+ - JUSTDB: --justdb
+ - NOTRIGGERS: --notriggers
+ - NODOCS: --excludedocs
+ - ALLFILES: --allfiles
+ - DIRSTASH: --dirstash
+ - REPACKAGE: --repackage
+ - NOTRIGGERPREIN: --notriggerprein
+ - NOPRE: --nopre
+ - NOPOST: --nopost
+ - NOTRIGGERIN: --notriggerin
+ - NOTRIGGERUN: --notriggerun
+ - NOPREUN: --nopreun
+ - NOPOSTUN: --nopostun
+ - NOTRIGGERPOSTUN: --notriggerpostun
+ - NOSUGGEST: --nosuggest
+ - NOMD5: --nomd5
+ - ADDINDEPS: --aid
+ - noscripts: Do not running any scripts, neither triggers
+
+I<From rpm prob filter>
+
+ - IGNOREOS: --ignoreos
+ - IGNOREARCH: --ignorearch
+ - REPLACEPKG: --replacepkgs
+ - REPLACENEWFILES: --replacefiles
+ - REPLACEOLDFILES: --replacefiles
+ - OLDPACKAGES: --oldpackage
+ - DISKSPACE: --ignoresize
+ - DISKNODE: --ignoresize
+
+Returns 0 on success.
+
+=head2 $db->transpbs
+
+Return a Hdlist::Db::Problems object containing problem found during
+rpms installation/desinstallation.
+
+See L<Hdlist::Db::Problems>
+
+=head1 SEE ALSO
+
+L<Hdlist>
diff --git a/RPM4/lib/RPM4/Transaction/Problems.pm b/RPM4/lib/RPM4/Transaction/Problems.pm
new file mode 100644
index 0000000..0266c7f
--- /dev/null
+++ b/RPM4/lib/RPM4/Transaction/Problems.pm
@@ -0,0 +1,115 @@
+##- 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 RPM4;
+use RPM4::Transaction;
+
+package RPM4::Transaction::Problems;
+
+sub new {
+ my ($class, $ts) = @_;
+ my $pbs = {
+ _problems => $ts->_transpbs() || undef,
+ _counter => -1,
+ };
+
+ $pbs->{_problems} or return undef;
+ bless($pbs, $class);
+}
+
+sub count {
+ my ($self) = @_;
+ return $self->{_problems}->count();
+}
+
+sub init {
+ my ($self) = @_;
+ $self->{_counter} = -1;
+}
+
+sub hasnext {
+ my ($self) = @_;
+ return ++$self->{_counter} < $self->{_problems}->count();
+}
+
+sub problem {
+ my ($self) = @_;
+ return $self->{_problems}->fmtpb($self->{_counter});
+}
+
+sub is_ignore {
+ my ($self) = @_;
+ return $self->{_problems}->isignore($self->{_counter});
+}
+
+sub print_all {
+ my ($self, $handle) = @_;
+ $handle ||= *STDOUT;
+ $self->{_problems}->print($handle);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+RPM4::Transaction::Problems
+
+RPM4::Transaction
+
+=head1 DESCRIPTION
+
+This module an object for a collection of problems return by the rpmlib
+when trying to install or removing rpms from the system.
+
+=head1 METHODS
+
+=head2 new(ts)
+
+Create a new problems collection from transaction. Return undef if now
+problems has been found in the transaction.
+
+=head2 $pbs->init
+
+Reset internal index and set it to -1, see L<$deps-\\>hasnext()>
+
+=head2 $pbs->hasnext
+
+Advance to next dependency in the set.
+Return FALSE if no further problem availlable, TRUE otherwise.
+
+=head2 $pbs->problem
+
+Return a format string about current problem in the set
+
+=head2 $pbs->is_ignore
+
+Return True if the problem should be ignored
+
+=head2 $pbs->print_all($handle)
+
+Print all error problems into the given handle, STDOUT if not specified.
+
+=head1 SEE ALSO
+
+L<RPM4>
+L<RPM4::Db>
diff --git a/RPM4/patches/Makefile.PL.staticrpm.patch b/RPM4/patches/Makefile.PL.staticrpm.patch
new file mode 100644
index 0000000..e63fcc0
--- /dev/null
+++ b/RPM4/patches/Makefile.PL.staticrpm.patch
@@ -0,0 +1,17 @@
+Index: src/Makefile.PL
+===================================================================
+RCS file: /cooker/soft/perl-Hdlist/src/Makefile.PL,v
+retrieving revision 1.1
+diff -r1.1 Makefile.PL
+5a6,8
+> my $staticrpm = join(' ', map { "$_" } glob ("librpm/*.a"));
+> print "$staticrpm\n";
+>
+9c12
+< OBJECT => 'Hdlist.o Hdlistsign.o',
+---
+> OBJECT => 'Hdlist.o Hdlistsign.o $staticrpm',
+12c15
+< LIBS => '-lrpm -lrpmio -lrpmdb -lrpmbuild -lpopt -lz -lbz2 -lrpmconstant',
+---
+> LIBS => '-lrpm -lpopt -lz -lbz2 -lrpmconstant',
diff --git a/RPM4/src/Makefile.PL b/RPM4/src/Makefile.PL
new file mode 100644
index 0000000..9b9a60f
--- /dev/null
+++ b/RPM4/src/Makefile.PL
@@ -0,0 +1,48 @@
+# $Id$
+
+# use 5.008;
+use ExtUtils::MakeMaker;
+
+my ($obj, $ldd, $fl) =
+ -f '/usr/include/rpmconstant/rpmconstant.h' ?
+ ('', '-lrpmconstant', '-DHAVE_RPMCONSTANT') :
+ ('rpmconstant.o rpmconstant_internal.o rpmconstanttbl.o', '', '');
+
+sub MY::postamble {
+ my $first = <<RPMCONSTTBL;
+
+rpmconstanttbl.c: Makefile rpmh2tbl
+ perl rpmh2tbl /usr/include/rpm/*.h > \$@
+RPMCONSTTBL
+ # This code is to reduce duplication of files
+ # in fact it is only usefull for the maintainers of this module
+ # if you get the module from CPAN, those files are allready here
+ # if you're building from svn, you need rpmconstant directory
+ my $second = "";
+ if(-d '../../rpmconstant') {
+ $second = <<RPMCONST
+rpmconstant.c: ../../rpmconstant/rpmconstant.c
+ cp -a \$< \$@
+
+rpmconstant.h: ../../rpmconstant/rpmconstant.h
+ cp -a \$< \$@
+
+rpmconstant_internal.c: ../../rpmconstant/rpmconstant_internal.c
+ cp -a \$< \$@
+
+rpmh2tbl: ../../rpmconstant/rpmh2tbl
+ cp -a \$< \$@
+RPMCONST
+ }
+
+ $first . $second
+}
+
+WriteMakefile(
+ NAME => 'RPM4',
+ VERSION_FROM => '../lib/RPM4.pm',
+ OBJECT => "RPM4.o RPM4sign.o $obj",
+ INC => '-I/usr/include/rpm',
+ LIBS => "-lrpm -lrpmio -lrpmdb -lrpmbuild -lpopt -lz -lbz2 $ldd",
+ 'CCFLAGS' => $fl,
+);
diff --git a/RPM4/src/RPM4.h b/RPM4/src/RPM4.h
new file mode 100644
index 0000000..fcad6b0
--- /dev/null
+++ b/RPM4/src/RPM4.h
@@ -0,0 +1,119 @@
+/* $Id$ */
+
+#ifndef _HDLIST_H
+#define _HDLIST_H
+
+#include "header.h"
+
+/* Hdlistsign.c: imported but modified functions */
+
+int rpmsign(char *passphrase, const char *rpm);
+
+int rpmchecksig(rpmts ts, const char * filename, int flags);
+
+/* rpmlib does not export some usefull functions
+ * We Import its here
+ * This File should be the last included */
+
+/* From rpmlead.h */
+
+#ifndef _H_RPMLEAD
+
+rpmRC writeLead(FD_t fd, const struct rpmlead *lead);
+rpmRC readLead(FD_t fd, struct rpmlead *lead);
+
+#endif /* _H_RPMLEAD */
+
+/* From signature.h */
+
+#ifndef H_SIGNATURE
+
+typedef enum sigType_e {
+ RPMSIGTYPE_HEADERSIG= 5
+} sigType;
+
+typedef enum pgpVersion_e {
+ PGP_NOTDETECTED = -1,
+ PGP_UNKNOWN = 0,
+ PGP_2 = 2,
+ PGP_5 = 5
+} pgpVersion;
+
+Header rpmNewSignature(void);
+
+rpmRC rpmReadSignature(FD_t fd, Header *sighp,
+ sigType sig_type, const char ** msg);
+
+int rpmWriteSignature(FD_t fd, Header h);
+
+int rpmAddSignature(Header sig, const char * file,
+ int_32 sigTag, const char * passPhrase);
+
+#define RPMLOOKUPSIG_QUERY 0 /*!< Lookup type in effect */
+#define RPMLOOKUPSIG_DISABLE 1 /*!< Disable (--sign was not given) */
+#define RPMLOOKUPSIG_ENABLE 2 /*!< Re-enable %_signature */
+
+int rpmLookupSignatureType(int action);
+
+char * rpmGetPassPhrase(const char * prompt,
+ const int sigTag);
+
+const char * rpmDetectPGPVersion(pgpVersion * pgpVer);
+
+#endif /* H_SIGNATURE */
+
+#ifndef H_HEADER_INTERNAL
+
+#ifdef HD_HEADER_INTERNAL
+/** \ingroup header
+ * Description of tag data.
+ */
+typedef /*@abstract@*/ struct entryInfo_s * entryInfo;
+struct entryInfo_s {
+ int_32 tag; /*!< Tag identifier. */
+ int_32 type; /*!< Tag data type. */
+ int_32 offset; /*!< Offset into data segment (ondisk only). */
+ int_32 count; /*!< Number of tag elements. */
+};
+
+/** \ingroup header
+ * A single tag from a Header.
+ */
+typedef /*@abstract@*/ struct indexEntry_s * indexEntry;
+struct indexEntry_s {
+ struct entryInfo_s info; /*!< Description of tag data. */
+/*@owned@*/
+ void * data; /*!< Location of tag data. */
+ int length; /*!< No. bytes of data. */
+ int rdlen; /*!< No. bytes of data in region. */
+};
+
+struct headerToken_s {
+ /*@unused@*/
+ struct HV_s hv; /*!< Header public methods. */
+ /*@only@*/ /*@null@*/
+ void * blob; /*!< Header region blob. */
+ /*@owned@*/
+ indexEntry index; /*!< Array of tags. */
+ int indexUsed; /*!< Current size of tag array. */
+ int indexAlloced; /*!< Allocated size of tag array. */
+ int flags;
+#define HEADERFLAG_SORTED (1 << 0) /*!< Are header entries sorted? */
+#define HEADERFLAG_ALLOCATED (1 << 1) /*!< Is 1st header region allocated? */
+#define HEADERFLAG_LEGACY (1 << 2) /*!< Header came from legacy source? */
+#define HEADERFLAG_DEBUG (1 << 3) /*!< Debug this header? */
+ /*@refs@*/
+ int nrefs; /*!< Reference count. */
+};
+#endif
+
+#endif /* H_HEADER_INTERNAL */
+
+#ifndef H_LEGACY
+
+void compressFilelist(Header h);
+void expandFilelist(Header h);
+
+#endif /* H_LEGACY */
+
+#endif
diff --git a/RPM4/src/RPM4.xs b/RPM4/src/RPM4.xs
new file mode 100644
index 0000000..77198e7
--- /dev/null
+++ b/RPM4/src/RPM4.xs
@@ -0,0 +1,2832 @@
+/* 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$ */
+
+/* PREPROSSEUR FLAGS
+ * HHACK: if defined, activate some functions or behaviour for expert user who
+ * want hacking purpose in their perl code
+ * HDLISTDEBUG: activate some debug code
+ * HDRPMDEBUG: activate rpm debug internals flags
+ * HDRPMMEM: print message about Free()/New on rpm
+ * HDEBUG: active all debug flags
+ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#undef Fflush
+#undef Mkdir
+#undef Stat
+
+/* copy data into rpm or use the header */
+#define O_SCAREMEM 1 /* If returning perl object */
+#define SCAREMEM 1
+
+/* Pre processor flags for debugging purpose */
+
+#ifdef HDEBUG
+ #undef HDLISTDEBUG
+ #define HDLISTDEBUG
+ #undef HDRPMDEBUG
+ #define HDRPMDEBUG
+ #undef HDRPMMEM
+ #define HDRPMMEM
+#endif
+
+#ifdef HDRPMMEM
+ #define PRINTF_FREE(o, a, r) fprintf(stderr, "HDEBUG FREE: %s[%p], %d at %s:%d\n", (o), (a), (r), CopFILE(PL_curcop), CopLINE(PL_curcop))
+ #define PRINTF_NEW(o, a, r) fprintf(stderr, "HDEBUG NEW : %s[%p], %d at %s:%d\n", (o), (a), (r), CopFILE(PL_curcop), CopLINE(PL_curcop))
+#endif
+
+#ifdef HDLISTDEBUG
+ #define PRINTF_CALL fprintf(stderr, "HDEBUG RUN: %s() at %s:%d\n", __FUNCTION__, CopFILE(PL_curcop), CopLINE(PL_curcop))
+#endif
+
+#if defined(HDRPMMEM) || defined(HDRPMDEBUG)
+ #define _RPMDS_INTERNAL
+ #define _RPMFI_INTERNAL
+ #define _RPMTS_INTERNAL
+ #define HD_HEADER_INTERNAL
+#endif
+
+#include <rpm/header.h>
+#include <rpm/rpmio.h>
+#include <rpm/rpmdb.h>
+#include <rpm/rpmts.h>
+#include <rpm/rpmte.h>
+#include <rpm/rpmps.h>
+#include <rpm/rpmds.h>
+#include <rpm/rpmfi.h>
+#include <rpm/rpmpgp.h>
+#include <rpm/misc.h>
+#include <rpm/rpmbuild.h>
+#include <rpm/rpmlib.h>
+#include <rpm/rpmpgp.h>
+
+#ifdef HAVE_RPMCONSTANT
+#include <rpmconstant/rpmconstant.h>
+#else
+#include "rpmconstant.h"
+#endif
+
+#include "RPM4.h"
+
+static unsigned char header_magic[8] = {
+ 0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
+};
+
+#define CHECK_RPMDS_IX(dep) if (rpmdsIx((dep)) < 0) croak("You call RPM4::Header::Dependencies method after lastest next() of before init()")
+
+#define bless_rpmds "RPM4::Header::Dependencies"
+#define bless_rpmps "RPM4::Db::_Problems"
+#define bless_rpmts "RPM4::Transaction"
+#define bless_header "RPM4::Header"
+#define bless_rpmfi "RPM4::Header::Files"
+#define bless_spec "RPM4::Spec"
+
+/* The perl callback for output err messages */
+SV * log_callback_function = NULL;
+
+static int scalar2constant(SV * svconstant, const char * context, int * val) {
+ int rc = 0;
+ if (!svconstant || !SvOK(svconstant)) {
+ warn("Use of an undefined value");
+ return 0;
+ } else if (SvIOK(svconstant)) {
+ *val = SvIV(svconstant);
+ rc = 1;
+ } else if (SvPOK(svconstant)) {
+ rc = rpmconstantFindName((char *)context, (void *) SvPV_nolen(svconstant), val, 0);
+ } else {
+ }
+ return rc;
+}
+
+static int sv2constant(SV * svconstant, const char * context) {
+ AV * avparam;
+ int val = 0;
+ SV **tmpsv;
+ int i;
+ if (svconstant == NULL) {
+ return 0;
+ } else if (!SvOK(svconstant)) {
+ return 0;
+ } else if (SvPOK(svconstant) || SvIOK(svconstant)) {
+ if (!scalar2constant(svconstant, context, &val))
+ warn("Unknow value '%s' in '%s'", SvPV_nolen(svconstant), context);
+ } else if (SvTYPE(SvRV(svconstant)) == SVt_PVAV) {
+ avparam = (AV*) SvRV(svconstant);
+ for (i = 0; i <= av_len(avparam); i++) {
+ tmpsv = av_fetch(avparam, i, 0);
+ if (!scalar2constant(*tmpsv, context, &val))
+ warn("Unknow value '%s' in '%s' from array", SvPV_nolen(*tmpsv), context);
+ }
+ } else {
+ }
+ return val;
+}
+
+/* Parse SV arg and return assossiated RPMLOG value */
+#define sv2loglevel(sv) sv2constant((sv), "rpmlog")
+
+#define sv2deptag(sv) sv2constant((sv), "rpmtag")
+
+/* compatibility */
+#define sv2sens(sv) sv2senseflags(sv)
+
+#define sv2vsflags(sv) sv2constant((sv), "rpmvsflags")
+
+#define sv2transflags(sv) sv2constant((sv), "rpmtransflags")
+
+static rpmTag sv2dbquerytag(SV * sv_tag) {
+ int val = 0;
+ if (!scalar2constant(sv_tag, "rpmdbi", &val) && !scalar2constant(sv_tag, "rpmtag", &val))
+ croak("unknown tag value '%s'", SvPV_nolen(sv_tag));
+ return val;
+}
+
+#define sv2rpmbuildflags(sv) sv2constant((sv), "rpmbuildflags")
+
+#define sv2fileattr(sv) sv2constant((sv), "rpmfileattrs")
+
+#define sv2senseflags(sv) sv2constant((sv), "rpmsenseflags")
+
+#define sv2tagtype(sv) sv2constant((sv), "rpmtagtype")
+
+/* This function replace the standard rpmShowProgress callback
+ * during transaction to allow perl callback */
+
+void * transCallback(const void *h,
+ const rpmCallbackType what,
+ const unsigned long amount,
+ const unsigned long total,
+ const void * pkgKey,
+ void * data) {
+
+ /* The call back is used to open/close file, so we fix value, run the perl callback
+ * and let rpmShowProgress from rpm rpmlib doing its job.
+ * This unsure we'll not have to follow rpm code at each change. */
+ const char * filename = (const char *)pkgKey;
+ const char * s_what = NULL;
+ dSP;
+
+#ifdef HDLISTDEBUG
+ fprintf(stderr, "HDEBUG: RPM4: running Callback transCallback()");
+#endif
+
+ PUSHMARK(SP);
+
+ switch (what) {
+ case RPMCALLBACK_UNKNOWN:
+ s_what = "UNKNOWN";
+ break;
+ case RPMCALLBACK_INST_OPEN_FILE:
+ if (filename != NULL && filename[0] != '\0') {
+ XPUSHs(sv_2mortal(newSVpv("filename", 0)));
+ XPUSHs(sv_2mortal(newSVpv(filename, 0)));
+ }
+ s_what = "INST_OPEN_FILE";
+ break;
+ case RPMCALLBACK_INST_CLOSE_FILE:
+ s_what = "INST_CLOSE_FILE";
+ break;
+ case RPMCALLBACK_INST_PROGRESS:
+ s_what = "INST_PROGRESS";
+ break;
+ case RPMCALLBACK_INST_START:
+ s_what = "INST_START";
+ if (h) {
+ XPUSHs(sv_2mortal(newSVpv("header", 0)));
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, &h)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_header, &h, -1);
+#endif
+ }
+ break;
+ case RPMCALLBACK_TRANS_PROGRESS:
+ s_what = "TRANS_PROGRESS";
+ break;
+ case RPMCALLBACK_TRANS_START:
+ s_what = "TRANS_START";
+ break;
+ case RPMCALLBACK_TRANS_STOP:
+ s_what = "TRANS_STOP";
+ break;
+ case RPMCALLBACK_UNINST_PROGRESS:
+ s_what = "UNINST_PROGRESS";
+ break;
+ case RPMCALLBACK_UNINST_START:
+ s_what = "UNINST_START";
+ break;
+ case RPMCALLBACK_UNINST_STOP:
+ s_what = "UNINST_STOP";
+ break;
+ case RPMCALLBACK_REPACKAGE_PROGRESS:
+ s_what = "REPACKAGE_PROGRESS";
+ break;
+ case RPMCALLBACK_REPACKAGE_START:
+ s_what = "REPACKAGE_START";
+ break;
+ case RPMCALLBACK_REPACKAGE_STOP:
+ s_what = "REPACKAGE_STOP";
+ break;
+ case RPMCALLBACK_UNPACK_ERROR:
+ s_what = "UNPACKAGE_ERROR";
+ break;
+ case RPMCALLBACK_CPIO_ERROR:
+ s_what = "CPIO_ERROR";
+ break;
+ }
+
+ XPUSHs(sv_2mortal(newSVpv("what", 0)));
+ XPUSHs(sv_2mortal(newSVpv(s_what, 0)));
+ XPUSHs(sv_2mortal(newSVpv("amount", 0)));
+ XPUSHs(sv_2mortal(newSViv(amount)));
+ XPUSHs(sv_2mortal(newSVpv("total", 0)));
+ XPUSHs(sv_2mortal(newSViv(total)));
+ PUTBACK;
+ call_sv((SV *) data, G_DISCARD | G_SCALAR);
+ SPAGAIN;
+
+ /* Running rpmlib callback, returning its value */
+ return rpmShowProgress(h,
+ what,
+ amount,
+ total,
+ pkgKey,
+ (long *) INSTALL_NONE /* shut up */);
+}
+
+/* This function is called by rpm if a callback
+ * is set for for the logging system.
+ * If the callback is set, rpm does not print any message,
+ * and let the callback to do it */
+void logcallback(void) {
+ dSP;
+ if (log_callback_function) {
+ int logcode = rpmlogCode();
+#ifdef HDLISTDEBUG
+ fprintf(stderr, "HDEBUG: RPM4: running Callback logcallback()");
+#endif
+
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(newSVpv("logcode", 0)));
+ XPUSHs(sv_2mortal(newSViv(logcode)));
+ XPUSHs(sv_2mortal(newSVpv("msg", 0)));
+ XPUSHs(sv_2mortal(newSVpv(rpmlogMessage(), 0)));
+ XPUSHs(sv_2mortal(newSVpv("priority", 0)));
+ XPUSHs(sv_2mortal(newSViv(RPMLOG_PRI(logcode))));
+ PUTBACK;
+ call_sv(log_callback_function, G_DISCARD | G_SCALAR);
+ SPAGAIN;
+ }
+}
+
+/* This callback is run during transcheck */
+int transSolveCallback(rpmts ts, rpmds Dep, const void * data) {
+ int rc = 0;
+ int count;
+ dSP;
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ /* Should return -1 retry, 0 ignore, 1 not found */
+ rc = rpmtsSolve(ts, Dep, data);
+ /* PUSHMARK(SP); */
+ if (ts) {
+ XPUSHs(sv_2mortal(newSVpv("db", 0)));
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmts, rpmtsLink(ts, "RPM4 transSolveCallback()"))));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmts, ts, ts->nrefs);
+#endif
+
+ }
+ if (Dep) {
+ XPUSHs(sv_2mortal(newSVpv("dep", 0)));
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmds, rpmdsLink(Dep, "RPM4 transSolveCallback()"))));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmds, Dep, Dep->nrefs);
+#endif
+ }
+ XPUSHs(sv_2mortal(newSVpv("rc", 0)));
+ XPUSHs(sv_2mortal(newSViv(rc)));
+ PUTBACK;
+ count = call_sv((SV *) data, G_SCALAR);
+ SPAGAIN;
+ if (count) {
+ rc = POPi;
+ if (rc < -1 || rc > 1)
+ croak("Uh Oh! Your perl callback should return 1 (retry), 0 (ignore) or 1 (not found) and not %d", rc);
+ } else {
+ rc = 1;
+ }
+ return rc;
+}
+
+/**************************************************
+ * Real Function rpmts function with double call *
+ * Aka function(arg) or RPM4::Db->function(arg) *
+ * This permit to reuse existing rpmts object *
+ **************************************************/
+
+void _rpm2header(rpmts ts, char * filename, int checkmode) {
+ FD_t fd;
+ Header ret = NULL;
+ rpmRC rc;
+ dSP;
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ if ((fd = Fopen(filename, "r"))) {
+ rc = rpmReadPackageFile(ts, fd, filename, &ret);
+ if (checkmode) {
+ XPUSHs(sv_2mortal(newSViv(rc)));
+ ret = headerFree(ret); /* For checking the package, we don't keep the header */
+ } else {
+ if (rc == 0) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, (void *)ret)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_header, ret, ret->nrefs);
+#endif
+ } else {
+ XPUSHs(sv_2mortal(&PL_sv_undef));
+ }
+ }
+ Fclose(fd);
+ } else {
+ XPUSHs(sv_2mortal(&PL_sv_undef));
+ }
+
+ PUTBACK;
+ return;
+}
+
+void _newdep(SV * sv_deptag, char * name, SV * sv_sense, SV * sv_evr) {
+ rpmTag deptag = 0;
+ rpmsenseFlags sense = RPMSENSE_ANY;
+ rpmds Dep;
+ char * evr = NULL;
+ dSP;
+
+ if (sv_deptag && SvOK(sv_deptag))
+ deptag = sv2deptag(sv_deptag);
+ if (sv_sense && SvOK(sv_sense))
+ sense = sv2sens(sv_sense);
+ if (sv_evr && SvOK(sv_evr))
+ evr = SvPV_nolen(sv_evr);
+ Dep = rpmdsSingle(deptag,
+ name,
+ evr ? evr : "", sense);
+ if (Dep) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmds, Dep)));
+ }
+ PUTBACK;
+}
+
+/* Get a new specfile */
+void _newspec(rpmts ts, char * filename, SV * svpassphrase, SV * svrootdir, SV * svcookies, SV * svanyarch, SV * svforce) {
+ Spec spec = NULL;
+ char * passphrase = NULL;
+ char * rootdir = NULL;
+ char * cookies = NULL;
+ int anyarch = 0;
+ int force = 0;
+
+ if (svpassphrase && SvOK(svpassphrase))
+ passphrase = SvPV_nolen(svpassphrase);
+
+ if (svrootdir && SvOK(svrootdir))
+ rootdir = SvPV_nolen(svrootdir);
+ else
+ rootdir = "/";
+
+ if (svcookies && SvOK(svcookies))
+ cookies = SvPV_nolen(svcookies);
+
+ if (svanyarch && SvOK(svanyarch))
+ anyarch = SvIV(svanyarch);
+
+ if (svforce && SvOK(svforce))
+ force = SvIV(svforce);
+
+ dSP;
+ if (filename) {
+ if (!parseSpec(ts, filename, rootdir, NULL, 0, passphrase, cookies, anyarch, force))
+ spec = rpmtsSetSpec(ts, NULL);
+#ifdef HHACK
+ } else {
+ spec = newSpec();
+#endif
+ }
+ if (spec) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_spec, (void *)spec)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_spec, spec, -1);
+#endif
+ } else
+ XPUSHs(sv_2mortal(&PL_sv_undef));
+ PUTBACK;
+ return;
+}
+
+/* Building a spec file */
+int _specbuild(rpmts ts, Spec spec, SV * sv_buildflags) {
+ rpmBuildFlags buildflags = sv2rpmbuildflags(sv_buildflags);
+ if (buildflags == RPMBUILD_NONE) croak("No action given for build");
+ return buildSpec(ts, spec, buildflags, 0);
+}
+
+void _installsrpms(rpmts ts, char * filename) {
+ const char * specfile = NULL;
+ const char * cookies = NULL;
+ dSP;
+ if (rpmInstallSource(
+ ts,
+ filename,
+ &specfile,
+ &cookies) == 0) {
+ XPUSHs(sv_2mortal(newSVpv(specfile, 0)));
+ XPUSHs(sv_2mortal(newSVpv(cookies, 0)));
+ }
+ PUTBACK;
+}
+
+int _header_vs_dep(Header h, rpmds dep, int nopromote) {
+ CHECK_RPMDS_IX(dep);
+ return rpmdsAnyMatchesDep(h, dep, nopromote);
+ /* return 1 if match */
+}
+
+int _headername_vs_dep(Header h, rpmds dep, int nopromote) {
+ char *name; int type;
+ int rc = 0;
+ CHECK_RPMDS_IX(dep);
+ headerGetEntry(h, RPMTAG_NAME, &type, (void **) &name, NULL);
+ if (strcmp(name, rpmdsN(dep)) != 0)
+ rc = 0;
+ else
+ rc = rpmdsNVRMatchesDep(h, dep, nopromote);
+ headerFreeData(name, type);
+ return rc;
+ /* return 1 if match */
+}
+
+MODULE = RPM4 PACKAGE = RPM4
+
+BOOT:
+if (rpmReadConfigFiles(NULL, NULL) != 0)
+ croak("Can't read configuration");
+#ifdef HDLISTDEBUG
+rpmSetVerbosity(RPMMESS_DEBUG);
+#else
+rpmSetVerbosity(RPMMESS_NORMAL);
+#endif
+#ifdef HDRPMDEBUG
+_rpmds_debug = -1;
+_rpmdb_debug = -1;
+_rpmts_debug = -1;
+_rpmfi_debug = -1;
+_rpmte_debug = -1;
+#endif
+
+int
+isdebug()
+ CODE:
+#ifdef HDLISTDEBUG
+ RETVAL = 1;
+#else
+ RETVAL = 0;
+#endif
+ OUTPUT:
+ RETVAL
+
+void
+moduleinfo()
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv("Hack", 0)));
+#ifdef HHACK
+ XPUSHs(sv_2mortal(newSVpv("Yes", 0)));
+#else
+ XPUSHs(sv_2mortal(newSVpv("No", 0)));
+#endif
+ XPUSHs(sv_2mortal(newSVpv("RPMVERSION", 0)));
+ XPUSHs(sv_2mortal(newSVpv("RPMVERSION", 0)));
+ XPUSHs(sv_2mortal(newSVpv(RPMVERSION, 0)));
+ XPUSHs(sv_2mortal(newSVpv("RPM4VERSION", 0)));
+ XPUSHs(sv_2mortal(newSVpv(VERSION, 0)));
+ XPUSHs(sv_2mortal(newSVpv("RPMNAME", 0)));
+ XPUSHs(sv_2mortal(newSVpv(rpmNAME, 0)));
+ XPUSHs(sv_2mortal(newSVpv("RPMEVR", 0)));
+ XPUSHs(sv_2mortal(newSVpv(rpmEVR, 0)));
+
+# Functions to control log/verbosity
+
+void
+setverbosity(svlevel)
+ SV * svlevel
+ CODE:
+ rpmSetVerbosity(sv2loglevel(svlevel));
+
+void
+setlogcallback(function)
+ SV * function
+ CODE:
+ if (function == NULL || !SvOK(function)) {
+ rpmlogSetCallback(NULL);
+ } else if (SvTYPE(SvRV(function)) == SVt_PVCV) {
+ log_callback_function = newSVsv(function);
+ rpmlogSetCallback(logcallback);
+ } else
+ croak("First arg is not a code reference");
+
+void
+lastlogmsg()
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmlogCode())));
+ XPUSHs(sv_2mortal(newSVpv(rpmlogMessage(), 0)));
+
+int
+setlogfile(filename)
+ char * filename
+ PREINIT:
+ FILE * ofp = NULL;
+ FILE * fp = NULL;
+ CODE:
+ if (filename && *filename != 0) {
+ if ((fp = fopen(filename, "a+")) == NULL) {
+ XSprePUSH; PUSHi((IV)0);
+ XSRETURN(1);
+ }
+ }
+ if((ofp = rpmlogSetFile(fp)) != NULL)
+ fclose(ofp);
+ RETVAL=1;
+ OUTPUT:
+ RETVAL
+
+int
+readconfig(rcfile = NULL, target = NULL)
+ char * rcfile
+ char * target
+ CODE:
+ RETVAL = rpmReadConfigFiles(rcfile, target);
+ OUTPUT:
+ RETVAL
+
+void
+rpmlog(svcode, msg)
+ SV * svcode
+ char * msg
+ CODE:
+ rpmlog(sv2loglevel(svcode), "%s", msg);
+
+# Return hash of know tag
+# Name => internal key (if available)
+
+void
+querytag()
+ PREINIT:
+ int i = 0;
+ const struct headerSprintfExtension_s * ext = rpmHeaderFormats;
+ PPCODE:
+ for (i = 0; i < rpmTagTableSize; i++) {
+ XPUSHs(sv_2mortal(newSVpv(rpmTagTable[i].name + 7, 0)));
+ XPUSHs(sv_2mortal(newSViv(rpmTagTable[i].val)));
+ }
+
+ while (ext->name != NULL) {
+ if (ext->type == HEADER_EXT_MORE) {
+ ext = ext->u.more;
+ continue;
+ }
+ for (i = 0; i < rpmTagTableSize; i++) {
+ if (!strcmp(rpmTagTable[i].name, ext->name))
+ break;
+ }
+ if (i >= rpmTagTableSize && ext->type == HEADER_EXT_TAG) {
+ XPUSHs(sv_2mortal(newSVpv(ext->name + 7, 0)));
+ XPUSHs(sv_newmortal());
+ }
+ ext++;
+ }
+
+int
+tagtypevalue(svtagtype)
+ SV * svtagtype
+ CODE:
+ RETVAL = sv2tagtype(svtagtype);
+ OUTPUT:
+ RETVAL
+
+int
+tagValue(tagname)
+ char * tagname
+ CODE:
+ RETVAL = tagValue((const char *) tagname);
+ OUTPUT:
+ RETVAL
+
+void
+tagName(tag)
+ int tag
+ PREINIT:
+ const char *r = NULL;
+ PPCODE:
+ r = tagName(tag);
+ XPUSHs(sv_2mortal(newSVpv(r, 0)));
+
+void
+flagvalue(flagtype, sv_value)
+ char * flagtype
+ SV * sv_value
+ PPCODE:
+ if (strcmp(flagtype, "loglevel") == 0) {
+ XPUSHs(sv_2mortal(newSViv(sv2constant(sv_value, "rpmlog"))));
+ } else if (strcmp(flagtype, "deptag") == 0) { /* Who will use this ?? */
+ XPUSHs(sv_2mortal(newSViv(sv2deptag(sv_value))));
+ } else if (strcmp(flagtype, "vsf") == 0) {
+ XPUSHs(sv_2mortal(newSViv(sv2constant(sv_value, "rpmverifyflags"))));
+ } else if (strcmp(flagtype, "trans") == 0) {
+ XPUSHs(sv_2mortal(newSViv(sv2transflags(sv_value))));
+ } else if (strcmp(flagtype, "dbquery") == 0) {
+ XPUSHs(sv_2mortal(newSViv(sv2dbquerytag(sv_value))));
+ } else if (strcmp(flagtype, "build") == 0) {
+ XPUSHs(sv_2mortal(newSViv(sv2rpmbuildflags(sv_value))));
+ } else if (strcmp(flagtype, "fileattr") == 0) {
+ XPUSHs(sv_2mortal(newSViv(sv2fileattr(sv_value))));
+ } else if (strcmp(flagtype, "sense") == 0) {
+ XPUSHs(sv_2mortal(newSViv(sv2senseflags(sv_value))));
+ } else if (strcmp(flagtype, "tagtype") == 0) {
+ XPUSHs(sv_2mortal(newSViv(sv2tagtype(sv_value))));
+ } else if (strcmp(flagtype, "list") == 0) {
+ XPUSHs(sv_2mortal(newSVpv("loglevel", 0)));
+ XPUSHs(sv_2mortal(newSVpv("deptag", 0)));
+ XPUSHs(sv_2mortal(newSVpv("vsf", 0)));
+ XPUSHs(sv_2mortal(newSVpv("trans", 0)));
+ XPUSHs(sv_2mortal(newSVpv("dbquery", 0)));
+ XPUSHs(sv_2mortal(newSVpv("build", 0)));
+ XPUSHs(sv_2mortal(newSVpv("fileattr", 0)));
+ XPUSHs(sv_2mortal(newSVpv("tagtype", 0)));
+ }
+
+# Macros functions:
+
+void
+expand(name)
+ char * name
+ PPCODE:
+ const char * value = rpmExpand(name, NULL);
+ XPUSHs(sv_2mortal(newSVpv(value, 0)));
+
+void
+expandnumeric(name)
+ char *name
+ PPCODE:
+ int value = rpmExpandNumeric(name);
+ XPUSHs(sv_2mortal(newSViv(value)));
+
+void
+add_macro(macro)
+ char * macro
+ CODE:
+ rpmDefineMacro(NULL, macro, RMIL_DEFAULT);
+
+void
+del_macro(name)
+ char * name
+ CODE:
+ delMacro(NULL, name);
+
+void
+loadmacrosfile(filename)
+ char * filename
+ PPCODE:
+ rpmInitMacros(NULL, filename);
+
+void
+resetmacros()
+ PPCODE:
+ rpmFreeMacros(NULL);
+
+void
+resetrc()
+ PPCODE:
+ rpmFreeRpmrc();
+
+void
+getosname()
+ PREINIT:
+ const char *v = NULL;
+ PPCODE:
+ rpmGetOsInfo(&v, NULL);
+ XPUSHs(sv_2mortal(newSVpv(v, 0)));
+
+void
+getarchname()
+ PREINIT:
+ const char *v = NULL;
+ PPCODE:
+ rpmGetArchInfo(&v, NULL);
+ XPUSHs(sv_2mortal(newSVpv(v, 0)));
+
+int
+osscore(os, build = 0)
+ char * os
+ int build;
+ PREINIT:
+ int machtable;
+ CODE:
+ machtable = build ? RPM_MACHTABLE_BUILDOS : RPM_MACHTABLE_INSTOS;
+ RETVAL = rpmMachineScore(machtable, os);
+ OUTPUT:
+ RETVAL
+
+int
+archscore(arch, build = 0)
+ char * arch
+ int build;
+ PREINIT:
+ int machtable;
+ CODE:
+ machtable = build ? RPM_MACHTABLE_BUILDARCH : RPM_MACHTABLE_INSTARCH;
+ RETVAL = rpmMachineScore(machtable, arch);
+ OUTPUT:
+ RETVAL
+
+void
+buildhost()
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(buildHost(),0)));
+
+# Dump to file functions:
+void
+dumprc(fp)
+ FILE *fp
+ CODE:
+ rpmShowRC(fp);
+
+void
+dumpmacros(fp)
+ FILE *fp
+ CODE:
+ rpmDumpMacroTable(NULL, fp);
+
+int
+rpmvercmp(one, two)
+ char *one
+ char *two
+
+# create a new empty header
+# Is this usefull
+
+void
+headernew()
+ PREINIT:
+ Header h = headerNew();
+ PPCODE:
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, (void *)h)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_header, h, h->nrefs);
+#endif
+
+
+# Read data from file pointer and return next header object
+# Return undef if failed
+# fedora use HEADER_MAGIC_NO, too bad, set no_header_magic make the function
+# compatible
+void
+stream2header(fp, no_header_magic = 0, callback = NULL)
+ FILE *fp
+ int no_header_magic
+ SV * callback
+ PREINIT:
+ FD_t fd;
+ Header header;
+ PPCODE:
+ if (fp && (fd = fdDup(fileno(fp)))) {
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ if (callback != NULL && SvROK(callback)) {
+ while ((header = headerRead(fd, no_header_magic ? HEADER_MAGIC_NO : HEADER_MAGIC_YES))) {
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, (void *)header)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_header, header, header->nrefs);
+#endif
+ PUTBACK;
+ call_sv(callback, G_DISCARD | G_SCALAR);
+ SPAGAIN;
+ FREETMPS;
+ LEAVE;
+ }
+ } else {
+ header = headerRead(fd, no_header_magic ? HEADER_MAGIC_NO : HEADER_MAGIC_YES);
+ if (header) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, (void *)header)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_header, header, header->nrefs);
+#endif
+
+ }
+#ifdef HDLISTDEBUG
+ else fprintf(stderr, "HDEBUG: No header found from fp: %d\n", fileno(fp));
+#endif
+ }
+ Fclose(fd);
+ }
+
+# Read a rpm and return a Header
+# Return undef if failed
+void
+rpm2header(filename, sv_vsflags = NULL)
+ char * filename
+ SV * sv_vsflags
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ rpmVSFlags vsflags = RPMVSF_DEFAULT;
+ PPCODE:
+ if (sv_vsflags == NULL) /* Nothing has been passed, default is no signature */
+ vsflags |= _RPMVSF_NOSIGNATURES;
+ else
+ vsflags = sv2vsflags(sv_vsflags);
+ rpmtsSetVSFlags(ts, vsflags);
+ _rpm2header(ts, filename, 0);
+ SPAGAIN;
+ ts = rpmtsFree(ts);
+
+int
+rpmresign(passphrase, rpmfile)
+ char * passphrase
+ char * rpmfile
+ CODE:
+ RETVAL = rpmsign(passphrase, (const char *) rpmfile);
+ OUTPUT:
+ RETVAL
+
+void
+installsrpm(filename, sv_vsflags = NULL)
+ char * filename
+ SV * sv_vsflags
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ rpmVSFlags vsflags = RPMVSF_DEFAULT;
+ PPCODE:
+ vsflags = sv2vsflags(sv_vsflags);
+ rpmtsSetVSFlags(ts, vsflags);
+ PUTBACK;
+ _installsrpms(ts, filename);
+ SPAGAIN;
+ ts = rpmtsFree(ts);
+
+MODULE = RPM4 PACKAGE = RPM4::Header PREFIX = Header_
+
+void
+Header_DESTROY(h)
+ Header h
+ CODE:
+#ifdef HDRPMMEM
+ PRINTF_FREE(bless_header, h, h->nrefs);
+#endif
+ headerFree(h);
+
+# Write rpm header into file pointer
+# fedora use HEADER_MAGIC_NO, too bad, set no_header_magic make the function
+# compatible
+int
+Header_write(h, fp, no_header_magic = 0)
+ Header h
+ FILE * fp
+ int no_header_magic
+ PREINIT:
+ FD_t fd;
+ CODE:
+ RETVAL = 0;
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ if (h) {
+ if ((fd = fdDup(fileno(fp))) != NULL) {
+ headerWrite(fd, h, no_header_magic ? HEADER_MAGIC_NO : HEADER_MAGIC_YES);
+ Fclose(fd);
+ RETVAL = 1;
+ }
+ }
+ OUTPUT:
+ RETVAL
+
+void
+Header_hsize(h, no_header_magic = 0)
+ Header h
+ int no_header_magic
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(headerSizeof(h, no_header_magic ? HEADER_MAGIC_NO : HEADER_MAGIC_YES))));
+
+void
+Header_copy(h)
+ Header h
+ PREINIT:
+ Header hcopy;
+ PPCODE:
+ hcopy = headerCopy(h);
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, (void *)hcopy)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_header, hcopy, hcopy->nrefs);
+#endif
+
+void
+Header_string(h, no_header_magic = 0)
+ Header h
+ int no_header_magic
+ PREINIT:
+ char * string = NULL;
+ int offset = 0;
+ void * ptr = NULL;
+ int hsize = 0;
+ PPCODE:
+ ptr = headerUnload(h);
+ hsize = headerSizeof(h, no_header_magic ? HEADER_MAGIC_NO : HEADER_MAGIC_YES);
+ string = malloc(hsize);
+ if (!no_header_magic) {
+ memcpy(string, header_magic, sizeof(header_magic));
+ offset = sizeof(header_magic);
+ }
+ memcpy(string + offset, ptr, headerSizeof(h, HEADER_MAGIC_NO));
+ PUSHs(sv_2mortal(newSVpv((char *)string, hsize)));
+ free(ptr);
+
+
+int
+Header_removetag(h, sv_tag)
+ Header h
+ SV * sv_tag
+ PREINIT:
+ rpmTag tag = -1;
+ CODE:
+ if (SvIOK(sv_tag)) {
+ tag = SvIV(sv_tag);
+ } else if (SvPOK(sv_tag)) {
+ tag = tagValue(SvPV_nolen(sv_tag));
+ }
+ if (tag > 0)
+ RETVAL = headerRemoveEntry(h, tag);
+ else
+ RETVAL = 1;
+ OUTPUT:
+ RETVAL
+
+int
+Header_addtag(h, sv_tag, sv_tagtype, ...)
+ Header h
+ SV * sv_tag
+ SV * sv_tagtype
+ PREINIT:
+ char * value;
+ int ivalue;
+ int i;
+ rpmTag tag = -1;
+ rpmTagType tagtype = RPM_NULL_TYPE;
+ STRLEN len;
+ CODE:
+ if (SvIOK(sv_tag)) {
+ tag = SvIV(sv_tag);
+ } else if (SvPOK(sv_tag)) {
+ tag = tagValue(SvPV_nolen(sv_tag));
+ }
+ tagtype = sv2tagtype(sv_tagtype);
+ if (tag > 0)
+ RETVAL = 1;
+ else
+ RETVAL = 0;
+ if (tag == RPMTAG_OLDFILENAMES)
+ expandFilelist(h);
+ for (i = 3; (i < items) && RETVAL; i++) {
+ switch (tagtype) {
+ case RPM_CHAR_TYPE:
+ case RPM_INT8_TYPE:
+ case RPM_INT16_TYPE:
+ case RPM_INT32_TYPE:
+ ivalue = SvUV(ST(i));
+ RETVAL = headerAddOrAppendEntry(h, tag, tagtype, &ivalue, 1);
+ break;
+ case RPM_BIN_TYPE:
+ value = (char *)SvPV(ST(i), len);
+ RETVAL = headerAddEntry(h, tag, tagtype, value, len);
+ break;
+ case RPM_STRING_ARRAY_TYPE:
+ value = SvPV_nolen(ST(i));
+ RETVAL = headerAddOrAppendEntry(h, tag, tagtype, &value, 1);
+ break;
+ default:
+ value = SvPV_nolen(ST(i));
+ RETVAL = headerAddOrAppendEntry(h, tag, tagtype, value, 1);
+ break;
+ }
+ }
+ if (tag == RPMTAG_OLDFILENAMES) {
+ compressFilelist(h);
+ }
+ OUTPUT:
+ RETVAL
+
+void
+Header_listtag(h)
+ Header h
+ PREINIT:
+ HeaderIterator iterator;
+ int tag;
+ PPCODE:
+ iterator = headerInitIterator(h);
+ while (headerNextIterator(iterator, &tag, NULL, NULL, NULL)) {
+ XPUSHs(sv_2mortal(newSViv(tag)));
+ }
+ headerFreeIterator(iterator);
+
+int
+Header_hastag(h, sv_tag)
+ Header h
+ SV * sv_tag
+ PREINIT:
+ rpmTag tag = -1;
+ CODE:
+ if (SvIOK(sv_tag)) {
+ tag = SvIV(sv_tag);
+ } else if (SvPOK(sv_tag)) {
+ tag = tagValue(SvPV_nolen(sv_tag));
+ }
+ if (tag > 0)
+ RETVAL = headerIsEntry(h, tag);
+ else
+ RETVAL = -1;
+ OUTPUT:
+ RETVAL
+
+# Return the tag value in headers
+void
+Header_tag(h, sv_tag)
+ Header h
+ SV * sv_tag
+ PREINIT:
+ void *ret = NULL;
+ int type;
+ int n;
+ rpmTag tag = -1;
+ PPCODE:
+ if (SvIOK(sv_tag)) {
+ tag = SvIV(sv_tag);
+ } else if (SvPOK(sv_tag)) {
+ tag = tagValue(SvPV_nolen(sv_tag));
+ }
+ if (tag > 0)
+ if (headerGetEntry(h, tag, &type, &ret, &n)) {
+ switch(type) {
+ case RPM_STRING_ARRAY_TYPE:
+ {
+ int i;
+ char **s;
+
+ EXTEND(SP, n);
+ s = (char **)ret;
+
+ for (i = 0; i < n; i++) {
+ PUSHs(sv_2mortal(newSVpv(s[i], 0)));
+ }
+ }
+ break;
+ case RPM_STRING_TYPE:
+ PUSHs(sv_2mortal(newSVpv((char *)ret, 0)));
+ break;
+ case RPM_CHAR_TYPE:
+ case RPM_INT8_TYPE:
+ case RPM_INT16_TYPE:
+ case RPM_INT32_TYPE:
+ {
+ int i;
+ int *r;
+
+ EXTEND(SP, n);
+ r = (int *)ret;
+
+ for (i = 0; i < n; i++) {
+ PUSHs(sv_2mortal(newSViv(r[i])));
+ }
+ }
+ break;
+ case RPM_BIN_TYPE:
+ PUSHs(sv_2mortal(newSVpv((char *)ret, n)));
+ break;
+ default:
+ croak("unknown rpm tag type %d", type);
+ }
+ }
+ headerFreeTag(h, ret, type);
+
+int
+Header_tagtype(h, sv_tag)
+ Header h
+ SV * sv_tag
+ PREINIT:
+ int type;
+ rpmTag tag = -1;
+ CODE:
+ if (SvIOK(sv_tag)) {
+ tag = SvIV(sv_tag);
+ } else if (SvPOK(sv_tag)) {
+ tag = tagValue(SvPV_nolen(sv_tag));
+ }
+ RETVAL = RPM_NULL_TYPE;
+ if (tag > 0)
+ if (headerGetEntry(h, tag, &type, NULL, NULL))
+ RETVAL = type;
+ OUTPUT:
+ RETVAL
+
+void
+Header_queryformat(h, query)
+ Header h
+ char * query
+ PREINIT:
+ char *s = NULL;
+ PPCODE:
+ s = headerSprintf(h, query,
+ rpmTagTable, rpmHeaderFormats, NULL);
+ if (s) {
+ char * cs = NULL;
+ int len = strlen(s);
+
+ cs = malloc(strlen(s)); /* TODO need to check return of malloc */
+ memcpy(cs, s, len);
+ XPUSHs(sv_2mortal(newSVpv(cs, len)));
+ }
+ _free(s);
+
+void
+Header_fullname(h)
+ Header h
+ PREINIT:
+ I32 gimme = GIMME_V;
+ char *name;
+ char *version;
+ char *release;
+ char *arch;
+ PPCODE:
+ if (h) {
+ headerGetEntry(h, RPMTAG_NAME, NULL, (void *) &name, NULL);
+ headerGetEntry(h, RPMTAG_VERSION, NULL, (void *) &version, NULL);
+ headerGetEntry(h, RPMTAG_RELEASE, NULL, (void *) &release, NULL);
+ headerGetEntry(h, RPMTAG_ARCH, NULL, (void *) &arch, NULL);
+
+ if (gimme == G_SCALAR) {
+ XPUSHs(sv_2mortal(newSVpvf("%s-%s-%s.%s",
+ name,
+ version,
+ release,
+ headerIsEntry(h, RPMTAG_SOURCEPACKAGE) ? "src" : arch
+ )));
+ } else if (gimme == G_ARRAY) {
+ EXTEND(SP, 4);
+ PUSHs(sv_2mortal(newSVpv(name, 0)));
+ PUSHs(sv_2mortal(newSVpv(version, 0)));
+ PUSHs(sv_2mortal(newSVpv(release, 0)));
+ if (headerIsEntry(h, RPMTAG_SOURCEPACKAGE)) {
+ PUSHs(sv_2mortal(newSVpv("src", 0)));
+ } else {
+ PUSHs(sv_2mortal(newSVpv(arch, 0)));
+ }
+ }
+ }
+ headerFreeTag(h, name, RPM_STRING_TYPE);
+ headerFreeTag(h, version, RPM_STRING_TYPE);
+ headerFreeTag(h, release, RPM_STRING_TYPE);
+ headerFreeTag(h, arch, RPM_STRING_TYPE);
+
+void
+Header_nevr(header)
+ Header header
+ PPCODE:
+ PUSHs(sv_2mortal(newSVpv(hGetNEVR(header, NULL), 0)));
+
+int
+Header_issrc(h)
+ Header h
+ CODE:
+ RETVAL = headerIsEntry(h, RPMTAG_SOURCEPACKAGE);
+ OUTPUT:
+ RETVAL
+
+# Dependancies versions functions
+
+int
+Header_compare(h1, h2)
+ Header h1
+ Header h2
+ CODE:
+ RETVAL = rpmVersionCompare(h1, h2);
+ OUTPUT:
+ RETVAL
+
+void
+Header_dep(header, type, scaremem = O_SCAREMEM)
+ Header header
+ SV * type
+ int scaremem
+ PREINIT:
+ rpmds ds;
+ rpmTag tag;
+ PPCODE:
+ tag = sv2deptag(type);
+ ds = rpmdsNew(header, tag, scaremem);
+ ds = rpmdsInit(ds);
+ if (ds != NULL)
+ if (rpmdsNext(ds) >= 0) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmds, ds)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmds, ds, ds->nrefs);
+#endif
+
+ }
+
+void
+Header_files(header, scaremem = O_SCAREMEM)
+ Header header
+ int scaremem
+ PREINIT:
+ rpmfi Files;
+ rpmts ts = NULL; /* setting this to NULL skip path relocation
+ * maybe a good deal is Header::Files(header, Dep = NULL) */
+ PPCODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ Files = rpmfiNew(ts, header, RPMTAG_BASENAMES, scaremem);
+ if ((Files = rpmfiInit(Files, 0)) != NULL && rpmfiNext(Files) >= 0) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmfi, Files)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmfi, Files, Files->nrefs);
+#endif
+ }
+
+void
+Header_hchkdep(h1, h2, type)
+ Header h1
+ Header h2
+ SV * type
+ PREINIT:
+ rpmds ds = NULL;
+ rpmds pro = NULL;
+ rpmTag tag;
+ PPCODE:
+ tag = sv2deptag(type);
+ ds = rpmdsNew(h1, tag, SCAREMEM);
+ pro = rpmdsNew(h2, RPMTAG_PROVIDENAME, SCAREMEM);
+#ifdef HDLISTDEBUG
+ fprintf(stderr, "HDEBUG: Header::hchkdep %d: %s vs %s %p\n", tag, hGetNEVR(h1, NULL), hGetNEVR(h2, NULL), ds);
+#endif
+ if (ds != NULL) {
+ rpmdsInit(ds);
+ while (rpmdsNext(ds) >= 0) {
+ rpmdsInit(pro);
+ while (rpmdsNext(pro) >= 0) {
+ if (rpmdsCompare(ds,pro)) {
+ XPUSHs(sv_2mortal(newSVpv(rpmdsDNEVR(ds), 0)));
+#ifdef HDLISTDEBUG
+ fprintf(stderr, "HDEBUG: Header::hchkdep match %s %s p in %s\n", rpmdsDNEVR(ds), rpmdsDNEVR(pro), hGetNEVR(h2, NULL));
+#endif
+ break;
+ }
+ }
+ }
+ }
+ pro = rpmdsFree(pro);
+ ds = rpmdsFree(ds);
+
+int
+Header_matchdep(header, Dep, sv_nopromote = NULL)
+ Header header
+ SV * sv_nopromote
+ rpmds Dep
+ PREINIT:
+ int nopromote = 0;
+ CODE:
+ if (sv_nopromote != NULL)
+ nopromote = SvIV(sv_nopromote);
+ RETVAL = _header_vs_dep(header, Dep, nopromote);
+ OUTPUT:
+ RETVAL
+
+int
+Header_namematchdep(header, Dep, sv_nopromote = NULL)
+ Header header
+ rpmds Dep
+ SV * sv_nopromote
+ PREINIT:
+ int nopromote = 0;
+ CODE:
+ if (sv_nopromote != NULL)
+ nopromote = SvIV(sv_nopromote);
+ RETVAL = _headername_vs_dep(header, Dep, nopromote); /* return 1 if match */
+ OUTPUT:
+ RETVAL
+
+# DB functions
+MODULE = RPM4 PACKAGE = RPM4
+
+int
+rpmdbinit(rootdir = NULL)
+ char * rootdir
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ CODE:
+ if (rootdir)
+ rpmtsSetRootDir(ts, rootdir);
+ /* rpm{db,ts}init is deprecated, we open a database with create flags
+ * and close it */
+ /* 0 on success */
+ RETVAL = rpmtsOpenDB(ts, O_CREAT);
+ ts = rpmtsFree(ts);
+ OUTPUT:
+ RETVAL
+
+int
+rpmdbverify(rootdir = NULL)
+ char * rootdir
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ CODE:
+ if (rootdir)
+ rpmtsSetRootDir(ts, rootdir);
+ /* 0 on success */
+ RETVAL = rpmtsVerifyDB(ts);
+ ts = rpmtsFree(ts);
+ OUTPUT:
+ RETVAL
+
+int
+rpmdbrebuild(rootdir = NULL)
+ char * rootdir
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ CODE:
+ if (rootdir)
+ rpmtsSetRootDir(ts, rootdir);
+ /* 0 on success */
+ RETVAL = rpmtsRebuildDB(ts);
+ ts = rpmtsFree(ts);
+ OUTPUT:
+ RETVAL
+
+#ifdef HHACK
+void
+emptydb()
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ PPCODE:
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmts, (void *)ts)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmts, ts, ts->nrefs);
+#endif
+
+
+#endif
+
+void
+newdb(write = 0, rootdir = NULL)
+ int write
+ char * rootdir
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ PPCODE:
+ if (rootdir)
+ rpmtsSetRootDir(ts, rootdir);
+
+ rpmtsSetVSFlags(ts, RPMTRANS_FLAG_NONE);
+ /* is O_CREAT a good idea here ? */
+ /* is the rpmtsOpenDB really need ? */
+ if (rpmtsOpenDB(ts, write ? O_RDWR | O_CREAT : O_RDONLY) == 0) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmts, (void *)ts)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmts, ts, ts->nrefs);
+#endif
+ } else {
+ ts = rpmtsFree(ts);
+ }
+
+MODULE = RPM4 PACKAGE = RPM4::Transaction PREFIX = Ts_
+
+void
+Ts_new(perlclass, rootdir = NULL)
+ char * perlclass
+ char * rootdir
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ PPCODE:
+ if (rootdir)
+ rpmtsSetRootDir(ts, rootdir);
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), perlclass, (void *)ts)));
+
+void
+Ts_DESTROY(ts)
+ rpmts ts
+ CODE:
+#ifdef HDRPMMEM
+ PRINTF_FREE(bless_rpmts, ts, ts->nrefs);
+#endif
+ ts = rpmtsFree(ts);
+
+# Function to control RPM4::Transaction behaviour
+
+int
+Ts_vsflags(ts, sv_vsflags = NULL)
+ rpmts ts
+ SV * sv_vsflags
+ PREINIT:
+ rpmVSFlags vsflags;
+ CODE:
+ if (sv_vsflags != NULL) {
+ vsflags = sv2vsflags(sv_vsflags);
+ RETVAL = rpmtsSetVSFlags(ts, vsflags);
+ } else {
+ RETVAL = rpmtsVSFlags(ts);
+ }
+ OUTPUT:
+ RETVAL
+
+int
+Ts_transflag(ts, sv_transflag = NULL)
+ rpmts ts
+ SV * sv_transflag
+ PREINIT:
+ rpmtransFlags transflags;
+ CODE:
+ if (sv_transflag != NULL) {
+ transflags = sv2transflags(sv_transflag);
+ /* Take care to rpm config (userland) */
+ if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
+ transflags |= RPMTRANS_FLAG_REPACKAGE;
+ RETVAL = rpmtsSetFlags(ts, transflags);
+ } else {
+ RETVAL = rpmtsFlags(ts);
+ }
+ OUTPUT:
+ RETVAL
+
+int
+Ts_injectheader(db, header)
+ rpmts db
+ Header header
+ PREINIT:
+ rpmdb rdb;
+ CODE:
+ rdb = rpmtsGetRdb(db);
+ RETVAL = rpmdbAdd(rdb, 0, header, db, NULL);
+ OUTPUT:
+ RETVAL
+
+int
+Ts_deleteheader(db, sv_offset)
+ rpmts db
+ SV * sv_offset
+ PREINIT:
+ rpmdb rdb;
+ unsigned int offset = 0;
+ CODE:
+ offset = SvUV(sv_offset);
+ rdb = rpmtsGetRdb(db);
+ if (offset)
+ RETVAL = rpmdbRemove(rdb, 0, offset, db, NULL);
+ else
+ RETVAL = 1;
+ OUTPUT:
+ RETVAL
+
+int
+Ts_traverse(ts, callback = NULL, sv_tagname = NULL, sv_tagvalue = NULL, keylen = 0, sv_exclude = NULL)
+ rpmts ts
+ SV * callback
+ SV * sv_tagname
+ SV * sv_tagvalue
+ SV * sv_exclude
+ int keylen
+ PREINIT:
+ rpmTag tag;
+ void * value = NULL;
+ rpmdbMatchIterator mi;
+ Header header;
+ int rc = 1;
+ int count = 0;
+ int * exclude = NULL;
+ AV * av_exclude;
+ int i;
+ CODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ ts = rpmtsLink(ts, "RPM4 Db::traverse()");
+ if (sv_tagname == NULL || !SvOK(sv_tagname)) {
+ tag = RPMDBI_PACKAGES; /* Assume search into installed packages */
+ } else {
+ tag = sv2dbquerytag(sv_tagname);
+ }
+ if (sv_tagvalue != NULL && SvOK(sv_tagvalue)) {
+ switch (tag) {
+ case RPMDBI_PACKAGES:
+ i = SvIV(sv_tagvalue);
+ value = &i;
+ keylen = sizeof(i);
+ break;
+ default:
+ value = (void *) SvPV_nolen(sv_tagvalue);
+ break;
+ }
+ }
+
+ RETVAL = 0;
+ if (tag >= 0) {
+ mi = rpmtsInitIterator(ts, tag, value, keylen);
+ if (sv_exclude != NULL && SvOK(sv_exclude) && SvTYPE(SvRV(sv_exclude)) == SVt_PVAV) {
+ av_exclude = (AV*)SvRV(sv_exclude);
+ exclude = malloc((av_len(av_exclude)+1) * sizeof(int));
+ for (i = 0; i <= av_len(av_exclude); i++) {
+ SV **isv = av_fetch(av_exclude, i, 0);
+ exclude[i] = SvUV(*isv);
+ }
+ rpmdbPruneIterator(mi, exclude, av_len(av_exclude) + 1, 0);
+ }
+ while (rc && ((header = rpmdbNextIterator(mi)) != NULL)) {
+ RETVAL++;
+ if (callback != NULL && SvROK(callback)) {
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, headerLink(header))));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_header, header, header->nrefs);
+#endif
+ XPUSHs(sv_2mortal(newSVuv(rpmdbGetIteratorOffset(mi))));
+ PUTBACK;
+ count = call_sv(callback, G_SCALAR);
+ SPAGAIN;
+ if (tag == RPMDBI_PACKAGES && value != NULL) {
+ rc = 0;
+ } else if (count == 1) {
+ rc = POPi;
+ }
+ FREETMPS;
+ LEAVE;
+
+ }
+ }
+ if (exclude != NULL) free(exclude);
+ rpmdbFreeIterator(mi);
+ } else
+ RETVAL = -1;
+ ts = rpmtsFree(ts);
+ OUTPUT:
+ RETVAL
+
+void
+Ts_get_header(ts, off)
+ rpmts ts
+ int off
+ PREINIT:
+ rpmdbMatchIterator mi;
+ Header header;
+ PPCODE:
+ mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &off, sizeof(off));
+ if ((header = rpmdbNextIterator(mi)) != NULL) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, headerLink(header))));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_header, header, header->nrefs);
+#endif
+ }
+ rpmdbFreeIterator(mi);
+
+int
+Ts_transadd(ts, header, key = NULL, upgrade = 1, sv_relocation = NULL, force = 0)
+ rpmts ts
+ Header header
+ char * key
+ int upgrade
+ SV * sv_relocation
+ int force
+ PREINIT:
+ rpmRelocation * relocations = NULL;
+ HV * hv_relocation;
+ HE * he_relocation;
+ int i = 0;
+ I32 len;
+ CODE:
+
+ if (key != NULL)
+ key = strdup(key);
+
+ /* Relocation settings */
+ if (sv_relocation && SvOK(sv_relocation) && !force) {
+/* if (! (headerGetEntry(eiu->h, RPMTAG_PREFIXES, &pft,
+ (void **) &paths, &c) && (c == 1))) { */
+ if (! headerIsEntry(header, RPMTAG_PREFIXES)) {
+ rpmMessage(RPMMESS_ERROR,
+ _("package %s is not relocatable\n"), "");
+ XPUSHi((IV)1);
+ XSRETURN(1);
+ }
+ if (SvTYPE(sv_relocation) == SVt_PV) {
+ /* String value, assume a prefix */
+ relocations = malloc(2 * sizeof(*relocations));
+ relocations[0].oldPath = NULL;
+ relocations[0].newPath = SvPV_nolen(sv_relocation);
+ relocations[1].oldPath = relocations[1].newPath = NULL;
+ } else if (SvTYPE(SvRV(sv_relocation)) == SVt_PVHV) {
+ hv_relocation = (HV*)SvRV(sv_relocation);
+ hv_iterinit(hv_relocation);
+ while ((he_relocation = hv_iternext(hv_relocation)) != NULL) {
+ relocations = realloc(relocations, sizeof(*relocations) * (++i));
+ relocations[i-1].oldPath = NULL;
+ relocations[i-1].newPath = NULL;
+ relocations[i-1].oldPath = hv_iterkey(he_relocation, &len);
+ relocations[i-1].newPath = SvPV_nolen(hv_iterval(hv_relocation, he_relocation));
+ }
+ /* latest relocation is identify by NULL setting */
+ relocations = realloc(relocations, sizeof(*relocations) * (++i));
+ relocations[i-1].oldPath = relocations[i-1].newPath = NULL;
+ } else {
+ croak("latest argument is set but is not an array ref or a string");
+ }
+ }
+
+ /* TODO fnpyKey: another value can be use... */
+ RETVAL = rpmtsAddInstallElement(ts, header, (fnpyKey) key, upgrade, relocations);
+ OUTPUT:
+ RETVAL
+
+int
+Ts_transremove(ts, recOffset, header = NULL)
+ rpmts ts
+ int recOffset
+ Header header
+ PREINIT:
+ rpmdbMatchIterator mi;
+ CODE:
+ RETVAL = 0;
+ if (header != NULL) { /* reprofit Db_traverse */
+ rpmtsAddEraseElement(ts, header, recOffset);
+ } else {
+ mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &recOffset, sizeof(recOffset));
+ if ((header = rpmdbNextIterator(mi)) != NULL) {
+#ifdef HDLISTDEBUG
+ fprintf(stderr, "HDEBUG: Db::transremove(h, o) H: %p Off:%u\n", header, recOffset);
+#endif
+ rpmtsAddEraseElement(ts, header, recOffset);
+ RETVAL = 1;
+ }
+ rpmdbFreeIterator(mi);
+ }
+ OUTPUT:
+ RETVAL
+
+int
+Ts_transremove_pkg(ts, N_evr)
+ rpmts ts
+ char * N_evr
+ PREINIT:
+ rpmdbMatchIterator mi;
+ Header header;
+ int recOffset;
+ CODE:
+ RETVAL = 0;
+ /* N_evr is not NEVR but N(EVR), with RPMDBI_LABEL
+ * I want to find another way to exactly match a header
+ * For more flexible function, check Db_traverse / Db_transremove */
+ mi = rpmtsInitIterator(ts, RPMDBI_LABEL, N_evr, 0);
+ while ((header = rpmdbNextIterator(mi))) {
+ recOffset = rpmdbGetIteratorOffset(mi);
+#ifdef HDLISTDEBUG
+ fprintf(stderr, "HDEBUG: Db::transremove(Name) N: %s H: %p Off:%u\n", N_evr, header, recOffset);
+#endif
+ if (recOffset != 0) {
+ rpmtsAddEraseElement(ts, header, recOffset);
+ RETVAL ++;
+ }
+ }
+ rpmdbFreeIterator(mi);
+ OUTPUT:
+ RETVAL
+
+int
+Ts_traverse_transaction(ts, callback, type = 0)
+ rpmts ts
+ SV * callback
+ int type
+ PREINIT:
+ rpmtsi pi;
+ rpmte Te;
+ CODE:
+ ts = rpmtsLink(ts, "RPM4 Db::traverse_transaction()");
+ pi = rpmtsiInit(ts);
+ RETVAL = 0;
+ while ((Te = rpmtsiNext(pi, type)) != NULL) {
+ RETVAL++;
+ if (callback != NULL && SvROK(callback)) {
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), "RPM4::Db::Te", Te)));
+ PUTBACK;
+ call_sv(callback, G_DISCARD | G_SCALAR);
+ SPAGAIN;
+ FREETMPS;
+ LEAVE;
+ }
+ }
+ pi = rpmtsiFree(pi);
+ ts = rpmtsFree(ts);
+ OUTPUT:
+ RETVAL
+
+int
+Ts_transcheck(ts, callback = NULL)
+ rpmts ts
+ SV * callback
+ CODE:
+ ts = rpmtsLink(ts, "RPM4 Db_transcheck()");
+ if (callback != NULL && SvOK(callback) && SvTYPE(SvRV(callback)) == SVt_PVCV) { /* Be sure we have a code ref */
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ rpmtsSetSolveCallback(ts, transSolveCallback, (void *) callback);
+ }
+
+ RETVAL = rpmtsCheck(ts);
+ /* Restoring default rpm setting */
+ rpmtsSetSolveCallback(ts, rpmtsSolve, NULL);
+ ts = rpmtsFree(ts);
+ OUTPUT:
+ RETVAL
+
+int
+Ts_transorder(ts)
+ rpmts ts
+ CODE:
+ RETVAL = rpmtsOrder(ts);
+ OUTPUT:
+ RETVAL
+
+void
+Ts_transclean(ts)
+ rpmts ts
+ PPCODE:
+ rpmtsClean(ts);
+
+int
+Ts_transrun(ts, callback, ...)
+ rpmts ts
+ SV * callback
+ PREINIT:
+ int i;
+ rpmprobFilterFlags probFilter = RPMPROB_FILTER_NONE;
+ rpmInstallInterfaceFlags install_flags = INSTALL_NONE;
+ rpmps ps;
+ CODE:
+ ts = rpmtsLink(ts, "RPM4 Db::transrun()");
+ if (!SvOK(callback)) { /* undef value */
+ rpmtsSetNotifyCallback(ts,
+ rpmShowProgress,
+ (void *) ((long) INSTALL_LABEL | INSTALL_HASH | INSTALL_UPGRADE));
+ } else if (SvTYPE(SvRV(callback)) == SVt_PVCV) { /* ref sub */
+ rpmtsSetNotifyCallback(ts,
+ transCallback, (void *) callback);
+ } else if (SvTYPE(SvRV(callback)) == SVt_PVAV) { /* array ref */
+ install_flags = sv2constant(callback, "rpminstallinterfaceflags");
+ rpmtsSetNotifyCallback(ts,
+ rpmShowProgress,
+ (void *) ((long) install_flags));
+ } else {
+ croak("Wrong parameter given");
+ }
+
+ for (i = 2; i < items; i++)
+ probFilter |= sv2constant(ST(i), "rpmprobfilterflags");
+
+ ps = rpmtsProblems(ts);
+ RETVAL = rpmtsRun(ts, ps, probFilter);
+ ps = rpmpsFree(ps);
+ ts = rpmtsFree(ts);
+ OUTPUT:
+ RETVAL
+
+# get from transaction a problem set
+void
+Ts__transpbs(ts)
+ rpmts ts
+ PREINIT:
+ rpmps ps;
+ PPCODE:
+ ps = rpmtsProblems(ts);
+ if (ps && ps->numProblems) /* if no problem, return undef */
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmps, ps)));
+
+int
+Ts_importpubkey(ts, filename)
+ rpmts ts
+ char * filename
+ PREINIT:
+ const byte * pkt = NULL;
+ size_t pktlen = 0;
+ int rc;
+ CODE:
+ rpmtsClean(ts);
+
+ if ((rc = pgpReadPkts(filename, &pkt, &pktlen)) <= 0) {
+ RETVAL = 1;
+ } else if (rc != PGPARMOR_PUBKEY) {
+ RETVAL = 1;
+ } else if (rpmcliImportPubkey(ts, pkt, pktlen) != RPMRC_OK) {
+ RETVAL = 1;
+ } else {
+ RETVAL = 0;
+ }
+ pkt = _free(pkt);
+ OUTPUT:
+ RETVAL
+
+void
+Ts_checkrpm(ts, filename, sv_vsflags = NULL)
+ rpmts ts
+ char * filename
+ SV * sv_vsflags
+ PREINIT:
+ rpmVSFlags vsflags = RPMVSF_DEFAULT;
+ rpmVSFlags oldvsflags = RPMVSF_DEFAULT;
+ PPCODE:
+ oldvsflags = rpmtsVSFlags(ts); /* keep track of old settings */
+ if (sv_vsflags != NULL) {
+ vsflags = sv2vsflags(sv_vsflags);
+ rpmtsSetVSFlags(ts, vsflags);
+ }
+ PUTBACK;
+ _rpm2header(ts, filename, 1); /* Rpmread header is not the most usefull,
+ * but no other function in rpmlib allow this :( */
+ SPAGAIN;
+ rpmtsSetVSFlags(ts, oldvsflags); /* resetting in case of change */
+
+void
+Ts_transreset(ts)
+ rpmts ts
+ PPCODE:
+ rpmtsEmpty(ts);
+
+# Remaping function:
+
+# RPM4::rpm2header(filename); # Reusing existing RPM4::Db
+void
+Ts_rpm2header(ts, filename)
+ rpmts ts
+ char * filename
+ PPCODE:
+ _rpm2header(ts, filename, 0);
+ SPAGAIN;
+
+# RPM4::Spec::specbuild([ buildflags ]); Reusing existing RPM4::Db
+int
+Ts_specbuild(ts, spec, sv_buildflags)
+ rpmts ts
+ Spec spec
+ SV * sv_buildflags
+ CODE:
+ RETVAL = _specbuild(ts, spec, sv_buildflags);
+ OUTPUT:
+ RETVAL
+
+void
+Ts_installsrpm(ts, filename)
+ rpmts ts
+ char * filename
+ PPCODE:
+ PUTBACK;
+ _installsrpms(ts, filename);
+ SPAGAIN;
+
+MODULE = RPM4 PACKAGE = RPM4::Db::Te PREFIX = Te_
+
+void
+Te_DESTROY(Te)
+ rpmte Te
+ CODE:
+#ifdef HDRPMMEM
+/* PRINTF_FREE(RPM4::Db::Te, -1); */
+#endif
+ /* Don't do that ! *
+ Te = rpmteFree(Te); */
+
+int
+Te_type(Te)
+ rpmte Te
+ CODE:
+ RETVAL = rpmteType(Te);
+ OUTPUT:
+ RETVAL
+
+void
+Te_name(Te)
+ rpmte Te
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmteN(Te), 0)));
+
+void
+Te_version(Te)
+ rpmte Te
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmteV(Te), 0)));
+
+void
+Te_release(Te)
+ rpmte Te
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmteR(Te), 0)));
+
+void
+Te_epoch(Te)
+ rpmte Te
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmteE(Te), 0)));
+
+void
+Te_arch(Te)
+ rpmte Te
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmteA(Te), 0)));
+
+void
+Te_os(Te)
+ rpmte Te
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmteO(Te), 0)));
+
+void
+Te_fullname(Te)
+ rpmte Te
+ PREINIT:
+ I32 gimme = GIMME_V;
+ PPCODE:
+ if (gimme == G_SCALAR) {
+ XPUSHs(sv_2mortal(newSVpvf("%s-%s-%s.%s",
+ rpmteN(Te), rpmteV(Te), rpmteR(Te), rpmteA(Te))));
+ } else {
+ XPUSHs(sv_2mortal(newSVpv(rpmteN(Te), 0)));
+ XPUSHs(sv_2mortal(newSVpv(rpmteV(Te), 0)));
+ XPUSHs(sv_2mortal(newSVpv(rpmteR(Te), 0)));
+ XPUSHs(sv_2mortal(newSVpv(rpmteA(Te), 0)));
+ }
+
+void
+Te_size(Te)
+ rpmte Te
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVuv(rpmtePkgFileSize(Te))));
+
+void
+Te_dep(Te, type)
+ rpmte Te
+ SV * type
+ PREINIT:
+ rpmds ds;
+ rpmTag tag;
+ PPCODE:
+ tag = sv2deptag(type);
+ ds = rpmteDS(Te, tag);
+ if (ds != NULL)
+ if (rpmdsNext(ds) >= 0) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmds, ds)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmds, ds, ds->nrefs);
+#endif
+ }
+
+void
+Te_files(Te)
+ rpmte Te
+ PREINIT:
+ rpmfi Files;
+ PPCODE:
+ Files = rpmteFI(Te, RPMTAG_BASENAMES);
+ if ((Files = rpmfiInit(Files, 0)) != NULL && rpmfiNext(Files) >= 0) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmfi, Files)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmfi, Files, Files->nrefs);
+#endif
+ }
+
+MODULE = RPM4 PACKAGE = RPM4
+
+# Return a new Dep object
+void
+newdep(sv_depTag, Name, sv_sense = NULL, sv_evr = NULL)
+ SV * sv_depTag
+ char * Name
+ SV * sv_evr
+ SV * sv_sense
+ PPCODE:
+ PUTBACK;
+ _newdep(sv_depTag, Name, sv_sense, sv_evr);
+ SPAGAIN;
+
+void
+rpmlibdep()
+ PREINIT:
+ rpmds Dep = NULL;
+ rpmds next;
+ const char ** provNames;
+ int * provFlags;
+ const char ** provVersions;
+ int num = 0;
+ int i;
+ PPCODE:
+ num = rpmGetRpmlibProvides(&provNames, &provFlags, &provVersions);
+ for (i = 0; i < num; i++) {
+#ifdef HDLISTDEBUG
+ fprintf(stderr, "HDEBUG: rpmlibdep %s %s %d\n", provNames[i], provVersions[i], provFlags[i]);
+#endif
+ next = rpmdsSingle(RPMTAG_PROVIDENAME, provNames[i], provVersions[i], provFlags[i]);
+ rpmdsMerge(&Dep, next);
+ next = rpmdsFree(next);
+ }
+ if (Dep != NULL) {
+ Dep = rpmdsInit(Dep);
+ if (rpmdsNext(Dep) >= 0) {
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmds, Dep)));
+#ifdef HDRPMMEM
+ PRINTF_NEW(bless_rpmds, Dep, Dep->nrefs);
+#endif
+ }
+ }
+
+MODULE = RPM4 PACKAGE = RPM4::Header::Dependencies PREFIX = Dep_
+
+void
+Dep_newsingle(perlclass, sv_tag, name, sv_sense = NULL, sv_evr = NULL)
+ char * perlclass
+ SV * sv_tag
+ char * name
+ SV * sv_sense
+ SV * sv_evr
+ PPCODE:
+ PUTBACK;
+ _newdep(sv_tag, name, sv_sense, sv_evr);
+ SPAGAIN;
+
+void
+Dep_DESTROY(Dep)
+ rpmds Dep
+ CODE:
+#ifdef HDRPMMEM
+ PRINTF_FREE(bless_rpmds, Dep, Dep->nrefs);
+#endif
+ Dep = rpmdsFree(Dep);
+
+int
+Dep_count(Dep)
+ rpmds Dep
+ CODE:
+ RETVAL = rpmdsCount(Dep);
+ OUTPUT:
+ RETVAL
+
+int
+Dep_move(Dep, index = 0)
+ rpmds Dep
+ int index
+ CODE:
+ if (index == -1) /* -1 do nothing and give actual index */
+ RETVAL = rpmdsIx(Dep);
+ else
+ RETVAL = rpmdsSetIx(Dep, index);
+ OUTPUT:
+ RETVAL
+
+void
+Dep_init(Dep)
+ rpmds Dep
+ CODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ rpmdsInit(Dep);
+
+int
+Dep_next(Dep)
+ rpmds Dep
+ CODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ RETVAL = rpmdsNext(Dep);
+ OUTPUT:
+ RETVAL
+
+int
+Dep_hasnext(Dep)
+ rpmds Dep
+ CODE:
+ RETVAL = rpmdsNext(Dep) > -1;
+ OUTPUT:
+ RETVAL
+
+int
+Dep_color(Dep)
+ rpmds Dep
+ CODE:
+ RETVAL = rpmdsColor(Dep);
+ OUTPUT:
+ RETVAL
+
+int
+Dep_find(Dep, depb)
+ rpmds Dep
+ rpmds depb
+ CODE:
+ RETVAL = rpmdsFind(Dep, depb);
+ OUTPUT:
+ RETVAL
+
+int
+Dep_merge(Dep, depb)
+ rpmds Dep
+ rpmds depb
+ CODE:
+ RETVAL = rpmdsMerge(&Dep, depb);
+ OUTPUT:
+ RETVAL
+
+int
+Dep_overlap(Dep1, Dep2)
+ rpmds Dep1
+ rpmds Dep2
+ CODE:
+ CHECK_RPMDS_IX(Dep1);
+ CHECK_RPMDS_IX(Dep2);
+ RETVAL = rpmdsCompare(Dep1, Dep2);
+ OUTPUT:
+ RETVAL
+
+void
+Dep_info(Dep)
+ rpmds Dep
+ PREINIT:
+ rpmsenseFlags flag;
+ I32 gimme = GIMME_V;
+ PPCODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ CHECK_RPMDS_IX(Dep);
+ if (gimme == G_SCALAR) {
+ XPUSHs(sv_2mortal(newSVpv(rpmdsDNEVR(Dep), 0)));
+ } else {
+ switch (rpmdsTagN(Dep)) {
+ case RPMTAG_PROVIDENAME:
+ XPUSHs(sv_2mortal(newSVpv("P", 0)));
+ break;
+ case RPMTAG_REQUIRENAME:
+ XPUSHs(sv_2mortal(newSVpv("R", 0)));
+ break;
+ case RPMTAG_CONFLICTNAME:
+ XPUSHs(sv_2mortal(newSVpv("C", 0)));
+ break;
+ case RPMTAG_OBSOLETENAME:
+ XPUSHs(sv_2mortal(newSVpv("O", 0)));
+ break;
+ case RPMTAG_TRIGGERNAME:
+ XPUSHs(sv_2mortal(newSVpv("T", 0)));
+ break;
+ default:
+ break;
+ }
+ XPUSHs(sv_2mortal(newSVpv(rpmdsN(Dep), 0)));
+ flag = rpmdsFlags(Dep);
+ XPUSHs(sv_2mortal(newSVpvf("%s%s%s",
+ flag & RPMSENSE_LESS ? "<" : "",
+ flag & RPMSENSE_GREATER ? ">" : "",
+ flag & RPMSENSE_EQUAL ? "=" : "")));
+ XPUSHs(sv_2mortal(newSVpv(rpmdsEVR(Dep), 0)));
+ }
+
+void
+Dep_tag(Dep)
+ rpmds Dep
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmdsTagN(Dep))));
+
+void
+Dep_name(Dep)
+ rpmds Dep
+ PPCODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ CHECK_RPMDS_IX(Dep);
+ XPUSHs(sv_2mortal(newSVpv(rpmdsN(Dep), 0)));
+
+void
+Dep_flags(Dep)
+ rpmds Dep
+ PPCODE:
+ CHECK_RPMDS_IX(Dep);
+ XPUSHs(sv_2mortal(newSViv(rpmdsFlags(Dep))));
+
+void
+Dep_evr(Dep)
+ rpmds Dep
+ PPCODE:
+ CHECK_RPMDS_IX(Dep);
+ XPUSHs(sv_2mortal(newSVpv(rpmdsEVR(Dep), 0)));
+
+int
+Dep_nopromote(Dep, sv_nopromote = NULL)
+ rpmds Dep
+ SV * sv_nopromote
+ CODE:
+ if (sv_nopromote == NULL) {
+ RETVAL = rpmdsNoPromote(Dep);
+ } else {
+ RETVAL = rpmdsSetNoPromote(Dep, SvIV(sv_nopromote));
+ }
+ OUTPUT:
+ RETVAL
+
+
+int
+Dep_add(Dep, name, sv_sense = NULL, sv_evr = NULL)
+ rpmds Dep
+ char * name
+ SV * sv_evr
+ SV * sv_sense
+ PREINIT:
+ rpmsenseFlags sense = RPMSENSE_ANY;
+ rpmds Deptoadd;
+ char * evr = NULL;
+ CODE:
+ RETVAL = 0;
+ if (sv_sense && SvOK(sv_sense))
+ sense = sv2sens(sv_sense);
+ if (sv_evr && SvOK(sv_evr))
+ evr = SvPV_nolen(sv_evr);
+ Deptoadd = rpmdsSingle(rpmdsTagN(Dep), name,
+ evr ? evr : "", sense);
+ if (Deptoadd) {
+ rpmdsMerge(&Dep, Deptoadd);
+ Deptoadd = rpmdsFree(Deptoadd);
+ RETVAL = 1;
+ }
+ OUTPUT:
+ RETVAL
+
+int
+Dep_matchheader(Dep, header, sv_nopromote = NULL)
+ Header header
+ SV * sv_nopromote
+ rpmds Dep
+ PREINIT:
+ int nopromote = 0;
+ CODE:
+ if (sv_nopromote != NULL)
+ nopromote = SvIV(sv_nopromote);
+ RETVAL = _header_vs_dep(header, Dep, nopromote);
+ OUTPUT:
+ RETVAL
+
+int
+Dep_matchheadername(Dep, header, sv_nopromote = NULL)
+ rpmds Dep
+ Header header
+ SV * sv_nopromote
+ PREINIT:
+ int nopromote = 0;
+ CODE:
+ if (sv_nopromote != NULL)
+ nopromote = SvIV(sv_nopromote);
+ RETVAL = _headername_vs_dep(header, Dep, nopromote);
+ OUTPUT:
+ RETVAL
+
+MODULE = RPM4 PACKAGE = RPM4::Header::Files PREFIX = Files_
+
+void
+Files_DESTROY(Files)
+ rpmfi Files
+ PPCODE:
+#ifdef HDRPMMEM
+ PRINTF_FREE(bless_rpmfi, Files, Files->nrefs);
+#endif
+ Files = rpmfiFree(Files);
+
+int
+Files_compare(Files, Fb)
+ rpmfi Files
+ rpmfi Fb
+ CODE:
+ RETVAL = rpmfiCompare(Files, Fb);
+ OUTPUT:
+ RETVAL
+
+int
+Files_move(Files, index = 0)
+ rpmfi Files;
+ int index
+ PREINIT:
+ int i;
+ CODE:
+ index ++; /* keeping same behaviour than Header::Dep */
+ rpmfiInit(Files, 0);
+ RETVAL = 0;
+ for (i=-1; i < index && (RETVAL = rpmfiNext(Files)) >= 0; i++) {}
+ if (RETVAL == -1) {
+ rpmfiInit(Files, 0);
+ rpmfiNext(Files);
+ }
+ OUTPUT:
+ RETVAL
+
+int
+Files_count(Files)
+ rpmfi Files
+ CODE:
+ RETVAL = rpmfiFC(Files);
+ OUTPUT:
+ RETVAL
+
+int
+Files_countdir(Files)
+ rpmfi Files
+ CODE:
+ RETVAL = rpmfiDC(Files);
+ OUTPUT:
+ RETVAL
+
+void
+Files_init(Files)
+ rpmfi Files
+ CODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ rpmfiInit(Files, 0);
+
+void
+Files_initdir(Files)
+ rpmfi Files
+ CODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ rpmfiInitD(Files, 0);
+
+int
+Files_next(Files)
+ rpmfi Files
+ CODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ RETVAL = rpmfiNext(Files);
+ OUTPUT:
+ RETVAL
+
+int
+Files_hasnext(Files)
+ rpmfi Files
+ CODE:
+ RETVAL = rpmfiNext(Files) > -1;
+ OUTPUT:
+ RETVAL
+
+int
+Files_nextdir(Files)
+ rpmfi Files
+ CODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+#endif
+ RETVAL = rpmfiNextD(Files);
+ OUTPUT:
+ RETVAL
+
+void
+Files_filename(Files)
+ rpmfi Files
+ PPCODE:
+#ifdef HDLISTDEBUG
+ PRINTF_CALL;
+ fprintf(stderr, "File %s", rpmfiFN(Files));
+#endif
+ XPUSHs(sv_2mortal(newSVpv(rpmfiFN(Files), 0)));
+
+void
+Files_dirname(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmfiDN(Files), 0)));
+
+void
+Files_basename(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmfiBN(Files), 0)));
+
+void
+Files_fflags(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmfiFFlags(Files))));
+
+void
+Files_mode(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmfiFMode(Files))));
+
+void
+Files_md5(Files)
+ rpmfi Files
+ PREINIT:
+ const byte * md5;
+ char * fmd5 = malloc((char) 33);
+ PPCODE:
+ if ((md5 = rpmfiMD5(Files)) != NULL && *md5 != 0 /* return undef if empty */) {
+ (void) pgpHexCvt(fmd5, md5, 16);
+ XPUSHs(sv_2mortal(newSVpv(fmd5, 0)));
+ }
+ _free(fmd5);
+
+void
+Files_link(Files)
+ rpmfi Files
+ PREINIT:
+ const char * link;
+ PPCODE:
+ if ((link = rpmfiFLink(Files)) != NULL && *link != 0 /* return undef if empty */) {
+ XPUSHs(sv_2mortal(newSVpv(link, 0)));
+ }
+
+void
+Files_user(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmfiFUser(Files), 0)));
+
+void
+Files_group(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSVpv(rpmfiFGroup(Files), 0)));
+
+void
+Files_inode(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmfiFInode(Files))));
+
+void
+Files_size(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmfiFSize(Files))));
+
+void
+Files_dev(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmfiFRdev(Files))));
+
+void
+Files_color(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmfiFColor(Files))));
+
+void
+Files_class(Files)
+ rpmfi Files
+ PREINIT:
+ const char * class;
+ PPCODE:
+ if ((class = rpmfiFClass(Files)) != NULL)
+ XPUSHs(sv_2mortal(newSVpv(rpmfiFClass(Files), 0)));
+
+void
+Files_mtime(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmfiFMtime(Files))));
+
+void
+Files_nlink(Files)
+ rpmfi Files
+ PPCODE:
+ XPUSHs(sv_2mortal(newSViv(rpmfiFNlink(Files))));
+
+MODULE = RPM4 PACKAGE = RPM4
+
+void
+newspec(filename = NULL, passphrase = NULL, rootdir = NULL, cookies = NULL, anyarch = NULL, force = NULL)
+ char * filename
+ SV * passphrase
+ SV * rootdir
+ SV * cookies
+ SV * anyarch
+ SV * force
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ PPCODE:
+ PUTBACK;
+ _newspec(ts, filename, passphrase, rootdir, cookies, anyarch, force);
+ ts = rpmtsFree(ts);
+ SPAGAIN;
+
+MODULE = RPM4 PACKAGE = RPM4::Spec PREFIX = Spec_
+
+void
+Spec_new(perlclass, specfile = NULL, ...)
+ char * perlclass
+ char * specfile
+ PREINIT:
+ rpmts ts = NULL;
+ SV * passphrase = NULL;
+ SV * rootdir = NULL;
+ SV * cookies = NULL;
+ SV * anyarch = 0;
+ SV * force = 0;
+ int i;
+ PPCODE:
+ for(i=2; i < items; i++) {
+ if(strcmp(SvPV_nolen(ST(i)), "transaction") == 0) {
+ i++;
+ if (sv_isobject(ST(i)) && (SvTYPE(SvRV(ST(i))) == SVt_PVMG)) {
+ ts = (rpmts)SvIV((SV*)SvRV(ST(i)));
+ ts = rpmtsLink(ts, bless_spec);
+ } else {
+ croak( "transaction is not a blessed SV reference" );
+ XSRETURN_UNDEF;
+ }
+ } else if (strcmp(SvPV_nolen(ST(i)), "force") == 0) {
+ i++;
+ force = ST(i);
+ } else if (strcmp(SvPV_nolen(ST(i)), "anyarch") == 0) {
+ i++;
+ anyarch = ST(i);
+ } else if (strcmp(SvPV_nolen(ST(i)), "passphrase") == 0) {
+ i++;
+ passphrase = ST(i);
+ } else if (strcmp(SvPV_nolen(ST(i)), "root") == 0) {
+ i++;
+ rootdir = ST(i);
+ } else {
+ warn("Unknown value in " bless_spec "->new, ignored");
+ i++;
+ }
+ }
+ if (!ts)
+ ts = rpmtsCreate();
+ PUTBACK;
+ _newspec(ts, specfile, passphrase, rootdir, cookies, anyarch, force);
+ SPAGAIN;
+ ts = rpmtsFree(ts);
+
+void
+Spec_DESTROY(spec)
+ Spec spec
+ CODE:
+#ifdef HDRPMMEM
+ PRINTF_FREE(bless_spec, spec, -1);
+#endif
+ freeSpec(spec);
+
+void
+Spec_srcheader(spec)
+ Spec spec
+ PPCODE:
+ if ( ! spec->sourceHeader)
+ initSourceHeader(spec);
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, (void *)headerLink(spec->sourceHeader))));
+
+void
+Spec_binheader(spec)
+ Spec spec
+ PREINIT:
+ Package pkg;
+ PPCODE:
+ for (pkg = spec->packages; pkg != NULL; pkg = pkg->next)
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_header, (void *)headerLink(pkg->header))));
+
+void
+Spec_srcrpm(spec)
+ Spec spec
+ PREINIT:
+ const char *name, *version, *release;
+ PPCODE:
+ (void) headerNVR(spec->packages->header, &name, &version, &release);
+ XPUSHs(sv_2mortal(newSVpvf("%s/%s-%s-%s.%ssrc.rpm",
+ rpmGetPath("%{_srcrpmdir}", NULL),
+ name, version, release,
+ spec->noSource ? "no" : ""
+ )));
+ headerFreeTag(spec->packages->header, name, RPM_STRING_TYPE);
+ headerFreeTag(spec->packages->header, version, RPM_STRING_TYPE);
+ headerFreeTag(spec->packages->header, release, RPM_STRING_TYPE);
+
+void
+Spec_binrpm(spec)
+ Spec spec
+ PREINIT:
+ Package pkg;
+ const char * binFormat;
+ char * binRpm;
+ PPCODE:
+ for(pkg = spec->packages; pkg != NULL; pkg = pkg->next) {
+ if (pkg->fileList == NULL)
+ continue;
+ /* headerCopyTags(h, pkg->header, copyTags); */
+ binFormat = rpmGetPath("%{_rpmfilename}", NULL);
+ binRpm = headerSprintf(pkg->header, binFormat, rpmTagTable,
+ rpmHeaderFormats, NULL);
+ _free(binFormat);
+ XPUSHs(sv_2mortal(newSVpv(rpmGetPath("%{_rpmdir}/", binRpm, NULL), 0)));
+ _free(binRpm);
+ }
+
+void
+Spec_check(spec, ts = NULL)
+ Spec spec
+ PREINIT:
+ int rc;
+ rpmts ts = rpmtsCreate();
+ rpmps ps;
+ PPCODE:
+ PUTBACK;
+ if (ts)
+ ts = rpmtsLink(ts, "Spec_check");
+ else
+ ts = rpmtsCreate();
+
+ if ( ! spec->sourceHeader)
+ initSourceHeader(spec);
+
+ if (!headerIsEntry(spec->sourceHeader, RPMTAG_REQUIRENAME)
+ && !headerIsEntry(spec->sourceHeader, RPMTAG_CONFLICTNAME))
+ /* XSRETURN_UNDEF; */
+ return;
+
+ (void) rpmtsAddInstallElement(ts, spec->sourceHeader, NULL, 0, NULL);
+
+ if(rpmtsCheck(ts))
+ croak("Can't check rpmts"); /* any better idea ? */
+
+ ps = rpmtsProblems(ts);
+ if (ps && ps->numProblems) /* if no problem, return undef */
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmps, ps)));
+ ts = rpmtsFree(ts);
+ SPAGAIN;
+
+
+int
+Spec_build(spec, sv_buildflags)
+ Spec spec
+ SV * sv_buildflags
+ PREINIT:
+ rpmts ts = rpmtsCreate();
+ CODE:
+ RETVAL = _specbuild(ts, spec, sv_buildflags);
+ ts = rpmtsFree(ts);
+ OUTPUT:
+ RETVAL
+
+const char *
+Spec_specfile(spec)
+ Spec spec
+ CODE:
+ RETVAL = spec->specFile;
+ OUTPUT:
+ RETVAL
+
+void
+Spec_sources(spec, is = 0)
+ Spec spec
+ int is
+ PREINIT:
+ struct Source *srcPtr;
+ PPCODE:
+ for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
+ char * dest = NULL;
+ int len;
+ if (is && !(srcPtr->flags & is))
+ continue;
+ len = strlen(srcPtr->source);
+ dest = malloc(len);
+ memcpy(dest, srcPtr->source, len);
+ XPUSHs(sv_2mortal(newSVpv(dest, len)));
+ }
+
+void
+Spec_sources_url(spec, is = 0)
+ Spec spec
+ int is
+ PREINIT:
+ struct Source * srcPtr;
+ PPCODE:
+ for (srcPtr = spec->sources; srcPtr != NULL; srcPtr = srcPtr->next) {
+ char * dest = NULL;
+ int len;
+ if (is && !(srcPtr->flags & is))
+ continue;
+ len = strlen(srcPtr->fullSource);
+ dest = malloc(len);
+ memcpy(dest, srcPtr->fullSource, len);
+ XPUSHs(sv_2mortal(newSVpv(dest, len)));
+ }
+
+
+MODULE = RPM4 PACKAGE = RPM4::Db::_Problems PREFIX = ps_
+
+void
+ps_new(perlclass, ts)
+ char * perlclass
+ rpmts ts
+ PREINIT:
+ rpmps ps;
+ PPCODE:
+ ps = rpmtsProblems(ts);
+ if (ps && ps->numProblems) /* if no problem, return undef */
+ XPUSHs(sv_2mortal(sv_setref_pv(newSVpv("", 0), bless_rpmps, ps)));
+
+void
+ps_DESTROY(ps)
+ rpmps ps
+ PPCODE:
+ ps = rpmpsFree(ps);
+
+int
+ps_count(ps)
+ rpmps ps
+ CODE:
+ RETVAL = rpmpsNumProblems(ps);
+ OUTPUT:
+ RETVAL
+
+void
+ps_print(ps, fp)
+ rpmps ps
+ FILE *fp
+ PPCODE:
+ rpmpsPrint(fp, ps);
+
+int
+ps_isignore(ps, numpb)
+ rpmps ps
+ int numpb
+ PREINIT:
+ rpmProblem p;
+ CODE:
+ if (ps->numProblems < numpb)
+ RETVAL = 0; /* croak here ? */
+ else {
+ p = ps->probs + numpb;
+ RETVAL = p->ignoreProblem;
+ }
+ OUTPUT:
+ RETVAL
+
+const char *
+ps_fmtpb(ps, numpb)
+ rpmps ps
+ int numpb
+ PREINIT:
+ rpmProblem p;
+ CODE:
+ if (ps->numProblems < numpb)
+ RETVAL = NULL;
+ else {
+ p = ps->probs + numpb;
+ RETVAL = rpmProblemString(p);
+ }
+ OUTPUT:
+ RETVAL
+
diff --git a/RPM4/src/RPM4sign.c b/RPM4/src/RPM4sign.c
new file mode 100644
index 0000000..04bb60f
--- /dev/null
+++ b/RPM4/src/RPM4sign.c
@@ -0,0 +1,28 @@
+/* $Id$ */
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#undef Fflush
+#undef Mkdir
+#undef Stat
+
+#include <rpm/rpmcli.h>
+
+#include "RPM4.h"
+
+/* Hight level function */
+int rpmsign(char *passphrase, const char *rpm) {
+ QVA_t qva = &rpmQVKArgs;
+ const char * file[2];
+
+ file[0] = rpm;
+ file[1] = NULL;
+
+ qva->qva_mode = RPMSIGN_ADD_SIGNATURE;
+ qva->passPhrase = passphrase;
+
+ return rpmcliSign(NULL, qva, file);
+}
+
diff --git a/RPM4/src/typemap b/RPM4/src/typemap
new file mode 100644
index 0000000..1889a0a
--- /dev/null
+++ b/RPM4/src/typemap
@@ -0,0 +1,21 @@
+TYPEMAP
+Header O_OBJECT
+Spec O_OBJECT
+rpmts O_OBJECT
+rpmds O_OBJECT
+rpmfi O_OBJECT
+rpmte O_OBJECT
+rpmps O_OBJECT
+
+INPUT
+O_OBJECT
+ if (sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG))
+ $var = ($type)SvIV((SV*)SvRV( $arg ));
+ else {
+ warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
+ XSRETURN_UNDEF;
+ }
+
+OUTPUT
+O_OBJECT
+ sv_setref_pv( $arg, (char *)CLASS, (void*)$var );
diff --git a/RPM4/t/01compile.t b/RPM4/t/01compile.t
new file mode 100644
index 0000000..568a258
--- /dev/null
+++ b/RPM4/t/01compile.t
@@ -0,0 +1,12 @@
+# $Id$
+
+use Test::More tests => 3;
+
+use_ok('RPM4');
+can_ok('RPM4', qw/rpm2header stream2header dumprc dumpmacros newdb/);
+
+#Header
+
+# Db
+can_ok('RPM4::Transaction', qw/traverse transadd transremove transcheck transorder transrun
+ importpubkey checkrpm transreset/);
diff --git a/RPM4/t/02header.t b/RPM4/t/02header.t
new file mode 100644
index 0000000..7bba1a4
--- /dev/null
+++ b/RPM4/t/02header.t
@@ -0,0 +1,78 @@
+# $Id$
+
+use strict;
+use Test::More tests => 40;
+use FindBin qw($Bin);
+use RPM4;
+
+my $headerfile;
+
+{
+my $hdr = RPM4::Header->new();
+isa_ok($hdr, "RPM4::Header", "Creating empty header works");
+ok(! defined $hdr->tag(1000), "empty tag return nothings");
+}
+
+{
+my $hdr = RPM4::Header->new("$Bin/test-rpm-1.0-1mdk.src.rpm");
+isa_ok($hdr, "RPM4::Header", "instanciating an header from a source rpm works");
+ok($hdr->hastag(1000) eq 1, "Has tag 1000 (NAME), yes");
+ok($hdr->hastag("NAME") eq 1, "Has 'NAME', yes");
+ok($hdr->hastag(1106) eq 1, "Has tag 1106 (SOURCEPACKAGE), yes");
+ok($hdr->listtag(), "can list tag");
+is($hdr->tag(1000), "test-rpm", "accessing tag by id works");
+is($hdr->tag("NAME"), "test-rpm", "accessing tag by name works");
+is($hdr->NAME(), "test-rpm", "accessing tag directly works");
+ok($hdr->queryformat("%{NAME}-%{VERSION}-%{RELEASE}") eq "test-rpm-1.0-1mdk", "Queryformat is ok");
+ok($hdr->nevr() eq "test-rpm-1.0-1mdk", "header->nevr works");
+ok(scalar($hdr->fullname) eq "test-rpm-1.0-1mdk.src", "scalar fullname works");
+ok(join(",", $hdr->fullname) eq "test-rpm,1.0,1mdk,src", "wantarray fullname works");
+ok($hdr->issrc == 1, "Is a src, Yes !");
+ok($hdr->sourcerpmname eq "test-rpm-1.0-1mdk.src.rpm", "sourcerpmname works");
+ok($hdr->removetag(1000) == 0, "Removing a tag");
+ok(! defined $hdr->tag(1000), "tag is not present");
+ok($hdr->addtag(1000, 6, "new name") == 1, "Adding a tag (string type)");
+ok($hdr->tag(1000) eq "new name", "Added tag return good value");
+}
+
+{
+my $hdr = RPM4::Header->new("$Bin/test-rpm-1.0-1mdk.noarch.rpm");
+isa_ok($hdr, "RPM4::Header", "instanciating an header from a binary rpm works");
+ok($hdr->hastag(1000) eq 1, "Has tag 1000 (NAME), yes");
+ok($hdr->tagtype(1000) eq RPM4::tagtypevalue("STRING"), "can get type of a tag");
+ok($hdr->hastag(1106) eq 0, "Has tag 1106 (SOURCEPACKAGE), no");
+ok($hdr->listtag(), "can list tag");
+is($hdr->tag(1000), "test-rpm", "accessing tag by id works");
+is($hdr->tag("NAME"), "test-rpm", "accessing tag by name works");
+is($hdr->NAME(), "test-rpm", "accessing tag directly works");
+ok($hdr->queryformat("%{NAME}-%{VERSION}-%{RELEASE}") eq "test-rpm-1.0-1mdk", "Queryformat is ok");
+ok(scalar($hdr->fullname) eq "test-rpm-1.0-1mdk.noarch", "scalar fullname works");
+ok(join(",", $hdr->fullname) eq "test-rpm,1.0,1mdk,noarch", "wantarray fullname works");
+ok($hdr->issrc == 0, "Is a src, No !");
+ok($hdr->sourcerpmname eq "test-rpm-1.0-1mdk.src.rpm", "sourcerpmname works");
+$headerfile = scalar($hdr->fullname).".hdr";
+
+
+my $hdrcopy = $hdr->copy();
+ok(defined $hdrcopy, "copy works");
+ok($hdrcopy->tag(1000) eq 'test-rpm', "tag 1000 (NAME) from copy works");
+
+open(my $hdfh, ">", $headerfile);
+ok($hdr->write($hdfh), "Write the header works");
+close($hdfh);
+
+my $size = $hdr->hsize;
+ok($size != 0, "Header size works");
+ok($size == (stat($headerfile))[7], "file size is same than in memory");
+}
+
+{
+open(my $hdfh, "< $headerfile");
+my $hdr2 = RPM4::Header->new($hdfh);
+isa_ok($hdr2, "RPM4::Header", "instanciating an header from a stream works");
+close $hdfh;
+unlink($headerfile);
+ok($hdr2->tag(1000) eq 'test-rpm', "tag 1000 from header file works");
+}
+
+
diff --git a/RPM4/t/03rpmlib.t b/RPM4/t/03rpmlib.t
new file mode 100755
index 0000000..24681bb
--- /dev/null
+++ b/RPM4/t/03rpmlib.t
@@ -0,0 +1,86 @@
+# $Id$
+
+use strict;
+use Test::More tests => 52;
+use FindBin qw($Bin);
+use RPM4;
+
+ok(! defined(RPM4::setverbosity("DEBUG")), "Set verbosity works");
+{
+my $marker = 0;
+ok(! defined(RPM4::setlogcallback(sub { my %m = @_; $marker = 1; print "$m{priority}: $m{msg}\n" } )),
+ "Setting log callback function works");
+ok(!defined(RPM4::rpmlog("ERR", "This is a rpm debug message")), "rpmlog function works");
+ok($marker == 1, "rpmlogcallback has been called");
+}
+ok(! defined(RPM4::setlogcallback(undef)), "remove callback function");
+ok(RPM4::setlogfile("logfile"), "set a log file");
+ok(!defined(RPM4::rpmlog(7, "This is a rpm debug message")), "rpmlog function works");
+ok(RPM4::setlogfile(undef), "set a log file");
+unlink("logfile");
+
+# Generic query:
+open(my $null, ">", "/dev/null");
+ok(!RPM4::dumprc($null), "Can dumprc");
+ok(!RPM4::dumpmacros($null), "Can dumpmacros");
+close($null);
+ok(length(RPM4::getosname), "Return OS name");
+ok(length(RPM4::getarchname), "Return arch name");
+ok(length(RPM4::buildhost), "Return buildhost");
+
+# Playing with macros
+my $target_cpu = RPM4::expand("%_target_cpu");
+ok(($target_cpu !~ /^\%/), "Getting _target_cpu macro");
+# setting test_macro to test
+ok(RPM4::expand("%test_macro") eq "%test_macro", "\%test_macro is no set");
+RPM4::add_macro("test_macro test");
+ok(RPM4::expand("%test_macro") eq "test", "add_macro works");
+RPM4::del_macro("test_macro");
+ok(RPM4::expand("%test_macro") eq "%test_macro", "del_macro works");
+RPM4::add_macro("test_macro test");
+ok(RPM4::expand("%test_macro") eq "test", "add_macro works");
+ok(!RPM4::resetmacros(), "Reset macro works");
+ok(!RPM4::resetrc(), "Reset rc works");
+ok(RPM4::expand("%test_macro") eq "%test_macro", "resetmacros works");
+RPM4::loadmacrosfile("$Bin/rpmmacros");
+ok(RPM4::expand("%RPM4") eq "perl-RPM4", "Checking macros define in our rpmmacros");
+ok(!RPM4::add_macro("_numeric 1"), "Add numeric macro");
+ok(RPM4::expandnumeric("%_numeric"), "expandnumeric works");
+
+ok(RPM4::readconfig("t/rpmrc") == 0, "Reading alternate config file");
+ok(RPM4::readconfig(undef, "xtentas-MandrakeSoft-osf1") == 0, "Reading conf for xtentas-MandrakeSoft-osf1");
+ok(RPM4::expand("%_target_cpu") eq "xtentas", "the conf is properly load");
+ok(RPM4::readconfig() == 0, "Re-Reading the conf, reset to default");
+ok(RPM4::expand("%_target_cpu") eq $target_cpu, "the conf is properly load");
+
+
+ok(RPM4::tagName(1000) eq "Name", "tagName works");
+ok(RPM4::tagValue("NAME") == 1000, "tagValue works");
+ok(RPM4::tagtypevalue("STRING"), "Get tage type value");
+
+# Version comparison
+ok(RPM4::rpmvercmp("1mdk", "1mdk") == 0, "rpmvercmp with =");
+ok(RPM4::rpmvercmp("1mdk", "2mdk") == -1, "rpmvercmp with <");
+ok(RPM4::rpmvercmp("2mdk", "1mdk") == 1, "rpmvercmp with >");
+
+ok(RPM4::compare_evr("1", "1") == 0, "comparing version only, equal");
+ok(RPM4::compare_evr("2", "1") == 1, "comparing version only, higther");
+ok(RPM4::compare_evr("1", "2") == -1, "comparing version only, lesser");
+ok(RPM4::compare_evr("1-1mdk", "1-1mdk") == 0, "comparing version-release only, equal");
+ok(RPM4::compare_evr("2-1mdk", "1-1mdk") == 1, "comparing version-release only, higther");
+ok(RPM4::compare_evr("1-1mdk", "2-1mdk") == -1, "comparing version-release only, lesser");
+ok(RPM4::compare_evr("1:1-1mdk", "1:1-1mdk") == 0, "comparing epoch:version-release only, equal");
+ok(RPM4::compare_evr("2:1-1mdk", "1:1-1mdk") == 1, "comparing epoch:version-release only, higther");
+ok(RPM4::compare_evr("1:1-1mdk", "2:1-1mdk") == -1, "comparing epoch:version-release only, lesser");
+
+ok(RPM4::compare_evr("0:1-1mdk", "1-1mdk") == 1, "comparing epoch 0 vs no epoch");
+ok(RPM4::compare_evr("1:1-1mdk", "1-1mdk") == 1, "comparing epoch 1 vs no epoch");
+ok(RPM4::compare_evr("1.0-1mdk", "1.0") == 1, "comparing version-release vs version only");
+ok(RPM4::compare_evr("0:1-1mdk", "1.0") == 1, "comparing epoch:version-release vs no version");
+
+ok(RPM4::osscore("osf1") == 0, "get os score");
+ok(RPM4::osscore("osf1", 1) == 0, "get build os score");
+
+ok(RPM4::archscore("noarch") != 0, "get arch score");
+ok(RPM4::archscore("noarch", 1) != 0, "get arch score");
+
diff --git a/RPM4/t/04spec.t b/RPM4/t/04spec.t
new file mode 100644
index 0000000..b1019eb
--- /dev/null
+++ b/RPM4/t/04spec.t
@@ -0,0 +1,62 @@
+# $Id$
+
+use strict;
+use Test::More tests => 23;
+use FindBin qw($Bin);
+use File::Temp qw(tempdir);
+use RPM4;
+
+my %info = RPM4::moduleinfo();
+
+my $testdir = tempdir( CLEANUP => 1 );
+mkdir("$testdir/$_") foreach (qw(BUILD RPMS RPMS/noarch SRPMS));
+
+my $passphrase = "RPM4";
+
+RPM4::add_macro("_tmppath $testdir");
+RPM4::add_macro("_builddir $testdir");
+RPM4::add_macro("_topdir $testdir");
+RPM4::add_macro("_signature gpg");
+RPM4::add_macro("_gpg_name RPM4 test key");
+RPM4::add_macro("_gpg_path $Bin/gnupg");
+
+ok((RPM4::installsrpm("$Bin/test-rpm-1.0-1mdk.src.rpm"))[0] =~ m/test-rpm\.spec$/, "installsrpms works");
+ok(!RPM4::installsrpm("$Bin/test-rpm-1.0-1mdk.noarch.rpm"), "installsrpms works");
+
+my $spec;
+if ($info{Hack} eq "Yes") {
+ ok( defined(RPM4::Spec->new()), "Create an empty spec object");
+} else {
+ ok(! defined(RPM4::Spec->new()), "Create an empty spec object don't works");
+}
+ok(!defined($spec = RPM4::Spec->new("$Bin/test-rpm-1.0-1mdk.noarch.rpm")), "Loading a bad spec file");
+ok($spec = RPM4::Spec->new("$Bin/test-rpm.spec", passphrase => $passphrase), "Loading a spec file");
+
+my @rpms = $spec->binrpm;
+ok(@rpms == 1, "Can find binary package");
+ok($rpms[0] =~ m!noarch/test-rpm-1.0-1mdk.noarch.rpm$!, "binrpm return good value");
+
+ok($spec->srcrpm =~ m!SRPMS/test-rpm-1.0-1mdk.src.rpm$!, "srcrpm return good value");
+
+ok(!defined($spec->check()), "Running spec::check");
+
+my $h;
+ok(defined($h = $spec->srcheader()), "Geting source header before build");
+ok($h->queryformat("%{NAME}") eq "test-rpm", "can querying header give by spec");
+
+ok($spec->build([ qw(PREP) ]) == 0, "simulate rpm -bp (check prep)");
+ok($spec->build([ qw(BUILD) ]) == 0, "simulate rpm -bc");
+ok($spec->build([ qw(INSTALL CHECK) ]) == 0, "simulate rpm -bi");
+ok($spec->build([ qw(FILECHECK) ]) == 0, "simulate rpm -bl");
+ok($spec->build([ qw(PACKAGEBINARY CLEAN) ]) == 0, "simulate rpm -bb (binary, clean)");
+ok($spec->build([ qw(PACKAGESOURCE) ]) == 0, "simulate rpm -bs");
+ok($spec->rpmbuild("bb") == 0, "testing spec->rpmbuild(-bb)");
+ok($spec->build([ qw(RMBUILD RMSOURCE) ]) == 0, "simulate cleaning spec, source, build");
+
+ok(defined($h = $spec->srcheader()), "Geting source header after build");
+ok($h->queryformat("%{NAME}") eq "test-rpm", "can querying header give by spec");
+
+my ($bh) = $spec->binheader();
+ok(defined($bh), "Can get binary header from spec");
+ok($bh->queryformat("%{NAME}") eq "test-rpm", "can querying header give by spec");
+
diff --git a/RPM4/t/05transaction.t b/RPM4/t/05transaction.t
new file mode 100644
index 0000000..8ee1f44
--- /dev/null
+++ b/RPM4/t/05transaction.t
@@ -0,0 +1,147 @@
+# $Id$
+
+use strict;
+use Test::More tests => 50;
+use FindBin qw($Bin);
+use File::Path;
+use File::Temp qw/tempdir/;
+use RPM4;
+use RPM4::Transaction::Problems;
+
+# Test on wrong db
+RPM4::add_macro("_dbpath /dev/null");
+ok(RPM4::rpmdbverify() != 0, "Verify non existing database (get error)");
+
+my $tempdir = tempdir();
+rmtree($tempdir) if $tempdir;
+my $testdir = "$tempdir/testdb";
+mkdir $testdir;
+
+RPM4::add_macro("_dbpath $testdir");
+
+ok(RPM4::rpmdbinit() == 0, "initdb works");
+ok(RPM4::rpmdbrebuild() == 0, "rebuild database");
+ok(RPM4::rpmdbverify() == 0, "Verify empty");
+
+my $ts;
+ok($ts = RPM4::Transaction->new(), "Open a new database");
+ok($ts->traverse(sub { print STDERR $_->tag(1000) . "\n"; }) != -1, "db->traverse()");
+
+ok($ts->importpubkey("$Bin/gnupg/test-key.gpg") == 0, "Importing a public key");
+
+my $hd = RPM4::rpm2header("$Bin/test-dep-1.0-1mdk.noarch.rpm");
+ok($hd, "Reading the header works");
+
+ok($ts->transadd($hd, "$Bin/test-dep-1.0-1mdk.noarch.rpm") == 0, "Adding a package to transaction works");
+ok($ts->transcheck() == 0, "Checking transaction works");
+ok($ts->transorder() == 0, "Run transaction order");
+
+if (0){
+my $pbs = RPM4::Transaction::Problems->new($ts);
+isa_ok(
+ $pbs,
+ 'RPM4::Db::Problems',
+ 'Can retrieve pb from transaction'
+);
+
+ok($pbs->count, "Can get number of problems");
+
+ok($pbs->init() || 1, "Resetting problems counter");
+my $strpb;
+while($pbs->hasnext()) {
+ $strpb .= $pbs->problem();
+}
+ok($strpb, "Can get problem description");
+}
+
+ok(defined($ts->transflag([qw(TEST)])), "Set transflags");
+ok($ts->transrun([ qw(LABEL PERCENT) ]) == 0, "Running transaction justdb");
+ok(!defined($ts->transreset()), "Resetting transaction");
+
+my $h = RPM4::rpm2header("$Bin/test-rpm-1.0-1mdk.noarch.rpm");
+ok($h, "Reading the header works");
+
+ok($ts->transadd($h, "$Bin/test-rpm-1.0-1mdk.noarch.rpm") == 0, "Adding a package to transaction works");
+ok($ts->traverse_transaction(sub {
+ ok($_[0]->fullname, "Can get name from te");
+ ok($_[0]->type, "Can get type from te");
+}), "traverse_transaction works");
+
+ok($ts->transcheck() == 0, "Checking transaction works");
+ok($ts->transorder() == 0, "Run transaction order");
+
+ok(defined($ts->transflag([qw(JUSTDB)])), "Set transflags");
+ok($ts->transrun( sub { my %a = @_; print STDERR "$a{what} $a{filename} $a{amount} / $a{total}\n"; }) == 0, "Running transaction justdb");
+
+ok($ts->injectheader($hd) == 0, "Injecting header in a db");
+
+my $found = 0;
+my ($rhf, $roffset);
+ok($ts->traverse( sub {
+ my ($hf, $offset) = @_;
+ scalar($hf->fullname()) eq "test-dep-1.0-1mdk.noarch" and do {
+ $found++;
+ ($rhf, $roffset) = ($hf, $offset);
+ };
+ 1;
+ }), "Running traverse");
+
+ok($found, "Can find heaer in db");
+ok($ts->deleteheader($roffset) == 0, "Removing header from db");
+
+$ts = undef; # explicitely calling DESTROY to close database
+
+ok($ts = RPM4::newdb(1), "Open existing database");
+$found = 0;
+
+($rhf, $roffset) = (undef, undef);
+ok($ts->traverse( sub {
+ my ($hf, $offset) = @_;
+ scalar($hf->fullname()) eq "test-rpm-1.0-1mdk.noarch" and do {
+ $found++;
+ ($rhf, $roffset) = ($hf, $offset);
+ }
+ }), "Running traverse");
+
+ok($found == 1, "The previously installed rpm is found");
+ok($roffset > 0, "Retrieve offset db");
+
+ok($ts->transremove_pkg("test-rpm(1.0-1mdk)") == 1, "Try to remove a rpm");
+ok($ts->transcheck() == 0, "Checking transaction works");
+ok(!defined($ts->transreset()), "Reseting current transaction");
+
+ok($ts->transremove($roffset), "Removing pkg from header and offset");
+ok($ts->transorder() == 0, "Run transaction order");
+ok($ts->transcheck() == 0, "Checking transaction works");
+ok(defined($ts->transflag([qw(JUSTDB)])), "Set transflags");
+ok($ts->transrun([ qw(LABEL PERCENT) ]) == 0, "Running transaction justdb");
+
+$found = 0;
+
+ok($ts->traverse( sub {
+ my ($hf, $offset) = @_;
+ scalar($hf->fullname()) eq "test-rpm-1.0-1mdk.noarch" and do {
+ $found++;
+ ($rhf, $roffset) = ($hf, $offset);
+ }
+ }), "Running traverse");
+
+ok($found == 0, "The previously removed rpm is not found");
+
+ok($ts->transadd($h, "test-rpm-1.0-1mdk.noarch.rpm", 1, "/usr", 1) == 0, "Adding a package to transaction with prefix");
+ok($ts->transorder() == 0, "Run transaction order");
+ok($ts->transcheck() == 0, "Checking transaction works");
+ok(!defined($ts->transreset()), "Reseting current transaction");
+
+ok($ts->transadd($h, "test-rpm-1.0-1mdk.noarch.rpm", 1, {"/etc" => "/usr" }, 1) == 0, "Adding a package to transaction with relocation works");
+ok($ts->transorder() == 0, "Run transaction order");
+ok($ts->transcheck() == 0, "Checking transaction works");
+ok(!defined($ts->transreset()), "Reseting current transaction");
+
+{
+my $spec = $ts->newspec("$Bin/test-rpm.spec");
+isa_ok($spec, 'RPM4::Spec', 'ts->newspec');
+}
+
+$ts = undef; # explicitely calling DESTROY to close database
+rmtree($tempdir);
diff --git a/RPM4/t/06sign.t b/RPM4/t/06sign.t
new file mode 100644
index 0000000..5dd0c02
--- /dev/null
+++ b/RPM4/t/06sign.t
@@ -0,0 +1,33 @@
+# $Id$
+
+use strict;
+use Test::More tests => 6;
+use FindBin qw($Bin);
+use File::Temp qw(tempdir);
+use File::Copy;
+use RPM4;
+
+my $passphrase = "RPM4";
+
+my $testdir = tempdir( CLEANUP => 1 );
+
+RPM4::add_macro("_dbpath $testdir");
+
+copy("$Bin/test-rpm-1.0-1mdk.noarch.rpm", "$testdir");
+
+RPM4::add_macro("_signature gpg");
+RPM4::add_macro("_gpg_name RPM4 test key");
+RPM4::add_macro("_gpg_path $Bin/gnupg");
+
+ok(RPM4::rpmresign($passphrase, "$testdir/test-rpm-1.0-1mdk.noarch.rpm") == 0, "can resign a rpm");
+
+ok(my $db = RPM4::newdb(1), "Open a new database");
+
+ok($db->checkrpm("$testdir/test-rpm-1.0-1mdk.noarch.rpm") != 0, "checking a rpm, key is missing");
+ok($db->checkrpm("$testdir/test-rpm-1.0-1mdk.noarch.rpm", [ "NOSIGNATURES" ]) == 0, "checking a rpm, no checking the key");
+
+ok($db->importpubkey("$Bin/gnupg/test-key.gpg") == 0, "Importing a public key");
+
+ok($db->checkrpm("$testdir/test-rpm-1.0-1mdk.noarch.rpm") == 0, "checking a rpm file");
+
+$db = undef;
diff --git a/RPM4/t/07changelogs.t b/RPM4/t/07changelogs.t
new file mode 100644
index 0000000..d2c2555
--- /dev/null
+++ b/RPM4/t/07changelogs.t
@@ -0,0 +1,18 @@
+# $Id$
+
+use strict;
+use Test::More tests => 1;
+use FindBin qw($Bin);
+use RPM4;
+use RPM4::Header::Changelogs;
+
+my $htest = RPM4::Header->new("$Bin/test-rpm-1.0-1mdk.noarch.rpm");
+
+my $ch = RPM4::Header::Changelogs->new($htest);
+
+isa_ok(
+ $ch,
+ 'RPM4::Header::Changelogs',
+ 'Get changelogs object'
+);
+
diff --git a/RPM4/t/07dep.t b/RPM4/t/07dep.t
new file mode 100644
index 0000000..e51327e
--- /dev/null
+++ b/RPM4/t/07dep.t
@@ -0,0 +1,97 @@
+# $Id$
+
+use strict;
+use Test::More tests => 43;
+use FindBin qw($Bin);
+use RPM4;
+use RPM4::Header::Dependencies;
+
+isa_ok(
+ RPM4::rpmlibdep(),
+ 'RPM4::Header::Dependencies',
+ "Can get a dep for rpmlib"
+);
+
+my $htest = RPM4::Header->new("$Bin/test-rpm-1.0-1mdk.noarch.rpm");
+my $hdep = RPM4::Header->new("$Bin/test-dep-1.0-1mdk.noarch.rpm");
+isa_ok($htest, 'RPM4::Header', '$htest');
+isa_ok($hdep, 'RPM4::Header' , '$hdep');
+
+isa_ok(
+ $hdep->dep("CONFLICTNAME"),
+ 'RPM4::Header::Dependencies',
+ '$hdep->dep("CONFLICTNAME")'
+);
+isa_ok(
+ $hdep->dep("REQUIRENAME"),
+ 'RPM4::Header::Dependencies',
+ '$hdep->dep("REQUIRENAME")'
+);
+isa_ok(
+ $hdep->dep("OBSOLETENAME"),
+ 'RPM4::Header::Dependencies',
+ '$hdep->dep("OBSOLETENAME")'
+);
+isa_ok(
+ $hdep->dep("PROVIDENAME"),
+ 'RPM4::Header::Dependencies',
+ '$hdep->dep("PROVIDENAME")'
+);
+ok(
+ ! defined $hdep->dep("TRIGGERNAME"),
+ "fetching triggers returns undef"
+);
+
+ok($htest->compare($hdep) == 0, "Compare two header");
+ok($hdep->compare($htest) == 0, "Compare two header");
+
+ok(! defined($htest->hchkdep($hdep, "REQUIRENAME")), "test-rpm requires test-dep, no");
+ok( defined($hdep->hchkdep($htest, "REQUIRENAME")), "test-dep requires test-rpm, yes");
+ok(! defined($htest->hchkdep($hdep, "OBSOLETENAME")), "test-rpm obsoletes test-dep, no");
+ok( defined($hdep->hchkdep($htest, "OBSOLETENAME")), "test-dep obsoletes test-rpm, yes");
+ok(! defined($htest->hchkdep($hdep, "CONFLICTNAME")), "test-rpm conflics test-dep, no");
+ok( defined($hdep->hchkdep($htest, "CONFLICTNAME")), "test-dep conflicts test-rpm, yes");
+ok(! defined($htest->hchkdep($hdep, "TRIGGERNAME")), "test-rpm trigger test-dep, no");
+ok(! defined($hdep->hchkdep($htest, "TRIGGERNAME")), "test-dep trigger test-rpm, no");
+ok(! defined($htest->hchkdep($hdep, "PROVIDENAME")), "test-rpm provide test-dep, no");
+ok(! defined($hdep->hchkdep($htest, "PROVIDENAME")), "test-dep provide test-rpm, no");
+
+ok( $hdep->is_better_than($htest), "test-dep better than test-rpm: yes");
+ok(! $htest->is_better_than($hdep), "test-rpm better than test-dep: no");
+
+my ($dep1, $dep2, $dep3);
+isa_ok(
+ RPM4::Header::Dependencies->new("REQUIRENAME",
+ [ "test-rpm", [ qw/LESS EQUAL/ ], "1.0-1mdk" ]
+ ),
+ 'RPM4::Header::Dependencies',
+ 'New REQUIRENAME dependencies'
+);
+
+ok($dep1 = RPM4::newdep("REQUIRENAME", "test-rpm", [ qw/LESS EQUAL/ ], "1.0-1mdk"), "Build a new dep");
+ok($dep2 = RPM4::newdep("REQUIRENAME", "test-rpm", [ qw/GREATER EQUAL/ ], "1.0-1mdk"), "Build a new dep");
+ok($dep3 = RPM4::newdep("REQUIRENAME", "test-rpm", [ "GREATER" ], "1.0-1mdk"), "Build a new dep");
+
+is($dep1->count(), 1, "dependencies number");
+ok(defined($dep1->move()), "Can move into dep");
+ok($dep1->next() == -1, "no further dependency");
+
+ok($dep1->add("test-dep", [ qw/LESS EQUAL/ ], "1.0-1mdk"), "Add a dep entry into existing dep");
+
+ok(scalar($dep1->info()) eq "R test-rpm <= 1.0-1mdk", "Can get info from RPM4::Header::Dep");
+ok(($dep1->info())[3] eq "1.0-1mdk", "Can get info from RPM4::Header::Dep");
+ok($dep1->name() eq 'test-rpm', "Get dep name from RPM4::Header::Dep");
+ok($dep1->flags(), "Get dep flags from RPM4::Header::Dep");
+ok($dep1->evr() eq '1.0-1mdk', "Get dep evr from RPM4::Header::Dep");
+
+ok($dep1->overlap($dep2), "compare two dep");
+ok($dep1->overlap($dep3) == 0, "compare two dep");
+
+ok($htest->matchdep($dep1), "Test single dep PROVIDE");
+ok($htest->matchdep($dep3) == 0, "Test single dep REQUIRE");
+
+ok($hdep->matchdep($dep1) == 0, "Test single dep PROVIDE");
+ok($htest->matchdep($dep2), "Test single dep REQUIRE");
+
+ok( $dep1->matchheadername($htest), "Dependancy match header name: yes");
+ok(! $dep1->matchheadername($hdep), "Dependancy match header name: no");
diff --git a/RPM4/t/07files.t b/RPM4/t/07files.t
new file mode 100644
index 0000000..ee5388f
--- /dev/null
+++ b/RPM4/t/07files.t
@@ -0,0 +1,37 @@
+# $Id$
+
+use strict;
+use Test::More tests => 10;
+use FindBin qw($Bin);
+use RPM4;
+
+my $htest = RPM4::Header->new("$Bin/test-rpm-1.0-1mdk.noarch.rpm");
+isa_ok($htest, 'RPM4::Header', '$htest');
+
+my $files = $htest->files();
+isa_ok($files, 'RPM4::Header::Files', '$files');
+
+is(
+ $files->count(),
+ 1,
+ "files count OK"
+);
+like(
+ $files->filename(),
+ qr!^/!,
+ "filename OK"
+);
+like(
+ $files->dirname(),
+ qr!^/!,
+ "dirname OK"
+);
+ok(defined($files->basename()), "Can get Files::basename()");
+ok(defined($files->fflags()), "Can get Files::fflags()");
+is(
+ $files->md5(),
+ "b9cb4e3dc1b8007e5c9678d1acecac47",
+ "md5 is OK"
+);
+ok(!defined($files->link()), "Can get Files::link()");
+ok(defined($files->mode()), "Can get Files::mode()");
diff --git a/RPM4/t/09hdlist.t b/RPM4/t/09hdlist.t
new file mode 100644
index 0000000..17d32f4
--- /dev/null
+++ b/RPM4/t/09hdlist.t
@@ -0,0 +1,27 @@
+# $Id$
+
+use strict;
+use Test::More tests => 6;
+use FindBin qw($Bin);
+use File::Temp qw(tempdir);
+use File::Glob;
+
+my $testdir = tempdir( CLEANUP => 1 );
+
+use_ok('RPM4');
+use_ok('RPM4::Index');
+
+my @headers;
+my $callback = sub { my %arg = @_; defined($arg{header}) and push(@headers, $arg{header}); };
+
+my @rpms = <$Bin/*.rpm>;
+
+RPM4::parserpms(callback => $callback, rpms => [ @rpms ]);
+ok(scalar(@headers) == 4, "RPM4::parserpms works");
+
+ok(RPM4::Index::buildhdlist(hdlist => "$testdir/hdlist.cz", rpms => [ @rpms ]),
+ "Creating a hdlist");
+ok(RPM4::Index::buildsynthesis(synthesis => "$testdir/synthesis.hdlist.cz", rpms => [ @rpms ]),
+ "Creating a synthesis");
+ok(RPM4::Index::buildindex(list => "$testdir/list", rpms => [ @rpms ]),
+ "Creating a list file");
diff --git a/RPM4/t/11media.t b/RPM4/t/11media.t
new file mode 100644
index 0000000..6df34bf
--- /dev/null
+++ b/RPM4/t/11media.t
@@ -0,0 +1,11 @@
+# $Id$
+
+use strict;
+use Test::More tests => 1;
+
+use_ok('RPM4::Media');
+
+
+
+
+
diff --git a/RPM4/t/gnupg/passphrase b/RPM4/t/gnupg/passphrase
new file mode 100644
index 0000000..0bff4aa
--- /dev/null
+++ b/RPM4/t/gnupg/passphrase
@@ -0,0 +1,6 @@
+RPM4
+
+# $Id$
+# This is key passphrase, this key is here only for testing.
+# Do not use it for signing/crypting.
+# Do not trust it.
diff --git a/RPM4/t/gnupg/pubring.gpg b/RPM4/t/gnupg/pubring.gpg
new file mode 100644
index 0000000..77672f4
--- /dev/null
+++ b/RPM4/t/gnupg/pubring.gpg
Binary files differ
diff --git a/RPM4/t/gnupg/secring.gpg b/RPM4/t/gnupg/secring.gpg
new file mode 100644
index 0000000..35d1b0a
--- /dev/null
+++ b/RPM4/t/gnupg/secring.gpg
Binary files differ
diff --git a/RPM4/t/gnupg/test-key.gpg b/RPM4/t/gnupg/test-key.gpg
new file mode 100644
index 0000000..f016987
--- /dev/null
+++ b/RPM4/t/gnupg/test-key.gpg
@@ -0,0 +1,26 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.2.4 (GNU/Linux)
+
+mQGiBEDpJpERBACs+drbbg4K8tPXhyTZdgwDDmejQrBFxqiPwu4CSrpx8qvjEieU
+JRGmwrv1pCSgag6bOF+04cnjaHT/FwUQpokDWRFWrHlJoFFHaP32I1n+nj/bv5Bg
+pUKgF5ZU8Jd8OeG9TZzzZUQ/EF9/QvpCN7ZdqkMoTRTzj8O8Pa6L5x/+EwCgpwA2
+1ULjab5DlcODWeBOltLtiGUD/jFBKDvOq+XxeRi4k8gEvI3UPs4utMir/e2hw1yC
+N6G3TZpOJHx+iMuy1LoqrBcwz3pZb1MwucA+QlF/imBBWurirFblOcGuw3Un6+Ef
+AeQ0kqX/76WN161xu6FAYkfIg7XUvdlEMM4svDl0jm7NbzBJHsw3Z84/jusPmCGJ
+hRCzBACTopdtD8FBzvihiCL7Fql4Vqu1U/kt2+fMXPDSduzUe8c0lgI2Irk0DBsH
+w3in1FaZrtai5f521v4b8Xqazcq7lcPVZFTrhPD8b1h21STKi4aB8QwZHZSLbP0A
+0kGLFqhyuBQ0sBRRQXNrjSufIuTto+BOplQ9srYX9dR9nssdB7R9SGRsaXN0IHRl
+c3Qga2V5IChUaGlzIGtleSBpcyBvbmx5IGZvciB0ZXN0aW5nIHJwbSBzaWduaW5n
+IHNvZnR3YXJlLCBETyBOT1QgVVNFUyBJVCwgRE8gTk9UIFRSVVNUIElUKSA8ZGV2
+ZWxAbWFuZHJha2Vzb2Z0LmNvbT6IXgQTEQIAHgUCQOkmkQIbAwYLCQgHAwIDFQID
+AxYCAQIeAQIXgAAKCRAqlxaKod9cSNLHAJ4xiVz5RIwpilxIszS+lOfs72ldFgCd
+HUFDq3t/xU+J/YdyOC2U6ojrbLy5AQ0EQOkmkRAEAMNv7Re/vT+jARIqrbbEyHjv
+vgqKiDEiBwowXOO7e3JVhGUG/vZqRFFUkPXxaXFIfosgbWFqNiKwPwTs5Avtm5gc
+U0BsxaeHsy9O4lCpyPaFc62qtDiqukRCGTRCrK0TmAJULgJmYh90fxAX11KL8fUi
+05qcI/mdM317kC6jYErjAAMFA/9WmDbkYlMAPlrU8oKSduXeFFBLTdG+5XNtf62E
+c+VKDcZKzRohEUYG/FLlzoLKp7nqGEnTaCldqIUIvJvC+5fuAVfhiae3SyAqHNxZ
+lTgIzAqjsaYOdVk2xZQZMiSM+UqTH15oXv/MgK4t/5Muwq5S6feqo/+tqJBFZ+cF
+EU0Yx4hJBBgRAgAJBQJA6SaRAhsMAAoJECqXFoqh31xISlAAn1kzaAaSc20WfhEl
+2uM8BV2NJNICAJ9o75o/N0GbzHxqZacdGVWncQv+PQ==
+=QAx/
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/RPM4/t/gnupg/trustdb.gpg b/RPM4/t/gnupg/trustdb.gpg
new file mode 100644
index 0000000..199a2f2
--- /dev/null
+++ b/RPM4/t/gnupg/trustdb.gpg
Binary files differ
diff --git a/RPM4/t/rpmmacros b/RPM4/t/rpmmacros
new file mode 100644
index 0000000..ae2aeed
--- /dev/null
+++ b/RPM4/t/rpmmacros
@@ -0,0 +1,8 @@
+# rpmmacros test file for perl-RPM4
+# $Id$
+
+%RPM4 perl-RPM4
+
+%_tmppath %(pwd)/testdir
+%_builddir %(pwd)/testdir
+%_topdir %(pwd)/testdir
diff --git a/RPM4/t/rpmrc b/RPM4/t/rpmrc
new file mode 100644
index 0000000..5ee28ee
--- /dev/null
+++ b/RPM4/t/rpmrc
@@ -0,0 +1,369 @@
+#/*! \page config_rpmrc Default configuration: /usr/lib/rpm/rpmrc
+# \verbatim
+#
+# $Id$
+#
+# This is a global RPM configuration file. All changes made here will
+# be lost when the rpm package is upgraded. Any per-system configuration
+# should be added to /etc/rpmrc, while per-user configuration should
+# be added to ~/.rpmrc.
+#
+#############################################################
+# Values for RPM_OPT_FLAGS for various platforms
+
+optflags: i386 -O2 -fomit-frame-pointer -pipe -march=i386 %{debugcflags}
+optflags: i486 -O2 -fomit-frame-pointer -pipe -march=i486 %{debugcflags}
+optflags: k6 -O2 -fomit-frame-pointer -pipe -march=k6 %{debugcflags}
+optflags: i586 -O2 -fomit-frame-pointer -pipe -march=i586 -mcpu=pentiumpro %{debugcflags}
+optflags: i686 -O2 -fomit-frame-pointer -pipe -march=i686 %{debugcflags}
+optflags: athlon -O2 -fomit-frame-pointer -pipe -march=athlon %{debugcflags}
+optflags: ia64 -O2 -pipe %{debugcflags}
+optflags: x86_64 -O2 -pipe %{debugcflags}
+optflags: amd64 -O2 -pipe %{debugcflags}
+
+ # XXX Please note that -mieee has been added in rpm-3.0.5.
+optflags: alpha -O2 -mieee -mcpu=ev5 -pipe %{debugcflags}
+optflags: alphaev5 -O2 -mieee -mcpu=ev5 -pipe %{debugcflags}
+optflags: alphaev56 -O2 -mieee -mcpu=ev56 -pipe %{debugcflags}
+optflags: alphapca56 -O2 -mieee -mcpu=pca56 -pipe %{debugcflags}
+optflags: alphaev6 -O2 -mieee -mcpu=ev6 -pipe %{debugcflags}
+optflags: alphaev67 -O2 -mieee -mcpu=ev67 -pipe %{debugcflags}
+
+optflags: sparc -O2 -m32 -mtune=ultrasparc %{debugcflags}
+optflags: sparcv9 -O2 -m32 -mcpu=ultrasparc %{debugcflags}
+optflags: sparc64 -O2 -m64 -mcpu=ultrasparc %{debugcflags}
+
+optflags: m68k -O2 %{debugcflags} -fomit-frame-pointer
+
+optflags: ppc -O2 -fsigned-char -frename-registers -mcpu=750 -mtune=7450 -pipe %{debugcflags}
+optflags: ppciseries -O2 %{debugcflags} -fsigned-char
+optflags: ppcpseries -O2 %{debugcflags} -fsigned-char
+optflags: ppc64 -O2 %{debugcflags} -fsigned-char
+
+optflags: parisc -O2 %{debugcflags} -mpa-risc-1-0
+optflags: hppa1.0 -O2 %{debugcflags} -mpa-risc-1-0
+optflags: hppa1.1 -O2 %{debugcflags} -mpa-risc-1-0
+optflags: hppa1.2 -O2 %{debugcflags} -mpa-risc-1-0
+optflags: hppa2.0 -O2 %{debugcflags} -mpa-risc-1-0
+
+optflags: mips -O2 %{debugcflags}
+optflags: mipsel -O2 %{debugcflags}
+
+optflags: armv3l -O2 %{debugcflags} -fsigned-char -fomit-frame-pointer -march=armv3
+optflags: armv4b -O2 %{debugcflags} -fsigned-char -fomit-frame-pointer -march=armv4
+optflags: armv4l -O2 %{debugcflags} -fsigned-char -fomit-frame-pointer -march=armv4
+
+optflags: atarist -O2 %{debugcflags} -fomit-frame-pointer
+optflags: atariste -O2 %{debugcflags} -fomit-frame-pointer
+optflags: ataritt -O2 %{debugcflags} -fomit-frame-pointer
+optflags: falcon -O2 %{debugcflags} -fomit-frame-pointer
+optflags: atariclone -O2 %{debugcflags} -fomit-frame-pointer
+optflags: milan -O2 %{debugcflags} -fomit-frame-pointer
+optflags: hades -O2 %{debugcflags} -fomit-frame-pointer
+
+optflags: s390 -O2 %{debugcflags}
+optflags: s390x -O2 %{debugcflags}
+
+#############################################################
+# Canonical arch names and numbers
+
+arch_canon: athlon: athlon 1
+arch_canon: i686: i686 1
+arch_canon: i586: i586 1
+arch_canon: k6: k6 1
+arch_canon: i486: i486 1
+arch_canon: i386: i386 1
+
+arch_canon: alpha: alpha 2
+arch_canon: alphaev5: alphaev5 2
+arch_canon: alphaev56: alphaev56 2
+arch_canon: alphapca56:alphapca56 2
+arch_canon: alphaev6: alphaev6 2
+arch_canon: alphaev67: alphaev67 2
+
+arch_canon: sparc: sparc 3
+arch_canon: sun4: sparc 3
+arch_canon: sun4m: sparc 3
+arch_canon: sun4c: sparc 3
+arch_canon: sun4d: sparc 3
+arch_canon: sparcv9: sparcv9 3
+# This is really a place holder for MIPS.
+arch_canon: mips: mips 4
+
+arch_canon: ppc: ppc 5
+arch_canon: ppciseries: ppciseries 5
+arch_canon: ppcpseries: ppcpseries 5
+
+arch_canon: m68k: m68k 6
+arch_canon: IP: sgi 7
+arch_canon: rs6000: rs6000 8
+arch_canon: ia64: ia64 9
+
+arch_canon: sparc64:sparc64 10
+arch_canon: sun4u: sparc64 10
+arch_canon: mipsel: mipsel 11
+
+arch_canon: armv3l: armv3l 12
+arch_canon: armv4b: armv4b 12
+arch_canon: armv4l: armv4l 12
+
+arch_canon: m68kmint: m68kmint 13
+arch_canon: atarist: m68kmint 13
+arch_canon: atariste: m68kmint 13
+arch_canon: ataritt: m68kmint 13
+arch_canon: falcon: m68kmint 13
+arch_canon: atariclone: m68kmint 13
+arch_canon: milan: m68kmint 13
+arch_canon: hades: m68kmint 13
+
+arch_canon: s390: s390 14
+arch_canon: i370: i370 14
+arch_canon: s390x: s390x 15
+
+arch_canon: ppc64: ppc64 16
+
+arch_canon: sh: sh 17
+arch_canon: xtensa: xtensa 18
+
+arch_canon: amd64: amd64 19
+arch_canon: x86_64: x86_64 19
+
+#############################################################
+# Canonical OS names and numbers
+
+os_canon: Linux: Linux 1
+os_canon: IRIX: Irix 2
+# This is wrong
+os_canon: SunOS5: solaris 3
+os_canon: SunOS4: SunOS 4
+
+os_canon: AmigaOS: AmigaOS 5
+os_canon: AIX: AIX 5
+os_canon: HP-UX: hpux10 6
+os_canon: OSF1: osf1 7
+os_canon: osf4.0: osf1 7
+os_canon: osf3.2: osf1 7
+os_canon: FreeBSD: FreeBSD 8
+os_canon: SCO_SV: SCO_SV3.2v5.0.2 9
+os_canon: IRIX64: Irix64 10
+os_canon: NEXTSTEP: NextStep 11
+os_canon: BSD_OS: bsdi 12
+os_canon: machten: machten 13
+os_canon: CYGWIN32_NT: cygwin32 14
+os_canon: CYGWIN32_95: cygwin32 15
+os_canon: UNIX_SV: MP_RAS: 16
+os_canon: MiNT: FreeMiNT 17
+os_canon: OS/390: OS/390 18
+os_canon: VM/ESA: VM/ESA 19
+os_canon: Linux/390: OS/390 20
+os_canon: Linux/ESA: VM/ESA 20
+
+#############################################################
+# For a given uname().machine, the default build arch
+
+buildarchtranslate: osfmach3_i686: i386
+buildarchtranslate: osfmach3_i586: i386
+buildarchtranslate: osfmach3_i486: i386
+buildarchtranslate: osfmach3_i386: i386
+
+buildarchtranslate: athlon: i586
+buildarchtranslate: i686: i586
+buildarchtranslate: k6: i586
+buildarchtranslate: i586: i586
+buildarchtranslate: i486: i486
+buildarchtranslate: i386: i386
+
+buildarchtranslate: alphaev5: alpha
+buildarchtranslate: alphaev56: alpha
+buildarchtranslate: alphapca56: alpha
+buildarchtranslate: alphaev6: alpha
+buildarchtranslate: alphaev67: alpha
+
+buildarchtranslate: sun4c: sparc
+buildarchtranslate: sun4d: sparc
+buildarchtranslate: sun4m: sparc
+buildarchtranslate: sparcv9: sparc
+buildarchtranslate: sun4u: sparc64
+
+buildarchtranslate: osfmach3_ppc: ppc
+buildarchtranslate: powerpc: ppc
+buildarchtranslate: powerppc: ppc
+buildarchtranslate: ppciseries: ppc
+buildarchtranslate: ppcpseries: ppc
+
+buildarchtranslate: atarist: m68kmint
+buildarchtranslate: atariste: m68kmint
+buildarchtranslate: ataritt: m68kmint
+buildarchtranslate: falcon: m68kmint
+buildarchtranslate: atariclone: m68kmint
+buildarchtranslate: milan: m68kmint
+buildarchtranslate: hades: m68kmint
+
+buildarchtranslate: s390: s390
+buildarchtranslate: s390x: s390x
+
+buildarchtranslate: ia64: ia64
+
+buildarchtranslate: amd64: amd64
+buildarchtranslate: x86_64: amd64
+
+#############################################################
+# Architecture compatibility
+
+arch_compat: alphaev67: alphaev6
+arch_compat: alphaev6: alphapca56
+arch_compat: alphapca56: alphaev56
+arch_compat: alphaev56: alphaev5
+arch_compat: alphaev5: alpha
+arch_compat: alpha: axp noarch
+
+arch_compat: athlon: i686
+arch_compat: i686: i586
+arch_compat: k6: i586
+arch_compat: i586: i486
+arch_compat: i486: i386
+arch_compat: i386: noarch
+
+arch_compat: osfmach3_i686: i686 osfmach3_i586
+arch_compat: osfmach3_i586: i586 osfmach3_i486
+arch_compat: osfmach3_i486: i486 osfmach3_i386
+arch_compat: osfmach3_i386: i486
+
+arch_compat: osfmach3_ppc: ppc
+arch_compat: powerpc: ppc
+arch_compat: powerppc: ppc
+arch_compat: ppciseries: ppc
+arch_compat: ppcpseries: ppc
+arch_compat: ppc64: ppc
+arch_compat: ppc: rs6000
+arch_compat: rs6000: noarch
+
+arch_compat: sun4c: sparc
+arch_compat: sun4d: sparc
+arch_compat: sun4m: sparc
+arch_compat: sun4u: sparc64
+arch_compat: sparc64: sparcv9
+arch_compat: sparcv9: sparc
+arch_compat: sparc: noarch
+
+arch_compat: mips: noarch
+arch_compat: mipsel: noarch
+
+arch_compat: hppa2.0: hppa1.2
+arch_compat: hppa1.2: hppa1.1
+arch_compat: hppa1.1: hppa1.0
+arch_compat: hppa1.0: parisc
+arch_compat: parisc: noarch
+
+arch_compat: armv4b: noarch
+arch_compat: armv4l: armv3l
+arch_compat: armv3l: noarch
+
+arch_compat: atarist: m68kmint noarch
+arch_compat: atariste: m68kmint noarch
+arch_compat: ataritt: m68kmint noarch
+arch_compat: falcon: m68kmint noarch
+arch_compat: atariclone: m68kmint noarch
+arch_compat: milan: m68kmint noarch
+arch_compat: hades: m68kmint noarch
+
+arch_compat: i370: noarch
+arch_compat: s390: noarch
+arch_compat: s390x: s390 noarch
+
+arch_compat: ia64: i686 noarch
+
+arch_compat: amd64: x86_64
+arch_compat: x86_64: athlon noarch
+
+os_compat: IRIX64: IRIX
+os_compat: solaris2.7: solaris2.3 solaris2.4 solaris2.5 solaris2.6
+os_compat: solaris2.6: solaris2.3 solaris2.4 solaris2.5
+os_compat: solaris2.5: solaris2.3 solaris2.4
+os_compat: solaris2.4: solaris2.3
+
+os_compat: hpux11.00: hpux10.30
+os_compat: hpux10.30: hpux10.20
+os_compat: hpux10.20: hpux10.10
+os_compat: hpux10.10: hpux10.01
+os_compat: hpux10.01: hpux10.00
+os_compat: hpux10.00: hpux9.07
+os_compat: hpux9.07: hpux9.05
+os_compat: hpux9.05: hpux9.04
+
+os_compat: osf4.0: osf3.2 osf1
+
+os_compat: ncr-sysv4.3: ncr-sysv4.2
+
+os_compat: FreeMiNT: mint MiNT TOS
+os_compat: MiNT: FreeMiNT mint TOS
+os_compat: mint: FreeMiNT MiNT TOS
+os_compat: TOS: FreeMiNT MiNT mint
+
+os_compat: BSD_OS: bsdi
+os_compat: bsdi4.0: bsdi
+
+buildarch_compat: ia64: noarch
+
+buildarch_compat: athlon: i686
+buildarch_compat: i686: i586
+buildarch_compat: k6: i486
+buildarch_compat: i586: i486
+buildarch_compat: i486: i386
+buildarch_compat: i386: noarch
+
+buildarch_compat: sun4c: noarch
+buildarch_compat: sun4d: noarch
+buildarch_compat: sun4m: noarch
+buildarch_compat: sun4u: noarch
+buildarch_compat: sparc64: noarch
+buildarch_compat: sparcv9: sparc
+buildarch_compat: sparc: noarch
+
+buildarch_compat: alphaev67: alphaev6
+buildarch_compat: alphaev6: alphapca56
+buildarch_compat: alphapca56: alphaev56
+buildarch_compat: alphaev56: alphaev5
+buildarch_compat: alphaev5: alpha
+buildarch_compat: alpha: noarch
+
+buildarch_compat: m68k: noarch
+
+buildarch_compat: ppciseries: noarch
+buildarch_compat: ppcpseries: noarch
+buildarch_compat: ppc: noarch
+buildarch_compat: ppc64: noarch
+
+buildarch_compat: mips: noarch
+buildarch_compat: mipsel: noarch
+
+buildarch_compat: armv3l: noarch
+buildarch_compat: armv4b: noarch
+buildarch_compat: armv4l: noarch
+
+buildarch_compat: hppa2.0: hppa1.2
+buildarch_compat: hppa1.2: hppa1.1
+buildarch_compat: hppa1.1: hppa1.0
+buildarch_compat: hppa1.0: parisc
+buildarch_compat: parisc: noarch
+
+buildarch_compat: atarist: m68kmint noarch
+buildarch_compat: atariste: m68kmint noarch
+buildarch_compat: ataritt: m68kmint noarch
+buildarch_compat: falcon: m68kmint noarch
+buildarch_compat: atariclone: m68kmint noarch
+buildarch_compat: milan: m68kmint noarch
+buildarch_compat: hades: m68kmint noarch
+
+buildarch_compat: s390: noarch
+buildarch_compat: s390x: noarch
+
+buildarch_compat: ia64: noarch
+
+buildarch_compat: amd64: noarch
+buildarch_compat: x86_64: noarch
+
+macrofiles: /usr/lib/rpm/macros:/usr/lib/rpm/%{_target}/macros:/etc/rpm/macros.specspo:/etc/rpm/macros.prelink:/etc/rpm/macros.solve:/etc/rpm/macros.up2date:/etc/rpm/macros:/etc/rpm/%{_target}/macros:~/.rpmmacros
+
+# \endverbatim
+#*/
diff --git a/RPM4/t/test-dep-1.0-1mdk.noarch.rpm b/RPM4/t/test-dep-1.0-1mdk.noarch.rpm
new file mode 100644
index 0000000..1e36db6
--- /dev/null
+++ b/RPM4/t/test-dep-1.0-1mdk.noarch.rpm
Binary files differ
diff --git a/RPM4/t/test-dep-1.0-1mdk.src.rpm b/RPM4/t/test-dep-1.0-1mdk.src.rpm
new file mode 100644
index 0000000..8b09d78
--- /dev/null
+++ b/RPM4/t/test-dep-1.0-1mdk.src.rpm
Binary files differ
diff --git a/RPM4/t/test-dep.spec b/RPM4/t/test-dep.spec
new file mode 100644
index 0000000..8cfb060
--- /dev/null
+++ b/RPM4/t/test-dep.spec
@@ -0,0 +1,38 @@
+# $Id$
+Summary: test rpm dependencies for perl-URPM test suite
+BuildArch: noarch
+Name: test-dep
+Version: 1.0
+Release: 1mdk
+License: GPL
+Group: Application/Development
+BuildRoot: %{_tmppath}/%{name}-root
+Requires: test-rpm
+Conflicts: test-rpm
+Obsoletes: test-rpm
+
+%description
+test rpm for dependencies
+
+%prep
+
+%build
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT%_sysconfdir
+
+date >> $RPM_BUILD_ROOT%_sysconfdir/%name
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%config(noreplace) %_sysconfdir/%name
+
+%changelog
+* Thu Apr 22 2004 Olivier Thauvin <thauvin@aerov.jussieu.fr> 1-1mdk
+- initial build
+
+
diff --git a/RPM4/t/test-rpm-1.0-1mdk.noarch.rpm b/RPM4/t/test-rpm-1.0-1mdk.noarch.rpm
new file mode 100644
index 0000000..6087dd2
--- /dev/null
+++ b/RPM4/t/test-rpm-1.0-1mdk.noarch.rpm
Binary files differ
diff --git a/RPM4/t/test-rpm-1.0-1mdk.src.rpm b/RPM4/t/test-rpm-1.0-1mdk.src.rpm
new file mode 100644
index 0000000..8f3730a
--- /dev/null
+++ b/RPM4/t/test-rpm-1.0-1mdk.src.rpm
Binary files differ
diff --git a/RPM4/t/test-rpm.spec b/RPM4/t/test-rpm.spec
new file mode 100644
index 0000000..bbd60f1
--- /dev/null
+++ b/RPM4/t/test-rpm.spec
@@ -0,0 +1,35 @@
+# $Id$
+Summary: test rpm for perl-URPM test suite
+BuildArch: noarch
+Name: test-rpm
+Version: 1.0
+Release: 1mdk
+License: GPL
+Group: Application/Development
+BuildRoot: %{_tmppath}/%{name}-root
+
+%description
+test rpm
+
+%prep
+
+%build
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT%_sysconfdir
+
+date >> $RPM_BUILD_ROOT%_sysconfdir/%name
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%config(noreplace) %_sysconfdir/%name
+
+%changelog
+* Thu Apr 22 2004 Olivier Thauvin <thauvin@aerov.jussieu.fr> 1-1mdk
+- initial build
+
+