openpkg-build.pl 63 KB

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