]> git.pld-linux.org Git - projects/distfiles.git/blobdiff - specparser.pl
Allow urls like 'https://pypi.python.org/packages/source/d/dugong/dugong-%{version...
[projects/distfiles.git] / specparser.pl
old mode 100644 (file)
new mode 100755 (executable)
index 7162f1a..510fbc5
@@ -1,5 +1,4 @@
 #!/usr/bin/perl
-# $Id$
 #
 # USAGE: specparser.pl file.spec
 #
@@ -21,6 +20,10 @@ my $spec;
 my $base_spec;
 my @spec;
 my @sources;
+my $sources_file;
+my %patchset;
+
+sub print_source($$$);
 
 sub next_spec($)
 {
@@ -43,10 +46,10 @@ sub warning($)
 sub trim_spaces($)
 {
        my $v = shift;
-       
+
        $v =~ s/\s+$//;
        $v =~ s/^\s+//;
-       
+
        return $v;
 }
 
@@ -74,7 +77,7 @@ sub expand($$) # {{{
        while ($v =~ s/\%\(\s*echo\s+([^\|]+?)\s*\|\s*tr\s*(-d|)\s+([^\)]+?)\s*\)/\@\@tr-me\@\@/) {
                my ($what, $d_opt, $how) = ($1, $2, $3);
                my ($from, $to) = ($how, "");
-               ($from, $to) = ($1, $2) 
+               ($from, $to) = ($1, $2)
                        if $how =~ /^([^\s]+)\s+([^\s]+)$/;
                if ($d_opt and $to ne "") {
                        error("tr -d with second string)");
@@ -88,13 +91,13 @@ sub expand($$) # {{{
                        error("illegal characters in tr string(s) '$from' '$to'");
                }
                $v =~ s/\@\@tr-me\@\@/$what/;
-               
+
                return $v if (length $v > 1000 or $cnt-- <= 0)
        }
 
        error("unexpanded macros in $v")
                if ($v =~ /\%[^0-9]/);
-       
+
        return $v;
 } # }}}
 
@@ -102,7 +105,7 @@ sub preparse_spec($) # {{{
 {
        @spec = ("");
 
-       open(F, "< $_[0]") or die;
+       open(F, "< $_[0]") or die("failed opening: " . $_[0]);
        while (<F>) {
                chomp;
                if (/^\s*(\%(description|package|prep|install|pre|post|files)|BuildRoot|URL)/) {
@@ -120,7 +123,17 @@ sub preparse_spec($) # {{{
                        }
                        push @spec, $_;
                } elsif (/^NoSource\s*:\s*(\d+)\s*$/i) {
-                       $no_source{$1} = 1;
+                       $no_source{ "source" . $1 } = 1;
+               } elsif (my ($patchset) = /^%patchset_source\s+(.+)$/) {
+                       use Getopt::Long qw(GetOptionsFromString);
+                       my ($f, $s);
+                       my ($ret, $args) = GetOptionsFromString($patchset, 's=s' => \$s, 'f=s' => \$f);
+                       %patchset = (
+                               pattern => $f,
+                               filelist => $s,
+                               start => $args->[0],
+                               end => $args->[1],
+                       );
                }
        }
        close(F);
@@ -128,6 +141,55 @@ sub preparse_spec($) # {{{
        shift @spec;
 } # }}}
 
+# read in 'sources' file
+sub read_sources_file {
+       my $filename = $_[0] || $sources_file;
+       return () unless $filename and -e $filename;
+
+       my %files;
+
+       open(my $fh, '<', $filename) or die $!;
+       while (<$fh>) {
+               chomp;
+               next unless my ($hash, $filename) = /^([a-f0-9]{32})\s+\*?(.+)$/;
+               $files{$filename} = $hash;
+       }
+       return \%files;
+}
+
+sub process_patchset($) {
+       my $macros = shift;
+       my $checksums;
+
+       return unless %patchset;
+
+       # print all files from sources file
+       if ($patchset{filelist}) {
+               my $prefix = expand($patchset{pattern}, $macros);
+               my $filelist = expand($patchset{filelist}, $macros);
+               $checksums = read_sources_file($filelist);
+               while (my($file, $hash) = each %$checksums) {
+                       my $url = $prefix . $file;
+                       print_source "patchset $file", $hash, $url;
+               }
+               return;
+       }
+
+       # parse sources file sequences
+       $checksums = read_sources_file() or return;
+
+       # print out patchset entries which source md5 is present in source file
+       my $start = expand($patchset{start}, $macros);
+       my $end = expand($patchset{end}, $macros);
+       my $pattern = expand($patchset{pattern}, $macros);
+       for (my $i = $start; $i <= $end; $i++) {
+               my $url = sprintf($pattern, $i);
+               my ($basename) = $url =~ m{/([^/]+$)};
+               my $hash = $checksums->{$basename} or next;
+               print_source "patchset $i", $hash, $url;
+       }
+}
+
 
 my $total = 0;
 
