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