package Mkcd::Disc; my $VERSION = '0.1.1'; use strict; use File::Path; use Mkcd::Functions; use Mkcd::Tools qw(du compute_md5 log_ include_md5); =head1 NAME Disc - mkcd disc functions =head1 SYNOPSYS require Mkcd::Disc; =head1 DESCRIPTION C include the mkcd disc handling subroutines. =head1 SEE ALSO mkcd =head1 COPYRIGHT Copyright (C) 2000,2001 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 => $conf, functions => new Mkcd::Functions($config) }, $class; } # FIXME must add space for synthesis, however they are negligeable compared to hdlist. Only # a pb with very small CD. sub guessHdlistSize{ my ($class,$group,$size,$cdsize,$lists,$discsFiles) = @_; my $FACTOR = 130; my $SynFACTOR = 90; my $msg; my $depsRep = "$config->{tmp}/$class->{config}{name}/$group->{depsrep}"; $msg = "guessHdlistSize: depsRep $depsRep\n"; # FIXME heuristic for hdlist size on installation disc, (RPMS size / $FACTOR) per discs # need genDeps to write hdlist/synthesis, overkill my $depsSize = du("$depsRep"); my $instdisc = $group->{installDisc}; my $sz; my (@notdone, @rem_size); push @rem_size, @$cdsize; foreach my $list (keys %{$group->{list}}){ if ($config->{list}[$list]{auto}){ if ($config->{list}[$list]{cd}){ my $tsize = ($config->{discsize}/$FACTOR) * $config->{list}[$list]{cd}; $sz += $tsize < $depsSize ? $tsize : $depsSize; }else { $sz += $depsSize } }else { my $ok; my $listsize = $group->{listsize}{$list}{rpm}; foreach my $rd (@{$group->{list}{$list}{rpm}}){ my ($cdrep,undef,undef,$opt) = @$rd; if ($opt->{nodeps}) { $ok = 1; next } if ($lists->{$cdrep}){ if ($listsize > $cdsize->[$cdrep]){ $sz += $rem_size[$cdrep] / $FACTOR; $listsize -= $rem_size[$cdrep]; $rem_size[$cdrep] = 0 }else{ $sz += $listsize / $FACTOR; $rem_size[$cdrep] -= $listsize; last } } } $ok and push @notdone, $list } } $msg .= "guessHdlistSize: reserving "; if ($depsSize < $sz && $depsSize > 10000){ $msg .= "$depsSize"; $size->{disc}[$instdisc] += int $depsSize; if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += int ($depsSize / $SynFACTOR) } } elsif ($sz > 10000) { $msg .= "$sz"; $size->{disc}[$instdisc] += int $sz ; if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += int ($sz / $SynFACTOR) } }else{ log_("ERROR guessHdlistSize: possibly wrong estimated dependencies file size\n",$config->{verbose},$config->{LOG}) } $msg .= " (new size $size->{disc}[$instdisc]) on disc $instdisc ($depsSize/$sz) for dependencies files\n"; log_($msg,$config->{verbose},$config->{LOG}); @notdone or return 1; $sz = 0; foreach my $list (@notdone){ foreach my $rd (@{$group->{list}{$list}{rpm}}){ my ($cd,$rep,$repopt,$opt) = @$rd; if ($lists->{$cd} == 1){ $sz += du("$class-{config}{topdir}/build/$class->{config}{name}/$cd/$class->{config}{disc}[$cd]{function}{data}{dir}{$rep}") }elsif ($lists->{$cd} == 2){ foreach my $rpm (keys %{$discsFiles->[$cd]{$rep}{$list}}){ $sz += du("$discsFiles->[$cd]{$rep}{$list}{$rpm}/$rpm.rpm") } } } } $sz /= $FACTOR; $msg = "guessHdlistSize: reserving $sz"; $size->{disc}[$instdisc] += $sz; if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += $sz / $SynFACTOR } $msg .= " (new size $size->{disc}[$instdisc]) on disc $instdisc ($sz) for extra dependencies files\n"; log_($msg,$config->{verbose},$config->{LOG}) } sub getBuiltDiscs{ my ($class, $lists, $group, $discsFiles) = @_; foreach my $l (keys %{$group->{list}}){ my @rpmlist; ref $group->{list}{$l}{rpm} and push @rpmlist, @{$group->{list}{$l}{rpm}}; ref $group->{list}{$l}{srpm} and push @rpmlist, @{$group->{list}{$l}{srpm}}; for (my $i; $i < @rpmlist; $i++){ my ($cd,$rep,$repopt) = @{$rpmlist[$i]}; $lists->{$cd} == 1 or next; my $dir = "$class->{config}{topdir}/build/$class->{config}{name}/$cd/$class->{config}{disc}[$cd]{function}{data}{dir}{$rep}"; # # FIXME maybe need to unshift instead of push # $repopt->{source} or push @{$class->{config}{list}[$l]{packages}}, [$dir]; $class->{config}{list}[$l]{disc}{$cd}{$rep}{done} = 1; log_("getBuiltDiscs: get files from $dir\n",1,$config->{LOG}); local *A; opendir A,$dir; foreach (readdir A){ /(.*)\.rpm/ or next; # FIXME need to check if it is well placed in getList function # $group->{done}{$rpm} = $group->{orderedrep}{"$cd/$rep"}; $discsFiles->[$cd]{$rep}{$l}{$1} = $dir } } } 1 } sub write_graft{ my ($graft, $file) = @_; log_("write_graft: $file ($graft)\n",1,$config->{LOG}); local *A; open A, ">$file"; foreach my $d (sort keys %$graft){ if (ref $graft->{$d}){ map { print A "$d=$_\n" } keys %{$graft->{$d}} } } } sub graft_to_md5{ my ($graft,$dir,$serial) = @_; my $mdfile = ".$serial.md5"; log_("graft_to_md5: $serial -> $dir/$mdfile ($graft)\n",1,$config->{LOG}); local *A; open A, ">$dir/$mdfile"; my %ignore; my @to_check; $graft->{$mdfile}{"$dir/$mdfile"} = 0; foreach my $f (keys %$graft) { if (ref $graft->{$f}) { foreach (keys %{$graft->{$f}}){ my ($file) = /\/([^\/]+)$/; my $dest = ($f =~ /\/$/) ? "/$f/$file" : "/$f"; if ($graft->{$f}{$_}) { push @to_check, [ $dest, $_ ]; } else { $ignore{$dest} = 1; print A "$f\n" } } } else { $ignore{$f} = 1; print A "$f\n" } } my $digest = compute_md5(\@to_check,\%ignore); print A "$digest - $serial\n" } sub makeDiscs { my ($class, $fixed, $lists, $cds, $size, $mkisos, $discsFile, $graft, $cdfile) = @_; my $dir; my $name = $class->{config}{name}; my $topdir = $class->{config}{topdir}; my $tmp = "$config->{tmp}/build/$name"; if (!$class->{config}{nolive}){ $dir = "$topdir/build/$name"; -d $dir or mkpath "$dir"; -d $tmp or mkpath $tmp; }else{ $dir = "$config->{tmp}/build/$name"; -d "$dir" or mkpath "$dir"; } log_("makeDiscs: Discs @$cds TOPDIR $dir\n",1,$config->{LOG}); foreach my $i (@$cds){ $lists->{$i} > 1 or next; my $cd = $class->{config}{disc}[$i]; $graft->{$i} ||= {}; if ($fixed > 1 && $cdfile->[$i] == 0){ log_("makeDiscs: nothing to do for disc $i\n",1,$config->{LOG}); next } if (!$fixed){ log_("makeDisc: Fixed part of disc $i\n",1,$config->{LOG}); if ($class->{config}{nolive}){ log_("makeDisc: removing $dir/$i.list\n",1,$config->{LOG}); -f "$dir/$i.list" and unlink "$dir/$i.list"; log_("makeDisc: removing $dir/$i\n",1,$config->{LOG}); rmtree "$dir/$i"; mkdir "$dir/$i" }else{ -d "$tmp/$i" or mkpath "$tmp/$i"; for ("$topdir/build/$name/$i","$topdir/build/$name/first/$i") { rmtree $_; mkdir $_ } } } else { log_("Finalizing disc $i\n",1,$config->{LOG}) } my $sz; for (my $j; $j < @{$cd->{steps}}; $j++){ my $name = $cd->{steps}[$j][0]; log_("makeDiscs: $name ($fixed)\n",1,$config->{LOG}); if (defined $Mkcd::Functions::{$name}) { $sz += &{$Mkcd::Functions::{$name}}($class->{disc}->{functions},$cd->{steps}[$j],$dir,$fixed,$class->{config}{nolive},$i,$cd,$cdfile,$lists,$mkisos,$graft,$discsFile)} else {log_("ERROR: unrecognized function name $name\n",1,$config->{LOG})} log_("SIZE ($name) $sz\n",$config->{verbose},$config->{LOG}); } if ($class->{config}{nolive}){ log_("SIZE $size->{disc}[$i] + $sz\n",$config->{verbose},$config->{LOG}); $size->{disc}[$i] += $sz }else{ $size->{disc}[$i] = du("$dir/$i") + $sz } log_("disc $i ($dir/$i) size: $size->{disc}[$i] ($sz)\n",$config->{verbose},$config->{LOG}); my $mkisoopt = $class->{config}{mkisoopt}; if ($fixed) { my $isodir = $class->{config}{isodir} ? $class->{config}{isodir} : "$topdir/iso/$name"; $graft->{$i}{".rr_moved"} = 0; my $publisher = $config->{Publisher} || $config->{disc}[$i]{Publisher}; my $commkiso = "-A \"$cd->{appname}\" -P \"$publisher\" -volset \"$cd->{serial}\" -V \"$cd->{label}\" -o $isodir/$i-$name.iso"; if ($config->{nolive}){ # include_md5 replaces md5 per files #graft_to_md5($graft->{$i},"$dir/$i",$cd->{serial}); write_graft($graft->{$i},"$dir/$i.list"); $mkisos->[$i] = "mkisofs $mkisoopt -graft-points -path-list $dir/$i.list $commkiso $mkisos->[$i]" if ($fixed == 1) }else{ $graft->{$i}{"/"}{"$dir/$i/"} = 1; # include_md5 replaces md5 per files #graft_to_md5($graft->{$i},"$dir/$i",$cd->{serial}); if ($mkisos->[$i]) { $mkisos->[$i] = "mkisofs $mkisoopt $commkiso $mkisos->[$i] $dir/$i" if ($fixed == 1) } else { $mkisos->[$i] = qq|mkisofs $mkisoopt $commkiso "$dir/$i"| if ($fixed == 1) } } } } !$fixed and return 1; if (!$class->{config}{noiso}){ -d "$topdir/iso/$name" or mkpath "$topdir/iso/$name"; foreach my $i (@$cds){ $lists->{$i} > 1 or next; if ($fixed > 1 && $cdfile->[$i] == 0){ log_("makeDiscs: nothing to do for disc $i\n",1,$config->{LOG}); next } log_("MKISOFS disc $i $mkisos->[$i]\n",$config->{verbose},$config->{LOG}); my $err = system $mkisos->[$i]; if (!$err){ log_("ERROR: disc $i $mkisos->[$i] failed ($!)\n",1,$config->{LOG}); print { $config->{LOG} } "WARNING: a problem may have appear, if ISOs files are not OK and you want to retry to build the ISOs, type the following command: $mkisos->[$i]\n " } include_md5("$topdir/iso/$name/$i-$name.iso",1); $size->{disc}[$i] = du("$topdir/iso/$name/$i-$name.iso") } } 1 } sub checkSize{ my ($class, $n,$size,$cdsize,$cds,$rejected) = @_; my $ok = 1; foreach my $i (@$cds) { if ($size->{save}{disc}[$i] != $size->{disc}[$i]){ $size->{save}{disc}[$i] = $size->{disc}[$i]; $ok = 0 } } if ($ok) { log_("checkSize: disc sizes has not changed, exiting\n",1,$config->{LOG}); return 1 } my $ok = 1; foreach my $i (@$cds) { $size->{disc}[$i] or next; my $origcdsize = $class->{config}{disc}[$i]{size}; log_("checkSize: disc $i size $size->{disc}[$i] ($origcdsize)\n",1,$config->{LOG}); my $d = ($size->{disc}[$i] - $origcdsize); if ($size->{disc}[$i] > $origcdsize) { if ($d > $origcdsize/10){ log_("ERROR: an error must have happen, disc $i is far too big ($size->{disc}[$i] > $origcdsize), ignoring\n",1,$config->{LOG}); next } if ($d > 0 && $d > ($origcdsize*$n)/1000) { $ok = 0; $cdsize->[$i] -= $d; log_("ERROR: disc $i is too big ($size->{disc}[$i] > $origcdsize ($d)\n",1,$config->{LOG}) } else { $cdsize->[$i] = $size->{disc}[$i]+1; } } else { if ($d < 0 && $rejected){ $d = -$d; # FIXME heuristic: do not change CD size if diff is greater than 10% of the original CD size if ($d > $origcdsize/10){ log_("ERROR: an error must have happen, disc $i is far too small ($size->{disc}[$i] << $origcdsize), ignoring\n",1,$config->{LOG}); next } if ($d > ($origcdsize*$n)/300) { $ok = 0; #$cdsize->[$i] += $d/2; log_("ERROR: disc $i is too small ($size->{disc}[$i] < $origcdsize, ($d)\n",1,$config->{LOG}) } } } log_("checkSize: new disc $i size $cdsize->[$i]\n",1,$config->{LOG}); } return $ok } 1 # Changelog # # 2002 05 22 # fix a pb in graft_to_md5 that made dest incomplete when dest is a directory # # 2002 08 25 # improve checkSize to better work with optimize_space