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

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

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

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