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