openpkg-build.pl 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313
  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/
  30. $opt_R $opt_r $opt_f $opt_u $opt_U $opt_a $opt_A
  31. $opt_z $opt_Z $opt_P $opt_N $opt_E $opt_i $opt_D
  32. $opt_p $opt_q $opt_s $opt_S $opt_X $opt_M $opt_L
  33. $opt_W $opt_K $opt_e $opt_b $opt_B $opt_g/;
  34. my $getopts = 'R:r:f:uUaAzZP:N:E:iD:p:qsSXMLWKebBg';
  35. getopts($getopts);
  36. ##########################################################################
  37. sub getopts ($) {
  38. my($opts) = @_;
  39. my(%optf) = map { /(\w)/; $1 => $_ } $opts =~ /(\w:|\w)/g;
  40. my(%opts,@argv,$optarg);
  41. foreach (@ARGV) {
  42. if (@argv) {
  43. push @argv, $_;
  44. } elsif (defined $optarg) {
  45. if (exists $opts{$optarg}) {
  46. $opts{$optarg} .= " $_";
  47. } else {
  48. $opts{$optarg} = $_;
  49. }
  50. $optarg = undef;
  51. } elsif (!/^[-]/) {
  52. push @argv, $_;
  53. } else {
  54. while (/^\-(\w)(.*)/) {
  55. if (exists $optf{$1}) {
  56. if (length($optf{$1}) > 1) {
  57. if ($2 ne '') {
  58. if (exists $opts{$1}) {
  59. $opts{$1} .= " $2";
  60. } else {
  61. $opts{$1} = $2;
  62. }
  63. } else {
  64. $optarg = $1;
  65. }
  66. last;
  67. } else {
  68. $opts{$1} = 1;
  69. }
  70. } else {
  71. warn "warning: unknown option $_\n";
  72. }
  73. $_ = "-$2";
  74. }
  75. }
  76. }
  77. if (defined $optarg) {
  78. warn "warning: option $optarg requires an argument\n";
  79. }
  80. foreach (keys %opts) {
  81. eval '$opt_'.$_.' = "'.quotemeta($opts{$_}).'";';
  82. }
  83. @ARGV = @argv;
  84. }
  85. my(%env) = ( '' => { } );
  86. if (open(FH, "< $ENV{'HOME'}/.openpkg/build")) {
  87. my($env) = $env{''};
  88. my($go) = $getopts;
  89. $go =~ s/[^a-zA-Z]//g;
  90. while (<FH>) {
  91. if (/^\s*\[([^\]]*)\]/) {
  92. $env{$1} = { } unless $env{$1};
  93. $env = $env{$1};
  94. } elsif (my($opt,$val) = /^\-([$go])\s*(.*?)\s*$/) {
  95. $val = 1 unless defined $val;
  96. if (exists $env->{$opt}) {
  97. $env->{$opt} .= " $val";
  98. } else {
  99. $env->{$opt} = $val;
  100. }
  101. }
  102. }
  103. close(FH);
  104. }
  105. die "openpkg:build:USAGE: $0 [-R rpm] [-r repository] [-f index.rdf] [-uUzZiqsSXMLWKebBg] [-P priv-cmd] [-N non-priv-cmd] [-p platform] [-Dwith ...] [-Ename ...] ( [-aA] | patternlist )\n"
  106. unless $#ARGV >= 0 || ($#ARGV == -1 && ($opt_a || $opt_A));
  107. ##########################################################################
  108. #
  109. # evaluate a condition attribute from an option set
  110. #
  111. sub conditional ($$) {
  112. my($cond,$with) = @_;
  113. my(@s,$res);
  114. return 1 if $cond eq '' || !defined $with;
  115. foreach (split(/\s+/,$cond)) {
  116. if ($_ eq '+') {
  117. die "FATAL: stack underflow in: $cond\n" if scalar(@s)<2;
  118. my($a) = pop @s;
  119. my($b) = pop @s;
  120. push @s, $a && $b;
  121. } elsif ($_ eq '|') {
  122. die "FATAL: stack underflow in: $cond\n" if scalar(@s)<2;
  123. my($a) = pop @s;
  124. my($b) = pop @s;
  125. push @s, $a || $b;
  126. } elsif ($_ eq '!') {
  127. die "FATAL: stack underflow in: $cond\n" if scalar(@s)<1;
  128. my($a) = pop @s;
  129. push @s, !$a;
  130. } else {
  131. push @s, ($with->{$_} eq 'yes') ? 1 : 0;
  132. }
  133. }
  134. die "FATAL: stack underflow in: $cond\n" if scalar(@s)<1;
  135. $res = pop @s;
  136. die "FATAL: stack not empty in: $cond\n" if scalar(@s)>0;
  137. return $res;
  138. }
  139. ##########################################################################
  140. my($RPM,$CURL,$PROG);
  141. $RPM = $opt_R || $env{''}->{'R'} || '@l_prefix@/bin/rpm';
  142. $RPM = (`which $RPM` =~ m{^(/.*)})[0] if ($RPM !~ m|^/|);
  143. die "FATAL: cannot locate rpm in path\n" unless $RPM =~ m{^/};
  144. # augment command line parameters
  145. foreach my $env (sort { $a cmp $b } grep { $RPM =~ /^\Q$_\E/ } keys %env) {
  146. while (my($opt,$val) = each %{$env{$env}}) {
  147. eval "\$opt_$opt = '$val' unless defined \$opt_$opt;";
  148. }
  149. }
  150. $CURL = $RPM;
  151. $CURL =~ s/\/bin\/rpm$/\/lib\/openpkg\/curl/
  152. or die "FATAL: cannot deduce curl path from $RPM\n";
  153. ($PROG) = $0 =~ /(?:.*\/)?(.*)/;
  154. sub cmd ($$) {
  155. my($w,$s) = @_;
  156. if (!defined $w) {
  157. return $s;
  158. } elsif ($w =~ /^-(.*)/) {
  159. return "$1 \"$s\"";
  160. } else {
  161. return "$w $s";
  162. }
  163. }
  164. sub priv ($) { cmd($opt_P,$_[0]); }
  165. sub npriv ($) { cmd($opt_N,$_[0]); }
  166. sub run ($) { my($c) = cmd($opt_N,$_[0]); `$c` }
  167. sub version_cmp ($$) {
  168. my($a,$b) = @_;
  169. my(@a,@b,$c);
  170. my($ax,$bx);
  171. @a = split(/\./, $a);
  172. @b = split(/\./, $b);
  173. while (@a && @b) {
  174. if ($a[0] =~ /^\d+$/ && $b[0] =~ /^\d+$/) {
  175. $c = $a[0] <=> $b[0];
  176. } elsif ((($a,$ax) = $a[0] =~ /^(\d+)(.*)$/) &&
  177. (($b,$bx) = $b[0] =~ /^(\d+)(.*)$/)) {
  178. $c = $a <=> $b;
  179. $c = $ax cmp $bx unless $c;
  180. } else {
  181. $c = $a[0] cmp $b[0];
  182. }
  183. return $c if $c;
  184. shift @a;
  185. shift @b;
  186. }
  187. $c = scalar(@a) <=> scalar(@b);
  188. return $c;
  189. }
  190. sub release_cmp ($$) {
  191. my($a,$b) = @_;
  192. return $a cmp $b;
  193. }
  194. sub vcmp ($$) {
  195. my($a,$b) = @_;
  196. return 0 if $a eq $b;
  197. my($av,$ar) = $a =~ /^(.*?)(?:\-([\d\.]+))?$/;
  198. my($bv,$br) = $b =~ /^(.*?)(?:\-([\d\.]+))?$/;
  199. my($c);
  200. if ((defined $ar) && (defined $br)) {
  201. $c = release_cmp($ar,$br);
  202. return $c if $c;
  203. }
  204. if ((defined $av) && (defined $bv)) {
  205. $c = version_cmp($av,$bv);
  206. return $c if $c;
  207. }
  208. return 0;
  209. }
  210. sub vs ($) {
  211. my($t) = @_;
  212. return defined $t->{release}
  213. ? "$t->{version}-$t->{release}"
  214. : $t->{version};
  215. }
  216. sub vsn ($) {
  217. my($t) = @_;
  218. return "$t->{name}-".vs($t);
  219. }
  220. ##########################################################################
  221. sub get_config ()
  222. {
  223. my($c,@q,@g);
  224. $c = run("$RPM --eval '%{_rpmdir} %{_rpmfilename} %{_target_os} %{_target_cpu} %{_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 = run("$RPM --showrc");
  230. @g = $c =~ /\%\{l_tool_locate\s+([^\s\}]+)/g;
  231. return {
  232. rpmdir => $q[0],
  233. template => $q[1],
  234. platform => '',
  235. prefix => $q[4],
  236. optreg => '(?:'.join('|', map { "\Quse_$_\E" } @g).')'
  237. };
  238. }
  239. sub get_release () {
  240. my($rel,$url);
  241. ($rel) = run("$RPM -qi openpkg") =~ /Version:\s*(\S+)/m;
  242. if ($rel =~ /^\d+$/) {
  243. print "# $PROG current($rel)\n";
  244. $url = "ftp://ftp.openpkg.org/current/";
  245. } elsif ($rel =~ /^(\d+\.\d+)/) {
  246. $rel = $1;
  247. print "# $PROG release($rel)\n";
  248. $url = "ftp://ftp.openpkg.org/release/$rel/";
  249. } else {
  250. die "FATAL: don't know how to handle this release\n";
  251. }
  252. return $url;
  253. }
  254. sub parse_provides ($) {
  255. my($s) = @_;
  256. my($nam,$val,$pre,$with,$pxy,$ver,$rel);
  257. ($nam,$val) = $s =~ /^(\S+)\s*(?:=\s*(\S*?))?$/;
  258. #
  259. # build options are encoded as a Requirement
  260. # <packagename>::<buildoption> = <value>
  261. #
  262. # since the value is interpreted as a version number
  263. # you can only do equality tests
  264. #
  265. if (($pre,$with) = $nam =~ /^(\S+?)::(\S*)$/) {
  266. $val =~ s/(?:\%([0-9a-fA-F][0-9a-fA-F]))/chr(hex($1))/eg;
  267. ($ver,$rel,$pxy) = ($val, undef, undef);
  268. } else {
  269. ($ver,$rel,$pxy) = $val =~ /^([^\s\-]+)-([^\s\+]+)(\+PROXY)?$/;
  270. }
  271. return {
  272. name => $nam, # the full name of the resource
  273. version => $ver, # the version (or value)
  274. release => $rel, # and release number
  275. proxy => $pxy, # wether the resource is a PROXY resource
  276. prefix => $pre, # the packagename (if resource is an option)
  277. with => $with # the buildoption (if resource is an option)
  278. };
  279. }
  280. sub parse_depends ($) {
  281. my($dep) = @_;
  282. my($name, $op, $val);
  283. if (ref $dep) {
  284. #
  285. # dependency from new index stored as a node
  286. #
  287. # content of the node is the name
  288. # certain attributes denote the comparison operator
  289. # the value of such an attribute is the comparison operand
  290. #
  291. # the operator (and operand) are optional and there can
  292. # only be one
  293. #
  294. $name = $dep->{content};
  295. $op = undef;
  296. $op = 'equ' if exists $dep->{equ};
  297. $op = 'geq' if exists $dep->{geq};
  298. $op = 'leq' if exists $dep->{leq};
  299. $op = 'gt' if exists $dep->{gt};
  300. $op = 'lt' if exists $dep->{lt};
  301. if (defined $op) {
  302. $val = $dep->{$op};
  303. }
  304. } elsif ($dep =~ /\S/) {
  305. #
  306. # dependency from old index stored as text string
  307. #
  308. # "name operator operand"
  309. # or
  310. # "name"
  311. #
  312. ($name,$op,$val) = $dep =~ /(\S+)\s*(?:(\S+)\s*(\S+))?\s*$/;
  313. if (defined $op) {
  314. $op = {
  315. '==' => 'equ', '=' => 'equ',
  316. '>=' => 'geq', '=>' => 'geq',
  317. '<=' => 'leq', '=<' => 'leq',
  318. '>' => 'gt', '<' => 'lt'
  319. }->{$op};
  320. unless (defined $op) {
  321. print "# don't know how to handle dependency: $dep\n";
  322. return;
  323. }
  324. }
  325. }
  326. return {
  327. name => $name,
  328. op => $op,
  329. val => $val
  330. };
  331. }
  332. sub depends2provides ($) {
  333. my($dep) = @_;
  334. my($ver,$rel,$pxy,$pre,$with);
  335. ($ver,$rel,$pxy) = $dep->{val} =~ /^([^\s\-]+)-([^\s\+]+)(\+PROXY)?$/;
  336. ($pre,$with) = $dep->{name} =~ /^(\S+?)::(\S*)$/;
  337. return {
  338. name => $dep->{name},
  339. version => (defined $ver ? $ver : $dep->{val}),
  340. release => $rel,
  341. proxy => $pxy,
  342. prefix => $pre,
  343. with => $with
  344. }
  345. }
  346. #
  347. # convert parser output to dependency records
  348. #
  349. sub depend_list ($) {
  350. my($dl) = @_;
  351. foreach (@$dl) {
  352. $_->{value} = parse_depends($_->{value});
  353. }
  354. return $dl;
  355. }
  356. #
  357. # compute list of package names from dependency list
  358. #
  359. sub depends2pkglist ($) {
  360. my($t) = @_;
  361. my(%d) = unique_map($t->{depends}, $t->{keeps});
  362. return (keys %d);
  363. }
  364. #
  365. # retrieve the local installed base
  366. #
  367. # for packages that provide option resources (packagename::buildoption)
  368. # the options are parsed into the OPTIONS hash
  369. #
  370. # other packages will query options on demand
  371. #
  372. sub get_installed () {
  373. my(%map);
  374. my(@l) = run("$RPM --provides -qa");
  375. my($p);
  376. my($nam,$val,%options);
  377. foreach (@l) {
  378. $p = parse_provides($_);
  379. if (defined $p->{with}) {
  380. $options{$p->{prefix}}->{$p->{with}} = $p->{version}
  381. }
  382. push @{$map{$p->{name}}->{vs($p)}}, {
  383. name => $p->{name},
  384. version => (defined $p->{version} ? $p->{version} : '*'),
  385. release => (defined $p->{release} ? $p->{release} : '*'),
  386. PROXY => $p->{proxy}
  387. };
  388. }
  389. #
  390. # options are provided for a package
  391. # apply them to all instances of the package
  392. #
  393. foreach $nam (keys %options) {
  394. foreach $val (keys %{$map{$nam}}) {
  395. foreach (@{$map{$nam}->{$val}}) {
  396. $_->{OPTIONS} = $options{$nam};
  397. }
  398. }
  399. }
  400. return \%map;
  401. }
  402. #
  403. # compute reverse dependency map
  404. #
  405. #
  406. sub get_revdep ($$) {
  407. my($env, $i) = @_;
  408. my($r) = $env->{'repository'};
  409. my($pkg, %dep, %dlist, %rev);
  410. my(@vers,$t);
  411. print "# computing reverse dependencies\n";
  412. foreach $pkg (keys %$i) {
  413. unless ($r->{$pkg}) {
  414. print "# ATTENTION: $pkg has no upgrade path\n";
  415. next;
  416. }
  417. #
  418. # get list of package versions from repository
  419. #
  420. @vers = get_versions($r->{$pkg}, sub { 1; });
  421. #
  422. # get forward dependencies from repository packages
  423. #
  424. # dep{a}{b} is true if b depends directly on a
  425. # dlist{a} is list of packages that depend on a
  426. #
  427. foreach (@vers) {
  428. foreach $t (@{$r->{$pkg}->{$_}}) {
  429. next unless $i->{$t->{name}};
  430. next unless $t->{depends} || $t->{keeps};
  431. foreach (depends2pkglist($t)) {
  432. unless ($dep{$_}{$t->{name}}) {
  433. $dep{$_}{$t->{name}} = 1;
  434. push @{$dlist{$_}}, $t;
  435. }
  436. }
  437. }
  438. }
  439. }
  440. #
  441. # sort reverse dependencies
  442. #
  443. foreach $pkg (keys %dep) {
  444. $rev{$pkg} = [
  445. sort {
  446. $dep{$b->{name}}{$a->{name}} ||
  447. -$dep{$a->{name}}{$b->{name}} ||
  448. $a->{name} cmp $b->{name}
  449. } @{$dlist{$pkg}}
  450. ];
  451. }
  452. return \%rev;
  453. }
  454. #
  455. # parse option from rpm output
  456. #
  457. sub parse_options ($) {
  458. my($l) = @_;
  459. $l = join("\n", @$l) if ref $l;
  460. return {} if ($l !~ m/(--define|\%option\s+)/s);
  461. my $with = {};
  462. $l =~ s/--define\s*'(\S+)\s+(\S+?)'/$with->{$1} = $2, ''/sge; # before openpkg-20021230
  463. $l =~ s/\%option\s+(\S+)\s+(\S+)/$with->{$1} = $2, ''/sge; # after openpkg-20021230
  464. return $with;
  465. }
  466. #
  467. # parse option from rpm provides list
  468. #
  469. sub parse_provideslist ($) {
  470. my($l) = @_;
  471. my($p);
  472. my($nam,$val,%opts);
  473. foreach (@$l) {
  474. $p = parse_provides($_);
  475. next unless defined $p->{with} && defined $p->{prefix};
  476. $opts{$p->{with}} = $p->{version}
  477. }
  478. return \%opts;
  479. }
  480. #
  481. # copy options from new to old
  482. # where option already exists in old or option key
  483. # matches regular expression
  484. #
  485. sub override_options ($$$) {
  486. my($old, $new, $reg) = @_;
  487. foreach my $k (keys %$new) {
  488. if ((exists $old->{$k} && $old->{$k} ne $new->{$k}) || $k =~ /^$reg$/) {
  489. $old->{$k} = $new->{$k};
  490. }
  491. }
  492. }
  493. #
  494. # pull in OPTIONS for a package or an RPM file
  495. #
  496. sub get_with ($;$) {
  497. my($t,$fn) = @_;
  498. my(@l,%with);
  499. my($optmap,$opt);
  500. if ($t->{OPTIONS}) {
  501. $opt = $t->{OPTIONS};
  502. } else {
  503. if (defined $fn) {
  504. @l = run("$RPM -q --provides -p $fn");
  505. } else {
  506. @l = run("$RPM -q --provides $t->{name}");
  507. }
  508. $opt = parse_provideslist(\@l);
  509. if (scalar(keys %$opt) == 0) {
  510. if (defined $fn) {
  511. @l = run("$RPM -qi -p $fn");
  512. } else {
  513. @l = run("$RPM -qi $t->{name}");
  514. }
  515. $opt = parse_options(\@l);
  516. }
  517. $t->{OPTIONS} = $opt;
  518. }
  519. return $opt;
  520. }
  521. #
  522. # compute absolute paths
  523. #
  524. # (url, fn) point to a base document
  525. # the location is the file path fn if fn is
  526. # defined, otherwise it is url.
  527. #
  528. # augment the pointer with suburl
  529. #
  530. # suburl can be an absolute url
  531. # then the new pointer is (suburl, undef)
  532. #
  533. # suburl can be a absolute file path
  534. # then the new pointer is (suburl, suburl)
  535. #
  536. # suburl can be a relative path
  537. # then it augments url or fn accordingly
  538. #
  539. sub relurl ($$$) {
  540. my($url,$fn,$suburl) = @_;
  541. my($subfn);
  542. if ($suburl =~ /^\w+:\/\//) {
  543. # NOP
  544. } elsif ($suburl =~ /^\//) {
  545. $subfn = $suburl;
  546. } else {
  547. if (defined $fn) {
  548. $subfn = $fn;
  549. $subfn =~ s/(\/)?\/*[^\/]*$/$1$suburl/;
  550. $suburl = $subfn;
  551. } else {
  552. $subfn = $url;
  553. $subfn =~ s/(\/)?\/*[^\/]*$/$1$suburl/;
  554. $suburl = $subfn;
  555. $subfn = undef;
  556. }
  557. }
  558. return ($suburl, $subfn);
  559. }
  560. #
  561. # return node value from XML parser
  562. #
  563. sub xel($) {
  564. my($a) = @_;
  565. my($l) = $a->[0];
  566. return '' if ref $l;
  567. return $l;
  568. }
  569. #
  570. # convert conditional XML Bag into flat list
  571. #
  572. sub xwith ($) {
  573. my($bags) = @_;
  574. my($bag,$li,$el);
  575. my(@out);
  576. foreach $bag (@$bags) {
  577. foreach $li (@{$bag->{'rdf:bag'}}) {
  578. $el = $li->{'resource'} || $li->{'rdf:li'};
  579. foreach (@$el) {
  580. push @out, {
  581. cond => $bag->{'cond'},
  582. value => $_
  583. };
  584. }
  585. }
  586. }
  587. return \@out;
  588. }
  589. #
  590. # convert simple parser Bag into flat list
  591. #
  592. sub swith ($$) {
  593. my($bags,$name) = @_;
  594. my($cond);
  595. my(@out);
  596. foreach $cond (keys %$bags) {
  597. foreach (@{$bags->{$cond}->{$name}}) {
  598. push @out, {
  599. cond => $cond,
  600. value => $_
  601. };
  602. }
  603. }
  604. return \@out;
  605. }
  606. sub goodpf ($$) {
  607. my($l,$p) = @_;
  608. return 1 if $l eq '';
  609. return $l =~ /(?:^|\s)\Q$p\E(?:\s|$)/;
  610. }
  611. sub simple_text_parser ($$$$$) {
  612. my($fh,$url,$map,$pfmatch,$installed) = @_;
  613. my(@include);
  614. my($section);
  615. my($name,$version);
  616. my($href,$release,$desc,$bags);
  617. my(%options,@provides);
  618. my($platform,$prefix);
  619. my($rec);
  620. my($tag,$cond,$attrname,$attrval,$body);
  621. my($usecond);
  622. my($options);
  623. print "# using simple text parser\n";
  624. while (<$fh>) {
  625. s/&gt;/>/g;
  626. s/&lt;/</g;
  627. if (!(defined $href) && /<rdf:Description.*?href="([^"]*)"/) {
  628. $href = $1;
  629. $section = undef;
  630. $name = undef;
  631. $release = undef;
  632. $desc = '';
  633. $platform = undef;
  634. $prefix = undef;
  635. $bags = {};
  636. @provides = ();
  637. }
  638. if (!(defined $href) &&
  639. /<Repository.*?href="([^"]*)"(?:\s*platform="([^"]*)")?/
  640. ) {
  641. if (goodpf($2,$pfmatch)) {
  642. push(@include, $1)
  643. }
  644. next;
  645. }
  646. next unless defined $href;
  647. ($tag,$cond,$attrname,$attrval,$body) = m{
  648. <
  649. (\/?[\w:]+)
  650. \s*
  651. (?:cond="([^"]+)")?
  652. (?:(\w+)="([^"]+)")?
  653. >
  654. (.*?)
  655. (?:<\/\1>)?
  656. $
  657. }mx;
  658. if ($tag eq 'Description') {
  659. $usecond = $cond;
  660. $section = 'description';
  661. } elsif ($tag eq '/Description') {
  662. $usecond = $cond;
  663. $section = undef;
  664. } elsif ($section eq 'description') {
  665. $desc .= $_;
  666. } elsif ($tag eq 'PreReq') {
  667. $usecond = $cond;
  668. $section = 'prereq';
  669. } elsif ($tag eq '/PreReq') {
  670. $usecond = undef;
  671. $section = undef;
  672. } elsif ($tag eq 'BuildPreReq') {
  673. $usecond = $cond;
  674. $section = 'bprereq';
  675. } elsif ($tag eq '/BuildPreReq') {
  676. $usecond = undef;
  677. $section = undef;
  678. } elsif ($tag eq 'Provides') {
  679. $usecond = $cond;
  680. $section = 'provides';
  681. } elsif ($tag eq '/Provides') {
  682. $usecond = undef;
  683. $section = undef;
  684. } elsif ($tag eq 'Conflicts') {
  685. $usecond = $cond;
  686. $section = 'conflicts';
  687. } elsif ($tag eq '/Conflicts') {
  688. $usecond = undef;
  689. $section = undef;
  690. } elsif ($tag eq 'NoSource') {
  691. $usecond = $cond;
  692. $section = 'nosource';
  693. } elsif ($tag eq '/NoSource') {
  694. $usecond = undef;
  695. $section = undef;
  696. } elsif ($tag eq 'Source') {
  697. $usecond = $cond;
  698. $section = 'source';
  699. } elsif ($tag eq '/Source') {
  700. $usecond = undef;
  701. $section = undef;
  702. } elsif ($tag eq 'Name') {
  703. $name = $body;
  704. } elsif ($tag eq 'Version') {
  705. $version = $body;
  706. } elsif ($tag eq 'Release') {
  707. $release = $body;
  708. } elsif ($tag eq 'Platform') {
  709. $platform = $body;
  710. } elsif ($tag eq 'Prefixes') {
  711. $prefix = $body;
  712. } elsif ($tag eq 'rdf:li' || $tag eq 'resource') {
  713. if (defined $attrname) {
  714. $body = {
  715. $attrname => $attrval,
  716. content => $body
  717. };
  718. }
  719. if ($section eq 'provides') {
  720. push @provides, $body;
  721. } elsif ($section ne '') {
  722. push @{$bags->{"$usecond"}->{$section}}, $body;
  723. }
  724. } elsif ($tag eq '/rdf:Description') {
  725. if (defined $href &&
  726. defined $name &&
  727. defined $version &&
  728. defined $release) {
  729. @provides = map {
  730. depends2provides(parse_depends($_))
  731. } @provides;
  732. %options = map {
  733. ( $_->{with} => $_->{version} )
  734. } grep {
  735. defined $_->{with}
  736. } @provides;
  737. push(@provides, {
  738. name => $name,
  739. version => $version,
  740. release => $release
  741. });
  742. $options = %options
  743. ? { %options }
  744. : parse_options($desc);
  745. if ($options) {
  746. my(@t) = get_targets($installed->{$name},sub { 1; });
  747. }
  748. eval {
  749. $rec = {
  750. href => (relurl($url, undef, $href))[0],
  751. name => $name,
  752. version => $version,
  753. release => $release,
  754. depends => depend_list(swith($bags,'bprereq')),
  755. keeps => depend_list(swith($bags,'prereq')),
  756. conflicts => swith($bags,'conflicts'),
  757. source => swith($bags,'source'),
  758. nosource => swith($bags,'nosource'),
  759. desc => $desc,
  760. platform => $platform,
  761. prefix => $prefix,
  762. OPTIONS => $options,
  763. DEFOPTS => { %$options }
  764. };
  765. };
  766. if ($@) {
  767. die "ERROR: when reading entry '$name'\n".$@;
  768. }
  769. foreach (@provides) {
  770. push(@{$map->{$_->{name}}->{vs($_)}}, $rec);
  771. }
  772. }
  773. $href = undef;
  774. }
  775. }
  776. return \@include;
  777. }
  778. sub xml_parser ($$$$$) {
  779. my($fh, $url, $map, $pfmatch, $installed) = @_;
  780. my(@include);
  781. my($xml,$rep,$sub);
  782. my($provides,@provides,%options,$rec);
  783. my($href,$name,$version,$release,$desc);
  784. my($options);
  785. print "# using XML parser\n";
  786. $xml = XML::Simple::XMLin($fh, forcearray => 1);
  787. $rep = $xml->{'Repository'}->[0]->{'rdf:Description'};
  788. $sub = $xml->{'Repository'}->[0]->{'Repository'};
  789. foreach (@$rep) {
  790. $href = $_->{'href'};
  791. $name = xel($_->{'Name'});
  792. $version = xel($_->{'Version'});
  793. $release = xel($_->{'Release'});
  794. next unless defined $href &&
  795. defined $name &&
  796. defined $version &&
  797. defined $release;
  798. $provides = $_->{'Provides'}->[0]->{'rdf:bag'}->[0];
  799. if ($provides->{'rdf:li'}) {
  800. $provides = $provides->{'rdf:li'};
  801. } else {
  802. $provides = $provides->{'resource'};
  803. }
  804. @provides = map {
  805. depends2provides(parse_depends($_))
  806. } @$provides;
  807. %options = map {
  808. ( $_->{with} => $_->{version} )
  809. } grep {
  810. defined $_->{with}
  811. } @provides;
  812. push(@provides, {
  813. name => $name,
  814. version => $version,
  815. release => $release
  816. });
  817. $desc = xel($_->{'Description'});
  818. $options = %options
  819. ? { %options }
  820. : parse_options($desc);
  821. if ($options) {
  822. my(@t) = get_targets($installed->{$name},sub { 1; });
  823. }
  824. eval {
  825. $rec = {
  826. href => (relurl($url, undef, $href))[0],
  827. name => $name,
  828. version => $version,
  829. release => $release,
  830. platform => xel($_->{'Platform'}),
  831. prefix => xel($_->{'Prefixes'}),
  832. depends => depend_list(xwith($_->{'BuildPreReq'})),
  833. keeps => depend_list(xwith($_->{'PreReq'})),
  834. conflicts => xwith($_->{'Conflicts'}),
  835. source => xwith($_->{'Source'}),
  836. nosource => xwith($_->{'NoSource'}),
  837. desc => $desc,
  838. OPTIONS => $options,
  839. DEFOPTS => { %$options }
  840. };
  841. };
  842. if ($@) {
  843. die "ERROR: when reading entry '$name'\n".$@;
  844. }
  845. foreach (@provides) {
  846. push(@{$map->{$_->{name}}->{vs($_)}}, $rec);
  847. }
  848. }
  849. if ($sub) {
  850. @include = map {
  851. goodpf($_->{platform},$pfmatch)
  852. ? ( $_->{href} )
  853. : ( )
  854. } @$sub;
  855. }
  856. return \@include;
  857. }
  858. sub open_index ($$) {
  859. my($url, $fn) = @_;
  860. my($fetch,$bzip2,$path);
  861. $fetch = defined $fn ? $fn : $url;
  862. $bzip2 = $RPM;
  863. $bzip2 =~ s/bin\/rpm$/lib\/openpkg\/bzip2/
  864. or die "FATAL: cannot deduce bzip2 path from $RPM\n";
  865. $fetch !~ /\.bz2$/ || -x $bzip2
  866. or die "FATAL: $bzip2 not found\n";
  867. if ($fetch =~ /^\w+:/) { # looks like URL scheme
  868. print "# curling index $fetch\n";
  869. if ($fetch =~ /\.bz2$/) {
  870. $path = "$CURL -q -s -o - \"$fetch\" | $bzip2 -dc |";
  871. } else {
  872. $path = "$CURL -q -s -o - \"$fetch\" |";
  873. }
  874. } else {
  875. print "# reading index file $fn\n";
  876. if ($fetch =~ /\.bz2$/) {
  877. $path = "$bzip2 -dc $fetch |";
  878. } else {
  879. $path = "< $fetch";
  880. }
  881. }
  882. open(RFH, $path) or
  883. die "FATAL: cannot open '$fetch' ($!)\n";
  884. }
  885. #
  886. # fetch index from file or URL
  887. # recursively fetch sub-indexes
  888. #
  889. sub get_index ($$$$$) {
  890. my($url,$fn,$noxml,$pfmatch,$installed) = @_;
  891. my(%map,$include);
  892. my($parser);
  893. open_index($url,$fn);
  894. unless ($noxml) {
  895. eval {
  896. require XML::Simple;
  897. };
  898. $noxml = 1 if $@;
  899. }
  900. $parser = $noxml ? \&simple_text_parser : \&xml_parser;
  901. $include = $parser->(\*RFH, $url, \%map, $pfmatch, $installed);
  902. close(RFH)
  903. or die "FATAL: an I/O error occured\n";
  904. #
  905. # cannot do real recursions on file handles, so we simply append
  906. # all sub-RDFs, the result is flattend into a big hash anyway
  907. #
  908. foreach (@$include) {
  909. my($submap);
  910. my($suburl,$subfn) = relurl($url,$fn,$_);
  911. $submap = get_index($suburl,$subfn,$noxml,$pfmatch,$installed);
  912. while (my($name,$vmap) = each %$submap) {
  913. while (my($vs,$recs) = each %$vmap) {
  914. push @{$map{$name}->{$vs}}, @$recs;
  915. }
  916. }
  917. }
  918. return \%map;
  919. }
  920. ############################################################################
  921. #
  922. # grep all versions of a name that
  923. # satisfy a condition
  924. #
  925. sub get_versions ($$) {
  926. my($relmap, $cond) = @_;
  927. return grep { $cond->($_); }
  928. sort { vcmp($a,$b); } keys %$relmap;
  929. }
  930. #
  931. # fetch targets of a name that
  932. # satisfies a condition
  933. #
  934. sub get_targets ($$) {
  935. my($relmap, $cond) = @_;
  936. return map {
  937. @{$relmap->{$_}}
  938. } get_versions($relmap, $cond);
  939. }
  940. #
  941. # check if target record describes a source package
  942. #
  943. sub is_source ($) {
  944. my($t) = @_;
  945. return !(defined $t->{'prefix'});
  946. }
  947. #
  948. # there can be multiple sources for a target release
  949. #
  950. sub chose_source ($$$$$) {
  951. my($env, $name, $select, $vmap, $cond) = @_;
  952. my(@vers,@recs,@nrecs,$rec,%nam);
  953. @vers = get_versions($vmap, sub { 1; });
  954. return unless @vers;
  955. @recs = map { $_->[1] } grep {
  956. my($v,$t) = @$_;
  957. is_source($t) ||
  958. ( !$env->{sourceonly} &&
  959. $t->{'platform'} eq $env->{config}->{platform} &&
  960. $t->{'prefix'} eq $env->{config}->{prefix} &&
  961. $cond->($v)
  962. )
  963. } map {
  964. my($v) = $_;
  965. my($l) = $vmap->{$_};
  966. map { [ $v, $_ ] } @$l;
  967. } @vers;
  968. return unless @recs;
  969. if (defined $select) {
  970. @recs = grep {
  971. vsn($_) =~ /^\Q$select\E/
  972. } @recs;
  973. }
  974. if (scalar(@recs) > 1) {
  975. @nrecs = grep {
  976. $env->{built}->{$_->{name}} ||
  977. $env->{installed}->{$_->{name}}
  978. } @recs;
  979. @recs = @nrecs if @nrecs;
  980. }
  981. if (scalar(@recs) > 1) {
  982. @nrecs = grep {
  983. $name eq $_->{name}
  984. } @recs;
  985. @recs = @nrecs if @nrecs;
  986. }
  987. if (scalar(@recs) > 1 && !$env->{sourceonly}) {
  988. @nrecs = grep {
  989. defined $_->{'platform'}
  990. } @recs;
  991. @recs = @nrecs if @nrecs;
  992. }
  993. if (scalar(@recs) > 1) {
  994. %nam = map { $_->{name} => 1 } @recs;
  995. if (scalar(keys %nam) > 1) {
  996. print "# ambigous sources for $name\n";
  997. my($i) = 0;
  998. foreach (@recs) {
  999. print "# $i: ".vsn($_)." = $_->{href}\n";
  1000. $i++;
  1001. }
  1002. return;
  1003. }
  1004. }
  1005. if (scalar(@recs) == 0) {
  1006. return;
  1007. }
  1008. $rec = $recs[-1];
  1009. print "# source for $name is ".vsn($rec)."\n";
  1010. return $rec;
  1011. }
  1012. #
  1013. # see wether target is in map
  1014. #
  1015. sub target_exists ($$) {
  1016. my($target, $map) = @_;
  1017. my($vmap) = $map->{$target->{name}};
  1018. return unless $vmap;
  1019. return !defined $target->{version} ||
  1020. defined $vmap->{vs($target)};
  1021. }
  1022. #
  1023. # find target in map
  1024. #
  1025. sub find_target ($$) {
  1026. my($name, $map) = @_;
  1027. my($vmap) = $map->{$name};
  1028. my(@vs);
  1029. return unless $vmap;
  1030. @vs = sort { vcmp($b,$a) } keys %$vmap;
  1031. return $vmap->{$vs[0]}->[-1];
  1032. }
  1033. #
  1034. # lookup target in map
  1035. #
  1036. sub target_lookup ($$) {
  1037. my($target, $map) = @_;
  1038. my($vmap,$vers);
  1039. $vmap = $map->{$target->{name}};
  1040. return unless $vmap;
  1041. $vers = $vmap->{vs($target)};
  1042. return unless $vers && @$vers;
  1043. return $vers->[0];
  1044. }
  1045. #
  1046. # retrieve conditional target attributes in map
  1047. #
  1048. sub target_attribute ($$$) {
  1049. my($target, $env, $attr) = @_;
  1050. my($with) = $env->{with};
  1051. my($optreg) = $env->{config}->{optreg};
  1052. my($name) = $target->{name};
  1053. my(@out);
  1054. return unless $target;
  1055. my(%mywith) = %{$target->{OPTIONS}};
  1056. override_options(\%mywith, name_with($name, $with), $optreg);
  1057. foreach (@{$target->{$attr}}) {
  1058. next unless conditional($_->{'cond'}, \%mywith);
  1059. push @out, $_->{'value'};
  1060. }
  1061. return \@out;
  1062. }
  1063. #
  1064. # see wether target has conflicts
  1065. #
  1066. sub target_conflicts ($$) {
  1067. my($target, $env) = @_;
  1068. return target_attribute($target, $env, 'conflicts');
  1069. }
  1070. #
  1071. # retrieve build dependencies for target
  1072. #
  1073. sub target_depends ($$) {
  1074. my($target, $env) = @_;
  1075. return target_attribute($target, $env, 'depends');
  1076. }
  1077. #
  1078. # retrieve runtime dependencies for target
  1079. #
  1080. sub target_keeps ($$) {
  1081. my($target, $env) = @_;
  1082. return target_attribute($target, $env, 'keeps');
  1083. }
  1084. #
  1085. # retrieve source list for target
  1086. #
  1087. sub target_source ($$) {
  1088. my($target, $env) = @_;
  1089. return target_attribute($target, $env, 'source');
  1090. }
  1091. #
  1092. # retrieve nosource list for target
  1093. #
  1094. sub target_nosource ($$) {
  1095. my($target, $env) = @_;
  1096. return target_attribute($target, $env, 'nosource');
  1097. }
  1098. #
  1099. # check wether target conflicts against map
  1100. #
  1101. sub target_has_conflicts ($$$) {
  1102. my($target, $map, $env) = @_;
  1103. my($conflicts, $t);
  1104. $conflicts = target_conflicts($target, $env);
  1105. foreach (@$conflicts) {
  1106. my($t) = find_target($_, $map);
  1107. return $t if $t;
  1108. }
  1109. return;
  1110. }
  1111. #
  1112. # strip doubles from depend/keep lists
  1113. # and a return a map name => depend/keep
  1114. #
  1115. sub unique_map {
  1116. my(%out);
  1117. foreach (@_) {
  1118. foreach (@$_) {
  1119. $out{$_->{value}->{name}} = $_;
  1120. }
  1121. }
  1122. return (%out);
  1123. }
  1124. #
  1125. # determine wether target should be rebuild
  1126. #
  1127. sub target_better ($$$) {
  1128. my($env, $target, $map) = @_;
  1129. my($vs) = vs($target);
  1130. my($vmap) = $map->{$target->{name}};
  1131. #
  1132. # rebuild if target isn't installed
  1133. #
  1134. return 'new' unless $vmap;
  1135. #
  1136. # if -e then
  1137. # always update if installed version is different from repository
  1138. #
  1139. if ($env->{exact} && !grep { vcmp($vs, $_) == 0; } keys %$vmap) {
  1140. return 'exact';
  1141. }
  1142. #
  1143. # if target is goal
  1144. # always update if installed version is older than repository
  1145. #
  1146. if ($target->{GOAL} && !grep { vcmp($vs, $_) <= 0; } keys %$vmap) {
  1147. return 'goal';
  1148. }
  1149. #
  1150. # if -U then
  1151. # always update if installed version is older than repository
  1152. #
  1153. if ($env->{upgrade} && !grep { vcmp($vs, $_) <= 0; } keys %$vmap) {
  1154. return 'upgrade';
  1155. }
  1156. #
  1157. # if -z/-Z then
  1158. # always update if installed version is equal or older than repository
  1159. if ($env->{zero} && grep { vcmp($vs, $_) >= 0; } keys %$vmap) {
  1160. return 'zero';
  1161. }
  1162. # keep installed target
  1163. return;
  1164. }
  1165. #
  1166. # filter package options
  1167. #
  1168. sub filter_name_with ($$$) {
  1169. my($name, $with, $global) = @_;
  1170. my(@keys);
  1171. if ($global) {
  1172. push(@keys, grep { !/::/ } keys %$with);
  1173. }
  1174. push(@keys, grep { /::/ } keys %$with);
  1175. return {
  1176. map {
  1177. my($k) = $_;
  1178. $k !~ /::/ || $k =~ s/^\Q$name\E:://
  1179. ? ( $k => $with->{$_} )
  1180. : ( )
  1181. } @keys
  1182. };
  1183. }
  1184. #
  1185. # filter out package relevant options
  1186. #
  1187. sub name_with ($$) {
  1188. filter_name_with($_[0],$_[1],1);
  1189. }
  1190. #
  1191. # filter out package specific options
  1192. #
  1193. sub name_only_with ($$) {
  1194. filter_name_with($_[0],$_[1],0);
  1195. }
  1196. #
  1197. # check wether installed package matches
  1198. # build options
  1199. #
  1200. sub target_suitable ($$) {
  1201. my($target, $with) = @_;
  1202. my($iwith);
  1203. my($k,$v);
  1204. if ($target->{GOAL}) {
  1205. $with = name_with($target->{name}, $with);
  1206. } else {
  1207. $with = name_only_with($target->{name}, $with);
  1208. }
  1209. $iwith = $target->{OPTIONS};
  1210. while (($k,$v) = each %$with) {
  1211. if (exists $iwith->{$k}) {
  1212. return 0 if $iwith->{$k} ne $with->{$k};
  1213. }
  1214. }
  1215. return 1;
  1216. }
  1217. #
  1218. # record target status
  1219. #
  1220. sub target_setstatus ($$$) {
  1221. my($target, $status, $pri) = @_;
  1222. if ($pri > $target->{STATUSPRI}) {
  1223. $target->{STATUSPRI} = $pri;
  1224. $target->{STATUS} = $status;
  1225. }
  1226. }
  1227. #
  1228. # report options that are not used for
  1229. #
  1230. sub warn_about_options ($$$) {
  1231. my($target, $with, $c) = @_;
  1232. my($iwith) = $target->{OPTIONS};
  1233. my($k,$v);
  1234. return unless defined $iwith;
  1235. $with = name_with($target->{name}, $with);
  1236. while (($k,$v) = each %$with) {
  1237. unless ($k =~ /^$c->{optreg}$/ || exists $iwith->{$k}) {
  1238. print "# ATTENTION: $target->{name} ignores option '$k'\n";
  1239. }
  1240. }
  1241. }
  1242. #
  1243. # add dependency as build option
  1244. #
  1245. sub depend_option ($$$) {
  1246. my($target,$dep,$env) = @_;
  1247. my($with,$opt,$relmap,@t,$t);
  1248. my($pro) = depends2provides($dep);
  1249. my($conflict) = 0;
  1250. return 1 unless defined $pro->{with};
  1251. my($val) = defined $pro->{version} ? $pro->{version} : 'yes';
  1252. $with = $env->{with};
  1253. $opt = $pro->{prefix}.'::'.$pro->{with};
  1254. if (defined $with->{$opt} && $with->{$opt} ne $val) {
  1255. print "# ",vsn($target),
  1256. " has conflicting requirement $opt = $with->{$opt} != $val\n";
  1257. $conflict = 1;
  1258. }
  1259. $relmap = $env->{built}->{$pro->{prefix}} ||
  1260. $env->{installed}->{$pro->{prefix}};
  1261. @t = get_targets($relmap, sub { 1; });
  1262. foreach $t (@t) {
  1263. $with = $t->{OPTIONS};
  1264. $opt = $pro->{with};
  1265. if (defined $with->{$opt} && $with->{$opt} ne $val) {
  1266. print "# ",vsn($t),
  1267. " has conflicting requirement $opt = $with->{$opt} != $val\n";
  1268. $conflict = 1;
  1269. }
  1270. }
  1271. return 0 if $conflict;
  1272. print "# ",vsn($target)," adds option $opt = $val\n";
  1273. $with->{$opt} = $val;
  1274. return 1;
  1275. }
  1276. ############################################################################
  1277. #
  1278. # LOGIC
  1279. #
  1280. #
  1281. # locate target for a dependency
  1282. #
  1283. sub dep2target ($$) {
  1284. my($dep, $env) = @_;
  1285. my($name,$op,@vers);
  1286. my($i,$r,$b,$cond,$version);
  1287. my($t,$tdef,$why);
  1288. ($name, $op, $version) = ($dep->{name}, $dep->{op}, $dep->{val});
  1289. $i = $env->{installed}->{$name};
  1290. $r = $env->{repository}->{$name};
  1291. $b = $env->{built}->{$name};
  1292. return unless $i || $r || $b;
  1293. if (!defined $op) {
  1294. $cond = sub { 1; };
  1295. } elsif ($op eq 'geq') {
  1296. $cond = sub { vcmp($_[0],$version) >= 0; };
  1297. } elsif ($op eq 'leq') {
  1298. $cond = sub { vcmp($_[0],$version) <= 0; };
  1299. } elsif ($op eq 'gt') {
  1300. $cond = sub { vcmp($_[0],$version) > 0; };
  1301. } elsif ($op eq 'lt') {
  1302. $cond = sub { vcmp($_[0],$version) < 0; };
  1303. } elsif ($op eq 'equ') {
  1304. $cond = sub { vcmp($_[0],$version) == 0; };
  1305. } else {
  1306. die "FATAL: internal error in dep2target\n";
  1307. }
  1308. $tdef = undef;
  1309. #
  1310. # search installed target that matches requirement
  1311. # use it if we are not upgrading (no -U and no -z/-Z)
  1312. #
  1313. if ($i && (@vers = get_versions($i, $cond))) {
  1314. foreach (@vers) {
  1315. $t = $i->{$_}->[0];
  1316. get_with($t);
  1317. if (target_suitable($t, $env->{with})) {
  1318. $tdef = $t;
  1319. unless ($env->{upgrade} || $env->{zero}) {
  1320. return ($t, 1);
  1321. }
  1322. }
  1323. }
  1324. }
  1325. #
  1326. # search target in current build list that matches requirement
  1327. # use it if it exists
  1328. #
  1329. if ($b && (@vers = get_versions($b, $cond))) {
  1330. return ($b->{$vers[0]}->[0], 1);
  1331. }
  1332. #
  1333. # search target in repository and install it, if it is newer
  1334. # than corresponding installed versions
  1335. # avoid repository packages that would install 'new' (i.e.
  1336. # are not an upgrade of an existing package)
  1337. #
  1338. $t = chose_source($env, $name, undef, $r, $cond);
  1339. if ($t) {
  1340. if (!$tdef || (
  1341. $why = target_better($env, $t, $env->{installed}) &&
  1342. $why ne 'new'
  1343. )) {
  1344. return ($t, 0);
  1345. }
  1346. }
  1347. #
  1348. # if nothing is suitable in repository then fall back to
  1349. # anything we already have installed but that we skipped
  1350. # above to look for upgrades.
  1351. #
  1352. if ($tdef) {
  1353. return ($tdef, 1);
  1354. }
  1355. return;
  1356. }
  1357. #
  1358. #
  1359. #
  1360. sub make_dep ($$$$$$$) {
  1361. my($who,$target,$depth,$env,$list,$blist,$clist) = @_;
  1362. my($d,$k,%d,%k,$t,$old);
  1363. my(@deps,$conflict,$why);
  1364. if (target_exists($target, $env->{built})) {
  1365. print "# $target->{name} is already in list\n";
  1366. return;
  1367. }
  1368. if ($t = target_has_conflicts($target, $env->{installed}, $env)) {
  1369. target_setstatus($target,'CONFLICT',4);
  1370. push(@$clist,$target);
  1371. print "# $target->{name} conflicts with ",vsn($t),"\n";
  1372. return;
  1373. }
  1374. if ($t = target_has_conflicts($target, $env->{built}, $env)) {
  1375. target_setstatus($target,'CONFLICT',4);
  1376. push(@$clist,$target);
  1377. print "# $target->{name} conflicts with ",vsn($t),"\n";
  1378. return;
  1379. }
  1380. #
  1381. # see if a target is already installed and requires a rebuild
  1382. #
  1383. if ($t = find_target($target->{name}, $env->{installed})) {
  1384. if (exists $env->{exclude}->{$target->{name}}) {
  1385. print "# excluding $target->{name} (no upgrade allowed)\n";
  1386. return;
  1387. }
  1388. # pull in options
  1389. if ($target->{REBUILD}) {
  1390. target_setstatus($target,'DEPEND',1);
  1391. print "# rebuilding $target->{name} (dependency)\n";
  1392. } elsif ($env->{zero}) {
  1393. target_setstatus($target,'ZERO',1);
  1394. print "# rebuilding $target->{name} (zero)\n";
  1395. } elsif ($why = target_better($env, $target, $env->{installed})) {
  1396. target_setstatus($target,'UPDATE',3);
  1397. print "# rebuilding $target->{name} ($why)\n";
  1398. } elsif (!target_suitable($t, $env->{with})) {
  1399. target_setstatus($target,'MISMATCH',2);
  1400. print "# rebuilding $target->{name} (parameter mismatch)\n";
  1401. } elsif ($env->{goals} && $target->{GOAL}) {
  1402. target_setstatus($target,'GOAL',3);
  1403. print "# rebuilding $target->{name} (goal)\n";
  1404. } else {
  1405. print "# $target->{name} is already installed\n";
  1406. return;
  1407. }
  1408. # use options from installed base
  1409. override_options(get_with($target), get_with($t),
  1410. $env->{config}->{optreg});
  1411. # remember this is a rebuild for a proxy package
  1412. $target->{PROXY} = $t->{PROXY};
  1413. $target->{REBUILD} = 1;
  1414. } else {
  1415. target_setstatus($target,'ADD',3);
  1416. }
  1417. if (exists $env->{exclude}->{$target->{name}}) {
  1418. die "FATAL: target ".vsn($target)." is forbidden\n";
  1419. }
  1420. # mark this as a target before reverse dependencies trigger
  1421. # it again
  1422. push(@{$env->{built}->{$target->{name}}->{vs($target)}}, $target);
  1423. $target->{LIMBO} = 1;
  1424. $d = target_depends(target_lookup($target, $env->{repository}), $env);
  1425. $k = target_keeps(target_lookup($target, $env->{repository}), $env);
  1426. #
  1427. # recurse over dependencies
  1428. #
  1429. if (@$d || @$k) {
  1430. %d = unique_map($d, $k);
  1431. %k = unique_map($k);
  1432. @deps = ();
  1433. $conflict = 0;
  1434. foreach (keys %d) {
  1435. # old index misses a OpenPKG provider in the index... skip it
  1436. next if $_ eq 'OpenPKG';
  1437. ($t,$old) = dep2target($d{$_}, $env);
  1438. if ($t) {
  1439. if ($old) {
  1440. print "# $target->{name} uses ".vsn($t)." for $_\n";
  1441. if ($t->{LIMBO}) {
  1442. print "# ATTENTION: ".vsn($t)." is in LIMBO\n";
  1443. }
  1444. }
  1445. # record which targets to keep in blist
  1446. if ($k{$_}) {
  1447. push @$blist,$t;
  1448. print "# $target->{name} installs ".vsn($t)." for $_\n";
  1449. } else {
  1450. print "# $target->{name} requires ".vsn($t)." for $_\n";
  1451. }
  1452. unless (depend_option($t, $d{$_}, $env)) {
  1453. print "# $target->{name} has conflicting requirement\n";
  1454. push(@{$env->{fatal}},vsn($target));
  1455. target_setstatus($target,'UNDEF',4);
  1456. push @$clist, $target;
  1457. $conflict = 1;
  1458. next;
  1459. }
  1460. push @deps, $t;
  1461. } else {
  1462. print "# $target->{name} searches a frood called '$_'\n";
  1463. push(@{$env->{fatal}},vsn($target));
  1464. target_setstatus($target,'UNDEF',4);
  1465. push @$clist, $target;
  1466. $conflict = 1;
  1467. }
  1468. }
  1469. unless ($conflict) {
  1470. foreach $t (@deps) {
  1471. make_dep($target,$t,$depth+1,$env,$list,$blist,$clist);
  1472. }
  1473. }
  1474. }
  1475. print "# adding ".vsn($target)." to list\n";
  1476. $target->{WHO} = $who;
  1477. $target->{WHY} = $target->{STATUS};
  1478. push(@$list, $target);
  1479. $target->{LIMBO} = 0;
  1480. # remember new options
  1481. override_options($target->{OPTIONS},
  1482. name_with($target->{name}, $env->{with}),
  1483. '');
  1484. foreach (@{target_nosource($target,$env)}) {
  1485. my($p) = target_source($target,$env)->[$_];
  1486. $p =~ s/.*\///;
  1487. print "# ATTENTION: unpackaged source $_: $p\n";
  1488. }
  1489. #
  1490. # a dependency could not be resolved, don't bother with reverse
  1491. # dependencies for this target
  1492. #
  1493. return if $conflict;
  1494. if (!$env->{quick} &&
  1495. $target->{name} ne 'openpkg' &&
  1496. $target->{REBUILD}) {
  1497. unless ($env->{revdep}) {
  1498. $env->{revdep} = get_revdep($env, $env->{installed});
  1499. }
  1500. foreach $t (@{$env->{revdep}->{$target->{name}}}) {
  1501. # this is a rebuild, triggering further revdeps
  1502. $t->{REBUILD} = 1;
  1503. # this is a rebuild, keep this installed
  1504. push(@$blist, $t);
  1505. print "# rebuilding revdep ".vsn($t)."\n";
  1506. make_dep($target,$t,$depth+1,$env,$list,$blist,$clist);
  1507. }
  1508. }
  1509. }
  1510. #
  1511. # grep environment for packages that match a pattern
  1512. #
  1513. sub search_pattern ($$) {
  1514. my($pattern, $env) = @_;
  1515. my(@todo);
  1516. #
  1517. # handle various patterns
  1518. #
  1519. if (defined $pattern) {
  1520. @todo = map {
  1521. my($p) = $_;
  1522. my($s);
  1523. $s = $1 if $p =~ s/(,[^\s,]+)$//;
  1524. if ($p =~ s/\*+$//) {
  1525. $p = '^'.quotemeta($p).'';
  1526. } else {
  1527. $p = '^'.quotemeta($p).'$';
  1528. }
  1529. map {
  1530. "$_$s"
  1531. } grep {
  1532. /$p/
  1533. } keys %{$env->{repository}}
  1534. } split(/\s+/,$pattern);
  1535. } else {
  1536. #
  1537. # undefined pattern means -a option that selects
  1538. # all packages from repository that are installed
  1539. #
  1540. @todo = grep {
  1541. my($n) = $_;
  1542. (ref $env->{installed}->{$n}) &&
  1543. grep { $_ ne '-' } keys %{$env->{installed}->{$n}}
  1544. } keys %{$env->{repository}};
  1545. }
  1546. return \@todo;
  1547. }
  1548. #
  1549. # generate build lists for targets matched by pattern
  1550. #
  1551. # all input and output is passed in 'env' hash
  1552. #
  1553. sub build_list ($$) {
  1554. my($pattern, $env) = @_;
  1555. my(@goals,@targets,@keeps,@conflicts,@bonly,$t);
  1556. my($name,$select,$r,$i);
  1557. my($todo,%keep);
  1558. $todo = search_pattern($pattern, $env);
  1559. #
  1560. # chose sources for goals from repository
  1561. #
  1562. foreach $name (@$todo) {
  1563. $select = undef;
  1564. $select = $1 if $name =~ s/,([^\s,]+)$//;
  1565. $t = undef;
  1566. #
  1567. # keeping installed packages for goals is ugly
  1568. # -> we currently do not support installed source RPMs
  1569. # -> source RPMs might already have expired from repository
  1570. #
  1571. # consequence:
  1572. # -> goals are always upgraded to repository versions
  1573. #
  1574. #unless ($env->{upgrade}) {
  1575. # $i = $env->{installed}->{$name};
  1576. # $t = chose_source($env, $name, $select, $i, sub { 1; });
  1577. #}
  1578. unless ($t) {
  1579. $r = $env->{repository}->{$name};
  1580. $t = chose_source($env, $name, $select, $r, sub { 1; });
  1581. }
  1582. if ($t) {
  1583. warn_about_options($t, $env->{with}, $env->{config});
  1584. $t->{GOAL} = 1;
  1585. push(@goals, $t);
  1586. } else {
  1587. if ($env->{status}) {
  1588. print "# dropping goal '$name'\n";
  1589. } else {
  1590. die "FATAL: cannot find source for '$name'\n";
  1591. }
  1592. }
  1593. }
  1594. return unless @goals;
  1595. @targets = ();
  1596. @keeps = @goals;
  1597. foreach $t (@goals) {
  1598. print "# recursing over dependencies for ".vsn($t)."\n";
  1599. make_dep(undef,$t,0,$env,\@targets,\@keeps,\@conflicts);
  1600. }
  1601. %keep = map { $_ => 1 } @keeps;
  1602. @bonly = reverse grep {
  1603. !$keep{$_} && !$env->{installed}->{$_->{name}}
  1604. } @targets;
  1605. return (\@targets, \@bonly, \@conflicts);
  1606. }
  1607. sub build_deps ($$) {
  1608. my($pattern, $env) = @_;
  1609. my($todo,@list,$list,@out);
  1610. $todo = search_pattern($pattern, $env);
  1611. #
  1612. # unfold target names into real targets
  1613. #
  1614. @list = map {
  1615. map {
  1616. map {
  1617. $_->{name}
  1618. } @$_
  1619. } values %{$env->{repository}->{$_}}
  1620. } @$todo;
  1621. #
  1622. # also add target name
  1623. #
  1624. push @list, @$todo;
  1625. #
  1626. # strip duplicates
  1627. #
  1628. @list = keys %{ { map { $_ => 1 } @list } };
  1629. #
  1630. # cache reverse dependencies
  1631. #
  1632. unless ($env->{revdep}) {
  1633. $env->{revdep} = get_revdep($env, $env->{repository});
  1634. }
  1635. #
  1636. # map targets into list of dependency names
  1637. #
  1638. @list = map { $env->{revdep}->{$_}
  1639. ? ( @{$env->{revdep}->{$_}} )
  1640. : ( )
  1641. } @list;
  1642. #
  1643. # recurse over dependencies
  1644. #
  1645. foreach (@list) {
  1646. # avoiding cycles
  1647. next if $env->{builddeps}->{$_->{name}};
  1648. $env->{builddeps}->{$_->{name}} = 1;
  1649. push @out, $_;
  1650. $list = build_deps($_->{name}, $env);
  1651. push @out, @$list;
  1652. }
  1653. return \@out;
  1654. }
  1655. #######################################################################
  1656. #
  1657. # OUTPUT
  1658. #
  1659. #
  1660. # compute path to binary RPM from rpm config and target data
  1661. #
  1662. sub target2rpm ($$) {
  1663. my($target,$c) = @_;
  1664. my($tmpl) = $c->{template};
  1665. my($popt) = $target->{PROXY} ? '+PROXY' : '';
  1666. $tmpl =~ s/%{NAME}/$target->{name}/;
  1667. $tmpl =~ s/%{VERSION}/$target->{version}/;
  1668. $tmpl =~ s/%{RELEASE}/$target->{release}$popt/;
  1669. return $c->{rpmdir}.'/'.$tmpl;
  1670. }
  1671. #
  1672. # compute new target based on old target augmented with options from
  1673. # a binary RPM file
  1674. #
  1675. sub binary_target ($$) {
  1676. my($t, $fn) = @_;
  1677. my(%target) = %$t;
  1678. # pull in options from binary RPM file
  1679. delete $target{'OPTIONS'};
  1680. get_with(\%target, $fn);
  1681. return \%target;
  1682. }
  1683. #
  1684. # return path to master package for a proxy package
  1685. #
  1686. sub find_proxy ($$) {
  1687. my($t,$bpkg) = @_;
  1688. my(@l) = run("$RPM -ql $t->{name}");
  1689. my($link) = (grep { $_ =~ /\/\.prefix-$t->{name}$/ } @l)[0];
  1690. return unless defined $link;
  1691. chomp $link;
  1692. my($prefix) = readlink($link);
  1693. return unless defined $prefix;
  1694. $bpkg =~ s/.*\///;
  1695. $bpkg =~ s/\+PROXY(\.[^-]+-[^-]+)-[^-]+\.rpm$/$1-*.rpm/;
  1696. return (glob("$prefix/RPM/PKG/$bpkg"))[0];
  1697. }
  1698. #
  1699. # merge parameters from installed package
  1700. # with new parameter set and global parameters
  1701. # from configuration
  1702. #
  1703. # then map the result to --define command line arguments
  1704. # suitable for rpm
  1705. #
  1706. sub make_defines ($$$$) {
  1707. my($old, $new, $def, $c) = @_;
  1708. my($with);
  1709. $old = {} unless $old;
  1710. $def = {} unless $def;
  1711. #
  1712. # override old parameters with new parameters
  1713. # drop new parameters that do not exist in old set
  1714. #
  1715. $old = { %$old };
  1716. override_options($old, $new, $c->{optreg});
  1717. #
  1718. # convert parameters to --define command line options
  1719. # skip parameter templates from index
  1720. # skip parameters that are identical to defaults
  1721. #
  1722. $with = join(' ',map { "--define '$_ $old->{$_}'" }
  1723. sort grep {
  1724. $old->{$_} =~ /\S/ &&
  1725. $old->{$_} !~ /^%/ &&
  1726. $old->{$_} ne $def->{$_}
  1727. } keys %$old);
  1728. $with = ' '.$with if $with ne '';
  1729. return $with;
  1730. }
  1731. #
  1732. # print commands from package build list
  1733. #
  1734. # c -> configuration to derive paths from
  1735. # uncond -> always do the --rebuild
  1736. # with -> parameter set passed to build tool
  1737. # ignore -> generate script that does not stop on error
  1738. # usebin -> build-time check to skip rebuild when binary exists
  1739. # allbin -> usebin also for goals
  1740. #
  1741. sub print_list1 ($$$$$$$) {
  1742. my($list,$c,$uncond,$with,$ignore,$usebin,$allbin) = @_;
  1743. my($spkg,$bpkg,$ppkg);
  1744. my($mywith, $opt);
  1745. my($cmd1, $cmd2, $mark);
  1746. $mark = '::::';
  1747. foreach (@$list) {
  1748. $spkg = $_->{href};
  1749. $bpkg = target2rpm($_, $c);
  1750. $mywith =
  1751. #
  1752. # rebuild binary package IF
  1753. #
  1754. # 'unconditional' option
  1755. # OR target is tagged as rebuilding
  1756. # OR there is no binary package
  1757. # OR dependency check found that installed package is not suitable
  1758. # OR existing binary package doesn't satisfy wanted options
  1759. #
  1760. $cmd1 = undef;
  1761. if ($uncond || $_->{REBUILD} || !-f $bpkg ||
  1762. !target_suitable(binary_target($_, $bpkg), $with)) {
  1763. $opt = make_defines($_->{OPTIONS}, $with,
  1764. $_->{DEFOPTS}, $c);
  1765. #
  1766. # proxy packages are rebuilt from their maste
  1767. # hierachy
  1768. #
  1769. # someone preferred a binary from the repository
  1770. # just copy it to the local store
  1771. #
  1772. if ($_->{PROXY}) {
  1773. $ppkg = find_proxy($_,$bpkg) or
  1774. die "FATAL: proxy package ",vsn($_)," does not exist\n";
  1775. #
  1776. # rpm doesn't support additional parameters to the
  1777. # mkproxy script
  1778. # $cmd1 = npriv("$RPM$opt --makeproxy $ppkg -- -o $bpkg");
  1779. #
  1780. $cmd1 = "( cd $c->{rpmdir} && ".
  1781. npriv("$RPM$opt --makeproxy $ppkg").
  1782. " )";
  1783. } elsif (defined $_->{prefix}) {
  1784. $cmd1 = npriv("$CURL -q -s -o $bpkg $spkg");
  1785. } else {
  1786. $cmd1 = npriv("$RPM$opt --rebuild $spkg");
  1787. }
  1788. }
  1789. #
  1790. # wrap build command with build-time check for existing
  1791. # binary target
  1792. #
  1793. if (defined $cmd1 &&
  1794. ( $allbin || ($usebin && !$_->{GOAL}) )
  1795. ) {
  1796. $cmd1 = "if test ! -f $bpkg ; then $cmd1 ; fi";
  1797. }
  1798. #
  1799. # if package exist force rpm to copy over new files
  1800. # better than erasing everything and losing configuration
  1801. # files
  1802. #
  1803. $opt = $_->{REBUILD} ? ' --force' : '';
  1804. $cmd2 = priv("$RPM$opt -Uvh $bpkg");
  1805. if ($ignore) {
  1806. $cmd2 = "$cmd1 && \\\n$cmd2" if defined $cmd1;
  1807. } else {
  1808. if (defined $cmd1) {
  1809. $cmd2 = "$cmd1 || exit \$?\n$cmd2 || exit \$?"
  1810. } else {
  1811. $cmd2 = "$cmd2 || exit \$?";
  1812. }
  1813. }
  1814. print "echo $mark $spkg $mark\n$cmd2\necho $mark $spkg = \$? $mark\n";
  1815. }
  1816. }
  1817. #
  1818. # print commands for the temporary package list
  1819. #
  1820. # temporary packages are only used for building other packages
  1821. # and are removed when everything is done
  1822. #
  1823. sub print_list2 ($$) {
  1824. my($list,$c) = @_;
  1825. my($pkg);
  1826. foreach (@$list) {
  1827. $pkg = "$_->{name}-$_->{version}-$_->{release}";
  1828. print priv("$RPM -e $pkg\n");
  1829. }
  1830. }
  1831. #
  1832. # instead of printing a command list, print a status map
  1833. # that shows all packages and how the build process would
  1834. # change their status
  1835. #
  1836. sub print_status ($$$$$) {
  1837. my($installed,$repository,$list,$bonly,$clist) = @_;
  1838. my(%bonly) = map { $_ => 1 } @$bonly;
  1839. my(%map,$n,@names,$t);
  1840. my($old,$tag,$new);
  1841. foreach (@$list, @$clist) {
  1842. next unless defined $_->{release};
  1843. $map{$_->{name}} = {
  1844. rel => "$_->{version}-$_->{release}",
  1845. status => $_->{STATUS}
  1846. };
  1847. }
  1848. foreach (@$bonly) {
  1849. $map{$_->{name}} = {
  1850. rel => "$_->{version}-$_->{release}",
  1851. status => 'TEMP'
  1852. };
  1853. }
  1854. @names = keys %map;
  1855. foreach $n (keys %$installed) {
  1856. next if $n =~ /::/;
  1857. next if exists $map{$n};
  1858. next unless grep { $_ ne '-' } keys %{$installed->{$n}};
  1859. $map{$n}->{'status'} = 'OK';
  1860. push @names,$n;
  1861. }
  1862. foreach $n (keys %$repository) {
  1863. next if $n =~ /::/;
  1864. next if exists $map{$n};
  1865. next unless grep { $_ ne '-' } keys %{$repository->{$n}};
  1866. $t = find_target($n, $repository);
  1867. $map{$n}->{'status'} = 'NEW';
  1868. $map{$n}->{'rel'} = vs($t);
  1869. push @names,$n;
  1870. }
  1871. foreach $n (sort @names) {
  1872. $old = join ',',
  1873. map { "$n-$_" }
  1874. sort
  1875. grep { $_ ne '-' }
  1876. keys %{$installed->{$n}};
  1877. $old = $n if $old eq '';
  1878. $tag = $map{$n}->{status};
  1879. $new = defined $map{$n}->{rel} ? " $n-$map{$n}->{rel}" : '';
  1880. printf "%-35s %-8s%s\n", $old, $tag, $new;
  1881. }
  1882. }
  1883. #
  1884. # print dependency map
  1885. #
  1886. sub print_map ($$$$$) {
  1887. my($installed,$repository,$list,$bonly,$clist) = @_;
  1888. my(%dep);
  1889. foreach (@$bonly) {
  1890. $_->{status} = 'TEMP';
  1891. }
  1892. foreach (reverse @$list) {
  1893. printf "%-35s %-8s %s\n",
  1894. $_->{WHO} ? vsn($_->{WHO}) : "GOAL",
  1895. $_->{WHY} ? $_->{WHY} : '???',
  1896. vsn($_);
  1897. }
  1898. }
  1899. #
  1900. # print dependency list
  1901. #
  1902. sub print_deps ($) {
  1903. my($list) = @_;
  1904. print join("\n", sort map { vsn($_) } @$list),"\n";
  1905. }
  1906. #######################################################################
  1907. my($config,$url,$repository,$installed,$env,$list,$bonly,$clist);
  1908. my($pattern,%with,%exclude);
  1909. if ($opt_a) {
  1910. $pattern = undef;
  1911. } else {
  1912. $pattern = join(' ', @ARGV);
  1913. }
  1914. if ($opt_A) {
  1915. $pattern = '*';
  1916. }
  1917. %with = map {
  1918. /([^\s=]+)(?:\=(\S+))?/
  1919. ? ($1 => (defined $2 ? $2 : 'yes'))
  1920. : ()
  1921. } split(/\s+/, $opt_D);
  1922. %exclude = map { $_ => 1 } split(/\s+/, $opt_E);
  1923. $config = get_config();
  1924. if (defined $opt_p) {
  1925. $config->{platform} = $opt_p;
  1926. }
  1927. if (defined $opt_r) {
  1928. $url = $opt_r;
  1929. $url .= '/' unless $url =~ /\/$/;
  1930. } else {
  1931. $url = get_release();
  1932. }
  1933. # if we read the index from a file we can no longer deduce
  1934. # repository paths from index paths. For now lets assume
  1935. # that everything is below SRC/ to be compatible with
  1936. # existing file indexes.
  1937. if (defined $opt_f && !defined $opt_r) {
  1938. $url .= 'SRC/';
  1939. }
  1940. $installed = $opt_Z ? {} : get_installed();
  1941. $repository = get_index(
  1942. $url.'00INDEX.rdf',
  1943. $opt_f,
  1944. $opt_X,
  1945. $config->{platform},
  1946. $installed);
  1947. $env = {
  1948. config => $config,
  1949. installed => $installed,
  1950. repository => $repository,
  1951. built => {},
  1952. revdep => undef,
  1953. with => \%with,
  1954. exclude => \%exclude,
  1955. upgrade => ($opt_a || $opt_U),
  1956. zero => ($opt_z || $opt_Z),
  1957. exact => $opt_e,
  1958. quick => $opt_q,
  1959. status => ($opt_s || $opt_S),
  1960. fatal => [],
  1961. goals => $opt_g,
  1962. sourceonly => ($opt_u ||
  1963. $opt_U ||
  1964. $opt_z ||
  1965. $opt_Z)
  1966. };
  1967. if ($opt_L) {
  1968. ($list) = build_deps($pattern, $env);
  1969. print_deps($list);
  1970. } else {
  1971. ($list,$bonly,$clist) = build_list($pattern, $env);
  1972. die "FATAL: cannot find package\n" unless defined $list;
  1973. if ($opt_M) {
  1974. print_map($installed,$repository,$list,$bonly,$clist);
  1975. } elsif ($opt_S) {
  1976. print_status($installed,$repository,$list,$bonly,$clist);
  1977. } elsif ($opt_s) {
  1978. print_status($installed,{},$list,$bonly,$clist);
  1979. } else {
  1980. if (@{$env->{fatal}}) {
  1981. die "FATAL: errors occured while building:\n",
  1982. join (',', @{$env->{fatal}}),
  1983. "\n";
  1984. }
  1985. print_list1($list,
  1986. $config,
  1987. $opt_a || $opt_u || $opt_U,
  1988. $env->{with},
  1989. $opt_i,
  1990. $opt_b,
  1991. $opt_B);
  1992. print_list2($bonly,$config) unless $opt_K;
  1993. }
  1994. }