rpm/perl-RPM2/RPM2.pm

416 lines
8.0 KiB
Perl

package RPM2;
use 5.00503;
use strict;
use DynaLoader;
use Data::Dumper;
use Cwd qw/realpath/;
use vars qw/$VERSION/;
$VERSION = '0.60';
use vars qw/@ISA/;
@ISA = qw/DynaLoader/;
bootstrap RPM2 $VERSION;
sub open_rpm_db {
my $class = shift;
my %params = @_;
my $self = bless { }, "RPM2::DB";
if ($params{-path}) {
$class->add_macro("_dbpath", $params{-path});
$self->{c_db} = RPM2::_open_rpm_db($params{-readwrite} ? 1 : 0);
$class->delete_macro("_dbpath");
}
else {
$self->{c_db} = RPM2::_open_rpm_db($params{-readwrite} ? 1 : 0);
}
return $self;
}
sub open_package {
my $class = shift;
my $file = shift;
open FH, "<$file"
or die "Can't open $file: $!";
my $hdr = RPM2::_read_package_info(*FH);
close FH;
$hdr = RPM2::Header->_new_raw($hdr, realpath($file));
return $hdr;
}
package RPM2::DB;
sub find_all_iter {
my $self = shift;
return RPM2::PackageIterator->new_iterator($self, "RPMTAG_NAME")
}
sub find_all {
my $self = shift;
return RPM2::PackageIterator->new_iterator($self)->expand_iter();
}
sub find_by_name_iter {
my $self = shift;
my $name = shift;
return RPM2::PackageIterator->new_iterator($self, "RPMTAG_NAME", $name);
}
sub find_by_name {
my $self = shift;
my $name = shift;
return $self->find_by_name_iter($name)->expand_iter;
}
sub find_by_provides_iter {
my $self = shift;
my $name = shift;
return RPM2::PackageIterator->new_iterator($self, "RPMTAG_PROVIDES", $name);
}
sub find_by_provides {
my $self = shift;
my $name = shift;
return $self->find_by_provides_iter($name)->expand_iter;
}
sub find_by_requires_iter {
my $self = shift;
my $name = shift;
return RPM2::PackageIterator->new_iterator($self, "RPMTAG_REQUIRENAME", $name);
}
sub find_by_requires {
my $self = shift;
my $name = shift;
return $self->find_by_requires_iter($name)->expand_iter;
}
sub find_by_file_iter {
my $self = shift;
my $name = shift;
return RPM2::PackageIterator->new_iterator($self, "RPMTAG_BASENAMES", $name);
}
sub find_by_file {
my $self = shift;
my $name = shift;
return $self->find_by_file_iter($name)->expand_iter;
}
package RPM2::Header;
use overload '<=>' => \&op_spaceship,
'bool' => \&op_bool;
sub _new_raw {
my $class = shift;
my $c_header = shift;
my $filename = shift;
my $self = bless { }, $class;
$self->{c_header} = $c_header;
$self->{filename} = $filename if defined $filename;
return $self;
}
sub tag {
my $self = shift;
my $tag = shift;
$tag = uc "RPMTAG_$tag";
die "tag $tag invalid"
unless exists $RPM2::header_tag_map{$tag};
return $self->{c_header}->tag_by_id($RPM2::header_tag_map{$tag});
}
sub tagformat {
my $self = shift;
my $format = shift;
return RPM2::C::Header::_header_sprintf($self->{c_header}, $format);
}
sub compare {
my $h1 = shift;
my $h2 = shift;
return RPM2::C::Header::_header_compare($h1->{c_header}, $h2->{c_header});
}
sub op_bool {
my $self = shift;
return defined($self) && defined($self->{c_header});
}
sub op_spaceship {
my $h1 = shift;
my $h2 = shift;
my $ret = $h1->compare($h2);
# rpmvercmp can return any neg/pos number; normalize here to -1, 0, 1
return 1 if $ret > 0;
return -1 if $ret < 0;
return 0;
}
sub is_source_package {
my $self = shift;
return $self->tag("sourcepackage");
}
sub filename {
my $self = shift;
if (exists $self->{filename}) {
return $self->{filename};
}
return;
}
sub as_nvre {
my $self = shift;
my $epoch = $self->tag('epoch');
my $epoch_str = '';
$epoch_str = "$epoch:" if defined $epoch;
my $ret = $epoch_str . join("-", map { $self->tag($_) } qw/name version release/);
return $ret;
}
foreach my $tag (keys %RPM2::header_tag_map) {
$tag =~ s/^RPMTAG_//g;
my $sub = q {
sub [[method]] {
my $self = shift;
return $self->tag("[[tag]]");
}
};
my $method = lc $tag;
$sub =~ s/\[\[method\]\]/$method/g;
$sub =~ s/\[\[tag\]\]/$tag/g;
eval $sub;
if ($@) {
die $@;
}
}
sub files {
my $self = shift;
if (not exists $self->{files}) {
my @base_names = $self->tag('basenames');
my @dir_names = $self->tag('dirnames');
my @dir_indexes = $self->tag('dirindexes');
my @files;
foreach (0 .. $#base_names) {
push @files, $dir_names[$dir_indexes[$_]] . $base_names[$_];
}
$self->{files} = \@files;
}
return @{$self->{files}};
}
package RPM2::PackageIterator;
sub new_iterator {
my $class = shift;
my $db = shift;
my $tag = shift;
my $key = shift;
my $self = bless { }, $class;
$self->{c_iter} = RPM2::C::DB::_init_iterator($db->{c_db},
$RPM2::header_tag_map{$tag},
$key || "",
defined $key ? length $key : 0);
return $self;
}
sub next {
my $self = shift;
return unless $self->{c_iter};
my $hdr = $self->{c_iter}->_iterator_next();
return unless $hdr;
my $ret = RPM2::Header->_new_raw($hdr);
return $ret;
}
sub expand_iter {
my $self = shift;
my @ret;
while (my $h = $self->next) {
push @ret, $h;
}
return @ret;
}
# Preloaded methods go here.
1;
__END__
# Below is stub documentation for your module. You better edit it!
=head1 NAME
RPM2 - Perl bindings for the RPM Package Manager API
=head1 SYNOPSIS
use RPM2;
my $db = RPM2->open_rpm_db();
my $i = $db->find_all_iter();
print "The following packages are installed (aka, 'rpm -qa'):\n";
while (my $pkg = $i->next) {
print $pkg->as_nvre, "\n";
}
$i = $db->find_by_name_iter("kernel");
print "The following kernels are installed (aka, 'rpm -q kernel'):\n";
while (my $pkg = $i->next) {
print $pkg->as_nvre, " ", int($pkg->size()/1024), "k\n";
}
$i = $db->find_by_provides_iter("kernel");
print "The following packages provide 'kernel' (aka, 'rpm -q --whatprovides kernel'):\n";
while (my $pkg = $i->next) {
print $pkg->as_nvre, " ", int($pkg->size()/1024), "k\n";
}
print "The following packages are installed (aka, 'rpm -qa' once more):\n";
foreach my $pkg ($db->find_by_file("/bin/sh")) {
print $pkg->as_nvre, "\n";
}
my $pkg = RPM2->open_package("/tmp/XFree86-4.1.0-15.src.rpm");
print "Package opened: ", $pkg->as_nvre(), ", is source: ", $pkg->is_source_package, "\n";
=head1 DESCRIPTION
The RPM2 module provides an object-oriented interface to querying both
the installed RPM database as well as files on the filesystem.
=head1 CLASS METHODS
Pretty much all use of the class starts here. There are two main
entrypoints into the package -- either through the database of
installed rpms (aka the rpmdb) or through a file on the filesystem
(such as kernel-2.4.9-31.src.rpm or kernel-2.4.9-31.i386.rpm
You can have multiple RPM databases open at once, as well as running
multiple queries on each.
=item open_rpm_db(-path => "/path/to/db")
As it sounds, it opens the RPM database, and returns it as an object.
=item open_package("foo-1.1-14.noarch.rpm")
Opens a specific package (RPM or SRPM). Returns a Header object.
=head1 RPM DB object methods
=item find_all_iter()
Returns an iterator object that iterates over the entire database.
=item find_all()
Returns an list of all of the results of the find_all_iter() method.
=item find_by_file_iter($filename)
Returns an iterator that returns all packages that contain a given file.
=item find_by_file($filename)
Ditto, except it just returns the list
=item find_by_name_iter($package_name)
You get the idea. This one is for iterating by package name.
=item find_by_name($package_name)
Ditto, except it returns a list.
=item find_by_provides_iter($provides_string)
This one iterates over provides.
=item find_by_provides($provides_string)
Ditto, except it returns a list.
=item find_by_requires_iter($requires_string)
This one iterates over requires.
=item find_by_requires($requires_string)
Ditto, except it returns a list.
=head1 RPM Header object methods
stuff goes here
=head1 TODO
Package installation and removal.
Signature validation.
=head1 HISTORY
=over 8
=item 0.01
Initial release
=back
=head1 AUTHOR
Chip Turner E<lt>cturner@redhat.comE<gt>
=head1 SEE ALSO
L<perl>.
The original L<RPM> module.
=cut