aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Youri/Package/RPM4.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Youri/Package/RPM4.pm')
-rw-r--r--lib/Youri/Package/RPM4.pm424
1 files changed, 424 insertions, 0 deletions
diff --git a/lib/Youri/Package/RPM4.pm b/lib/Youri/Package/RPM4.pm
new file mode 100644
index 0000000..b1ed5d8
--- /dev/null
+++ b/lib/Youri/Package/RPM4.pm
@@ -0,0 +1,424 @@
+# $Id: /local/youri/soft/trunk/lib/Youri/Package/URPM.pm 2129 2006-06-23T09:41:01.599329Z guillomovitch $
+package Youri::Package::RPM4;
+
+=head1 NAME
+
+Youri::Package::RPM4 - URPM-based rpm package implementation
+
+=head1 DESCRIPTION
+
+This is an RPM4-based L<Youri::Package> implementation for rpm.
+
+=cut
+
+use strict;
+use warnings;
+use Carp;
+use RPM4;
+use RPM4::Header;
+use RPM4::Sign;
+use File::Spec;
+use Scalar::Util qw/refaddr/;
+use base 'Youri::Package::RPM';
+use overload
+ '""' => 'as_string',
+ '0+' => '_to_number',
+ fallback => 1;
+
+=head1 CLASS METHODS
+
+=head2 new(%args)
+
+Creates and returns a new Youri::Package::RPM4 object.
+
+Specific parameters:
+
+=over
+
+=item file $file
+
+Path of file to use for creating this package.
+
+=item header $header
+
+L<RPM4::Header> object to use for creating this package.
+
+=back
+
+=cut
+
+sub _init {
+ my ($self, %options) = @_;
+
+ my $header;
+ HEADER: {
+ if (exists $options{header}) {
+ croak "undefined header"
+ unless $options{header};
+ croak "invalid header"
+ unless $options{header}->isa('RPM4::Header');
+ $header = $options{header};
+ last HEADER;
+ }
+
+ if (exists $options{file}) {
+ croak "undefined file"
+ unless $options{file};
+ croak "non-existing file $options{file}"
+ unless -f $options{file};
+ croak "non-readable file $options{file}"
+ unless -r $options{file};
+ $header = RPM4::Header->new($options{file});
+ croak "Can't get header from file $options{file}" if (!$header);
+
+ last HEADER;
+ }
+
+ croak "no way to extract header from arguments";
+ }
+
+ $self->{_header} = $header;
+ $self->{_file} = File::Spec->rel2abs($options{file});
+}
+
+sub compare_versions {
+ my ($class, $version1, $version2) = @_;
+
+ return RPM4::rpmvercmp($version1, $version2);
+}
+
+sub _depsense2flag {
+ my ($string) = @_;
+ my @flags = 0;
+ push(@flags, 'EQUAL') if ($string =~ /=/);
+ push(@flags, 'LESS') if ($string =~ /</);
+ push(@flags, 'GREATER') if ($string =~ />/);
+ return \@flags;
+}
+
+sub check_ranges_compatibility {
+ my ($class, $range1, $range2) = @_;
+ my @deps1 = split(/ /, $range1);
+ my @deps2 = split(/ /, $range2);
+ $deps1[1] = _depsense2flag($range1);
+ $deps2[1] = _depsense2flag($range2);
+ my $dep1 = RPM4::Header::Dependencies(
+ "PROVIDENAME",
+ \@deps1,
+ );
+ my $dep2 = RPM4::Header::Dependencies(
+ "PROVIDENAME",
+ \@deps2,
+ );
+
+ return $dep1->overlap($dep2);
+}
+
+sub get_name {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('name');
+}
+
+sub get_version {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('version');
+}
+
+sub get_release {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('release');
+}
+
+sub get_revision {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->queryformat('%|EPOCH?{%{EPOCH}:}:{}|%{VERSION}-%{RELEASE}');
+}
+
+sub get_file_name {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->queryformat('%{NAME}-%{VERSION}-%{RELEASE}.%|SOURCERPM?{%{ARCH}}:{src}|.rpm');
+}
+
+
+sub get_arch {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->queryformat('%|SOURCERPM?{%{ARCH}}:{src}|');
+}
+
+sub get_url {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('url');
+}
+
+sub get_summary {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('summary');
+}
+
+sub get_description {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('description');
+}
+
+sub get_packager {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('packager');
+}
+
+sub is_source {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->issrc();
+}
+
+sub is_binary {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return !$self->{_header}->issrc();
+}
+
+sub get_type {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return
+ $self->{_header}->issrc() ?
+ "source" :
+ "binary";
+}
+
+sub get_age {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('buildtime');
+}
+
+sub get_source_package {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->tag('sourcerpm');
+}
+
+sub get_canonical_name {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ $self->{_header}->sourcerpmname() =~ /^(\S+)-[^-]+-[^-]+\.src\.rpm$/;
+ return $1;
+}
+
+sub get_tag {
+ my ($self, $tag) = @_;
+ croak "Not a class method" unless ref $self;
+ #croak "invalid tag $tag" unless $self->{_header}->can($tag);
+ return $self->{_header}->tag($tag);
+}
+
+
+sub _get_dependencies {
+ my ($self, $deptype) = @_;
+ my $deps = $self->{_header}->dep($deptype);
+ my @deps_list;
+ if ($deps) {
+ $deps->init();
+ while ($deps->next() >= 0) {
+ my @deps = $deps->info();
+ $deps[1] =~ m/^rpmlib\(/ and next; # skipping internal rpmlib dep
+ $deps[2] =~ s/^=$/==/; # rpm say foo = 1, not foo == 1, == come from URPM, which sucks
+ my $range = $deps[3] ? ($deps[2] . ' ' . $deps[3]) : undef;
+ push(@deps_list, [ $deps[1], $range ]);
+ }
+ }
+ @deps_list
+}
+
+sub get_requires {
+ my ($self) = @_;
+
+ return $self->_get_dependencies('REQUIRENAME');
+}
+
+sub get_provides {
+ my ($self) = @_;
+
+ return $self->_get_dependencies('PROVIDENAME');
+}
+
+sub get_obsoletes {
+ my ($self) = @_;
+
+ return $self->_get_dependencies('OBSOLETENAME');
+}
+
+sub get_conflicts {
+ my ($self) = @_;
+
+ return $self->_get_dependencies('CONFLICTNAME');
+}
+
+sub get_files {
+ my ($self) = @_;
+
+ my $files = $self->{_header}->files();
+ my @fileslist;
+ if ($files) {
+ $files->init();
+ while ($files->next() >= 0) {
+ my $smode = $files->mode();
+ my $umode = 0;
+ foreach (0..15) { # converting unsigned to signed int :\
+ $umode |= $smode & (1 << $_);
+ }
+ push(@fileslist, [ $files->filename(), $umode, $files->md5() || '' ]);
+ }
+ }
+ @fileslist
+}
+
+sub get_gpg_key {
+ my ($self) = @_;
+
+ my $signature = $self->{_header}->queryformat('%{SIGGPG:pgpsig}');
+
+ return if $signature eq '(not a blob)';
+
+ my $key_id = (split(/\s+/, $signature))[-1];
+
+ return substr($key_id, 8);
+}
+
+sub get_information {
+ my ($self) = @_;
+
+ return $self->{_header}->queryformat(<<EOF);
+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}
+EOF
+}
+
+sub get_changes {
+ my ($self) = @_;
+
+ my @names = $self->{_header}->tag('changelogname');
+ my @time = $self->{_header}->tag('changelogtime');
+ my @text = $self->{_header}->tag('changelogtext');
+
+ my @changes;
+ foreach my $i (0 .. $#names) {
+ $changes[$i] = [
+ $names[$i],
+ $time[$i],
+ $text[$i],
+ ];
+ }
+
+ return @changes;
+}
+
+sub get_last_change {
+ my ($self) = @_;
+
+ return [
+ ($self->{_header}->tag('changelogname'))[0],
+ ($self->{_header}->tag('changelogtime'))[0],
+ ($self->{_header}->tag('changelogtext'))[0],
+ ];
+}
+
+sub as_string {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->fullname();
+}
+
+sub as_formated_string {
+ my ($self, $format) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->queryformat($format);
+}
+
+sub _to_number {
+ return refaddr($_[0]);
+}
+
+sub compare {
+ my ($self, $package) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->{_header}->compare($package->{_header}) || 0;
+}
+
+sub satisfy_range {
+ my ($self, $range) = @_;
+ croak "Not a class method" unless ref $self;
+
+ return $self->check_range_compatibility($self->get_revision(), $range);
+}
+
+sub sign {
+ my ($self, $name, $path, $passphrase) = @_;
+ croak "Not a class method" unless ref $self;
+
+ # check if parent directory is writable
+ my $parent = (File::Spec->splitpath($self->{_file}))[1];
+ croak "Unsignable package, parent directory is read-only"
+ unless -w $parent;
+
+ my $sign = RPM4::Sign->new(
+ name => $name,
+ path => $path,
+ );
+ $sign->{passphrase} = $passphrase;
+
+ $sign->rpmssign($self->{_file})
+}
+
+sub extract {
+ my ($self) = @_;
+ croak "Not a class method" unless ref $self;
+
+ system("rpm2cpio $self->{_file} | cpio -id >/dev/null 2>&1");
+}
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2002-2006, YOURI project
+
+This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
+
+=cut
+
+1;