source: soft/build_system/build_system/mkcd/tags/V3_8_3_1mdk/pm/Mkcd/Tools.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: 30.5 KB
Line 
1package Mkcd::Tools;
2
3our $VERSION = '1.0.0';
4
5use strict;
6use File::NCopy qw(copy);       
7use Image::Size qw(:all);
8use Mkcd::Commandline qw(parseCommandLine usage);
9use Digest::MD5;
10use MDK::Common qw(all any);
11require Exporter;
12use URPM;
13our @ISA = qw(Exporter);
14our @EXPORT = qw(printTable getTracks du cpal checkcds checkDiscs cleanrpmsrate imageSize printDiscsFile readBatchFile printBatchFile config compute_md5 log_ include_md5 convert_size compute_files_md5 fix_dir filter_path);
15our ($GB, $MB, $KB, $INFO_OFFSET, $SIZE_OFFSET, $SKIP);
16$INFO_OFFSET = 883;
17$SIZE_OFFSET = 84;
18$SKIP = 15;
19
20$KB = 1024;
21$MB = 1024 * 1024;
22$GB = $MB * 1024;
23
24=head1 NAME
25
26tools - mkcd tools
27
28=head1 SYNOPSYS
29
30    require mkcd::tools;
31
32=head1 DESCRIPTION
33
34<mkcd::tools> includes mkcd tools.
35
36=head1 SEE ALSO
37
38mkcd
39
40=head1 COPYRIGHT
41
42Copyright (C) 2000-2003 Mandrakesoft <warly@mandrakesoft.com>
43
44This program is free software; you can redistribute it and/or modify
45it under the terms of the GNU General Public License as published by
46the Free Software Foundation; either version 2, or (at your option)
47any later version.
48
49This program is distributed in the hope that it will be useful,
50but WITHOUT ANY WARRANTY; without even the implied warranty of
51MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
52GNU General Public License for more details.
53
54You should have received a copy of the GNU General Public License
55along with this program; if not, write to the Free Software
56Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
57
58=head1 CREDITS
59
60md5 code highly inspired from Redhat anaconda md5 in ISO code
61
62=cut
63
64sub printTable {
65    my ($a, $log) = @_;
66    my $LOG; if ($log) { $LOG = $log } else { open $LOG, ">&STDERR" }
67    #
68    # iterative version of a recursive scanning of a table.
69    # ex: @config = [[[1,3],3,[1,3,[1,3]]],3,4,[4,[4,4]]]
70    #   
71    my @A;
72    my @i;
73    my @tab;
74    my $i = 0;
75    while ($a) {
76        my $u = ref $a;
77        if ($u eq 'ARRAY') {
78            while ($i < @$a) {
79                my $b = $a->[$i];
80                my $t = ref $b;
81                if ($t eq 'ARRAY') {
82                    push @tab, "\t";
83                    push @i, $i+1;
84                    push @A, $a;
85                    $i = 0;
86                    $a = $b;
87                    next
88                } elsif ($t eq 'HASH') { 
89                    $i++; print $LOG "@tab", join ' ', keys %$b, "\n"
90                } else { $i++; print $LOG "@tab$b\n" }
91            }
92        } else { print $LOG "$a\n" }
93        pop @tab;
94        $i = pop @i;
95        $a = pop @A;
96    }
97
98}
99
100sub getTracks {
101    my ($tracks, $log) = @_;
102    my $LOG; if ($log) { $LOG = $log } else { open $LOG, ">&STDERR" }
103    my @tracks = split ',',$tracks;
104    my @t;
105    foreach (@tracks) {
106        /(\d+)/ and push @t, $1;
107        /(\d+)-(\d+)/ and push @t, $1..$2       
108    }
109    my @ntracks;
110    my %done;
111    for (my $i = $#t; $i >= 0; $i--) {
112        push @ntracks, $t[$i] if !$done{$t[$i]};
113        $done{$t[$i]}=1
114    }
115    \@ntracks;
116}
117
118sub du {
119    my ($path, $inode) = @_;
120    my $size;
121    $inode ||= {};
122    if (-d $path) {
123        opendir O, $path;
124        foreach (readdir O) {
125            /^\.{1,2}$/ and next;
126            -l "$path/$_" or $size += du("$path/$_",$inode)
127        }
128    } else {
129        if (! -l $path) {
130            my @stat = stat $path;
131            if (!$inode->{$stat[0]}{$stat[1]}) {
132                $size = $stat[7] + 2048;
133                $inode->{$stat[0]}{$stat[1]} = 1
134            }
135        }
136    }
137    $size
138}
139
140sub cpal {
141    my ($source, $dest, $exclude, $verbose, $log) = @_;
142    my $LOG; if ($log) { $LOG = $log } else { open $LOG, ">&STDERR" }
143    if ($exclude && "$source/$_" =~ /$exclude/) { return 0 }
144    if (!-l $source && -d $source) {
145        mkdir $dest;
146        opendir O, $source; 
147        foreach (readdir O) {
148            /^\.{1,2}$/ and next;
149            cpal("$source/$_", "$dest/$_",$exclude,$verbose)
150        }
151    } else {
152        my $ok;
153        if (-d $dest) { my ($filename) = $source =~ m,([^/]*)$,; $dest .= "/$filename" }
154        $ok = link $source, $dest;
155        $verbose and print $LOG "cpal: link $source -> $dest\n";
156        if (!$ok) {
157            print $LOG "Linking failed $source -> $dest: $!, trying to copy\n";
158            $ok = copy $source, $dest;
159            if (!$ok) { print $LOG "Copying failed $source -> $dest: $!,\n"; return 0 }
160        }
161    }
162    1
163}
164
165sub checkDiscs {
166    my ($hdlists, $depslist, $discsFiles, $check, $log) = @_;
167    my $LOG; if ($log) { $LOG = $log } else { open $LOG, ">&STDOUT" }
168   
169    print $LOG "checkDiscs: depslist $depslist\n";
170    #
171    # depslist hdlist consistency -> error                        ok (not the same as install one, but duplicate will break anyway)
172    #
173    # in hdlist, not in depslist -> error                         ok
174    #
175    # in hdlist, not in dir -> error                              ok
176    #
177    # in hdlist with packdrake, no with parsehdlist -> error
178    #
179    # in depslist, not in hdlist -> error                         ok
180    #
181    # in depslist, not in dir -> error                            ok
182    #
183    # in dir, not in hdlist -> warning                            ok
184    #
185    # in dir, not in depslist -> warning                          ok
186    #
187    # multiple version in depslist -> error                       ok
188    #
189    # multiple version in hdlist -> error                         ok
190    #
191    # multiple in dir -> warning                                  ok
192    #
193   
194    my $ok = 1;
195    my $OK = 1;
196    my %depslist;
197    my %depslistname;
198    if ($depslist) {
199        my $i = 1;
200        open my $A, $depslist or print $LOG "ERROR: unable to open $depslist" and return 0;
201        print $LOG "checkDiscs: duplicate version in $depslist:";
202        while (<$A>) {
203            my ($pkg, $name, $arch) = ((split)[0]) =~ m/((.*)-[^-]+-[^-]+\.([^:]+))/;
204            $depslist{$pkg} and do { print $LOG "\n$pkg"; $ok = 0 };
205            $depslistname{$arch}{$name} and do { print $LOG "\n$name"; $ok = 0 };
206            $depslist{$pkg} = $i;
207            $depslistname{$arch}{$name} = $i++;
208        }
209        close $A;
210    }
211    $ok or $OK = 0;
212    $ok ? print $LOG " OK\n" : print $LOG "\nFAILED\n";
213    my %hdlist;
214    print $LOG "\ncheckDiscs: duplicate version in hdlists:";
215    my $maxidx;
216    my %rpm;
217    my (@rnh, @hnd, @duprep, @rnd, @hnr, %rpmKeys, %parsehdlist, @pnh, @hnp);
218    $ok = 1;
219    my $parsehdlist;
220    my $path = $0;
221    $path =~ s,[^/]*$,,;
222    if (-x "$path/parsehdlist") {
223        $parsehdlist = "$path/parsehdlist"
224    } elsif (-x "/usr/bin/parsehdlist") {
225        $parsehdlist = "/usr/bin/parsehdlist"
226    } else {
227        my $err = system('parsehdlist');
228        if ($err) {
229            $parsehdlist = "parsehdlist"       
230        } else {
231            print $LOG, "ERROR checkDiscs: could not find parsehdlist command ($!)\n";
232            return 0
233        }
234    }
235    for (my $i = 1; $i < @$hdlists; $i++) {
236        if (! -f $hdlists->[$i]) {
237            print $LOG "\nWARNING checkDiscs: $hdlists->[$i] is empty, ignoring\n";
238            next
239        }
240        my $packer = new packdrake($hdlists->[$i]);
241        my $j;
242        foreach my $file (@{$packer->{files}}) {
243            my ($rpm, $key) = $file =~ /([^:]*)(?::(.*))?/;
244            $rpmKeys{key}{$rpm} = $key || $rpm;
245            $rpmKeys{rpm}{$rpmKeys{key}{$rpm}} = $rpm;
246            my $sok;
247            foreach my $c (@{$check->[$i]}) {
248                my ($cd, $rep, $list) = @$c;
249                $discsFiles->[$cd]{$rep}{$list}{$rpmKeys{key}{$rpm}} and $sok = 1;
250            }
251            $sok or push @hnr, [ $i, $rpm ];
252            $hdlist{all}{$rpm} and do { print $LOG "\n$rpm"; $ok = 0 };
253            $hdlist{all}{$rpm} = 1;
254            $hdlist{cd}{$i}{$rpm}  = 1;
255            if ($depslist) {
256                $depslist{$rpm} or push @hnd, $rpm;
257                $depslist{$rpm} > $j and $j = $depslist{$rpm};
258                $depslist{$rpm} < $maxidx and print $LOG "ERROR checkDiscs: inconsistency in position between hdlist $i rpm $rpm and depslist.ordered\n"
259            }
260        }
261        foreach my $c (@{$check->[$i]}) {
262            my ($cd, $rep, $list) = @$c;
263            foreach my $rpm (keys %{$discsFiles->[$cd]{$rep}{$list}}) {
264                $rpm{$rpmKeys{rpm}{$rpm}} and push @duprep, $rpm;
265                $rpm{$rpmKeys{rpm}{$rpm}} = 1;
266                $depslist && $depslist{$rpmKeys{rpm}{$rpm}} or push @rnd,  [ $i, $cd, $rep, $rpm ];
267                $hdlist{cd}{$i}{$rpmKeys{rpm}{$rpm}} or push @rnh, [ $i, $rpm ]
268            }
269        }
270        open my $PAR, "$parsehdlist $hdlists->[$i] |";
271        while (<$PAR>) {
272            chomp;
273            s/\.rpm$//;
274            $parsehdlist{$i}{$_} = 1;
275            $hdlist{cd}{$i}{$_} and next;
276            push @pnh, $_
277        }
278        foreach my $p (keys %{$hdlist{cd}{$i}}) {
279            $parsehdlist{$i}{$p} or push @hnp, $p
280        }
281        $maxidx = $j;
282    }
283    $ok or $OK = 0;
284    $ok ? print $LOG " OK\n" : print $LOG "\nFAILED\n";
285
286    my @dnh;
287    $ok = 1;
288    if ($depslist) {
289        print $LOG "\ncheckDiscs: in depslist, not on discs:";
290        foreach my $rpm (keys %depslist) {
291            $hdlist{all}{$rpm} or do { push @dnh, $rpm };
292            $rpm{$rpm} or do { $ok = 0; print $LOG "\n$rpm" };
293        }
294        $ok or $OK = 0;
295        $ok ? print $LOG " OK\n" : print $LOG "\nFAILED\n";
296
297        print $LOG "\ncheckDiscs: in depslist, not in hdlists:";
298        @dnh ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n";
299        foreach (@dnh) {
300            print $LOG "$_\n"
301        }
302    }
303    print $LOG "\ncheckDiscs: in hdlists, not on discs:";
304    @hnr ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n";
305    foreach (@hnr) {
306        print $LOG "hdlist $_->[0] rpm $_->[3]\n"
307    }
308    print $LOG "\ncheckDiscs: in hdlists, not in depslist:";
309    @hnd ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n";
310    foreach (@hnd) {
311        print $LOG "$_\n"
312    }
313    print $LOG "\ncheckDiscs: in hdlists, not see with parsehdlist:";
314    @hnp ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n";
315    foreach (@hnp) {
316        print $LOG "$_\n"
317    }
318    print $LOG "\ncheckDiscs: see with parsehdlist, not with packdrake:";
319    @pnh ? do { print $LOG " FAILED\n" and $OK = 0 } : print $LOG " OK\n";
320    foreach (@pnh) {
321        print $LOG "$_\n"
322    }
323    print $LOG "\ncheckDiscs: on discs, not in hdlist:";
324    @rnh ? print $LOG " WARNING\n" : print $LOG " OK\n";
325    foreach (@rnh) {
326        print $LOG "hdlist $_->[0] rpm $_->[1]\n"
327    }
328    print $LOG "\ncheckDiscs: on discs, not in depslist:";
329    @rnd ? print $LOG " WARNING\n" : print $LOG " OK\n";
330    foreach (@rnd) {
331        print $LOG "hdlist $_->[0] cd $_->[1] rep $_->[2] missing rpm $_->[3]\n"
332    }
333    print $LOG "\ncheckDiscs: duplicate version on discs:";
334    @duprep ? print $LOG " WARNING\n" : print $LOG " OK\n";
335    foreach (@duprep) {
336        print $LOG "$_\n"
337    }
338    return $OK
339}
340
341#
342# check depslist, depslists.ordered and hdlists
343#
344sub checkcds {
345    my (@tops) = @_;
346   
347    my $top = "$tops[0]/";
348    my $depslist = "$tops[0]/Mandrake/base/depslist.ordered";
349    -f $depslist or print "ERROR: could not find depslist $depslist file\n" and return 0;
350    my $hdlists = "$top/Mandrake/base/hdlists";
351    open my $A, $hdlists or die "unable to open $hdlists";
352    my @hdlist = 0;
353    my @discsFiles;
354    my @check = 0;
355    while (<$A>) {
356        my ($hdlist, $dir, undef) = split;
357        my ($hdid) = $hdlist =~ /(\d*).cz/;
358        my $hdfile = "$tops[0]/Mandrake/base/$hdlist";
359        push @hdlist, $hdfile;
360        push @check, [[ $hdid, $dir, 1 ]];
361        -f $hdfile or print "ERROR: could not find $hdfile file\n" and return 0;
362        print "Reading $top/$dir\n";
363        my $C;
364        if (! opendir $C, "$top/$dir") {
365            foreach (@tops) {
366                opendir $C, "$_/$dir" or next;
367                last
368            }
369        }
370        foreach (readdir $C) {
371            /(.*)\.rpm/ or next;
372            $discsFiles[$hdid]{$dir}{1}{$1} = 1
373        }
374
375    }
376    checkDiscs(\@hdlist, $depslist, \@discsFiles, \@check)
377}
378
379#
380# regexp version
381#
382sub cleanrpmsrate2 {
383    my ($rpmsrate, @rpms) = @_;
384    my $LOG; open $LOG, ">&STDERR";
385    my @rpm;
386    foreach (@rpms) {
387        -d $_ or print $LOG "ERROR: $_ is not a directory\n" and next;
388        opendir my $A, $_;
389        push @rpm, grep { s/-[^-]+-[^-]+\.[^.]+\.rpm// } all $A;
390    }
391    my %done;
392    my (@flags, @c);
393    my ($mod, $text, $prev, $rate, $current);
394    my (%rate, %section);
395    open my $A, $rpmsrate or print $LOG "ERROR: cannot open $rpmsrate\n";
396    while (<$A>) {
397        s/#.*//;
398        /^\s*$/ and $text .= "\n" and next;
399        if (/^(\S+)/) {
400            $text .= "$1\n";
401            $current = $1;
402            @flags = $current;
403            next
404        }
405        my ($indent, $r, $flags, $data) = /^(\s*)([1-5]?)((?:\s+(?:(?:!\s*)?[0-9A-Z_]+(?:"[^"]*")?(?:\s+(?:\|\|\s+)?)*)+\s+)|\s+)(.*)$/;
406        if ($r) {
407            $rate = $r
408        } elsif ($prev) {
409            chop $indent;
410            $r = $prev
411        }
412        push @flags, split ' ', $flags; 
413        $data or $text .= "$indent$r$flags" and next;
414        my ($postfix) = $data =~ /(\s*)$/;
415        my @k;
416        foreach my $n (split ' ', $data) {
417            @c = grep { /^$n$/ } @rpm;
418            map { if ((!$done{$_}[1] || $current eq "INSTALL") && $done{$_}[0] ne $current) { push @k, $_; @{$done{$_}} = @flags } } @c
419        } 
420        if (@k) { $text .= "$indent$r$flags@k$postfix\n"; $prev = '' } else { $prev = $r };
421        @rate{@k} = ($rate) x @k;
422        push @{$section{$current}}, @k
423    }
424    close A;
425    if (@rpms) {
426        if (open A, ">$rpmsrate") {
427            print A $text;
428            close A
429        } else {
430            @rpms and print $LOG "ERROR: cannot open $rpmsrate for writing\n";
431            print $text
432        }
433    }
434    [\%rate, \%section, \%done];
435}
436
437sub cleanrpmsrate {
438    my ($rpmsrate, $output, $norpmsrate, $reprpms, $urpm) = @_;
439    $norpmsrate ||= [];
440    my $LOG; open $LOG, ">&STDERR";
441    open my $A, $rpmsrate or print $LOG "ERROR: cannot open $rpmsrate\n";
442    my (@rpmsrate, %potloc);
443    # must preread to get locale guessed packages
444    # postfix is just used not to break the diff when checking if the result is correct
445    while (<$A>) {
446        chomp;
447        s/#.*//;
448        #s/\s*$//;
449        /^(\s*)$/ and push @rpmsrate, [ '', 0, '', [] ] and next;
450        if (/^(\S+)(.*)$/) {
451            push @rpmsrate, [ 0, 0, $1, [], $2 ];
452            next
453        }
454        if (/^(\s*)([1-5])?(\s?[0-9A-Z_]+)$/) {
455            push @rpmsrate, [ $1, $2, $3, [] ];
456            next
457        }
458        my ($indent, $r, $flags, $data) = /^(\s*)([1-5])?(\s*(?:(?:(?:!\s*)?[0-9A-Z_]+(?:"[^"]*")?(?:\s+(?:\|\|\s+)?)*)+\s+)|\s*)(.*)$/;
459        my ($postfix) = $data =~ /(\s*)$/;
460        my @data;
461        my $i;
462        foreach ([$data =~ /(?:^|\s)(\S+)-(?:\S+)\s+\1-(?:\S+)(?:\s|$)/g], [split ' ', $data]) {
463            $data[$i++] = [ @$norpmsrate ? any { my $r = $_; $r if !any { $r =~ /$_/ } @$norpmsrate } @$_ : @$_ ]
464        }
465        $potloc{$_} = [] foreach  @{$data[0]};
466        push @rpmsrate, [ $indent,$r, $flags, $data[1], $postfix ];
467    }
468    my (%rpms, $text);
469    my (%rate, %section, %keyword);
470    my (%locale, %localized_pkg);
471    my $kernel_like = "((?:(?:NVIDIA_)?kernel.*)|NVIDIA_nforce.*|cm2020.*)";
472    my $urpm2 = new URPM;
473    foreach my $dir (keys %$reprpms) {
474        foreach (@{$reprpms->{$dir}}) { 
475            my $rpm = "$_.rpm";
476            my $key = $_;
477            s/-[^-]+-[^-]+\.[^.]+$// or next;
478            any { $rpm =~ /$_/ } @$norpmsrate and next;
479            if (/(.*?)([_-]*[\d._]*)-devel$/ || /$kernel_like(-[^.]+(?:\.[^.]+){3,5}mdk)$/) { 
480                if (!$rpms{$1}) { $rpms{$1} = $2 }
481                elsif (URPM::ranges_overlap("== $2", "> $rpms{$1}")) { $rpms{$1} = $2 }
482            } elsif (my ($pg, $loc) = /^(.*)-([^-+]+)$/) {
483                if ($potloc{$pg}) {
484                    my $pkg = $urpm->{rpm}{$urpm->{rpmkey}{key}{$key}} if ref $urpm;
485                    if (!$pkg) {
486                        my $id = $urpm2->parse_rpm("$dir/$rpm");
487                        $pkg = $urpm2->{depslist}[$id];
488                    }
489                    if (!$pkg) {
490                        print "ERROR cleanrpmsrate: parse_rpm $dir/$rpm ($key) failed\n";
491                        next
492                    }
493                    # some i18n packages does not require the same locale, e.g. kde-i18n-nb and nn requires locales-no
494                    # if (grep { s/locales-// && $loc =~ /^$_(_|$)/ } @{$header{REQUIRENAME}}) {
495                    if (any { /^locales-..$/ } $pkg->requires) {
496                        push @{$locale{$pg}}, $loc;
497                        $localized_pkg{"$pg-$loc"} = 1
498                    }
499                }
500            }
501        }
502    }
503    my (%done, @flags, $prev, @tree_rate, $prev_level);
504    foreach (@rpmsrate) {
505        if (!$_->[0]) {
506            $text .= "$_->[2]$_->[4]\n";
507            if ($_->[2]) {
508                @flags = $_->[2]
509            }
510            next
511        }
512        my ($indent, $r, $flags, $data, $postfix) = @$_;
513        my $level = (length $indent)/2 - 1;
514        my $rate;
515        if ($r) {
516            #print "tree_rate[$level] = $r\n";
517            $rate = $r;
518            $tree_rate[$level] = $r
519        } else {
520            if (@$data) {
521                if ($level > $prev_level) {
522                    $level-- 
523                } else {
524                    # fix a syntax error in rpmsrate such as
525                    # A
526                    #   1 toto
527                    #   B tata <---
528                    #     4 titi
529                    @$data = ()
530                }
531            }
532            $rate = $tree_rate[$level];
533        }
534        $prev_level = $level;
535        @flags = @flags[0 .. $level];
536        push @flags, grep { s/\s//; !/(\|\||[A-Z_]+"[^"]+")/ } split(' ', $flags);
537        my $flat_path = join ' ', @flags;
538        if (!@$data) { $text .= "$indent$r$flags$postfix\n"; next }
539        my @k;
540        foreach (@$data) {
541            my $c = $_;
542            if (any { $flat_path eq $_ } @{$done{$_}}) { next }
543            my ($d) = /(.*)-[^-]+/;
544            my ($a, $b);
545            if (($flags[0] ne "INSTALL" && s/(-devel)// ? ($b = "-devel") : /^$kernel_like/) && ($rpms{$_} || (defined $rpms{"lib$_"} and $a = "lib") || (defined $rpms{"lib64$_"} and $a = "lib64"))) {
546                my $d = "$a$_" . $rpms{"$a$_"} . $b;
547                $keyword{$c} = $d;
548                if (! ref $done{$d} || $flags[0] eq "INSTALL") { push @{$done{$d}}, $flat_path; push @k, $d }
549            }
550            if ($locale{$d} && $localized_pkg{$c}) {
551                foreach (sort @{$locale{$d}}) {
552                    next if any { $_ eq $flat_path } @{$done{"$d-$_"}};
553                    push @{$done{"$d-$_"}}, $flat_path; 
554                    push @k , "$d-$_"
555                }
556                next
557            }
558            push @k, $c;
559            push @{$done{$c}}, $flat_path
560        } 
561        if (@k) { $text .= "$indent$r$flags@k$postfix\n" }
562        @rate{@k} = ($rate) x @k;
563        my $path;
564        foreach (@flags) {
565            $path .= $path ? "/$_" : $_;
566            push @{$section{$path}}, @k
567        }
568    }
569    if (%rpms || $output) {
570        if (%$reprpms || $output) {
571            $output ||= $rpmsrate;
572            if (open A, ">$output") { 
573                print A $text;
574                close A
575            } else { 
576                print $LOG "ERROR cleanrpmsrate: cannot open $rpmsrate for writing\n";
577                print $text
578            }
579        }
580    }
581    [\%rate, \%section, \%keyword]
582}
583
584sub imageSize {
585    my ($file) = @_;
586    my ($width, $height, $err) = imgsize $file;
587
588    return (defined $width ?
589    [ $width, $height ] :
590    "error: $err")
591}
592
593sub printDiscsFile {
594    my ($config, $discsFiles, $PRINT, $metagroups) = @_;
595    my (%done, $output);
596    my $log = $config->{LOG};
597    if ($PRINT) { open $output, ">$PRINT" } else { $output = $config->{LOG} }
598    my $print_rejected = sub {
599        my ($groups, $i, $rpm, $size, $install_cd) = @_;
600        # FIXME ugly hack to display more rejected in multigroups buildings because discFiles is per disc and not per group.
601        # $done{$groups->[$i]{urpm}{rpmkey}{rpm}{$rpm}} && ! ref $groups->[$i]{rejected}{$rpm} and return 1;
602        $done{$groups->[$i]{urpm}{rpmkey}{rpm}{$rpm}} and return 1;
603        $groups->[$i]{done}{rep}{$rpm} and return 1;
604        if ($groups->[$i]{brokendeps}{$rpm} == 2) {
605            ref $groups->[$i]{rejected}{$rpm} or print $output "ERROR printDiscsFile: this should not happen, rejected is not a table for $rpm (group $i)\n" and next;
606        }
607        printf $output "REJECTED master disc $install_cd %10d $rpm (", $size;
608        if (ref $groups->[$i]{rejected}{$rpm}) { 
609            print $output join(',', map { "$config->{rejected_options}{$_->[0]}: $_->[1]" } @{$groups->[$i]{rejected}{$rpm}})
610        } else {
611            print $output "not selected"
612        }
613        print $output ")\n";
614        0
615    };
616    my %size;
617    # this is not really correct as multiple list may have packages with the same name but different size
618    foreach (@$metagroups) {
619        my $groups = $_->[0];
620        for (my $i; $i < @$groups; $i++) {
621            foreach my $rpm (keys %{$groups->[$i]{size}}) {
622                foreach my $list (keys %{$groups->[$i]{size}{$rpm}}) { 
623                    $size{$rpm} = $groups->[$i]{size}{$rpm}{$list}[0] if $size{$rpm} < $groups->[$i]{size}{$rpm}{$list}[0] 
624                }
625            }
626        }
627    }
628    for (my $cd; $cd < @$discsFiles; $cd++) {
629        $discsFiles->[$cd] or next;
630        print $log "discsFiles: $cd\n";
631        my $cdname = $config->{disc}[$cd]{label};
632        foreach my $rep (keys %{$discsFiles->[$cd]}) {
633            foreach my $list (keys %{$discsFiles->[$cd]{$rep}}) {
634                foreach my $rpm (sort { $size{$a} <=> $size{$b} } keys %{$discsFiles->[$cd]{$rep}{$list}}) {
635                    #$done{$rpm} = 1;
636                    #$rpm =~ /src$/ and next;
637                    printf $output "$cdname %10d $rpm\n", $size{$rpm};
638                }
639            }
640        }
641    }
642    if (!$metagroups) { $output = $config->{LOG} }
643    foreach (@$metagroups) {
644        my $groups = $_->[0];
645        for (my $i; $i < @$groups; $i++) {
646            my $install_cd = "$config->{disc}[$groups->[$i]{installDisc}]{label} ($groups->[$i]{installDisc})";
647            if (ref $groups->[$i]{buildlist}) {
648                foreach (sort { $size{$a} <=> $size{$b} } @{$groups->[$i]{buildlist}}) {
649                    $print_rejected->($groups, $i, $_, $size{$_}, $install_cd) and next;
650                    $done{$groups->[$i]{urpm}{rpmkey}{rpm}{$_}} = 1
651                }
652            }
653            foreach (sort { $size{$a} <=> $size{$b} } keys %{$groups->[$i]{urpm}{rpm}}) {
654                $print_rejected->($groups, $i, $_, $size{$_}, $install_cd)
655            }
656        }
657    }
658}
659
660sub printBatchFile {
661    my ($config, $discsFiles, $PRINTSCRIPT) = @_;
662    # FIXME to please perl_checker
663    my $log = $config->{LOG}; 
664    if (-f $PRINTSCRIPT) {
665        my $err = unlink $PRINTSCRIPT;
666        if (!$err) { print $log "Unlinking failed $PRINTSCRIPT: $!\n"; return };
667    }
668    my $err = copy $config->{configfile}, $PRINTSCRIPT;
669    if (!$err) { print $log "Linking failed $PRINTSCRIPT: $!\n"; return };
670    open my $A, ">>$PRINTSCRIPT";
671    print $A "END\n";
672    for (my $cd; $cd < @$discsFiles; $cd++) {
673        $discsFiles->[$cd] or next;
674        print $log "discsFiles: $cd\n";
675        print $A "CD $cd\n";
676        foreach my $rep (keys %{$discsFiles->[$cd]}) {
677            print $A " REP $rep\n";
678            foreach my $list (keys %{$discsFiles->[$cd]{$rep}}) {
679                print $A "  LIST $list\n";
680                foreach my $rpm (keys %{$discsFiles->[$cd]{$rep}{$list}}) {
681                    $rpm and print $A "   $rpm $discsFiles->[$cd]{$rep}{$list}{$rpm}\n";
682                }
683            }
684        }
685    }
686}
687
688sub readBatchFile {
689    my ($file) = @_;
690    local *A; open A, $file or print "ERROR readBatchFile: could not open $file for reading\n" and return 0;
691    my @discsFiles;
692    my @cd;
693    while (<A>) { /^END/ and last }
694    my ($cd, $rep, $list);
695    while (<A>) {
696        if (/^CD (\d+)/) { $cd = $1; next }
697        if (/^ REP (\S+)/) { $rep = $1; next }
698        if (/^  LIST (\d+)/) { $list = $1; next }
699        if (/^   (\S+) (\S+)/) { 
700            $discsFiles[$cd]{$rep}{$list}{$1} = $2;
701            push @{$cd[$cd]{$rep}{$list}{$2}}, [ 1, "$1.rpm" ];
702            next 
703        }
704    }
705    return \@discsFiles, \@cd
706}
707
708sub config {
709    my ($file, $config, $functions) = @_;
710    my $log = $config->{LOG};
711    open F,$file or die "ERROR config: cannot open $file\n";
712    while (<F>) { chomp; /^#/ or !$_ or last }
713    chomp;
714    $config->{name} = (split)[0];
715    my $match_val = q((?:([^"\s]+)|"([^\"]+)"));
716    my $match_val2 = q(((?:[^"\s]*(?:[^"\s]+|"[^\"]+")[^"\s]*)+));
717    my ($cd, $fn, $nk, $type, @todo, $discMax);
718    $config->{virtual_disc} = [];
719    my ($line, $a);
720    while (<F>) {
721        /^#/ and next;
722        chomp;
723        $_ or next;
724        s/#.*//;
725        my $b = s/\\\s*$//;
726        if ($a) {
727            $line .= $_
728        } else {
729            $line = $_ 
730        }
731        $a = $b;
732        $a and next;
733        local $_ = $line;
734        if (/^list (.*)/) {
735                my $line = $1;
736                my @args;
737                while ($line =~ s/$match_val2//) { my $a = $1; $a =~ s/"//g; push @args, $a }
738                #print "config: args (" . ( join ' | ', @args) . ")\n";
739                my $todo = parseCommandLine("list", \@args, $functions->{list});
740                $cd = $todo->[0][1][0];
741                #print "config: list $cd (@{$todo->[0][1]})\n";
742                if (!$config->{list}[$cd]) {
743                    @args and usage('list', $functions->{list}, "list $cd, list definition (@args) too many arguments");
744                    foreach (@$todo) {
745                        log_("$_->[2]\n", $config->{verbose}, $log, 3);
746                        if (!&{$_->[0]}($cd, @{$_->[1]})) { log_("ERROR: $_->[2]\n", $config->{verbose}, $log); $nk = 1 }
747                    }
748                    $type = 1;
749                    $fn = 0
750                } else {
751                    $type = 0;
752                    log_("ERROR config: list $cd already defined, ignoring\n", $config->{verbose}, $log);
753                }
754            # FIXME keep for compatibility
755        } elsif (/^LIST /) {
756            if (/^LIST (\d+)(?:\s+(\S.*))*/) {
757                $cd = $1;
758                push @{$config->{list}[$cd]{filelist}},  (split ' ',$2) if $2;
759                $type = 1;
760                log_("LIST $1 $2\n", $config->{verbose}, $log, 3)
761            } else {
762                $nk = 1;
763                log_("WARNING: LIST syntax error ($_)\n", $config->{verbose}, $log);
764                log_("         LIST <list number> <file list 1> <file list 2> ... <file list n>\n", $config->{verbose}, $log)
765            }
766        } elsif (/^disc (.*)/) {
767                my $line = $1;
768                my @args;
769                while ($line =~ s/$match_val2//) { my $a = $1; $a =~ s/"//g; push @args, $a }
770                #print "config: args (" . ( join ' | ', @args) . ")\n";
771                my $todo = parseCommandLine("disc", \@args, $functions->{disc});
772                $cd = $todo->[0][1][0];
773                #print "config: disc $cd (@{$todo->[0][1]})\n";
774                if (!$config->{disc}[$cd]) {
775                    @args and usage('disc', $functions->{disc}, "disc $cd, disc definition (@args) too many arguments");
776                    foreach (@$todo) {
777                        log_("$_->[2]\n", $config->{verbose}, $log, 3);
778                        if (!&{$_->[0]}($cd, @{$_->[1]})) { log_("ERROR: $_->[2]\n", $config->{verbose}, $log); $nk = 1 }
779                    }
780                    $type = 2;
781                    $fn = 0
782                } else {
783                    $type = 0;
784                    log_("ERROR config: disc $cd already defined, ignoring\n", $config->{verbose}, $log);
785                }
786            # FIXME keep for compatibility
787        } elsif (/^DISC (.*)/) {
788            if (/^DISC (\d+)\s+(\d+)\s+$match_val(?:\s+DISC\s+(\d+))?\s+$match_val(?:\s+$match_val)?/) { 
789                #print "1($1) 2($2) 3($3) 4($4) 5($5) 6($6) 7($7) 8($8) 8($9)\n";
790                $config->{disc}[$1]{size} = $2;
791                my $disc = $config->{disc}[$1];
792                $disc->{serial} = substr "$3$4", 0, 128;
793                $disc->{name} = $5;
794                $disc->{longname} = "$6$7";
795                $disc->{appname} = substr("$6$7", 0, 128);
796                $disc->{label} = substr(("$6$7" ? "$8$9" : "$6$7"), 0, 32);
797                $cd = $1;
798                $type = 2;
799                $fn = 0;
800                $4 > $discMax and $discMax = $4;
801                log_("DISC $1 $2 $3$4 $5 $6$7 $8$9\n", $config->{verbose}, $log)
802            } else {
803                $nk = 1;
804                $type = 0;
805                log_("WARNING: DISC syntax error ($_)\n", $config->{verbose}, $log);
806                log_("         DISC <cd number> <cd size> <cd serial name> DISC <real cd number> <disc name>\n", $config->{verbose}, $log)
807            }
808        } elsif (/^END/) {
809            last       
810        } else {
811            my @args;
812            while (s/$match_val2//) { my $a = $1; $a =~ s/"//g; push @args, $a }
813            my $prog = shift @args;
814            log_("config: function $prog(" . join(' | ',@args) . ")\n", $config->{verbose}, $log,4);
815            $type == 1 and do {
816                if ($prog ne 'rpmlist') {
817                    push @{$config->{list}[$cd]{packages}}, { rpm => [ $prog ] , srpm => \@args } 
818                } else {
819                    push @todo, [ $prog, \@args, $cd, $fn ];
820                    $fn++;
821                }
822                next
823            };
824            $type == 2 and do {
825                push @todo, [$prog, \@args, $cd, $fn];
826                $fn++;
827                next
828            }
829        }
830    }
831    $config->{configfile} = $file;
832    $config->{discMax} = $discMax;
833    foreach (@todo) {
834        my ($prog, $args, $cd, $fn) = @$_;
835        if ($functions->{$prog}) {
836            log_("FUNCTION $prog (@$args)\n", $config->{verbose}, $log,5);
837            my $todo = parseCommandLine($prog, $args, $functions->{$prog});
838            @$args and usage($prog, $functions->{$prog}, "disc $cd, function $fn, @$args, too many arguments");
839            foreach (@$todo) {
840                log_("config: todo $_->[2]\n", $config->{verbose}, $log, 4);
841                if (!&{$_->[0]}($cd, $fn, @{$_->[1]})) { log_("ERROR: $_->[2]\n", $config->{verbose}, $log); $nk = 1 }
842            }
843        }
844    }
845    $nk and return 0;
846    #printTable($config);
847    1
848}
849
850sub compute_files_md5 {
851    my ($md5file, $files) = @_;
852    open my $MD5, ">$md5file";
853    my $text;
854    foreach (@$files) {
855        my $md5 = new Digest::MD5;
856        open my $F, $_ or die "FATAL: Could not open $_\n";
857        $md5->addfile($F);
858        my $digest = $md5->hexdigest;
859        $text .= "$digest  $1\n" if m,([^/]+)$,
860    }
861    print $MD5 $text;
862    close $MD5
863}
864
865sub compute_md5 {
866    my ($to_check, $ignore) = @_;
867    my @files;
868    md5_add_tree($to_check, \@files, $ignore);
869    my $md5 = new Digest::MD5;
870    foreach (sort { $a->[0] cmp $b->[0] } @files) {
871        my $f = $_->[1];
872        open my $A, $f;
873        $md5->addfile($A);
874        #my $tmpmd5 = new Digest::MD5;
875        #local *A, open A, $f;
876        #$tmpmd5->addfile(*A);
877        #print "MD5: $_->[0] (", $tmpmd5->hexdigest() ,")\n";
878    }
879    my $digest = $md5->hexdigest;
880    # print "IGNORE " , join " ",keys %$ignore ,"\n";
881    return $digest
882}
883
884sub md5_add_tree {
885    my ($to_check, $files, $ignore) = @_;
886    foreach (@$to_check) {
887        my ($dest, $f) = @$_;
888        $f =~ m|/?\.{1,2}$| and next;
889        $f =~ /~$/ and next;
890        $f =~ s|//+|/|g;
891        $dest =~ s|//+|/|g;
892        $ignore->{$dest} and next;
893        if (-d $f) {
894            md5_add_tree([ map { [ "$dest/$_", "$f/$_" ] } all $f ], $files, $ignore)
895        } else {
896            push @$files, [ $dest, $f ]
897        }
898    }
899}
900
901sub log_ {
902    my ($msg, $verbose, $log, $level) = @_;
903    return if $level > $verbose;
904    my $LOG;
905    if (!$log) { open $LOG, ">&STDERR" } else { $LOG = $log }
906    print $LOG $msg;
907}
908
909# TODO must add some check of maximum authorized size
910sub include_md5 {
911    my ($iso, $write, $verbose) = @_;
912    my $ISO; 
913    if ($write) {
914        open $ISO, "+<$iso" or return "ERROR include_md5: unable to open $iso ($!)\n"; 
915    } else {
916        open $ISO, $iso or return "ERROR include_md5: unable to open $iso ($!)\n";     
917    }
918    binmode $ISO;
919    my $offset = 16*2048;
920    # blank header
921    seek $ISO, $offset, 0;
922    my ($buf, $msg);
923    while (1) {
924        read $ISO,$buf,2048;
925        my $c = ord $buf;
926        last if $c == 1;
927        return "ERROR include_md5: could not find primary volume descriptor\n" if $c == 255;
928        $offset += 2048
929    }
930    my $size = ((ord substr $buf, $SIZE_OFFSET, 1) * 0x1000000 + 
931                (ord substr $buf, $SIZE_OFFSET + 1, 1) * 0x10000 + 
932                (ord substr $buf, $SIZE_OFFSET + 2, 1) * 0x100 + 
933                (ord substr $buf, $SIZE_OFFSET + 3, 1)) * 2048;
934    my $volume = substr $buf, 30, 40;
935    $volume =~ s/^\s*(\S.*\S)\s*$/$1/;
936    my $id = substr $buf, 180, 20;
937    $msg = "include_md5: volume name $volume volume id: $id iso size $size\n";
938    seek $ISO, $offset + $INFO_OFFSET, 0;
939    read $ISO, $buf,512;
940    my ($md5sum) = $buf =~ /.md5 = (\S+)/;
941    $msg .= "include_md5: previous data $buf\n";
942    seek $ISO, 0, 0;
943    my $md5 = new Digest::MD5;
944    my $read = read $ISO, $buf, $offset + $INFO_OFFSET;
945    $md5->add($buf);
946    seek $ISO, 512, 1;
947    $read += 512;
948    $|=1;
949    my $val = int $size/2048/100;
950    $verbose and print "\rReading: 0 %";
951    my ($i, $j);
952    # skip last $SKIP bytes that sometimes are not correctly burned by some drives
953    my $n = 1;
954    while ($n && $read < $size - $SKIP * 2048) {
955        $n = read $ISO, $buf,2048;
956        print "\rReading: ", $j++, " %" if ($verbose && !($i++ % $val));
957        $md5->add($buf);
958        $read += $n;
959    }
960    print "\n";
961    my $digest = $md5->hexdigest;
962    $msg .= "include_md5: computed md5 $digest\n";
963    my $res = $md5sum eq $digest;
964    if ($md5sum) {
965        $msg .= "include_md5: previous md5 $md5sum\ninclude_md5: md5sum check ";
966        $msg .= $res ? "OK\n" : "FAILED\n"
967    }
968    print $msg if $verbose;
969    $write or return $res;
970    seek $ISO, $offset + $INFO_OFFSET, 0;
971    my $str = substr "$volume.md5 = $digest", 0, 512;
972    my $l = length $str;
973    print $ISO ($l > 512 ? substr $str, -1, 512 : $str . ' ' x (512 - $l));
974    close $ISO
975}
976
977sub convert_size {
978    my ($size, $default, $LOG) = @_;
979    if ($size =~ /[\d.]+g$/i) {
980        $size = $size * $GB;
981    } elsif ($size =~ /[\d+.]+m$/i) {
982        $size = $size * $MB;
983    } elsif ($size =~ /[\d+.]+k$/i) {
984        $size = $size * $KB;
985    } elsif ($size !~ /[\d+.]+$/i) {
986        log_("ERROR disc: $size is invalid, using default ($default)\n",1,$LOG);
987        $size = $default;
988    }                   
989   $size 
990}
991
992sub fix_dir {
993    chomp(my $pwd = `pwd`);
994    return map { m,^/, or $_ = "$pwd/$_"; $_ } @_
995}
996
9971
998
999#
1000# Changelog
1001#
1002# 2002 02 27
1003# make the locale constraint free on the right for cleanrpmsrate locale addition (kde-i18n-zh_BG and such)
1004#
1005# 2002 03 03
1006# fix typo in checkdiscs
1007#
1008# 2002 03 04
1009# fix checkcds pb with check[0] used.
1010#
1011# 2002 03 07
1012# add possibility to remove package from rpmsrate
1013#
1014# 2002 03 12
1015# add all .*kernel- in rpmsrate
1016#
1017# 2002 03 17
1018# add serial name instead of cdnumber when name is not know
1019#
1020# 2002 05 07
1021# add check_discs, compute_md5, write_graft, md5_add_tree
1022#
1023# 2002 05 22
1024# fix a pb in md5
1025#
1026# 2002 05 25
1027# add log function
1028#
1029# 2002 06 05
1030# fix md5 for isolinux
1031#
1032# 2002 08 12
1033# fix/change cleanrpmsrate
1034#
1035# 2002 09 04
1036# do not open for writing iso file in include_md5 if not in write mode
1037#
1038# 2002 09 25
1039# add completion feedback to include_md5
Note: See TracBrowser for help on using the repository browser.