openpkg-build.pl 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569
  1. ##
  2. ## openpkg-build.pl -- create build scripts from package index
  3. ##
  4. ## Copyright (c) 2000-2003 Cable & Wireless Deutschland GmbH
  5. ## Copyright (c) 2000-2003 The OpenPKG Project <http://www.openpkg.org/>
  6. ## Copyright (c) 2000-2003 Ralf S. Engelschall <rse@engelschall.com>
  7. ##
  8. ## Permission to use, copy, modify, and distribute this software for
  9. ## any purpose with or without fee is hereby granted, provided that
  10. ## the above copyright notice and this permission notice appear in all
  11. ## copies.
  12. ##
  13. ## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  14. ## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  15. ## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  16. ## IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
  17. ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  18. ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  19. ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  20. ## USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  22. ## OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  23. ## OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. ## SUCH DAMAGE.
  25. ##
  26. require 5;
  27. $|=1; # autoflush
  28. use strict;
  29. use vars qw/$opt_R $opt_r $opt_f $opt_u $opt_U $opt_a $opt_A $opt_z $opt_Z $opt_P $opt_N $opt_E $opt_i $opt_D $opt_p $opt_q $opt_s $opt_S/;
  30. getopts('R:r:f:uUaAzZP:N:E:iD:p:qsS');
  31. ##########################################################################
  32. sub getopts ($) {
  33. my($opts) = @_;
  34. my(%optf) = map { /(\w)/; $1 => $_ } $opts =~ /(\w:|\w)/g;
  35. my(%opts,@argv,$optarg);
  36. foreach (@ARGV) {
  37. if (@argv) {
  38. push @argv, $_;
  39. } elsif (defined $optarg) {
  40. if (exists $opts{$optarg}) {
  41. $opts{$optarg} .= " $_";
  42. } else {
  43. $opts{$optarg} = $_;
  44. }
  45. $optarg = undef;
  46. } elsif (!/^[-]/) {
  47. push @argv, $_;
  48. } else {
  49. while (/^\-(\w)(.*)/) {
  50. if (exists $optf{$1}) {
  51. if (length($optf{$1}) > 1) {
  52. if ($2 ne '') {
  53. if (exists $opts{$1}) {
  54. $opts{$1} .= " $2";
  55. } else {
  56. $opts{$1} = $2;
  57. }
  58. } else {
  59. $optarg = $1;
  60. }
  61. last;
  62. } else {
  63. $opts{$1} = 1;
  64. }
  65. } else {
  66. warn "warning: unknown option $_\n";
  67. }
  68. $_ = "-$2";
  69. }
  70. }
  71. }
  72. if (defined $optarg) {
  73. warn "warning: option $optarg requires an argument\n";
  74. }
  75. foreach (keys %opts) {
  76. eval '$opt_'.$_.' = "'.quotemeta($opts{$_}).'";';
  77. }
  78. @ARGV = @argv;
  79. }
  80. my(%env) = ( '' => { } );
  81. if (open(FH, "< $ENV{'HOME'}/.openpkg/build")) {
  82. my($env) = $env{''};
  83. while (<FH>) {
  84. if (/^\s*\[([^\]]*)\]/) {
  85. $env{$1} = { } unless $env{$1};
  86. $env = $env{$1};
  87. } elsif (my($opt,$val) = /^\-([RfruUaAzPN])\s*(.*?)\s*$/) {
  88. $val = 1 unless defined $val;
  89. $env->{$opt} = $val;
  90. }
  91. }
  92. close(FH);
  93. }
  94. die "openpkg:build:USAGE: $0 [-R rpm] [-r repository] [-f index.rdf] [-uUzZiqS] [-P priv-cmd] [-N non-priv-cmd] [-p platform] [-Dwith ...] [-Ename ...] ( [-aA] | patternlist )\n"
  95. unless $#ARGV >= 0 || ($#ARGV == -1 && ($opt_a || $opt_A));
  96. ##########################################################################
  97. sub conditional ($$) {
  98. my($cond,$with) = @_;
  99. my(@s,$res);
  100. return 1 if $cond eq '';
  101. foreach (split(/\s+/,$cond)) {
  102. if ($_ eq '+') {
  103. die "FATAL: stack underflow in: $cond\n" if scalar(@s)<2;
  104. my($a) = pop @s;
  105. my($b) = pop @s;
  106. push @s, $a && $b;
  107. } elsif ($_ eq '|') {
  108. die "FATAL: stack underflow in: $cond\n" if scalar(@s)<2;
  109. my($a) = pop @s;
  110. my($b) = pop @s;
  111. push @s, $a || $b;
  112. } elsif ($_ eq '!') {
  113. die "FATAL: stack underflow in: $cond\n" if scalar(@s)<1;
  114. my($a) = pop @s;
  115. push @s, !$a;
  116. } else {
  117. push @s, ($with->{$_} eq 'yes') ? 1 : 0;
  118. }
  119. }
  120. die "FATAL: stack underflow in: $cond\n" if scalar(@s)<1;
  121. $res = pop @s;
  122. die "FATAL: stack not empty in: $cond\n" if scalar(@s)>0;
  123. return $res;
  124. }
  125. sub with_list ($$) {
  126. my($bags,$with) = @_;
  127. my($bag,$li);
  128. my(@out);
  129. foreach $bag (@$bags) {
  130. next unless conditional($bag->{'cond'}, $with);
  131. foreach $li (@{$bag->{'rdf:bag'}}) {
  132. push @out, @{$li->{'rdf:li'}};
  133. }
  134. }
  135. return \@out;
  136. }
  137. sub make_hash ($$$) {
  138. my($bags,$tag,$with) = @_;
  139. my($bag,$li);
  140. my(%out,$el);
  141. foreach $bag (@$bags) {
  142. next unless conditional($bag->{'cond'}, $with);
  143. foreach $li (@{$bag->{'rdf:bag'}}) {
  144. foreach (@{$li->{'rdf:li'}}) {
  145. next unless exists $_->{$tag};
  146. $el = $_->{$tag}->[0];
  147. $out{$el->{'ID'}} = $el->{'content'};
  148. }
  149. }
  150. }
  151. return \%out;
  152. }
  153. ##########################################################################
  154. my($RPM,$RPM_PRIV,$RPM_NPRIV,$CURL,$PROG);
  155. $RPM = $opt_R || $env{''}->{opt}->{'R'} || '@l_prefix@/bin/rpm';
  156. $RPM = (`which $RPM` =~ m{^(/.*)})[0];
  157. die "FATAL: cannot locate rpm in path\n" unless $RPM =~ m{^/};
  158. # augment command line parameters
  159. foreach my $env (sort { $a cmp $b } grep { $RPM =~ /^\Q$_\E/ } keys %env) {
  160. while (my($opt,$val) = each %{$env{$env}}) {
  161. eval "\$opt_$opt = '$val' unless defined \$opt_$opt;";
  162. }
  163. }
  164. $RPM_PRIV = ($opt_P ? $opt_P." ".$RPM : $RPM);
  165. $RPM_NPRIV = ($opt_N ? $opt_N." ".$RPM : $RPM);
  166. $CURL = $RPM;
  167. $CURL =~ s/\/bin\/rpm$/\/lib\/openpkg\/curl/
  168. or die "FATAL: cannot deduce curl path from $RPM\n";
  169. ($PROG) = $0 =~ /(?:.*\/)?(.*)/;
  170. sub version_cmp ($$) {
  171. my($a,$b) = @_;
  172. my(@a,@b,$c);
  173. my($ax,$bx);
  174. @a = split(/\./, $a);
  175. @b = split(/\./, $b);
  176. while (@a && @b) {
  177. if ($a[0] =~ /^\d+$/ && $b[0] =~ /^\d+$/) {
  178. $c = $a[0] <=> $b[0];
  179. } elsif ((($a,$ax) = $a[0] =~ /^(\d+)(.*)$/) &&
  180. (($b,$bx) = $b[0] =~ /^(\d+)(.*)$/)) {
  181. $c = $a <=> $b;
  182. $c = $ax cmp $bx unless $c;
  183. } else {
  184. $c = $a[0] cmp $b[0];
  185. }
  186. return $c if $c;
  187. shift @a;
  188. shift @b;
  189. }
  190. $c = scalar(@a) <=> scalar(@b);
  191. return $c;
  192. }
  193. sub release_cmp ($$) {
  194. my($a,$b) = @_;
  195. return $a cmp $b;
  196. }
  197. sub vcmp ($$) {
  198. my($a,$b) = @_;
  199. return 0 if $a eq $b;
  200. my($av,$ar) = $a =~ /^(.*?)(?:\-([\d\.]+))?$/;
  201. my($bv,$br) = $b =~ /^(.*?)(?:\-([\d\.]+))?$/;
  202. my($c);
  203. if ((defined $ar) && (defined $br)) {
  204. $c = release_cmp($ar,$br);
  205. return $c if $c;
  206. }
  207. if ((defined $av) && (defined $bv)) {
  208. $c = version_cmp($av,$bv);
  209. return $c if $c;
  210. }
  211. return 0;
  212. }
  213. sub vs ($) {
  214. my($t) = @_;
  215. return "$t->{version}-$t->{release}";
  216. }
  217. sub vsn ($) {
  218. my($t) = @_;
  219. return "$t->{name}-$t->{version}-$t->{release}";
  220. }
  221. ##########################################################################
  222. sub get_config ()
  223. {
  224. my($c,@q,@g);
  225. $c = `$RPM_NPRIV --eval '%{_rpmdir} %{_rpmfilename} %{_target_os} %{_target_cpu} %{_target_platform} %{_prefix}'`;
  226. chomp($c);
  227. (@q) = split(/\s+/,$c);
  228. $q[1] =~ s/%{OS}/$q[2]/;
  229. $q[1] =~ s/%{ARCH}/$q[3]/;
  230. $c = `$RPM_NPRIV --showrc`;
  231. @g = $c =~ /\%\{l_tool_locate\s+([^\s\}]+)/g;
  232. return {
  233. rpmdir => $q[0],
  234. template => $q[1],
  235. platform => $q[4],
  236. prefix => $q[5],
  237. optreg => '(?:'.join('|', map { "\Qwith_$_\E" } @g).')'
  238. };
  239. }
  240. sub get_release () {
  241. my($rel,$url);
  242. ($rel) =`$RPM_NPRIV -qi openpkg` =~ /Version:\s*(\S+)/m;
  243. if ($rel =~ /^\d+$/) {
  244. print "# $PROG current($rel)\n";
  245. print "# using '$RPM_NPRIV' (build) and '$RPM_PRIV' (install)\n";
  246. $url = "ftp://ftp.openpkg.org/current/";
  247. } elsif ($rel =~ /^(\d+\.\d+)/) {
  248. $rel = $1;
  249. print "# $PROG release($rel)\n";
  250. $url = "ftp://ftp.openpkg.org/release/$rel/";
  251. } else {
  252. die "FATAL: don't know how to handle this release\n";
  253. }
  254. return $url;
  255. }
  256. sub parse_provides ($) {
  257. my($s) = @_;
  258. my($nam,$val,$pre,$with,$pxy,$ver,$rel);
  259. ($nam,$val) = $s =~ /^(\S+)\s*(?:=\s*(\S*?))?$/;
  260. #
  261. # build options are encoded as a Requirement
  262. # <packagename>::<buildoption> = <value>
  263. #
  264. # since the value is interpreted as a version number
  265. # you can only do equality tests
  266. #
  267. if (($pre,$with) = $nam =~ /^(\S+?)::(\S*)$/) {
  268. $val =~ s/(?:\%([0-9a-fA-F][0-9a-fA-F]))/chr(hex($1))/eg;
  269. ($ver,$rel,$pxy) = ($val, '', undef);
  270. } else {
  271. ($ver,$rel,$pxy) = $val =~ /^([^\s\-]+)-([^\s\+]+)(\+PROXY)?$/;
  272. }
  273. return {
  274. name => $nam,
  275. version => $ver,
  276. release => $rel,
  277. proxy => $pxy,
  278. prefix => $pre,
  279. with => $with
  280. };
  281. }
  282. sub get_installed () {
  283. my(%map);
  284. my(@l) = `$RPM_NPRIV --provides -qa`;
  285. my($p);
  286. my($nam,$val,%options);
  287. foreach (@l) {
  288. $p = parse_provides($_);
  289. if (defined $p->{with}) {
  290. $options{$p->{prefix}}->{$p->{with}} = $p->{version}
  291. }
  292. push @{$map{$p->{name}}->{"$p->{version}-$p->{release}"}}, {
  293. name => $p->{name},
  294. version => (defined $p->{version} ? $p->{version} : '*'),
  295. release => (defined $p->{release} ? $p->{release} : '*'),
  296. PROXY => $p->{proxy}
  297. };
  298. }
  299. #
  300. # options are provided for a package
  301. # apply them to all instances of the package
  302. #
  303. foreach $nam (keys %options) {
  304. foreach $val (keys %{$map{$nam}}) {
  305. foreach (@{$map{$nam}->{$val}}) {
  306. $_->{OPTIONS} = $options{$nam};
  307. }
  308. }
  309. }
  310. return \%map;
  311. }
  312. sub revdep ($$$) {
  313. my($rev,$t,$name) = @_;
  314. return 1 if $name eq $t->{name};
  315. foreach (@{$rev->{$_}}) {
  316. return 1 if revdep($rev,$t,$_->{name});
  317. }
  318. return -1;
  319. }
  320. sub get_revdep ($) {
  321. my($env) = @_;
  322. my($i) = $env->{'installed'};
  323. my($r) = $env->{'repository'};
  324. my($pkg, %rev);
  325. my(@vers,$t,@names);
  326. print "# computing reverse dependencies\n";
  327. foreach $pkg (keys %$i) {
  328. unless ($r->{$pkg}) {
  329. print "# ATTENTION: $pkg has no upgrade path\n";
  330. next;
  331. }
  332. @vers = get_versions($r->{$pkg}, sub { 1; });
  333. foreach (@vers) {
  334. foreach $t (@{$r->{$pkg}->{$_}}) {
  335. next unless $i->{$t->{name}};
  336. next unless $t->{depends};
  337. @names = grep { $_ ne '' }
  338. map { /^(\S+)/ }
  339. @{$t->{depends}};
  340. next unless @names;
  341. push @{$rev{$_}}, $t foreach @names;
  342. }
  343. }
  344. }
  345. foreach $pkg (keys %rev) {
  346. $rev{$pkg} = [
  347. sort {
  348. revdep(\%rev, $b, $a->{name});
  349. } @{$rev{$pkg}}
  350. ];
  351. }
  352. return \%rev;
  353. }
  354. #
  355. # parse option from rpm output
  356. #
  357. sub parse_options ($) {
  358. my($l) = @_;
  359. $l = join("\n", @$l) if ref $l;
  360. return if ($l !~ m/(--define|\%option\s+)/s);
  361. my $with = {};
  362. $l =~ s/--define\s*'(\S+)\s+(\S+?)'/$with->{$1} = $2, ''/sge; # before openpkg-20021230
  363. $l =~ s/\%option\s+(\S+)\s+(\S+)/$with->{$1} = $2, ''/sge; # after openpkg-20021230
  364. return $with;
  365. }
  366. #
  367. # copy options from new to old
  368. # where option already exists in old or option key
  369. # matches regular expression
  370. #
  371. sub override_options ($$$) {
  372. my($old, $new, $reg) = @_;
  373. foreach my $k (keys %$new) {
  374. $old->{$k} = $new->{$k} if exists $old->{$k} || $k =~ /^$reg$/;
  375. }
  376. }
  377. sub get_with ($;$) {
  378. my($t,$fn) = @_;
  379. my(@l,%with);
  380. unless ($t->{OPTIONS}) {
  381. if (defined $fn) {
  382. @l = `$RPM_NPRIV -qi -p $fn`;
  383. } else {
  384. @l = `$RPM_NPRIV -qi $t->{name}`;
  385. }
  386. $t->{OPTIONS} = parse_options(\@l);
  387. }
  388. return $t->{OPTIONS};
  389. }
  390. sub relurl ($$$) {
  391. my($url,$fn,$suburl) = @_;
  392. my($subfn,$submap);
  393. unless ($suburl =~ /^\w+:\/\// || $suburl =~ /^\//) {
  394. if (defined $fn) {
  395. $subfn = $fn;
  396. $subfn =~ s/\/[^\/]*$//;
  397. $subfn .= '/' unless $subfn =~ /\/$/;
  398. $subfn .= $suburl;
  399. $suburl = $subfn;
  400. } else {
  401. $subfn = $url;
  402. $subfn =~ s/\/[^\/]*$//;
  403. $subfn .= '/' unless $subfn =~ /\/$/;
  404. $suburl = "$subfn$suburl";
  405. $subfn = undef;
  406. }
  407. }
  408. return ($suburl, $subfn);
  409. }
  410. sub xel($) {
  411. my($a) = @_;
  412. my($l) = $a->[0];
  413. return '' if ref $l;
  414. return $l;
  415. }
  416. sub get_index ($$$) {
  417. my($url,$fn,$with) = @_;
  418. my($ua,$req,$res,$rdf);
  419. my($bzip2,$path);
  420. my(%map,@include);
  421. my($fetch);
  422. $fetch = defined $fn ? $fn : $url;
  423. $bzip2 = $RPM;
  424. $bzip2 =~ s/bin\/rpm$/lib\/openpkg\/bzip2/
  425. or die "FATAL: cannot deduce bzip2 path from $RPM\n";
  426. $fetch !~ /\.bz2$/ || -x $bzip2
  427. or die "FATAL: $bzip2 not found\n";
  428. if ($fetch =~ /^\w+:/) { # looks like URL scheme
  429. print "# curling index $fetch\n";
  430. if ($fetch =~ /\.bz2$/) {
  431. $path = "$CURL -q -s -o - \"$fetch\" | $bzip2 -dc |";
  432. } else {
  433. $path = "$CURL -q -s -o - \"$fetch\" |";
  434. }
  435. } else {
  436. print "# reading index file $fn\n";
  437. if ($fetch =~ /\.bz2$/) {
  438. $path = "$bzip2 -dc $fetch |";
  439. } else {
  440. $path = "< $fetch";
  441. }
  442. }
  443. open(RFH, $path) or
  444. die "FATAL: cannot open '$fetch' ($!)\n";
  445. eval {
  446. require XML::Simple;
  447. };
  448. if ($@) {
  449. print "# using simple text parser\n";
  450. my($section);
  451. my($name,$version);
  452. my($href,$release,$desc);
  453. my(@prereq,@bprereq);
  454. my(@provides,@conflicts);
  455. my(%options);
  456. my($platform,$prefix);
  457. my($rec);
  458. my($tag,$cond,$body);
  459. my($useit);
  460. while (<RFH>) {
  461. s/&gt;/>/g;
  462. s/&lt;/</g;
  463. if (!(defined $href) && /<rdf:Description.*?href="([^"]*)"/) {
  464. $href = $1;
  465. $section = undef;
  466. $name = undef;
  467. $release = undef;
  468. $desc = '';
  469. $platform = undef;
  470. $prefix = undef;
  471. @prereq = ();
  472. @bprereq = ();
  473. @provides = ();
  474. @conflicts = ();
  475. }
  476. if (!(defined $href) && /<Repository.*?href="([^"]*)"/) {
  477. push(@include, $1);
  478. next;
  479. }
  480. next unless defined $href;
  481. ($tag,$cond,$body) = /
  482. <
  483. (\/?[\w:]+)
  484. \s*
  485. (?:cond="([^"]+)")?
  486. >
  487. (.*?)
  488. (?:<\/\1>)?
  489. $
  490. /mx;
  491. $useit = conditional($cond,$with);
  492. if ($tag eq 'Description') {
  493. $section = 'description';
  494. } elsif ($tag eq '/Description') {
  495. $section = undef;
  496. } elsif ($section eq 'description') {
  497. $desc .= $_;
  498. } elsif ($tag eq 'PreReq') {
  499. $section = 'prereq' if $useit;
  500. } elsif ($tag eq '/PreReq') {
  501. $section = undef;
  502. } elsif ($tag eq 'BuildPreReq') {
  503. $section = 'bprereq' if $useit;
  504. } elsif ($tag eq '/BuildPreReq') {
  505. $section = undef;
  506. } elsif ($tag eq 'Provides') {
  507. $section = 'provides' if $useit;
  508. } elsif ($tag eq '/Provides') {
  509. $section = undef;
  510. } elsif ($tag eq 'Conflicts') {
  511. $section = 'conflicts' if $useit;
  512. } elsif ($tag eq '/Conflicts') {
  513. $section = undef;
  514. } elsif ($tag eq 'Name') {
  515. $name = $body;
  516. } elsif ($tag eq 'Version') {
  517. $version = $body;
  518. } elsif ($tag eq 'Release') {
  519. $release = $body;
  520. } elsif ($tag eq 'Platform') {
  521. $platform = $body;
  522. } elsif ($tag eq 'Prefixes') {
  523. $prefix = $body;
  524. } elsif ($tag eq 'rdf:li') {
  525. if ($section eq 'prereq') {
  526. push(@prereq, $body);
  527. } elsif ($section eq 'bprereq') {
  528. push(@bprereq, $body);
  529. } elsif ($section eq 'provides') {
  530. push(@provides, $body);
  531. } elsif ($section eq 'conflicts') {
  532. push(@conflicts, $body);
  533. }
  534. } elsif ($tag eq '/rdf:Description') {
  535. if (defined $href &&
  536. defined $name &&
  537. defined $version &&
  538. defined $release) {
  539. @provides = map { parse_provides($_) } @provides;
  540. %options = map {
  541. ( $_->{with} => $_->{version} )
  542. } grep {
  543. defined $_->{with}
  544. } @provides;
  545. unless (grep($_->{name} eq $name, @provides)) {
  546. push(@provides, {
  547. name => $name,
  548. version => $version,
  549. release => $release
  550. });
  551. }
  552. $rec = {
  553. href => (relurl($url, undef, $href))[0],
  554. name => $name,
  555. version => $version,
  556. release => $release,
  557. depends => [ @bprereq ],
  558. keeps => [ @prereq ],
  559. conflicts => [ @conflicts ],
  560. desc => $desc,
  561. platform => $platform,
  562. prefix => $prefix
  563. };
  564. $rec->{OPTIONS} =
  565. %options
  566. ? { %options }
  567. : parse_options($rec->{desc});
  568. foreach (@provides) {
  569. push(@{$map{$_->{name}}->{vs($_)}}, $rec);
  570. }
  571. }
  572. $href = undef;
  573. }
  574. }
  575. } else {
  576. print "# using XML parser\n";
  577. my($xml) = XML::Simple::XMLin(\*RFH, forcearray => 1);
  578. my($desc) = $xml->{'Repository'}->[0]->{'rdf:Description'};
  579. my($sub) = $xml->{'Repository'}->[0]->{'Repository'};
  580. my($provides,@provides,%options,$rec);
  581. my($href,$name,$version,$release);
  582. foreach (@$desc) {
  583. $href = $_->{'href'};
  584. $name = xel($_->{'Name'});
  585. $version = xel($_->{'Version'});
  586. $release = xel($_->{'Release'});
  587. next unless defined $href &&
  588. defined $name &&
  589. defined $version &&
  590. defined $release;
  591. $provides = $_->{'Provides'}->[0]->{'rdf:bag'}->[0]->{'rdf:li'};
  592. @provides = map { parse_provides($_) } @$provides;
  593. %options = map {
  594. ( $_->{with} => $_->{version} )
  595. } grep {
  596. defined $_->{with}
  597. } @provides;
  598. unless (grep($_->{name} eq $name, @provides)) {
  599. push(@provides, {
  600. name => $name,
  601. version => $version,
  602. release => $release
  603. });
  604. }
  605. $rec = {
  606. href => (relurl($url, undef, $href))[0],
  607. name => $name,
  608. version => $version,
  609. release => $release,
  610. platform => xel($_->{'Platform'}),
  611. prefix => xel($_->{'Prefixes'}),
  612. depends => with_list($_->{'BuildPreReq'}, $with),
  613. keeps => with_list($_->{'PreReq'}, $with),
  614. conflicts => with_list($_->{'Conflicts'}, $with),
  615. desc => xel($_->{'Description'})
  616. };
  617. $rec->{OPTIONS} =
  618. %options
  619. ? { %options }
  620. : parse_options($rec->{desc});
  621. foreach (@provides) {
  622. push(@{$map{$_->{name}}->{vs($_)}}, $rec);
  623. }
  624. }
  625. if ($sub) {
  626. @include = map { $_->{href} } @$sub;
  627. }
  628. }
  629. close(RFH)
  630. or die "FATAL: an I/O error occured\n";
  631. #
  632. # cannot do real recursions on file handles, so we simply append
  633. # all sub-RDFs, the result is flattend into a big hash anyway
  634. #
  635. foreach (@include) {
  636. my($submap);
  637. my($suburl,$subfn) = relurl($url,$fn,$_);
  638. $submap = get_index($suburl,$subfn,$with);
  639. while (my($name,$vmap) = each %$submap) {
  640. while (my($vs,$recs) = each %$vmap) {
  641. push @{$map{$name}->{$vs}}, @$recs;
  642. }
  643. }
  644. }
  645. return \%map;
  646. }
  647. #
  648. # grep all versions of a name that
  649. # satisfy a condition
  650. #
  651. sub get_versions ($$) {
  652. my($relmap, $cond) = @_;
  653. return grep { $cond->($_); }
  654. sort { vcmp($a,$b); } keys %$relmap;
  655. }
  656. #
  657. # there can be multiple sources for a target release
  658. #
  659. sub chose_source ($$@) {
  660. my($env, $name, $vmap, @vers) = @_;
  661. my(@recs,@nrecs,$rec);
  662. return unless @vers;
  663. @recs = grep {
  664. $env->{sourceonly} ? (
  665. !(defined $_->{'platform'})
  666. ) : (
  667. !(defined $_->{'platform'}) || (
  668. defined $_->{'prefix'} &&
  669. $_->{'platform'} eq $env->{config}->{platform} &&
  670. $_->{'prefix'} eq $env->{config}->{prefix}
  671. )
  672. )
  673. } map { @{$vmap->{$_}} } @vers;
  674. return unless @recs;
  675. if (scalar(@recs) > 1) {
  676. @nrecs = grep {
  677. $env->{built}->{$_->{name}} ||
  678. $env->{installed}->{$_->{name}}
  679. } @recs;
  680. @recs = @nrecs if @nrecs;
  681. }
  682. if (scalar(@recs) > 1 && !$env->{sourceonly}) {
  683. @nrecs = grep {
  684. defined $_->{'platform'}
  685. } @recs;
  686. @recs = @nrecs if @nrecs;
  687. }
  688. if (scalar(@recs) > 1) {
  689. print "# ambigous sources for $name\n";
  690. my($i) = 0;
  691. foreach (@recs) {
  692. print "# $i: ".vsn($_)." = $_->{href}\n";
  693. $i++;
  694. }
  695. return;
  696. } else {
  697. if ($env->{upgrade}) {
  698. $rec = $recs[-1];
  699. } else {
  700. $rec = $recs[0];
  701. }
  702. }
  703. print "# source for $name is ".vsn($rec)."\n";
  704. return $rec;
  705. }
  706. #
  707. # see wether target is in map
  708. #
  709. sub target_exists ($$) {
  710. my($target, $map) = @_;
  711. my($vmap) = $map->{$target->{name}};
  712. return unless $vmap;
  713. return !defined $target->{version} ||
  714. defined $vmap->{vs($target)};
  715. }
  716. #
  717. # find target in map
  718. #
  719. sub find_target ($$) {
  720. my($name, $map) = @_;
  721. my($vmap) = $map->{$name};
  722. my(@vs);
  723. return unless $vmap;
  724. @vs = sort { vcmp($b,$a) } keys %$vmap;
  725. return $vmap->{$vs[0]}->[-1];
  726. }
  727. #
  728. # see wether target has conflicts in map
  729. #
  730. sub target_conflicts ($$) {
  731. my($target, $map) = @_;
  732. my($t);
  733. foreach (@{$target->{conflicts}}) {
  734. $t = find_target($_, $map);
  735. return $t if $t;
  736. }
  737. return;
  738. }
  739. #
  740. # retrieve build dependencies for target in map
  741. #
  742. sub target_depends ($$) {
  743. my($target, $map) = @_;
  744. my($vmap,$vers);
  745. die "FATAL: ",vsn($target)," not in depend map\n"
  746. unless
  747. ( $vmap = $map->{$target->{name}} ) &&
  748. ( defined $target->{version} ) &&
  749. ( $vers = $vmap->{vs($target)} ) &&
  750. @$vers;
  751. return $vers->[0]->{depends};
  752. }
  753. #
  754. # retrieve runtime dependencies for target in map
  755. #
  756. sub target_keeps ($$) {
  757. my($target, $map) = @_;
  758. my($vmap,$vers);
  759. die "FATAL: ",vsn($target)," not in keep map\n"
  760. unless
  761. ( $vmap = $map->{$target->{name}} ) &&
  762. ( defined $target->{version} ) &&
  763. ( $vers = $vmap->{vs($target)} ) &&
  764. @$vers;
  765. return $vers->[0]->{keeps};
  766. }
  767. #
  768. # test wether target could be upgraded
  769. #
  770. sub target_newer ($$) {
  771. my($target, $map) = @_;
  772. my($vs) = vs($target);
  773. my($vmap) = $map->{$target->{name}};
  774. return 1 unless $vmap;
  775. return !grep { vcmp($vs, $_) <= 0; } keys %$vmap;
  776. }
  777. #
  778. # check wether installed package matches
  779. # build options
  780. #
  781. sub target_suitable ($$) {
  782. my($target, $with) = @_;
  783. my($iwith);
  784. my($k,$v);
  785. $iwith = $target->{OPTIONS};
  786. while (($k,$v) = each %$with) {
  787. if (exists $iwith->{$k}) {
  788. return 0 if $iwith->{$k} ne $with->{$k};
  789. }
  790. }
  791. return 1;
  792. }
  793. #
  794. # record target status
  795. #
  796. sub target_setstatus ($$$) {
  797. my($target, $status, $pri) = @_;
  798. if ($pri > $target->{STATUSPRI}) {
  799. $target->{STATUSPRI} = $pri;
  800. $target->{STATUS} = $status;
  801. }
  802. }
  803. #
  804. # report options that are not used for
  805. #
  806. sub warn_about_options ($$$) {
  807. my($target, $with, $c) = @_;
  808. my($iwith) = $target->{OPTIONS};
  809. my($k,$v);
  810. return unless defined $iwith;
  811. while (($k,$v) = each %$with) {
  812. if (!exists $iwith->{$k} && $k !~ $c->{optreg}) {
  813. print "# ATTENTION: $target->{name} ignores option '$k'\n";
  814. }
  815. }
  816. }
  817. #
  818. # locate target for a dependency
  819. #
  820. sub dep2target ($$) {
  821. my($dep, $env) = @_;
  822. my($name,@vers);
  823. my($i,$r,$b,$cond,$version);
  824. my($t,$tdef);
  825. $dep =~ s/(\S+)\s*//;
  826. $name = $1;
  827. $i = $env->{installed}->{$name};
  828. $r = $env->{repository}->{$name};
  829. $b = $env->{built}->{$name};
  830. return unless $i || $r || $b;
  831. if ($dep =~ /^(?:>=|=>)\s*(\S+)$/) {
  832. $version = $1;
  833. $cond = sub { vcmp($_[0],$version) >= 0; };
  834. } elsif ($dep =~ /^(?:<=|=<)\s*(\S+)$/) {
  835. $version = $1;
  836. $cond = sub { vcmp($_[0],$version) <= 0; };
  837. } elsif ($dep =~ /^>\s*(\S+)$/) {
  838. $version = $1;
  839. $cond = sub { vcmp($_[0],$version) > 0; };
  840. } elsif ($dep =~ /^<\s*(\S+)$/) {
  841. $version = $1;
  842. $cond = sub { vcmp($_[0],$version) < 0; };
  843. } elsif ($dep =~ /^==?\s*(\S+)$/) {
  844. $version = $1;
  845. $cond = sub { vcmp($_[0],$version) == 0; };
  846. } elsif ($dep =~ /^\s*$/) {
  847. $cond = sub { 1; };
  848. } else {
  849. print "# don't know how to handle PreReq: $name $dep\n";
  850. return;
  851. }
  852. $tdef = undef;
  853. if ($i && (@vers = get_versions($i, $cond))) {
  854. foreach (@vers) {
  855. $t = $i->{$_}->[0];
  856. if (get_with($t), target_suitable($t, $env->{with})) {
  857. $tdef = $t;
  858. if (!$env->{upgrade}) {
  859. return ($t, 1);
  860. }
  861. }
  862. }
  863. }
  864. if ($b && (@vers = get_versions($b, $cond))) {
  865. return ($b->{$vers[0]}->[0], 1);
  866. }
  867. $t = chose_source($env, $name, $r, get_versions($r, $cond));
  868. if ($t) {
  869. return ($t, 0);
  870. }
  871. if ($tdef) {
  872. return ($tdef, 1);
  873. }
  874. return;
  875. }
  876. sub make_dep ($$$$$$) {
  877. my($target,$depth,$env,$list,$blist,$clist) = @_;
  878. my($d,$k,%d,%k,$t,$old);
  879. my(@deps,$conflict);
  880. if (target_exists($target, $env->{built})) {
  881. print "# $target->{name} is already in list\n";
  882. return;
  883. }
  884. if ($t = target_conflicts($target, $env->{installed})) {
  885. target_setstatus($target,'CONFLICT',4);
  886. push(@$clist,$target);
  887. print "# $target->{name} conflicts with ",vsn($t),"\n";
  888. return;
  889. }
  890. if ($t = target_conflicts($target, $env->{built})) {
  891. target_setstatus($target,'CONFLICT',4);
  892. push(@$clist,$target);
  893. print "# $target->{name} conflicts with ",vsn($t),"\n";
  894. return;
  895. }
  896. #
  897. # see if a target is already installed and requires a rebuild
  898. #
  899. if ($t = find_target($target->{name}, $env->{installed})) {
  900. if (exists $env->{exclude}->{$target->{name}}) {
  901. print "# excluding $target->{name} (no upgrade allowed)\n";
  902. return;
  903. }
  904. get_with($t);
  905. if ($target->{REBUILD}) {
  906. target_setstatus($target,'DEPEND',1);
  907. print "# rebuilding $target->{name} (dependency)\n";
  908. } elsif ($env->{zero}) {
  909. target_setstatus($target,'ZERO',1);
  910. print "# rebuilding $target->{name} (zero)\n";
  911. } elsif (target_newer($target, $env->{installed})) {
  912. target_setstatus($target,'UPGRADE',3);
  913. print "# rebuilding $target->{name} (upgrade)\n";
  914. } elsif (!target_suitable($t, $env->{with})) {
  915. target_setstatus($target,'MISMATCH',2);
  916. print "# rebuilding $target->{name} (parameter mismatch)\n";
  917. } else {
  918. print "# $target->{name} is already installed\n";
  919. return;
  920. }
  921. # use options from installed base
  922. override_options($target->{OPTIONS}, $t->{OPTIONS},
  923. $env->{config}->{optreg});
  924. # remember this is a rebuild for a proxy package
  925. $target->{PROXY} = $t->{PROXY};
  926. $target->{REBUILD} = 1;
  927. } else {
  928. target_setstatus($target,'ADD',3);
  929. }
  930. if (exists $env->{exclude}->{$target->{name}}) {
  931. die "FATAL: target ".vsn($target)." is forbidden\n";
  932. }
  933. # mark this as a target before reverse dependencies trigger
  934. # it again
  935. push(@{$env->{built}->{$target->{name}}->{vs($target)}}, $target);
  936. $d = target_depends($target, $env->{repository});
  937. $k = target_keeps($target, $env->{repository});
  938. #
  939. # recurse over dependencies
  940. #
  941. if (@$d || @$k) {
  942. %d = map { $_ => 1 } @$d, @$k;
  943. %k = map { $_ => 1 } @$k;
  944. @deps = ();
  945. $conflict = 0;
  946. foreach (keys %d) {
  947. # old index misses a OpenPKG provider in the index... skip it
  948. next if $_ eq 'OpenPKG';
  949. ($t,$old) = dep2target($_, $env);
  950. if ($t) {
  951. if ($old) {
  952. print "# $target->{name} uses ".vsn($t)." for $_\n";
  953. next;
  954. }
  955. # record which targets to keep in blist
  956. if ($k{$_}) {
  957. push @$blist,$t;
  958. print "# $target->{name} installs ".vsn($t)." for $_\n";
  959. } else {
  960. print "# $target->{name} requires ".vsn($t)." for $_\n";
  961. }
  962. push @deps, $t;
  963. } else {
  964. print "# $target->{name} searches a frood called '$_'\n";
  965. push(@{$env->{fatal}},vsn($target));
  966. target_setstatus($target,'UNDEF',4);
  967. push @$clist, $target;
  968. $conflict = 1;
  969. }
  970. }
  971. unless ($conflict) {
  972. foreach $t (@deps) {
  973. make_dep($t,$depth+1,$env,$list,$blist,$clist);
  974. }
  975. }
  976. }
  977. print "# adding ".vsn($target)." to list\n";
  978. push(@$list, $target);
  979. return if $conflict;
  980. if (!$env->{quick} &&
  981. $target->{name} ne 'openpkg' &&
  982. $target->{REBUILD}) {
  983. unless ($env->{revdep}) {
  984. $env->{revdep} = get_revdep($env);
  985. }
  986. foreach $t (@{$env->{revdep}->{$target->{name}}}) {
  987. # this is a rebuild, triggering further revdeps
  988. $t->{REBUILD} = 1;
  989. # this is a rebuild, keep this installed
  990. push(@$blist, $t);
  991. print "# rebuilding revdep ".vsn($t)."\n";
  992. make_dep($t,$depth+1,$env,$list,$blist,$clist);
  993. }
  994. }
  995. }
  996. sub remove_list ($$$) {
  997. my($targets, $keeps, $installed) = @_;
  998. my(%keep);
  999. %keep = map { $_ => 1 } @$keeps;
  1000. return [ grep {
  1001. !$keep{$_} && !$installed->{$_->{name}}->{vs($_)};
  1002. } @$targets
  1003. ];
  1004. }
  1005. sub build_list ($$) {
  1006. my($pattern, $env) = @_;
  1007. my(@goals,@targets,@keeps,@conflicts,$bonly,$t);
  1008. my($name,$r,$i,@vers);
  1009. my(@todo);
  1010. if (defined $pattern) {
  1011. @todo = ();
  1012. foreach (split(/\s+/,$pattern)) {
  1013. next unless /\S/;
  1014. if (s/\*+$//) {
  1015. push @todo, '^'.quotemeta($_).'';
  1016. } else {
  1017. push @todo, '^'.quotemeta($_).'$';
  1018. }
  1019. }
  1020. @todo = map {
  1021. my($p) = $_;
  1022. grep(/$p/, keys %{$env->{repository}})
  1023. } @todo;
  1024. } else {
  1025. @todo = grep {
  1026. my($n) = $_;
  1027. (ref $env->{installed}->{$n}) &&
  1028. grep { $_ ne '-' } keys %{$env->{installed}->{$n}}
  1029. } keys %{$env->{repository}};
  1030. }
  1031. #
  1032. # chose sources for goals from repository
  1033. #
  1034. foreach $name (@todo) {
  1035. $t = undef;
  1036. #
  1037. # keeping installed packages for goals is ugly
  1038. # -> we currently do not support installed source RPMs
  1039. # -> source RPMs might already have expired from repository
  1040. #
  1041. # consequence:
  1042. # -> goals are always upgraded to repository versions
  1043. #
  1044. #unless ($env->{upgrade}) {
  1045. # $i = $env->{installed}->{$name};
  1046. # if (@vers = get_versions($i, sub { 1; })) {
  1047. # $t = chose_source($env, $name, $i, @vers);
  1048. # }
  1049. #}
  1050. unless ($t) {
  1051. $r = $env->{repository}->{$name};
  1052. if (@vers = get_versions($r, sub { 1; })) {
  1053. $t = chose_source($env, $name, $r, @vers);
  1054. }
  1055. }
  1056. if ($t) {
  1057. warn_about_options($t, $env->{with}, $env->{config});
  1058. push(@goals, $t);
  1059. } else {
  1060. if ($env->{status}) {
  1061. print "# dropping goal '$name'\n";
  1062. } else {
  1063. die "FATAL: cannot find source for '$name'\n";
  1064. }
  1065. }
  1066. }
  1067. return unless @goals;
  1068. @targets = ();
  1069. @keeps = @goals;
  1070. foreach $t (@goals) {
  1071. print "# recursing over dependencies for ".vsn($t)."\n";
  1072. make_dep($t,0,$env,\@targets,\@keeps,\@conflicts);
  1073. }
  1074. $bonly = remove_list(\@targets, \@keeps, $env->{installed});
  1075. return (\@targets, $bonly, \@conflicts);
  1076. }
  1077. #######################################################################
  1078. sub target2rpm ($$) {
  1079. my($target,$c) = @_;
  1080. my($tmpl) = $c->{template};
  1081. my($popt) = $target->{PROXY} ? '+PROXY' : '';
  1082. $tmpl =~ s/%{NAME}/$target->{name}/;
  1083. $tmpl =~ s/%{VERSION}/$target->{version}/;
  1084. $tmpl =~ s/%{RELEASE}/$target->{release}$popt/;
  1085. return $c->{rpmdir}.'/'.$tmpl;
  1086. }
  1087. #######################################################################
  1088. sub binary_target ($$) {
  1089. my($t, $fn) = @_;
  1090. my(%target) = %$t;
  1091. get_with(\%target, $fn);
  1092. return \%target;
  1093. }
  1094. sub find_proxy ($$) {
  1095. my($t,$bpkg) = @_;
  1096. my(@l) = `$RPM_NPRIV -ql $t->{name}`;
  1097. my($link) = (grep { $_ =~ /\/\.prefix-$t->{name}$/ } @l)[0];
  1098. return unless defined $link;
  1099. chomp $link;
  1100. my($prefix) = readlink($link);
  1101. return unless defined $prefix;
  1102. $bpkg =~ s/.*\///;
  1103. $bpkg =~ s/\+PROXY(\.[^-]+-[^-]+)-[^-]+\.rpm$/$1-*.rpm/;
  1104. return (glob("$prefix/RPM/PKG/$bpkg"))[0];
  1105. }
  1106. sub make_defines ($$$) {
  1107. my($old, $new, $c) = @_;
  1108. my($with);
  1109. #
  1110. # override old parameters with new parameters
  1111. # drop new parameters that do not exist in old set
  1112. #
  1113. # if there is no old set at all (which happens if there
  1114. # is no template and no installed package), just use the
  1115. # new parameters and assume these are useful.
  1116. #
  1117. if ($old) {
  1118. $old = { %$old };
  1119. override_options($old, $new, $c->{optreg});
  1120. } else {
  1121. $old = $new;
  1122. }
  1123. #
  1124. # convert parameters to --define command line options
  1125. # skip parameter templates from index
  1126. #
  1127. $with = join(' ',map { "--define '$_ $old->{$_}'" }
  1128. grep { $old->{$_} !~ /^%/ } keys %$old);
  1129. $with = ' '.$with if $with ne '';
  1130. return $with;
  1131. }
  1132. sub print_list1 ($$$@$) {
  1133. my($list,$c,$uncond,$with,$ignore) = @_;
  1134. my($spkg,$bpkg,$ppkg);
  1135. my($opt);
  1136. my($cmd1, $cmd2, $mark);
  1137. $mark = '::::';
  1138. foreach (@$list) {
  1139. $spkg = $_->{href};
  1140. $bpkg = target2rpm($_, $c);
  1141. #
  1142. # rebuild binary package IF
  1143. #
  1144. # 'unconditional' option
  1145. # OR there is no binary package
  1146. # OR dependency check found that installed package is not suitable
  1147. # OR existing binary package doesn't satisfy wanted options
  1148. #
  1149. $cmd1 = undef;
  1150. if ($uncond || !-f $bpkg || $_->{REBUILD} ||
  1151. !target_suitable(binary_target($_, $bpkg),$with)) {
  1152. $opt = make_defines($_->{OPTIONS}, $with, $c);
  1153. #
  1154. # proxy packages are rebuilt from their maste
  1155. # hierachy
  1156. #
  1157. # someone preferred a binary from the repository
  1158. # just copy it to the local store
  1159. #
  1160. if ($_->{PROXY}) {
  1161. $ppkg = find_proxy($_,$bpkg) or
  1162. die "FATAL: proxy package ",vsn($_)," does not exist\n";
  1163. #
  1164. # rpm doesn't support additional parameters to the
  1165. # mkproxy script
  1166. # $cmd1 = "$RPM_NPRIV$opt --makeproxy $ppkg -- -o $bpkg";
  1167. #
  1168. $cmd1 = "( cd $c->{rpmdir} && $RPM_NPRIV$opt --makeproxy $ppkg )";
  1169. } elsif (defined $_->{platform}) {
  1170. $cmd1 = "$CURL -q -s -o $bpkg $spkg";
  1171. } else {
  1172. $cmd1 = "$RPM_NPRIV$opt --rebuild $spkg";
  1173. }
  1174. }
  1175. #
  1176. # if package exist force rpm to copy over new files
  1177. # better than erasing everything and losing configuration
  1178. # files
  1179. #
  1180. $opt = $_->{REBUILD} ? ' --force' : '';
  1181. $cmd2 = "$RPM_PRIV$opt -Uvh $bpkg";
  1182. if ($ignore) {
  1183. $cmd2 = "$cmd1 && \\\n$cmd2" if defined $cmd1;
  1184. } else {
  1185. if (defined $cmd1) {
  1186. $cmd2 = "$cmd1 || exit \$?\n$cmd2 || exit \$?"
  1187. } else {
  1188. $cmd2 = "$cmd2 || exit \$?";
  1189. }
  1190. }
  1191. print "echo $mark $spkg $mark\n$cmd2\necho $mark $spkg = \$? $mark\n";
  1192. }
  1193. }
  1194. sub print_list2 ($$) {
  1195. my($list,$c) = @_;
  1196. my($pkg);
  1197. foreach (@$list) {
  1198. $pkg = "$_->{name}-$_->{version}-$_->{release}";
  1199. print "$RPM_PRIV -e $pkg\n";
  1200. }
  1201. }
  1202. sub print_status ($$$$$) {
  1203. my($installed,$repository,$list,$bonly,$clist) = @_;
  1204. my(%bonly) = map { $_ => 1 } @$bonly;
  1205. my(%map,$n,@names,$t);
  1206. my($old,$tag,$new);
  1207. foreach (@$list, @$clist) {
  1208. $map{$_->{name}} = {
  1209. rel => "$_->{version}-$_->{release}",
  1210. status => $_->{STATUS}
  1211. };
  1212. }
  1213. foreach (@$bonly) {
  1214. $map{$_->{name}} = {
  1215. rel => "$_->{version}-$_->{release}",
  1216. status => 'TEMP'
  1217. };
  1218. }
  1219. @names = keys %map;
  1220. foreach $n (keys %$installed) {
  1221. next if exists $map{$n};
  1222. next unless grep { $_ ne '-' } keys %{$installed->{$n}};
  1223. $map{$n}->{'status'} = 'OK';
  1224. push @names,$n;
  1225. }
  1226. foreach $n (keys %$repository) {
  1227. next if exists $map{$n};
  1228. next unless grep { $_ ne '-' } keys %{$repository->{$n}};
  1229. $t = find_target($n, $repository);
  1230. $map{$n}->{'status'} = 'NEW';
  1231. $map{$n}->{'rel'} = vs($t);
  1232. push @names,$n;
  1233. }
  1234. foreach $n (sort @names) {
  1235. $old = join ',',
  1236. map { "$n-$_" }
  1237. sort
  1238. grep { $_ ne '-' }
  1239. keys %{$installed->{$n}};
  1240. $old = $n if $old eq '';
  1241. $tag = $map{$n}->{status};
  1242. $new = defined $map{$n}->{rel} ? " $n-$map{$n}->{rel}" : '';
  1243. printf "%-35s %-8s%s\n", $old, $tag, $new;
  1244. }
  1245. }
  1246. #######################################################################
  1247. my($config,$url,$repository,$installed,$env,$list,$bonly,$clist);
  1248. my($pattern,%with,%exclude);
  1249. if ($opt_a) {
  1250. $pattern = undef;
  1251. } else {
  1252. $pattern = join(' ', @ARGV);
  1253. }
  1254. if ($opt_A) {
  1255. $pattern = '*';
  1256. }
  1257. %with = map {
  1258. /([^\s=]+)(?:\=(\S+))?/
  1259. ? ($1 => (defined $2 ? $2 : 'yes'))
  1260. : ()
  1261. } split(/\s+/, $opt_D);
  1262. %exclude = map { $_ => 1 } split(/\s+/, $opt_E);
  1263. $config = get_config();
  1264. if (defined $opt_p) {
  1265. $config->{platform} = $opt_p;
  1266. }
  1267. if (defined $opt_r) {
  1268. $url = $opt_r;
  1269. $url .= '/' unless $url =~ /\/$/;
  1270. } else {
  1271. $url = get_release();
  1272. }
  1273. #
  1274. # if we read the index from a file we can no longer deduce
  1275. # repository paths from index paths. For now lets assume
  1276. # that everything is below SRC/ to be compatible with
  1277. # existing file indexes.
  1278. #
  1279. if (defined $opt_f && !defined $opt_r) {
  1280. $url .= 'SRC/';
  1281. }
  1282. $installed = $opt_Z ? {} : get_installed();
  1283. $repository = get_index($url.'00INDEX.rdf',$opt_f,\%with);
  1284. $env = {
  1285. config => $config,
  1286. installed => $installed,
  1287. repository => $repository,
  1288. built => {},
  1289. revdep => undef,
  1290. with => \%with,
  1291. exclude => \%exclude,
  1292. upgrade => ($opt_a || $opt_U),
  1293. zero => ($opt_z || $opt_Z),
  1294. quick => $opt_q,
  1295. status => ($opt_s || $opt_S),
  1296. fatal => [],
  1297. sourceonly => ($opt_u ||
  1298. $opt_U ||
  1299. $opt_z ||
  1300. $opt_Z ||
  1301. scalar(%with) > 0 )
  1302. };
  1303. ($list,$bonly,$clist) = build_list($pattern, $env);
  1304. die "FATAL: cannot find package\n" unless defined $list;
  1305. if ($opt_S) {
  1306. print_status($installed,$repository,$list,$bonly,$clist);
  1307. } elsif ($opt_s) {
  1308. print_status($installed,{},$list,$bonly,$clist);
  1309. } else {
  1310. if (@{$env->{fatal}}) {
  1311. die "FATAL errors occured while building:\n",
  1312. join (',', @{$env->{fatal}}),
  1313. "\n";
  1314. }
  1315. print_list1($list,$config,$opt_a || $opt_u || $opt_U,\%with,$opt_i);
  1316. print_list2($bonly,$config);
  1317. }