4 unshift @INC, ($::ENV{'BUILD_DIR'} || '/usr/lib/build');
12 use Digest::MD5 qw(md5 md5_hex md5_base64);
13 use File::Path qw(mkpath rmtree);
17 Getopt::Long::Configure("no_ignore_case");
20 my @primaryfiles = ();
23 my $baseurl; # current url
29 my $cachedir = "/var/cache/build";
36 _start => \&repomd_handle_data_start,
37 _end => \&repomd_handle_data_end,
39 _start => \&repomd_handle_location,
42 _text => \&repomd_handle_size,
51 _start => \&primary_handle_package_start,
52 _end => \&primary_handle_package_end,
53 name => { _text => \&primary_collect_text, _end => \&primary_store_text },
54 arch => { _text => \&primary_collect_text, _end => \&primary_store_text },
55 version => { _start => \&primary_handle_version },
56 'time' => { _start => \&primary_handle_time },
58 'rpm:provides' => { 'rpm:entry' => { _start => \&primary_handle_package_provides }, },
59 'rpm:requires' => { 'rpm:entry' => { _start => \&primary_handle_package_requires }, },
60 'rpm:conflicts' => { 'rpm:entry' => { _start => \&primary_handle_package_conflicts }, },
61 'rpm:obsoletes' => { 'rpm:entry' => { _start => \&primary_handle_package_obsoletes }, },
62 'rpm:buildhost' => { _text => \&primary_collect_text, _end => \&primary_store_text },
63 'rpm:sourcerpm' => { _text => \&primary_collect_text, _end => \&primary_store_text },
64 ### currently commented out, as we ignore file provides in createrpmdeps
66 # _start => \&primary_handle_file_start,
67 # _text => \&primary_collect_text,
68 # _end => \&primary_handle_file_end
71 location => { _start => \&primary_handle_package_location },
80 sub repomd_handle_data_start
85 my $attr = map_attrs(@_);
87 if($attr->{'type'} ne 'primary') {
92 sub repomd_handle_data_end
96 push @primaryfiles, { %datafile } if exists $datafile{'location'};
100 sub repomd_handle_location
105 my $attr = map_attrs(@_);
106 $datafile{'location'} = $attr->{'href'} if defined $attr->{'href'};
109 sub repomd_handle_size
113 $datafile{'size'} = $el;
117 sub generic_handle_start
122 if(exists $cursor[-1]->[1]->{$el})
124 my $h = $cursor[-1]->[1]->{$el};
125 push @cursor, [$el, $h];
126 if(exists $h->{'_start'}) {
127 &{$h->{'_start'}}($p, $el, @_);
132 sub generic_handle_char
137 my $h = $cursor[-1]->[1];
139 if(exists $h->{'_text'}) {
140 &{$h->{'_text'}}($p, $text);
144 sub generic_handle_end
149 if(!defined $cursor[-1]->[0] || $cursor[-1]->[0] eq $el)
151 my $h = $cursor[-1]->[1];
153 if(exists $h->{'_end'}) {
154 &{$h->{'_end'}}($p, $el);
172 # expat does not guarantee that character data doesn't get split up
173 # between multiple calls
175 sub primary_collect_text
183 sub primary_store_text
188 $packages[-1]->{$cursor[-1]->[0]} = $textbuf;
192 sub primary_handle_package_start
197 my $attr = map_attrs(@_);
199 push @packages, { type => $attr->{'type'}, baseurl => $baseurl };
202 sub primary_handle_package_end
208 printasbuildcachefile(@packages);
211 foreach my $pkg (@packages) {
212 my $arch = $pkg->{'arch'};
213 $arch = 'src' if $pkg->{'arch'} eq 'nosrc';
214 next if ($arch eq 'src' && $opt_nosrc);
215 if(exists($old_seen->{$pkg->{'name'}}->{$arch})) {
216 my $pv = $old_seen->{$pkg->{'name'}}->{$arch}->{'ver'};
217 my $rv = $pkg->{'ver'}.'-'.$pkg->{'rel'};
218 my $vv = Build::Rpm::verscmp($pv, $rv, 0);
221 print $old_seen->{$pkg->{'name'}}->{$arch}->{'loc'}."\n";
222 $old_seen->{$pkg->{'name'}}->{$arch}->{'ver'} = $pkg->{'ver'}.'-'.$pkg->{'rel'};
223 $old_seen->{$pkg->{'name'}}->{$arch}->{'loc'} = $pkg->{'baseurl'} . $pkg->{'location'};
225 print $pkg->{'baseurl'} . $pkg->{'location'}."\n";
228 $old_seen->{$pkg->{'name'}}->{$arch}->{'ver'} = $pkg->{'ver'}.'-'.$pkg->{'rel'};
229 $old_seen->{$pkg->{'name'}}->{$arch}->{'loc'} = $pkg->{'baseurl'} . $pkg->{'location'};
236 sub primary_handle_version
241 my $attr = map_attrs(@_);
242 $packages[-1]->{'ver'} = $attr->{'ver'};
243 $packages[-1]->{'rel'} = $attr->{'rel'};
246 sub primary_handle_time
251 my $attr = map_attrs(@_);
252 $packages[-1]->{'filetime'} = $attr->{'file'};
253 $packages[-1]->{'buildtime'} = $attr->{'build'};
256 sub primary_handle_package_location
261 my $attr = map_attrs(@_);
262 $packages[-1]->{'location'} = $attr->{'href'};
265 sub primary_handle_file_start
270 my $attr = map_attrs(@_);
271 if(exists $attr->{'type'}) {
276 sub primary_handle_file_end
281 primary_handle_package_deps('provides', 'name', $textbuf);
294 sub primary_handle_package_deps
297 my $attr = map_attrs(@_);
299 if(exists $attr->{'flags'}) {
300 if(!exists($flagmap{$attr->{'flags'}})) {
301 print STDERR "bogus relation: ", $attr->{'flags'}, "\n";
304 $attr->{'flags'} = $flagmap{$attr->{'flags'}};
306 return if($attr->{'name'} =~ /^rpmlib\(/);
307 push @{$packages[-1]->{$dep}}, $attr;
311 sub primary_handle_package_conflicts
313 shift;shift; primary_handle_package_deps('conflicts', @_);
316 sub primary_handle_package_obsoletes
318 shift;shift; primary_handle_package_deps('obsoletes', @_);
321 sub primary_handle_package_requires
323 shift;shift; primary_handle_package_deps('requires', @_);
325 sub primary_handle_package_provides
327 shift;shift; primary_handle_package_deps('provides', @_);
332 return join(' ', map {
333 my $s = $_->{'name'};
334 if(exists $_->{'flags'}) {
335 $s .= ' '.$_->{'flags'}.' ';
336 $s .= $_->{'epoch'}.':' if(exists $_->{'epoch'} && $_->{'epoch'} != 0);
338 $s .= '-'.$_->{'rel'} if exists $_->{'rel'};
344 sub printasbuildcachefile(@)
346 foreach my $pkg (@_) {
347 next if $pkg->{'arch'} eq 'src' || $pkg->{'arch'} eq 'nosrc';
348 my $id = sprintf("%s.%s-%d/%d/%d: ",
354 print "F:".$id. $pkg->{'baseurl'} . $pkg->{'location'} . "\n";
356 my $deps = deps2string(@{$pkg->{'provides'}});
357 print "P:$id$deps\n";
359 $deps = deps2string(@{$pkg->{'requires'}});
360 print "R:$id$deps\n";
362 my $tag = sprintf("%s-%s-%s %s",
366 # $pkg->{'rpm:buildhost'},
367 $pkg->{'buildtime'});
377 my $dest = $dir . "repodata";
379 system($INC[0].'/download', $dest, $url . "repodata/repomd.xml");
385 "nosrc" => \$opt_nosrc,
386 "dump" => \$opt_dump,
388 "cachedir=s" => \$cachedir,
391 $opt_bc = 1 unless ($opt_dump || $opt_old);
393 my $p = new XML::Parser(
395 Start => \&generic_handle_start,
396 End => \&generic_handle_end,
397 Char => \&generic_handle_char
400 #my $url = '/mounts/mirror/SuSE/ftp.suse.com/pub/suse/update/10.1/';
401 for my $url (@ARGV) {
403 if ($url =~ /^zypp:\/\/([^\/]*)\/?/) {
405 my $repo = Build::Zypp::parsecfg($1);
406 die "can't parse $1\n" unless $repo;
407 my $type = $repo->{'type'};
408 if($type eq 'rpm-md') {
409 my $name = $repo->{'name'};
410 $dir = "/var/cache/zypp/raw/$name/";
412 $baseurl .= '/' unless $baseurl =~ /\/$/;
413 } elsif ($type eq 'yast2') {
415 exec ($INC[0].'/createyastdeps', $url);
417 die "unsupported repo type: $type\n";
419 } elsif ($url =~ /^http[s]?:\/\/([^\/]*)\/?/) {
420 my $repoid = md5_hex($url);
421 $dir = "$cachedir/$repoid/";
423 $baseurl .= '/' unless $baseurl =~ /\/$/;
424 getmetadata($baseurl, $dir);
425 } elsif ($url =~ /^arch\@/) {
426 exec ("$INC[0]/createarchdeps", "--cachedir=$cachedir", substr($url, 5));
429 $dir .= '/' unless $dir =~ /\/$/;
434 @cursor = ([undef, $repomdparser]);
436 $p->parsefile($dir . 'repodata/repomd.xml');
438 # print Dumper(\@primaryfiles);
440 foreach my $f (@primaryfiles) {
441 @cursor = ([undef, $primaryparser]);
443 my $u = $dir . $f->{'location'};
451 $cached = 0 if exists($f->{'size'}) && $f->{'size'} != (-s _);
452 $cached = 0 if !exists($f->{'size'}) && $u !~ /[0-9a-f]{32}-primary/;
454 if ($url =~ /^http[s]?:\/\/([^\/]*)\/?/ and !$cached) {
455 if (system($INC[0].'/download', $dir . "repodata/", $baseurl . "repodata/" . basename($u))) {
456 die("download failed\n");
460 open($fh, '<', $u) or die "Error opening $u: $!\n";
462 use IO::Uncompress::Gunzip qw($GunzipError);
463 $fh = new IO::Uncompress::Gunzip $fh or die "Error opening $u: $GunzipError\n";
471 print Data::Dumper->Dump([\@packages], ['packages']); # caution: excessive memory consumption!
475 # my %amap = map { $_ => 1 } @archs;
476 # my $packages = do $rpmdepdump or die $!;
478 # foreach my $pkg (@$packages) {
479 # next if exists $packs{$pkg->{'name'}};
480 # next unless exists $amap{$pkg->{'arch'}};
481 # next if $pkg->{'arch'} eq 'src' || $pkg->{'arch'} eq 'nosrc';
482 # next if $pkg->{'location'} =~ /\.(?:patch|delta)\.rpm$/;
484 # my $pa = $pkg->{'name'}.'.'.$pkg->{'arch'};
485 # $packs{$pkg->{'name'}} = $pa;
486 # $fn{$pa} = $pkg->{'baseurl'}.$pkg->{'location'};
488 # # flags and version ignored
489 # my @pr = map { $_->{'name'} } @{$pkg->{'provides'}};
490 # my @re = map { $_->{'name'} } @{$pkg->{'requires'}};
491 # $r->{'provides'} = \@pr;
492 # $r->{'requires'} = \@re;
493 # $repo{$pkg->{'name'}} = $r;