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