openpkg-build.pl 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519
  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. my($av,$ar) = $a =~ /^(.*?)(?:\-([\d\.]+))?$/;
  200. my($bv,$br) = $b =~ /^(.*?)(?:\-([\d\.]+))?$/;
  201. my($c);
  202. if ((defined $ar) && (defined $br)) {
  203. $c = release_cmp($ar,$br);
  204. return $c if $c;
  205. }
  206. if ((defined $av) && (defined $bv)) {
  207. $c = version_cmp($av,$bv);
  208. return $c if $c;
  209. }
  210. return 0;
  211. }
  212. sub vs ($) {
  213. my($t) = @_;
  214. return "$t->{version}-$t->{release}";
  215. }
  216. sub vsn ($) {
  217. my($t) = @_;
  218. return "$t->{name}-$t->{version}-$t->{release}";
  219. }
  220. ##########################################################################
  221. sub get_config ()
  222. {
  223. my($c,@q,@g);
  224. $c = `$RPM_NPRIV --eval '%{_rpmdir} %{_rpmfilename} %{_target_os} %{_target_cpu} %{_target_platform} %{_prefix}'`;
  225. chomp($c);
  226. (@q) = split(/\s+/,$c);
  227. $q[1] =~ s/%{OS}/$q[2]/;
  228. $q[1] =~ s/%{ARCH}/$q[3]/;
  229. $c = `$RPM_NPRIV --showrc`;
  230. @g = $c =~ /\%\{l_tool_locate\s+([^\s\}]+)/g;
  231. return {
  232. rpmdir => $q[0],
  233. template => $q[1],
  234. platform => $q[4],
  235. prefix => $q[5],
  236. optreg => '(?:'.join('|', map { "\Qwith_$_\E" } @g).')'
  237. };
  238. }
  239. sub get_release () {
  240. my($rel,$url);
  241. ($rel) =`$RPM_NPRIV -qi openpkg` =~ /Version:\s*(\S+)/m;
  242. if ($rel =~ /^\d+$/) {
  243. print "# $PROG current($rel)\n";
  244. print "# using '$RPM_NPRIV' (build) and '$RPM_PRIV' (install)\n";
  245. $url = "ftp://ftp.openpkg.org/current/";
  246. } elsif ($rel =~ /^(\d+\.\d+)/) {
  247. $rel = $1;
  248. print "# $PROG release($rel)\n";
  249. $url = "ftp://ftp.openpkg.org/release/$rel/";
  250. } else {
  251. die "FATAL: don't know how to handle this release\n";
  252. }
  253. return $url;
  254. }
  255. sub get_installed () {
  256. my(%map);
  257. my(@l) = `$RPM_NPRIV --provides -qa`;
  258. foreach (@l) {
  259. /^(\S+)\s*(?:=\s*([^\s\-]+)-([^\s\+]+)(\+PROXY)?)?$/;
  260. push(@{$map{$1}->{"$2-$3"}}, {
  261. name => $1,
  262. version => (defined $2 ? $2 : '*'),
  263. release => (defined $3 ? $3 : '*'),
  264. PROXY => $4
  265. });
  266. }
  267. return \%map;
  268. }
  269. sub revdep ($$$) {
  270. my($rev,$t,$name) = @_;
  271. return 1 if $name eq $t->{name};
  272. foreach (@{$rev->{$_}}) {
  273. return 1 if revdep($rev,$t,$_->{name});
  274. }
  275. return -1;
  276. }
  277. sub get_revdep ($) {
  278. my($env) = @_;
  279. my($i) = $env->{'installed'};
  280. my($r) = $env->{'repository'};
  281. my($pkg, %rev);
  282. my(@vers,$t,@names);
  283. print "# computing reverse dependencies\n";
  284. foreach $pkg (keys %$i) {
  285. unless ($r->{$pkg}) {
  286. print "# ATTENTION: $pkg has no upgrade path\n";
  287. next;
  288. }
  289. @vers = get_versions($r->{$pkg}, sub { 1; });
  290. foreach (@vers) {
  291. foreach $t (@{$r->{$pkg}->{$_}}) {
  292. next unless $i->{$t->{name}};
  293. next unless $t->{depends};
  294. @names = grep { $_ ne '' }
  295. map { /^(\S+)/ }
  296. @{$t->{depends}};
  297. next unless @names;
  298. push @{$rev{$_}}, $t foreach @names;
  299. }
  300. }
  301. }
  302. foreach $pkg (keys %rev) {
  303. $rev{$pkg} = [
  304. sort {
  305. revdep(\%rev, $b, $a->{name});
  306. } @{$rev{$pkg}}
  307. ];
  308. }
  309. return \%rev;
  310. }
  311. #
  312. # parse option from rpm output
  313. #
  314. sub parse_options ($) {
  315. my($l) = @_;
  316. $l = join("\n", @$l) if ref $l;
  317. return if ($l !~ m/(--define|%option\s+)/s);
  318. my $with = {};
  319. $l =~ s/--define\s*'(\S+)\s+(\S+?)'/$with->{$1} = $2, ''/sge; # before openpkg-20021230
  320. $l =~ s/%option\s+(\S+)\s+(\S+)/$with->{$1} = $2, ''/sge; # after openpkg-20021230
  321. return $with;
  322. }
  323. #
  324. # copy options from new to old
  325. # where option already exists in old or option key
  326. # matches regular expression
  327. #
  328. sub override_options ($$$) {
  329. my($old, $new, $reg) = @_;
  330. foreach my $k (keys %$new) {
  331. $old->{$k} = $new->{$k} if exists $old->{$k} || $k =~ /^$reg$/;
  332. }
  333. }
  334. sub get_with ($;$) {
  335. my($t,$fn) = @_;
  336. my(@l,%with);
  337. unless ($t->{OPTIONS}) {
  338. if (defined $fn) {
  339. @l = `$RPM_NPRIV -qi -p $fn`;
  340. } else {
  341. @l = `$RPM_NPRIV -qi $t->{name}`;
  342. }
  343. $t->{OPTIONS} = parse_options(\@l);
  344. }
  345. return $t->{OPTIONS};
  346. }
  347. sub relurl ($$$) {
  348. my($url,$fn,$suburl) = @_;
  349. my($subfn,$submap);
  350. unless ($suburl =~ /^\w+:\/\// || $suburl =~ /^\//) {
  351. if (defined $fn) {
  352. $subfn = $fn;
  353. $subfn =~ s/\/[^\/]*$//;
  354. $subfn .= '/' unless $subfn =~ /\/$/;
  355. $subfn .= $suburl;
  356. $suburl = $subfn;
  357. } else {
  358. $subfn = $url;
  359. $subfn =~ s/\/[^\/]*$//;
  360. $subfn .= '/' unless $subfn =~ /\/$/;
  361. $suburl = "$subfn$suburl";
  362. $subfn = undef;
  363. }
  364. }
  365. return ($suburl, $subfn);
  366. }
  367. sub xel($) {
  368. my($a) = @_;
  369. my($l) = $a->[0];
  370. return '' if ref $l;
  371. return $l;
  372. }
  373. sub get_index ($$$) {
  374. my($url,$fn,$with) = @_;
  375. my($ua,$req,$res,$rdf);
  376. my($bzip2,$path);
  377. my(%map,@include);
  378. my($fetch);
  379. $fetch = defined $fn ? $fn : $url;
  380. $bzip2 = $RPM;
  381. $bzip2 =~ s/bin\/rpm$/lib\/openpkg\/bzip2/
  382. or die "FATAL: cannot deduce bzip2 path from $RPM\n";
  383. $fetch !~ /\.bz2$/ || -x $bzip2
  384. or die "FATAL: $bzip2 not found\n";
  385. if ($fetch =~ /^\w+:/) { # looks like URL scheme
  386. print "# curling index $fetch\n";
  387. if ($fetch =~ /\.bz2$/) {
  388. $path = "$CURL -q -s -o - \"$fetch\" | $bzip2 -dc |";
  389. } else {
  390. $path = "$CURL -q -s -o - \"$fetch\" |";
  391. }
  392. } else {
  393. print "# reading index file $fn\n";
  394. if ($fetch =~ /\.bz2$/) {
  395. $path = "$bzip2 -dc $fetch |";
  396. } else {
  397. $path = "< $fetch";
  398. }
  399. }
  400. open(RFH, $path) or
  401. die "FATAL: cannot open '$fetch' ($!)\n";
  402. eval {
  403. require XML::Simple;
  404. };
  405. if ($@) {
  406. print "# using simple text parser\n";
  407. my($section);
  408. my($name,$version);
  409. my($href,$release,$desc);
  410. my(@prereq,@bprereq);
  411. my(@provides,@conflicts);
  412. my(%options);
  413. my($platform,$prefix);
  414. my($rec);
  415. my($tag,$cond,$body);
  416. my($useit);
  417. while (<RFH>) {
  418. s/&gt;/>/g;
  419. s/&lt;/</g;
  420. if (!(defined $href) && /<rdf:Description.*?href="([^"]*)"/) {
  421. $href = $1;
  422. $section = undef;
  423. $name = undef;
  424. $release = undef;
  425. $desc = '';
  426. $platform = undef;
  427. $prefix = undef;
  428. @prereq = ();
  429. @bprereq = ();
  430. @provides = ();
  431. @conflicts = ();
  432. %options = ();
  433. }
  434. if (!(defined $href) && /<Repository.*?href="([^"]*)"/) {
  435. push(@include, $1);
  436. next;
  437. }
  438. next unless defined $href;
  439. ($tag,$cond,$body) = /
  440. <
  441. (\/?[\w:]+)
  442. \s*
  443. (?:cond="([^"]+)")?
  444. >
  445. (.*?)
  446. (?:<\/\1>)?
  447. $
  448. /mx;
  449. $useit = conditional($cond,$with);
  450. if ($tag eq 'Description') {
  451. $section = 'description';
  452. } elsif ($tag eq '/Description') {
  453. $section = undef;
  454. } elsif ($section eq 'description') {
  455. $desc .= $_;
  456. } elsif ($tag eq 'Options') {
  457. $section = 'options' if $useit;
  458. } elsif ($tag eq '/Options') {
  459. $section = undef;
  460. } elsif ($tag eq 'PreReq') {
  461. $section = 'prereq' if $useit;
  462. } elsif ($tag eq '/PreReq') {
  463. $section = undef;
  464. } elsif ($tag eq 'BuildPreReq') {
  465. $section = 'bprereq' if $useit;
  466. } elsif ($tag eq '/BuildPreReq') {
  467. $section = undef;
  468. } elsif ($tag eq 'Provides') {
  469. $section = 'provides' if $useit;
  470. } elsif ($tag eq '/Provides') {
  471. $section = undef;
  472. } elsif ($tag eq 'Conflicts') {
  473. $section = 'conflicts' if $useit;
  474. } elsif ($tag eq '/Conflicts') {
  475. $section = undef;
  476. } elsif ($tag eq 'Name') {
  477. $name = $body;
  478. } elsif ($tag eq 'Version') {
  479. $version = $body;
  480. } elsif ($tag eq 'Release') {
  481. $release = $body;
  482. } elsif ($tag eq 'Platform') {
  483. $platform = $body;
  484. } elsif ($tag eq 'Prefixes') {
  485. $prefix = $body;
  486. } elsif ($tag eq 'rdf:li') {
  487. if ($section eq 'options') {
  488. if ($body =~ /<.*?ID="([^"]+)".*?>\s*([^<]+?)\s*</) {
  489. $options{$1} = $2;
  490. }
  491. } elsif ($section eq 'prereq') {
  492. push(@prereq, $body);
  493. } elsif ($section eq 'bprereq') {
  494. push(@bprereq, $body);
  495. } elsif ($section eq 'provides') {
  496. push(@provides, $body);
  497. } elsif ($section eq 'conflicts') {
  498. push(@conflicts, $body);
  499. }
  500. } elsif ($tag eq '/rdf:Description') {
  501. if (defined $href &&
  502. defined $name &&
  503. defined $version &&
  504. defined $release) {
  505. @provides = map {
  506. /(\S+)\s*(?:=\s*(\S+?)\-(\S+))?$/;
  507. {
  508. name => $1,
  509. version => $2,
  510. release => $3
  511. }
  512. } @provides;
  513. unless (grep($_->{name} eq $name, @provides)) {
  514. push(@provides, {
  515. name => $name,
  516. version => $version,
  517. release => $release
  518. });
  519. }
  520. $rec = {
  521. href => (relurl($url, undef, $href))[0],
  522. name => $name,
  523. version => $version,
  524. release => $release,
  525. depends => [ @bprereq ],
  526. keeps => [ @prereq ],
  527. conflicts => [ @conflicts ],
  528. desc => $desc,
  529. platform => $platform,
  530. prefix => $prefix
  531. };
  532. $rec->{OPTIONS} =
  533. %options
  534. ? \%options
  535. : parse_options($rec->{desc});
  536. foreach (@provides) {
  537. push(@{$map{$_->{name}}->{vs($_)}}, $rec);
  538. }
  539. }
  540. $href = undef;
  541. }
  542. }
  543. } else {
  544. print "# using XML parser\n";
  545. my($xml) = XML::Simple::XMLin(\*RFH, forcearray => 1);
  546. my($desc) = $xml->{'Repository'}->[0]->{'rdf:Description'};
  547. my($sub) = $xml->{'Repository'}->[0]->{'Repository'};
  548. my($provides,@provides,$rec);
  549. my($href,$name,$version,$release);
  550. foreach (@$desc) {
  551. $href = $_->{'href'};
  552. $name = xel($_->{'Name'});
  553. $version = xel($_->{'Version'});
  554. $release = xel($_->{'Release'});
  555. next unless defined $href &&
  556. defined $name &&
  557. defined $version &&
  558. defined $release;
  559. $provides = $_->{'Provides'}->[0]->{'rdf:bag'}->[0]->{'rdf:li'};
  560. @provides = map {
  561. /(\S+)\s*(?:=\s*(\S+?)\-(\S+))?$/;
  562. {
  563. name => $1,
  564. version => $2,
  565. release => $3
  566. }
  567. } @$provides;
  568. unless (grep($_->{name} eq $name, @provides)) {
  569. push(@provides, {
  570. name => $name,
  571. version => $version,
  572. release => $release
  573. });
  574. }
  575. $rec = {
  576. href => (relurl($url, undef, $href))[0],
  577. name => $name,
  578. version => $version,
  579. release => $release,
  580. platform => xel($_->{'Platform'}),
  581. prefix => xel($_->{'Prefixes'}),
  582. depends => with_list($_->{'BuildPreReq'}, $with),
  583. keeps => with_list($_->{'PreReq'}, $with),
  584. conflicts => with_list($_->{'Conflicts'}, $with),
  585. desc => xel($_->{'Description'})
  586. };
  587. $rec->{OPTIONS} =
  588. exists $_->{'Options'}
  589. ? make_hash($_->{'Options'}, 'Option', $with)
  590. : parse_options($rec->{desc});
  591. foreach (@provides) {
  592. push(@{$map{$_->{name}}->{vs($_)}}, $rec);
  593. }
  594. }
  595. if ($sub) {
  596. @include = map { $_->{href} } @$sub;
  597. }
  598. }
  599. close(RFH)
  600. or die "FATAL: an I/O error occured\n";
  601. #
  602. # cannot do real recursions on file handles, so we simply append
  603. # all sub-RDFs, the result is flattend into a big hash anyway
  604. #
  605. foreach (@include) {
  606. my($submap);
  607. my($suburl,$subfn) = relurl($url,$fn,$_);
  608. $submap = get_index($suburl,$subfn,$with);
  609. while (my($name,$vmap) = each %$submap) {
  610. while (my($vs,$recs) = each %$vmap) {
  611. push @{$map{$name}->{$vs}}, @$recs;
  612. }
  613. }
  614. }
  615. return \%map;
  616. }
  617. #
  618. # grep all versions of a name that
  619. # satisfy a condition
  620. #
  621. sub get_versions ($$) {
  622. my($relmap, $cond) = @_;
  623. return grep { $cond->($_); }
  624. sort { vcmp($a,$b); } keys %$relmap;
  625. }
  626. #
  627. # there can be multiple sources for a target release
  628. #
  629. sub chose_source ($$@) {
  630. my($env, $name, $vmap, @vers) = @_;
  631. my(@recs,@nrecs,$rec);
  632. return unless @vers;
  633. @recs = grep {
  634. $env->{sourceonly} ? (
  635. !(defined $_->{'platform'})
  636. ) : (
  637. !(defined $_->{'platform'}) || (
  638. defined $_->{'prefix'} &&
  639. $_->{'platform'} eq $env->{config}->{platform} &&
  640. $_->{'prefix'} eq $env->{config}->{prefix}
  641. )
  642. )
  643. } map { @{$vmap->{$_}} } @vers;
  644. return unless @recs;
  645. if (scalar(@recs) > 1) {
  646. @nrecs = grep {
  647. $env->{built}->{$_->{name}} ||
  648. $env->{installed}->{$_->{name}}
  649. } @recs;
  650. @recs = @nrecs if @nrecs;
  651. }
  652. if (scalar(@recs) > 1 && !$env->{sourceonly}) {
  653. @nrecs = grep {
  654. defined $_->{'platform'}
  655. } @recs;
  656. @recs = @nrecs if @nrecs;
  657. }
  658. if (scalar(@recs) > 1) {
  659. print "# ambigous sources for $name\n";
  660. my($i) = 0;
  661. foreach (@recs) {
  662. print "# $i: ".vsn($_)." = $_->{href}\n";
  663. $i++;
  664. }
  665. return;
  666. } else {
  667. if ($env->{upgrade}) {
  668. $rec = $recs[-1];
  669. } else {
  670. $rec = $recs[0];
  671. }
  672. }
  673. print "# source for $name is ".vsn($rec)."\n";
  674. return $rec;
  675. }
  676. #
  677. # see wether target is in map
  678. #
  679. sub target_exists ($$) {
  680. my($target, $map) = @_;
  681. my($vmap) = $map->{$target->{name}};
  682. return unless $vmap;
  683. return !defined $target->{version} ||
  684. defined $vmap->{vs($target)};
  685. }
  686. #
  687. # find target in map
  688. #
  689. sub find_target ($$) {
  690. my($name, $map) = @_;
  691. my($vmap) = $map->{$name};
  692. my(@vs);
  693. return unless $vmap;
  694. @vs = sort { vcmp($b,$a) } keys %$vmap;
  695. return $vmap->{$vs[0]}->[-1];
  696. }
  697. #
  698. # see wether target has conflicts in map
  699. #
  700. sub target_conflicts ($$) {
  701. my($target, $map) = @_;
  702. my($t);
  703. foreach (@{$target->{conflicts}}) {
  704. $t = find_target($_, $map);
  705. return $t if $t;
  706. }
  707. return;
  708. }
  709. #
  710. # retrieve build dependencies for target in map
  711. #
  712. sub target_depends ($$) {
  713. my($target, $map) = @_;
  714. my($vmap,$vers);
  715. die "FATAL: ",vsn($target)," not in depend map\n"
  716. unless
  717. ( $vmap = $map->{$target->{name}} ) &&
  718. ( defined $target->{version} ) &&
  719. ( $vers = $vmap->{vs($target)} ) &&
  720. @$vers;
  721. return $vers->[0]->{depends};
  722. }
  723. #
  724. # retrieve runtime dependencies for target in map
  725. #
  726. sub target_keeps ($$) {
  727. my($target, $map) = @_;
  728. my($vmap,$vers);
  729. die "FATAL: ",vsn($target)," not in keep map\n"
  730. unless
  731. ( $vmap = $map->{$target->{name}} ) &&
  732. ( defined $target->{version} ) &&
  733. ( $vers = $vmap->{vs($target)} ) &&
  734. @$vers;
  735. return $vers->[0]->{keeps};
  736. }
  737. #
  738. # test wether target could be upgraded
  739. #
  740. sub target_newer ($$) {
  741. my($target, $map) = @_;
  742. my($vs) = vs($target);
  743. my($vmap) = $map->{$target->{name}};
  744. return 1 unless $vmap;
  745. return !grep { vcmp($vs, $_) <= 0; } keys %$vmap;
  746. }
  747. #
  748. # check wether installed package matches
  749. # build options
  750. #
  751. sub target_suitable ($$) {
  752. my($target, $with) = @_;
  753. my($iwith);
  754. my($k,$v);
  755. $iwith = $target->{OPTIONS};
  756. while (($k,$v) = each %$with) {
  757. if (exists $iwith->{$k}) {
  758. return 0 if $iwith->{$k} ne $with->{$k};
  759. }
  760. }
  761. return 1;
  762. }
  763. #
  764. # record target status
  765. #
  766. sub target_setstatus ($$$) {
  767. my($target, $status, $pri) = @_;
  768. if ($pri > $target->{STATUSPRI}) {
  769. $target->{STATUSPRI} = $pri;
  770. $target->{STATUS} = $status;
  771. }
  772. }
  773. #
  774. # report options that are not used for
  775. #
  776. sub warn_about_options ($$$) {
  777. my($target, $with, $c) = @_;
  778. my($iwith) = $target->{OPTIONS};
  779. my($k,$v);
  780. return unless defined $iwith;
  781. while (($k,$v) = each %$with) {
  782. if (!exists $iwith->{$k} && $k !~ $c->{optreg}) {
  783. print "# ATTENTION: $target->{name} ignores option '$k'\n";
  784. }
  785. }
  786. }
  787. #
  788. # locate target for a dependency
  789. #
  790. sub dep2target ($$) {
  791. my($dep, $env) = @_;
  792. my($name,@vers);
  793. my($i,$r,$b,$cond,$version);
  794. my($t,$tdef);
  795. $dep =~ s/(\S+)\s*//;
  796. $name = $1;
  797. $i = $env->{installed}->{$name};
  798. $r = $env->{repository}->{$name};
  799. $b = $env->{built}->{$name};
  800. return unless $i || $r || $b;
  801. if ($dep =~ /^>=\s*(\S+)$/) {
  802. $version = $1;
  803. $cond = sub { vcmp($_[0],$version) >= 0; };
  804. } elsif ($dep =~ /^=\s*(\S+)$/) {
  805. $version = $1;
  806. $cond = sub { vcmp($_[0],$version) == 0; };
  807. } elsif ($dep =~ /^\s*$/) {
  808. $cond = sub { 1; };
  809. } else {
  810. print "# don't know how to handle PreReq: $name $dep\n";
  811. return;
  812. }
  813. $tdef = undef;
  814. if ($i && (@vers = get_versions($i, $cond))) {
  815. foreach (@vers) {
  816. $t = $i->{$_}->[0];
  817. if (get_with($t), target_suitable($t, $env->{with})) {
  818. $tdef = $t;
  819. if (!$env->{upgrade}) {
  820. return ($t, 1);
  821. }
  822. }
  823. }
  824. }
  825. if ($b && (@vers = get_versions($b, $cond))) {
  826. return ($b->{$vers[0]}->[0], 1);
  827. }
  828. $t = chose_source($env, $name, $r, get_versions($r, $cond));
  829. if ($t) {
  830. return ($t, 0);
  831. }
  832. if ($tdef) {
  833. return ($tdef, 1);
  834. }
  835. return;
  836. }
  837. sub make_dep ($$$$$$) {
  838. my($target,$depth,$env,$list,$blist,$clist) = @_;
  839. my($d,$k,%d,%k,$t,$old);
  840. my(@deps,$conflict);
  841. if (target_exists($target, $env->{built})) {
  842. print "# $target->{name} is already in list\n";
  843. return;
  844. }
  845. if ($t = target_conflicts($target, $env->{installed})) {
  846. target_setstatus($target,'CONFLICT',4);
  847. push(@$clist,$target);
  848. print "# $target->{name} conflicts with ",vsn($t),"\n";
  849. return;
  850. }
  851. if ($t = target_conflicts($target, $env->{built})) {
  852. target_setstatus($target,'CONFLICT',4);
  853. push(@$clist,$target);
  854. print "# $target->{name} conflicts with ",vsn($t),"\n";
  855. return;
  856. }
  857. #
  858. # see if a target is already installed and requires a rebuild
  859. #
  860. if ($t = find_target($target->{name}, $env->{installed})) {
  861. if (exists $env->{exclude}->{$target->{name}}) {
  862. print "# excluding $target->{name} (no upgrade allowed)\n";
  863. return;
  864. }
  865. get_with($t);
  866. if ($target->{REBUILD}) {
  867. target_setstatus($target,'DEPEND',1);
  868. print "# rebuilding $target->{name} (dependency)\n";
  869. } elsif ($env->{zero}) {
  870. target_setstatus($target,'ZERO',1);
  871. print "# rebuilding $target->{name} (zero)\n";
  872. } elsif (target_newer($target, $env->{installed})) {
  873. target_setstatus($target,'UPGRADE',3);
  874. print "# rebuilding $target->{name} (upgrade)\n";
  875. } elsif (!target_suitable($t, $env->{with})) {
  876. target_setstatus($target,'MISMATCH',2);
  877. print "# rebuilding $target->{name} (parameter mismatch)\n";
  878. } else {
  879. print "# $target->{name} is already installed\n";
  880. return;
  881. }
  882. # use options from installed base
  883. override_options($target->{OPTIONS}, $t->{OPTIONS},
  884. $env->{config}->{optreg});
  885. # remember this is a rebuild for a proxy package
  886. $target->{PROXY} = $t->{PROXY};
  887. $target->{REBUILD} = 1;
  888. } else {
  889. target_setstatus($target,'ADD',3);
  890. }
  891. if (exists $env->{exclude}->{$target->{name}}) {
  892. die "FATAL: target ".vsn($target)." is forbidden\n";
  893. }
  894. # mark this as a target before reverse dependencies trigger
  895. # it again
  896. push(@{$env->{built}->{$target->{name}}->{vs($target)}}, $target);
  897. $d = target_depends($target, $env->{repository});
  898. $k = target_keeps($target, $env->{repository});
  899. #
  900. # recurse over dependencies
  901. #
  902. if (@$d || @$k) {
  903. %d = map { $_ => 1 } @$d, @$k;
  904. %k = map { $_ => 1 } @$k;
  905. @deps = ();
  906. $conflict = 0;
  907. foreach (keys %d) {
  908. # old index misses a OpenPKG provider in the index... skip it
  909. next if $_ eq 'OpenPKG';
  910. ($t,$old) = dep2target($_, $env);
  911. if ($t) {
  912. if ($old) {
  913. print "# $target->{name} uses ".vsn($t)." for $_\n";
  914. next;
  915. }
  916. # record which targets to keep in blist
  917. if ($k{$_}) {
  918. push @$blist,$t;
  919. print "# $target->{name} installs ".vsn($t)." for $_\n";
  920. } else {
  921. print "# $target->{name} requires ".vsn($t)." for $_\n";
  922. }
  923. push @deps, $t;
  924. } else {
  925. print "# $target->{name} searches a frood called '$_'\n";
  926. push(@{$env->{fatal}},vsn($target));
  927. target_setstatus($target,'UNDEF',4);
  928. push @$clist, $target;
  929. $conflict = 1;
  930. }
  931. }
  932. unless ($conflict) {
  933. foreach $t (@deps) {
  934. make_dep($t,$depth+1,$env,$list,$blist,$clist);
  935. }
  936. }
  937. }
  938. print "# adding ".vsn($target)." to list\n";
  939. push(@$list, $target);
  940. return if $conflict;
  941. if (!$env->{quick} &&
  942. $target->{name} ne 'openpkg' &&
  943. $target->{REBUILD}) {
  944. unless ($env->{revdep}) {
  945. $env->{revdep} = get_revdep($env);
  946. }
  947. foreach $t (@{$env->{revdep}->{$target->{name}}}) {
  948. # this is a rebuild, triggering further revdeps
  949. $t->{REBUILD} = 1;
  950. # this is a rebuild, keep this installed
  951. push(@$blist, $t);
  952. print "# rebuilding revdep ".vsn($t)."\n";
  953. make_dep($t,$depth+1,$env,$list,$blist,$clist);
  954. }
  955. }
  956. }
  957. sub remove_list ($$$) {
  958. my($targets, $keeps, $installed) = @_;
  959. my(%keep);
  960. %keep = map { $_ => 1 } @$keeps;
  961. return [ grep {
  962. !$keep{$_} && !$installed->{$_->{name}}->{vs($_)};
  963. } @$targets
  964. ];
  965. }
  966. sub build_list ($$) {
  967. my($pattern, $env) = @_;
  968. my(@goals,@targets,@keeps,@conflicts,$bonly,$t);
  969. my($name,$r,$i,@vers);
  970. my(@todo);
  971. if (defined $pattern) {
  972. @todo = ();
  973. foreach (split(/\s+/,$pattern)) {
  974. next unless /\S/;
  975. if (s/\*+$//) {
  976. push @todo, '^'.quotemeta($_).'';
  977. } else {
  978. push @todo, '^'.quotemeta($_).'$';
  979. }
  980. }
  981. @todo = map {
  982. my($p) = $_;
  983. grep(/$p/, keys %{$env->{repository}})
  984. } @todo;
  985. } else {
  986. @todo = grep {
  987. my($n) = $_;
  988. (ref $env->{installed}->{$n}) &&
  989. grep { $_ ne '-' } keys %{$env->{installed}->{$n}}
  990. } keys %{$env->{repository}};
  991. }
  992. #
  993. # chose sources for goals from repository
  994. #
  995. foreach $name (@todo) {
  996. $t = undef;
  997. #
  998. # keeping installed packages for goals is ugly
  999. # -> we currently do not support installed source RPMs
  1000. # -> source RPMs might already have expired from repository
  1001. #
  1002. # consequence:
  1003. # -> goals are always upgraded to repository versions
  1004. #
  1005. #unless ($env->{upgrade}) {
  1006. # $i = $env->{installed}->{$name};
  1007. # if (@vers = get_versions($i, sub { 1; })) {
  1008. # $t = chose_source($env, $name, $i, @vers);
  1009. # }
  1010. #}
  1011. unless ($t) {
  1012. $r = $env->{repository}->{$name};
  1013. if (@vers = get_versions($r, sub { 1; })) {
  1014. $t = chose_source($env, $name, $r, @vers);
  1015. }
  1016. }
  1017. if ($t) {
  1018. warn_about_options($t, $env->{with}, $env->{config});
  1019. push(@goals, $t);
  1020. } else {
  1021. if ($env->{status}) {
  1022. print "# dropping goal '$name'\n";
  1023. } else {
  1024. die "FATAL: cannot find source for '$name'\n";
  1025. }
  1026. }
  1027. }
  1028. return unless @goals;
  1029. @targets = ();
  1030. @keeps = @goals;
  1031. foreach $t (@goals) {
  1032. print "# recursing over dependencies for ".vsn($t)."\n";
  1033. make_dep($t,0,$env,\@targets,\@keeps,\@conflicts);
  1034. }
  1035. $bonly = remove_list(\@targets, \@keeps, $env->{installed});
  1036. return (\@targets, $bonly, \@conflicts);
  1037. }
  1038. #######################################################################
  1039. sub target2rpm ($$) {
  1040. my($target,$c) = @_;
  1041. my($tmpl) = $c->{template};
  1042. my($popt) = $target->{PROXY} ? '+PROXY' : '';
  1043. $tmpl =~ s/%{NAME}/$target->{name}/;
  1044. $tmpl =~ s/%{VERSION}/$target->{version}/;
  1045. $tmpl =~ s/%{RELEASE}/$target->{release}$popt/;
  1046. return $c->{rpmdir}.'/'.$tmpl;
  1047. }
  1048. #######################################################################
  1049. sub binary_target ($$) {
  1050. my($t, $fn) = @_;
  1051. my(%target) = %$t;
  1052. get_with(\%target, $fn);
  1053. return \%target;
  1054. }
  1055. sub find_proxy ($$) {
  1056. my($t,$bpkg) = @_;
  1057. my(@l) = `$RPM_NPRIV -ql $t->{name}`;
  1058. my($link) = (grep { $_ =~ /\/\.prefix-$t->{name}$/ } @l)[0];
  1059. return unless defined $link;
  1060. chomp $link;
  1061. my($prefix) = readlink($link);
  1062. return unless defined $prefix;
  1063. $bpkg =~ s/.*\///;
  1064. $bpkg =~ s/\+PROXY(\.[^-]+-[^-]+)-[^-]+\.rpm$/$1-*.rpm/;
  1065. return (glob("$prefix/RPM/PKG/$bpkg"))[0];
  1066. }
  1067. sub make_defines ($$$) {
  1068. my($old, $new, $c) = @_;
  1069. my($with);
  1070. #
  1071. # override old parameters with new parameters
  1072. # drop new parameters that do not exist in old set
  1073. #
  1074. # if there is no old set at all (which happens if there
  1075. # is no template and no installed package), just use the
  1076. # new parameters and assume these are useful.
  1077. #
  1078. if ($old) {
  1079. $old = { %$old };
  1080. override_options($old, $new, $c->{optreg});
  1081. } else {
  1082. $old = $new;
  1083. }
  1084. #
  1085. # convert parameters to --define command line options
  1086. # skip parameter templates from index
  1087. #
  1088. $with = join(' ',map { "--define '$_ $old->{$_}'" }
  1089. grep { $old->{$_} !~ /^%/ } keys %$old);
  1090. $with = ' '.$with if $with ne '';
  1091. return $with;
  1092. }
  1093. sub print_list1 ($$$@$) {
  1094. my($list,$c,$uncond,$with,$ignore) = @_;
  1095. my($spkg,$bpkg,$ppkg);
  1096. my($opt);
  1097. my($cmd1, $cmd2, $mark);
  1098. $mark = '::::';
  1099. foreach (@$list) {
  1100. $spkg = $_->{href};
  1101. $bpkg = target2rpm($_, $c);
  1102. #
  1103. # rebuild binary package IF
  1104. #
  1105. # 'unconditional' option
  1106. # OR there is no binary package
  1107. # OR dependency check found that installed package is not suitable
  1108. # OR existing binary package doesn't satisfy wanted options
  1109. #
  1110. $cmd1 = undef;
  1111. if ($uncond || !-f $bpkg || $_->{REBUILD} ||
  1112. !target_suitable(binary_target($_, $bpkg),$with)) {
  1113. $opt = make_defines($_->{OPTIONS}, $with, $c);
  1114. #
  1115. # proxy packages are rebuilt from their maste
  1116. # hierachy
  1117. #
  1118. # someone preferred a binary from the repository
  1119. # just copy it to the local store
  1120. #
  1121. if ($_->{PROXY}) {
  1122. $ppkg = find_proxy($_,$bpkg) or
  1123. die "FATAL: proxy package ",vsn($_)," does not exist\n";
  1124. #
  1125. # rpm doesn't support additional parameters to the
  1126. # mkproxy script
  1127. # $cmd1 = "$RPM_NPRIV$opt --makeproxy $ppkg -- -o $bpkg";
  1128. #
  1129. $cmd1 = "( cd $c->{rpmdir} && $RPM_NPRIV$opt --makeproxy $ppkg )";
  1130. } elsif (defined $_->{platform}) {
  1131. $cmd1 = "$CURL -q -s -o $bpkg $spkg";
  1132. } else {
  1133. $cmd1 = "$RPM_NPRIV$opt --rebuild $spkg";
  1134. }
  1135. }
  1136. #
  1137. # if package exist force rpm to copy over new files
  1138. # better than erasing everything and losing configuration
  1139. # files
  1140. #
  1141. $opt = $_->{REBUILD} ? ' --force' : '';
  1142. $cmd2 = "$RPM_PRIV$opt -Uvh $bpkg";
  1143. if ($ignore) {
  1144. $cmd2 = "$cmd1 && \\\n$cmd2" if defined $cmd1;
  1145. } else {
  1146. if (defined $cmd1) {
  1147. $cmd2 = "$cmd1 || exit \$?\n$cmd2 || exit \$?"
  1148. } else {
  1149. $cmd2 = "$cmd2 || exit \$?";
  1150. }
  1151. }
  1152. print "echo $mark $spkg $mark\n$cmd2\necho $mark $spkg = \$? $mark\n";
  1153. }
  1154. }
  1155. sub print_list2 ($$) {
  1156. my($list,$c) = @_;
  1157. my($pkg);
  1158. foreach (@$list) {
  1159. $pkg = "$_->{name}-$_->{version}-$_->{release}";
  1160. print "$RPM_PRIV -e $pkg\n";
  1161. }
  1162. }
  1163. sub print_status ($$$$$) {
  1164. my($installed,$repository,$list,$bonly,$clist) = @_;
  1165. my(%bonly) = map { $_ => 1 } @$bonly;
  1166. my(%map,$n,@names,$t);
  1167. my($old,$tag,$new);
  1168. foreach (@$list, @$clist) {
  1169. $map{$_->{name}} = {
  1170. rel => "$_->{version}-$_->{release}",
  1171. status => $_->{STATUS}
  1172. };
  1173. }
  1174. foreach (@$bonly) {
  1175. $map{$_->{name}} = {
  1176. rel => "$_->{version}-$_->{release}",
  1177. status => 'TEMP'
  1178. };
  1179. }
  1180. @names = keys %map;
  1181. foreach $n (keys %$installed) {
  1182. next if exists $map{$n};
  1183. next unless grep { $_ ne '-' } keys %{$installed->{$n}};
  1184. $map{$n}->{'status'} = 'OK';
  1185. push @names,$n;
  1186. }
  1187. foreach $n (keys %$repository) {
  1188. next if exists $map{$n};
  1189. next unless grep { $_ ne '-' } keys %{$repository->{$n}};
  1190. $t = find_target($n, $repository);
  1191. $map{$n}->{'status'} = 'NEW';
  1192. $map{$n}->{'rel'} = vs($t);
  1193. push @names,$n;
  1194. }
  1195. foreach $n (sort @names) {
  1196. $old = join ',',
  1197. map { "$n-$_" }
  1198. sort
  1199. grep { $_ ne '-' }
  1200. keys %{$installed->{$n}};
  1201. $old = $n if $old eq '';
  1202. $tag = $map{$n}->{status};
  1203. $new = defined $map{$n}->{rel} ? " $n-$map{$n}->{rel}" : '';
  1204. printf "%-35s %-8s%s\n", $old, $tag, $new;
  1205. }
  1206. }
  1207. #######################################################################
  1208. my($config,$url,$repository,$installed,$env,$list,$bonly,$clist);
  1209. my($pattern,%with,%exclude);
  1210. if ($opt_a) {
  1211. $pattern = undef;
  1212. } else {
  1213. $pattern = join(' ', @ARGV);
  1214. }
  1215. if ($opt_A) {
  1216. $pattern = '*';
  1217. }
  1218. %with = map {
  1219. /([^\s=]+)(?:\=(\S+))?/
  1220. ? ($1 => (defined $2 ? $2 : 'yes'))
  1221. : ()
  1222. } split(/\s+/, $opt_D);
  1223. %exclude = map { $_ => 1 } split(/\s+/, $opt_E);
  1224. $config = get_config();
  1225. if (defined $opt_p) {
  1226. $config->{platform} = $opt_p;
  1227. }
  1228. if (defined $opt_r) {
  1229. $url = $opt_r;
  1230. $url .= '/' unless $url =~ /\/$/;
  1231. } else {
  1232. $url = get_release();
  1233. }
  1234. #
  1235. # if we read the index from a file we can no longer deduce
  1236. # repository paths from index paths. For now lets assume
  1237. # that everything is below SRC/ to be compatible with
  1238. # existing file indexes.
  1239. #
  1240. if (defined $opt_f && !defined $opt_r) {
  1241. $url .= 'SRC/';
  1242. }
  1243. $installed = $opt_Z ? {} : get_installed();
  1244. $repository = get_index($url.'00INDEX.rdf',$opt_f,\%with);
  1245. $env = {
  1246. config => $config,
  1247. installed => $installed,
  1248. repository => $repository,
  1249. built => {},
  1250. revdep => undef,
  1251. with => \%with,
  1252. exclude => \%exclude,
  1253. upgrade => ($opt_a || $opt_U),
  1254. zero => ($opt_z || $opt_Z),
  1255. quick => $opt_q,
  1256. status => ($opt_s || $opt_S),
  1257. fatal => [],
  1258. sourceonly => ($opt_u ||
  1259. $opt_U ||
  1260. $opt_z ||
  1261. $opt_Z ||
  1262. scalar(%with) > 0 )
  1263. };
  1264. ($list,$bonly,$clist) = build_list($pattern, $env);
  1265. die "FATAL: cannot find package\n" unless defined $list;
  1266. if ($opt_S) {
  1267. print_status($installed,$repository,$list,$bonly,$clist);
  1268. } elsif ($opt_s) {
  1269. print_status($installed,{},$list,$bonly,$clist);
  1270. } else {
  1271. if (@{$env->{fatal}}) {
  1272. die "FATAL errors occured while building:\n",
  1273. join (',', @{$env->{fatal}}),
  1274. "\n";
  1275. }
  1276. print_list1($list,$config,$opt_a || $opt_u || $opt_U,\%with,$opt_i);
  1277. print_list2($bonly,$config);
  1278. }