@@ -156,12 +218,11 @@ sub cont($$) # {{{
                        }
 
                        # continue parsing
-                       
                } elsif ($_ eq '%else') {
 
                        # %else happens only when %if was interpreted
                        # so skip until %endif
-                       
+
                        my $level = 0;
                        while ($_ = shift @{$spec}) {
                                if ($level <= 0 and $_ eq '%endif') {
@@ -185,6 +246,9 @@ sub cont($$) # {{{
                }
        }
 
+       # so we have macros now, can parse patchset source
+       process_patchset($macros);
+
        # the end, yuppie !
        foreach my $s (@sources) {
                my $src = expand( $s->[2], $macros );
@@ -196,7 +260,7 @@ sub cont($$) # {{{
                        }
                }
        }
-       
+
        if (++$total > 10000) {
                error("maximum number of bcond posibilities exceeded");
                exit 0;
@@ -217,7 +281,7 @@ sub print_source($$$) # {{{
 {
        my ($no, $md5, $s) = @_;
 
-       if ($s =~ /^([a-z0-9A-Z:\=\?\@\+\~\.\-\/_]|\%[0-9])+$/) {
+       if ($s =~ /^([a-z0-9A-Z;:\=\?&\@\+\~\.,\-\/\#_]|\%[0-9])+(#\/[a-zA-Z0-9\._-]+)?$/) {
                if ($s =~ /^(ftp|http|https):\/\//) {
                        if ($s =~ /\/$/) {
                                error("source $no ($s) is directory");
@@ -240,37 +304,56 @@ sub print_source($$$) # {{{
 
 sub add_md5_to_print($) # {{{
 {
-       open(F, "< $_[0]") or die;
-       my $sourceno = undef;
-       my $source = undef;
+       open(F, "< $_[0]") or die("failed opening: " . $_[0]);
+       my %sourcemap = ();
        while (<F>) {
                chomp;
-               if (/^Source(\d+)\s*:\s*(.*)/i) {
-                       $sourceno = $1;
-                       $source = $2;
-               } elsif (/^\s*#\s*source(\d+)-md5\s*:\s*([a-f0-9]{32})/i) {
-                       my $no = $1;
+               if (/^((?:Source|Patch)\d+)\s*:\s*(.*)/i) {
+                       my $sourceno = lc $1;
+                       my $source = $2;
+                       # master.dl is outdated currently
+                       # $source =~ s/dl.sourceforge.net/master.dl.sourceforge.net/;
+                       $sourcemap{ $sourceno } = $source;
+               } elsif (/^\s*#\s*((?:source|patch)\d+)-md5\s*:\s*([a-f0-9]{32})/i) {
+                       my $no = lc $1;
                        my $md5 = $2;
                        if (defined $no_source{$no}) {
                                error("both NoSource: $no and md5 given");
-                       } if (defined $sourceno) {
-                               if ($sourceno == $no) {
-                                       push @sources, [$no, $md5, $source];
-                               } else {
-                                       error("found md5 for source $no, but last defined source is $sourceno (# SourceN-md5: has to be placed just after SourceN:)");
-                               }
+                       } elsif (defined $sourcemap{ $no} ) {
+                               my $source = $sourcemap{ $no };
+                               push @sources, [$no, $md5, $source];
                        } else {
                                error("source $no not defined (# SourceN-md5: has to be placed just after SourceN:)");
                        }
-
-                       $sourceno = undef;
-                       $source = undef;
+               } elsif (/^\s*BuildRequires:\s*digest\(%((?:SOURCE|PATCH)\d+)\)\s*=\s*([a-f0-9]{32})/i) {
+                       my $no = lc $1;
+                       my $md5 = $2;
+                       if (defined $no_source{ $no }) {
+                               error("both NoSource: $no and md5 given");
+                       } elsif (defined $sourcemap{ $no }) {
+                               my $source = $sourcemap{ $no };
+                               push @sources, [$no, $md5, $source];
+                       } else {
+                               error("source $no not defined (# Source digest has to be placed after SourceN:)");
+                       }
                }
        }
        close(F);
+
+       # find extra sources from detached checksum file
+       my $checksums = read_sources_file();
+       my @mapped = map { $_->[0] } @sources;
+       delete @sourcemap{@mapped};
+       while (my($source, $url) = each %sourcemap) {
+               my ($basename) = $url =~ m{/([^/]+$)};
+               next unless defined $basename;
+               my $hash = $checksums->{$basename} or next;
+               push @sources, [$source, $hash, $url];
+       }
 } # }}}
 
 next_spec(shift);
+$sources_file = shift if @ARGV;
 preparse_spec($spec);
 add_md5_to_print($spec);
 cont( \@spec, { "nil" => "" } );
This page took 0.057689 seconds and 4 git commands to generate.