chiark / gitweb /
* adt-testreport-runloop: fix handling of test_classes (was xoptslist)
[autopkgtest.git] / runner / adt-testreport-onepackage
index 23374f77ea2772bf5db9767cd01ebfe3f41dd103..b0f138bd05289160939c7878f384f4df4eb78b7c 100755 (executable)
@@ -2,26 +2,61 @@
 
 set -e
 
-mirror=http://mirror.relativity.greenend.org.uk/mirror/ubuntu.good
-distro=feisty
-suite=main
 salt=''
 tmp=tmp
 var=var
-administrator_email=ian@davenant.greenend.org.uk
-maintainer_email_override="$administrator_email"
-salutation="Ian"
-from="$salutation Jackson <ian@davenant.greenend.org.uk>"
 rsync=rsync
+disable=true
+interactive=true
+target=source
+suppressrepeatedemails=false
+arch=`dpkg --print-architecture`
+logheadmaxbytes=32768
+logtailmaxbytes=32768
+
+for config in "$@"; do
+       case "$config" in
+       *=*)    eval "$config"  ;;
+       *)      . "$config"     ;;
+       esac
+done
+
+if $disable; then
+       echo >&2 'disabled because config inadequate (no disable=false)'
+       exit 1
+fi
+
+: ${destdirtail:=$distro-$target}
+: ${destdirfin:="$destdircommon$destdirtail"}
+
+case $target in
+source)
+       sources=Sources
+       descx=''
+       ;;
+binary-*)
+       sources=Packages
+       descx="${target#binary-}"
+       ;;
+*)
+       echo >&2 'target must be source or binary-*'
+       exit 1
+esac
 
-destdirtail=autopkgtest-output/$distro
-destrsynchead=ijackson@chiark:public-html/
-desthttphead=http://www.chiark.greenend.org.uk/~ijackson/
+exec 3>&1
+printf >&3 "starting "
 
 rm -rf "$tmp"
 mkdir "$tmp"
 
