package Mkcd::List; my $VERSION = '0.3.4'; use strict; use File::NCopy qw(copy); use Mkcd::Package qw(rpmVersionCompare); =head1 NAME List - mkcd module =head1 SYNOPSYS require Mkcd::List; =head1 DESCRIPTION C include the mkcd packages list functions. =head1 SEE ALSO mkcd =head1 COPYRIGHT Copyright (C) 2000 MandrakeSoft This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =cut my $config; sub new { my ($class, $conf) = @_; $config = $conf; bless { config => $config, }, $class; } sub processDiff { my ($class,$groups, $diff, $log, $discsFiles) = @_; my @cd; for(my $cd; $cd < @$diff; $cd++){ my $dc = $diff->[$cd]; $dc or next; for(my $grp; $grp < @$dc; $grp++){ my $dcg = $dc->[$grp]; $dcg or next; for (my $list; $list < @{$dcg}; $list++){ my $dcgl = $dcg->[$list]; $dcgl or next; for (my $rep ; $rep < @{$dcgl}; $rep++){ my $dcglr = $dcgl->[$rep]; $dcglr or next; for (my $type ; $type < @{$dcglr}; $type++){ my $dcglrt = $dcglr->[$type]; $dcglrt or next; for (my $i; $i < @{$dcglrt}; $i++){ my $ent = $dcglrt->[$i]; $log and push @{$log->[$cd][$grp][$list][$rep][$type]}, $ent; my $rpm = $ent->[0]; my $curdir = $ent->[3]; $config->{verbose} and print {$config->{LOG}} "LOG disc $cd group $grp: $rpm ($groups->[$grp]{size}{$rpm}{$list}[1])\n"; if (!$rpm) { foreach (@$ent){ if (ref) { print {$config->{LOG}} "ERROR processDiff: @$_\n" } else { print {$config->{LOG}} "ERROR processDiff: $_\n" } } } $rpm or next; my $source = $groups->[$grp]{size}{$rpm}{$list}[1]; push @{$cd[$cd]{$curdir->[1]}{$list}{$source}}, [$ent->[1],"$groups->[$grp]{rpmkey}{rpm}{$rpm}.rpm"]; if ($ent->[1] == 1) { $discsFiles->[$cd]{$curdir->[1]}{$list}{$groups->[$grp]{rpmkey}{rpm}{$rpm}} = $source } # FIXME may need to delete upper hash if empty elsif ($ent->[1] == 2) { delete $discsFiles->[$cd]{$curdir->[1]}{$list}{$groups->[$grp]{rpmkey}{rpm}{$rpm}} } } } } } } } return \@cd } sub getDoneList{ my ($config,$group, $listnumber, $discsFiles) = @_; if (@{$group->{list}{$listnumber}{rpm}} > 1) { print "WARNING getDoneList: $listnumber appears in several directories, getting only the first one\n"} if (@{$group->{list}{$listnumber}{srpm}} > 1) { print "WARNING getDoneList: $listnumber appears in several sources directories, getting only the first one\n"} my $r = $group->{list}{$listnumber}{rpm}[0]; my $rs = $group->{list}{$listnumber}{srpm}[0]; my ($cd,$rep) = ($r->[0],$r->[1]); my ($scd,$srep) = ($rs->[0],$rs->[1]); foreach my $r (@{$config->{list}[$listnumber]{packages}}){ $config->{verbose} and print {$config->{LOG}} "getDoneList: $listnumber (@$r)\n"; local *A; opendir A, $r->[0]; foreach (readdir A){ /src.rpm$/ and next; /(.*)\.rpm/ or next; my $rpm = $group->{rpmkey}{key}{$1}; $group->{done}{$rpm} = $group->{orderedrep}{rpm}{"$cd/$rep"}; $discsFiles->[$cd]{$rep}{$listnumber}{$1} = $r->[0] } local *A; opendir A, $r->[1]; foreach (readdir A){ /(.*src)\.rpm/ or next; my $srpm = $group->{rpmkey}{key}{$1}; $group->{done}{$srpm} = 1; $discsFiles->[$scd]{$srep}{$listnumber}{$1} = $r->[1] } } # # FIXME this may be better placed in the function setting the list as done, that is to say # for example in cdcom or like. # $config->{list}[$listnumber]{disc}{$cd}{$rep}{done} = 1; $config->{list}[$listnumber]{disc}{$scd}{$srep}{done} = 1; } sub getList{ my ($class, $group,$discsFiles) = @_; my $config = $class->{config}; my %filelist; my @norpmsrate; foreach my $listnumber (keys %{$group->{list}}){ my $done = $config->{list}[$listnumber]{done}; $done and getDoneList($config,$group, $listnumber,$discsFiles); if ($config->{list}[$listnumber]{filelist}){ foreach (@{$config->{list}[$listnumber]{filelist}}){ $config->{verbose} and print {$config->{LOG}} "getList: FILE LIST listnumber $listnumber ($_)\n"; local *A; open A, $_ or print {$config->{LOG}} "ERROR: cannot open $_, ignoring\n" and next; local $_; while (){ s/#.*//; $_ or next; my ($name, $options) = /(\S*)\s*(.*)/; my @options = split ',',$options; $config->{verbose} and print {$config->{LOG}} "FILESLIST: $_ -> $name options @options\n"; my %opt; foreach (@options){ s/^\s*//; /norpmsrate/ and push @norpmsrate, $name and next; /^(?:(?:nosrc|noalternatives|regexp|ignore|nodeps|force|limit|section|exclude)|(rate|notondisc) (\d+))$/ or print {$config->{LOG}} "WARNING: getList: $_: unknown option\n" and next; $_ = $1 || $_; $opt{$_} = $2 || 1; } $config->{verbose} and print {$config->{LOG}} "Adding $name -- ", join ' ', keys %opt, "\n"; push @{$filelist{$listnumber}}, [$name,\%opt]; } } }else{ if (!$done && $config->{list}[$listnumber]{auto}){ push @{$filelist{$listnumber}}, ["INSTALL",{ section=>1, force => 1 }]; push @{$filelist{$listnumber}}, ["SYSTEM",{ section=>1, force => 1 }]; push @{$filelist{$listnumber}}, [".*",{ regexp => 1 }] } # else{ # push @{$filelist{$listnumber}}, [".*",{ done => $done, regexp => 1, force => $done }] # } } my $listdone = 1; foreach my $r (@{$group->{list}{$listnumber}{rpm}}){ my ($cd,$rep,$repopt,$opt) = @$r; if ($config->{list}[$listnumber]{disc}{$cd}{$rep}{done}){ if (!$opt->{dup}){ foreach my $rpmkey (keys %{$discsFiles->[$cd]{$rep}{$listnumber}}){ my $rpm = $group->{rpmkey}{key}{$rpmkey}; $group->{done}{$rpm} = $group->{orderedrep}{rpm}{"$cd/$rep"}; $config->{verbose} and print {$config->{LOG}} "getList: $rpm in $cd/$rep -> $group->{done}{$rpm}\n"; push @{$filelist{$listnumber}}, [$rpm,{ done => 1, regexp => 1, force => 1, udpate => $r->[2]{update}}]; } } }else { $listdone = 0 } } $listdone and print {$config->{LOG}} "getList: setting list $listnumber as done\n" and $config->{list}[$listnumber]{done} = 1; } (\%filelist,\@norpmsrate) } # # compute individual scoring (max_size*(rpmsrate+1)*rpmsrate_factor/(size*size_factor)) # then add dependencies sons score ( score + deps_factor*(sons_score) # # special rpmsrate groups score could be added in the rpmsrate value # # FIXME current scoring rules make size only significant for equaly dependent packages, # dependencies get far more importance for packages a lot of packages depend on. # # Size scoring could be added afterwards, but this will break the autodeps created with # this scheme. # # TODO # add scoring rules to include srpm size in score. # # sub scoreList{ my ($class,$group) = @_; my $scoreweight = $group->{score}; my $params = $group->{params}; my $rpmsrate = $group->{rpmsrate}; my $maxsize = $group->{maxsize} || 1; $config->{verbose} and print {$config->{LOG}} "SCORE for group: @$scoreweight\n"; $config->{verbose} and print {$config->{LOG}} "Individual scoring\n"; my $sf; my $i; my $total; my (@min,@max); if ($scoreweight->[1]){ (@min,@max) = (($maxsize*$scoreweight->[0]*6/($scoreweight->[1]*1),0),(0,0)) }else{ (@min,@max) = (($maxsize*$scoreweight->[0]*6,0),(0,0)) } my @specialdeps; foreach (keys %{$params->{info}}){ #print "INFO KEYS $_\n"; my ($ratekey) = /(.*)-[^-]+-[^-]+\.[^.]+$/; # FIXME take the bigger size when package appears in multiple lists my $size; foreach my $list (keys %{$group->{size}{$_}}){ $size < $group->{size}{$_}{$list}[0] and $size = $group->{size}{$_}{$list}[0] } $size or print {$config->{LOG}} "ERROR: $_ has zero size\n" and next; my $s; my $rate = $group->{brokendeps}{$_} ? 0 : (defined $group->{pkgrate}{$_} ? $group->{pkgrate}{$_}: $rpmsrate->[0]{$ratekey}); if ($scoreweight->[1]) { $sf = ($size*9)/$maxsize + 1; # from 1 to 10 $s = $scoreweight->[0]*($rate + 1)/($scoreweight->[1]*$sf); } else { $s = $scoreweight->[0]*($rate + 1); } $group->{scorelist}{$_} = $s; ($s < $min[0]) and @min = ($s,$_); ($s > $max[0]) and @max = ($s,$_); $config->{verbose} and print {$config->{LOG}} "SCORE package $_: $s (rpmsrate ($ratekey): $rate, sf: $sf)\n"; $total+=$s; $i++ } $i and print {$config->{LOG}} "minimal $min[0] ($min[1]), maximal $max[0] ($max[1]), average ",$total/$i,"\n"; 1 } sub autodeps{ my ($class,$group, $rpmlist) = @_; my $scoredeps = $group->{score}[2]; $scoredeps or print {$config->{LOG}} "autodeps: deps score is null, bypassing autodeps\n" and return 1; $config->{verbose} and print {$config->{LOG}} "autodeps: compute reversed depslist.ordered ($scoredeps)\n"; my $revDeps = $group->{revdeps}; my %rpm; foreach my $k (keys %{$rpmlist}){ foreach (keys %{$rpmlist->{$k}}) { $rpm{$_} = $rpmlist->{$k}{$_} }} # FIXME this algo is not correct for (my $i = @{$group->{params}{depslist}} - 1 ; $i >= 0; $i--){ my $rpm = $group->{depslistid}[$i]; $rpm{$rpm} or print {$config->{LOG}} "autodeps: ignoring $rpm\n" and next; if ($rpm{$rpm}{ignore}) { print {$config->{LOG}} "autodeps: $rpm has ignore flag, do not add deps score\n"; next } foreach (@{$revDeps->[$i]}){ $group->{scorelist}{$rpm} += $scoredeps*$group->{scorelist}{$group->{depslistid}[$_]}; } } 1 } sub reverseDepslist{ my ($class,$group) = @_; my $depslist = $group->{params}{depslist}; my $locales = $group->{lang}; my @revdeps; my %skip; $config->{verbose} and print {$config->{LOG}} "reverseDepslist\n"; for (my $i; $i < @$depslist; $i++){ my $d = $depslist->[$i]; my $rpm = "$d->{name}-$d->{version}-$d->{release}.$d->{arch}"; $group->{depslistid}[$i] = $rpm; my %rev; foreach ( split (' ', $d->{deps})){ if (!$group->{options}{nodeps} && !$class->{config}->{nodeps} && /NOTFOUND_(\S*)/) { $skip{$i} = 1; $group->{brokendeps}{$rpm} = 2; push @{$group->{missingdeps}{$rpm}}, $1; print {$config->{LOG}} "WARNING: $rpm has unresolved dependencies ($1), ignored\n"; next } if (/\|/) { my $s = [split '\|', $_]; push @{$group->{pkgdeps}{$rpm}}, $s; foreach (@$s) { $skip{$_} or push @{$revdeps[$_]}, $i } } else { if ($locales && $group->{depslistid}[$_] =~ /locales-([^-]+)-[^-]+-[^-]+\.[^.]+/){ if (!$locales->{$1}){ $config->{verbose} and print {$config->{LOG}} "reverseDepslist: locale $1 ($group->{depslistid}[$_]) skipped for $rpm\n" and $skip{$i} = 1; !$group->{brokendeps}{$rpm} and $group->{brokendeps}{$rpm} = 1 } } push @{$group->{pkgdeps}{$rpm}}, $_; $skip{$_} or push @{$revdeps[$_]}, $i; } } } return \@revdeps } sub closeRpmsList{ my ($group,$rpmfile) = @_; my $n=1; my %done; my %doneName; my %alternatives; while ($n){ $n = 0; foreach my $listnumber (@{$group->{orderedlist}{rpm}}){ foreach my $rpm (keys %{$rpmfile->{$listnumber}}){ if (!$group->{options}{dup}){ my ($name,$version,$release,$arch) = $rpm =~ /^(.*)-([^-]+)-([^-]+)\.([^.]+)$/; if ($doneName{$name}){ if (!($doneName{$name}[0] eq "$version-$release.$arch")){ print {$config->{LOG}} "WARNING closeRpmsList: $name-$version-$release.$arch duplicated with $doneName{$name}[0]\n"; my ($v,$r,$a) = @{$doneName{$name}[1]}; my $todel; my $vers; my $ret = rpmVersionCompare($rpm,"$name-$v-$r.$a"); if ($ret < 0){ $todel = $rpm; $vers = [$v,$r,$a] }elsif ($ret > 0){ $todel = "$name-$v-$r.$a"; $vers = [$version,$release,$arch] }else{ print {$config->{LOG}} "ERROR closeRpmsList: oops, something not possible happened in duplicate version comparaison ($rpm and $name-$v-$r.$a)\n"; } if ($todel){ $config->{verbose} and print {$config->{LOG}} "closeRpmsList: deleting $todel\n"; $doneName{$name} = [ "$vers->[0]-$vers->[1].$vers->[2]", $vers]; $group->{brokendeps}{$todel} = 3; delete $rpmfile->{$listnumber}{$todel}; $todel eq $rpm and next } $n = 1 } }else{ $doneName{$name} = [ "$version-$release.$arch",[$version,$release,$arch]] } } if ($group->{brokendeps}{$rpm} == 2 || $group->{brokendeps}{$rpm} == 3){ $config->{verbose} and print {$config->{LOG}} "closeRpmsList: deleting $rpm (list $listnumber)\n"; $rpmfile->{$listnumber}{$rpm} = undef; delete $rpmfile->{$listnumber}{$rpm}; $n = 1; next } $done{$rpm} and next; $rpmfile->{$listnumber}{$rpm}{nodeps} and next; my $force; ($rpmfile->{$listnumber}{$rpm}{done} || $rpmfile->{$listnumber}{$rpm}{force}) and $force = 0; foreach (@{$group->{pkgdeps}{$rpm}}){ /NOTFOUND_(.*)/ and print {$config->{LOG}} "ERROR closeRpmsList: $1 not provided\n" and next; my $rpmdep; my $rpmdeplist; my $specialrpmdep; if (ref){ if ($alternatives{"@$_"}) { ($rpmdep, $rpmdeplist) = @{$alternatives{"@$_"}}; } if (! ref $rpmfile->{$rpmdeplist}{$rpmdep}){ ($rpmdep, $rpmdeplist) = (undef,undef); # FIXME this is wrong, package can come from any list my @score = ($group->{maxlist}{rpm},int @{$group->{list}{$listnumber}{rpm}},$group->{maxsize}); my @specialscore = (int @{$group->{list}{$listnumber}{rpm}},$group->{maxsize}); $config->{verbose} and print {$config->{LOG}} "closeRpmsList: $rpm @$_ (maxscore @score) alternative\n"; foreach (@$_) { my $pkg = $group->{depslistid}[$_]; print {$config->{LOG}} "closeRpmsList: trying $pkg (brokendeps $group->{brokendeps}{$pkg})\n"; $group->{brokendeps}{$pkg} == 2 and next; $group->{brokendeps}{$pkg} == 3 and next; my $pkglist = findList($group,$pkg,$listnumber); $pkglist or print "closeRpmsList: $pkg list could not be used for $rpm dependencies\n" and next; $config->{verbose} and print {$config->{LOG}} "closeRpmsList: list $pkglist rpmfile $rpmfile->{$pkglist}{$pkg}\n"; if ($rpmfile->{$pkglist}{$pkg}){ $rpmfile->{$pkglist}{$pkg}{limit} and next; $rpmfile->{$pkglist}{$pkg}{noalternatives} and next; } my $rep = $group->{size}{$pkg}{$pkglist}[2]; my $s = $group->{size}{$pkg}{$pkglist}[0]; my $l = $group->{listsort}{rpm}{$pkglist}; $config->{verbose} and print {$config->{LOG}} "\t$pkg ($l,$rep,$s) (@score)\n"; # also put an alternative from this list if ($pkglist == $listnumber){ if ($rep < $specialscore[1]){ @specialscore = ($rep,$s); $specialrpmdep = $pkg; }elsif ($rep == $specialscore[1] && $s < $specialscore[2]){ @specialscore = ($rep,$s); $specialrpmdep = $pkg; } } if ($l < $score[0]){ @score = ($l,$rep,$s); $rpmdep = $pkg; $rpmdeplist = $pkglist; $config->{verbose} and print {$config->{LOG}} "1 $rpmdep -- $rpmdeplist -- $l,$rep,$s\n"; }elsif ($l == $score[0]){ if ($pkglist == $listnumber){ if ($rep < $score[1]){ @score = ($l,$rep,$s); $rpmdep = $pkg; $rpmdeplist = $pkglist; $config->{verbose} and print {$config->{LOG}} "2 $rpmdep -- $rpmdeplist -- $l,$rep,$s\n"; }elsif ($rep == $score[1] && $s < $score[2]){ @score = ($l,$rep,$s); $rpmdep = $pkg; $rpmdeplist = $pkglist; $config->{verbose} and print {$config->{LOG}} "3 $rpmdep -- $rpmdeplist -- $l,$rep,$s\n"; } }elsif ($s < $score[2]){ @score = ($l,$rep,$s); $rpmdep = $pkg; $rpmdeplist = $pkglist; $config->{verbose} and print {$config->{LOG}} "4 $rpmdep -- $rpmdeplist -- $l,$rep,$s\n"; } } } if ($rpmdep && $rpmdeplist){ $config->{verbose} and print {$config->{LOG}} "\tResult:\t$rpmdep\n"; $alternatives{"@$_"} = [ $rpmdep, $rpmdeplist ] }else{ print {$config->{LOG}} "WARNING: $rpm has unresolved or excluded dependencies, removed\n"; print {$config->{LOG}} "closeRpmsList: deleting $rpm (list $listnumber)\n"; delete $rpmfile->{$listnumber}{$rpm}; $n = 1; $group->{brokendeps}{$rpm} = 2 } } } else { # TODO verify that there is no need to do $rpmfile->{$pkglist}{$rpmdep} or brokendeps; $rpmdep = $group->{depslistid}[$_]; $rpmdeplist = findList($group,$rpmdep,$listnumber); } if ($rpmdep){ if (!$rpmdeplist || $group->{brokendeps}{$rpmdep} == 2 || $group->{brokendeps}{$rpmdep} == 3){ $group->{brokendeps}{$rpm} = $group->{brokendeps}{$rpmdep}; $n = 1; print {$config->{LOG}} "WARNING closeRpmsList: $rpm has unresolved or excluded dependencies ($rpmdep), removed\n"; print {$config->{LOG}} "closeRpmsList: deleting $rpm (list $listnumber)\n"; delete $rpmfile->{$listnumber}{$rpm}; next } if (! ref $rpmfile->{$rpmdeplist}{$rpmdep}){ $n = 1; $config->{verbose} and print {$config->{LOG}} "closeRpmsList: ADDED $rpmdep (list $rpmdeplist)\n"; $rpmfile->{$rpmdeplist}{$rpmdep} = { force => $force } } } if ($specialrpmdep){ if (! ref $rpmfile->{$listnumber}{$specialrpmdep}){ $n = 1; $config->{verbose} and print {$config->{LOG}} "closeRpmsList: ADDED $specialrpmdep (list $listnumber)\n"; $rpmfile->{$listnumber}{$specialrpmdep} = { force => $force } } } } $done{$rpm} = 1; } $config->{verbose} and print {$config->{LOG}} "closeRpmsList: $listnumber {$n}\n"; } } } # TODO must merge the regexp code with this one sub addRPMToList{ my ($group,$listnumber,$rpmfile,$done,$rpms,$fentry,$name) = @_; $name =~ s/\+/\\+/g; my @toadd; if ($fentry->{regexp}) { @toadd = grep { /$name/ } @$rpms } else { @toadd = grep { /^$name-[^-]+-[^-]+\.[^.]*$/ } @$rpms } $config->{verbose} and print {$config->{LOG}} "addRPMToList: toadd $name (regexp $fentry->{regexp}) (@toadd)\n"; if ($fentry->{done}){ foreach (@toadd){ my ($pkg) = /^(.*)-[^-]+-[^-]+\.[^.]*$/; $rpmfile->{$listnumber}{$_} = $fentry; $done->{$pkg} = [ $_, $group->{size}{$_}{$listnumber}[2], $fentry, $listnumber ]; $config->{verbose} and print {$config->{LOG}} "addRPMToList: ADDED $_ (list $listnumber)\n" } return } my %pkg; if ($fentry->{regexp}) { foreach (@toadd){ $_ or print {$config->{LOG}} "ERROR addRPMToList: empty rpm\n" and next; $group->{size}{$_}{$listnumber} or next; $group->{brokendeps}{$_} == 2 and next; $group->{brokendeps}{$_} == 3 and next; my ($pkgname) = /^(.*)-[^-]+-[^-]+\.[^.]*$/; $done->{$_} and next; my $rep = $group->{size}{$_}{$listnumber}[2]; $fentry->{exclude} and print {$config->{LOG}} "addRPMToList: excluding $_\n" and $group->{brokendeps}{$_} = 3 and next; if ($done->{$pkgname} && $done->{$pkgname}->[3] == $listnumber){ if (!$fentry->{update} || !$done->{$pkgname}[2]{done}){ if ($rep < $done->{$pkgname}->[1]){ $pkg{$done->{$pkgname}->[0]} = 0; $config->{verbose} and print {$config->{LOG}} "REPLACING $done->{$pkgname}->[0] with $_ (list $listnumber)\n"; $pkg{$_} = 1; $done->{$pkgname} = [ $_, $rep, $fentry, $listnumber ]; $done->{$_} = 1 }elsif ($done->{$pkgname}->[1] == $rep){ if (rpmVersionCompare($done->{$pkgname}->[0],$_) < 0){ $pkg{$done->{$pkgname}->[0]} = 0; $config->{verbose} and print {$config->{LOG}} "REPLACING $done->{$pkgname}->[0] with $_ (list $listnumber)\n"; $pkg{$_} = 1; $done->{$pkgname} = [ $_, $rep, $fentry, $listnumber ]; $done->{$_} = 1 } } } }else{ $pkg{$_} = 1; $done->{$pkgname} = [ $_, $rep, $fentry, $listnumber ]; $done->{$_} = 1 } } }else{ my $rep; my $pkg; # FIXME present algorythm selects only one package per version, and choose the one in the list declared first. # Maybe adding all the version and letting closeRRPMsList choose the right one is better. foreach (@toadd){ $_ or print {$config->{LOG}} "ERROR addRPMToList: empty rpm\n" and next; $group->{size}{$_}{$listnumber} or next; $group->{brokendeps}{$_} == 2 and next; $group->{brokendeps}{$_} == 3 and next; $fentry->{exclude} and print {$config->{LOG}} "addRPMToList: excluding $_\n" and $group->{brokendeps}{$_} = 3 and next; if ($group->{size}{$_}{$listnumber}[2] < $rep || !$rep) { $rep = $group->{size}{$_}{$listnumber}[2]; print {$config->{LOG}} "addRPMToList: choosing $_ (rep $rep)\n"; $pkg = $_ }elsif ($group->{size}{$_}{$listnumber}[2] == $rep){ if (rpmVersionCompare($pkg,$_) < 0){ $rep = $group->{size}{$_}{$listnumber}[2]; print {$config->{LOG}} "addRPMToList: choosing $_ (rep $rep)\n"; $pkg = $_ } } } my ($pkgname) = $pkg =~ /^(.*)-[^-]+-[^-]+\.[^.]*$/; if (!$done->{$pkgname}) { $pkg{$pkg} = 1; $done->{$pkgname} = [ $pkg, $rep, $fentry, $listnumber ]; $done->{$pkg} = 1 } } $fentry->{exclude} and return 1; foreach (keys %pkg){ $pkg{$_} or next; defined $fentry->{rate} and $group->{pkgrate}{$_} = $fentry->{rate} and print {$config->{LOG}} "addRPMToList: setting $_ rate to $fentry->{rate}\n"; $rpmfile->{$listnumber}{$_} = $fentry; $config->{verbose} and print {$config->{LOG}} "addRPMToList: ADDED $_ (list $listnumber)\n" } } sub buildList{ my ($class,$group) = @_; my %rpmfile; my $filelist = $group->{filelist}; my @fullrpm = (keys %{$group->{params}{info}}); my @section = (keys %{$group->{rpmsrate}[1]}); my %done; foreach my $listnumber (keys %{$group->{list}}){ my $rpms = $group->{listrpm}{$listnumber}; if (ref $rpms){ print {$config->{LOG}} "$listnumber -- $group->{filelist} -- ", keys %{$group->{filelist}},"\n"; ref $filelist->{$listnumber} or print {$config->{LOG}} "WARNING: list $listnumber has an empty file list\n" and next; $config->{verbose} and print {$config->{LOG}} "buildList: FILE LIST $listnumber (", int @{$filelist->{$listnumber}},")\n"; foreach my $fentry (@{$filelist->{$listnumber}}){ my $name = $fentry->[0]; my $opt = $fentry->[1]; $config->{verbose} and print {$config->{LOG}} "buildList: processing $name ", join ' ', keys %{$opt},"\n"; my @toadd; if ($opt->{section}){ $opt->{section} = 0; if ($opt->{regexp}){ @toadd = grep {/$name/} @section; foreach (@toadd){ foreach (@{$group->{rpmsrate}[1]{$_}}){ addRPMToList($group,$listnumber,\%rpmfile,\%done,$rpms,$opt,$_); } } }else{ my $rpmlist = $group->{rpmsrate}[1]{$name} or print {$config->{LOG}} "ERROR buildList: $name unknown rpmsrate section\n" and next; foreach (@$rpmlist){ addRPMToList($group,$listnumber,\%rpmfile,\%done,$rpms,$opt,$_); } } }else{ addRPMToList($group,$listnumber,\%rpmfile,\%done,$rpms,$opt,$name); } } }else{ print {$config->{LOG}} "WARNING: List $listnumber is empty, ignoring\n"; $class->{config}->{list}[$listnumber]{empty} = 1; } } if (!$class->{config}->{nodeps} && !$group->{options}{nodeps}){ my @toadd = grep { /^basesystem-[^-]+-[^-]+\.[^.]*$/ } @fullrpm; my $rep; my $pkg; my $listnumber; foreach (@toadd){ # FIXME need to select default list in a better way my $l; foreach $l (keys %{$group->{size}{$_}}){ if ($l == $listnumber && $group->{size}{$_}{$listnumber}[2] < $rep || !$rep){ $rep = $group->{size}{$_}{$listnumber}[2]; $pkg = $_; $listnumber = $l } } $listnumber or $listnumber = $l } if ($pkg){ $rpmfile{$listnumber}{$pkg} = {}; print {$config->{LOG}} "B ADDED $pkg \n" }else { print {$config->{LOG}} "ERROR: basesystem package is not available.\n"} # add deps closeRpmsList($group,\%rpmfile) } \%rpmfile } sub optimizeSpace{ my ($groups,$log,$diff,$size,$cdsize,$cdnum,$gain,$grp,$cdlists,$list) = @_; my $maxSpace; return 0; for(my $i; $i < @$cdsize; $i++){ $cdlists->{$i} or next; $maxSpace += $cdsize->[$i] - $size->{disc}[$i] } if ($maxSpace < $gain) { print {$config->{LOG}} "Could not get $gain on disc $cdnum\n"; return 0} else { print {$config->{LOG}} "$maxSpace available, try to move packages to get $gain free space on disc $cdnum\n"} if ($list){ my %cd; my $space; my $group = $groups->[$grp]; my @cd; for (my $j; $j < @{$group->{list}{$list}{srpm}}; $j++){ my $cd = $group->{list}{$list}[$j][0]; $cd{$cd} = 1; $space += $cdsize->[$cd] - $size->{disc}[$cd] } my $ok; for (my $j; $j < @{$group->{list}{$list}{rpm}}; $j++){ my $cd = $group->{list}{$list}[$j][0]; $space += $cdsize->[$cd] - $size->{disc}[$cd]; if ($cd{$cd}){ $ok = 1; push @cd, $cd } } if ($ok && $space >= $gain){ print {$config->{LOG}} "optimizeSpace: trying to gain $gain within group\n"; foreach (@cd){ } } } 0 } sub addRPMToDiff{ my ($rpm,$srpm,$rpmd,$diff,$cdnum,$repnumber, $i, $list, $curdir, $size, $rpmsize,$totrpmsize,$j, $done) = @_; my @interdeps; for (my $s; $s < @$rpm; $s++){ push @{$diff->[$cdnum][$i][$list][$j][0]}, [$rpm->[$s],1,$rpmd->[$s],$curdir,$rpmsize->[$s]]; my $id = @{$diff->[$cdnum][$i][$list][$j][0]}; print {$config->{LOG}} "addRPMToDiff: $rpm->[$s] DONE on CD $repnumber\n"; $done->{$rpm->[$s]} = $repnumber; $done->{$srpm->[$s]}++; $interdeps[$s][0] = $id-1; $interdeps[$s][1] = [$cdnum, $i, $list, $curdir, $id]; } if (@$rpm > 1){ for (my $s; $s < @$rpmd; $s++){ my $id = $interdeps[$s][0]; foreach (my $t; $t < @interdeps; $t++){ $t == $s and next; push @{$diff->[$cdnum][$i][$list][$j][0][$id][6]}, $interdeps[$t][1] } } } $size->{disc}[$cdnum] += $totrpmsize; $size->{rep}{$cdnum}{$curdir->[1]}{$list} += $totrpmsize; $config->{verbose} and print {$config->{LOG}} "addRPMToDiff: SIZE disc $cdnum: $size->{disc}[$cdnum] (+ @$rpm $totrpmsize)\n"; 1 } sub findList { my ($group,$r,$list) = @_; my $l; foreach (keys %{$group->{size}{$r}}){ $l = $_ if (($l && $group->{listmatrix}{rpm}{$l}{$_}) || $group->{listmatrix}{rpm}{$list}{$_}) } return $l } sub processDeps{ my ($r,$group,$rejected,$done,$rpmlist,$topush,$intopush,$depsdisc,$rpmd,$list,$loop,$i,$tobedone,$buildlist,$rpm) = @_; print {$config->{LOG}} "processDeps: deps $r\n"; # FIXME default to random list if $l != $list my $l = findList($group,$r,$list); if ($rejected->[$i]{$r}) { print {$config->{LOG}} "ERROR processDeps: deps $r rejected, rejecting @$rpm\n"; $config->{verbose} and print {$config->{LOG}} "Rejecting @$rpm $r\n"; @{$rejected->[$i]}{@$rpm} = map 1, @$rpm; $rejected->[$i]{$r} = 1; $$loop = 1; %$topush = (); return 0 } my $tcd = $done->{$r}; if ($tcd){ if ($tcd > $$depsdisc) { $$depsdisc = $tcd}; $config->{verbose} and print {$config->{LOG}} "processDeps: deps done $r on rep $tcd ($$depsdisc)\n"; return 2 } if ($tobedone->[$i]{$r}){ if ($l == $list){ print {$config->{LOG}} "$r tobedone\n"; $intopush->{$r} and print {$config->{LOG}} "WARNING processDeps: $r added twice\n" and return 1; push @$rpmd, [$r, $rpmlist->[$i]{$l}{$r}]; $intopush->{$r} = 1; push @{$topush->{$l}}, $rpmd; $config->{verbose} and print {$config->{LOG}} "processDeps: adding looping deps $r ($_ -- $l) with @$rpm\n" }else{ if ($group->{listmatrix}{rpm}{$list}{$l}){ # FIXME tobedone may not mean dependencies loop in parallel mode for different list. print {$config->{LOG}} "processDeps: $r is already scheduled on list $l, waiting.\n"; %$topush = (); push @{$buildlist->[$i]{$list}}, @$rpmd > 1 ? $rpmd : $rpmd->[0]; return 3 #$intopush{$r} and print {$config->{LOG}} "ERROR: $r added twice\n" and return 0; #$intopush{$r} = 1; #push @{$topush{$l}}, [$r, $rpmlist->[$i]{$l}{$r}]; #$config->{verbose} and print {$config->{LOG}} "DEPS $r ($_ -- $l)\n" }else{ print {$config->{LOG}} "ERROR processDeps: deps $r could not be put in directory before packages @$rpm\n"; $config->{verbose} and print {$config->{LOG}} "Rejecting @$rpm $r\n"; @{$rejected->[$i]}{@$rpm} = map 1, @$rpm; $rejected->[$i]{$r} = 1; %$topush = (); $$loop = 1; return 0 } } }else{ if ($l == $list){ $intopush->{$r} and print {$config->{LOG}} "WARNING processDeps: $r added twice\n" and return 1; $intopush->{$r} = 1; push @{$topush->{$l}}, [$r, $rpmlist->[$i]{$l}{$r}]; $config->{verbose} and print {$config->{LOG}} "processDeps: adding normal deps $r ($_ -- $l)\n" } else { if ($group->{options}{sequential}){ print {$config->{LOG}} "WARNING processDeps: could not add interlist deps in sequential mode\n"; $config->{verbose} and print {$config->{LOG}} "Rejecting @$rpm\n"; @{$rejected->[$i]}{@$rpm} = map 1, @$rpm; %$topush = (); $$loop = 1; return 0 } else { if ($group->{listmatrix}{rpm}{$list}{$l}){ $intopush->{$r} and print {$config->{LOG}} "WARNING processDeps: $r added twice\n" and return 1; $intopush->{$r} = 1; push @{$topush->{$l}}, [$r, $rpmlist->[$i]{$l}{$r}]; $config->{verbose} and print {$config->{LOG}} "processDeps: adding normal deps $r ($_ -- $l)\n" }else{ print {$config->{LOG}} "ERROR processDeps: deps $r could not be put in directory before packages @$rpm\n"; $config->{verbose} and print {$config->{LOG}} "Rejecting @$rpm\n"; @{$rejected->[$i]}{@$rpm} = map 1, @$rpm; %$topush = (); $$loop = 1; return 0 } } } } } sub updateGenericLimit { my ($groups,$cdsize) = @_; $config->{verbose} and print {$config->{LOG}} "updateGenericLimit\n"; for (my $i; $i < @$groups; $i++){ foreach my $type (keys %{$groups->[$i]{orderedlist}}){ foreach my $list (@{$groups->[$i]{orderedlist}{$type}}){ foreach my $r (@{$groups->[$i]{list}{$list}{$type}}){ my ($cd,$rep,$repopt) = @$r; #print {$config->{LOG}} "trying to update disc $cd rep $rep list $list limit repopt $repopt (",keys %$repopt,") opt $opt (",keys %$opt,")\n"; $config->{list}[$list]{disc}{$cd}{$rep}{done} and next; $repopt->{limit} or next; $repopt->{limit}{size} = $repopt->{limit}{value} * $cdsize->[$cd]; $config->{verbose} and print {$config->{LOG}} "updateGenericLimit: setting disc $cd rep $rep list $list limit to $repopt->{limit}{size} ($repopt->{limit}{value} * $cdsize->[$cd])\n"; } } } } } sub testSoftLimit{ my ($opt,$cd,$groups,$buildlist) = @_; print $config->{verbose} and print {$config->{LOG}} "testSoftLimit\n"; my $softnok = 1; # FIXME this code must be tested if ($opt->{limit} && $opt->{limit}{soft}){ foreach my $l (@{$config->{disc}[$cd]{fastgeneric}}){ my $lst = $l->[2]{list}; for (my $i; $i < @$groups; $i++){ $groups->[$i]{list}{$lst} or next; $softnok = 0 if (@{$buildlist->[$i]{$lst}} && !($lst->{limit} && $lst->{limit}{soft})) } } } return $softnok; } sub addOneDisc{ my ($cdlists,$group,$cdsize,$list,$cds) = @_; my $ncd; foreach (keys %{$cdlists}){ $ncd = $_ + 1 if $ncd <= $_ } print {$config->{LOG}} "addOneDisc: $config->{list}[$list]{cd} -- $ncd\n"; if (!$config->{list}[$list]{cd} || ($config->{list}[$list]{cd} >= $ncd)){ print {$config->{LOG}} "addOneDisc: adding new disc $ncd\n"; $config->{disc}[$ncd]{size} = $config->{discsize}; $config->{disc}[$ncd]{serial} = "$config->{name}-disc$ncd"; $config->{disc}[$ncd]{name} = $ncd; $config->{disc}[$ncd]{longname} = "MandrakeLinux $config->{name}"; $cdsize->[$ncd] = $config->{discsize}; my $functions = $config->{group}{disc}{functions}{functions}; &{$functions->{dir}[0][5]}($ncd,1,"rpms","Mandrake/RPMS$ncd"); &{$functions->{generic}[0][5]}($ncd,2,"rpms",1); $group->{orderedrep}{rpm}{"$ncd/rpms"} = $ncd; # # generic has no FIXED part, otherwize a call to generic with fixed=0 # had beed needed # my $f = "$config->{tmp}/build/$config->{name}/$ncd.list"; -f $f and unlink $f; my $curdir = [$ncd, "rpms"]; push @{$group->{list}{$list}{rpm}}, $curdir; my $instcd = $group->{installDisc}; my $k = push @{$config->{disc}[$instcd]{function}{data}{installation}[1]{rpmsdir}}, [ 0, $ncd,"rpms"]; my $l; my $srpmcurdir; if ($config->{list}[$list]{sources}){ &{$functions->{dir}[0][5]}($ncd,3,"srpms","Mandrake/SRPMS"); &{$functions->{generic}[0][5]}($ncd,4,"srpms",1); &{$functions->{generic}[1][5]}($ncd,6, {source => 1}); push @{$config->{disc}[$instcd]{function}{data}{installation}[1]{srpmsdir}}, [ 0, $ncd,"srpms"]; $srpmcurdir = [ $ncd, "srpms" ]; $l = push @{$group->{list}{$list}{srpm}}, $srpmcurdir } push @$cds, $ncd; $cdlists->{$ncd} = 2; return ($curdir,$k-1,$srpmcurdir,$l-1) } else { return 0 } } # TODO the algo is not as beautiful as it should be, but it is getting better sub buildDiscs{ my ($class,$groups,$buildlist,$rpmlist,$log,$groupok,$size,$cdsize,$cdlists,$cds) = @_; $config->{verbose} and print {$config->{LOG}} "buildDiscs\n"; my $config = $class->{config}; my @diff; for(my $i; $i < @{$size->{disc}}; $i++){ if ($size->{disc}[$i] > $cdsize->[$i]) { my $gain = $size->{disc}[$i] - $cdsize->[$i]; optimizeSpace($groups,$log,\@diff,$size,$cdsize,$gain,$i,$cdlists) } } my $ok; my @groupok = map 0, @$groups; my @tobedone; my @rejected; my @needed; my $iti; updateGenericLimit($groups,$cdsize); while (!$ok){ $config->{verbose} and print {$config->{LOG}} "iti: ",$iti++,"\n"; $ok = 1; for (my $i; $i < @$groups; $i++){ $groupok[$i] and next; my $group = $groups->[$i]; # # FIXME source rpms are not shared between group, it may be usefull for mutilple installation # with common source dir, so that the same source rpm is shared (but this is not so common). # my $done = $group->{done}; my $dn; while (!$dn){ $groupok[$i] = 1; foreach my $list (@{$group->{orderedlist}{rpm}}){ $config->{verbose} and print {$config->{LOG}} "buildDiscs: list $list\n"; do { $config->{list}[$list]{done} and goto end; $config->{list}[$list]{empty} and goto end; my $next; foreach (@{$needed[$i]{$list}}){ $config->{verbose} and print {$config->{LOG}} "List $list need list $_->[0] to be <= $_->[1] (",int @{$buildlist->[$i]{$_->[0]}},")\n"; int @{$buildlist->[$i]{$_->[0]}} <= $_->[1] or $next = 1 } $next and print {$config->{LOG}} "LIST $list waiting\n" and goto end; $needed[$i]{$list} = []; my $trpmd; my $k; my $goon; my @rpmd; do { $trpmd = pop @{$buildlist->[$i]{$list}} or goto end; if (ref $trpmd->[0]){ foreach (@$trpmd){ !$done->{$_->[0]} and push @rpmd, $_ } } else { !$done->{$trpmd->[0]} and push @rpmd, $trpmd} } until (@rpmd); $groupok[$i] = 0; $ok = 0; my @rpm; my $rpmsize; my @rpmsize; foreach (@rpmd){ my $r = $_->[0]; !$r and print {$config->{LOG}} "ERROR buildDisc: empty package @$_\n"; push @rpm, $r; $config->{verbose} and print {$config->{LOG}} "RPM $r (group $i list $list)\n"; $tobedone[$i]{$r} = 1; $rpmsize += $group->{size}{$r}{$list}[0]; push @rpmsize, $group->{size}{$r}{$list}[0] } my $loop; my $dn2; for (my $j; !$loop && !$dn2 && $j < @{$group->{list}{$list}{rpm}}; $j++){ $loop = 0; my $curdir = $group->{list}{$list}{rpm}[$j]; $config->{list}[$list]{disc}{$curdir->[0]}{$curdir->[1]}{done} and next; my ($cdnum,$repname,$repopt) = @$curdir; $cdlists->{$cdnum} > 1 or next; my $thisorderrep = $group->{orderedrep}{rpm}{"$cdnum/$repname"}; my $softnok = testSoftLimit($repopt,$cdnum,$groups,$buildlist); $config->{verbose} and print {$config->{LOG}} "buildDiscs: softnok $softnok\n"; if ($size->{disc}[$cdnum] + $rpmsize > $cdsize->[$cdnum] || $repopt->{limit} && ($softnok || !$repopt->{limit}{soft}) && ($size->{rep}{$cdnum}{$repname}{$list} + $rpmsize > $repopt->{limit}{size})) { if ($j == @{$group->{list}{$list}{rpm}}-1){ if (!($repopt->{limit} && !$softnok && $repopt->{limit}{soft})){ if (!optimizeSpace($groups,$log,\@diff,$size,$cdsize,$cdnum,$rpmsize,$i,$cdlists,$list)){ if ($config->{list}[$list]{auto}){ my ($curdir,$j) = addOneDisc($cdlists,$group,$cdsize,$list,$cds); if ($curdir){ $cdnum = $curdir->[0] } else { $config->{verbose} and print {$config->{LOG}} "Could not add more disc, rejecting @rpm\n"; @{$rejected[$i]}{@rpm} = map 1, @rpm and next } }else { $config->{verbose} and print {$config->{LOG}} "Rejecting $@rpm\n"; @{$rejected[$i]}{@rpm} = map 1, @rpm and next } } }else { foreach my $l (@{$config->{disc}[$cdnum]{fastgeneric}}){ my $lst = $l->[2]{list}; $list == $lst and next; for (my $i; $i < @$groups; $i++){ $groups->[$i]{list}{$lst}{rpm} or next; push @{$needed[$i]{$list}}, [ $lst, 0 ] if (!($lst->{limit} && $lst->{limit}{soft})) } } } }else { next } } if (!$config->{nodeps} && !$group->{options}{nodeps}) { my @tdeps; my %curID; foreach (@rpmd){ my $rpm = $_->[0]; $curID{$group->{params}{info}{$rpm}{id}} = 1; $_->[1]{nodeps} and next; $group->{pkgdeps}{$rpm} and push @tdeps, @{$group->{pkgdeps}{$rpm}} } my @deps; my %depsdone; foreach (@tdeps){ if (ref){ my @toadd; my $key = join '|',@$_; $depsdone{$key}++ and next; foreach my $d (@$_){ if ($curID{$d}){ @toadd = (); last } push @toadd, $d } @toadd and push @deps, \@toadd }elsif(!$curID{$_}){ $depsdone{$_}++ and next; push @deps, $_ } } if (@deps){ my $waiting; my %topush; my %intopush; my $depsdisc; foreach (@deps){ if (!ref){ my $a = processDeps($group->{depslistid}[$_],$group,\@rejected,$done,$rpmlist,\%topush,\%intopush,\$depsdisc,\@rpmd,$list,\$loop,$i,\@tobedone,$buildlist,\@rpm); if ($a < 0) {return 0 } elsif ($a == 0) { last } elsif ($a == 2) { next } elsif ($a == 3) { $waiting = 1; last } }else{ # must create a virtual package that install all of them in one loop my $score = [ 0, $group->{maxlist} ]; my $r = -1; $config->{verbose} and print {$config->{LOG}} "buildDiscs: alternatives deps @$_\n"; foreach (@$_){ # FIXME it may have a problem here, as depslistid are not erased when the # package is removed, that is to say that if the previous deps failed for # any reason, alternates deps may be added, although excluded before # however this _must_ not happen, and signify a bug somewhere else. my $pkg = $group->{depslistid}[$_]; $intopush{$pkg} and $r = $pkg and last; $config->{verbose} and print {$config->{LOG}} "buildDiscs: alternatives deps $pkg\n"; $rejected[$i]{$pkg} and next; my $tcd = $done->{$pkg}; if ($done->{$pkg} && $tcd <= $group->{orderedrep}{rpm}{"$cdnum/$repname"}){ print {$config->{LOG}} "$pkg ($tcd) done\n"; $r = 0; last } my $s = $group->{scorelist}{$pkg}; my $pkgList = findList($group,$pkg,$list); if ($group->{options}{sequential} && !$config->{list}[$list]{done} && @{$buildlist->[$i]{$pkgList}}) { next } $config->{verbose} and print {$config->{LOG}} "buildDiscs: $pkg list $pkgList\n"; if (!$tcd && $group->{listmatrix}{rpm}{$list}{$pkgList}){ if ($group->{listsort}{rpm}{$pkgList} < $score->[1] || ($group->{listsort}{rpm}{$pkgList} == $score->[1] && $s > $score->[0])){ $config->{verbose} and print {$config->{LOG}} "buildDiscs: choosing $pkg ($s, $group->{listsort}{$pkgList})\n"; $score = [ $s, $group->{listsort}{rpm}{$pkgList} ]; $r = $pkg; } } } $intopush{$r} and next; if ($r == -1){ print {$config->{LOG}} "ERROR buildDiscs: alternatives deps (@$_) could not be put in directory before packages @rpm\n"; $config->{verbose} and print {$config->{LOG}} "Rejecting @rpm\n"; @{$rejected[$i]}{@rpm} = map 1, @rpm; %topush = (); $loop = 1; last } if ($r){ my $a = processDeps($r,$group,\@rejected,$done,$rpmlist,\%topush,\%intopush,\$depsdisc,\@rpmd,$list,\$loop,$i,\@tobedone,$buildlist,\@rpm); if ($a < 0) {return 0 } elsif ($a == 0) { last } elsif ($a == 2) { next } elsif ($a == 3) { $waiting = 1; last } }else{ $config->{verbose} and print {$config->{LOG}} "Finding better alternatives rep (@$_ - $depsdisc)\n"; my $bestdisc = (keys %{$group->{orderedrep}{rpm}}); if ($bestdisc >= $depsdisc){ foreach (@$_){ my $pkg = $group->{depslistid}[$_]; $rejected[$i]{$pkg} and print {$config->{LOG}} "$pkg rejected\n" and next; my $tcd = $done->{$pkg} or next; $config->{verbose} and print {$config->{LOG}} "$pkg => rep $tcd\n"; if ($tcd < $bestdisc) { $bestdisc = $tcd} } $bestdisc > $depsdisc and $depsdisc = $bestdisc } $config->{verbose} and print {$config->{LOG}} "Finding better alternatives rep result $depsdisc\n"; } } } $waiting and next; if (keys %topush){ $config->{verbose} and print {$config->{LOG}} "Adding dependencies, looping\n"; $loop = 1; my $test = @rpmd > 1 ? \@rpmd : $rpmd[0]; push @{$buildlist->[$i]{$list}}, @rpmd > 1 ? \@rpmd : $rpmd[0]; foreach (keys %topush){ $list != $_ and push @{$needed[$i]{$list}}, [ $_, int @{$buildlist->[$i]{$_}} ]; push @{$buildlist->[$i]{$_}}, @{$topush{$_}} } }elsif ($thisorderrep < $depsdisc) { if ($group->{listmaxrep}{rpm}{$list} >= $depsdisc){ # has a chance to put it after depsdic $config->{verbose} and print {$config->{LOG}} "Dependencies on further directories ($depsdisc)\n"; next }else{ $config->{verbose} and print {$config->{LOG}} "buildDiscs: dependances are in further directories, rejecting @rpm\n"; @{$rejected[$i]}{@rpm} = map 1, @rpm; $loop = 1 } } } } $loop and next; $config->{verbose} and print {$config->{LOG}} "@rpm deps ok\n"; my $nosrc = 1; my @srpm; my $donesrpm = 1; if (!$group->{options}{nosources} && @{$group->{list}{$list}{srpm}}){ for (my $s; $s < @rpmd; $s++){ my $srpm = $group->{params}{info}{$rpm[$s]}{sourcerpm}; $srpm =~ s/\.rpm$//; if (!$group->{size}{$srpm}{$list}) { print {$config->{LOG}} "buildDiscs: ERROR: $srpm not available, trying alternatives => "; my ($srpmname) = $srpm =~ /(.*)-[^-]+-[^-]+\.src/; $srpm = $group->{srpmname}{$srpmname}; if ($srpm) { print {$config->{LOG}} " $srpm\n" } else { print {$config->{LOG}} "not found\n"} } if ($srpm) { $done->{$srpm} or $donesrpm = 0; $srpm[$s] = $srpm; $rpmd[$s][1]{nosrc} or $nosrc = 0 } } } $config->{verbose} and print {$config->{LOG}} "buildDiscs: list $list: @rpm (@srpm) -- $curdir->[0] -- $curdir->[1] -- disc $cdnum\n"; if ($group->{options}{nosources} || !@{$group->{list}{$list}{srpm}} || $nosrc || $donesrpm) { $dn2 = addRPMToDiff(\@rpm, \@srpm, \@rpmd,\@diff,$cdnum, $group->{orderedrep}{rpm}{"$cdnum/$repname"}, $i, $list, $curdir, $size,\@rpmsize,$rpmsize,$j,$done) }else{ my %srpmrep; my $srpmok = 1; my @srpmsize; for (my $s; $s < @srpm; $s++){ $done->{$srpm[$s]} and next; $rpmd[$s][1]{nosrc} and next; my $srpmsize = $group->{size}{$srpm[$s]}{$list}[0]; $srpmsize[$s] = $srpmsize; for (my $k; !$dn2 && $k < @{$group->{list}{$list}{srpm}}; $k++){ my $srpmdir = $group->{list}{$list}{srpm}[$k]; my ($srccd,$srcrepname,$srcopt)= @$srpmdir; $config->{verbose} and print {$config->{LOG}} "trying source disc $srccd\n"; $cdlists->{$srccd} > 1 or next; my $currentrpm; $cdnum == $srccd and $currentrpm = $rpmsize; my $softnok = testSoftLimit($srcopt,$srccd,$groups,$buildlist); # FIXME this need to be tested # FIXME in auto mode a new disc must be added if ($size->{disc}[$srccd] + $srpmsize + $currentrpm <= $cdsize->[$srccd] && !( $srcopt->{limit} && ($softnok || !$srcopt->{limit}{soft}) && $size->{rep}{$srccd}{$srcrepname}{$list} > $srcopt->{limit}{size})){ $srpmrep{$srpm[$s]} = [$srccd,$k,$srpmdir]; last } } if (!$srpmrep{$srpm[$s]}){ $srpmok = 0 } } if (!$srpmok && $config->{list}[$list]{auto}){ my (undef,undef,$srpmdir,$k) = addOneDisc($cdlists,$group,$cdsize,$list,$cds); if ($srpmdir){ for (my $s; $s < @srpm; $s++){ if (!$srpmrep{$srpm[$s]}){ $srpmrep{$srpm[$s]} = [$srpmdir->[0], $k, $srpmdir]; } } $srpmok = 1 } } if ($srpmok){ my @interdeps; for (my $s; $s < @rpm; $s++){ if (!$rpmd[$s][1]{nosrc} && !$done->{$srpm[$s]}){ my $srpmrep = $srpmrep{$srpm[$s]}; push @{$diff[$cdnum][$i][$list][$j][0]}, [$rpm[$s],1,$rpmd[$s],$curdir,$rpmsize]; push @{$diff[$srpmrep->[0]][$i][$list][$srpmrep->[1]][1]}, [$srpm[$s],1,$rpmd[$s],$srpmrep->[2],$srpmsize[$s]]; my $idx = @{$diff[$cdnum][$i][$list][$j][0]}; my $sidx = @{$diff[$srpmrep->[0]][$i][$list][$srpmrep->[1]][1]}; $interdeps[$s][0] = $idx-1; my $rdeps = [$cdnum,$i, $list, $j,$idx-1]; $interdeps[$s][1] = $rdeps; $diff[$cdnum][$i][$list][$j][0][$idx-1][5] = [$srpmrep->[0], $i, $list, $srpmrep->[1], $sidx-1]; $diff[$srpmrep->[0]][$i][$list][$srpmrep->[1]][1][$sidx-1][5] = $rdeps; $size->{disc}[$srpmrep->[0]] += $srpmsize[$s]; $size->{rep}{$srpmrep->[0]}{$srpmrep->[1]}{$list} += $srpmsize[$s]; $config->{verbose} and print {$config->{LOG}} "SIZE disc $srpmrep->[0]: $size->{disc}[$srpmrep->[0]] (+ $srpm[$s] $srpmsize[$s])\n"; }else{ push @{$diff[$cdnum][$i][$list][$j][0]}, [$rpm[$s],1,$rpmd[$s],$curdir,$rpmsize]; my $idx = @{$diff[$cdnum][$i][$list][$j][0]}; $interdeps[$s][0] = $idx-1; $interdeps[$s][1] = [$cdnum,$i, $list, $j,$idx-1]; } $done->{$rpm[$s]} = $group->{orderedrep}{rpm}{"$cdnum/$repname"}; $done->{$srpm[$s]}++; } if (@rpm > 1) { for (my $s; $s < @rpmd; $s++){ my $id = $interdeps[$s][0]; foreach (my $t; $t < @interdeps; $t++){ $t == $s and next; push @{$diff[$cdnum][$i][$list][$j][0][$id][6]}, $interdeps[$t][1] } } } $dn2 = 1; $size->{disc}[$cdnum] += $rpmsize; $size->{rep}{$cdnum}{$repname}{$list} += $rpmsize; $config->{verbose} and print {$config->{LOG}} "SIZE disc $cdnum: $size->{disc}[$cdnum] (+ @rpm $rpmsize)\n"; }else{ print {$config->{LOG}} "WARNING: @srpm does not fit on the discs\n" } if (!$dn2){ if ($config->{nosrcfit} || $group->{options}{nosrcfit}){ $dn2 = addRPMToDiff(\@rpm, \@srpm, \@rpmd,\@diff,$cdnum, $group->{orderedrep}{rpm}{"$cdnum/$repname"}, $i, $list, $curdir, $size,\@rpmsize,$rpmsize,$j,$done) }else{ @{$rejected[$i]}{@rpm} = map 1, @rpm; print {$config->{LOG}} "WARNING: @rpm does not fit on the disc ($size->{disc}[$cdnum] + $rpmsize > $cdsize->[$cdnum]) \n" } } } } $dn2 and $dn = 1; } while ($group->{options}{sequential} && @{$buildlist->[$i]{$list}}); end: next if ($group->{options}{sequential} && @{$buildlist->[$i]{$list}}) } $groupok[$i] and $dn = 1 } } } my $rejected; $config->{verbose} and print {$config->{LOG}} "buildDiscs: rejected packages\n"; for(my $i; $i < @rejected; $i++){ $rejected[$i] or next; print {$config->{LOG}} "groups $i\n"; $rejected=1; foreach (keys %{$rejected[$i]}){ print {$config->{LOG}} "$_\n" } } (\@diff,$rejected); } 1 # Changelog # # 2002 02 21 # # change false $j comparaison to $depsdisc in buildDisc to new $thisorderrep value. # # 2002 03 03 # # new limit option handling. # add updateGenericSoft function # add testSoftLimit function # update size to check rep size # # 2002 03 08 # # fix autoMode CD adding # # 2002 03 13 # # better selection of alternatives in multi-list to take the one in the first lists. # # 2002 03 14 # # add sources new sources handling method