2 # Filename: get_sources
3 # Purpose: Fetches sources and creates to report
4 # Authors: grml-team (grml.org), (c) Alexander Wirt
5 # Bug-Reports: see http://grml.org/bugs/
6 # License: This file is licensed under the GPL v2.
7 # Latest change: So Mai 06 00:35:39 CEST 2007 [formorer]
8 ################################################################################
14 use LWP::Simple qw(!head);
17 use CGI qw/:standard/;
18 use YAML qw( LoadFile );
19 use Params::Validate qw(:all);
23 #validates the configfile
24 sub validate_config ($) {
28 title => { type => SCALAR },
29 statusfile => { type => SCALAR },
30 chroot => { type => SCALAR },
31 reportdir => { type => SCALAR },
32 debug => { type => SCALAR, regex => qr/^(1|0)$/, optional => 1},
33 alternativeurl => { type => HASHREF, optional => 1},
34 updatesource => { type => SCALAR, regex => qr/^(1|0)$/, optional => 1},
36 on_fail => sub { print STDERR "Could not validate configfile: @_"; exit -1},
40 my $configfile = shift;
41 die "Usage: $0 <configfile>" unless $configfile && -f $configfile;
43 my $config = LoadFile($configfile);
44 validate_config($config);
45 my $debug = $config->{debug} || 0;
47 # if we can't write our reports and packages we can die soon ;)
48 if (! -d $config->{reportdir}) {
49 mkdir $config->{reportdir}
50 or die "Could not create reportdir '".$config->{reportdir}."':$!";
53 #fsrst build a package tree
54 die "Status file '".$config->{statusfile}."' not found" unless -f $config->{statusfile};
56 open (my $fh, '<', $config->{statusfile}) or die "Could not open status file '".$config->{statusfile}."': $!";
57 my ($package_tree, $package, $version, $source);
59 while (my $line = <$fh>) {
62 if ($line =~ /^Package: (.*)/) {
64 } elsif ($line =~ /^Version: (.*)/){
66 } elsif ($line =~ /Source: (.*)/){
67 if ($1 =~ /^(\S+) \(([^)]+)\)$/) {
73 } elsif ($line =~ /^$/) { #finalizing
74 $source = $source || $package;
76 #filter out binary nmus
77 if ($version =~ /^(.*)\+b/) {
79 } elsif ($version =~ /(.*-.*)\.0\.\d+$/) { #old bin nmu
81 } elsif ($version =~ /(.*-.*\.0)\.\d+$/) { #also old binnmu
84 if ($version && $source && $package) {
85 $package_tree->{$package}->{'version'} = $version;
86 $package_tree->{$package}->{'source'} = $source;
88 print STDERR "Finalizing of ($linenum) not possible: package='$package', source='$source', version='$version'";
90 ($source, $package, $version) = '';
97 system ("sudo chroot " . $config->{chroot} . " apt-get update") if $config->{updatesource};
99 foreach my $package (keys %{$package_tree}) {
100 print "Working on $package\n" if $debug;
102 my $version = $package_tree->{$package}->{'version'};
103 my $source = $package_tree->{$package}->{'source'};
104 if (exists $config->{alternativeurl}->{$source}) {
105 print "Alternativ URL for $source => " . $config->{alternativeurl}->{$source} . "\n" if $debug;
106 $package_tree->{$package}->{'status'} = 'OK/External';
107 $package_tree->{$package}->{'url'} = $config->{alternativeurl}->{$source};
110 $package_tree->{$package}->{'errors'} = ();
111 open (my $fh, '-|', "sudo chroot " . $config->{chroot} . " apt-get --print-uris -d source $source=$version 2>&1 ")
112 or warn "Could not launch chroot command:$!";
113 while (my $line = <$fh>) {
115 if ($line =~ /^'([^']+)'\s+(\S+)\s+(\S+)\s+(\S+)/) {
120 print "Filename: $filename\n" if $debug;
121 if (! -d $config->{reportdir}."/$source") {
122 mkdir ($config->{reportdir}."/$source")
123 or die "Could not create package dir '".$config->{reportdir}."/$source':$!";
126 if ( -e $config->{reportdir}."/$source/$filename" ) {
127 open(FILE, $config->{reportdir}."/$source/$filename")
128 or die "Can't open ".$config->{reportdir}."/$source/$filename: $!";
130 my $tested_md5sum = Digest::MD5->new->addfile(*FILE)->hexdigest;
131 if ($md5sum eq $tested_md5sum) {
132 print $config->{reportdir}."/$source/$filename already downloaded\n" if $debug;
135 print $config->{reportdir}."/$source/$filename corrupt - download again\n" if $debug;
140 print "Getting uri '$uri' to ".$config->{reportdir}. "/$source/$filename\n" if $debug;
141 my $ret = getstore($uri, $config->{reportdir}."/$source/$filename");
143 print STDERR "Could not download $uri - Server returned: " . status_message($ret) . "\n";
144 push @{$package_tree->{$package}->{'errors'}}, "$uri failed: " . status_message($ret);
147 open(FILE, $config->{reportdir}."/$source/$filename")
148 or die "Can't open ".$config->{reportdir}."/$source/$filename: $!";
150 my $tested_md5sum = Digest::MD5->new->addfile(*FILE)->hexdigest;
151 if ($md5sum eq $tested_md5sum) {
152 open (my $urifh, '>', $config->{reportdir}."/$source/$filename.md5")
153 or die "Could not open " . $config->{reportdir}."/$source/$filename.md5 for writing: $!";
154 print $urifh $md5sum;
156 open ($urifh, '>', $config->{reportdir}."/$source/$filename.uri")
157 or die "Could not open " . $config->{reportdir}."/$source/$filename.uri for writing: $!";
158 print $urifh "$uri\n";
161 print STDERR "md5sum mismatch of $uri\n";
162 push @{$package_tree->{$package}->{'errors'}}, "$uri failed: md5sum mismatch";
166 } elsif ($line =~ /^E: (.*)/) {
167 push @{$package_tree->{$package}->{'errors'}}, "$1";
168 print STDERR "Got an error from apt-get for package $package (Source: $source, Version: $version): $1\n";
174 print "Package $package failed:\n" if $debug;
175 print join("\n", @{$package_tree->{$package}->{'errors'}}) . "\n" if $debug;
176 $package_tree->{$package}->{'status'} = 'FAILED';
178 print "Package $package successfull\n" if $debug;
179 $package_tree->{$package}->{'status'} = 'OK';
183 my $t = new HTML::Table(
186 -head=> ['Package','Source','Version', 'Status'],
188 foreach my $package (sort(keys %{$package_tree})) {
189 if ($package_tree->{$package}->{'status'} eq 'OK') {
190 $t->addRow( $package,
191 "<a href='". $package_tree->{$package}->{'source'} . "'>" . $package_tree->{$package}->{'source'} . "</a>",
192 $package_tree->{$package}->{'version'},
193 $package_tree->{$package}->{'status'}
195 } elsif ($package_tree->{$package}->{'status'} eq 'FAILED') {
196 open (my $fh, '>', $config->{reportdir}."/$package-error.html")
197 or die "Could not create error file '".$config->{reportdir}."/$package-error.html': $!";
198 print $fh start_html("Errors for $package (" . $package_tree->{$package}->{'version'} . ")");
199 print $fh "<h2>Errors for $package (". $package_tree->{$package}->{'version'} . ")</h2>";
200 print $fh join("<br>\n", @{$package_tree->{$package}->{'errors'}});
201 print $fh "<br><br><a href='index.html'>Back to index</a>";
204 $t->addRow( $package,
205 $package_tree->{$package}->{'source'},
206 $package_tree->{$package}->{'version'},
207 "<a href='$package-error.html'>".$package_tree->{$package}->{'status'}."</a>"
209 } elsif ($package_tree->{$package}->{'status'} eq 'OK/External') {
210 $t->addRow( $package,
211 "<a href='".$package_tree->{$package}->{'url'} . "'>" . $package_tree->{$package}->{'source'} . "</a>",
212 $package_tree->{$package}->{'version'},
213 $package_tree->{$package}->{'status'}
219 copy($config->{chroot}."/etc/apt/sources.list", $config->{reportdir}."/sources.list") or die "Sources list cannot be copied: $!";
221 #first some statistics
222 my $pnum = keys(%{$package_tree});
225 foreach my $package (keys(%{$package_tree})) {
226 $errors++ if $package_tree->{$package}->{'status'} =~ /^OK/;
227 if (! exists $s_hash{ $package_tree->{$package}->{'source'} }) {
228 $s_hash{$package_tree->{$package}->{'source'}} = 1;
232 my $snum = keys(%s_hash);
233 open ($fh, '>', $config->{reportdir}."/index.html") or die "Could not create indexfile '".$config->{reportdir}."/index.html': $!";
234 print $fh start_html("Report for " . $config->{title});
235 print $fh "<center><h2>Report for " . $config->{title} . "</h2>";
236 print $fh "<b>Packages:</b> $pnum<br>";
237 print $fh "<b>Sources:</b> $snum<br>";
238 print $fh "<b>Errors:</b> $errors (" . $errors/$snum*100 . "%)<br>";
239 print $fh "<a href='sources.list'>Sources list of the chroot</a><br><br>";