| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968 |
- ##
- ## openpkg-index.pl -- create index from spec files
- ##
- ## Copyright (c) 2000-2003 Cable & Wireless Deutschland GmbH
- ## Copyright (c) 2000-2003 The OpenPKG Project <http://www.openpkg.org/>
- ## Copyright (c) 2000-2003 Ralf S. Engelschall <rse@engelschall.com>
- ##
- ## Permission to use, copy, modify, and distribute this software for
- ## any purpose with or without fee is hereby granted, provided that
- ## the above copyright notice and this permission notice appear in all
- ## copies.
- ##
- ## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
- ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- ## SUCH DAMAGE.
- ##
- require 5;
- use strict;
- use Getopt::Std;
- getopts('r:p:C:o:ci');
- use vars qw/$opt_r $opt_p $opt_C $opt_o $opt_c $opt_i/;
- use FileHandle;
- use DirHandle;
- my $l_prefix = '@l_prefix@';
- my $RPM = "$l_prefix/bin/rpm";
- my $R2C = "$l_prefix/bin/rpm2cpio";
- my $BZ = "$l_prefix/lib/openpkg/bzip2 -9";
- #########################################################################
- #
- # escape XML special characters for output in RDF file
- #
- # remove trailing whitespace
- # remove common leading whitespace
- #
- sub e ($) {
- my($s) = @_;
- my($i);
- $s =~ s/\n+$//sg;
- $s =~ s/[^\S\n]+$//mg;
- $i = undef;
- while ($s =~ /^([^\S\n]+)/mg) {
- $i = $1 if !defined $i || length($1) < length($i);
- }
- $s =~ s/^\Q$i\E//mg if defined $i;
- $s =~ s/&/&/sg;
- $s =~ s/</</sg;
- $s =~ s/>/>/sg;
- return $s;
- }
- my %attrname = (
- '==' => 'equ',
- '=' => 'equ',
- '>=' => 'geq',
- '=>' => 'geq',
- '<=' => 'leq',
- '=<' => 'leq',
- '>' => 'gt',
- '<' => 'lt'
- );
- my($opreg) = join '|',
- map {
- "\Q$_\E"
- } sort {
- length($b) <=> length($a) ||
- $b cmp $a
- } keys %attrname;
- sub make_resource ($) {
- my($s) = @_;
- if ($s =~ /(\S+)\s*($opreg)\s*(.*?)\s*$/o) {
- return {
- resource => $1,
- attrname => $attrname{$2},
- attrval => $3
- }
- }
- return {
- resource => $s
- }
- }
- sub commasep ($$) {
- my($k,$v) = @_;
- if ($k =~ /^(NoSource)$/) {
- return split(/\s*,\s*/, $v);
- } elsif ($k =~ /^(PreReq|BuildPreReq|Provides|Conflicts)$/) {
- return map { make_resource($_) }
- split(/\s*,\s*/, $v);
- }
- return $v;
- }
- sub optesc ($) {
- my($s) = @_;
- $s =~ s/([\x00-\x1f\x80-\xbf\s\%])/sprintf("%%%02x",ord($1))/eg;
- return $s;
- }
- sub vsub ($$) {
- my($var,$v) = @_;
- $v =~ s/\%\{([^}]+)\}/exists $var->{$1} ? $var->{$1} : '%{'.$1.'}'/emg;
- return $v;
- }
- sub upn ($) {
- my($t) = @_;
- my(@tok) = $t =~ /(\(|\)|\&\&|\|\||\!|\S+)/g;
- my(@out,$op,$o);
- my(@save);
- $op = [];
- foreach (@tok) {
- if ($_ eq '(') {
- push @save, $op;
- $op = [];
- } elsif ($_ eq ')') {
- die "FATAL: unresolved operators in: @tok\n" if @$op;
- $op = pop @save
- or die "FATAL: parenthesis stack underflow in: @tok\n";
- while ($o = pop @$op) {
- push @out, $o->[0];
- last if $o->[1];
- }
- } elsif ($_ eq '&&') {
- push @$op, [ '+', 1 ] ;
- } elsif ($_ eq '||') {
- push @$op, [ '|', 1 ] ;
- } elsif ($_ eq '!') {
- push @$op, [ '!', 0 ];
- } elsif (/^\%\{(\S*?)\}$/) {
- push @out, $1;
- while ($o = pop @$op) {
- push @out, $o->[0];
- last if $o->[1]; # binop
- }
- }
- }
- return join (' ',@out);
- }
- #
- # deduce external variables from description
- #
- # before openpkg-20021230
- #
- sub find_options ($) {
- my($descr) = @_;
- my $evar = {};
- $descr =~ s/--define\s*'(\S+)\s*\%\{\1\}'/$evar->{$1} = '%{'.$1.'}', ''/sge;
- return $evar;
- }
- #
- # translate default section from spec-file
- # into a hash
- # %if/%ifdef/%define... are translated to #if/#ifdef/#define
- #
- # #defines are interpolated (correct ?)
- #
- # #if/#ifdef/... sections are stripped
- # result is the same as if all conditions evaluate false (!)
- #
- # all attributes are of the form key: value
- # repeated attributes are coalesced into a list
- #
- sub package2data ($$) {
- my($s,$ovar) = @_;
- my(%evar,%var);
- my(@term, $term);
- my(%attr);
- my($l, $v, $cond, $d, $p);
- my($re,@defs);
- # combine multilines
- $s =~ s/\\\n/ /sg;
- #
- # map conditional variable macros
- #
- $s =~ s/^#\{\!\?([^:]*):\s*%(.*?)\s*\}\s*$/#ifndef $1\n#$2\n#endif/mg;
- $s =~ s/^#\{\!\?([^:]*):\s*(.*?)\s*\}\s*$/#ifndef $1\n$2\n#endif/mg;
- #
- # map option macro
- #
- $s =~ s/^#option\s+(\S+)\s*(.*?)\s*$/#ifndef $1\n#define $1 $2\n#endif\n#provides $1 $2/mg;
- #
- # use option variables for interpolation
- #
- %evar = %$ovar;
- #
- # guess more external parameters by scanning for "default" sections.
- #
- $re = '^\#ifndef\s+[\w\_]+\s*\n((?:\#define\s+[\w\_]+\s.*\n)+)\#endif\n';
- @defs = $s =~ /$re/gm;
- foreach (@defs) {
- while (/^\#define\s+([\w\_]+)\s(.*?)\s*$/mg) {
- $ovar->{$1} = $2;
- $evar{$1} = '%{'.$1.'}';
- }
- }
- $s =~ s/$re//gm;
- #
- # add everything looking like a with_ variable
- #
- $re = '%{(with\_[\w\_]+)}';
- @defs = $s =~ /$re/gm;
- foreach (@defs) {
- next if exists $ovar->{$1};
- $ovar->{$1} = '%{'.$1.'}';
- $evar{$1} = '%{'.$1.'}';
- }
- #
- # extract all conditional sections
- #
- @term = ();
- %var = ();
- $cond = '';
- foreach $l (split(/\n/, $s)) {
- $v = vsub(\%var,$l);
- if (($p) = $v =~ /^\#if\s+(.*?)\s*$/) {
- #
- # normalize #if expressions
- # "%{variable}" == "yes"
- # "%{variable}" == "no"
- # operators ! && ||
- #
- $term = '';
- while ($p =~ /(!=)|(\!|\|\||\&\&|\(|\))|"\%\{([^}]+)\}"\s*==\s*"(yes|no)"|(\S+)/g) {
- if (defined $1) {
- warn "WARNING: unknown token '$1':\n< $l\n> $v\n";
- } elsif (defined $5) {
- warn "WARNING: unknown token '$5':\n< $l\n> $v\n";
- } elsif (defined $2) {
- $term .= " $2 ";
- } elsif (exists $evar{$3}) {
- $term .= ($4 eq 'no' ? '! ' : '').vsub(\%evar,'%{'.$3.'}');
- } else {
- warn "WARNING: unknown conditional '$2':\n< $l\n> $v\n";
- }
- }
- #
- # join with previous conditions for this #if/#endif block
- #
- if ($term ne '') {
- push @term, "( $term )";
- $cond = join(' && ', grep { $_ ne '' } @term).'';
- } else {
- push @term, '';
- }
- } elsif ($v =~ /^\#else\s*$/) {
- #
- # reverse last condition
- #
- if (@term) {
- $term[-1] = ' ! '.$term[-1];
- $cond = join(' && ', grep { $_ ne '' } @term).'';
- } else {
- die "FATAL: else without if\n";
- }
- } elsif ($v =~ /^\#endif\s*$/) {
- #
- # unwind last #if expression
- #
- pop @term;
- $cond = join(' && ', grep { $_ ne '' } @term).'';
- } elsif ($v =~ /^\#(?:define)\s*(\S+)\s*(.*?)\s*$/) {
- #
- # define conditional variables
- # truth-value becomes current condition
- #
- # define internal variables
- # -> store for subsequent substitution
- #
- if (exists $evar{$1}) {
- if ($2 eq 'yes') {
- $evar{$1} = "( \%\{$1\} || ( $cond ) )";
- } elsif ($2 eq 'no') {
- $evar{$1} = "( %\{$1\} && ! ( $cond ) )";
- } else {
- warn "WARNING: logic too complex for '$1':\n< $l\n> $v\n";
- }
- } else {
- $var{$1} = $2;
- }
- } elsif ($v =~ /^\#(?:undefine)\s*(\S+)\s*$/) {
- if (exists $evar{$1}) {
- $evar{$1} = "\%\{$1\}";
- } else {
- delete $var{$1};
- }
- } elsif ($v =~ /^\#(?:provides)\s*(\S+)\s*(.*?)\s*$/) {
- #
- # store option for current condition
- #
- if (exists $attr{'Name'}->{''}) {
- push @{$attr{'Provides'}->{$cond}}, {
- resource => $attr{'Name'}->{''}->[0].'::'.$1,
- attrname => 'equ',
- attrval => optesc($2)
- }
- } else {
- warn "ERROR: no package name set for option $1 = $2\n";
- }
- } elsif ($v =~ /^\#NoSource\s*(.*?)\s*$/) {
- #
- # store conditional NoSource attribute
- #
- push @{$attr{'NoSource'}->{$cond}}, commasep('NoSource',$1);
- } elsif ($v =~ /^\s*([^\#]\S*)\s*:\s*(.*?)\s*$/) {
- #
- # store attribute=value for current condition
- #
- push @{$attr{$1}->{$cond}}, commasep($1,$2);
- }
- }
- return \%attr;
- }
- #
- # split spec file into sections starting with a %word
- #
- # concatenate extended lines
- # strip comment lines
- # map %command to #command
- # split sections
- #
- # return package2data from default section.
- #
- sub spec2data ($) {
- my($s) = @_;
- my(%map);
- my($a,$o);
- my $spec = $s;
- # remove comments
- $s =~ s/^\s*#.*?\n//mg;
- # map commands
- $s =~ s/^%(ifdef|ifndef|if|NoSource|option|undefine|define|else|endif|\{)/#$1/mg;
- # split sections
- foreach (split(/^(?=%\w+\s*\n)/m, $s)) {
- if (/^%(\w+)\s*\n/) {
- $map{$1} .= $';
- } else {
- $map{'*'} .= $_;
- }
- }
- if (exists $map{'description'}) {
- $o = find_options($map{'description'});
- $a = package2data($map{'*'}, $o );
- $a->{'Description'} = { '' => [ $map{'description'} ] };
- } else {
- $a = package2data($map{'*'}, {});
- }
- return $a;
- }
- ##########################################################################
- #
- # start of XML file
- #
- sub xml_head ($$) {
- my($fh,$res) = @_;
- print $fh <<EOFEOF;
- <?xml version="1.0" encoding="iso-8859-1"?>
- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns="http://www.openpkg.org/xml-rdf-index/0.9">
- <Repository rdf:resource="$res">
- EOFEOF
- }
- #
- # end of XML file, corresponds with start tags
- #
- sub xml_foot ($) {
- my($fh) = @_;
- print $fh <<EOFEOF;
- </Repository>
- </rdf:RDF>
- EOFEOF
- }
- sub n($$) {
- my($a,$k) = @_;
- return unless $a->{$k};
- return unless $a->{$k}->{''};
- return $a->{$k}->{''}->[0];
- }
- #
- # send out $a->{$k} as text-style tag
- #
- sub xml_text ($$$;$) {
- my($i,$a,$k,$tag) = @_;
- my($out);
- return "" unless exists $a->{$k};
- $tag = $k unless defined $tag;
- $i = ' ' x $i;
- $out = e(n($a,$k));
- return if $out eq '';
- return "$i<$tag>\n$out\n$i</$tag>\n";
- }
- #
- # send out @{$a->{$k}} as body of an XML tag
- # $k is the name of the tag unless overridden by $tag
- # $i denotes the depth of indentation to form nicely
- # looking files.
- #
- # all data from the list is flattened into a single
- # body, separated by LF and escaped for XML metachars.
- #
- sub xml_tag ($$$;$) {
- my($i,$a,$k,$tag) = @_;
- my($out,$cond,$upn);
- return "" unless exists $a->{$k};
- $tag = $k unless defined $tag;
- $out = '';
- $i = ' ' x $i;
- foreach $cond (sort keys %{$a->{$k}}) {
- $upn = e(upn($cond));
- $out .= $i.
- ($cond ne '' ? "<$tag cond=\"$upn\">" : "<$tag>").
- join("\n", map { e($_) } @{$a->{$k}->{$cond}}).
- "</$tag>\n";
- }
-
- return $out;
- }
- #
- # send out @{$a->{$k}} as a rdf:bag
- # $k is the name of the outer tag unless overriden by $tag
- # $i denotes the depth of indentation, inner tags are indented
- # 2 or 4 more character positions.
- #
- # each element of the bag is listed
- #
- sub xml_bag ($$$;$) {
- my($i,$a,$k,$tag) = @_;
- my($out,$cond,$upn);
- return "" unless exists $a->{$k};
- $tag = $k unless defined $tag;
- $out = '';
- $i = ' ' x $i;
- foreach $cond (sort keys %{$a->{$k}}) {
- next unless @{$a->{$k}->{$cond}};
- $upn = e(upn($cond));
- $out .= $i.
- ($cond ne '' ? "<$tag cond=\"$upn\">\n" : "<$tag>\n").
- "$i <rdf:bag>\n".
- join("",
- map {
- ref $_
- ? "$i <resource".
- ( exists $_->{attrname}
- ? " $_->{attrname}=\"".e($_->{attrval})."\""
- : ""
- ).
- ">".e($_->{resource})."</resource>\n"
- : "$i <rdf:li>".e($_)."</rdf:li>\n"
- }
- @{$a->{$k}->{$cond}}).
- "$i </rdf:bag>\n".
- "$i</$tag>\n";
- }
- return $out;
- }
- #
- # send out reference to another RDF
- #
- sub xml_reference ($$$) {
- my($fh, $res, $href) = @_;
- print $fh <<EOFEOF;
- <Repository rdf:resource="$res" href="$href"/>
- EOFEOF
- }
- #
- # translate attributes from %$a as generated by package2data
- # into XML and write to file $fh
- #
- sub xml_record ($$$) {
- my($fh, $a, $href) = @_;
- my($maj,$min,$rel,$about);
- $about =
- n($a,'Name').'-'.
- n($a,'Version').'-'.
- n($a,'Release');
- unless (defined $href) {
- # guess location from Information in Specfile
- if (exists $a->{'NoSource'}) {
- $href = "$about.nosrc.rpm";
- } else {
- $href = "$about.src.rpm";
- }
- ($maj,$min,$rel) = n($a,'Release') =~ /^(\d+)\.(\d+)\.(\d+)/;
- if (defined $min) {
- if ($maj > 1 || ($maj == 1 && $min > 0)) {
- # 1.1 or later
- if (n($a,'Distribution') =~ /\[PLUS\]/) {
- $href = 'PLUS/'.$href;
- }
- }
- if ($maj > 1 || ($maj == 1 && $min >= 0)) {
- # 1.0 or later
- if ($rel > 0) {
- $href = 'UPD/'.$href;
- }
- }
- } else {
- # current
- }
- }
-
- print $fh <<EOFEOF;
- <rdf:Description about="$about" href="$href">
- EOFEOF
- # fake Source attribute from Source\d attribtutes
- # XXX only default conditional
- $a->{'Source'} = { '' => [
- map {
- s/\Q%{name}\E/n($a,'Name')/esg;
- s/\Q%{version}\E/n($a,'Version')/esg;
- s/\Q%{release}\E/n($a,'Release')/esg;
- #s/.*\///;
- $_;
- }
- map {
- $a->{$_}->{''} ? @{$a->{$_}->{''}} : ()
- }
- sort {
- my($x) = $a =~ /^(\d*)$/;
- my($y) = $b =~ /^(\d*)$/;
- return $x <=> $y;
- }
- grep {
- /^Source\d*$/
- } keys %$a
- ]};
- delete $a->{'Source'} unless @{$a->{'Source'}->{''}};
- print $fh
- xml_tag(6, $a, 'Name'),
- xml_tag(6, $a, 'Version'),
- xml_tag(6, $a, 'Release'),
- xml_tag(6, $a, 'Distribution'),
- xml_tag(6, $a, 'Group'),
- xml_tag(6, $a, 'License'),
- xml_tag(6, $a, 'Packager'),
- xml_tag(6, $a, 'Summary'),
- xml_tag(6, $a, 'URL'),
- xml_tag(6, $a, 'Vendor'),
- xml_tag(6, $a, 'SourceRPM'),
- xml_tag(6, $a, 'Arch'),
- xml_tag(6, $a, 'Os'),
- xml_tag(6, $a, 'BuildRoot'),
- xml_tag(6, $a, 'BuildHost'),
- xml_tag(6, $a, 'BuildSystem'),
- xml_tag(6, $a, 'BuildTime'),
- xml_tag(6, $a, 'Relocations'),
- xml_tag(6, $a, 'Size'),
- xml_tag(6, $a, 'Prefixes'),
- xml_tag(6, $a, 'Platform'),
- xml_tag(6, $a, 'SigSize'),
- xml_tag(6, $a, 'SigMD5'),
- xml_tag(6, $a, 'SigPGP'),
- xml_tag(6, $a, 'SigGPG'),
- xml_bag(6, $a, 'BuildPreReq'),
- xml_bag(6, $a, 'PreReq'),
- xml_bag(6, $a, 'Provides'),
- xml_bag(6, $a, 'Conflicts'),
- xml_bag(6, $a, 'Source'),
- xml_bag(6, $a, 'NoSource'),
- xml_bag(6, $a, 'Filenames'),
- xml_text(6, $a, 'Description');
- print $fh <<EOFEOF;
- </rdf:Description>
- EOFEOF
- }
- #####################################################################
- sub rpm2spec ($) {
- my($fn) = @_;
- my($pipe) = new FileHandle "$R2C '$fn' |"
- or die "FATAL: cannot read '$fn' ($!)\n";
- my($buf,@hdr,$n,$m,$name,$step);
- my($spec);
- while (read($pipe,$buf,110) == 110) {
- @hdr = unpack('a6a8a8a8a8a8a8a8a8a8a8a8a8a8',$buf);
- $n = hex($hdr[12]); # filename length
- $m = int(($n+5)/4)*4-2; # filename size (padded)
- last unless read($pipe,$buf,$m) == $m;
- $name = substr($buf,0,$n-1);
- $n = hex($hdr[7]); # file length
- $m = int(($n+3)/4)*4; # file size (padded)
- if ($name !~ /.spec$/) {
- while ($m > 0) {
- $step = $m > 8192 ? 8192 : $m;
- last unless read($pipe,$buf,$step);
- $m -= length($buf);
- }
- } else {
- if (read($pipe,$buf,$n) == $n) {
- $spec = $buf;
- }
- last;
- }
- }
- $pipe->close;
- return $spec;
- }
- #####################################################################
- sub rpm2data ($$) {
- my($fn,$platform) = @_;
- my($q,$pipe,%a);
- my($t,$v);
- $q = <<EOFEOF;
- Name %{Name}
- Version %{Version}
- Release %{Release}
- URL %{URL}
- Summary %{Summary}
- Copyright %{Copyright}
- License %{License}
- Distribution %{Distribution}
- Vendor %{Vendor}
- Group %{Group}
- Packager %{Packager}
- Prefixes %{Prefixes}
- BuildRoot %{BuildRoot}
- BuildHost %{BuildHost}
- BuildTime %{BuildTime}
- Arch %{Arch}
- Os %{Os}
- Size %{Size}
- SigSize %{SigSize}
- SigMD5 %{SigMD5}
- SigPGP %{SigPGP}
- SigGPG %{SigGPG}
- SourceRPM %{SourceRPM}
- [Patch %{Patch}
- ]
- [Source %{Source}
- ]
- [Filenames %{Filenames}
- ]
- [Conflicts %{CONFLICTNAME} %|CONFLICTFLAGS?{%{CONFLICTFLAGS:depflags} %{CONFLICTVERSION}}:{}|
- ]
- [PreReq %{REQUIRENAME} %|REQUIREFLAGS?{%{REQUIREFLAGS:depflags} %{REQUIREVERSION}}:{}|
- ]
- [Provides %{PROVIDENAME} %|PROVIDEFLAGS?{%{PROVIDEFLAGS:depflags} %{PROVIDEVERSION}}:{}|
- ]
- Description %{Description}
- EOFEOF
- $pipe = new FileHandle "$RPM -qp --qf '$q' '$fn' |"
- or die "FATAL: cannot read '$fn' ($!)\n";
- while (<$pipe>) {
- if (/^(\S+)\s+(.*?)\s*$/) {
- $t = $1;
- $v = $2;
- } elsif (/^(\s+.+?)\s*$/) {
- next unless defined $t;
- $v = $1;
- } else {
- $t = undef;
- next;
- }
- if (exists $a{$t}) {
- $a{$t} .= "\n$v";
- } else {
- $a{$t} = $v;
- }
- }
- $pipe->close;
- %a = map { $_ => $a{$_} }
- grep { $a{$_} ne '(none)' }
- keys %a;
- if ($a{'Relocations'} eq '(non relocatable)') {
- delete $a{'Relocations'};
- }
- if ($a{'SigMD5'} eq '(unknown type)') {
- delete $a{'SigMD5'};
- }
- $a{'Platform'} = "$a{'Arch'}-$platform-$a{'Os'}";
- $a{'PreReq'} =~ s/^rpmlib\(.*$//mg;
- $a{'Description'} = [ $a{'Description'} ];
- return { map {
- $_ => { '' => (ref $a{$_} ? $a{$_} : [ split(/\n+/, $a{$_}) ]) }
- } keys %a };
- }
- #####################################################################
- sub getindex ($) {
- my($dir) = @_;
- my(@idx) = sort { -M $a <=> -M $b; }
- grep { -f $_ }
- ( <$dir/00INDEX.rdf>, <$dir/00INDEX.rdf.*> );
- return unless @idx;
- return $idx[0];
- }
- sub list_specdir ($) {
- my($dir) = @_;
- my($dh,$d,$path);
- my(@list);
- $dh = new DirHandle($dir);
- while ($d = $dh->read) {
- next if $d =~ /^\./;
- $path = "$dir/$d/$d.spec";
- push @list, $path if -f $path;
- }
- return \@list;
- }
- sub list_rpmdir ($) {
- my($dir) = @_;
- my($dh,$d,$path);
- my(@list,$idx,$sub);
- $dh = new DirHandle($dir);
- while ($d = $dh->read) {
- next if $d =~ /^\./;
- $path = "$dir/$d";
- if (-d $path) {
- $idx = getindex($path);
- if (defined $idx) {
- push @list, $idx;
- } else {
- $sub = list_rpmdir($path);
- push @list, @$sub;
- undef $sub;
- }
- } else {
- next unless $d =~ /\.rpm$/ && -f $path;
- push @list, $path;
- }
- }
- return \@list;
- }
- #####################################################################
- sub readfile ($) {
- my($fn) = @_;
- my($fh) = new FileHandle "< $fn"
- or die "FATAL: cannot read '$fn' ($!)\n";
- my(@l) = <$fh>;
- $fh->close;
- return join('',@l);
- }
- sub relpath ($$) {
- my($prefix,$path) = @_;
- $path =~ s/^\Q$prefix\E\///s;
- return $path;
- }
- sub dirname ($) {
- my($path) = @_;
- $path =~ s/\/[^\/]*$//s;
- return $path.'/';
- }
- sub getresource ($) {
- my($fn) = @_;
- my($fh, $buf);
- if ($fn =~ /\.bz2$/) {
- $fh = new FileHandle "$BZ -dc $fn |"
- or die "FATAL: cannot read '$fn' ($!)\n";
- } else {
- $fh = new FileHandle "< $fn"
- or die "FATAL: cannot read '$fn' ($!)\n";
- }
- $fh->read($buf, 1024);
- $fh->close;
- if ($buf =~ /<Repository.*?rdf:resource="([^"]+)"/) {
- return $1;
- }
- return undef;
- }
- #####################################################################
- sub write_index ($$$$$$) {
- my($fh,$prefix,$resource,$platform,$list,$cache) = @_;
- my($a,$h,$r,$spec);
- my($mtime);
- foreach (@$list) {
- $a = undef;
- $h = undef;
- $r = undef;
- if (/\.spec$/) {
- $spec = readfile($_);
- $a = spec2data($spec);
- } elsif (/([^\/]+\.(?:no)?src\.rpm)$/) {
- $h = relpath($prefix, $_);
- if ($cache) {
- $mtime = (stat $_)[9];
- if (exists $cache->{"M$_"} &&
- $cache->{"M$_"} == $mtime) {
- $spec = $cache->{"S$_"};
- } else {
- $spec = rpm2spec($_);
- $cache->{"S$_"} = $spec;
- $cache->{"M$_"} = $mtime;
- }
- } else {
- $spec = rpm2spec($_);
- }
- $a = spec2data($spec);
- } elsif (/([^\/]+\.rpm)$/) {
- $h = relpath($prefix, $_);
- $a = rpm2data($_, $platform);
- } elsif (/([^\/]+\.rdf[^\/]*)$/) {
- $h = relpath($prefix, $_);
- $r = getresource($_) || $resource.dirname($h);
- }
- if ($a) {
- xml_record($fh, $a, $h);
- } elsif ($r) {
- xml_reference($fh, $r, $h);
- } else {
- warn "ERROR: cannot process $_\n";
- }
- }
- }
- #####################################################################
- my($prefix,$list,$fh,%cache,$tmpo);
- if ($#ARGV < 0) {
- print "openpkg:index:USAGE: $0 [-r resource] [-p platform] [-C cache.db] [-o index.rdf] [-c] [-i] dir ...\n";
- die "\n";
- }
- if ($opt_C) {
- require DB_File;
- tie %cache, 'DB_File', $opt_C, O_CREAT|O_RDWR, 0666, $DB_File::DB_HASH
- or die "FATAL: cannot tie cache '$opt_C' ($!)\n";
- }
- $opt_r = 'OpenPKG-CURRENT/Source/' unless defined $opt_r;
- $opt_p = 'unknown' unless defined $opt_p;
- if (defined $opt_o) {
- $tmpo = $opt_o . '.tmp';
- if ($opt_c) {
- $fh = new FileHandle "| $BZ -c > '$tmpo'"
- or die "FATAL: cannot write '$tmpo' ($!)\n";
- } else {
- $fh = new FileHandle "> $tmpo"
- or die "FATAL: cannot write '$tmpo' ($!)\n";
- }
- } else {
- if ($opt_c) {
- $fh = new FileHandle "| $BZ -c"
- or die "FATAL: cannot write to stdout ($!)\n";
- } else {
- $fh = new FileHandle ">&=1"
- or die "FATAL: cannot write to stdout ($!)\n";
- }
- }
- xml_head($fh, $opt_r);
- foreach $prefix (@ARGV) {
- die "FATAL: $prefix is not a directory\n" unless -d $prefix;
- if ($opt_i) {
- $list = list_rpmdir($prefix);
- } else {
- $list = list_specdir($prefix);
- }
- write_index($fh, $prefix, $opt_r, $opt_p, $list, $opt_C ? \%cache : undef);
- }
- xml_foot($fh);
- $fh->close
- or die "FATAL: write error on output ($!)\n";
- if (defined $tmpo) {
- rename $tmpo,$opt_o
- or die "FATAL: cannot rename $tmpo to $opt_o ($!)\n";
- }
|