source: soft/build_system/build_system/mkcd/tags/V3_6_1_1mdk/pm/Mkcd/List.pm @ 1

Last change on this file since 1 was 1, checked in by fasma, 12 years ago

Initial Import from Mandriva's soft revision 224062 and package revision 45733

File size: 69.6 KB
Line 
1package Mkcd::List;
2
3my $VERSION = '2.4.2';
4
5use strict;
6use File::NCopy qw(copy);       
7use File::Path;
8use URPM qw(ranges_overlap);
9use Mkcd::Package qw(rpmVersionCompare);
10use Mkcd::Tools qw(log_);
11use Mkcd::Optimize qw(optimize_space get_pkgs_deps);
12
13=head1 NAME
14
15List - mkcd module
16
17=head1 SYNOPSYS
18
19    require Mkcd::List;
20
21=head1 DESCRIPTION
22
23C<mkcd::List> include the mkcd packages list functions.
24
25=head1 SEE ALSO
26
27mkcd
28
29=head1 COPYRIGHT
30
31Copyright (C) 2000 MandrakeSoft <warly@mandrakesoft.com>
32
33This program is free software; you can redistribute it and/or modify
34it under the terms of the GNU General Public License as published by
35the Free Software Foundation; either version 2, or (at your option)
36any later version.
37
38This program is distributed in the hope that it will be useful,
39but WITHOUT ANY WARRANTY; without even the implied warranty of
40MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
41GNU General Public License for more details.
42
43You should have received a copy of the GNU General Public License
44along with this program; if not, write to the Free Software
45Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
46
47=cut
48
49my $config;
50
51sub new {
52    my ($class, $conf) = @_;
53    $config = $conf;
54    bless {
55           config       => $config,
56          }, $class;
57}
58
59sub processDiff {
60    my ($class, $groups, $diff, $discsFiles) = @_;
61    my (@cd, @action);
62    my %new;
63    my $prev = $diff->{previous_idx} || {};
64    foreach (@{$diff->{idx}}) {
65        push @{$action[1]}, $_ if !$prev->{$_};
66        $new{$_} = 1
67    }
68    foreach (keys %$prev) {
69        push @{$action[2]}, $_ if !$new{$_}
70    }
71    foreach my $op (2,1) {
72        foreach my $idx (@{$action[$op]}) {
73            my $d = $diff->{data}[$idx];
74            log_("ERROR processDiff: THIS MUST NOT HAPPEN action is null ($d) op $op idx $idx\n", $config->{verbose}, $config->{LOG}) and next if !$d;
75            my ($curdir, $grp, $list,undef,undef, $data) = @$d;
76            my $cd = $curdir->[0];
77            foreach my $ent (@$data) {
78                my $rpm = $ent->[0];
79                log_("LOG disc $cd group $grp: ($op) $rpm ($groups->[$grp]{size}{$rpm}{$list}[1])\n", $config->{verbose}, $config->{LOG},3);
80                if (!$rpm) {
81                    foreach (@$ent) {
82                        if (ref $_) { log_("ERROR processDiff: @$_\n", $config->{verbose}, $config->{LOG},2) }
83                        else { log_("ERROR processDiff: $_\n", $config->{verbose}, $config->{LOG},2) }
84                    }
85                }
86                $rpm or next;
87                my $source = $groups->[$grp]{size}{$rpm}{$list}[1];
88                push @{$cd[$cd]{$curdir->[1]}{$list}{$source}}, [$op, "$groups->[$grp]{urpm}{rpmkey}{rpm}{$rpm}.rpm"];
89                if ($op == 1) { $discsFiles->[$cd]{$curdir->[1]}{$list}{$groups->[$grp]{urpm}{rpmkey}{rpm}{$rpm}} = $source }
90                elsif ($op == 2) { delete $discsFiles->[$cd]{$curdir->[1]}{$list}{$groups->[$grp]{urpm}{rpmkey}{rpm}{$rpm}} }
91            }
92        }
93    }
94    my %new_diff;
95    # clear diff
96    foreach my $idx (@{$diff->{idx}}) {
97        my $nidx = push @{$new_diff{data}}, $diff->{data}[$idx];
98        push @{$new_diff{idx}}, $nidx - 1;
99        $new_diff{previous_idx}{$nidx - 1} = 1
100    }
101    return (\@cd, \%new_diff)
102}
103
104sub getDoneList {
105    my ($config, $group, $listnumber, $discsFiles) = @_;
106
107    my $topdir = "$config->{topdir}/build/$config->{name}";
108    my $add_rpm = sub {
109            my ($d, $rpm, $cd, $rep, $type) = @_;
110            #$rpm =~ /($test)\.rpm$/ or return;
111            $rpm =~ /(.*)\.rpm$/ or return;
112            #$rpm =~ /src\.rpm$/ and return;
113            my $rpm = $group->{urpm}{rpmkey}{key}{$1};
114            $group->{done}{$rpm} = $group->{orderedrep}{$type}{"$cd/$rep"};
115            $discsFiles->[$cd]{$rep}{$listnumber}{$1} = $d
116    };
117    my $read_dir = sub {
118        my ($dir, $cd, $rep, $type) = @_;
119        opendir my $RPMS, $dir or log_("WARNING getGroupReps: cannot open $dir\n",1, $config->{LOG},0) and return;
120        foreach (readdir $RPMS) {
121            if (-d "$dir/$_"){
122                opendir my $D, "$dir/$_";
123                foreach my $r (readdir $D){ 
124                    $add_rpm->("$dir/$_", $r, $cd, $rep, $type)
125                }
126            } else {
127                $add_rpm->($dir, $_, $cd, $rep, $type)
128            }
129        }
130    };
131    foreach my $type ('rpm', 'srpm') {
132        foreach my $curdir (@{$group->{list}{$listnumber}{$type}}) {
133            my ($cd, $rep) = @$curdir;
134            my $path = $config->{disc}[$cd]{function}{data}{dir}{$rep}[1]{reploc};
135            my $dir = "$topdir/$cd/$path";
136            log_("getDoneList: $listnumber disc $cd rep $rep\n", $config->{verbose}, $config->{LOG},2);
137            if ($config->{nolive}) {
138                if ($config->{list}[$listnumber]{packages}) {
139                    foreach my $ent (@{$config->{list}[$listnumber]{packages}}) {
140                        foreach my $type (keys %{$ent}) { 
141                            my $rpm_tab = $ent->{$type};
142                            log_("getDoneList: @$rpm_tab\n",1, $config->{LOG},3);
143                            foreach my $dir (@$rpm_tab) {
144                                $read_dir->($dir, $cd, $rep, $type) 
145                            }
146                        }
147                    }
148                } else {
149                    log_("ERROR getDoneList: could not find data for $listnumber disc $cd rep $rep\n", $config->{verbose}, $config->{LOG},0);
150                }
151            } elsif (-d $dir) {
152                $read_dir->($dir, $cd, $rep, $type);
153            } else {
154                log_("ERROR getDoneList: could not find data for $listnumber disc $cd rep $rep\n", $config->{verbose}, $config->{LOG},0);
155                next
156            }
157            $config->{list}[$listnumber]{disc}{$cd}{$rep}{done} = 1
158        }
159    }
160
161    foreach my $d (@{$config->{list}[$listnumber]{virtual}}) {
162        my $cd = $d->{disc};
163        my $path = $d->{path};
164        my $rep = $d->{repname};
165        my $dir = "$topdir/$cd/$path";
166        log_("getDoneList: virtual disc $cd path $path in $dir\n",1, $config->{LOG},2);
167        foreach my $list_rep (@{$group->{rep}{$listnumber}}) {
168            $list_rep->{rpm}{$dir} or next;
169            foreach (@{$list_rep->{rpm}{$dir}}) {
170                my $rpm = $group->{urpm}{rpmkey}{key}{$_};
171                $group->{done}{$rpm} = $group->{orderedrep}{rpm}{"$cd/$rep"};
172                $discsFiles->[$cd]{$rep}{$listnumber}{$_} = $dir
173            }
174        }
175        $config->{list}[$listnumber]{disc}{$cd}{$rep}{done} = 1;
176    }
177}
178
179sub getList {
180    my ($class, $group, $discsFiles) = @_;
181    my $config = $class->{config};
182    my %filelist;
183    my @norpmsrate;
184    log_("getList: group list " . join(' ', (keys %{$group->{list}})) . "\n", $config->{verbose}, $config->{LOG},1);
185    foreach my $listnumber (keys %{$group->{list}}) {
186        my $done = $config->{list}[$listnumber]{done};
187        $done and getDoneList($config, $group, $listnumber, $discsFiles);
188        log_("getList: FILE LIST listnumber $listnumber ($config->{list}[$listnumber]{filelist}) or ($config->{list}[$listnumber]{prelist})\n", $config->{verbose}, $config->{LOG},2);
189        if ($config->{list}[$listnumber]{filelist} || $config->{list}[$listnumber]{prelist}) {
190            foreach (@{$config->{list}[$listnumber]{filelist}}) {
191                log_("getList: FILE LIST listnumber $listnumber ($_)\n", $config->{verbose}, $config->{LOG},2);
192                open my $A, $_ or log_("ERROR: cannot open $_, ignoring\n",1, $config->{LOG}) and next;
193                local $_;
194                while (<$A>) {
195                    s/#.*//;
196                    next if !$_ || /^\s*$/;
197                    my ($name, $options) = /\s*(\S+)\s*(.*)/;
198                    my @options = split ',', $options;
199                    log_("FILESLIST: $_ -> $name options @options\n", $config->{verbose}, $config->{LOG},3);
200                    my %opt;
201                    foreach (@options) {
202                        s/^\s*//;
203                        /norpmsrate/ and push @norpmsrate, $name and next;
204                        /^(?:(?:nosrc|section|noalternatives|regexp|ignore|nodeps|force|limit|exclude)|(rate|notondisc|rpmsrate|needed|section) (\d+))$/ or log_("WARNING: getList: $_: unknown option\n",1, $config->{LOG}) and next;
205                        $_ = $1 || $_; 
206                        $opt{$_} = $2 || 1;
207                    }
208                    log_("Adding $name -- " . join(' ', keys %opt) . "\n", $config->{verbose}, $config->{LOG},4);
209                    push @{$filelist{$listnumber}}, [ $name, \%opt ];   
210                }
211                close $A
212            }
213            foreach my $p (@{$config->{list}[$listnumber]{prelist}}) {
214                log_("Prelist Adding $p->[0] -- " . join(' ', keys %{$p->[1]}) . "\n", $config->{verbose}, $config->{LOG},3);
215                $p->[1]{norpmsrate} and push @norpmsrate, $_->[0] and next;
216                push @{$filelist{$listnumber}}, $p
217            }
218        } else {
219            if (!$done && $config->{list}[$listnumber]{auto}) {
220                push @{$filelist{$listnumber}}, [ "INSTALL", { section =>1, force => 1 } ];
221                push @{$filelist{$listnumber}}, [ "SYSTEM", { section =>1, force => 1 } ];
222                push @{$filelist{$listnumber}}, [ "kernel-(smp-|)[0-9].*", { regexp => 1, force => 1 } ];
223                push @{$filelist{$listnumber}}, [ "kernel.*linus", { regexp => 1, noalternatives => 1 } ];
224                push @{$filelist{$listnumber}}, [ ".*", { regexp => 1 } ]
225            } else {
226                log_("getList: FILE LIST listnumber $listnumber defaulting to .* regexp\n", $config->{verbose}, $config->{LOG},2);
227                push @{$filelist{$listnumber}}, [ ".*" , { regexp => 1 } ]
228            }
229        }
230        my $listdone = 1;
231        foreach my $r (@{$group->{list}{$listnumber}{rpm}}) {
232            my ($cd, $rep, $repopt, $opt) = @$r;
233            log_("getList: searching for done rep ($cd/$rep)\n", $config->{verbose}, $config->{LOG},2);
234            if ($config->{list}[$listnumber]{disc}{$cd}{$rep}{done}) {
235                if (!$opt->{dup}) {
236                    foreach my $rpmkey (keys %{$discsFiles->[$cd]{$rep}{$listnumber}}) {
237                        my $rpm = $group->{urpm}{rpmkey}{key}{$rpmkey};
238                        $group->{done}{$rpm} = $group->{orderedrep}{rpm}{"$cd/$rep"};
239                        log_("getList: $rpm in $cd/$rep -> $group->{done}{$rpm}\n", $config->{verbose}, $config->{LOG},3);
240                        push @{$filelist{$listnumber}}, [$rpm, { done => $group->{done}{$rpm}, regexp => 1, udpate => $r->[2]{update} }];
241                    }
242                }
243            } else { $listdone = 0 }
244        }
245        $listdone and log_("getList: setting list $listnumber as done\n", $config->{verbose}, $config->{LOG},2) and $config->{list}[$listnumber]{done} = 1;
246    }
247    (\%filelist, \@norpmsrate)
248}
249
250#
251# compute individual scoring (max_size*(rpmsrate+1)*rpmsrate_factor/(size*size_factor))
252# then add dependencies sons score ( score + deps_factor*(sons_score)
253#
254# special rpmsrate groups score could be added in the rpmsrate value
255#
256# FIXME current scoring rules make size only significant for equaly dependent packages,
257# dependencies get far more importance for packages a lot of packages depend on.
258#
259# Size scoring could be added afterwards, but this will break the autodeps created with
260# this scheme.
261#
262# TODO
263# add scoring rules to include srpm size in score.
264#
265#
266sub scoreList {
267    my ($class, $group) = @_;
268    my $scoreweight = $group->{score};
269    my $urpm = $group->{urpm};
270    my $rpmsrate = $group->{rpmsrate};
271    my $maxsize = $group->{maxsize} || 1;
272    $scoreweight ||= [1,1,1];
273    log_("scoreList: SCORE for group: @$scoreweight\n", $config->{verbose}, $config->{LOG},2);
274    log_("scoreList: Individual scoring\n", $config->{verbose}, $config->{LOG},2);
275    my ($sf, $i, $total);
276    my (@min, @max);
277    if ($scoreweight->[1]) {
278        (@min,@max) = (($maxsize*$scoreweight->[0]*6/($scoreweight->[1]*1),0), (0,0))
279    } else {
280        (@min,@max) = (($maxsize*$scoreweight->[0]*6,0), (0,0))
281    }
282    my @specialdeps;
283    foreach (keys %{$urpm->{rpm}}) {
284        # print "INFO KEYS $_\n";
285        my ($ratekey) = /(.*)-[^-]+-[^-]+\.[^.]+$/;
286        # FIXME take the bigger size when package appears in multiple lists
287        my $size;
288        foreach my $list (keys %{$group->{size}{$_}}) { $size = $group->{size}{$_}{$list}[0] if $size < $group->{size}{$_}{$list}[0] }
289        $size or log_("WARNING scoreList: $_ has zero size\n",1, $config->{LOG});
290        my $s;
291        my $rate = $group->{brokendeps}{$_} ? 0 : (defined $group->{pkgrate}{$_} ? $group->{pkgrate}{$_} : $rpmsrate->[0]{$ratekey});
292        if ($scoreweight->[1]) {
293            $sf = ($size*9)/$maxsize + 1; # from 1 to 10
294            $s = $scoreweight->[0]*($rate + 1)/($scoreweight->[1]*$sf);
295        } else {
296            $s = $scoreweight->[0]*($rate + 1);
297        }
298        $group->{scorelist}{$_} = $s;
299        $s < $min[0] and @min = ($s, $_);
300        $s > $max[0] and @max = ($s, $_);
301
302        $total+=$s;
303        $i++
304    }
305    $i and log_("scoreList: minimal $min[0] ($min[1]), maximal $max[0] ($max[1]), average " . $total/$i . "\n", $config->{verbose}, $config->{LOG},3);
306    1
307}
308
309sub autodeps {
310    my ($class, $group, $rpmlist) = @_;
311    my $scoredeps = $group->{score}[2];
312    $scoredeps or log_("autodeps: deps score is null, bypassing autodeps\n",1, $config->{LOG},1) and return 1;
313    log_("autodeps: compute reversed depslist.ordered ($scoredeps)\n", $config->{verbose}, $config->{LOG},2);
314    my $revDeps = $group->{revdeps};
315    my %rpm;
316    foreach my $k (values %$rpmlist) { foreach (keys %$k) { $rpm{$_} = $k->{$_} } }
317    # FIXME this algo is not correct
318    ref $group->{urpm}{depslist} or return 0;
319    for (my $i = @{$group->{urpm}{depslist}} - 1; $i >= 0; $i--) {
320        my $rpm = $group->{depslistid}[$i];
321        if (!$rpm{$rpm}) { 
322            #log_("autodeps: ignoring $rpm\n",1, $config->{LOG});
323            #push @{$group->{rejected}{$rpm}}, [ "autodeps", $1 ];
324            next
325        }
326        if ($rpm{$rpm}{ignore}) { log_("autodeps: $rpm has ignore flag, do not add deps score\n", $config->{verbose}, $config->{LOG},3); next }
327        foreach (@{$revDeps->[$i]}) {
328            $group->{scorelist}{$rpm} += $scoredeps * $group->{scorelist}{$group->{depslistid}[$_]};
329        }
330    }
331    1
332}
333
334sub reverseDepslist {
335    my ($class, $group) = @_;
336    my $urpm = $group->{urpm};
337    my $depslist = $urpm->{depslist};
338    $depslist or return ();
339    my $locales = $group->{lang};
340    my (@revdeps, %skip);
341    log_("reverseDepslist\n", $config->{verbose}, $config->{LOG},2);
342    for (my $i; $i < @$depslist; $i++) {
343        my $d = $depslist->[$i];
344        my $rpm = sprintf "%s-%s-%s.%s", $d->name, $d->version, $d->release, $d->arch;
345        $group->{depslistid}[$i] = $rpm;
346        my %rev;
347        # FIXME deps is deprecated, the correct function to use it packages->requires
348        foreach (split(' ', $urpm->{deps}[$i])) {
349            if (!$group->{options}{nodeps} && !$class->{config}{nodeps} && m/NOTFOUND_(\S*)/) {
350                $skip{$i} = 1;
351                $group->{brokendeps}{$rpm} = 2;
352                push @{$group->{rejected}{$rpm}}, [ "deps", $1 ];
353                log_("WARNING reverseDepslist: $rpm has unresolved dependencies ($1)\n", $config->{verbose}, $config->{LOG}, 1);
354                next
355            }
356            if (/\|/) { 
357                my $s = [split '\|', $_];
358                my (@tmp_s, $msg_tot);
359                foreach (@$s) { 
360                    my ($ok, $msg) = check_version($d, $depslist->[$_], $rpm);
361                    log_("ERROR check_version: $msg\n", $config->{verbose}, $config->{LOG}, 0) if $msg;
362                    if ($ok) {
363                        push @tmp_s, $_ 
364                    } else { 
365                        $msg_tot .= $msg
366                    }
367                    $skip{$_} or push @{$revdeps[$_]}, $i 
368                }
369                if (@tmp_s) {
370                    push @{$group->{pkgdeps}{$rpm}}, \@tmp_s
371                } else {
372                    $skip{$i} = 1;
373                    $group->{brokendeps}{$rpm} = 2;
374                    log_("WARNING reverseDepslist: rejecting $rpm on $_\n", $config->{verbose}, $config->{LOG}, 4);
375                    push @{$group->{rejected}{$rpm}}, [ "deps", $msg_tot ]
376                }
377            } else { 
378                if ($locales && $group->{depslistid}[$_] =~ /locales-([^-]+)-[^-]+-[^-]+\.[^.]+/)  {
379                    if (!$locales->{$1}) {
380                        log_("reverseDepslist: locale $1 ($group->{depslistid}[$_]) skipped for $rpm\n", $config->{verbose}, $config->{LOG}, 2) and $skip{$i} = 1;
381                        !$group->{brokendeps}{$rpm} and $group->{brokendeps}{$rpm} = 1 
382                    }
383                }
384       
385                my ($ok, $msg) = check_version($d, $depslist->[$_], $rpm);
386                log_("ERROR check_version: $msg\n", $config->{verbose}, $config->{LOG}, 0) if $msg;
387                if ($ok) {
388                    push @{$group->{pkgdeps}{$rpm}}, $_ 
389                } else { 
390                    $skip{$i} = 1;
391                    $group->{brokendeps}{$rpm} = 2;
392                    log_("WARNING reverseDepslist: rejecting $rpm on $_\n", $config->{verbose}, $config->{LOG}, 4);
393                    push @{$group->{rejected}{$rpm}}, [ "deps", $msg ]
394                }
395                $skip{$_} or push @{$revdeps[$_]}, $i
396            }
397        }
398    }
399    return \@revdeps
400}
401
402# check if ONE require is satisfied
403sub check_version {
404    my ($d, $deps_d, $rpm, $special_require) = @_;
405    my ($msg, $real_ok, $ok);
406    $ok = 1;
407    my $deps_v = sprintf "%s-%s", $deps_d->version, $deps_d->release;
408    my $deps_rpm = sprintf "%s-%s.%s", $deps_d->name, $deps_v, $deps_d->arch;
409    $rpm ||= sprintf "%s-%s-%s.%s", $d->name, $d->version, $d->release, $d->arch;
410    foreach my $req ($d->requires) {
411        my ($n, $s) = $req =~ /^([^\s\[]*)(?:\[\*\])?\[?([^\s\]]*\s*[^\s\]]*)/;
412        # perl needs major checking
413        $n eq 'perl' and next;
414        # Some deps are broken and as a consequence using the major rejects some packages that shouldn't
415        #$s and ($s =~ /:/ or $s =~ s/([>=<]+) /$1 0:/);
416        $s =~ /:/ and $s =~ s/ \d+:/ /;
417        if ($n && $s) {
418            # nok is usefull in case the package provides several times the require, each time with a different version
419            my $tok;
420            foreach my $prov ($deps_d->provides) {
421                my ($deps_n, $deps_s) = $prov =~ /^([^\s\[]*)(?:\[\*\])?\[?([^\s\]]*\s*[^\s\]]*)/;
422                #$deps_s and ($deps_s =~ /:/ or $deps_s =~ s/([>=<]+) /$1 0:/);
423                $deps_s =~ /:/ and $deps_s =~ s/ \d+:/ /;
424                $deps_s ||= ($s =~ /-/) ? "= $deps_v" : "= " . $deps_d->version;
425                if ($deps_n && $deps_s) {
426                    if ($deps_n eq $n) { 
427                        if (URPM::ranges_overlap($deps_s, $s)) {
428                            $real_ok = 1 if !$special_require || $special_require eq $n;
429                        } else {
430                            my $t = "$deps_rpm provides $deps_n $deps_s but $rpm needs $n $s";
431                            $msg .= " $t";
432                        }
433                    }
434                }
435            }
436        } else {
437            foreach my $prov ($deps_d->provides) {
438                my ($deps_n) = $prov =~ /^([^\s\[]*)(?:\[\*\])?\[?([^\s\]]*\s*[^\s\]]*)/;
439                if ($deps_n eq $n) { 
440                    $real_ok = 1 if !$special_require || $special_require eq $n;
441                }
442            }
443        }
444    }
445    ($ok, $msg, $real_ok)
446}
447
448sub closeRpmsList {
449    my ($group, $rpmfile) = @_;
450    my $n = 1;
451    my %done;
452    my %doneName;
453    my %alternatives;
454    while ($n) {
455        $n = 0;
456        foreach my $listnumber (@{$group->{orderedlist}{rpm}}) {
457            foreach my $rpm (keys %{$rpmfile->{$listnumber}}) {
458                # FIXME if the different packages have different deps, old packages may be better.
459                # this should be done in buildDisc, or better packages have to be selected here.
460                if (!$group->{options}{dup}) {
461                    my ($name, $version, $release, $arch) = $rpm =~ /^(.*)-([^-]+)-([^-]+)\.([^.]+)$/;
462                    if ($doneName{$name}) {
463                        if (!($doneName{$name}[0] eq "$version-$release.$arch")) {
464                            log_("WARNING closeRpmsList: $name-$version-$release.$arch duplicated with $doneName{$name}[0]\n", $config->{verbose}, $config->{LOG}, 1);
465                            my ($v, $r, $a) = @{$doneName{$name}[1]};   
466                            my $todel;
467                            my $vers;
468                            my $ret = rpmVersionCompare($rpm, "$name-$v-$r.$a");
469                            if ($ret < 0) {
470                                $todel = $rpm;
471                                $vers = [$v, $r, $a]
472                            } elsif ($ret > 0) {
473                                $todel = "$name-$v-$r.$a";
474                                $vers = [$version, $release, $arch]
475                            } else {
476                                log_("ERROR closeRpmsList: oops, something not possible happened in duplicate version comparaison ($rpm and $name-$v-$r.$a)\n",1, $config->{LOG});
477                            }
478                            if ($todel) {
479                                log_("closeRpmsList: deleting $todel\n", $config->{verbose}, $config->{LOG},2);
480                                $doneName{$name} = [ "$vers->[0]-$vers->[1].$vers->[2]", $vers ];
481                                #$group->{brokendeps}{$todel} = 3;
482                                #push @{$group->{rejected}{$todel}}, [ "old_version", "$name-$vers->[0]-$vers->[1].$vers->[2]"];
483                                delete $rpmfile->{$listnumber}{$todel};
484                                $todel eq $rpm and next 
485                            }
486                            $n = 1
487                        }
488                    } else {
489                        $doneName{$name} = [ "$version-$release.$arch", [$version, $release, $arch] ]
490                    }
491                }
492                if ($group->{brokendeps}{$rpm} == 2 || $group->{brokendeps}{$rpm} == 3) {
493                    log_("closeRpmsList: deleting $rpm (list $listnumber)\n", $config->{verbose}, $config->{LOG},2);
494                    delete $rpmfile->{$listnumber}{$rpm};
495                    $n = 1;
496                    next
497                }
498                $done{$rpm} and next;
499                $rpmfile->{$listnumber}{$rpm}{nodeps} and next;
500                my $needed;
501                # FIXME the right thing to do would be to put the require in the rep just before the one of the $rpm, and not to force it.
502                $needed = 1 if $rpmfile->{$listnumber}{$rpm}{force};
503                $needed ||= $rpmfile->{$listnumber}{$rpm}{done};
504                $needed ||= $rpmfile->{$listnumber}{$rpm}{needed};
505                # $needed and log_("closeRpmsList: $rpm needed set to $needed (force $rpmfile->{$listnumber}{$rpm}{force} done $rpmfile->{$listnumber}{$rpm}{done} needed $rpmfile->{$listnumber}{$rpm}{needed})\n", $config->{verbose}, $config->{LOG});
506                foreach (@{$group->{pkgdeps}{$rpm}}) {
507                    m/NOTFOUND_(.*)/ and log_("ERROR closeRpmsList: $1 not provided\n", $config->{verbose}, $config->{LOG},1) and next;
508                    my $rpmdep;
509                    my $rpmdeplist;
510                    my $specialrpmdep;
511                    if (ref $_) {
512                        if ($alternatives{"@$_"}) {
513                            ($rpmdep, $rpmdeplist) = @{$alternatives{"@$_"}};
514                            log_("closeRpmsList: $rpm taking alternatives from already selected package ($rpmdep $rpmdeplist)\n", $config->{verbose}, $config->{LOG}, 4)
515                        }
516                        if (! ref $rpmfile->{$rpmdeplist}{$rpmdep}) {
517                            foreach my $testalt (1,0) {
518                                ($rpmdep, $rpmdeplist) = (undef,undef);
519                                # FIXME this is wrong, package can come from any list
520                                my @score = ($group->{maxlist}{rpm}, int @{$group->{list}{$listnumber}{rpm}}, $group->{maxsize});
521                                my @specialscore = (int @{$group->{list}{$listnumber}{rpm}}, $group->{maxsize});
522                                log_("closeRpmsList: $rpm @$_ (maxscore @score) alternative\n", $config->{verbose}, $config->{LOG}, 4);
523                                foreach (@$_) {
524                                    my $pkg = $group->{depslistid}[$_];
525                                    log_("closeRpmsList: trying $pkg (brokendeps $group->{brokendeps}{$pkg})\n", $config->{verbose}, $config->{LOG}, 4);
526                                    $group->{brokendeps}{$pkg} == 2 and next;
527                                    $group->{brokendeps}{$pkg} == 3 and next;
528                                    my $pkglist = find_list($group, $pkg, $listnumber);
529                                    $pkglist or log_("closeRpmsList: $pkg list could not be used for $rpm dependencies\n", $config->{verbose}, $config->{LOG}, 4) and next;
530                                    log_("closeRpmsList: list $pkglist\n", $config->{verbose}, $config->{LOG}, 4);
531
532                                    if ($rpmfile->{$pkglist}{$pkg}) {
533                                        $rpmfile->{$pkglist}{$pkg}{limit} and next;
534                                        $testalt and $rpmfile->{$pkglist}{$pkg}{noalternatives} and next;
535                                    }
536                                    my $rep = $group->{size}{$pkg}{$pkglist}[2];
537                                    my $s = $group->{size}{$pkg}{$pkglist}[0];
538                                    my $l = $group->{listsort}{$pkglist}{rpm};
539                                    log_("\t$pkg ($l, $rep, $s) (@score)\n", $config->{verbose}, $config->{LOG}, 5);
540                                    # also put an alternative from this list
541                                    if ($pkglist == $listnumber) {
542                                        if ($rep < $specialscore[1]) {
543                                            @specialscore = ($rep, $s);
544                                            $specialrpmdep = $pkg;
545                                        } elsif ($rep == $specialscore[1] && $s < $specialscore[2]) {
546                                            @specialscore = ($rep, $s);
547                                            $specialrpmdep = $pkg;
548                                        }               
549                                    }
550                                    if ($l < $score[0]) {
551                                        @score = ($l, $rep, $s);
552                                        $rpmdep = $pkg;
553                                        $rpmdeplist = $pkglist;
554                                        log_("1 $rpmdep -- $rpmdeplist -- $l, $rep, $s\n", $config->{verbose}, $config->{LOG}, 6);
555                                    } elsif ($l == $score[0]) {
556                                        if ($pkglist == $listnumber) {
557                                            if ($rep < $score[1]) {
558                                                @score = ($l, $rep, $s);
559                                                $rpmdep = $pkg;
560                                                $rpmdeplist = $pkglist;
561                                                log_("2 $rpmdep -- $rpmdeplist -- $l, $rep, $s\n", $config->{verbose}, $config->{LOG}, 6);
562                                            } elsif ($rep == $score[1] && $s < $score[2]) {
563                                                @score = ($l, $rep, $s);
564                                                $rpmdep = $pkg;
565                                                $rpmdeplist = $pkglist;
566                                                log_("3 $rpmdep -- $rpmdeplist -- $l, $rep, $s\n", $config->{verbose}, $config->{LOG}, 6);
567                                            }
568                                        } elsif ($s < $score[2]) {
569                                            @score = ($l, $rep, $s);
570                                            $rpmdep = $pkg;
571                                            $rpmdeplist = $pkglist;
572                                            log_("4 $rpmdep -- $rpmdeplist -- $l, $rep, $s\n", $config->{verbose}, $config->{LOG}, 6);
573                                        }
574
575                                    }
576                                }
577                                last if $rpmdep && $rpmdeplist
578                            }
579                            if ($rpmdep && $rpmdeplist) {
580                                log_("\tResult:\t$rpmdep\n", $config->{verbose}, $config->{LOG}, 4);
581                                $alternatives{"@$_"} = [ $rpmdep, $rpmdeplist ]
582                            } else {
583                                log_("WARNING: $rpm has unresolved or excluded dependencies, removed\n", $config->{verbose}, $config->{LOG}, 1);
584                                log_("closeRpmsList: deleting $rpm (list $listnumber)\n", $config->{verbose}, $config->{LOG}, 2);
585                                delete $rpmfile->{$listnumber}{$rpm};
586                                $n = 1;
587                                $group->{brokendeps}{$rpm} = 2;
588                                push @{$group->{rejected}{$rpm}}, ["deps_rejected", (join ' ', map { $group->{depslistid}[$_] } @$_)];
589                            }
590                        }
591                    } else {   
592                        # TODO verify that there is no need to do $rpmfile->{$pkglist}{$rpmdep} or brokendeps;
593                        $rpmdep = $group->{depslistid}[$_];
594                        $rpmdeplist = find_list($group, $rpmdep, $listnumber);
595                    }
596                    # log_("rpmdep $rpmdep rpmdeplist $rpmdeplist rpm $rpm\n",1, $config->{LOG});
597                    if ($rpmdep) {
598                        if (!$rpmdeplist || $group->{brokendeps}{$rpmdep} == 2 || $group->{brokendeps}{$rpmdep} == 3) {
599                            $group->{brokendeps}{$rpm} = $group->{brokendeps}{$rpmdep};
600                            push @{$group->{rejected}{$rpm}}, [ "deps_rejected", $rpmdep ];
601                            $n = 1;
602                            log_("WARNING closeRpmsList: $rpm has unresolved or excluded dependencies ($rpmdep list $rpmdeplist), removed\n", $config->{verbose}, $config->{LOG}, 1);
603                            log_("closeRpmsList: deleting $rpm (list $listnumber)\n", $config->{verbose}, $config->{LOG}, 2);
604                            delete $rpmfile->{$listnumber}{$rpm};
605                            next
606                        }
607                        if (! ref $rpmfile->{$rpmdeplist}{$rpmdep}) {
608                            $n = 1;
609                            log_("closeRpmsList: ADDED $rpmdep (list $rpmdeplist) needed $needed\n", $config->{verbose}, $config->{LOG}, 3);
610                            $rpmfile->{$rpmdeplist}{$rpmdep} = { needed => $needed }
611                        } elsif ($needed) {
612                            my $n = $rpmfile->{$rpmdeplist}{$rpmdep}{needed};
613                            $rpmfile->{$rpmdeplist}{$rpmdep}{needed} = !$n || $needed < $n ? $needed : $n;
614                            log_("closeRpmsList: setting $rpmdep needed option to $rpmfile->{$rpmdeplist}{$rpmdep}{needed}\n", $config->{verbose}, $config->{LOG}, 4);
615                        }
616                    }
617                    if ($specialrpmdep) {
618                        if (! ref $rpmfile->{$listnumber}{$specialrpmdep}) {
619                            $n = 1;
620                            log_("closeRpmsList: ADDED $specialrpmdep (list $listnumber)\n", $config->{verbose}, $config->{LOG}, 3);
621                            $rpmfile->{$listnumber}{$specialrpmdep} = { }
622                        }
623                    }
624                }
625                $done{$rpm} = 1;
626            }
627            log_("closeRpmsList: $listnumber [$n]\n", $config->{verbose}, $config->{LOG}, 2);
628        }
629    }
630}
631
632sub addRPMToList {
633    my ($group, $listnumber, $rpmfile, $done, $rpms, $fentry, $name) = @_;
634    my $exclude = sub {
635        my ($rpm, $name) = @_;
636        log_("addRPMToList: excluding $_\n",1, $config->{LOG}, 1);
637        $group->{brokendeps}{$rpm} = 3;
638        push @{$group->{rejected}{$rpm}}, ["excluded", $name];
639    };
640    $name =~ s/\+/\\+/g;
641    my @toadd;
642    if ($fentry->{regexp}) { @toadd = grep { /$name/ } @$rpms } 
643    else { @toadd = grep { /^$name-[^-]+-[^-]+\.[^.]*$/ } @$rpms }
644    log_("addRPMToList: toadd $name (regexp $fentry->{regexp}) (@toadd)\n", $config->{verbose}, $config->{LOG}, 3);
645    if ($fentry->{done}) {
646        foreach (@toadd) {
647            my ($pkg) = /^(.*)-[^-]+-[^-]+\.[^.]*$/;
648            my %ht;
649            foreach my $k (keys %$fentry) { $ht{$k} = $fentry->{$k} }   
650            $rpmfile->{$listnumber}{$_} = \%ht;
651            $done->{$pkg} = [ $_, $group->{size}{$_}{$listnumber}[2], \%ht, $listnumber ];
652            log_("addRPMToList: ADDED done $_ (list $listnumber) options " . (join '', keys %ht) . "\n", $config->{verbose}, $config->{LOG}, 4)
653        }
654        return
655    }
656    my %pkg;
657    if ($fentry->{regexp}) { 
658        foreach (@toadd) {
659            $rpmfile->{$listnumber}{$_} and log_("WARNING addRPMToList: do not replace $_ entry in rpmfile\n", $config->{verbose}, $config->{LOG}, 1) and next;
660            $_ or log_("ERROR addRPMToList: empty rpm\n", $config->{verbose}, $config->{LOG}, 2) and next;
661            $group->{size}{$_}{$listnumber} or next;
662            $group->{brokendeps}{$_} == 2 and next;
663            $group->{brokendeps}{$_} == 3 and next;
664            my ($pkgname) = /^(.*)-[^-]+-[^-]+\.[^.]*$/;
665            $done->{$_} and next;
666            my $rep = $group->{size}{$_}{$listnumber}[2];
667            if ($fentry->{exclude}) {
668                $exclude->($_, $name);
669                next
670            }
671            if ($done->{$pkgname} && $done->{$pkgname}[3] == $listnumber) {
672                if (!$fentry->{update} || !$done->{$pkgname}[2]{done}) {
673                    if ($rep < $done->{$pkgname}[1]) {
674                        $pkg{$done->{$pkgname}[0]} = 0;
675                        log_("REPLACING $done->{$pkgname}[0] with $_ (list $listnumber)\n", $config->{verbose}, $config->{LOG}, 4);
676                        $pkg{$_} = 1;
677                        $done->{$pkgname} = [ $_, $rep, $fentry, $listnumber ];
678                        $done->{$_} = 1
679                    } elsif ($done->{$pkgname}[1] == $rep) {
680                        if (rpmVersionCompare($done->{$pkgname}[0], $_) < 0) {
681                            $pkg{$done->{$pkgname}[0]} = 0;
682                            log_("REPLACING $done->{$pkgname}[0] with $_ (list $listnumber)\n", $config->{verbose}, $config->{LOG}, 4);
683                            $pkg{$_} = 1;
684                            $done->{$pkgname} = [ $_, $rep, $fentry, $listnumber ];
685                            $done->{$_} = 1
686                        }
687                    }
688                }
689            } else { $pkg{$_} = 1; $done->{$pkgname} = [ $_, $rep, $fentry, $listnumber ]; $done->{$_} = 1 }
690        }
691    } else {
692        my $rep;
693        my $pkg;
694        # FIXME present algorythm selects only one package per version, and choose the one in the list declared first.
695        # Maybe adding all the version and letting closeRRPMsList choose the right one is better.
696        foreach (@toadd) {
697            $_ or log_("ERROR addRPMToList: empty rpm\n",1, $config->{LOG}, 2) and next;
698            $rpmfile->{$listnumber}{$_} and log_("WARNING addRPMToList: do not replace $_ entry in rpmfile\n", $config->{verbose}, $config->{LOG}, 1) and next;
699            $group->{size}{$_}{$listnumber} or next;
700            $group->{brokendeps}{$_} == 2 and next;
701            $group->{brokendeps}{$_} == 3 and next;
702            if ($fentry->{exclude}) {
703                $exclude->($_, $name);
704                next;
705            }
706            if ($group->{size}{$_}{$listnumber}[2] < $rep || !$rep)  {
707                $rep = $group->{size}{$_}{$listnumber}[2];
708                log_("addRPMToList: choosing $_ (rep $rep)\n", $config->{verbose}, $config->{LOG}, 2);
709                $pkg = $_
710            } elsif ($group->{size}{$_}{$listnumber}[2] == $rep) {
711                if (rpmVersionCompare($pkg, $_) < 0) {
712                    $rep = $group->{size}{$_}{$listnumber}[2];
713                    log_("addRPMToList: choosing $_ (rep $rep)\n", $config->{verbose}, $config->{LOG}, 2);
714                    $pkg = $_
715                }
716            }
717        }
718        my ($pkgname) = $pkg =~ /^(.*)-[^-]+-[^-]+\.[^.]*$/;
719        if (!$done->{$pkgname}) { $pkg{$pkg} = 1; $done->{$pkgname} = [ $pkg, $rep, $fentry, $listnumber ]; $done->{$pkg} = 1 }
720    }
721    $fentry->{exclude} and return 1;
722    foreach (keys %pkg) {
723        $rpmfile->{$listnumber}{$_} and log_("WARNING addRPMToList: do not replace $_ entry in rpmfile\n", $config->{verbose}, $config->{LOG}, 1) and next;
724        $pkg{$_} or next;
725        defined $fentry->{rate} and $group->{pkgrate}{$_} = $fentry->{rate} and log_("addRPMToList: setting $_ rate to $fentry->{rate}\n",1, $config->{LOG}, 2);
726        my %ht;
727        foreach my $k (keys %$fentry) { $ht{$k} = $fentry->{$k} }
728        $rpmfile->{$listnumber}{$_} = \%ht;     
729        log_("addRPMToList: ADDED $_ (list $listnumber) options " . join(" ", keys %ht) . "\n", $config->{verbose}, $config->{LOG}, 4)
730    }
731}
732
733sub build_list {
734    my ($class, $group) = @_;
735    my %rpmfile;
736    my $filelist = $group->{filelist};
737    my @fullrpm = keys %{$group->{urpm}{rpm}};
738    my @section = keys %{$group->{rpmsrate}[1]};
739    my %done;
740    foreach my $listnumber (@{$group->{orderedlist}{rpm}}) {
741        log_("build_list: list $listnumber ($group->{listrpm}{$listnumber})\n", $config->{verbose}, $config->{LOG}, 2);
742        my $rpms = $group->{listrpm}{$listnumber};
743        if (ref $rpms) {
744            log_("$listnumber -- $group->{filelist} -- " . keys(%{$group->{filelist}}) . "\n", $config->{verbose}, $config->{LOG}, 3);
745            ref $filelist->{$listnumber} or log_("WARNING: list $listnumber has an empty file list\n", $config->{verbose}, $config->{LOG}, 1) and next;
746            log_("build_list: FILE LIST $listnumber (" . int @{$filelist->{$listnumber}} . ")\n", $config->{verbose}, $config->{LOG}, 4);
747            foreach my $fentry (@{$filelist->{$listnumber}}) {
748                my $name = $fentry->[0];
749                my $opt = $fentry->[1]; 
750                log_("build_list: processing $name " . join(' ', keys %$opt) . "\n", $config->{verbose}, $config->{LOG}, 5);
751                my @toadd;
752                if ($opt->{section}) {
753                    my $level = $opt->{section};
754                    log_("build_list: selecting rpmsrate package of section $name with score higher than $level\n", $config->{verbose}, $config->{LOG}, 2);
755                    $opt->{section} = 0;
756                    if ($opt->{regexp}) {
757                        $opt->{regexp} = 0;
758                        @toadd = grep { /$name/ } @section;
759                        log_("$name (@section) -> @toadd\n", $config->{verbose}, $config->{LOG}, 4);
760                        foreach (@toadd) {
761                            foreach (@{$group->{rpmsrate}[1]{$_}}) {
762                                log_("$_ -> $group->{rpmsrate}[0]{$_}\n", $config->{verbose}, $config->{LOG}, 4);
763                                if ($group->{rpmsrate}[0]{$_} >= $level) {
764                                    addRPMToList($group, $listnumber, \%rpmfile, \%done, $rpms, $opt, $_);
765                                }
766                            }
767                        }
768                    } else {
769                        my $rpmlist = $group->{rpmsrate}[1]{$name} or log_("ERROR build_list: $name unknown rpmsrate section\n", $config->{verbose}, $config->{LOG}, 0) and next;
770                        foreach (@$rpmlist) {
771                            if ($group->{rpmsrate}[0]{$_} >= $level) {
772                                addRPMToList($group, $listnumber, \%rpmfile, \%done, $rpms, $opt, $_)
773                            }
774                        }
775                    }
776                } else {
777                    addRPMToList($group, $listnumber, \%rpmfile, \%done, $rpms, $opt, $name);
778                }
779            }
780        } else {
781            log_("WARNING: List $listnumber is empty, ignoring\n", $config->{verbose}, $config->{LOG}, 0);     
782            $class->{config}{list}[$listnumber]{empty} = 1;
783        }
784    }
785    if (!$class->{config}{nodeps} && !$group->{options}{nodeps}) {
786        my @toadd = grep { /^basesystem-[^-]+-[^-]+\.[^.]*$/ } @fullrpm; 
787        my $pkg;
788        my $listnumber;
789        foreach (@toadd) {
790            my $l = find_list($group, $_);
791            if ($group->{listmatrix}{rpm}{$listnumber}{$l} || !$listnumber) {
792                $pkg = $_;
793                $listnumber = $l
794            }
795        }
796        if ($pkg) {
797            $rpmfile{$listnumber}{$pkg} = {};
798            log_("build_list ADDED $pkg (list $listnumber)\n", $config->{verbose}, $config->{LOG}, 4);
799        } else { log_("ERROR: basesystem package is not available.\n",1, $config->{LOG}) }
800
801        # add deps
802        closeRpmsList($group, \%rpmfile)
803    }
804    \%rpmfile
805}
806
807sub addRPMToDiff {
808    my ($rpm, $rpmd, $diff, $cdnum, $repnumber, $i, $list, $curdir, $size, $rpmsize, $totrpmsize, $repnum, $done, $packages) = @_;
809    my @data;
810    for (my $s; $s < @$rpm; $s++) {
811        push @data, [$rpm->[$s],1, $rpmd->[$s], $rpmsize->[$s]];
812        log_("addRPMToDiff: $rpm->[$s] put in rep $repnumber\n", $config->{verbose}, $config->{LOG}, 4);
813        $done->{$rpm->[$s]} = $repnumber;
814    }
815    my $idx = push @{$diff->{data}}, [ $curdir, $i, $list, $repnum, 1, \@data, $rpmd, $totrpmsize ];
816    push @{$diff->{idx}}, --$idx;
817    $size->{disc}[$cdnum] += $totrpmsize;
818    $size->{rep}{$cdnum}{$curdir->[1]}{$list} += $totrpmsize;
819    log_("addRPMToDiff: SIZE disc $cdnum: $size->{disc}[$cdnum] (+ @$rpm $totrpmsize ID $idx) added rpmd $rpmd\n", $config->{verbose}, $config->{LOG}, 3);
820    1
821}
822
823sub find_list {
824    my ($group, $r, $list, $notdone) = @_;
825    my $l;
826    foreach (keys %{$group->{size}{$r}}) {
827#       log_("find_list: for $r trying list $_ (listmatrix $l - $_ -> $group->{listmatrix}{rpm}{$l}{$_} listmatrix $list - $_ -> $group->{listmatrix}{rpm}{$list}{$_})\n",1, $config->{LOG});
828        $l = $_ if ( ($l && $group->{listmatrix}{rpm}{$l}{$_} 
829                       || 
830                     (!$l && ($group->{listmatrix}{rpm}{$list}{$_} || !$list)))
831                   && ($notdone && !$config->{list}[$_]{done} || !$notdone))
832    }
833    return $l
834}
835
836sub processDeps {
837    my ($r, $group, $done, $rpmlist, $topush, $intopush, $depsdisc, $rpmd, $list, $loop, $i, $tobedone, $buildlist, $rpm, $needed) = @_;
838    log_("processDeps: deps $r\n", $config->{verbose}, $config->{LOG}, 3);
839    my $tcd = $done->{$r};
840    my $l = find_list($group, $r, $list, !$tcd);
841    if ($group->{rejected}{$r}) { 
842        log_("ERROR processDeps: deps $r rejected, rejecting @$rpm\n",1, $config->{LOG}, 1);
843        log_("Rejecting @$rpm $r\n", $config->{verbose}, $config->{LOG},1);
844        foreach (@$rpm) { push @{$group->{rejected}{$_}}, ["deps_rejected", $r] }
845        $$loop = 1; %$topush = (); return 0 
846    }
847    if ($tcd) {
848        if ($tcd > $$depsdisc) { $$depsdisc = $tcd };
849        log_("processDeps: deps done $r on rep $tcd ($$depsdisc)\n", $config->{verbose}, $config->{LOG}, 4);
850        return 2 
851    }
852    if ($tobedone->{$r}) {
853        if ($l == $list) {
854            log_("$r tobedone\n", $config->{verbose}, $config->{LOG},3);
855            $intopush->{$r} and log_("WARNING processDeps: $r added twice\n", $config->{verbose}, $config->{LOG}, 3) and return 1;
856            push @$rpmd, [$r, $rpmlist->[$i]{$l}{$r}];
857            $intopush->{$r} = 1;
858            push @{$topush->{$l}}, $rpmd; 
859            log_("processDeps: adding looping deps $r ($_ -- $l) with @$rpm\n", $config->{verbose}, $config->{LOG},3)
860        } else {
861                if ($group->{listmatrix}{rpm}{$list}{$l}) {
862                    # FIXME tobedone may not mean dependencies loop in parallel mode for different list.
863                    log_("processDeps: $r is already scheduled on list $l, waiting.\n", $config->{verbose}, $config->{LOG},4);
864                    %$topush = ();
865                    push @{$buildlist->[$i]{$list}}, @$rpmd > 1 ? $rpmd : $rpmd->[0];
866                    return 3
867                    #$intopush{$r} and log_("ERROR: $r added twice\n",1, $config->{LOG}) and return 0;
868                    #$intopush{$r} = 1;
869                    #push @{$topush{$l}}, [$r, $rpmlist->[$i]{$l}{$r}];
870                    #log_("DEPS $r ($_ -- $l)\n", $config->{verbose}, $config->{LOG})
871                } else {
872                    log_("ERROR processDeps: deps $r could not be put in directory before packages @$rpm\n", $config->{verbose}, $config->{LOG},1);
873                    log_("Rejecting @$rpm $r\n", $config->{verbose}, $config->{LOG},1);
874                    reject_rpm($rpm, $group, 'order_pb', $r, \$loop, $topush);
875                    return 0
876            }
877        }
878    } else {
879        if ($l == $list) {
880            $intopush->{$r} and log_("WARNING processDeps: $r added twice\n",1, $config->{LOG},2) and return 1;
881            $intopush->{$r} = 1;
882            push @{$topush->{$l}}, [$r, $rpmlist->[$i]{$l}{$r}]; 
883            log_("processDeps: adding normal deps $r ($_ -- $l)\n", $config->{verbose}, $config->{LOG},3)
884        } else {
885            if ($group->{options}{sequential}) {
886                log_("WARNING processDeps: could not add interlist deps in sequential mode\n",1, $config->{LOG},2);
887                reject_rpm($rpm, $group, 'sequential', $r, \$loop, $topush);
888                return 0
889            } else {
890                if (defined $needed->{$list}{asap} && grep { $l == $_->[0] } @{$needed->{$list}{asap}}) {
891                    log_("ERROR processDeps: list of deps $r is already wainting for @$rpm list\n",1, $config->{LOG},1);
892                    reject_rpm($rpm, $group, 'order_pb', $r, \$loop);
893                    return 0
894                } else {
895                    if ($group->{listmatrix}{rpm}{$list}{$l}) {
896                        $intopush->{$r} and log_("WARNING processDeps: $r added twice\n",1, $config->{LOG},2) and return 1;
897                        $intopush->{$r} = 1;
898                        push @{$topush->{$l}}, [$r, $rpmlist->[$i]{$l}{$r}]; 
899                        log_("processDeps: adding normal deps $r ($_ -- $l)\n", $config->{verbose}, $config->{LOG},3)
900                    } else {
901                        log_("ERROR processDeps: deps $r could not be put in directory before packages @$rpm\n",1, $config->{LOG},1);
902                        reject_rpm($rpm, $group, 'order_pb', $r, \$loop);
903                        return 0
904                    } 
905                }
906            }
907        }
908    }
909}
910
911sub reject_rpm {
912    my ($rpm, $group, $reason, $r, $loop, $topush) = @_;
913    log_("Rejecting @$rpm\n", $config->{verbose}, $config->{LOG},1);
914    foreach (@$rpm) { push @{$group->{rejected}{$_}}, [ $reason, $r] }
915    %$topush = ();
916    $$loop = 1;
917}
918
919sub updateGenericLimit {
920    my ($groups, $cdsize) = @_;
921    log_("updateGenericLimit\n", $config->{verbose}, $config->{LOG},2);
922    for (my $i; $i < @$groups; $i++) {
923        foreach my $type (keys %{$groups->[$i]{orderedlist}}) {
924            foreach my $list (@{$groups->[$i]{orderedlist}{$type}}) {
925                foreach my $r (@{$groups->[$i]{list}{$list}{$type}}) {
926                    my ($cd, $rep, $repopt) = @$r;
927                    #log_("trying to update disc $cd rep $rep list $list limit repopt $repopt (",1, $config->{LOG}),keys %$repopt,") opt $opt (",keys %$opt,")\n";
928                    $config->{list}[$list]{disc}{$cd}{$rep}{done} and next;
929                    $repopt->{limit} or next;
930                    $repopt->{limit}{size} = $repopt->{limit}{value} * $cdsize->[$cd];
931                    log_("updateGenericLimit: setting disc $cd rep $rep list $list limit to $repopt->{limit}{size} ($repopt->{limit}{value} * $cdsize->[$cd])\n", $config->{verbose}, $config->{LOG}, 3);
932                }
933            }
934        }
935    }
936}
937
938sub testSoftLimit {
939    my ($opt, $cd, $groups, $buildlist) = @_;
940    log_("testSoftLimit\n", $config->{verbose}, $config->{LOG}, 2);
941    my $softnok = 1;
942    # FIXME this code must be tested
943    if ($opt->{limit} && $opt->{limit}{soft}) {
944        foreach my $l (@{$config->{disc}[$cd]{fastgeneric}}) {
945            my $lst = $l->[2]{list};
946            for (my $i; $i < @$groups; $i++) {
947                $groups->[$i]{list}{$lst} or next;     
948                $softnok = 0 if (@{$buildlist->[$i]{$lst}} && !($lst->{limit} && $lst->{limit}{soft}))   
949            }
950        }
951    }
952    return $softnok;
953}
954
955sub add_one_disc {
956    my ($cdlists, $group, $cdsize, $list, $cds, $sources, $size, $g) = @_;
957    my $ncd;
958    foreach (keys %$cdlists) {
959        $ncd = $_ + 1 if $ncd <= $_
960    }
961    log_("add_one_disc: $config->{list}[$list]{cd} -- $ncd\n", $config->{verbose}, $config->{LOG}, 3);
962    if (!$config->{list}[$list]{cd} || $config->{list}[$list]{cd} >= $ncd) {
963        log_("add_one_disc: adding new disc $ncd\n", $config->{verbose}, $config->{LOG}, 4);
964        $config->{disc}[$ncd]{size} = $config->{discsize};
965        my $functions = $config->{group}{disc}{functions}{functions};
966        $cdsize->[$ncd] = $config->{discsize};
967        $config->{disc}[$ncd]{name} = $ncd;
968        $size->{optimize_space}{disc}{$ncd} = $cdsize->[$ncd];
969        $group->{disc_impacted}{$ncd} = 1;
970        my ($curdir, $srpmcurdir);
971        my $tmp = "$config->{tmp}/build/$config->{name}";
972        my $f = "$tmp/$ncd.list";
973        -f $f and unlink $f;
974        if ($config->{nolive}) {
975            log_("makeDisc: removing $tmp/$ncd\n", $config->{verbose}, $config->{LOG}, 3);
976            rmtree "$tmp/$ncd";
977            mkpath "$tmp/$ncd";
978        } else {
979            my $dir = "$config->{topdir}/build/$config->{name}";
980            rmtree "$dir/$ncd";
981            rmtree "$dir/first/$ncd";
982            mkpath "$dir/$ncd"
983        }
984        my $instcd = $group->{installDisc};
985        my ($rep, $src_rep);
986
987        if ($sources && $config->{list}[$list]{sources} && $config->{list}[$list]{sources}{separate}) {
988            $config->{disc}[$ncd]{serial} = "$config->{name}-$ncd-src";
989            $config->{disc}[$ncd]{longname} = "MandrakeLinux $config->{name} sources";
990            $config->{disc}[$ncd]{appname} = "MandrakeLinux $config->{name} sources disc $ncd";
991            $config->{disc}[$ncd]{label} = substr "MandrakeLinux-$config->{name}-$ncd.src", 0, 32;
992            $config->{disc}[$ncd]{group_list}{$g}{$list}{srpm} = 1;
993            &{$functions->{dir}[0][5]}($ncd, 3, "srpms", "Mandrake/SRPMS");
994            &{$functions->{generic}[0][5]}($ncd, 4, "srpms",1);
995            &{$functions->{generic}[1][5]}($ncd, 5, { source => 1 });
996            push @{$config->{disc}[$instcd]{function}{data}{installation}[1]{srpmsdir}}, [ 0, $ncd, "srpms" ];
997            $srpmcurdir = [ $ncd, "srpms" ];
998            push @{$group->{list}{$list}{srpm}}, $srpmcurdir;
999            $src_rep = $group->{maxrep}{srpm};
1000            push @{$group->{replist}{srpm}}, [ $ncd, 'srpms', $group->{maxrep}{srpm}++, { $list => $srpmcurdir } ];
1001        } else {
1002            $config->{disc}[$ncd]{serial} = "$config->{name}-$ncd";
1003            $config->{disc}[$ncd]{longname} = "MandrakeLinux $config->{name}";
1004            $config->{disc}[$ncd]{appname} = "MandrakeLinux $config->{name} disc $ncd";
1005            $config->{disc}[$ncd]{label} = substr "MandrakeLinux-$config->{name}-$ncd.i586", 0, 32;
1006            $config->{disc}[$ncd]{group_list}{$g}{$list}{rpm} = 1;
1007            &{$functions->{dir}[0][5]}($ncd, 1, "rpms", "Mandrake/RPMS$ncd");
1008            &{$functions->{generic}[0][5]}($ncd, 2, "rpms", 1);
1009            $group->{orderedrep}{rpm}{"$ncd/rpms"} = $ncd;
1010            #
1011            # generic has no FIXED part, otherwize a call to generic with fixed=0
1012            # would have been needed
1013            #
1014            $curdir = [$ncd, "rpms"];
1015            push @{$group->{list}{$list}{rpm}}, $curdir;
1016            $rep = $group->{maxrep}{rpm};
1017            if ($group->{replist}{rpm}[$group->{maxrep}{rpm}-1]) {
1018                die "FATAL add_one_disc: rep $group->{maxrep}{rpm} should not exist !\n"
1019            } else {
1020                $group->{replist}{rpm}[$group->{maxrep}{rpm}-1], [ $ncd, 'rpms', $group->{maxrep}{rpm}++, { $list => $curdir } ];
1021            }
1022            push @{$config->{disc}[$instcd]{function}{data}{installation}[1]{rpmsdir}}, [ 0, $ncd, "rpms" ];
1023            if ($config->{list}[$list]{sources}) {
1024                &{$functions->{dir}[0][5]}($ncd,3, "srpms", "Mandrake/SRPMS");
1025                &{$functions->{generic}[0][5]}($ncd,4, "srpms",1);
1026                &{$functions->{generic}[1][5]}($ncd,5, { source => 1 });
1027                push @{$config->{disc}[$instcd]{function}{data}{installation}[1]{srpmsdir}}, [ 0, $ncd, "srpms" ];
1028                $srpmcurdir = [ $ncd, "srpms" ];
1029                $src_rep = $group->{maxrep}{srpm};
1030                if ($group->{replist}{srpm}[$group->{maxrep}{srpm}-1]) {
1031                    die "FATAL add_one_disc: rep $group->{maxrep}{srpm} should not exist !\n"
1032                } else {
1033                    $group->{replist}{srpm}[$group->{maxrep}{srpm}-1], [ $ncd, 'srpms', $group->{maxrep}{srpm}++, { $list => $srpmcurdir } ];
1034                } 
1035                push @{$group->{list}{$list}{srpm}}, $srpmcurdir
1036            }
1037        }
1038        push @$cds, $ncd;
1039        $cdlists->{$ncd} = 2;
1040        return ($curdir, $rep, $srpmcurdir, $src_rep)
1041    } else { return 0 }
1042}
1043
1044sub addSRPMToDiff {
1045    my ($rpmd, $done, $diff, $size, $srpmrep, $srpmsize, $curdir, $srpm, $list, $i, $cdnum) = @_;
1046    for (my $s; $s < @$rpmd; $s++) {
1047        if (!$rpmd->[$s][1]{nosrc} && !$done->{$srpm->[$s]}) {
1048            my $srep = $srpmrep->{$srpm->[$s]};
1049            my $idx = push @{$diff->{data}}, [ $srep->[2], $i, $list, $srep->[1], 2, [[$srpm->[$s],1, $rpmd->[$s], $srpmsize->[$s]]], 0, $srpmsize->[$s] ];
1050            push @{$diff->{idx}}, $idx - 1;
1051            $size->{disc}[$srep->[0]] += $srpmsize->[$s];
1052            $size->{rep}{$srep->[0]}{$srep->[2][1]}{$list} += $srpmsize->[$s];
1053            log_("SIZE disc $srep->[0]: $size->{disc}[$srep->[0]] (+ $srpm->[$s] $srpmsize->[$s])\n", $config->{verbose}, $config->{LOG}, 2);
1054        }
1055        $done->{$srpm->[$s]}++;
1056    }
1057    1
1058}
1059
1060sub sourcesSizeCheck {
1061    my ($done, $rpmd, $srpm, $group, $groups, $size, $cdsize, $list, $cdlists, $cdnum, $rpmsize, $buildlist, $cds, $i, $diff) = @_;
1062    my %srpmrep;   
1063    my $srpmok = 1;
1064    my @srpmsize;
1065    for (my $s; $s < @$srpm; $s++) {
1066        $done->{$srpm->[$s]} and next;
1067        $rpmd->[$s][1]{nosrc} and next;
1068        my $srpmsize = $group->{size}{$srpm->[$s]}{$list}[0];
1069        $srpmsize[$s] = $srpmsize;
1070        for (my $k; $k < @{$group->{list}{$list}{srpm}}; $k++) {
1071            my $srpmdir = $group->{list}{$list}{srpm}[$k];
1072            my ($srccd, $srcrepname, $srcopt) = @$srpmdir;
1073            my $src_rep_num = $group->{orderedrep}{srpm}{"$srccd/$srcrepname"};
1074            log_("trying source disc $srccd\n", $config->{verbose}, $config->{LOG}, 2);
1075            $cdlists->{$srccd} > 1 or next;
1076            my $currentrpm;
1077            $cdnum == $srccd and $currentrpm = $rpmsize;
1078            my $softnok = testSoftLimit($srcopt, $srccd, $groups, $buildlist);
1079            my $gain = $size->{disc}[$srccd] + $srpmsize + $currentrpm - $cdsize->[$srccd];
1080            # FIXME this need to be tested
1081            if ($gain <= 0 && !($srcopt->{limit} && ($softnok || !$srcopt->{limit}{soft}) && $size->{rep}{$srccd}{$srcrepname}{$list} > $srcopt->{limit}{size})) {
1082                $srpmrep{$srpm->[$s]} = [$srccd, $src_rep_num, $srpmdir];
1083                last
1084            } elsif ($k == $#{$group->{list}{$list}{srpm}}) {
1085                if (optimize_space($config, $groups, $diff, $size, $cdsize, $srccd, $gain, $cdlists,0, $i, $list, 'srpm', $srpmsize + $currentrpm) < $gain) {
1086                    $srpmok = 0
1087                } else {
1088                    $srpmrep{$srpm->[$s]} = [$srccd, $src_rep_num, $srpmdir];
1089                }
1090            }
1091        }
1092        if (!$srpmrep{$srpm->[$s]}) {
1093            $srpmok = 0
1094            # no last here because if in autoMode a CD will be added after and we will not retest for each srpm if it could be put on an existing CD.
1095        }
1096    }
1097    if (!$srpmok && $config->{list}[$list]{auto}) {
1098        my (undef,undef, $srpmdir, $repnum) = add_one_disc($cdlists, $group, $cdsize, $list, $cds,1, $size, $i);
1099        if ($srpmdir) {
1100            for (my $s; $s < @$srpm; $s++) {
1101                if (!$srpmrep{$srpm->[$s]}) {
1102                    $srpmrep{$srpm->[$s]} = [$srpmdir->[0], $repnum, $srpmdir];
1103                }
1104            }
1105            $srpmok = 1
1106        }
1107    }
1108    return (\%srpmrep, \@srpmsize, $srpmok)
1109}
1110
1111sub choose_alt {
1112    my ($deps, $rpmlist, $group, $cdnum, $repname, $list, $buildlist, $intopush, $tobedone, $needed) = @_;
1113    my $r = -1;
1114    my $score = [ 0, $group->{maxlist} ];
1115    my $done = $group->{done};
1116    foreach my $testalt (1,0) {
1117        foreach (@$deps) {
1118            # FIXME it may have a problem here, as depslistid are not erased when the
1119            # package is removed, that is to say that if the previous deps failed for
1120            # any reason, alternates deps may be added, although excluded before
1121            # however this _must_ not happen, and signify a bug somewhere else.
1122            my $pkg = $group->{depslistid}[$_];
1123
1124            my $l = find_list($group, $pkg, $list);
1125            $testalt and $rpmlist->{$l}{$pkg}{noalternatives} and log_("choose_alt: $pkg is not selected in first pass for alternatives\n", $config->{verbose}, $config->{LOG},6) and next;
1126            $intopush->{$pkg} and $r = $pkg and last;
1127            log_("choose_alt: alternatives deps $pkg\n", $config->{verbose}, $config->{LOG}, 6);
1128            $group->{rejected}{$pkg} and log_("choose_alt: $pkg is rejected, ignoring\n", $config->{verbose}, $config->{LOG}, 6) and next;
1129            my $tcd = $done->{$pkg};
1130            if ($tcd && $tcd <= $group->{orderedrep}{rpm}{"$cdnum/$repname"}) {
1131                log_("$pkg ($tcd) done\n", $config->{verbose}, $config->{LOG}, 6);
1132                $r = 0;
1133                last
1134            } 
1135            my $s = $group->{scorelist}{$pkg};
1136            my $pkgList = find_list($group, $pkg, $list, !$tcd);
1137            if ($list != $pkgList && ((defined $needed->{$pkgList}{asap} && grep { $list == $_->[0] } @{$needed->{$pkgList}{asap}}) || ($group->{options}{sequential} && !$config->{list}[$pkgList]{done} && @{$buildlist->{$pkgList}}))) { next }
1138            log_("choose_alt: $pkg list $pkgList\n", $config->{verbose}, $config->{LOG}, 6);
1139            if (!$tcd && $group->{listmatrix}{rpm}{$list}{$pkgList}) {
1140                if ($group->{listsort}{$pkgList}{rpm} < $score->[1] || $group->{listsort}{$pkgList}{rpm} == $score->[1] && $s > $score->[0]) {
1141                    log_("choose_alt: choosing $pkg ($s, $group->{listsort}{$pkgList}{rpm})\n", $config->{verbose}, $config->{LOG}, 6);
1142                    $score = [ $s, $group->{listsort}{$pkgList}{rpm} ];
1143                    $r = $pkg;
1144                    last if $tobedone->{$r} 
1145                }
1146            }
1147        }
1148        $r and last
1149    }
1150    return $r
1151}
1152
1153sub check_deps {
1154    my ($rpmd, $group, $done, $rpmlist, $list, $i, $tobedone, $buildlist, $rpm, $cdnum, $repname, $needed, $thisorderrep) = @_;
1155    my $deps = get_pkgs_deps($rpmd, $group);
1156    my $loop;
1157    if (@$deps) {
1158        my ($waiting, %topush, %intopush, $depsdisc);
1159        foreach (@$deps) {
1160            if (!ref $_) {
1161                my $a = processDeps($group->{depslistid}[$_], $group, $done, $rpmlist, \%topush, \%intopush, \$depsdisc, $rpmd, $list, \$loop, $i, $tobedone, $buildlist, $rpm, $needed->[$i]);
1162                if ($a < 0) { return 0 } elsif ($a == 0) { last } elsif ($a == 2) { next } elsif ($a == 3) { $waiting = 1; last  }
1163            } else {
1164                # must create a virtual package that install all of them in one loop
1165                log_("check_deps: alternatives deps @$_\n", $config->{verbose}, $config->{LOG}, 5);
1166                my $r = choose_alt($_, $rpmlist->[$i], $group, $cdnum, $repname, $list, $buildlist->[$i], \%intopush, $tobedone, $needed->[$i]);
1167                $intopush{$r} and next;
1168                if ($r == -1) {
1169                    log_("ERROR check_deps: alternatives deps (@$_) could not be put in directory before packages @$rpm\n", $config->{verbose}, $config->{LOG}, 2);
1170                    log_("Rejecting @$rpm\n", $config->{verbose}, $config->{LOG},2);
1171                    foreach my $p (@$rpm) { push @{$group->{rejected}{$p}}, ["order_pb", "@$_"] }
1172                    %topush = ();
1173                    $loop = 1;
1174                    last
1175                }
1176                if ($r) { 
1177                    my $a = processDeps($r, $group, $done, $rpmlist, \%topush, \%intopush, \$depsdisc, $rpmd, $list, \$loop, $i, $tobedone, $buildlist, $rpm, $needed->[$i]);
1178                    if ($a < 0) { return 0 } elsif ($a == 0) { last } elsif ($a == 2) { next } elsif ($a == 3) { $waiting = 1; last  }
1179                } else {
1180                    log_("Finding better alternatives rep (@$_ - $depsdisc)\n", $config->{verbose}, $config->{LOG}, 4);
1181                    my $bestdisc = keys %{$group->{orderedrep}{rpm}};
1182                    if ($bestdisc >= $depsdisc) {
1183                        foreach (@$_) {
1184                            my $pkg = $group->{depslistid}[$_];
1185                            $group->{rejected}{$pkg} and log_("$pkg rejected\n", $config->{verbose}, $config->{LOG}, 2) and next;
1186                            my $tcd = $done->{$pkg} or next; 
1187                            log_("$pkg => rep $tcd\n", $config->{verbose}, $config->{LOG}, 4);
1188                            if ($tcd < $bestdisc) { $bestdisc = $tcd }
1189                        }
1190                        $bestdisc > $depsdisc and $depsdisc = $bestdisc
1191                    }
1192                    log_("Finding better alternatives rep result $depsdisc\n", $config->{verbose}, $config->{LOG}, 4);
1193                }
1194            }
1195        }
1196        $waiting and next;
1197        if (keys %topush) {
1198            log_("Adding dependencies, looping\n", $config->{verbose}, $config->{LOG}, 3);
1199            $loop = 1;
1200            my $test = @$rpmd > 1 ? $rpmd : $rpmd->[0];
1201            push @{$buildlist->[$i]{$list}}, @$rpmd > 1 ? $rpmd : $rpmd->[0];
1202            foreach (keys %topush) {
1203                $list != $_ and push @{$needed->[$i]{$list}{asap}}, [ $_, int @{$buildlist->[$i]{$_}} ];
1204                push @{$buildlist->[$i]{$_}}, @{$topush{$_}}
1205            }
1206        } elsif ($thisorderrep < $depsdisc) {
1207            if ($group->{listmaxrep}{rpm}{$list} >= $depsdisc) {
1208                # has a chance to put it after depsdic
1209                log_("Dependencies on further directories ($depsdisc)\n", $config->{verbose}, $config->{LOG}, 3);
1210                next
1211            } else {
1212                log_("check_deps: dependances are in further directories, rejecting @$rpm\n", $config->{verbose}, $config->{LOG}, 2);
1213                foreach (@$rpm) { push @{$group->{rejected}{$_}}, ["order_pb", ""] }
1214                $loop = 1
1215            }
1216        }
1217    }
1218    return $loop;
1219}
1220
1221sub put_in_rep {
1222    my ($i, $groups, $group, $size, $rpmsize, $all_rpmsize, $cdsize, $needed, $rpm, $rpmd, $list, $cdlists, $buildlist, $diff, $cds, $done, $tobedone, $rpmlist, $nosrcfit) = @_; 
1223    my $loop;
1224    my $dn;
1225    log_("put_in_rep: @$rpm\n", $config->{verbose}, $config->{LOG}, 3);
1226    for (my $j; !$loop && !$dn && $j < @{$group->{list}{$list}{rpm}}; $j++) {
1227        $loop = 0;
1228        my $curdir = $group->{list}{$list}{rpm}[$j];
1229        $config->{list}[$list]{disc}{$curdir->[0]}{$curdir->[1]}{done} and next;
1230        my ($cdnum, $repname, $repopt) = @$curdir;
1231        my $rep_num = $group->{orderedrep}{rpm}{"$cdnum/$repname"};
1232        $cdlists->{$cdnum} > 1 or next;
1233        my $thisorderrep = $group->{orderedrep}{rpm}{"$cdnum/$repname"};
1234        my $softnok = testSoftLimit($repopt, $cdnum, $groups, $buildlist);
1235        my $gain = $size->{disc}[$cdnum] + $all_rpmsize - $cdsize->[$cdnum];
1236        log_("put_in_rep: curdir cd $cdnum (space $gain rpm size $all_rpmsize) rep $repname rep_num $rep_num softnok $softnok\n", $config->{verbose}, $config->{LOG}, 4);
1237        if ($gain > 0 || $repopt->{limit} && ($softnok || !$repopt->{limit}{soft}) && $size->{rep}{$cdnum}{$repname}{$list} + $all_rpmsize > $repopt->{limit}{size}) {
1238            if ($j == $#{$group->{list}{$list}{rpm}}) {
1239                if (!($repopt->{limit} && !$softnok && $repopt->{limit}{soft})) {
1240                    if (optimize_space($config, $groups, $diff, $size, $cdsize, $cdnum, $gain, $cdlists,0, $i, $list, 'rpm', $all_rpmsize) < $gain) {
1241                        if ($config->{list}[$list]{auto}) {
1242                            ($curdir, $rep_num) = add_one_disc($cdlists, $group, $cdsize, $list, $cds,0, $size, $i);
1243                            if ($curdir) {
1244                                $cdnum = $curdir->[0]
1245                            } else {
1246                                log_("Could not add more disc, rejecting @$rpm\n", $config->{verbose}, $config->{LOG}, 2);
1247                                foreach my $p (@$rpm) { push @{$group->{rejected}{$p}}, [ "no_disc", "" ] }
1248                                next
1249                            }
1250                        } else {
1251                            log_("Rejecting @$rpm\n", $config->{verbose}, $config->{LOG}, 2);
1252                            foreach my $p (@$rpm) { push @{$group->{rejected}{$p}}, ["no_space", ""] }
1253                            next
1254                        }
1255                    }
1256                } else { 
1257                    foreach my $l (@{$config->{disc}[$cdnum]{fastgeneric}}) {
1258                        my $lst = $l->[2]{list};
1259                        $list == $lst and next;
1260                        for (my $i; $i < @$groups; $i++) {
1261                            $groups->[$i]{list}{$lst}{rpm} or next;     
1262                            push @{$needed->[$i]{$list}{asap}}, [ $lst, 0 ] if (!($lst->{limit} && $lst->{limit}{soft}))
1263                        }
1264                    }
1265                }
1266            } else { next }
1267        }
1268        if (!$config->{nodeps} && !$group->{options}{nodeps}) {
1269           $loop = check_deps($rpmd, $group, $done, $rpmlist, $list, $i, $tobedone->[$i], $buildlist, $rpm, $cdnum, $repname, $needed, $thisorderrep)
1270        }
1271        $loop and next; 
1272        log_("@$rpm deps ok\n", $config->{verbose}, $config->{LOG}, 4);
1273        my $nosrc = 1;
1274        my @srpm;
1275        my $donesrpm = 1;
1276        if (!$group->{options}{nosources} && @{$group->{list}{$list}{srpm}}) {
1277            for (my $s; $s < @$rpmd; $s++) {
1278                my $srpm = $group->{urpm}{sourcerpm}{$rpm->[$s]}; 
1279                $srpm =~ s/\.rpm$//;
1280                if (!$group->{size}{$srpm}{$list}) {
1281                    log_("put_in_rep ERROR: $srpm not available, trying alternatives => ", $config->{verbose}, $config->{LOG}, 5);
1282                    my ($srpmname) = $srpm =~ /(.*)-[^-]+-[^-]+\.src/;
1283                    $srpm = $group->{srpmname}{$srpmname};
1284                    if ($group->{size}{$srpm}{$list}) { 
1285                        log_(" $srpm\n", $config->{verbose}, $config->{LOG}) 
1286                    } else {
1287                        if ($srpm) {
1288                            log_("not found (but a srpm $srpm exist in another list)\n", $config->{verbose}, $config->{LOG}, 5);
1289                            $srpm = 0
1290                        } else {
1291                            log_("not found\n", $config->{verbose}, $config->{LOG}, 5) 
1292                        }
1293                    }
1294                }
1295                if ($srpm) { 
1296                    $done->{$srpm} or $donesrpm = 0;
1297                    $srpm[$s] = $srpm;
1298                    $rpmd->[$s][1]{nosrc} or $nosrc = 0 
1299                }
1300            }
1301        }
1302        log_("put_in_rep: group $i list $list: @$rpm (@srpm) -- $curdir->[0] -- $curdir->[1] -- disc $cdnum\n", $config->{verbose}, $config->{LOG}, 4);
1303        if ($config->{nosrc} || $group->{options}{nosources} || !@{$group->{list}{$list}{srpm}} || $nosrc || $donesrpm) {
1304            ($dn) = addRPMToDiff($rpm, $rpmd, $diff, $cdnum, $group->{orderedrep}{rpm}{"$cdnum/$repname"}, $i, $list, $curdir, $size, $rpmsize, $all_rpmsize, $rep_num, $done)
1305        } else {
1306            if ($config->{nosrcfit} || $group->{options}{nosrcfit}) {
1307                $dn = addRPMToDiff($rpm, $rpmd, $diff, $cdnum, $group->{orderedrep}{rpm}{"$cdnum/$repname"}, $i, $list, $curdir, $size, $rpmsize, $all_rpmsize, $rep_num, $done);
1308                push @$nosrcfit, [$rpmd, \@srpm, $list, $i, $curdir, $cdnum]
1309            } else {
1310                my ($srpmrep, $srpmsize, $srpmok) = sourcesSizeCheck($done, $rpmd, \@srpm, $group, $groups, $size, $cdsize, $list, $cdlists, $cdnum, $all_rpmsize, $buildlist, $cds, $i, $diff);
1311                if ($srpmok) {
1312                    addRPMToDiff($rpm, $rpmd, $diff, $cdnum, $group->{orderedrep}{rpm}{"$cdnum/$repname"}, $i, $list, $curdir, $size, $rpmsize, $all_rpmsize, $rep_num, $done);
1313                    $dn = addSRPMToDiff($rpmd, $done, $diff, $size, $srpmrep, $srpmsize, $curdir, \@srpm, $list, $i, $cdnum);
1314                } else {
1315                    log_("WARNING: @srpm does not fit on the discs\n",1, $config->{LOG}, 2)
1316                }
1317            }
1318            if (!$dn) {
1319                foreach my $p (@$rpm) { push @{$group->{rejected}{$p}}, ["no_space", ""] }
1320                log_("WARNING: @$rpm does not fit on the disc ($size->{disc}[$cdnum] + $all_rpmsize > $cdsize->[$cdnum]) \n", $config->{verbose}, $config->{LOG}, 1)
1321            }
1322        }
1323    }
1324    return $dn
1325}
1326
1327sub loop_on_lists {
1328    my ($i, $groups, $group, $groupok, $needed, $buildlist, $tobedone, $diff, $nosrcfit, $size, $cdsize, $cds, $rpmlist, $cdlists, $ok) = @_; 
1329    #
1330    # FIXME source rpms are not shared between group, it may be usefull for mutilple installation
1331    # with common source dir, so that the same source rpm is shared (but this is not so common).
1332    #
1333
1334    my $done = $group->{done};
1335    my $dn;
1336    log_("loop_on_lists: group $i (@{$group->{orderedlist}{rpm}})\n", $config->{verbose}, $config->{LOG}, 2);
1337    while (!$dn) {
1338        $groupok->[$i] = 1;
1339        foreach my $list (@{$group->{orderedlist}{rpm}}) {
1340            log_("loop_on_lists: list $list (empty $config->{list}[$list]{empty} done $config->{list}[$list]{done})\n", $config->{verbose}, $config->{LOG}, 3);
1341            do {
1342                $config->{list}[$list]{done} and goto end;
1343                $config->{list}[$list]{empty} and goto end;
1344                my $next;
1345                foreach (@{$needed->[$i]{$list}{asap}}) {
1346                    my $nb_elt = @{$buildlist->[$i]{$_->[0]}};
1347                    log_("List $list need list $_->[0] to be <= $_->[1] ($nb_elt)\n", $config->{verbose}, $config->{LOG}, 4);
1348                    $nb_elt <= $_->[1] or $next = 1
1349                }
1350                $next and log_("List $list waiting\n",1, $config->{LOG},4) and goto end;
1351                $needed->[$i]{$list}{asap} = [];
1352                my ($trpmd, $k, $goon, @rpmd);
1353                do { 
1354                    $trpmd = pop @{$buildlist->[$i]{$list}} or goto end;
1355                    if (ref $trpmd->[0]) {
1356                        foreach (@$trpmd) {
1357                            !$done->{$_->[0]} and push @rpmd, $_
1358                        }
1359                    } else { !$done->{$trpmd->[0]} and push @rpmd, $trpmd }
1360                } until @rpmd;
1361                $groupok->[$i] = 0;
1362                $ok = 0;
1363                my @rpm;
1364                my $all_rpmsize;
1365                my @rpmsize;
1366                foreach (@rpmd) {
1367                    my $r = $_->[0];
1368                    !$r and log_("ERROR loop_on_lists: empty package @$_\n", $config->{verbose}, $config->{LOG}, 2);
1369                    push @rpm, $r;
1370                    log_("RPM $r (group $i list $list)\n", $config->{verbose}, $config->{LOG},6);
1371                    $tobedone->[$i]{$r} = 1;
1372                    $all_rpmsize += $group->{size}{$r}{$list}[0];
1373                    push @rpmsize, $group->{size}{$r}{$list}[0]
1374                }
1375                $dn = put_in_rep($i, $groups, $group, $size, \@rpmsize, $all_rpmsize, $cdsize, $needed, \@rpm, \@rpmd, $list, $cdlists, $buildlist, $diff, $cds, $done, $tobedone, $rpmlist, $nosrcfit); 
1376            } while $group->{options}{sequential} && @{$buildlist->[$i]{$list}};
1377            end:
1378            last if $group->{options}{sequential} && @{$buildlist->[$i]{$list}} && !$config->{list}[$list]{done}
1379        } 
1380        $groupok->[$i] and $dn = 1
1381    }
1382    return $ok
1383}
1384
1385sub calc_needed_size {
1386    my ($group, $i, $needed, $needed_size, $buildlist, $rpmlist, $tobedone) = @_;
1387    my ($msg, %local_done);
1388    $msg = "calc_needed_size\n";
1389    my $done = $group->{done};
1390    foreach my $rep (@{$group->{replist}{rpm}}) {
1391        my ($cd, $repname, $num, $l) = @$rep;
1392        $msg .= "calc_needed_size: rep $num\n";
1393        foreach my $list (keys %$needed) {
1394            $l->{$list} or next;
1395            $config->{list}[$list]{disc}{$cd}{$repname}{done} and log_("calc_needed_size: rep $cd/$repname for list $list is done, ignoring\n", $config->{verbose}, $config->{LOG}, 5) and next;
1396            foreach my $elt (@{$needed->{$list}{alap}[$num]}) {
1397                my $rpm = $elt->[0];
1398                if ($done->{$rpm} || $local_done{$rpm}) {
1399                    next
1400                }
1401                if ($group->{rejected}{$rpm}) {
1402                    $msg .= "ERROR: $rpm is rejected, ignoring\n";
1403                    next
1404                }
1405                $msg .= "calc_needed_size: list $list rpm $rpm size $group->{size}{$rpm}{$list}[0]\n";
1406                $needed_size->[$num]{fix} += $group->{size}{$rpm}{$list}[0];
1407                $local_done{$rpm} = 1;
1408                # FIXME This following code is a simplified version of check_deps. It may be overkill to use
1409                # full check_deps as anyway check_deps will be used to put the package at the end.
1410                foreach (@{$group->{pkgdeps}{$rpm}}) {
1411                    if (ref $_) {
1412                        $local_done{"@$_"} and next;
1413                        $local_done{"@$_"} = 1;
1414                        my $r = choose_alt($_, $rpmlist->[$i], $group, $cd, $num, $list, $buildlist, $tobedone, $needed);
1415                        if ($r != -1 && $r != 0) {
1416                            next if $local_done{$r};
1417                            $needed_size->[$num]{var} += $group->{size}{$r}{$list}[0];
1418                        }
1419                    } else {
1420                        my $pkg = $group->{depslistid}[$_];
1421                        next if $done->{$pkg} || $local_done{$pkg};
1422                        $local_done{$pkg} = 1;
1423                        $needed_size->[$num]{var} += $group->{size}{$pkg}{$list}[0];
1424                    }
1425                }
1426            }
1427        }
1428    }
1429    log_($msg, $config->{verbose}, $config->{LOG}, 3)
1430}
1431
1432sub revert_to {
1433    my ($groups, $i, $p2r, $diff, $size, $buildlist) = @_;
1434    log_("revert_to: try to find $p2r\n", $config->{verbose}, $config->{LOG}, 3);
1435    foreach (@{$diff->{data}}) {
1436        $_ or next; 
1437        foreach (@{$_->[5]}) {
1438            goto revert_to_ok if $_->[0] eq $p2r
1439        } 
1440    }
1441    log_("ERROR revert_to: $p2r is not present in movement history\n", $config->{verbose}, $config->{LOG}, 2);
1442    return 0;
1443    revert_to_ok:
1444    log_("revert_to: $p2r found\n", $config->{verbose}, $config->{LOG}, 5);
1445    my @keep;
1446    my $idx;
1447    do {
1448        $idx = pop @{$diff->{idx}};
1449        goto revert_to_endloop if grep { $_->[0] eq $p2r } @{$diff->{data}[$idx][5]}; 
1450        my $step = $diff->{data}[$idx];
1451        if ($groups->[$i]{conflict}{$step->[1]}) {
1452            my ($curdir, $g, $list) = @$step;
1453            my $cdnum = $curdir->[0];
1454            foreach (@{$step->[5]}) { 
1455                my ($rpm,undef,undef, $rpmsize) = @$_; 
1456                delete $groups->[$g]{done}{$rpm}; 
1457                $diff->{data}[$idx] = 0;
1458                $size->{disc}[$cdnum] -= $rpmsize; 
1459                $size->{rep}{$cdnum}{$curdir->[1]}{$list} -= $rpmsize;
1460                log_("revert_to: reverting $rpm ID $idx for $p2r on cd $cdnum group $g list $list (cd size $size->{disc}[$cdnum])\n", $config->{verbose}, $config->{LOG}, 3)
1461            }
1462            push @{$buildlist->{$list}}, $step->[6] if $step->[4] == 1
1463        } else {
1464            unshift @keep, $idx;
1465        }
1466    } while @{$diff->{idx}};
1467revert_to_endloop:
1468    die "FATAL revert_to: diff data are empty\n" if ! @{$diff->{data}};
1469    push @{$diff->{idx}}, $idx, @keep;
1470    1
1471}
1472
1473sub mark_and_check_lists {
1474    my ($groups, $i, $needed, $diff, $buildlist, $rpmlist, $mark, $size, $cdsize, $ok, $tobedone) = @_;
1475    my @needed_size;
1476    my $group = $groups->[$i];
1477    my $need_to_calc;
1478    foreach my $list (@{$group->{orderedlist}{rpm}}) {
1479        ref $buildlist->{$list} or next;
1480        log_("mark_and_check_list: list $list\n", $config->{verbose}, $config->{LOG}, 3);
1481        $config->{list}[$list]{done} and log_("mark_and_check_lists: list $list is done, ignoring\n", $config->{verbose}, $config->{LOG}, 5) and next;
1482        if (defined $mark->{cur}{$list}) {
1483            $need_to_calc = 1;
1484            my $m = $mark->{cur}{$list};
1485            my $m_rpm = $m->[0];
1486            if ($group->{done}{$m_rpm}) {
1487                log_("mark_and_check_list: $m_rpm done, deleting mark for list $list\n", $config->{verbose}, $config->{LOG},4);
1488                push @{$mark->{his}}, $m;
1489                delete $mark->{cur}{$list}
1490            } elsif ($group->{rejected}{$m_rpm}) {
1491                log_("mark_and_check_list: $m_rpm rejected, deleting mark for list $list\n", $config->{verbose}, $config->{LOG},4);
1492                delete $mark->{cur}{$list}
1493            } elsif (!@{$buildlist->{$list}}) {
1494                log_("mark_and_check_list: list $list finished and $m_rpm not done or rejected\n",1, $config->{LOG},4)
1495            }
1496        }
1497        if (!defined $mark->{cur}{$list} && @{$buildlist->{$list}}) {
1498            my $rpm;
1499            for (my $i = $#{$buildlist->{$list}}; $i >= 0; $i--) {
1500                my $t = $buildlist->{$list}[$i];
1501                $rpm = ref $t->[0] ? $t->[0] : $t;
1502                if (!$group->{done}{$rpm->[0]}) {
1503                    last
1504                } 
1505                # this is not necessary, but when we are at it...
1506                pop @{$buildlist->{$list}}
1507            }
1508            $mark->{cur}{$list} = $rpm;
1509            log_("mark_and_check_list: marking $rpm->[0] for $list\n", $config->{verbose}, $config->{LOG},3);
1510        }
1511    }
1512    if ($need_to_calc || $ok) {
1513        calc_needed_size($group, $i, $needed, \@needed_size, $buildlist, $rpmlist, $tobedone);
1514        my ($need_in_rep, $av_in_rep, %done_disc);
1515        #
1516        # First impression would have been to check needed in reverse order, because we could imagine
1517        # that, in the current configuration, if needed 2 does not fit, for exemple, one package
1518        # is removed, needed 2 is put. But if needed does not fit at this moment, needed 2 is removed,
1519        # and needed 3 put, then needed 2 does not fit, and it is needed to revert more to make both of
1520        # them fit.
1521        #
1522        # If fact this could not happen, because if needed 3 does not fit when needed 2 has just been
1523        # put, this mean that the calc_needed_size if bogus.
1524        #
1525        foreach my $rep (@{$group->{replist}{rpm}}) {
1526            my ($cd,undef, $num) = @$rep;
1527            $need_in_rep += $needed_size[$num]{var} + $needed_size[$num]{fix};
1528            if (! $done_disc{$num}) {
1529                $av_in_rep += $cdsize->[$cd] - $size->{disc}[$cd];
1530                $done_disc{$num} = 1
1531            }
1532            log_("mark_and_check_list: rep $num need_in_rep $need_in_rep av_in_rep $av_in_rep needed_size $needed_size[$num]{fix} disc_av_space ($cdsize->[$cd] - $size->{disc}[$cd])\n", $config->{verbose}, $config->{LOG}, 4);
1533            if ($need_in_rep && $need_in_rep > $av_in_rep || $needed_size[$num]{fix} > $cdsize->[$cd] - $size->{disc}[$cd]) {
1534                log_("mark_and_check_list: not enough space for needed in rep $num on disc $cd\n", $config->{verbose}, $config->{LOG}, 3);
1535                pop @{$mark->{his}};
1536                my $p2r = pop @{$mark->{his}};
1537                log_("mark_and_check_list: trying to revert $p2r->[0]\n", $config->{verbose}, $config->{LOG}, 4);
1538                if (revert_to($groups, $i, $p2r->[0], $diff, $size, $buildlist)) {
1539                    log_("mark_and_check_list: $p2r->[0] reverted\n", $config->{verbose}, $config->{LOG}, 3);
1540                    foreach my $idx (0 .. @{$group->{orderedlist}{rpm}}) {
1541                        my $list = $group->{orderedlist}{rpm}[$idx];
1542                        $needed->{$list} or next;
1543                        my $elt;
1544                        foreach my $tr (1 .. $num) {
1545                            foreach my $elt (@{$needed->{$list}{alap}[$tr]}) {
1546                                my $rpm = $elt->[0];
1547                                if ($group->{rejected}{$rpm}) {
1548                                    log_("ERROR: $rpm is rejected, ignoring\n", $config->{verbose}, $config->{LOG}, 3);
1549                                    next
1550                                }
1551                                push @{$buildlist->{$list}}, $elt;
1552                            }
1553                        }
1554                        $mark->{cur}{$list} = $elt->[0];
1555                        my $l_idx = $#{$buildlist->{$list}};
1556                        next if $l_idx < 0;
1557                        foreach my $tidx ($idx + 1 .. @{$group->{orderedlist}{rpm}}) {
1558                            my $l = $group->{orderedlist}{rpm}[$tidx];
1559                            push @{$needed->{$l}{asap}}, [ $list, $l_idx ]
1560                        }
1561                    }
1562                } else {
1563                    log_("ERROR mark_and_check_list: reverting to $p2r->[0] failed\n", $config->{verbose}, $config->{LOG}, 4)
1564                }
1565               
1566            }
1567        }
1568    }
1569    return $ok
1570}
1571
1572# TODO the algo is not as beautiful as it should be
1573# ... but it is getting better
1574# ... and better
1575sub buildDiscs {
1576    my ($class, $groups, $buildlist, $rpmlist, $groupok, $size, $cdsize, $cdlists, $cds, $needed, $diff, $n) = @_;
1577    log_("buildDiscs\n", $config->{verbose}, $config->{LOG}, 3);
1578    $config = $class->{config};
1579    if ($n > 1) {
1580        foreach my $i (reverse @$cds) {
1581            $size->{optimize_space}{disc}{$i} = $size->{disc}[$i];
1582            if ($size->{disc}[$i] > $cdsize->[$i]) { 
1583                my $gain = ($size->{disc}[$i] - $cdsize->[$i])/2;
1584                next if $gain < 0;
1585                optimize_space($config, $groups, $diff, $size, $cdsize, $i, $gain, $cdlists,1)
1586            } else {
1587                log_("buildDiscs: disc $i size OK $size->{disc}[$i] ($cdsize->[$i])\n", $config->{verbose}, $config->{LOG},2)
1588            }
1589        }
1590    }
1591    my ($ok, $iti);
1592    my @groupok;
1593    my (@tobedone, @nosrcfit);
1594    my @mark = ({}) x @$groups;
1595    updateGenericLimit($groups, $cdsize);
1596    while (!$ok) {
1597        log_("iti: " . $iti++ . "\n", $config->{verbose}, $config->{LOG},4);
1598        $ok = 1;
1599        for (my $i = 0; $i < @$groups; $i++) {
1600            my $group = $groups->[$i];
1601            if (!$config->{fast}) {
1602                $groupok[$i] = mark_and_check_lists($groups, $i, $needed->[$i], $diff, $buildlist->[$i], $rpmlist, $mark[$i], $size, $cdsize, $groupok[$i], $tobedone[$i]);
1603                $groupok[$i] and next;
1604            }
1605            $ok = loop_on_lists($i, $groups, $group, \@groupok, $needed, $buildlist, \@tobedone, $diff, \@nosrcfit, $size, $cdsize, $cds, $rpmlist, $cdlists, $ok); 
1606        }
1607    }
1608    foreach (@nosrcfit) {
1609        my ($rpmd, $srpm, $list, $i, $curdir, $cdnum) = @$_;
1610        my $group = $groups->[$i];
1611        my $done = $group->{done};
1612        my ($srpmrep, $srpmsize, $srpmok) = sourcesSizeCheck($done, $rpmd, $srpm, $group, $groups, $size, $cdsize, $list, $cdlists,0,0, $buildlist, $cds, $i, $diff);
1613        if ($srpmok) {
1614            addSRPMToDiff($rpmd, $done, $diff, $size, $srpmrep, $srpmsize, $curdir, $srpm, $list, $i, $cdnum);
1615        } else {
1616            log_("WARNING: @$srpm does not fit on the discs\n",1, $config->{LOG},2)
1617        }
1618    }
1619    my $is_rejected;
1620    log_("buildDiscs: rejected packages\n", $config->{verbose}, $config->{LOG},2);
1621    for (my $i; $i < @$groups; $i++) {
1622        $groups->[$i]{rejected} or next;
1623        my $gh = $groups->[$i]{rejected};
1624        foreach (keys %$gh) {
1625            if (!$is_rejected) {
1626                $is_rejected = 1 if grep { $_->[0] =~ /no_disc/ || $_->[0] =~ /no_space/ } @{$gh->{$_}};
1627            }
1628            log_("WARNING buildDisc: group $i REJECTED $_ (",1, $config->{LOG},2);
1629            ref $groups->[$i]{rejected}{$_} and log_((join ',', map { "$config->{rejected_options}{$_->[0]}: $_->[1]" } @{$groups->[$i]{rejected}{$_}}),1, $config->{LOG},2);
1630            log_(")\n",1, $config->{LOG});
1631        }
1632    }
1633    ($is_rejected)
1634}
16351
1636
1637# Changelog
1638#
1639# 2002 02 21
1640# change false $j comparaison to $depsdisc in buildDisc to new $thisorderrep value.
1641#
1642# 2002 03 03
1643# new limit option handling.
1644# add updateGenericSoft function
1645# add testSoftLimit function
1646# update size to check rep size
1647#
1648# 2002 03 08
1649# fix autoMode CD adding
1650#
1651# 2002 03 13
1652# better selection of alternatives in multi-list to take the one in the first lists.
1653#
1654# 2002 03 14
1655# add sources new sources handling method
1656# in nosrcfit mode sources are added afterwards
1657#
1658# 2002 03 19
1659# add prelist in geList for cdcom, will be useful for oem too I guess.
1660#
1661# 2002 05 02
1662# add_one_disc: add separate mode for sources mode
1663#
1664# 2002 05 09
1665# add graft structure for md5 and graft point handling
1666#
1667# 2002 05 13
1668# fix a tricky bugs in build_list about fentry shared and not recreated for each packages.
1669#
1670# 2002 06 01
1671# use perl-URPM
1672#
1673# 2002 06 15
1674# new diff mode, global, shared between disc and group, only one table.
1675#
1676# 2002 08 16
1677# new diff_idx table to sort diff data
1678#
1679# 2002 08 24
1680# optimize_space first version, still need to handle correctly needed and more advanced optimization methods.
1681#
1682# 2002 09 18
1683# optimize_space work, fixes and updates.
1684#
1685# 2002 10 25
1686# fix needed assignation pb in closeRPMslist
Note: See TracBrowser for help on using the repository browser.