-exec >"$tmp"/log
+>"$tmp"/_log_raw
+
+if $interactive; then
+       echo '(log diverted to stdout)' >>"$tmp"/_log_raw
+else
+       exec >>"$tmp"/_log_raw
+fi
+exec 4>&1
 
 progress () {
        echo "++++++ $1 ++++++"
@@ -29,64 +64,221 @@ progress () {
 
 gurl () {
        progress "fetching $1"
-       curl -sS "$1" >"$2"
+       curl -fsS "$1" >"$2"
 }
 
-gurl "$mirror/dists/$distro/$suite/source/Sources.gz" "$tmp"/sources.gz
-zcat "$tmp"/sources.gz >"$tmp"/sources-in
+gurl "$mirror/dists/$distro/$suite/$target/$sources.gz" "$tmp"/_$sources.gz
+zcat "$tmp"/_$sources.gz >"$tmp"/_$sources-in
 
-sed -n 's/^Package: \([-+.0-9a-z][-+.0-9a-z]*\)$/\1/p' \
- <"$tmp"/sources-in >"$tmp"/sources-packages
+lastinfo="$var"/lastinfo-$target
+: "${scorelog:="$var"/scores-$target}"
 
-if test -f "$var"/last; then
-       sed -e 's/$/ _/' "$var"/last >>"$tmp"/sources-packages
+now=`date +%s`
+>>"$lastinfo"
+
+progress selecting
+
+if test $target = source; then
+       blacklist="$blacklistsourcepackages"
 else
-       echo ' _' >>"$tmp"/sources-packages
+       blacklist="$blacklistbinarypackages"
 fi
 
-sort <"$tmp"/sources-packages >"$tmp"/all-sorted
-pkg="`
-       perl -ne '
-               if ($now) { print or die $!; $now++; exit; }
-               $now = m/ _$/;
-               END { die unless $now>1; }
-       ' <"$tmp"/all-sorted
-`"
-
-progress "selected $pkg"
+if [ "x$pkg" = x ]; then
+ pkg="`perl -e '
+       use IO::Handle;
+
+       $pre= "[-+.0-9a-z]+";
+       $vre= "[-+.0-9a-zA-Z:~]+";
+
+       sub f1() { $fn=shift @ARGV; open F, $fn or die "$fn $!"; }
+       sub f2() { F->error and die "$fn $!"; close F or die "$fn $!"; }
+
+       $scorelog= "'"$scorelog"'";
+       if (length $scorelog) { open SCORE, "> $scorelog.new" or die $!; }
+       sub pscore ($;$) {
+               return unless length $scorelog;
+               printf SCORE "%$_[1]s", $_[0] or die $!;
+       }
+
+       sub readpkglist ($$) {
+               my ($arrayref, $filename) = @_;
+               return unless length $filename;
+               unshift @ARGV, $filename; f1();
+               while (<F>) {
+                       next if m/^\#/ or !m/\S/;
+                       die unless m/^($pre)\s*$/;
+                       $arrayref->{$1}= 1;
+               }
+               f2();
+       }
+       readpkglist(\%suppress, "'"$suppresspackages"'");
+       readpkglist(\%blacklist, "'"$blacklist"'");
+
+       f1();
+       while (<F>) {
+               die unless m/^($pre) ($vre) (\d+)( .*)?$/;
+               $lastver{$1}= $2;
+               $lasttime{$1}= $3;
+               $extras{$1}= $4." ";
+       }
+       f2();
+       f1();
+       $best_score= -2e9;
+       sub scorepackage () {
+               return if length $skip;
+               return if $blacklist{$package};
+               return if $score < $best_score
+                    or ($score==$best_score and \
+                        $package gt $best_package);
+#printf STDERR " <----- best score=%s best_score=%s\n", $score, $best_score;
+               pscore(" (best)");
+               $best_score= $score;
+               $best_package= $package;
+       }
+       sub endpackage () {
+               return unless (defined $package
+                               or defined $version
+                               or defined $skip
+                               or defined $source);
+               die unless defined $package;
+               die unless defined $version;
+               $source= $package if !defined $source;
+
+               $score= '$now' - $lasttime{$package};
+               pscore("$package ",-30);
+               pscore("$source ",-25);
+               pscore("$score",10);
+
+               if ($score>1e7) {
+                       $score= 1e7;
+                       $scorechars.='c';
+               }
+               pscore(" $lastver{$package}",-25);
+               pscore(" $version ",-25);
+               $scorechars= "";
+               if ($lastver{$package} ne $version) {
+                       $score *= 5;
+                       $scorechars.="U";
+               }
+               if ($extras{$package} =~ m/ nt /) {
+                       $scorechars.="n";
+               } else {
+                       $score *= 10;
+               }
+               if ($suppress{$source}) {
+                       $score -= 2e7;
+                       $scorechars.="s";
+               }
+               $scorechars.="[$skip]" if length $skip;
+
+               pscore("-$scorechars",-7);
+               pscore("$score",10);
+
+#print STDERR "SCORE package=$package score $score source=$source\n";
+               scorepackage();
+               pscore("\n");
+               undef $package;
+               undef $version;
+               undef $skip;
+               undef $source;
+       }
+       while (<F>) {
+               if (m/^Package: ($pre)$/) {
+                       die if defined $package;
+                       $package= $1;
+               } elsif (m/^Version: ($vre)$/) {
+                       die if defined $version;
+                       $version= $1;
+               } elsif (m/^Source: ($pre)$/) {
+                       die if defined $source;
+                       $source= $1;
+               } elsif (m/^Architecture:.*/ &&
+                        !m/\s(?:'$arch'|all|any)\s/) {
+#printf STDERR " <----- skip %s %s\n", $&, "'$arch'";
+                       $skip .= 'a';
+               } elsif (m/^$/) {
+                       endpackage();
+               }
+       }
+       f2();
+       endpackage();
+       if (length $scorelog) {
+               close SCORE or die $!;
+               rename "$scorelog.new","$scorelog" or die $!;
+       }
+       die unless length $best_package;
+       open L, ">&4" or die $!;
+       printf L "selected %s (age %s, score %d)\n",
+               $best_package,
+               exists($lastime{$best_package})
+               ? '$now' - $lasttime{$best_package}
+               : "<never-yet>",
+               $best_score;
+       print "$best_package\n" or die $!;
+ ' "$lastinfo" "$tmp"/_$sources-in`"
+else
+       printf >&4 "package forced: %s\n" "$pkg"
+fi
 
 sed -n "/^Package: $pkg\$/,/^\$/p" \
- <"$tmp"/sources-in >"$tmp"/this-stanza
+ <"$tmp"/_$sources-in >"$tmp"/_this-stanza
 
-cat "$tmp"/this-stanza
+echo
+cat "$tmp"/_this-stanza
 
 getfield () {
        eval 'p'$1'="`
                sed -n '\''s/^'$1': //p'\'' \
-                <"$tmp"/this-stanza
+                <"$tmp"/_this-stanza
        `"'
 }
 
-getfield Directory
-
-leafnames="`
-       sed -n '/^Files:/,/^([^ ].*)?$/{ /^ /{
-               s/^ [0-9a-z][0-9a-z]*  *[0-9][0-9]* //; p
-               }}' \
-        <"$tmp"/this-stanza
-`"
+printf >&3 "selected \"%s\" " $pkg
 
 tp="$tmp/$pkg"
 mkdir "$tp" "$tp/src" "$tp/tmp" "$tp/out"
 
-for leafname in $leafnames; do
-       df="$tp/src/$leafname"
-       case "$leafname" in
-       */*|.*) echo >&2 "bad leafname: $leafname"; exit 1;;
-       *.dsc) dsc="$df";;
-       esac
-       gurl "$mirror/pool/$suite/$pDirectory/$leafname" "$df"
-done
+getfield Version
+
+getfield Source
+if [ "x$pSource" != x ]; then
+       src="$pSource"
+else
+       src="$pkg"
+fi
+
+if test $target = source; then
+       getfield Directory
+       leafnames="`
+               sed -n '/^Files:/,/^([^ ].*)?$/{ /^ /{
+                       s/^ [0-9a-z][0-9a-z]*  *[0-9][0-9]* //; p
+                       }}' \
+                <"$tmp"/_this-stanza
+       `"
+       for leafname in $leafnames; do
+               df="$tp/src/$leafname"
+               case "$leafname" in
+               */*|.*) echo >&2 "bad leafname: $leafname"; exit 1;;
+               *.dsc) fot="$df";;
+               esac
+               gurl "$mirror/$pDirectory/$leafname" "$df"
+       done
+       testmode=--source
+       testmode2=''
+       desc="$pkg"
+       : ${upload_if_ok:=true}
+       email_package_header="$email_sourcepackage_header"
+else
+       getfield Filename
+       fot="$tp/src/$pkg.deb"
+       gurl "$mirror/$pFilename" "$fot"
+       testmode='--binaries=install --binary'
+       testmode2=--instantiate
+       desc="$pkg $descx"
+       : ${upload_if_ok:=false}
+       email_package_header="$email_binarypackage_header"
+fi
 
 if [ "x$maintainer_email_override" = x ]; then
        getfield Maintainer
@@ -95,6 +287,8 @@ else
        maintainer_email=maintainer_email_override
 fi
 
+printf >&3 "adt-run "
+
 progress "starting test"
 
 xrc () {
@@ -105,66 +299,127 @@ xrc () {
        set -e
 }
 
+echo 'fatal: adt-run did not start properly' >"$tmp"/_summary
+
 xrc adt-run --tmp-dir "$tp"/tmp                                \
        --output-dir "$tp"/out                          \
        --log-file "$tp"/log                            \
-       --source "$dsc"                                 \
+       --summary "$tmp"/_summary                       \
+       $adtrun_extra_opts                              \
+       $testmode "$fot" $testmode2                     \
  ---                                                   \
  adt-virt-xenlvm                                       \
-       distro="$distro"                                \
- 2>&1
+       $adtvirt_extra_opts                             \
+       --distro="$distro"                              \
+ --                                                    \
+ 2>&1 3>&- 4>&-
+
+printf >&3 "%s " $rc
+
+ourx=0
+upload=true
+: ${upload_if_notests:=false}
+extras=''
 
 case "$rc" in
-0)     summary='all OK';                       email=''                ;;
-2)     summary='OK (some skipped)';            email=''                ;;
-8)     summary='package declares no tests';    email=''                ;;
+0)     summary='all OK';                       email=''
+                                       upload=$upload_if_ok            ;;
+2)     summary='OK (some skipped)';            email=''
+                                       upload=$upload_if_ok            ;;
+8)     summary='package declares no tests';    email=''
+                               upload=$upload_if_notests; extras='nt'  ;;
 4|6)   summary='test(s) failed!';      email="$maintainer_email"       ;;
 12)    summary='erroneous package!';   email="$maintainer_email"       ;;
 16)    summary='testbed failed!';      email="administrator_email"     ;;
-*)     summary='unexpected failure!';  email="administrator_email"     ;;
+*)     summary='unexpected failure!';  email="administrator_email"; ourx=20;;
 esac
 
 progress "RESULTS $summary"
-progress "contacting $email"
 
-for odir in tmp out; do
-       if test -d "$tp"/$odir; then
-               GZIP=-2 tar -f "$tp"/$odir.tar.gz -C "$tp" -zc $odir
-               rm -r "$tp"/$odir
+if  [ "x$suppresspackages" != x ] \
+ && grep -x "$src" "$suppresspackages" >/dev/null; then
+       printf >&3 "email-suppressed "
+       email=''
+fi
+
+if $upload; then
+       progress "bundling"
+       printf "\n%s\n" "$summary" >>"$tmp"/_summary
+
+       edest=${email%_email}
+       esummary="$var"/emailed/last-$pkg,$edest
+       if [ "x$edest" = x ]; then
+               printf >&3 "email-none "
+               rm -f "$var"/emailed/last-$pkg,*
+               esummary=''
+       elif $suppressrepeatedemails \
+         && [ -f "$esummary" ] \
+         && diff -u "$esummary" "$tmp"/_summary >"$var"/emailed/diff-$pkg; then
+               printf >&3 "email-same $email "
+               email=''
+               esummary=''
+       else
+               cp "$tmp"/_summary "$esummary".new
        fi
-done
 
-$rsync -rltH --safe-links --delete "$tp" "$destrsynchead/$destdirtail/"
+       ln -f "$tmp"/_summary "$tp"/summary
+
+       for odir in tmp out; do
+               if test -d "$tp"/$odir; then
+                       GZIP=-2 tar -f "$tp"/$odir.tar.gz -C "$tp" -zc $odir
+                       rm -r "$tp"/$odir
+               fi
+       done
+
+       progress "uploading"
+       printf >&3 "uploading"
+       $rsync -rltH --safe-links --delete "$tp" "$destrsynchead/$destdirfin/"
+       printf >&3 " "
+fi
 
 if [ "x$email" != x ]; then
+       progress "contacting $email"
        eval "email_addr=\$$email"
-       cat >"$tmp"/email <<END
+       printf >&3 "email \"%s\" " "$email_addr"
+       cat >"$tmp"/_email_header <<END
 From: $from
 To: $email_addr
-Subject: autopkgtest $distro $pkg: $summary
+Subject: autopkgtest $distro $desc: $summary
+
+END
+
+       email_package_header="${email_package_header//@p/$pkg}"
+       email_package_header="${email_package_header//@s/$src}"
+       email_package_header="${email_package_header//@v/$pVersion}"
+       email_package_header="${email_package_header//@a/@}"
+       printf >"$tmp"/_email "%s" "$email_package_header"
 
- Test executed for:  $distro  $pkg
+       cat >>"$tmp"/_email <<END
+ Test executed for:  $distro  $target  $pkg
  Outcome: $summary
+END
+       sed -e 's/^/  /' "$tmp"/_summary >>"$tmp"/_email
+       cat >>"$tmp"/_email <<END
 
 This message is automatically generated by the autopkgtest package
 testing system.  You are receiving it because:
 END
        case "$email" in
                pMaintainer)
-                       cat >>"$tmp"/email <<END
+                       cat >>"$tmp"/_email <<END
  You are listed in the Maintainer field of the $pkg package in $distro
 and the test results appear to indicate a problem with the package.
+ and the test results appear to indicate a problem with the package.
 END
                        ;;
                maintainer_email_override)
-                       cat >>"$tmp"/email <<END
+                       cat >>"$tmp"/_email <<END
  The test results appear to indicate a problem with the package
 and reports for package maintainers for $distro are being directed to
 $maintainer_email_override
+ and reports for package maintainers for $distro are being directed to
+ $maintainer_email_override
 END
                        ;;
                administrator_email)
-                       cat >>"$tmp"/email <<END
+                       cat >>"$tmp"/_email <<END
  You are the administrator for the autopkgtest installation.
 END
                        ;;
@@ -173,14 +428,14 @@ END
                        exit 1
                        ;;
        esac
-       cat >>"$tmp/email" <<END
-
-The test log, which is intended to be sufficient to diagnose most
-failures, can be found below.  However, in case this is not
-sufficient, another copy can be found along with output files, saved
-temporary files, and so on, at:
- $desthttphead/$destdirtail/
-
+       cat >>"$tmp/_email" <<END
+
+The top and tail of the test log, which is intended to be sufficient
+to diagnose most failures, can be found below.  However, in case this
+is not sufficient, a complete log can be found along with output
+files, saved temporary files, and so on, at:
+ $desthttphead/$destdirfin/
+$email_extra_info
 If you have any questions about this service please contact me at:
  $from
 
@@ -189,13 +444,77 @@ $salutation
 
 -8<-
 END
-       cat >>"$tmp"/email 2>&1 "$tmp"/log ||:
-       sendmail -odq -oem -t -oi <"$tmp"/email
 fi
 
-printf >>"$var"/log "package=%s rc=%s emailed='%s'\n" \
-       "$pkg" $rc "$email_addr"
-echo $pkg >"$var"/last.new
-mv "$var"/last.new "$var"/last
+printf >>"$var"/log "%s=%s rc=%s emailed='%s'\n" \
+       "$target" "$pkg" $rc "$email_addr"
+
+if [ "x$ourx" = x0 ]; then
+       sed -e "/^$pkg /d" <"$lastinfo" >"$lastinfo".new
+       printf "%s %s %s %s\n" "$pkg" "$pVersion" "$now" "$extras" \
+               >>"$lastinfo".new
+       mv "$lastinfo".new "$lastinfo"
+       progress "tested."
+else
+       progress "fault ($ourx)."
+fi
+
+perl <"$tmp"/_log_raw >"$tmp"/_log -ne '
+       s/[^\012\040-\133\135-\176]/
+               $& eq "\t" ? "\\t" :
+               $& eq "\r" ? "\\r" :
+               $& eq "\b" ? "\\b" :
+               $& eq "\\" ? "\\\\" :
+               sprintf "\\x%02x", ord $&
+       /ge;
+
+       if (!$middle) {
+               $headlen += length;
+               $middle=1 if $headlen > '"$logheadmaxbytes"';
+       }
+       if (!$middle) {
+               print or die $!;
+       } else {
+               $taillen += length;
+               push @tail, $_;
+               while ($taillen > '"$logtailmaxbytes"') {
+                       $taillen -= length shift @tail;
+                       $some_dropped= 1;
+               }
+       }
+       END {
+               print "...\n" or die $! if $some_dropped;
+               print @tail or die $!;
+       }
+'
+
+if [ "x$email" = x ]; then
+       if $interactive; then
+               cat "$tmp"/_log >&2
+       fi
+else
+       cat >>"$tmp"/_email 2>&1 "$tmp"/_log ||:
+
+       if [ "x$email_signing_key" != x ]; then
+               printf >&3 "signing "
+               echo >>"$tmp/_email"
+               gpg -u"$email_signing_key" --clearsign \
+                       <"$tmp/_email" >"$tmp/_email.asc"
+               mv -f "$tmp/_email.asc" "$tmp/_email"
+       fi
+       cat "$tmp/_email_header" "$tmp/_email" >"$tmp/_email.new"
+       mv -f "$tmp/_email.new" "$tmp/_email"
+
+       if $interactive; then
+               cat "$tmp"/_email >&2
+       else
+               sendmail -odi -oem -t -oi <"$tmp"/_email
+               if [ "x$esummary" != x ]; then
+                       printf >&3 "email-recorded "
+                       mv "$esummary".new "esummary"
+               fi
+       fi
+fi
 
-progress "done."
+printf >&3 "done %s.\n" $ourx
+exit $ourx