source: soft/build_system/build_system/mkcd/tags/V4_1_4_1mdk/pm/Mkcd/Disc.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: 16.0 KB
Line 
1package Mkcd::Disc;
2
3my $VERSION = '0.1.1';
4
5use strict;
6use File::Path;
7use Mkcd::Functions;
8use Mkcd::Tools qw(du compute_md5 log_ include_md5);
9use MDK::Common qw(any);
10use Mkcd::Package qw(list_hdlist);
11
12=head1 NAME
13
14Disc - mkcd disc functions
15
16=head1 SYNOPSYS
17
18    require Mkcd::Disc;
19
20=head1 DESCRIPTION
21
22C<Mkcd::Disc> include the mkcd disc handling subroutines.
23
24=head1 SEE ALSO
25
26mkcd
27
28=head1 COPYRIGHT
29
30Copyright (C) 2000-2004 Mandrakesoft <warly@mandrakesoft.com>
31
32This program is free software; you can redistribute it and/or modify
33it under the terms of the GNU General Public License as published by
34the Free Software Foundation; either version 2, or (at your option)
35any later version.
36
37This program is distributed in the hope that it will be useful,
38but WITHOUT ANY WARRANTY; without even the implied warranty of
39MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
40GNU General Public License for more details.
41
42You should have received a copy of the GNU General Public License
43along with this program; if not, write to the Free Software
44Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
45
46=cut
47
48my $config;
49
50sub new {
51    my ($class, $conf) = @_;
52    $config = $conf;
53    bless {
54           config       => $conf,
55           functions    => new Mkcd::Functions($config)
56          }, $class;
57}
58
59# FIXME must add space for synthesis, however they are negligeable compared to hdlist. Only
60# a pb with very small CD.
61
62sub guessHdlistSize {
63    my ($class, $group, $size, $cdsize, $lists, $discsFiles) = @_;
64    my $FACTOR = 130;
65    my $SynFACTOR = 90;
66    my $msg;
67    my $depsRep = "$config->{tmp}/$class->{config}{name}/$group->{depsrep}";
68    $msg = "guessHdlistSize: depsRep $depsRep\n";
69    # FIXME heuristic for hdlist size on installation disc, (RPMS size / $FACTOR) per discs
70    # need genDeps to write hdlist/synthesis, overkill
71    my $depsSize = du($depsRep);
72    my $instdisc = $group->{installDisc};
73    my $sz;
74    my (@notdone, @rem_size);
75    push @rem_size, @$cdsize;
76    foreach my $list (keys %{$group->{list}}) {
77        $msg .= "guessHdlistSize: list $list\n";
78        if ($config->{list}[$list]{auto}) {
79            $msg .= "guessHdlistSize: auto mode\n";
80            if ($config->{list}[$list]{cd}) {
81                my $tsize = ($config->{discsize}/$FACTOR) * $config->{list}[$list]{cd}; 
82                $sz += $tsize < $depsSize ? $tsize : $depsSize;
83            } else {
84                $sz += $depsSize
85            }
86        } else {
87            $msg .= "guessHdlistSize: normal mode\n";
88            my $ok;
89            my $listsize = $group->{listsize}{$list}{rpm};
90            $msg .= "guessHdlistSize: listsize $listsize\n";
91            foreach my $rd (@{$group->{list}{$list}{rpm}}) {
92                my ($cdrep, undef, undef, $opt) = @$rd;
93                $msg .= "guessHdlistSize: cd $cdrep\n";
94                if ($opt->{nodeps}) { $ok = 1; next }
95                if ($lists->{$cdrep}) {
96                    if ($listsize > $cdsize->[$cdrep]) {
97                        $sz += $rem_size[$cdrep] / $FACTOR;
98                        $listsize -= $rem_size[$cdrep];
99                        $rem_size[$cdrep] = 0
100                    } else {
101                        $sz += $listsize / $FACTOR;
102                        $rem_size[$cdrep] -= $listsize;
103                        last
104                    }
105                }
106            }
107            $ok and push @notdone, $list       
108        }
109    }
110    $msg .= "guessHdlistSize: reserving ";
111    if ($depsSize < $sz && $depsSize > 10000) { 
112        $msg .= $depsSize;
113        $size->{disc}[$instdisc] += int $depsSize;
114        if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += int($depsSize / $SynFACTOR) }
115    } elsif ($sz > 10000) { 
116        $msg .= $sz; 
117        $size->{disc}[$instdisc] += int $sz;
118        if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += int($sz / $SynFACTOR) }
119    } else {
120        log_("ERROR guessHdlistSize: possibly wrong estimated dependencies file size\n", $config->{verbose}, $config->{LOG},2) 
121    }
122    $msg .= " (new size $size->{disc}[$instdisc]) on disc $instdisc ($depsSize/$sz) for dependencies files\n";
123    log_($msg, $config->{verbose}, $config->{LOG},2);
124    @notdone or return 1;
125    $sz = 0;
126    foreach my $list (@notdone) {
127        foreach my $rd (@{$group->{list}{$list}{rpm}}) {
128            my ($cd, $rep, $repopt, $opt) = @$rd;
129            if ($lists->{$cd} == 1) {
130                $sz += du("$class-{config}{topdir}/build/$class->{config}{name}/$cd/$class->{config}{disc}[$cd]{function}{data}{dir}{$rep}[1]{reploc}")
131            } elsif ($lists->{$cd} == 2) {
132                foreach my $rpm (keys %{$discsFiles->[$cd]{$rep}{$list}}) {
133                    $sz += du("$discsFiles->[$cd]{$rep}{$list}{$rpm}/$rpm.rpm")
134                }
135            }
136        }
137    }
138    $sz /= $FACTOR;
139    $msg = "guessHdlistSize: reserving $sz";
140    $size->{disc}[$instdisc] += $sz;
141    if ($config->{disc}[$instdisc]{function}{data}{installation}[1]{synthesis}) { $size->{disc}[$instdisc] += $sz / $SynFACTOR }
142    $msg .= " (new size $size->{disc}[$instdisc]) on disc $instdisc ($sz) for extra dependencies files\n";
143    log_($msg, $config->{verbose}, $config->{LOG},1)
144}               
145
146sub getBuiltDiscs {
147    my ($class, $lists, $group, $discsFiles, $size, $cdsize) = @_;
148    foreach my $l (keys %{$group->{list}}) {
149        log_("getBuiltDiscs: get rep from list $l\n", $config->{verbose}, $config->{LOG},2);
150        my @rpmlist;
151        ref $group->{list}{$l}{rpm} and push @rpmlist, @{$group->{list}{$l}{rpm}};
152        ref $group->{list}{$l}{srpm} and push @rpmlist, @{$group->{list}{$l}{srpm}};
153        for (my $i; $i < @rpmlist; $i++) {
154            my ($cd, $rep, $repopt, $opt) = @{$rpmlist[$i]};
155            $lists->{$cd} == 1 or next;
156            $size->{disc}[$cd] = $cdsize->[$cd];
157            $class->{config}{list}[$l]{disc}{$cd}{$rep}{done} = 1;
158            if ($opt->{hdlist}) {
159                log_("getBuiltDiscs: getting rpm from hdlist $opt->{hdlist}\n", $config->{verbose}, $config->{LOG},2);
160                my $tmphdlist = "$class->{config}{tmp}/.mkcd_build_hdlist";
161                foreach (@{list_hdlist([$opt->{hdlist}], $config->{verbose}, 1, $tmphdlist)}) {
162                    log_("getBuiltDiscs: adding $_\n", $config->{verbose}, $config->{LOG},6);
163                    $discsFiles->[$cd]{$rep}{$l}{$_} = ''
164                }
165            } else { 
166                my $dir = "$class->{config}{topdir}/build/$class->{config}{name}/$cd/$class->{config}{disc}[$cd]{function}{data}{dir}{$rep}[1]{reploc}";
167                #
168                # FIXME maybe need to unshift instead of push
169                #
170                $repopt->{source} ? push(@{$class->{config}{list}[$l]{packages}[0]{srpm}}, $dir) : push(@{$class->{config}{list}[$l]{packages}[0]{rpm}}, $dir);
171                log_("getBuiltDiscs: get files from $dir\n", $config->{verbose}, $config->{LOG},2);
172                opendir my $A, $dir;
173                foreach (readdir $A) {
174                    /(.*)\.rpm/ or next;
175                    # FIXME need to check if it is well placed in getList function
176                    # $group->{done}{$rpm} = $group->{orderedrep}{"$cd/$rep"};
177                    # log_("getBuiltDiscs: adding $1 in $dir for $cd/$rep list $l\n", $config->{verbose}, $config->{LOG},2);
178                    $size->{rep}{$cd}{$rep}{$l} += $group->{size}{$1}{$l}[0];
179                    $discsFiles->[$cd]{$rep}{$l}{$1} = $dir
180                }
181            }
182        }
183    }
184    1
185}
186
187sub write_graft {
188    my ($graft, $file, $exclude) = @_;
189    log_("write_graft: $file ($graft)\n", $config->{verbose}, $config->{LOG},2); 
190    open my $A, ">$file";
191    open my $B, ">$exclude";
192    foreach my $d (sort keys %$graft) {
193        if (ref $graft->{$d}) {
194            map { print $A "$d=$_\n" } keys %{$graft->{$d}}
195        } elsif ($graft->{$d} == 3) {
196            print $B "$d\n"
197        }
198    }
199}
200
201sub graft_to_md5 {
202    my ($graft, $dir, $serial) = @_;
203    my $mdfile = ".$serial.md5";
204    log_("graft_to_md5: $serial -> $dir/$mdfile ($graft)\n", $config->{verbose}, $config->{LOG},2); 
205    local *A; open A, ">$dir/$mdfile";
206    my %ignore;
207    my @to_check;
208    $graft->{$mdfile}{"$dir/$mdfile"} = 0;
209    foreach my $f (keys %$graft) { 
210        if (ref $graft->{$f}) { 
211            foreach (keys %{$graft->{$f}}) {
212                my ($file) = m,/([^/]+)$,;
213                my $dest = $f =~ m,/$, ? "/$f/$file" : "/$f";
214                if ($graft->{$f}{$_}) {
215                    push @to_check, [ $dest, $_ ];
216                } else {
217                    $ignore{$dest} = 1;
218                    print A "$f\n"
219                }
220            }
221        } else {
222            $ignore{$f} = 1;
223            print A "$f\n"
224        }
225    }
226    my $digest = compute_md5(\@to_check, \%ignore);
227    print A "$digest - $serial\n"
228}   
229
230sub makeDiscs {
231    my ($class, $fixed, $lists, $cds, $size, $mkisos, $discsFile, $graft, $sort, $inode, $cdfile) = @_;
232    my $dir;
233    my $name = $class->{config}{name};
234    my $topdir = $class->{config}{topdir};
235    my $tmp = "$config->{tmp}/build/$name";
236    my $first;
237    my $isodir = $class->{config}{isodir} ? $class->{config}{isodir} : "$topdir/iso/$name";
238   
239    if (!$class->{config}{nolive}) {
240        $dir = "$topdir/build/$name";
241        -d $dir or mkpath $dir;
242        -d $tmp or mkpath $tmp;
243    } else {
244        $dir = "$config->{tmp}/build/$name";
245        -d $dir or mkpath $dir;
246    }
247    if ($fixed == -1) {
248        buildISO($class->{config}, $isodir, $name, $lists, $fixed, $mkisos, $size, $cds, $cdfile, $sort, $first, 0);
249        return 1
250    }
251    log_("makeDiscs: Discs @$cds topdir $dir\n", $config->{verbose}, $config->{LOG},1);
252    foreach my $i (@$cds) {
253        $lists->{$i} > 1 or next;
254        my $cd = $class->{config}{disc}[$i];
255        $graft->{$i} ||= {};
256        $sort ||= {};
257        if ($fixed > 1 && $cdfile->[$i] == 0) {
258            log_("makeDiscs: nothing to do for disc $i\n", $config->{verbose}, $config->{LOG},2);
259            next
260        }
261        if (!$fixed) {
262            log_("makeDisc: Fixed part of disc $i\n", $config->{verbose}, $config->{LOG},3);
263            if ($class->{config}{nolive}) {
264                log_("makeDisc: removing $dir/$i.list\n", $config->{verbose}, $config->{LOG},3);
265                -f "$dir/$i.list" and unlink "$dir/$i.list";
266                log_("makeDisc: removing $dir/$i\n", $config->{verbose}, $config->{LOG},3);
267                rmtree "$dir/$i";
268                mkdir "$dir/$i"
269            } else {
270                -d "$tmp/$i" or mkpath "$tmp/$i";
271                foreach ("$topdir/build/$name/$i", "$topdir/build/$name/first/$i") { rmtree $_; mkdir $_ }
272                $first = "$topdir/build/$name/first/$i"
273            }
274        } else { log_("Finalizing disc $i\n", $config->{verbose}, $config->{LOG},2) }
275        my $sz;
276        if (ref $cd->{steps}) {
277            for (my $j; $j < @{$cd->{steps}}; $j++) {
278                my $name = $cd->{steps}[$j][0];
279                log_("makeDiscs: $name ($fixed)\n", $config->{verbose}, $config->{LOG},2);
280                if (defined $Mkcd::Functions::{$name}) {
281                    $sz += &{$Mkcd::Functions::{$name}}($class->{disc}{functions}, $cd->{steps}[$j], $dir, $fixed, $class->{config}{nolive}, $i, $cd, $cdfile, $lists, $mkisos, $graft, $inode->{$i}, $discsFile, $sort, $size)
282                }
283                else { log_("ERROR: unrecognized function name $name\n",0, $config->{LOG}) }
284                log_("SIZE ($name) $sz\n", $config->{verbose}, $config->{LOG},4);
285            }
286        } else {
287            die "FATAL make_discs: impossible to find definition of disc $i, problem in config file ?"
288        }
289        if ($class->{config}{nolive}) {
290            log_("SIZE $size->{disc}[$i] + $sz\n", $config->{verbose}, $config->{LOG},4);
291            $size->{disc}[$i] += $sz
292        } else {
293            $size->{disc}[$i] = du("$dir/$i") + $sz
294        }
295        log_("disc $i ($dir/$i) size: $size->{disc}[$i] ($sz)\n", $config->{verbose}, $config->{LOG},3);
296        my $mkisoopt = $class->{config}{mkisoopt};
297        if ($fixed) {
298            $graft->{$i}{".rr_moved"} = 0;
299            my $publisher = $config->{Publisher} || $config->{disc}[$i]{Publisher};
300            my $sysid = $config->{sysid} || $config->{disc}[$i]{sysid};
301            my $seq_size = $config->{disc}[$i]{seq_size} || 1;
302            my $seq_num = $config->{disc}[$i]{seq_num} || 1;
303            my $seq_st = "[$seq_num/$seq_size]";
304            my $volset = substr $cd->{volset}, 0, 128 - length $seq_st;
305            my $commkiso = qq(-A "$cd->{appname}" -publisher "$publisher" -sysid "$sysid" -p "$cd->{serial}" -volset "$volset $seq_st" -V "$cd->{label}" -o $isodir/$i-$name.iso);
306            if ($config->{nolive}) {
307                # include_md5 replaces md5 per files
308                #graft_to_md5($graft->{$i},"$dir/$i",$cd->{serial});
309                write_graft($graft->{$i}, "$dir/$i.list", "$dir/$i-exclude.list");
310                #$mkisos->[$i] = "$mkisoopt -graft-points -path-list $dir/$i.list -sort $dir/$i.sort " . (-f "$dir/$i-exclude.list" ? "-exclude-list $dir/$i-exclude.list" : "") . " $commkiso $mkisos->[$i]" if $fixed == 1
311                $mkisos->[$i] = "$mkisoopt -graft-points -path-list $dir/$i.list " . (-f "$dir/$i-exclude.list" ? "-exclude-list $dir/$i-exclude.list" : "") . " $commkiso $mkisos->[$i]" if $fixed == 1
312            } else {
313                $graft->{$i}{"/"}{"$dir/$i/"} = 1;
314                # include_md5 replaces md5 per files
315                #graft_to_md5($graft->{$i},"$dir/$i",$cd->{serial});
316                if ($mkisos->[$i]) {
317                    $mkisos->[$i] = "$mkisoopt $commkiso $mkisos->[$i] $dir/$i" if $fixed == 1
318                } else {
319                    $mkisos->[$i] = qq($mkisoopt $commkiso "$dir/$i") if $fixed == 1
320                }
321            }
322        }
323    }
324    !$fixed and return 1;
325    buildISO($class->{config}, $isodir, $name, $lists, $fixed, $mkisos, $size, $cds, $cdfile, $sort, $first, 1);
326    1
327}
328
329sub buildISO {
330    my ($config, $isodir, $name, $lists, $fixed, $mkisos, $size, $cds, $cdfile, $sort, $first, $checksize) = @_;
331    my $log = $config->{LOG};
332    $isodir or return;
333    -d $isodir or mkpath $isodir;
334    log_("buildISO: isodir $isodir\n", $config->{verbose}, $config->{LOG}, 5);
335    my $dir = "$config->{tmp}/build/$name";
336    compute_sort_file($sort, $cds, $dir, $first) if !$checksize;
337    foreach my $i (@$cds) {
338        $lists->{$i} > 1 or next;
339        if ($fixed > 1 && $cdfile->[$i] == 0) {
340            log_("buildISO: nothing to do for disc $i\n",0, $config->{LOG});
341            next
342        }
343        my $sort_cmd = "-sort $dir/$i.sort " if ref $sort->{$i};
344        my $cmd = $checksize ? "mkisofs -print-size -quiet $mkisos->[$i]" : "mkisofs $sort_cmd$mkisos->[$i]";
345        if ($checksize) {
346            $size->{disc}[$i] = 1024 * 2 * `$cmd`;
347            log_("MKISOFS disc $i size $size->{disc}[$i]\n", $config->{verbose}, $config->{LOG},1);
348        } elsif (!$config->{noiso}) {
349            $cmd .= " > /dev/null" if !$config->{verbose};
350            my $err = system $cmd;
351            log_("disc $i: $cmd\n", 1, $config->{LOG});
352            if ($err) {
353                log_("ERROR: disc $i $cmd failed ($!)\n", 1, $config->{LOG});
354                print $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:
355                $cmd\n "
356            }
357            my $boot_cat_location = `isoinfo -l -R -i $isodir/$i-$name.iso`;
358            $boot_cat_location =~ /.*\[\s*(\d+) \d\d]  boot.cat.*/m;
359            log_("buildISO: checking boot.cat location ($1)\n", 5, $config->{LOG});
360            die "FATAL buildISO: boot.cat at $1" if any { $1 == $_ } @{$config->{boot_cat_fatal_location}};
361            my $ok = include_md5("$isodir/$i-$name.iso",1);
362            log_("ERROR: disc $i include_md5 failed ($err)\n", 1, $config->{LOG}) if !$ok;
363            $size->{disc}[$i] = du("$isodir/$i-$name.iso")
364        }
365    }
366}
367
368sub checkSize {
369    my ($class, $n, $size, $cdsize, $cds, $rejected) = @_;
370    my $ok = 1;
371    foreach my $i (@$cds) {
372        if ($size->{save}{disc}[$i] != $size->{disc}[$i]) {
373            $size->{save}{disc}[$i] = $size->{disc}[$i];
374            $ok = 0
375        }
376    }
377    if ($ok) {
378        log_("checkSize: disc sizes has not changed, exiting\n",1, $config->{LOG});
379        return 1
380    }
381    my $ok = 1;
382    foreach my $i (@$cds) {
383        $size->{disc}[$i] or next;
384        my $origcdsize = $class->{config}{disc}[$i]{size};
385        log_("checkSize: disc $i size $size->{disc}[$i] ($origcdsize)\n",1, $config->{LOG});
386        my $d = $size->{disc}[$i] - $origcdsize;
387        if ($size->{disc}[$i] > $origcdsize) {
388            if ($d > $origcdsize/10) {
389                log_("ERROR: an error must have happen, disc $i is far too big ($size->{disc}[$i] > $origcdsize), ignoring\n",1, $config->{LOG});
390                next
391            }
392            if ($d > 0 && $d > ($origcdsize*$n)/1000) {
393                $ok = 0;
394                $cdsize->[$i] -= $d;
395                log_("ERROR: disc $i is too big ($size->{disc}[$i] > $origcdsize ($d)\n",1, $config->{LOG})
396            } else {
397                $cdsize->[$i] = $size->{disc}[$i]+1;       
398            }
399        } else {
400            if ($d < 0 && $rejected) {
401                $d = -$d;
402                # FIXME heuristic: do not change CD size if diff is greater than 10% of the original CD size
403                if ($d > $origcdsize/10) {
404                    log_("ERROR: an error must have happen, disc $i is far too small ($size->{disc}[$i] << $origcdsize), ignoring\n",1, $config->{LOG});
405                    next
406                }
407                if ($d > ($origcdsize*$n)/300) {
408                    $ok = 0;
409                    #$cdsize->[$i] += $d/2;
410                    log_("ERROR: disc $i is too small ($size->{disc}[$i] < $origcdsize, ($d)\n",1, $config->{LOG})
411                }
412            }
413        }
414        log_("checkSize: new disc $i size $cdsize->[$i]\n",1, $config->{LOG});
415    }
416    return $ok
417}
418
419sub compute_sort_file {
420    my ($sort, $cds, $dir, $first) = @_;
421    foreach my $cd (@$cds) {
422        ref $sort->{$cd} or next;
423        open my $F, ">$dir/$cd.sort" or return 0;
424        my $i=1;
425        my %done;
426        foreach my $chunks (@{$sort->{$cd}}) {
427            foreach my $f (@$chunks) {
428                $f or next;
429                $done{$f} and next;
430                $done{$f} = 1;
431                print $F "$f $i\n";
432                $i++
433            }
434        }
435        print $F "$first $i\n" if $first
436    }
437}
438
4391
440
441# Changelog
442#
443# 2002 05 22
444# fix a pb in graft_to_md5 that made dest incomplete when dest is a directory
445#
446# 2002 08 25
447# improve checkSize to better work with optimize_space
Note: See TracBrowser for help on using the repository browser.