]> git.pld-linux.org Git - projects/distfiles.git/blame - specparser.pl
Merge changes for git to master
[projects/distfiles.git] / specparser.pl
CommitLineData
0db58532 1#!/usr/bin/perl
b396edfa 2# $Id$
0db58532
MM
3#
4# USAGE: specparser.pl file.spec
5#
6# Output:
7# stdout:
8# list of:
9# <md5><space><url>\n
10# for given specfile.
1b5ce8c2 11# except for lines prefixed with: ERROR:
0db58532
MM
12# exit status:
13# 0 - normal
14# 2 - cannot open spec file
15#
8079fcc5 16use strict;
17use warnings;
18
19my %no_source;
20my $spec;
21my $base_spec;
22my @spec;
23my @sources;
0db58532 24
0dd6294b
MM
25sub next_spec($)
26{
7a1a3819
ER
27 $spec = shift;
28 @spec = ();
29 $base_spec = $spec;
30 $base_spec =~ s|.*/||;
0dd6294b 31}
0db58532 32
0dd6294b 33sub error($)
0db58532 34{
7a1a3819 35 print_once( "ERROR: $base_spec: $_[0]" );
0dd6294b
MM
36}
37
38sub warning($)
39{
7a1a3819 40 print "ERROR: $base_spec: $_[0]\n";
0dd6294b 41}
51a652ef 42
0dd6294b
MM
43sub trim_spaces($)
44{
7a1a3819 45 my $v = shift;
62c5617b 46
7a1a3819
ER
47 $v =~ s/\s+$//;
48 $v =~ s/^\s+//;
62c5617b 49
7a1a3819 50 return $v;
0dd6294b
MM
51}
52
53# expand macros in string
8079fcc5 54sub expand($$) # {{{
0dd6294b 55{
7a1a3819
ER
56 my $v = trim_spaces(shift);
57 my $macrotree = shift;
58 my $cnt = 20;
8079fcc5 59
7a1a3819
ER
60 while ($v =~ /\%\{([^\}]+)\}/) {
61 my $value;
62 if (defined $macrotree->{$1}) {
63 $value = $macrotree->{$1};
64 } else {
65 error("undefined macro $1");
66 $value = "UNDEFINED";
67 return undef;
68 }
69 $v =~ s/\%\{([^\}]+)\}/$value/;
8079fcc5 70
7a1a3819
ER
71 return $v if (length $v > 1000 or $cnt-- <= 0)
72 }
0db58532 73
7a1a3819
ER
74 while ($v =~ s/\%\(\s*echo\s+([^\|]+?)\s*\|\s*tr\s*(-d|)\s+([^\)]+?)\s*\)/\@\@tr-me\@\@/) {
75 my ($what, $d_opt, $how) = ($1, $2, $3);
76 my ($from, $to) = ($how, "");
62c5617b 77 ($from, $to) = ($1, $2)
7a1a3819
ER
78 if $how =~ /^([^\s]+)\s+([^\s]+)$/;
79 if ($d_opt and $to ne "") {
80 error("tr -d with second string)");
81 } elsif (($from . $to) =~ /^[a-zA-Z0-9\+_\-\.]+$/) {
82 if ($d_opt) {
83 eval "\$what =~ tr/$from//d;";
84 } else {
85 eval "\$what =~ tr/$from/$to/;";
86 }
87 } else {
88 error("illegal characters in tr string(s) '$from' '$to'");
89 }
90 $v =~ s/\@\@tr-me\@\@/$what/;
62c5617b 91
7a1a3819
ER
92 return $v if (length $v > 1000 or $cnt-- <= 0)
93 }
8079fcc5 94
7a1a3819
ER
95 error("unexpanded macros in $v")
96 if ($v =~ /\%[^0-9]/);
62c5617b 97
7a1a3819 98 return $v;
8079fcc5 99} # }}}
100
101sub preparse_spec($) # {{{
0db58532 102{
7a1a3819 103 @spec = ("");
8079fcc5 104
7a1a3819
ER
105 open(F, "< $_[0]") or die("failed opening: " . $_[0]);
106 while (<F>) {
107 chomp;
108 if (/^\s*(\%(description|package|prep|install|pre|post|files)|BuildRoot|URL)/) {
109 last;
110 } elsif (/^\s*(\%if.*|\%else|\%endif|\%define\s+.*|Version.*|Name.*)\s*$/) {
111 $_ = $1;
112 if ($spec[$#spec] =~ /\%if/) {
113 if (/\%else/) {
114 next; # don't include empty %if-%else
115 } elsif (/\%endif/) {
116 # remove empty %if-%endif
117 pop @spec;
118 next;
119 }
120 }
121 push @spec, $_;
122 } elsif (/^NoSource\s*:\s*(\d+)\s*$/i) {
754883c6 123 $no_source{ "source" . $1 } = 1;
7a1a3819
ER
124 }
125 }
126 close(F);
8079fcc5 127
7a1a3819 128 shift @spec;
8079fcc5 129} # }}}
130
131
132my $total = 0;
133
134sub cont($$);
135sub cont($$) # {{{
136{
7a1a3819
ER
137 my ($spec, $macros) = @_;
138 local $_;
139 while ($_ = shift @{$spec}) {
140 if (0 <= index $_, '%if') { # if, ifarch, ifos
8079fcc5 141
7a1a3819
ER
142 # split spec parsing
143 my @speccopy = @{$spec};
144 my %macroscopy = %{$macros};
145 cont(\@speccopy, \%macroscopy);
0db58532 146
7a1a3819
ER
147 my $level = 0;
148 while ($_ = shift @{$spec}) {
149 if ($level <= 0 and ($_ eq '%else' or $_ eq '%endif')) {
150 last;
151 } elsif (0 <= index $_, '%if') {
152 $level++;
153 } elsif ($_ eq '%endif') {
154 $level--;
155 }
156 }
8079fcc5 157
7a1a3819 158 # continue parsing
7a1a3819 159 } elsif ($_ eq '%else') {
8079fcc5 160
7a1a3819
ER
161 # %else happens only when %if was interpreted
162 # so skip until %endif
62c5617b 163
7a1a3819
ER
164 my $level = 0;
165 while ($_ = shift @{$spec}) {
166 if ($level <= 0 and $_ eq '%endif') {
167 last;
168 } elsif (0 <= index $_, '%if') {
169 $level++;
170 } elsif ($_ eq '%endif') {
171 $level--;
172 }
173 }
8079fcc5 174
7a1a3819
ER
175 } elsif (/^\s*\%(define|global)\s+([^\s]+)\s+([^\s].*?)\s*$/) {
176 $macros->{$2} = $3;
8079fcc5 177
7a1a3819
ER
178 } elsif (/^Version\s*:\s*(.*?)\s*$/i) {
179 $macros->{"version"} = $1;
180 } elsif (/^Name\s*:\s*(.*?)\s*$/i) {
181 $macros->{"name"} = $1;
182 } elsif (!/\%endif/) {
183 warn "unrecognised line: $_\n";
184 }
185 }
8079fcc5 186
7a1a3819
ER
187 # the end, yuppie !
188 foreach my $s (@sources) {
189 my $src = expand( $s->[2], $macros );
190 if (defined $src) {
191 our %tried;
192 unless (exists $tried{$src}) {
193 print_source( $s->[0], $s->[1], $src );
194 $tried{$src} = 1;
195 }
196 }
197 }
62c5617b 198
7a1a3819
ER
199 if (++$total > 10000) {
200 error("maximum number of bcond posibilities exceeded");
201 exit 0;
202 }
8079fcc5 203} # }}}
204
205sub print_once($)
0db58532 206{
7a1a3819
ER
207 our %printed;
208 my $l = shift;
209 unless (exists $printed{$l}) {
210 print $l . "\n";
211 $printed{$l} = 1;
212 }
0db58532
MM
213}
214
8079fcc5 215sub print_source($$$) # {{{
0db58532 216{
7a1a3819 217 my ($no, $md5, $s) = @_;
8079fcc5 218
7a1a3819
ER
219 if ($s =~ /^([a-z0-9A-Z;:\=\?&\@\+\~\.,\-\/_]|\%[0-9])+(#\/[a-zA-Z0-9\._-]+)?$/) {
220 if ($s =~ /^(ftp|http|https):\/\//) {
221 if ($s =~ /\/$/) {
222 error("source $no ($s) is directory");
223 } else {
224 if ($s =~ /:\/\/distfiles\.pld-linux\.org\/src/) {
225 $s =~ s|.*/||;
226 print_once( "$md5 no-url-copy://$s" );
227 } else {
228 print_once( "$md5 $s" );
229 }
230 }
231 } else {
232 $s =~ s|.*/||;
233 print_once( "$md5 no-url://$s");
234 }
235 } else {
236 error("source $no url $s is ill-formatted");
237 }
8079fcc5 238} # }}}
239
240sub add_md5_to_print($) # {{{
241{
7a1a3819 242 open(F, "< $_[0]") or die("failed opening: " . $_[0]);
754883c6 243 my %sourcemap = ();
7a1a3819
ER
244 while (<F>) {
245 chomp;
754883c6 246 if (/^((?:Source|Patch)\d+)\s*:\s*(.*)/i) {
247 my $sourceno = lc $1;
7a1a3819
ER
248 my $source = $2;
249 # master.dl is outdated currently
250 # $source =~ s/dl.sourceforge.net/master.dl.sourceforge.net/;
754883c6 251 $sourcemap{ $sourceno } = $source;
252 } elsif (/^\s*#\s*((?:source|patch)\d+)-md5\s*:\s*([a-f0-9]{32})/i) {
253 my $no = lc $1;
7a1a3819
ER
254 my $md5 = $2;
255 if (defined $no_source{$no}) {
256 error("both NoSource: $no and md5 given");
754883c6 257 } elsif (defined $sourcemap{ $no} ) {
258 my $source = $sourcemap{ $no };
7a1a3819
ER
259 push @sources, [$no, $md5, $source];
260 } else {
261 error("source $no not defined (# SourceN-md5: has to be placed just after SourceN:)");
262 }
754883c6 263 } elsif (/^\s*BuildRequires:\s*digest\(%((?:SOURCE|PATCH)\d+)\)\s*=\s*([a-f0-9]{32})/i) {
264 my $no = lc $1;
7a1a3819 265 my $md5 = $2;
754883c6 266 if (defined $no_source{ $no }) {
7a1a3819 267 error("both NoSource: $no and md5 given");
754883c6 268 } elsif (defined $sourcemap{ $no }) {
269 my $source = $sourcemap{ $no };
7a1a3819
ER
270 push @sources, [$no, $md5, $source];
271 } else {
272 error("source $no not defined (# Source digest has to be placed after SourceN:)");
273 }
274 }
275 }
276 close(F);
8079fcc5 277} # }}}
0db58532 278
0dd6294b 279next_spec(shift);
8079fcc5 280preparse_spec($spec);
281add_md5_to_print($spec);
282cont( \@spec, { "nil" => "" } );
0db58532
MM
283
284exit(0);
8079fcc5 285
286# vim: ts=4:sw=4:fdm=marker
This page took 0.071813 seconds and 4 git commands to generate.