chiark / gitweb /
* adt-xenlvm-with-testbed: sleep 1 after xm destroy, which is racy.
[autopkgtest.git] / runner / adt-testreport-onepackage
1 #!/bin/bash
2
3 set -e
4
5 salt=''
6 tmp=tmp
7 var=var
8 rsync=rsync
9 disable=true
10 interactive=true
11 target=source
12 suppressrepeatedemails=false
13 arch=`dpkg --print-architecture`
14 logheadmaxbytes=32768
15 logtailmaxbytes=32768
16
17 for config in "$@"; do
18         case "$config" in
19         *=*)    eval "$config"  ;;
20         *)      . "$config"     ;;
21         esac
22 done
23
24 if $disable; then
25         echo >&2 'disabled because config inadequate (no disable=false)'
26         exit 1
27 fi
28
29 : ${destdirtail:=$distro-$target}
30 : ${destdirfin:="$destdircommon$destdirtail"}
31
32 case $target in
33 source)
34         sources=Sources
35         descx=''
36         ;;
37 binary-*)
38         sources=Packages
39         descx="${target#binary-}"
40         ;;
41 *)
42         echo >&2 'target must be source or binary-*'
43         exit 1
44 esac
45
46 exec 3>&1
47 printf >&3 "starting "
48
49 rm -rf "$tmp"
50 mkdir "$tmp"
51
52 >"$tmp"/_log_raw
53
54 if $interactive; then
55         echo '(log diverted to stdout)' >>"$tmp"/_log_raw
56 else
57         exec >>"$tmp"/_log_raw
58 fi
59 exec 4>&1
60
61 progress () {
62         echo "++++++ $1 ++++++"
63 }
64
65 gurl () {
66         progress "fetching $1"
67         curl -fsS "$1" >"$2"
68 }
69
70 gurl "$mirror/dists/$distro/$suite/$target/$sources.gz" "$tmp"/_$sources.gz
71 zcat "$tmp"/_$sources.gz >"$tmp"/_$sources-in
72
73 lastinfo="$var"/lastinfo-$target
74 : "${scorelog:="$var"/scores-$target}"
75
76 now=`date +%s`
77 >>"$lastinfo"
78
79 progress selecting
80
81 if test $target = source; then
82         blacklist="$blacklistsourcepackages"
83 else
84         blacklist="$blacklistbinarypackages"
85 fi
86
87 if [ "x$pkg" = x ]; then
88  pkg="`perl -e '
89         use IO::Handle;
90
91         $pre= "[-+.0-9a-z]+";
92         $vre= "[-+.0-9a-zA-Z:~]+";
93
94         sub f1() { $fn=shift @ARGV; open F, $fn or die "$fn $!"; }
95         sub f2() { F->error and die "$fn $!"; close F or die "$fn $!"; }
96
97         $scorelog= "'"$scorelog"'";
98         if (length $scorelog) { open SCORE, "> $scorelog.new" or die $!; }
99         sub pscore ($;$) {
100                 return unless length $scorelog;
101                 printf SCORE "%$_[1]s", $_[0] or die $!;
102         }
103
104         sub readpkglist ($$) {
105                 my ($arrayref, $filename) = @_;
106                 return unless length $filename;
107                 unshift @ARGV, $filename; f1();
108                 while (<F>) {
109                         next if m/^\#/ or !m/\S/;
110                         die unless m/^($pre)(?:\S.*)?\s*$/;
111                         $arrayref->{$1}= 1;
112                 }
113                 f2();
114         }
115         readpkglist(\%suppress, "'"$suppresspackages"'");
116         readpkglist(\%blacklist, "'"$blacklist"'");
117
118         f1();
119         while (<F>) {
120                 die unless m/^($pre) ($vre) (\d+)( .*)?$/;
121                 $lastver{$1}= $2;
122                 $lasttime{$1}= $3;
123                 $extras{$1}= $4." ";
124         }
125         f2();
126         f1();
127         $best_score= -2e9;
128         sub scorepackage () {
129                 return if length $skip;
130                 return if $blacklist{$package};
131                 return if $score < $best_score
132                      or ($score==$best_score and \
133                          $package gt $best_package);
134 #printf STDERR " <----- best score=%s best_score=%s\n", $score, $best_score;
135                 pscore(" (best)");
136                 $best_score= $score;
137                 $best_package= $package;
138         }
139         sub endpackage () {
140                 return unless (defined $package
141                                 or defined $version
142                                 or defined $skip
143                                 or defined $source);
144                 die unless defined $package;
145                 die unless defined $version;
146                 $source= $package if !defined $source;
147
148                 $score= '$now' - $lasttime{$package};
149                 pscore("$package ",-30);
150                 pscore("$source ",-25);
151                 pscore("$score",10);
152
153                 if ($score>1e7) {
154                         $score= 1e7;
155                         $scorechars.='c';
156                 }
157                 pscore(" $lastver{$package}",-25);
158                 pscore(" $version ",-25);
159                 $scorechars= "";
160                 if ($lastver{$package} ne $version) {
161                         $score *= 5;
162                         $scorechars.="U";
163                 }
164                 if ($extras{$package} =~ m/ nt /) {
165                         $scorechars.="n";
166                 } else {
167                         $score *= 10;
168                 }
169                 if ($suppress{$source}) {
170                         $score -= 2e7;
171                         $scorechars.="s";
172                 }
173                 $scorechars.="[$skip]" if length $skip;
174
175                 pscore("-$scorechars",-7);
176                 pscore("$score",10);
177
178 #print STDERR "SCORE package=$package score $score source=$source\n";
179                 scorepackage();
180                 pscore("\n");
181                 undef $package;
182                 undef $version;
183                 undef $skip;
184                 undef $source;
185         }
186         while (<F>) {
187                 if (m/^Package: ($pre)$/) {
188                         die if defined $package;
189                         $package= $1;
190                 } elsif (m/^Version: ($vre)$/) {
191                         die if defined $version;
192                         $version= $1;
193                 } elsif (m/^Source: ($pre)$/) {
194                         die if defined $source;
195                         $source= $1;
196                 } elsif (m/^Architecture:.*/ &&
197                          !m/\s(?:'$arch'|all|any)\s/) {
198 #printf STDERR " <----- skip %s %s\n", $&, "'$arch'";
199                         $skip .= 'a';
200                 } elsif (m/^$/) {
201                         endpackage();
202                 }
203         }
204         f2();
205         endpackage();
206         if (length $scorelog) {
207                 close SCORE or die $!;
208                 rename "$scorelog.new","$scorelog" or die $!;
209         }
210         die unless length $best_package;
211         open L, ">&4" or die $!;
212         printf L "selected %s (age %s, score %d)\n",
213                 $best_package,
214                 exists($lastime{$best_package})
215                 ? '$now' - $lasttime{$best_package}
216                 : "<never-yet>",
217                 $best_score;
218         print "$best_package\n" or die $!;
219  ' "$lastinfo" "$tmp"/_$sources-in`"
220 else
221         printf >&4 "package forced: %s\n" "$pkg"
222 fi
223
224 sed -n "/^Package: $pkg\$/,/^\$/p" \
225  <"$tmp"/_$sources-in >"$tmp"/_this-stanza
226
227 echo
228 cat "$tmp"/_this-stanza
229
230 getfield () {
231         eval 'p'$1'="`
232                 sed -n '\''s/^'$1': //p'\'' \
233                  <"$tmp"/_this-stanza
234         `"'
235 }
236
237 printf >&3 "selected \"%s\" " $pkg
238
239 tp="$tmp/$pkg"
240 mkdir "$tp" "$tp/src" "$tp/tmp" "$tp/out"
241
242 getfield Version
243
244 getfield Source
245 if [ "x$pSource" != x ]; then
246         src="$pSource"
247 else
248         src="$pkg"
249 fi
250
251 if test $target = source; then
252         getfield Directory
253         leafnames="`
254                 sed -n '/^Files:/,/^([^ ].*)?$/{ /^ /{
255                         s/^ [0-9a-z][0-9a-z]*  *[0-9][0-9]* //; p
256                         }}' \
257                  <"$tmp"/_this-stanza
258         `"
259         for leafname in $leafnames; do
260                 df="$tp/src/$leafname"
261                 case "$leafname" in
262                 */*|.*) echo >&2 "bad leafname: $leafname"; exit 1;;
263                 *.dsc) fot="$df";;
264                 esac
265                 gurl "$mirror/$pDirectory/$leafname" "$df"
266         done
267         testmode=--source
268         testmode2=''
269         desc="$pkg"
270         : ${upload_if_ok:=true}
271         email_package_header="$email_sourcepackage_header"
272 else
273         getfield Filename
274         fot="$tp/src/$pkg.deb"
275         gurl "$mirror/$pFilename" "$fot"
276         testmode='--binaries=install --binary'
277         testmode2=--instantiate
278         desc="$pkg $descx"
279         : ${upload_if_ok:=false}
280         email_package_header="$email_binarypackage_header"
281 fi
282
283 if [ "x$maintainer_email_override" = x ]; then
284         getfield Maintainer
285         maintainer_email=pMaintainer
286 else
287         maintainer_email=maintainer_email_override
288 fi
289
290 printf >&3 "adt-run "
291
292 progress "starting test"
293
294 xrc () {
295         printf "+ %s\n" "$*"
296         set +e
297         "$@"
298         rc=$?
299         set -e
300 }
301
302 echo 'fatal: adt-run did not start properly' >"$tmp"/_summary
303
304 xrc adt-run --tmp-dir "$tp"/tmp                         \
305         --output-dir "$tp"/out                          \
306         --log-file "$tp"/log                            \
307         --summary "$tmp"/_summary                       \
308         $adtrun_extra_opts                              \
309         $testmode "$fot" $testmode2                     \
310  ---                                                    \
311  adt-virt-xenlvm                                        \
312         $adtvirt_extra_opts                             \
313         --distro="$distro"                              \
314  --                                                     \
315  2>&1 3>&- 4>&-
316
317 printf >&3 "%s " $rc
318
319 ourx=0
320 upload=true
321 : ${upload_if_notests:=false}
322 extras=''
323
324 case "$rc" in
325 0)      summary='all OK';                       email=''
326                                         upload=$upload_if_ok            ;;
327 2)      summary='OK (some skipped)';            email=''
328                                         upload=$upload_if_ok            ;;
329 8)      summary='package declares no tests';    email=''
330                                 upload=$upload_if_notests; extras='nt'  ;;
331 4|6)    summary='test(s) failed!';      email="$maintainer_email"       ;;
332 12)     summary='erroneous package!';   email="$maintainer_email"       ;;
333 16)     summary='testbed failed!';      email="administrator_email"     ;;
334 *)      summary='unexpected failure!';  email="administrator_email"; ourx=20;;
335 esac
336
337 progress "RESULTS $summary"
338
339 if  [ "x$suppresspackages" != x ] \
340  && grep -x "$src" "$suppresspackages" >/dev/null; then
341         printf >&3 "email-suppressed "
342         email=''
343 fi
344
345 if $upload; then
346         progress "bundling"
347         printf "\n%s\n" "$summary" >>"$tmp"/_summary
348
349         edest=${email%_email}
350         esummary="$var"/emailed/last-$pkg,$edest
351         if [ "x$edest" = x ]; then
352                 printf >&3 "email-none "
353                 rm -f "$var"/emailed/last-$pkg,*
354                 esummary=''
355         elif $suppressrepeatedemails \
356           && [ -f "$esummary" ] \
357           && diff -u "$esummary" "$tmp"/_summary >"$var"/emailed/diff-$pkg; then
358                 printf >&3 "email-same $email "
359                 email=''
360                 esummary=''
361         else
362                 cp "$tmp"/_summary "$esummary".new
363         fi
364
365         ln -f "$tmp"/_summary "$tp"/summary
366
367         for odir in tmp out; do
368                 if test -d "$tp"/$odir; then
369                         GZIP=-2 tar -f "$tp"/$odir.tar.gz -C "$tp" -zc $odir
370                         rm -r "$tp"/$odir
371                 fi
372         done
373
374         progress "uploading"
375         printf >&3 "uploading"
376         $rsync -rltH --safe-links --delete "$tp" "$destrsynchead/$destdirfin/"
377         printf >&3 " "
378 fi
379
380 if [ "x$email" != x ]; then
381         progress "contacting $email"
382         eval "email_addr=\$$email"
383         printf >&3 "email \"%s\" " "$email_addr"
384         cat >"$tmp"/_email_header <<END
385 From: $from
386 To: $email_addr
387 Subject: autopkgtest $distro $desc: $summary
388
389 END
390
391         email_package_header="${email_package_header//@p/$pkg}"
392         email_package_header="${email_package_header//@s/$src}"
393         email_package_header="${email_package_header//@v/$pVersion}"
394         email_package_header="${email_package_header//@a/@}"
395         printf >"$tmp"/_email "%s" "$email_package_header"
396
397         cat >>"$tmp"/_email <<END
398  Test executed for:  $distro  $target  $pkg
399  Outcome: $summary
400 END
401         sed -e 's/^/  /' "$tmp"/_summary >>"$tmp"/_email
402         cat >>"$tmp"/_email <<END
403
404 This message is automatically generated by the autopkgtest package
405 testing system.  You are receiving it because:
406 END
407         case "$email" in
408                 pMaintainer)
409                         cat >>"$tmp"/_email <<END
410  You are listed in the Maintainer field of the $pkg package in $distro
411  and the test results appear to indicate a problem with the package.
412 END
413                         ;;
414                 maintainer_email_override)
415                         cat >>"$tmp"/_email <<END
416  The test results appear to indicate a problem with the package
417  and reports for package maintainers for $distro are being directed to
418  $maintainer_email_override
419 END
420                         ;;
421                 administrator_email)
422                         cat >>"$tmp"/_email <<END
423  You are the administrator for the autopkgtest installation.
424 END
425                         ;;
426                 *)
427                         echo >&2 "huh email $email is what why?"
428                         exit 1
429                         ;;
430         esac
431         cat >>"$tmp/_email" <<END
432
433 The top and tail of the test log, which is intended to be sufficient
434 to diagnose most failures, can be found below.  However, in case this
435 is not sufficient, a complete log can be found along with output
436 files, saved temporary files, and so on, at:
437  $desthttphead/$destdirfin/
438 $email_extra_info
439 If you have any questions about this service please contact me at:
440  $from
441
442 Regards,
443 $salutation
444
445 -8<-
446 END
447 fi
448
449 printf >>"$var"/log "%s=%s rc=%s emailed='%s'\n" \
450         "$target" "$pkg" $rc "$email_addr"
451
452 if [ "x$ourx" = x0 ]; then
453         sed -e "/^$pkg /d" <"$lastinfo" >"$lastinfo".new
454         printf "%s %s %s %s\n" "$pkg" "$pVersion" "$now" "$extras" \
455                 >>"$lastinfo".new
456         mv "$lastinfo".new "$lastinfo"
457         progress "tested."
458 else
459         progress "fault ($ourx)."
460 fi
461
462 perl <"$tmp"/_log_raw >"$tmp"/_log -ne '
463         s/[^\012\040-\133\135-\176]/
464                 $& eq "\t" ? "\\t" :
465                 $& eq "\r" ? "\\r" :
466                 $& eq "\b" ? "\\b" :
467                 $& eq "\\" ? "\\\\" :
468                 sprintf "\\x%02x", ord $&
469         /ge;
470
471         if (!$middle) {
472                 $headlen += length;
473                 $middle=1 if $headlen > '"$logheadmaxbytes"';
474         }
475         if (!$middle) {
476                 print or die $!;
477         } else {
478                 $taillen += length;
479                 push @tail, $_;
480                 while ($taillen > '"$logtailmaxbytes"') {
481                         $taillen -= length shift @tail;
482                         $some_dropped= 1;
483                 }
484         }
485         END {
486                 print "...\n" or die $! if $some_dropped;
487                 print @tail or die $!;
488         }
489 '
490
491 if [ "x$email" = x ]; then
492         if $interactive; then
493                 cat "$tmp"/_log >&2
494         fi
495 else
496         cat >>"$tmp"/_email 2>&1 "$tmp"/_log ||:
497
498         if [ "x$email_signing_key" != x ]; then
499                 printf >&3 "signing "
500                 echo >>"$tmp/_email"
501                 gpg -u"$email_signing_key" --clearsign \
502                         <"$tmp/_email" >"$tmp/_email.asc"
503                 mv -f "$tmp/_email.asc" "$tmp/_email"
504         fi
505         cat "$tmp/_email_header" "$tmp/_email" >"$tmp/_email.new"
506         mv -f "$tmp/_email.new" "$tmp/_email"
507
508         if $interactive; then
509                 cat "$tmp"/_email >&2
510         else
511                 sendmail -odi -oem -t -oi <"$tmp"/_email
512                 if [ "x$esummary" != x ]; then
513                         printf >&3 "email-recorded "
514                         mv "$esummary".new "esummary"
515                 fi
516         fi
517 fi
518
519 printf >&3 "done %s.\n" $ourx
520 exit $ourx