]>
Commit | Line | Data |
---|---|---|
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 | 16 | use strict; |
17 | use warnings; | |
18 | ||
19 | my %no_source; | |
20 | my $spec; | |
21 | my $base_spec; | |
22 | my @spec; | |
23 | my @sources; | |
0db58532 | 24 | |
0dd6294b MM |
25 | sub next_spec($) |
26 | { | |
8079fcc5 | 27 | $spec = shift; |
28 | @spec = (); | |
29 | $base_spec = $spec; | |
30 | $base_spec =~ s|.*/||; | |
0dd6294b | 31 | } |
0db58532 | 32 | |
0dd6294b | 33 | sub error($) |
0db58532 | 34 | { |
8079fcc5 | 35 | print_once( "ERROR: $base_spec: $_[0]" ); |
0dd6294b MM |
36 | } |
37 | ||
38 | sub warning($) | |
39 | { | |
8079fcc5 | 40 | print "ERROR: $base_spec: $_[0]\n"; |
0dd6294b | 41 | } |
51a652ef | 42 | |
0dd6294b MM |
43 | sub trim_spaces($) |
44 | { | |
8079fcc5 | 45 | my $v = shift; |
46 | ||
47 | $v =~ s/\s+$//; | |
48 | $v =~ s/^\s+//; | |
49 | ||
50 | return $v; | |
0dd6294b MM |
51 | } |
52 | ||
53 | # expand macros in string | |
8079fcc5 | 54 | sub expand($$) # {{{ |
0dd6294b | 55 | { |
8079fcc5 | 56 | my $v = trim_spaces(shift); |
57 | my $macrotree = shift; | |
58 | my $cnt = 20; | |
59 | ||
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/; | |
70 | ||
71 | return $v if (length $v > 1000 or $cnt-- <= 0) | |
72 | } | |
0db58532 | 73 | |
8079fcc5 | 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, ""); | |
77 | ($from, $to) = ($1, $2) | |
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/; | |
91 | ||
92 | return $v if (length $v > 1000 or $cnt-- <= 0) | |
93 | } | |
94 | ||
95 | error("unexpanded macros in $v") | |
96 | if ($v =~ /\%[^0-9]/); | |
97 | ||
98 | return $v; | |
99 | } # }}} | |
100 | ||
101 | sub preparse_spec($) # {{{ | |
0db58532 | 102 | { |
8079fcc5 | 103 | @spec = (""); |
104 | ||
105 | open(F, "< $_[0]") or die; | |
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) { | |
123 | $no_source{$1} = 1; | |
124 | } | |
125 | } | |
126 | close(F); | |
127 | ||
128 | shift @spec; | |
129 | } # }}} | |
130 | ||
131 | ||
132 | my $total = 0; | |
133 | ||
134 | sub cont($$); | |
135 | sub cont($$) # {{{ | |
136 | { | |
137 | my ($spec, $macros) = @_; | |
138 | local $_; | |
139 | while ($_ = shift @{$spec}) { | |
140 | if (0 <= index $_, '%if') { # if, ifarch, ifos | |
141 | ||
142 | # split spec parsing | |
143 | my @speccopy = @{$spec}; | |
144 | my %macroscopy = %{$macros}; | |
145 | cont(\@speccopy, \%macroscopy); | |
0db58532 | 146 | |
8079fcc5 | 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 | } | |
157 | ||
158 | # continue parsing | |
159 | ||
160 | } elsif ($_ eq '%else') { | |
161 | ||
162 | # %else happens only when %if was interpreted | |
163 | # so skip until %endif | |
164 | ||
165 | my $level = 0; | |
166 | while ($_ = shift @{$spec}) { | |
167 | if ($level <= 0 and $_ eq '%endif') { | |
168 | last; | |
169 | } elsif (0 <= index $_, '%if') { | |
170 | $level++; | |
171 | } elsif ($_ eq '%endif') { | |
172 | $level--; | |
173 | } | |
174 | } | |
175 | ||
176 | } elsif (/^\s*\%(define|global)\s+([^\s]+)\s+([^\s].*?)\s*$/) { | |
177 | $macros->{$2} = $3; | |
178 | ||
179 | } elsif (/^Version\s*:\s*(.*?)\s*$/i) { | |
180 | $macros->{"version"} = $1; | |
181 | } elsif (/^Name\s*:\s*(.*?)\s*$/i) { | |
182 | $macros->{"name"} = $1; | |
183 | } elsif (!/\%endif/) { | |
184 | warn "unrecognised line: $_\n"; | |
185 | } | |
186 | } | |
187 | ||
188 | # the end, yuppie ! | |
189 | foreach my $s (@sources) { | |
190 | my $src = expand( $s->[2], $macros ); | |
191 | if (defined $src) { | |
192 | our %tried; | |
193 | unless (exists $tried{$src}) { | |
194 | print_source( $s->[0], $s->[1], $src ); | |
195 | $tried{$src} = 1; | |
196 | } | |
197 | } | |
198 | } | |
199 | ||
200 | if (++$total > 10000) { | |
201 | error("maximum number of bcond posibilities exceeded"); | |
202 | exit 0; | |
203 | } | |
204 | } # }}} | |
205 | ||
206 | sub print_once($) | |
0db58532 | 207 | { |
8079fcc5 | 208 | our %printed; |
209 | my $l = shift; | |
210 | unless (exists $printed{$l}) { | |
211 | print $l . "\n"; | |
212 | $printed{$l} = 1; | |
213 | } | |
0db58532 MM |
214 | } |
215 | ||
8079fcc5 | 216 | sub print_source($$$) # {{{ |
0db58532 | 217 | { |
8079fcc5 | 218 | my ($no, $md5, $s) = @_; |
219 | ||
0dd6294b | 220 | if ($s =~ /^([a-z0-9A-Z:\=\?\@\+\~\.\-\/_]|\%[0-9])+$/) { |
8079fcc5 | 221 | if ($s =~ /^(ftp|http|https):\/\//) { |
222 | if ($s =~ /\/$/) { | |
223 | error("source $no ($s) is directory"); | |
224 | } else { | |
225 | if ($s =~ /:\/\/distfiles\.pld-linux\.org\/src/) { | |
226 | $s =~ s|.*/||; | |
227 | print_once( "$md5 no-url-copy://$s" ); | |
228 | } else { | |
229 | print_once( "$md5 $s" ); | |
230 | } | |
231 | } | |
232 | } else { | |
233 | $s =~ s|.*/||; | |
234 | print_once( "$md5 no-url://$s"); | |
235 | } | |
7882011d | 236 | } else { |
8079fcc5 | 237 | error("source $no url $s is ill-formatted"); |
0db58532 | 238 | } |
8079fcc5 | 239 | } # }}} |
240 | ||
241 | sub add_md5_to_print($) # {{{ | |
242 | { | |
243 | open(F, "< $_[0]") or die; | |
244 | my $sourceno = undef; | |
245 | my $source = undef; | |
246 | while (<F>) { | |
247 | chomp; | |
248 | if (/^Source(\d+)\s*:\s*(.*)/i) { | |
249 | $sourceno = $1; | |
250 | $source = $2; | |
251 | } elsif (/^\s*#\s*source(\d+)-md5\s*:\s*([a-f0-9]{32})/i) { | |
252 | my $no = $1; | |
253 | my $md5 = $2; | |
254 | if (defined $no_source{$no}) { | |
255 | error("both NoSource: $no and md5 given"); | |
256 | } if (defined $sourceno) { | |
257 | if ($sourceno == $no) { | |
258 | push @sources, [$no, $md5, $source]; | |
259 | } else { | |
260 | error("found md5 for source $no, but last defined source is $sourceno (# SourceN-md5: has to be placed just after SourceN:)"); | |
261 | } | |
262 | } else { | |
263 | error("source $no not defined (# SourceN-md5: has to be placed just after SourceN:)"); | |
264 | } | |
265 | ||
266 | $sourceno = undef; | |
267 | $source = undef; | |
268 | } | |
269 | } | |
270 | close(F); | |
271 | } # }}} | |
0db58532 | 272 | |
0dd6294b | 273 | next_spec(shift); |
8079fcc5 | 274 | preparse_spec($spec); |
275 | add_md5_to_print($spec); | |
276 | cont( \@spec, { "nil" => "" } ); | |
0db58532 MM |
277 | |
278 | exit(0); | |
8079fcc5 | 279 | |
280 | # vim: ts=4:sw=4:fdm=marker |