Add match for missing source package
[buildd-scripts.git] / bin / analyze_results
1 #! /usr/bin/perl
2 #
3 # analyze_results
4 #
5 # Script to analyze failed build logs. Look for specific regexps to
6 # classify things
7 #
8 #
9 # (c) 2018 Steve McIntyre <steve@einval.com> GPL v2+
10
11 use strict;
12 use warnings;
13 use POSIX qw(strftime);
14 use Data::Dumper;
15
16 my $name = "analyze_results";
17 my $repo = "https://git.einval.com/cgi-bin/gitweb.cgi?p=buildd-scripts.git";
18 my $hostname;
19 my $date;
20 my $time_start = time();
21 my $time_end;
22 my $time_taken;
23 my $num_fail = 0;
24 my $lines_read = 0;
25 my $existing_bugs = 0;
26
27 use constant {
28     ERR_ARCH_MISMATCH      => 1,
29     ERR_NO_SOURCE          => 2,
30     ERR_INFRA              => 3,
31     ERR_BD_PROBLEM         => 4,
32     ERR_DETECT_WRONG_ARCH  => 5,
33     ERR_CRASH              => 6,
34     ERR_BUILD_PROBLEM      => 7,
35     ERR_TEST_PROBLEM       => 8,
36     ERR_BUILD_TIMEOUT      => 9,
37 };
38
39 my @err_descriptions;
40 $err_descriptions [ERR_ARCH_MISMATCH]     = "Architecture mismatches";
41 $err_descriptions [ERR_NO_SOURCE]         = "No source found";
42 $err_descriptions [ERR_INFRA]             = "Infrastructure errors";
43 $err_descriptions [ERR_BD_PROBLEM]        = "Problems with build-deps";
44 $err_descriptions [ERR_DETECT_WRONG_ARCH] = "Builds detected wrong architecture";
45 $err_descriptions [ERR_CRASH]             = "Crashes detected";
46 $err_descriptions [ERR_BUILD_PROBLEM]     = "Problems detected during build phase";
47 $err_descriptions [ERR_TEST_PROBLEM]      = "Problems detected during test phase";
48 $err_descriptions [ERR_BUILD_TIMEOUT]     = "Package builds timed out";
49
50 # Known failure modes to look for
51 my @logcheck = (
52     {
53         # "rchitecture mismatch" -> should never build on this arch
54         # Stop working on this log at this point
55         string   => 'rchitecture mismatch',
56         message  => 'Architecture mismatch',
57         check    => 1,
58         stop     => 1,
59         type     => ERR_ARCH_MISMATCH,
60     },
61     {
62         string   => 'not in arch list or does not match any',
63         message  => 'Architecture mismatch',
64         check    => 1,
65         stop     => 1,
66         type     => ERR_ARCH_MISMATCH,
67     },
68     {
69         # "binary build with no binary artifacts found" -> no packages
70         # built. Why not picked up already above?.
71         # Stop working on this log at this point
72         string   => 'binary build with no binary artifacts found',
73         message  => 'No binaries built',
74         check    => 1,
75         stop     => 1,
76         type     => ERR_ARCH_MISMATCH,
77     },
78     {
79         string   => 'E: Can not find version \S+ of package',
80         message  => 'Could not find specified source package',
81         check    => 1,
82         stop     => 1,
83         type     => ERR_NO_SOURCE,
84     },
85     {
86         string   => 'schroot.*File is not owned by user root',
87         message  => 'Schroot setup failure',
88         check    => 1,
89         stop     => 1,
90         type     => ERR_INFRA,
91     },
92     {
93         string   => 'No space left on device',
94         message  => 'Build ran out of disk space',
95         check    => 1,
96         stop     => 1,
97         type     => ERR_INFRA,
98     },
99     {
100         string   => 'The system has no more ptys',
101         message  => 'Build ran out of ptys',
102         check    => 1,
103         stop     => 1,
104         type     => ERR_INFRA,
105     },
106     {
107         string   => 'aarch64-unknown-linux-gnu',
108         message  => 'Wrong arch detected',
109         check    => 1,
110         stop     => 1,
111         type     => ERR_DETECT_WRONG_ARCH,
112     },
113     {
114         string   => 'binutils-aarch64',
115         message  => 'Wrong arch detected',
116         check    => 0,
117         stop     => 1,
118         type     => ERR_DETECT_WRONG_ARCH,
119     },
120     {
121         string   => 'lib.linux-aarch64',
122         message  => 'Wrong arch detected',
123         check    => 1,
124         stop     => 1,
125         type     => ERR_DETECT_WRONG_ARCH,
126     },
127     {
128         # "Bus error" -> alignment bug
129         string   => 'Bus error',
130         message  => 'Alignment problem',
131         check    => 1,
132         stop     => 1,
133         type     => ERR_CRASH,
134     },
135     {
136         # "Segmentation fault" -> code problem
137         string   => 'Segmentation fault',
138         pstring  => 'Setting up (\S+)',
139         message  => 'Segmentation fault when installing RESULT',
140         check    => 1,
141         stop     => 1,
142         type     => ERR_CRASH,
143     },
144     {
145         # "Segmentation fault" -> code problem
146         string   => 'Segmentation fault',
147         message  => 'Segmentation fault',
148         check    => 1,
149         stop     => 1,
150         type     => ERR_CRASH,
151     },
152     {
153         # "Illegal instruction" -> bad build target?
154         string   => 'Illegal instruction',
155         pstring  => 'Setting up (\S+)',
156         message  => 'Illegal instruction when installing RESULT',
157         check    => 1,
158         stop     => 1,
159         type     => ERR_CRASH,
160     },
161     {
162         # "Illegal instruction" -> bad build target?
163         string   => 'Illegal instruction',
164         message  => 'Illegal instruction',
165         check    => 1,
166         stop     => 1,
167         type     => ERR_CRASH,
168     },
169     {
170         # Installing build-deps failed
171         string   => 'dpkg: error processing package (\S+)',
172         message  => 'Build-dep failed to install (RESULT)',
173         check    => 1,
174         stop     => 0,
175         type     => ERR_BD_PROBLEM,
176     },
177     {
178         # Installing build-deps failed
179         string   => 'E: pbuilder-satisfydepends failed.',
180         message  => 'Pbuilder build-deps failed',
181         check    => 1,
182         stop     => 1,
183         type     => ERR_BD_PROBLEM,
184     },
185     {
186         # Installing build-deps failed
187         string   => 'E: Unmet dependencies',
188         message  => 'Build-deps failed',
189         check    => 1,
190         stop     => 1,
191         type     => ERR_BD_PROBLEM,
192     },
193     {
194         # Installing build-deps failed
195         string   => 'unsat-dependency: (\S+)',
196         message  => 'Missing build-dep (RESULT)',
197         check    => 1,
198         stop     => 1,
199         type     => ERR_BD_PROBLEM,
200     },
201     {
202         # Installing build-deps failed
203         string   => 'unsat-conflict: (\S+)',
204         message  => 'Unsatisfiable build-dep conflict (RESULT)',
205         check    => 1,
206         stop     => 1,
207         type     => ERR_BD_PROBLEM,
208     },
209     {
210         # Build failed - missing build-dep?
211         string   => 'build dependencies/conflicts unsatisfied',
212         message  => 'Build-deps not satisfiable',
213         check    => 1,
214         stop     => 1,
215         type     => ERR_BD_PROBLEM,
216     },
217     {
218         # Build failed
219         string   => 'dpkg-source: error: unrepresentable changes to source',
220         message  => 'dpkg-source failure',
221         check    => 1,
222         stop     => 1,
223         type     => ERR_BUILD_PROBLEM,
224     },
225     {
226         # Build failed - missing build-dep?
227         string   => 'ld: cannot find',
228         message  => 'Build failure: missing library - missing build-dep?',
229         check    => 1,
230         stop     => 1,
231         type     => ERR_BUILD_PROBLEM,
232     },
233     {
234         # Build failed - missing build-dep?
235         string   => 'fatal error:.*No such file or directory',
236         message  => 'Build failure: missing header - missing build-dep?',
237         check    => 1,
238         stop     => 1,
239         type     => ERR_BUILD_PROBLEM,
240     },
241     {
242         # Build failed - missing build-dep?
243         string   => 'SEVERE: Cannot resolve dependencies',
244         message  => 'Build failure - missing build-dep?',
245         check    => 1,
246         stop     => 1,
247         type     => ERR_BUILD_PROBLEM,
248     },
249     {
250         # Build failed - can't exec something...
251         string   => 'error trying to exec.*execvp: No',
252         message  => 'Build failure (missing binary)',
253         check    => 1,
254         stop     => 1,
255         type     => ERR_BUILD_PROBLEM,
256     },
257     {
258         # Build failed
259         string   => 'BUILD FAIL',
260         message  => 'Build failure (java/javadoc)',
261         check    => 1,
262         stop     => 1,
263         type     => ERR_BUILD_PROBLEM,
264     },
265     {
266         # Build failed
267         string   => 'make.*returned exit code',
268         message  => 'Build failure (other)',
269         check    => 1,
270         stop     => 0,
271         type     => ERR_BUILD_PROBLEM,
272     },
273     {
274         # Build failed
275         string   => '^make.*\*\*\*.* \[debian/rules.*Error \d+$',
276         message  => 'Build failure (other)',
277         check    => 1,
278         stop     => 1,
279         type     => ERR_BUILD_PROBLEM,
280     },
281     {
282         # Build failure
283         string   => 'dh_auto_build:.*returned exit code \d+',
284         message  => 'Build failure (other)',
285         check    => 1,
286         stop     => 1,
287         type     => ERR_BUILD_PROBLEM,
288     },
289     {
290         # Build failure
291         string   => 'dh_auto_clean:.*returned exit code \d+',
292         message  => 'Build failure (clean failed)',
293         check    => 1,
294         stop     => 1,
295         type     => ERR_BUILD_PROBLEM,
296     },
297     {
298         # Build failure
299         string   => 'dh_auto_install:.*returned exit code \d+',
300         message  => 'Build failure (install failed)',
301         check    => 1,
302         stop     => 1,
303         type     => ERR_BUILD_PROBLEM,
304     },
305     {
306         # Build failure
307         string   => 'dh_auto_configure:.*returned exit code \d+',
308         message  => 'Build failure (configure failed)',
309         check    => 1,
310         stop     => 1,
311         type     => ERR_BUILD_PROBLEM,
312     },
313     {
314         # Build failed
315         string   => '^debian/.*recipe for target (\S+) failed',
316         message  => 'Build failure (RESULT)',
317         check    => 1,
318         stop     => 1,
319         type     => ERR_BUILD_PROBLEM,
320     },
321     {
322         # Build failed
323         string   => '^debian/.*\*\*\* (.*).  Stop.',
324         message  => 'Build error (RESULT)',
325         check    => 1,
326         stop     => 1,
327         type     => ERR_BUILD_PROBLEM,
328     },
329     {
330         # Build failed
331         string   => 'dpkg-buildpackage: error: (debian/rules \S+) subprocess returned exit status 2',
332         message  => 'Build error (RESULT)',
333         check    => 1,
334         stop     => 1,
335         type     => ERR_BUILD_PROBLEM,
336     },
337     {
338         # Build failed
339         string   => 'fakeroot debian/rules binary',
340         message  => 'Build failure (other)',
341         check    => 0,
342         stop     => 1,
343         type     => ERR_BUILD_PROBLEM,
344     },
345     {
346         # Test failure
347         string   => 'OSError: \[Errno 13\] Permission denied',
348         message  => 'Python EPERM test failure',
349         check    => 1,
350         stop     => 1,
351         type     => ERR_TEST_PROBLEM,
352     },
353     {
354         # Test failure
355         string   => 'dh_auto_test:.*returned exit code \d+',
356         message  => 'Test failure',
357         check    => 1,
358         stop     => 1,
359         type     => ERR_TEST_PROBLEM,
360     },
361     {
362         # Timeout. pbuilder is too dumb to do this properly :-(
363         string   => 'I: Terminating build process due to timeout',
364         message  => 'Pbuilder build timeout',
365         check    => 1,
366         stop     => 1,
367         type     => ERR_BUILD_TIMEOUT,
368     },
369     {
370         # Timeout from sbuild
371         string   => 'Build killed with signal TERM after \d+ minutes of inactivity',
372         message  => 'Sbuild build timeout',
373         check    => 1,
374         stop     => 1,
375         type     => ERR_BUILD_TIMEOUT,
376     },
377 );
378
379 my %log_results;
380
381 #foreach my $checktmp (@logcheck) {
382 #    my %check = %$checktmp;
383 #    print "looking for \"$check{string}\"\n";
384 #    print "  with log message \"$check{message}\"\n";
385 #    print "  check this regexp: $check{check}\n";
386 #    print "  stop if found: $check{stop}\n";
387 #}
388
389 print "<html>\n";
390 print "<head>\n";
391 print "<title>Build log analysis</title>\n";
392 print "</head>\n";
393 print "<body>\n";
394 print "<h1>Build log analysis</h1>\n";
395 print "<p><a href=\"#summary\">Summary</a></p>\n";
396 print "<h2>Packages</h2>\n";
397 print "<ol>\n";
398
399 foreach my $input (@ARGV) {
400     open (IN, "< $input") or die "Can't read $input: $!\n";
401     $num_fail++;
402     my $stop = 0;
403     my $lineno = 0;
404     my $errors = 0;
405     my $oldline = "";
406     my %file_results;
407     print "<li>Looking at <a href=\"$input\">$input</a>:\n";
408     print "<ul>\n";
409     while (defined (my $line = <IN>) and !$stop) {
410         $lineno++;
411         $lines_read++;
412         foreach my $checktmp (@logcheck) {
413             my %check = %$checktmp;
414             if ($check{check}) {
415                 if (!$stop
416                     and ($line =~ m/$check{string}/)
417                     and (!$check{pstring} or $oldline =~ m/$check{pstring}/)) {
418 #                   print "  Line $lineno: found \"$check{string}\"\n";
419                     my $match = $1;
420                     my $message = $check{message};
421                     $message =~ s,RESULT,$match,g;
422                     $file_results{$message} = $check{type};
423                     if (($check{type} == ERR_BUILD_TIMEOUT) and ($errors == 0)) {
424                         print "  <li>Line $lineno: $message\n";
425                         print "  <li>Build killed by timeout before any errors at line $lineno\n";
426                     } else {
427                         print "  <li>Line $lineno: $message\n";
428                         $errors++;
429                     }
430                     if ($check{stop}) {
431 #                       print "  stopping processing\n";
432                         $stop = 1;
433                     }
434                 }
435             }
436         }
437         $oldline = $line;
438     }
439     close IN;
440     # End of checking this package
441     print "  <li><strong>Found errors: $errors</strong>\n";
442     if (!$errors) {
443         print " (maybe just timed out during build?)\n";
444     }
445
446     # Look for a note for manually-added logfile analysis
447     my $note = $input;
448     $note =~ s,\.log$,.note,;
449     if (-f $note) {
450         open (IN, "< $note") or die "Can't open $note for reading: $!\n";
451         while (defined (my $line = <IN>)) {
452             chomp $line;
453             if ($line =~ m,#(\d+),) {
454                 my $bugno = $1;
455                 $existing_bugs++;
456                 $line =~ s,#(\d+),<a href="https://bugs.debian.org/$1">#$1</a>,g;
457             }
458             print "  <li>$line\n";
459         }
460         close IN;
461     }
462
463     print "</ul>\n";
464     foreach my $key (keys %file_results) {
465         $log_results{$file_results{$key}}{$key} += 1;
466 #       print "now have $log_results{$key} for \"$key\"\n";
467     }
468 }
469 print "</ol>\n";
470
471 print "<a name=\"summary\"</a>\n";
472 print "<h2>Summary of results from $num_fail failed builds:</h2>\n";
473 print "<ul>\n";
474 print "<li>  Found $existing_bugs existing bugs in the Debian BTS</li>\n";
475 foreach my $type (sort keys %log_results) {
476     print "  <h3>$err_descriptions[$type]</h3>\n";
477     my $tmp = $log_results{$type};
478     my %result = %$tmp;
479     foreach my $key (sort { $result{$b} <=> $result{$a} }keys %result) {
480         print "  <li>Found $result{$key} log(s) showing $key\n";
481     }
482 }
483 print "</ul>\n";
484
485 $time_end = time();
486 $time_taken = $time_end - $time_start;
487 $date = strftime "%a %b %e %H:%M:%S %Z %Y", localtime;
488 $hostname = `hostname`;
489 chomp $hostname;
490
491 print "<hr>\n";
492 print "<p>Log analysis generated on $hostname, $date.\n";
493 print "<br>Output from $name - see <a href=\"$repo\">$repo</a> for source.\n";
494 print "<br>Read $lines_read lines of logs and took $time_taken seconds to complete.\n";
495
496 print "</body>\n";
497 print "</html>\n";