summaryrefslogtreecommitdiff
path: root/Build/Rpmmd.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Build/Rpmmd.pm')
-rw-r--r--Build/Rpmmd.pm205
1 files changed, 205 insertions, 0 deletions
diff --git a/Build/Rpmmd.pm b/Build/Rpmmd.pm
new file mode 100644
index 0000000..de5cfb6
--- /dev/null
+++ b/Build/Rpmmd.pm
@@ -0,0 +1,205 @@
+################################################################
+#
+# Copyright (c) 1995-2014 SUSE Linux Products GmbH
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or 3 as
+# published by the Free Software Foundation.
+#
+# 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 (see the file COPYING); if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+################################################################
+
+package Build::Rpmmd;
+
+use strict;
+
+use XML::Parser;
+
+sub generic_parse {
+ my ($how, $in, $res, %options) = @_;
+ $res ||= [];
+ my @cursor = ([undef, $how, undef, $res, undef, \%options]);
+ my $p = new XML::Parser(Handlers => {
+ Start => sub {
+ my ($p, $el) = @_;
+ my $h = $cursor[-1]->[1];
+ return unless exists $h->{$el};
+ $h = $h->{$el};
+ push @cursor, [$el, $h];
+ $cursor[-1]->[2] = '' if $h->{'_text'};
+ $h->{'_start'}->($h, \@cursor, @_) if exists $h->{'_start'};
+ },
+ End => sub {
+ my ($p, $el) = @_;
+ if ($cursor[-1]->[0] eq $el) {
+ my $h = $cursor[-1]->[1];
+ $h->{'_end'}->($h, \@cursor, @_) if exists $h->{'_end'};
+ pop @cursor;
+ }
+ },
+ Char => sub {
+ my ($p, $text) = @_;
+ $cursor[-1]->[2] .= $text if defined $cursor[-1]->[2];
+ },
+ }, ErrorContext => 2);
+ if (ref($in)) {
+ $p->parse($in);
+ } else {
+ $p->parsefile($in);
+ }
+ return $res;
+}
+
+sub generic_store_text {
+ my ($h, $c, $p, $el) = @_;
+ my $data = $c->[0]->[4];
+ $data->{$h->{'_tag'}} = $c->[-1]->[2] if defined $c->[-1]->[2];
+}
+
+sub generic_store_attr {
+ my ($h, $c, $p, $el, %attr) = @_;
+ my $data = $c->[0]->[4];
+ $data->{$h->{'_tag'}} = $attr{$h->{'_attr'}} if defined $attr{$h->{'_attr'}};
+}
+
+sub generic_new_data {
+ my ($h, $c, $p, $el, %attr) = @_;
+ $c->[0]->[4] = {};
+ generic_store_attr(@_) if $h->{'_attr'};
+}
+
+sub generic_add_result {
+ my ($h, $c, $p, $el) = @_;
+ my $data = $c->[0]->[4];
+ return unless $data;
+ my $res = $c->[0]->[3];
+ if (ref($res) eq 'CODE') {
+ $res->($data);
+ } else {
+ push @$res, $data;
+ }
+ undef $c->[0]->[4];
+}
+
+my $repomdparser = {
+ repomd => {
+ data => {
+ _start => \&generic_new_data,
+ _attr => 'type',
+ _tag => 'type',
+ _end => \&generic_add_result,
+ location => { _start => \&generic_store_attr, _attr => 'href', _tag => 'location'},
+ size => { _text => 1, _end => \&generic_store_text, _tag => 'size'},
+ },
+ },
+};
+
+my $primaryparser = {
+ metadata => {
+ 'package' => {
+ _start => \&generic_new_data,
+ _attr => 'type',
+ _tag => 'type',
+ _end => \&primary_add_result,
+ name => { _text => 1, _end => \&generic_store_text, _tag => 'name' },
+ arch => { _text => 1, _end => \&generic_store_text, _tag => 'arch' },
+ version => { _start => \&primary_handle_version },
+ 'time' => { _start => \&primary_handle_time },
+ format => {
+ 'rpm:provides' => { 'rpm:entry' => { _start => \&primary_handle_dep , _tag => 'provides' }, },
+ 'rpm:requires' => { 'rpm:entry' => { _start => \&primary_handle_dep , _tag => 'requires' }, },
+ 'rpm:conflicts' => { 'rpm:entry' => { _start => \&primary_handle_dep , _tag => 'conflicts' }, },
+ 'rpm:recommends' => { 'rpm:entry' => { _start => \&primary_handle_dep , _tag => 'recommends' }, },
+ 'rpm:suggests' => { 'rpm:entry' => { _start => \&primary_handle_dep , _tag => 'suggests' }, },
+ 'rpm:supplements' => { 'rpm:entry' => { _start => \&primary_handle_dep , _tag => 'supplements' }, },
+ 'rpm:enhances' => { 'rpm:entry' => { _start => \&primary_handle_dep , _tag => 'enhances' }, },
+ 'rpm:obsoletes' => { 'rpm:entry' => { _start => \&primary_handle_dep , _tag => 'obsoletes' }, },
+ 'rpm:buildhost' => { _text => 1, _end => \&generic_store_text, _tag => 'buildhost' },
+ 'rpm:sourcerpm' => { _text => 1, _end => \&primary_handle_sourcerpm , _tag => 'source' },
+### currently commented out, as we ignore file provides in expanddeps
+# file => { _text => 1, _end => \&primary_handle_file_end, _tag => 'provides' },
+ },
+ location => { _start => \&generic_store_attr, _attr => 'href', _tag => 'location'},
+ },
+ },
+};
+
+sub primary_handle_sourcerpm {
+ my ($h, $c, $p, $el, %attr) = @_;
+ my $data = $c->[0]->[4];
+ return unless defined $c->[-1]->[2];
+ $c->[-1]->[2] =~ s/-[^-]*-[^-]*\.[^\.]*\.rpm$//;
+ $data->{$h->{'_tag'}} = $c->[-1]->[2];
+}
+
+sub primary_handle_version {
+ my ($h, $c, $p, $el, %attr) = @_;
+ my $data = $c->[0]->[4];
+ $data->{'epoch'} = $attr{'epoch'} if $attr{'epoch'};
+ $data->{'version'} = $attr{'ver'};
+ $data->{'release'} = $attr{'rel'};
+}
+
+sub primary_handle_time {
+ my ($h, $c, $p, $el, %attr) = @_;
+ my $data = $c->[0]->[4];
+ $data->{'filetime'} = $attr{'file'} if $attr{'file'};
+ $data->{'buildtime'} = $attr{'build'} if $attr{'build'};
+}
+
+sub primary_handle_file_end {
+ my ($h, $c, $p, $el) = @_;
+ primary_handle_dep($h, $c, $p, $el, 'name', $c->[-1]->[2]);
+}
+
+my %flagmap = ( EQ => '=', LE => '<=', GE => '>=', GT => '>', LT => '<', NE => '!=' );
+
+sub primary_handle_dep {
+ my ($h, $c, $p, $el, %attr) = @_;
+ my $dep = $attr{'name'};
+ return if $dep =~ /^rpmlib\(/;
+ if(exists $attr{'flags'}) {
+ my $evr = $attr{'ver'};
+ return unless defined($evr) && exists($flagmap{$attr{'flags'}});
+ $evr = "$attr{'epoch'}:$evr" if $attr{'epoch'};
+ $evr .= "-$attr{'rel'}" if defined $attr{'rel'};
+ $dep .= " $flagmap{$attr{'flags'}} $evr";
+ }
+ my $data = $c->[0]->[4];
+ push @{$data->{$h->{'_tag'}}}, $dep;
+}
+
+sub primary_add_result {
+ my ($h, $c, $p, $el) = @_;
+ my $options = $c->[0]->[5] || {};
+ my $data = $c->[0]->[4];
+ if ($options->{'addselfprovides'} && defined($data->{'name'}) && defined($data->{'version'})) {
+ if (($data->{'arch'} || '') ne 'src' && ($data->{'arch'} || '') ne 'nosrc') {
+ my $evr = $data->{'version'};
+ $evr = "$data->{'epoch'}:$evr" if $data->{'epoch'};
+ $evr = "$evr-$data->{'release'}" if defined $data->{'release'};
+ my $s = "$data->{'name'} = $evr";
+ push @{$data->{'provides'}}, $s unless grep {$_ eq $s} @{$data->{'provides'} || []};
+ }
+ }
+ return generic_add_result(@_);
+}
+
+sub parse_repomd {
+ return generic_parse($repomdparser, @_);
+}
+
+sub parse {
+ return generic_parse($primaryparser, @_);
+}
+
+1;