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