- only print parse warnings if $config->{'warnings'} is set
[platform/upstream/build.git] / substitutedeps
1 #!/usr/bin/perl -w
2
3 BEGIN {
4   unshift @INC, ($::ENV{'BUILD_DIR'} || '/usr/lib/build');
5 }
6
7 use strict;
8
9 use Build;
10
11
12 sub expand {
13   my ($config, $str) = @_;
14   my @xspec;
15   my %cf = %$config;
16   $cf{'save_expanded'} = 1;
17   Build::Rpm::parse(\%cf, [ "$str" ], \@xspec);
18   return @xspec && ref($xspec[0]) ? $xspec[0]->[1] : '';
19 }
20
21 my ($dist, $buildroot, $rpmdeps, $archs, $configdir, $release, $changelog);
22
23 while (@ARGV)  {
24   if ($ARGV[0] eq '--root') {
25     shift @ARGV;
26     $buildroot = shift @ARGV;
27     next;
28   }
29   if ($ARGV[0] eq '--dist') {
30     shift @ARGV;
31     $dist = shift @ARGV;
32     next;
33   }
34   if ($ARGV[0] eq '--archpath') {
35     shift @ARGV;
36     $archs = shift @ARGV;
37     next;
38   }
39   if ($ARGV[0] eq '--configdir') {
40     shift @ARGV;
41     $configdir = shift @ARGV;
42     next;
43   }
44   if ($ARGV[0] eq '--release') {
45     shift @ARGV;
46     $release = shift @ARGV;
47     next;
48   }
49   if ($ARGV[0] eq '--changelog') {
50     shift @ARGV;
51     $changelog = shift @ARGV;
52     next;
53   }
54   last;
55 }
56 die("Usage: substitutedeps --dist <dist> --archpath <archpath> [--configdir <configdir>] <specin> <specout>\n") unless @ARGV == 2;
57 my $spec = $ARGV[0];
58 my $specdir = $spec;
59 $specdir =~ s/[^\/]*$//;
60 $specdir = "./" if $specdir eq '';
61
62 my $newspec = $ARGV[1];
63
64 my $cf = Build::read_config_dist($dist, $archs, $configdir);
65 $cf->{'warnings'} = 1;
66
67 #######################################################################
68
69 my $xspec = [];
70 my $d = Build::parse($cf, $spec, $xspec) || {};
71 my @sdeps = @{$d->{'deps'} || []};
72 my @neg = map {substr($_, 1)} grep {/^-/} @{$d->{'deps'} || []};
73 my %neg = map {$_ => 1} @neg;
74 @sdeps = grep {!$neg{$_}} @sdeps;
75 @sdeps = Build::do_subst($cf, @sdeps);
76 @sdeps = grep {!$neg{$_}} @sdeps;
77 my %sdeps = map {$_ => 1} @sdeps;
78
79 open(F, '>', $newspec) || die("$newspec: $!\n");
80
81 my $used;
82 my $inchangelog = 0;
83 my $mainpkg = '';
84 my $pkg;
85
86 for my $l (@$xspec) {
87   $used = 1;
88   if (ref($l)) {
89     if (!defined($l->[1])) {
90       $used = 0;
91       $l = $l->[0];
92     } else {
93       $l = $l->[1];
94     }
95   }
96
97   if ($inchangelog) {
98     $inchangelog = 0 if $l =~ /^\s*%[^%]/;
99     next if $inchangelog;
100   }
101   if ($changelog && ($l =~ /\s*\%changelog\b/)) {
102     $inchangelog = 1;
103     next;
104   }
105
106   if ($l =~ /^Name\s*:\s*(\S+)/i) {
107     $pkg = $mainpkg = $1 unless $mainpkg;
108   }
109   if ($l =~ /^\s*%package\s+(-n\s+)?(\S+)/) {
110     if ($1) {
111       $pkg = $2;
112     } else {
113       $pkg = "$mainpkg-$2";
114     }
115   }
116
117   if ($l =~ /^Release:/i) {
118     my $oldl = $l;
119     if ($release) {
120       if (!($l =~ s/<RELEASE\d*>/$release/g)) {
121         if ($l =~ /<(?:CI_CNT|B_CNT)>/) {
122           # XXX: should pass ci_cnt/b_cnt instead
123           if ($release =~ /(\d+)\.(\d+)$/) {
124             my ($ci, $b) = ($1, $2);
125             $l =~ s/<CI_CNT>/$ci/;
126             $l =~ s/<B_CNT>/$b/;
127           } elsif ($release =~ /(\d+)$/) {
128             my $b = $1;
129             $l =~ s/<B_CNT>/$b/ unless $l =~ s/<CI_CNT>/$b/;
130           }
131         } else {
132           $l =~ s/^(Release:\s*).*/$1$release/i;
133         }
134       }
135     }
136     # this is to be compatible to legacy autobuild.
137     # you can specify a releaseprg in the project configuration,
138     # if your package contains this file it is executed and its
139     # output is used as a release.
140     # use only if you really must.
141     if ($cf->{'releaseprg'} && -f "$specdir$cf->{'releaseprg'}") {
142       my $newl = $l;
143       $newl =~ s/^Release:\s*//;
144       $oldl =~ s/^Release:\s*//;
145       my $project = expand($cf, "%?_project") || 'BUILD_BASENAME';
146       my $arch = expand($cf, "%?_target_cpu") || 'noarch';
147       $::ENV{'BUILD_OLDRELEASE'} = $oldl;
148       my @nl;
149       my $interpreter = "/bin/bash";
150       if (open(RP, '<', "$specdir$cf->{'releaseprg'}")) {
151         @nl = <RP>;
152         close RP;
153         if (@nl && $nl[0] =~ /^#!\s*(\S*)/) {
154           $interpreter = $1;
155         }
156       }
157       if ($buildroot) {
158         my $sd = $specdir;
159         $sd =~ s/^\Q$buildroot\E//;
160         open(RP, "-|", 'chroot', $buildroot, $interpreter, "$sd$cf->{'releaseprg'}", $project, $newl, $pkg, $arch) || die("$cf->{'releaseprg'}: $!\n");
161       } else {
162         open(RP, "-|", $interpreter, "$specdir$cf->{'releaseprg'}", $project, $newl, $pkg, $arch) || die("$cf->{'releaseprg'}: $!\n");
163       }
164       @nl = grep {$_ ne ''} <RP>;
165       if (!close(RP)) {
166         warn("$cf->{'releaseprg'} failed: $?\n");
167       }
168       # and another compatibility hack: if the prg returns pkg:<package>,
169       # the release of the package will be used. yuck...
170       if (@nl && $nl[0] =~ s/^pkg://) {
171         my $relpkg = $nl[0];
172         chomp $relpkg;
173         if ($buildroot) {
174           open(RP, "-|", 'chroot', $buildroot, 'rpm', '-q', '--qf', '%{RELEASE}', $relpkg) || die("rpm: $!\n");
175         } else {
176           open(RP, "-|", 'rpm', '-q', '--qf', '%{RELEASE}', $relpkg) || die("rpm: $!\n");
177         }
178         @nl = grep {$_ ne ''} <RP>;
179         if (!close(RP)) {
180           warn("rpm package query of '$relpkg' failed: $?\n");
181         }
182       }
183       if ($nl[0]) {
184         chomp $nl[0];
185         $l =~ s/^(Release:\s*).*/$1$nl[0]/i;
186         if ($release) {
187           if (!($l =~ s/<RELEASE\d*>/$release/g)) {
188             if ($l =~ /<(?:CI_CNT|B_CNT)>/) {
189               # XXX: should pass ci_cnt/b_cnt instead
190               if ($release =~ /(\d+)\.(\d+)$/) {
191                 my ($ci, $b) = ($1, $2);
192                 $l =~ s/<CI_CNT>/$ci/;
193                 $l =~ s/<B_CNT>/$b/;
194               } elsif ($release =~ /(\d+)$/) {
195                 my $b = $1;
196                 $l =~ s/<B_CNT>/$b/ unless $l =~ s/<CI_CNT>/$b/;
197               }
198             }
199           }
200         }
201       }
202     }
203     # all compat stuff done. we return to your scheduled program
204   }
205
206   if (!$used || ($l !~ /^(?:Build)?Requires:/i)) {
207     print F "$l\n";
208     next;
209   }
210
211   my $isbuildrequires = 0;
212   $isbuildrequires = 1 if $l =~ /^BuildRequires:/i;
213   my $r = $l;
214   $r =~ s/^[^:]*:\s*//;
215   my @deps = $r =~ /([^\s\[,]+)(\s+[<=>]+\s+[^\s\[,]+)?[\s,]*/g;
216   my @ndeps = ();
217   my $replace = 0;
218   my @f2 = Build::do_subst_vers($cf, @deps);
219   my %f2 = @f2;
220   if ($isbuildrequires) {
221     delete $f2{$_} for @neg;
222     delete $f2{$_} for grep {/^-/} keys %f2;
223   }
224   while (@deps) {
225     my ($pack, $vers) = splice(@deps, 0, 2);
226     $vers = '' unless defined $vers;
227     if (($isbuildrequires && $sdeps{$pack}) || exists($f2{$pack})) {
228       push @ndeps, "$pack$vers";
229       delete $f2{$pack};
230     } else {
231       $replace = 1;
232     }
233   }
234   if (%f2) {
235     while (@f2) {
236       my ($pack, $vers) = splice(@f2, 0, 2);
237       next unless exists $f2{$pack};
238       $vers = '' unless defined $vers;
239       push @ndeps, "$pack$vers";
240     }
241     $replace = 1
242   }
243   if ($replace) {
244     $l =~ /^(.*?:\s*)/;
245     print F $1.join(' ', @ndeps)."\n" if @ndeps;
246   } else {
247     print F "$l\n";
248   }
249 }
250
251 if ($changelog) {
252   print F "%changelog\n";
253   if (open(CF, '<', $changelog)) {
254     while(<CF>) {
255       print F $_;
256     }
257     close CF;
258   }
259 }
260
261 close(F) || die("close: $!\n");
262
263 exit(0);