openpkg-build.pl 63 KB

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