blob: 338636405e7152eefc2323c2f8e10c739a06cbef [file] [log] [blame]
#!/usr/local/bin/bash
#
# $Id: xbuildgen 601917 2007-12-06 23:46:48Z sebor $
#
########################################################################
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed
# with this work for additional information regarding copyright
# ownership. The ASF licenses this file to you under the Apache
# License, Version 2.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
#
# Copyright 2007 Rogue Wave Software, Inc.
#
########################################################################
#
# NAME
# xbuildgen - Generate build results across multiple platforms.
#
# SYNOPSIS
# xbuildgen [option(s)...] [log-file(s)...]
#
# DESCRIPTION
# The xbuildgen utility generates a build result in HTML format
# across multiple platforms or tests with builds in columns and
# components such as examples, locales, and tests in rows by
# default.
#
# OPTIONS
# -n No clean. Avoid removing temporary files.
#
# -s Stylesheet. Create a style sheet named resultstyle.css in
# the same directory as the output file when the -o option
# is specified, or in the current working directory otherwise.
#
# -v Verbose. Produce verbose output on stdout.
#
# -e <list-of-examples>
# Generate a report for the specified list of example programs
# with examples listed in columns and builds in rows.
#
# -h Print help.
#
# -l <list-of-locales>
# Generate a report for the specified list of locales with
# locales listed in columns and builds in rows.
#
# -o <output-file>
# Specify the pathname of the output file. The utility will
# use stdout when no output file is specified.
#
# -T <text>
# Specify the title for the page.
#
# -t <list-of-tests>
# Generate a report for the specified list of tests with
# tests listed in columns and builds in rows.
#
########################################################################
######################################################################
# global constants
# set program name (used in diagnostic messages)
readonly myname=`basename $0`
readonly today=`LC_ALL="C" date`
# URL to the ViewVC directory
readonly viewvc="http://svn.apache.org/viewvc"
# URL to the revision number (use: "$revurl=$revno")
readonly revurl="$viewvc?view=rev&rev"
# URL to the trunk of the source repository
readonly svnpath="$viewvc/incubator/stdcxx/trunk"
# expected failures
readonly xfailfile=$HOME/stdcxx/etc/config/xfail.txt
######################################################################
# global variables
# by default, display one component (example, locale, or test) per row
components_in_rows=1
# no verbosity by default
verbose=0
# default page title (unless overridden on the command line)
title="Multi-platform Test Result View"
# script's revision number
myrev='$Revision$'
myrev=${myrev#'$Revision: '}
myrev=${myrev%' $'}
# URL to this version of the script in the repository
readonly myurl="$svnpath/bin/xbuildgen?view=markup&rev=$myrev"
######################################################################
print_help ()
{
echo "NAME"
echo " $myname - generate a cross-build result page"
echo
echo "SYNOPSIS"
echo " $myname [option(s)...] [log-file(s)...]"
echo
echo "DESCRIPTION"
echo " The $myname utility generates a build result in HTML format"
echo " across multiple platforms or tests with builds in columns and"
echo " components such as examples, locales, and tests in rows by"
echo " default."
echo
echo "OPTIONS"
echo " -n No clean. Avoid removing temporary files."
echo
echo " -s Stylesheet. Create a style sheet named resultstyle.css in"
echo " the same directory as the output file when the -o option"
echo " is specified, or in the current working directory otherwise."
echo
echo " -v Verbose. Produce verbose output on stdout."
echo
echo " -e <list-of-examples>"
echo " Generate a report for the specified list of example programs"
echo " with examples listed in columns and builds in rows."
echo
echo " -h Print help."
echo
echo " -l <list-of-locales>"
echo " Generate a report for the specified list of locales with"
echo " locales listed in columns and builds in rows."
echo
echo " -o <output-file>"
echo " Specify the pathname of the output file. The utility will"
echo " use stdout when no output file is specified."
echo
echo " -T <text>"
echo " Specify the title for the page."
echo
echo " -t <list-of-tests>"
echo " Generate a report for the specified list of tests with"
echo " tests listed in columns and builds in rows."
}
######################################################################
# extracts the real, user and system times for a specified stage
# of the build process from the file given by the second argument
# and writes them out to stdout
get_times ()
{
stage=$1
file=$2
pattern="^### real, user, system time ($stage):"
# extract the real, user and system times for the children
# of the shell that executed the commands from the log
# the format of the output is:
# <real-time>
# <times-output>
# with <real-time> looking like:
# [1-9][0-9]*m[1-9][0-9]s
# and with <times-output> being the output of the POSIX standard
# times built-in utility, i.e., the first line giving the system
# and user times for the shell and the second line giving the
# system and user times for its children in the format:
# "%dm%fs %dm%fs"
# we don't care about the shell times, just the times for its
# children, so we skip that line
stage_times=` sed -n "/$pattern/{n;p;n;n;p;}" $file`
# strip newlines and fractional parts of seconds and replace
# 'm' with ':'
stage_times=` echo $stage_times \
| sed -e "s/\.[0-9][0-9]*s//g" \
-e "s/s//" \
-e "s/m/:/g"`
# extract the real time (first)
real_time=${stage_times%% *}
# append a leading '0' to single-digit seconds
sec=${real_time##*:}
if [ ${#sec} -eq 1 ]; then
real_time=${real_time%:*}":0$sec"
fi
# extract the user time (middle)
user_time=${stage_times#* }
user_time=${user_time%% *}
# append a leading '0' to single-digit seconds
sec=${user_time##*:}
if [ ${#sec} -eq 1 ]; then
user_time=${user_time%:*}":0$sec"
fi
# extract the system time (last)
sys_time=${stage_times##* }
# append a leading '0' to single-digit seconds
sec=${sys_time##*:}
if [ ${#sec} -eq 1 ]; then
sys_time=${sys_time%:*}":0$sec"
fi
# output the three times
cat <<EOF
<td>$real_time</td>
<td>$user_time</td>
<td>$sys_time</td>
EOF
}
######################################################################
# extracts the date and time the build started from the file
# given by the second argument
get_build_date ()
{
file=$1
# extract the date and time the build started
# the date is expected to be introduced by a line like this:
# ### date:
date=`sed -n "/^##* *date *: *$/{n;p;q;}" $file`
if [ "$date" = "" ]; then
echo "$myname: warning: unable to extract date from $l" >&2
unset date
fi
# strip the year from the date
echo ${date% [1-9][0-9][0-9][0-9]}
}
######################################################################
# formats a size value in an easy-to-read way
format_size ()
{
size=$1
if [ "$size" = "" ]; then
:
elif [ $size -ge 1000000000 ]; then
# over billion bytes, get size in gigabytes up to 2 decimal places
gbsize="$((size / 1073741824)).$(((size % 1073741) / 100000))"
size="<div title=\"$size bytes\">$gbsize GB</div>"
elif [ $size -ge 1000000 ]; then
# over million bytes, get size in megabytes up to 2 decimal places
mbsize="$((size / 1048576)).$(((size % 1048576) / 100000))"
size="<div title=\"$size bytes\">$mbsize MB</div>"
elif [ $size -ge 10000 ]; then
# over ten thoudand bytes, get even size in kilobytes
kbsize="$((size / 1024))"
size="<div title=\"$size bytes\">$kbsize kB</div>"
elif [ $size -ge 1000 ]; then
# over thoudand bytes, get size in kilobytes up to 2 decimal places
kbsize="$((size / 1024)).$(((size % 1024) / 100))"
size="<div title=\"$size bytes\">$kbsize kB</div>"
fi
echo $size
}
######################################################################
# extracts the size of the library binary from the build log
# being careful to avoid the symlink (in the case of a .so)
get_lib_size ()
{
file=$1
libsize=`awk '/build\/lib\/libstd[^ ]*\$/{ print $5 }' $file`
if [ "$libsize" = "" ]; then
# avoid warning for missing library size to reduce the noise
# in cases when it fails to build
# echo "$myname: warning: unable to extract library size from $l" >&2
unset libsize
fi
echo $libsize
}
######################################################################
# extracts the build type from the string specified by the argument
# (the name of the log)
get_buildtype ()
{
str=$1
# extract the build type from the name of the log, removing
# the name of thread library
buildtype=` echo $str \
| sed "s/\(.*-[18][125]*[aAdDsS]\)-dce-\(.*\)/\1-\2/" \
| sed "s/\(.*-[18][125]*[aAdDsS]\)-solaris-\(.*\)/\1-\2/" \
| sed "s/\(.*-[18][125]*[aAdDsS]\)-win32-\(.*\)/\1-\2/" \
| sed "s/.*-\([18][125]*[aAdDsS]\)-[1-9][0-9]*-log.*/\1/"`
if [ "$buildtype" = "" ]; then
echo "$myname: warning: unable to extract build type from $str" >&2
unset buildtype
fi
echo $buildtype
}
######################################################################
# extracts the operating system name and version from the log file
get_os ()
{
file=$1
uname=`sed -n "/^##* uname *-a.*:$/{n;p;q;}" $file`
case "$uname" in
"AIX "*)
osname="AIX"
# extract the version number from AIX uname -a output:
# "AIX <hostname> <minor> <major> ...
osver=${uname#* } # remove AIX
osver=${osver#* } # remove hostname
minor=${osver%% *} # extract minor version
osver=${osver% *} # remove gibberish at the end
osver=${osver#* }"."$minor
;;
CYGWIN*)
osname="Cygwin"
osver=${uname#* } # remove CYGWIN
osver=${osver#* } # remove hostname
osver=${osver%%(*} # extract version
;;
*"FreeBSD "*)
osname="FreeBSD"
;;
"HP-UX "*)
# for example
# HP-UX hostname B.11.23 U ia64 0025699549 unlimited-user license
osname="HP-UX"
osver=${uname#* } # remove HP-UX
osver=${osver#* } # remove hostname
osver=${osver%% *} # extract full version
osver=${osver#[A-Z].} # remove letter prefix
;;
"IRIX64 "*)
;;
"Linux "*)
# extract the Linux distron name from the contents
# of the /etc/*-release files
osname=` sed -n "/^##* * cat *\/etc\/.*-release /{n;p;n;p;}" \
$file \
| sed -e "/^ *LSB_VERSION *=/d" -e "/^ *VERSION *= */d"`
rhel="Red Hat Enterprise Linux"
# SuSE Linux 10
suse_Linux="SUSE Linux Enterprise Server"
# SuSE Linux 9 (sigh...)
suse_LINUX="SUSE LINUX Enterprise Server"
pfx="<div title=\"$osname\">"
sfx="</div>"
case "$osname" in
"$rhel "*)
# remove the Red Hat code name including the release
# and keep the distribution code name and update info:
# RHEL 5: Tikanga (Update 1 through 2)
# RHEL 4: Nahant (Update 1 through 6)
# RHEL 3: Taroon (Update 1 through 9)
# RHEL 2.1 AS: Pensacola
# RHEL 2.1 ES: Panama
oscode=${osname##* (}
# append space (important below)
oscode="${oscode%)} "
update=${oscode#* } # strip code name
update=${update#* } # strip the word "Update"
osver=${osname#$rhel } # strip the distro name
ostype=${osver%% *} # extract OS type (AS or Server)
osver=${osver#* release } # strip OS type
osver=${osver%% (*}
# osver="[osver=$osver][oscode=$oscode][update=$update]"
osname="RHEL"
if [ "$update" != "" ]; then
osver="$osver.$update"
fi
;;
"$suse_Linux "*)
osver=${osname#$suse_Linux }
osver=${osver%% *}
osname="SLES"
;;
"$suse_LINUX "*)
osver=${osname#$suse_LINUX }
osver=${osver%% *}
osname="SLES"
;;
*)
;;
esac
;;
"SunOS "*)
osname="SunOS"
osver=${uname#* } # remove SunOS
osver=${osver#* } # remove hostname
osver=${osver%% *} # strip averything past version
;;
*)
osname=$uname
;;
esac
echo "$pfx$osname $osver$sfx"
}
######################################################################
# extracts the hardware architecture from the log file
get_arch ()
{
file=$1
uname=`sed -n "/^##* uname *-a.*:$/{n;p;}" $file`
if [ "$uname" = "" -o "${uname%%_*}" = "CYGWIN" ]; then
# Windows or CygWin
id=`sed -n "s/^ *PROCESSOR_IDENTIFIER *= *\(.*\)/\1/p" $file`
arch=${id%% *}
arch="<div title=\"$id\">$arch</div>"
else
case "$uname" in
# recent HP-UX machines always return 9000/800
"HP-UX "*" 9000/8"??" "*) arch="PA-RISC";;
*" i686 "*) arch="i686";;
*" i586 "*) arch="i586";;
*" i486 "*) arch="i486";;
*" i386 "*) arch="i386";;
*" i286 "*) arch="i286";;
*" ia64 "*) arch="IA64";;
*" sparc "*) arch="SPARC";;
*" x86_64 "*)
arch="x86_64"
model=` sed -n "s/^model name.*: *\(.*\)/\1/p" $file \
| sed 's/ */ /g' | head -n 1`
if [ ${model%% *} = "Intel(R)" ]; then
arch="<div title=\"$model\">EM64T</div>"
else
arch="<div title=\"$model\">AMD64</div>"
fi
;;
esac
fi
echo $arch
}
######################################################################
# extracts the compiler and version from the log file
get_compiler ()
{
file=$1
compiler=` sed -n "/^configuring stdcxx /{p;q;}" $file \
| sed "s/.* for \([^ ][^ ]*\) .*/\1/"`
if [ "${compiler%%[-_]*}" = "xlCcore" ]; then
# replace xlCcore with XLC++ for IBM XLC/C++
compiler="XLC++ "${compiler#*-}
elif [ "${compiler%%-*}" = "aCC" ]; then
# remove the "A.0" version prefix from HP aCC version
compiler="aCC ${compiler#aCC-[A-Z].0}"
elif [ "$compiler" = "" ]; then
# this must be a Windoze compiler...
compiler=` sed -n "/^ *CXX *=.*/{p;q;}" $file \
| sed "s/^.*= *\(.*\)/\1/"`
if [ "$compiler" = "cl" ]; then
vs="Microsoft Visual Studio"
compiler=` sed -n "/^ *Variables *: *$/{n;p;}" $file\
| sed "s/ *VERSION= *\(.*\)/\1/"`
compiler="MSVC $compiler"
elif [ "$compiler" = "icl" ]; then
true
fi
fi
echo $compiler | sed "s/-/ /g"
}
######################################################################
# process command line options
while getopts ":hnsv:e:l:o:T:t:" opt_name; do
case $opt_name in
# options with no arguments
h) # print help and exit
print_help
exit
;;
n) # avoid cleaning up temporary files
no_clean=1
;;
s) # create a style sheet
create_stylesheet=1
;;
v) # output all components (including passing ones)
verbose=1
;;
# options with arguments
e) # argument is a list of examples to process
example_list=$OPTARG
components_in_rows=0
;;
l) # argument is a list of locales to process
locale_list=$OPTARG
components_in_rows=0
;;
o) # argument is the name of output file (stdout by default)
outfile=$OPTARG
;;
T) # argument is the title of the page
title=$OPTARG
;;
t) # argument is a list of tests to process
test_list=$OPTARG
components_in_rows=0
;;
*) echo "$myname: unknown option : -$opt_name" >&2;
echo
print_help
exit 1;;
esac;
done
# remove command line options and their arguments from the command line
shift $(($OPTIND - 1))
# take the remaining command line arguments as the names of logs
# to process
gzlogs=$*
# set the TMP variable to /tmp if not set
[ -z $TMP ] && TMP=/tmp
######################################################################
# output to output file when specified or to stdout
output ()
{
if [ $# -eq 0 ]; then
# no arguments provided, copy its own stdin to outfile
if [ -z $outfile ]; then
cat
else
cat >>$outfile
fi
elif [ -z $outfile ]; then
echo "$*"
else
echo "$*" >>$outfile
fi
}
######################################################################
# remove output file if specified
if [ ! -z $outfile ]; then
rm -f $outfile
fi
# overwrite style sheet
if [ "$create_stylesheet" = "1" ]; then
if [ -z $outfile ]; then
dir=.
else
dir=`dirname $outfile`
fi
cat <<EOF >$dir/resultstyle.css
table {
background:lightslategray;
font-family:courier;
font-size: 80%;
}
caption {
background:lightslategray;
color:lightgray;
font-weight:bold;
font-family:lucida mono;
font-size: 120%;
}
th {
background:lightgray;
text-align:center;
font-family:lucida mono;
}
td {
padding: 2px;
text-align: center;
}
tr {
background:powderblue;
}
td.rowno {
text-align: right;
background:lightgray;
}
td.name {
text-align: left;
background:lightblue;
}
td.number {
text-align: center;
background:lightblue;
}
td.na {
background:white;
text-align:left;
}
.header {
background:#cccccc;
text-align:center;
font-weight:bold;
font-family:lucida mono;
}
td.total {
text-align:center;
font-weight:bold;
}
td.OK {
background:forestgreen;
text-align:center;
font-weight:bold;
}
td.XPASS {
color:yellow;
background:forestgreen;
text-align:center;
font-weight:bold;
}
td.BASE {
background:lightgreen;
text-align:center;
font-weight:bold;
}
td.NOUT {
background:lightgreen;
text-align:center;
font-weight:bold;
}
td.OUTPUT {
background:lightgreen;
text-align:center;
font-weight:bold;
}
td.MISS {
color:white;
background:lightgray;
text-align:center;
font-weight:bold;
}
td.WARN {
color:red;
background:#ffff99;
text-align:center;
font-weight:bold;
}
td.XWARN {
color:tomato;
background:lightgreen;
text-align:center;
font-weight:bold;
}
td.EXIT {
color:red;
background:gold;
text-align:center;
font-weight:bold;
}
td.XEXIT {
color:tomato;
background:lightgreen;
text-align:center;
font-weight:bold;
}
td.FORMAT {
background:#ffffcc;
text-align:center;
}
td.RUNWARN {
color:black;
background:#ffff99;
text-align:center;
font-weight:bold;
}
td.XRUNWARN {
color:dimgray;
background:lightgreen;
text-align:center;
font-weight:bold;
}
td.DIFF {
color:red;
background:#ffff99;
font-weight:bold;
text-align:center;
}
td.XDIFF {
color:tomato;
background:lightgreen;
font-weight:bold;
text-align:center;
}
td.ASSERT {
color:red;
background:#ffff99;
font-weight:bold;
text-align:center;
}
td.XASSERT {
color:tomato;
background:lightgreen;
font-weight:bold;
text-align:center;
}
td.SIGNAL {
color:yellow;
background:red;
font-weight:bold;
text-align:center;
}
td.XSIGNAL {
color:tomato;
background:lightgreen;
font-weight:bold;
text-align:center;
}
td.COMP {
background:violet;
font-weight:bold;
text-align:center;
}
td.XCOMP {
color:violet;
background:lightgreen;
font-weight:bold;
text-align:center;
}
td.LINK {
color:yellow;
background:mediumpurple;
font-weight:bold;
text-align:center;
}
td.XLINK {
color:mediumpurple;
background:lightgreen;
font-weight:bold;
text-align:center;
}
td.xdep {
color:yellow;
background:gray;
font-weight:bold;
text-align:center;
}
tr.LIB {
background:pink;
color:black;
}
EOF
fi
######################################################################
readonly scripturl="<a href=\"$myurl\"><code>$myname</code></a>"
# output the initial portion of the HTML file
cat <<EOF | output
<html>
<head>
<title>$title</title>
<link rel="stylesheet" href="resultstyle.css" type="text/css"
title="Cross-Build View Style Sheet">
</head>
<body>
<h1>$title</h1>
Generated $today by $scripturl on `hostname` running `uname -sr`
<hr>
<h2>Index</h2>
<ul>
<li><a href="#logs">Logs and Columns</a></li>
<li><a href="#timings">Timings</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#tests">Tests</a></li>
<li><a href="#locales">Locales</a></li>
<li><a href="#codes">Codes and Colors</a></li>
<li><a href="#buildtypes">Build Types</a></li>
</ul>
<hr>
EOF
######################################################################
# the location of the logs
logdir="http://people.apache.org/~sebor/stdcxx/results"
# the name of a temporary file containing the build timings
timings_file=$TMP/.stdcxx-timings.$$
# remove the temporary file
rm -f timings_file
if [ $? -ne 0 ]; then
exit 2
fi
cat <<EOF | output
<h2>Logs and Columns</h2>
EOF
if [ $components_in_rows -ne 0 ]; then
cat <<EOF >$timings_file
<h2>Timings</h2>
<table>
<thead>
<tr>
<th rowspan=3 title="column number and log">log</th>
<th rowspan=3>build<br>type</th>
<th colspan=21>build and run times (M:SS)</th>
</tr>
<tr>
<th colspan=3 title="library configuration times">config</th>
<th colspan=3 title="library build times">library</th>
<th colspan=3 title="build times for all examples">examples</th>
<th colspan=3 title="build times for all utilities">utilities</th>
<th colspan=3 title="build times for all tests">tests</th>
<th colspan=3 title="run times for all components">run times</th>
<th colspan=3 title="total build and run times">total</th>
</tr>
<tr>
<th>real</th>
<th>user</th>
<th>sys</th>
<th>real</th>
<th>user</th>
<th>sys</th>
<th>real</th>
<th>user</th>
<th>sys</th>
<th>real</th>
<th>user</th>
<th>sys</th>
<th>real</th>
<th>user</th>
<th>sys</th>
<th>real</th>
<th>user</th>
<th>sys</th>
<th>real</th>
<th>user</th>
<th>sys</th>
</tr>
</thead>
<tbody>
EOF
cat <<EOF | output
<table>
<thead>
<tr>
<th rowspan=3 title="column number and log">log</th>
<th rowspan=3>operating<br>system</th>
<th rowspan=3 title="hardware architecture">arch</th>
<th rowspan=3>compiler</th>
<th rowspan=3>build<br>type</th>
<th rowspan=3>start date and time</th>
<th rowspan=3 title="build age at the time of this report">age</th>
<th rowspan=3>revision</th>
<th colspan=5>sizes</th>
<th colspan=2>diagnostics</th>
<!-- <th colspan=6>components</th> -->
</tr>
<tr>
<th rowspan=2 title="size of the library binary">library</th>
<th colspan=2>log</th>
<th colspan=2>build</th>
<th rowspan=2 title="number of error messages found">errors</th>
<th rowspan=2 title="number of warning messages found">warnings</th>
<!-- <th colspan=2>examples</th> -->
<!-- <th colspan=2>locales</th> -->
<!-- <th colspan=2>tests</th> -->
</tr>
<tr>
<th title="size of gzipped log">gzip</th>
<th title="size of expanded log">text</th>
<th title="size of full build">full</th>
<th title="size of clean build">clean</th>
<!-- <th title="number of examples exercised">total</th> -->
<!-- <th title="number of examples failed">failed</th> -->
<!-- <th title="number of locales exercised">total</th> -->
<!-- <th title="number of locales failed">failed</th> -->
<!-- <th title="number of tests exercised">total</th> -->
<!-- <th title="number of tests failed">failed</th> -->
</tr>
</thead>
<tbody>
EOF
fi
######################################################################
# expand gzipped logs and extract the relevant portion from each into
# a smaller text file for fast and easy processing; the names of all
# the text files are stored in the textlogs variable
# number of logs processed in loop below
logcount=0
# space-separated list of names of text logs processed in loop below
textlogs=""
# the minimum, maximum, and the sum of library sizes
libsize_min=9999999999
libsize_max=0
libsize_sum=0
# the minimum, maximum, and the sum of compressed log sizes
gzlogsize_min=9999999999
gzlogsize_max=0
gzlogsize_sum=0
# the minimum, maximum, and the sum of uncompressed log sizes
txtlogsize_min=9999999999
txtlogsize_max=0
txtlogsize_sum=0
# the number of logs counted equals logcount (see above)
# the minimum, maximum, and the sum of full build sizes
fullbuildsize_min=9999999999
fullbuildsize_max=0
fullbuildsize_sum=0
# the minimum, maximum, and the sum of clean build sizes
cleanbuildsize_min=9999999999
cleanbuildsize_max=0
cleanbuildsize_sum=0
# the number of build sizes counted
buildsize_count=0
# the number of successfully built (non-zero size) libraries
libcount=0
for l in $gzlogs; do
logcount=$((logcount + 1))
fname=`basename $l`
if [ $verbose -eq 1 ]; then
echo "$myname: processing $l"
fi
# set temporary variables (valid only within the loop)
txtlog=$TMP/`basename $l .gz.txt`.txt.$$
# append the name of the log to the list
textlogs="$textlogs $txtlog"
# unzip the log into a temporary text file
gunzip -c $l > $txtlog
if [ $? -ne 0 ]; then
echo "$myname: error unzipping $l" >&2
# continue processing the empty log below
fi
# determine the size of the compressed and decompressed log
gzlogsize=`wc -c $l`
gzlogsize=${gzlogsize% *}
if [ $gzlogsize -lt $gzlogsize_min ]; then
gzlogsize_min=$gzlogsize
fi
if [ $gzlogsize -gt $gzlogsize_max ]; then
gzlogsize_max=$gzlogsize
fi
gzlogsize_sum=$((gzlogsize_sum + gzlogsize))
gzlogsize=`format_size $gzlogsize`
txtlogsize=`wc -c $txtlog`
txtlogsize=${txtlogsize% *}
if [ $txtlogsize -lt $txtlogsize_min ]; then
txtlogsize_min=$txtlogsize
fi
if [ $txtlogsize -gt $txtlogsize_max ]; then
txtlogsize_max=$txtlogsize
fi
txtlogsize_sum=$((txtlogsize_sum + txtlogsize))
txtlogsize=`format_size $txtlogsize`
# extract the date and time the build started
# the date is expected to be introduced by a line like this:
# ### date:
date=`sed -n "/^### date:$/{n;p;q;}" $txtlog`
if [ "$date" = "" ]; then
echo "$myname: warning: unable to extract date from $l" >&2
unset date
unset age
else
# compute the age of the build as the difference between
# the build date and now in days, or hours, or minutes,
# or just seconds, whichever happens to be the most
# significant
age=`$HOME/stdcxx/bin/duration "$date" "$today"`
full_age=`$HOME/stdcxx/bin/duration -f "$date" "$today"`
age="<div title=\"$full_age\">$age</div>"
fi
# strip the year from the date
date=`echo ${date% [1-9][0-9][0-9][0-9]}`
# extract the size of the library binary from the build log
libsize=`get_lib_size $txtlog`
if [ "$libsize" != "" ]; then
if [ $libsize -lt $libsize_min ]; then
libsize_min=$libsize
fi
if [ $libsize -gt $libsize_max ]; then
libsize_max=$libsize
fi
libsize_sum=$((libsize_sum + libsize))
libsize=`format_size $libsize`
libcount=$((libcount + 1))
fi
# extract the size of the whole build introduced by a line
# containing the strings "# du -sk build", both before and
# afterit's been cleaned
buildsizes=` sed -n '/^##* *du *-sk *.*build/{n;p;}' \
$txtlog | sed 's/ *\([1-9][0-9]*\).*/\1/'`
if [ "$buildsizes" = "" ]; then
# avoid warning for missing build size to reduce the noise
# in cases when the library fails to build
# echo "$myname: warning: unable to extract build size from $l" >&2
unset fullbuildsize
unset cleanbuildsize
else
fullbuildsize=${buildsizes%%[^0-9]*}
cleanbuildsize=${buildsizes#[0-9]*[^0-9]}
fullbuildsize=$((fullbuildsize * 1024))
cleanbuildsize=$((cleanbuildsize * 1024))
if [ "$fullbuildsize" != "" ]; then
# compute the minimum, maximum, sum, and average
if [ $fullbuildsize -lt $fullbuildsize_min ]; then
fullbuildsize_min=$fullbuildsize
fi
if [ $cleanbuildsize -lt $cleanbuildsize_min ]; then
cleanbuildsize_min=$cleanbuildsize
fi
if [ $fullbuildsize -gt $fullbuildsize_max ]; then
fullbuildsize_max=$fullbuildsize
fi
if [ $cleanbuildsize -gt $cleanbuildsize_max ]; then
cleanbuildsize_max=$cleanbuildsize
fi
fullbuildsize_sum=$((fullbuildsize_sum + fullbuildsize))
cleanbuildsize_sum=$((cleanbuildsize_sum + cleanbuildsize))
buildsize_count=$((buildsize_count + 1))
fi
fullbuildsize=`format_size $fullbuildsize`
cleanbuildsize=`format_size $cleanbuildsize`
fi
# extract the source repository revision number the build
# corresponds to from the name of the log
revno=`echo $l | sed "s/.*-\([1-9][0-9]*\)-log.*/\1/"`
if [ "$revno" = "" ]; then
echo "$myname: warning: unable to extract revision number from $l" >&2
unset revno
fi
# extract the build type from the name of the log
buildtype=`get_buildtype $l`
# extract the operating system name and version from the log
osname=`get_os $txtlog`
# extract hardware architecture info from the log
arch=`get_arch $txtlog`
# extract compiler name and version from the log
compiler=`get_compiler $txtlog`
# count the number of errors and warnings in the build
# avoid including false positives for words containing
# the string "error" or "warning"
# avoid counting (often ignored) make errors
errors=` grep -i "[^a-z_A-Z0-9]error[^a-z_A-Z0-9]" $txtlog \
| grep -v "[^a-z_A-Z0-9]*gmake[^a-z_A-Z0-9]"| wc -l`
# (try to) avoid counting lines showing the context of the warning
# this should be tailored to every compiler
warnings=` grep -i "[^a-z_A-Z0-9]warning[^a-z_A-Z0-9]" $txtlog \
| grep -i -v "called from here" | wc -l`
###
if [ $components_in_rows -ne 0 ]; then
# retrieve the revision log
# revlog="`svn log -r $revno \
# http://svn.apache.org/repos/asf/incubator/stdcxx`"
# trim the suffix from fname, including the revision number
# and the build type
fbase=${fname%%-log.gz.txt}
fbase=${fbase%-$revno}
fbase=${fbase%-$buildtype}
# componse the column header
colhdr="<a href=\"$logdir/$fname\" title=\"$fbase\">$logcount"
colhdr="$colhdr</a>"
# when displaying one component (example, test, or locale) per row
# of the table, format the table header so as to include the build
# date, source repository revision number, and build type, and
# include the same information in the list of logs
tbl_hdr_1="$tbl_hdr_1 <th>$colhdr</th>"
tbl_hdr_2="$tbl_hdr_2 <th>$buildtype</th>"
if [ "$libsize" = "" ]; then
table_row=" <tr class=\"LIB\">"
else
table_row=" <tr>"
fi
output "$table_row"
output " <td>$colhdr</td>"
output " <td>$osname</td>"
output " <td>$arch</td>"
output " <td>$compiler</td>"
output " <td>$buildtype</td>"
output " <td>$date</td>"
output " <td>$age</td>"
output " <td><a href=$revurl=$revno>$revno</a></td>"
output " <td>$libsize</td>"
output " <td>$gzlogsize</td>"
output " <td>$txtlogsize</td>"
output " <td>$fullbuildsize</td>"
output " <td>$cleanbuildsize</td>"
output " <td>$errors</td>"
output " <td>$warnings</td>"
output " </tr>"
cat <<EOF >>$timings_file
$table_row
<td>$colhdr</td>
<td>$buildtype</td>
EOF
# extract timings for each stage and append them
# to the timings file
get_times "config" $txtlog >>$timings_file
get_times "lib" $txtlog >>$timings_file
get_times "examples" $txtlog >>$timings_file
get_times "bin" $txtlog >>$timings_file
get_times "tests" $txtlog >>$timings_file
get_times "runall" $txtlog >>$timings_file
get_times "total" $txtlog >>$timings_file
echo " </tr>" >>$timings_file
fi
done
if [ $components_in_rows -ne 0 ]; then
gzlogsize_avg=$((gzlogsize_sum / logcount))
txtlogsize_avg=$((txtlogsize_sum / logcount))
if [ 0 -ne $libcount ]; then
libsize_avg=$((libsize_sum / libcount))
else
libsize_avg=""
fi
if [ 0 -ne $buildsize_count ]; then
fullbuildsize_avg=$((fullbuildsize_sum / buildsize_count))
cleanbuildsize_avg=$((cleanbuildsize_sum / buildsize_count))
else
fullbuildsize_avg=""
cleanbuildsize_avg=""
fi
output " </tbody>"
output " <tfooter>"
output " <tr>"
output " <td colspan=8 class=\"header\">min</td>"
output " <td>`format_size $libsize_min`</td>"
output " <td>`format_size $gzlogsize_min`</td>"
output " <td>`format_size $txtlogsize_min`</td>"
output " <td>`format_size $fullbuildsize_min`</td>"
output " <td>`format_size $cleanbuildsize_min`</td>"
output " <td></td>"
output " <td></td>"
output " </tr>"
output " <tr>"
output " <td colspan=8 class=\"header\">max</td>"
output " <td>`format_size $libsize_max`</td>"
output " <td>`format_size $gzlogsize_max`</td>"
output " <td>`format_size $txtlogsize_max`</td>"
output " <td>`format_size $fullbuildsize_max`</td>"
output " <td>`format_size $cleanbuildsize_max`</td>"
output " <td></td>"
output " <td></td>"
output " </tr>"
output " <tr>"
output " <td colspan=8 class=\"header\">total</td>"
output " <td>`format_size $libsize_sum`</td>"
output " <td>`format_size $gzlogsize_sum`</td>"
output " <td>`format_size $txtlogsize_sum`</td>"
output " <td>`format_size $fullbuildsize_sum`</td>"
output " <td>`format_size $cleanbuildsize_sum`</td>"
output " <td class=\"header\" colspan=9 rowspan=2></td>"
output " </tr>"
output " <tr>"
output " <td colspan=8 class=\"header\">average</td>"
output " <td>`format_size $libsize_avg`</td>"
output " <td>`format_size $gzlogsize_avg`</td>"
output " <td>`format_size $txtlogsize_avg`</td>"
output " <td>`format_size $fullbuildsize_avg`</td>"
output " <td>`format_size $cleanbuildsize_avg`</td>"
output " </tr>"
output " </tfooter>"
output " </table>"
output " <hr>"
cat <<EOF >>$timings_file
</tbody>
</table>
EOF
cat $timings_file | output
else
output " <ol>"
logcount=0
for c in $example_list $test_list $locale_list; do
logcount=$((logcount + 1))
# output one build per row, with components in columns
table_header="$table_header <th title=\"$c\">$logcount</th>"
output " <li>$c</li>"
done
output " </ol>"
fi
output " <hr>"
######################################################################
# xcross-component script
xcomp=$HOME/stdcxx/bin/xcomp.awk
######################################################################
# process a list of builds, one build per row
process_builds()
{
component_type=$1 # example, locale, or test
component_list=$2 # list of component names
cat <<EOF | output
<h2>Results of ${component_type}s</h2>
<table>
<tr>
<th><a name="${component_type}s"></a>log</th>
$table_header
</tr>
EOF
for l in $textlogs; do
fname=`basename $l .$$`
cat <<EOF | output
<tr>
<td class="name">
<a href="$logdir/$fname">$fname</a>
</td>
EOF
for c in $component_list; do
line=`grep "^$c *[^-]" $l`
if [ $? -eq 0 -a "$line" != "" ]; then
echo $line \
| awk -f $xcomp component=$component_type \
name=$c verbose=$verbose expect="$expect" \
| output
else
output " <td class=\"missing\">N/A</td>"
fi
done
output " </tr>"
done
output " </table>"
}
if [ $components_in_rows -ne 0 ]; then
# check to see
if [ -r $xfailfile ]; then
xfails=$xfailfile
else
xfails=""
fi
awk -f $xcomp bodyonly=1 $xfails $textlogs | output
else
if [ "$examples_list" != "" ]; then
process_builds "example" "$examples_list"
fi
if [ "$test_list" != "" ]; then
process_builds "test" "$test_list"
fi
if [ "$locale_list" != "" ]; then
process_builds "locale" "$locale_list"
fi
fi
######################################################################
# output the rest of the HTML file
cat <<EOF | output
<h2><a name="codes"></a>Codes and Colors</h2>
<table>
<thead>
<tr>
<th colspan=4 class="header">Status</th>
<th rowspan=2 class="header">Meaning</th>
</tr>
<tr>
<th class="header" title="Unexpected success or ordinary failure">
Unexpected
</th>
<th class="header">Severity</th>
<th class="header" title="Ordinary success or expected failure">
Expected
</th>
<th class="header">Severity</th>
</tr>
</thead>
<tbody>
<tr>
<td class="XPASS">XPASS</td>
<td class="na">Success</td>
<td class="OK">OK</td>
<td class="na">Success</td>
<td class="na">
Component completed successfully and produced the expected
output.
</td>
</tr>
<tr>
<td colspan=2 class="na"><center>Not Applicable</center></td>
<td class="NOUT">NOUT</td>
<td class="na">Success</td>
<td class="na">
Component completed successfully and produced no output.
</td>
</tr>
<tr>
<td colspan=2 class="na"><center>Not Applicable</center></td>
<td class="BASE">BASE</td>
<td class="na">Success</td>
<td class="na">
Component completed successfully and matched the baseline.
</td>
</tr>
<tr>
<td colspan=2 class="na"><center>Not Applicable</center></td>
<td class="FORMAT">FORMAT</td>
<td class="na">Success</td>
<td class="na">
Component completed successfully but produced unexpected
output.
</td>
</tr>
<tr>
<td class="MISS">N/A</td>
<td class="na">Success</td>
<td colspan=2 class="na"><center>Not Applicable</center></td>
<td class="na">Component was not tested.</td>
</tr>
<tr>
<td class="XDEP">XDEP</td>
<td class="na">Failure</td>
<td colspan=2 class="na"><center>Not Applicable</center></td>
<td class="na">
Component was not attempted due to a missing (or failed)
dependency.
</td>
</tr>
<tr>
<td class="COMP">COMP</td>
<td class="na">Failure</td>
<td class="XCOMP">XCOMP</td>
<td class="na">Success</td>
<td class="na">Component failed to compile.</td>
</tr>
<tr>
<td class="LINK">LINK</td>
<td class="na">Failure</td>
<td class="XLINK">XLINK</td>
<td class="na">Success</td>
<td class="na">
Component compiled successfully but failed to link.
</td>
</tr>
<tr>
<td class="WARN">WARN</td>
<td class="na">Success</td>
<td class="XWARN">XWARN</td>
<td class="na">Success</td>
<td class="na">
Component compiled and linked successfully but with warnings.
</td>
</tr>
<tr>
<td class="RUNWARN">(N)</td>
<td class="na">Success</td>
<td class="XRUNWARN">(N)</td>
<td class="na">Success</td>
<td class="na">
Component compiled and linked successfully, exited with
a status of 0, but produced N warnings at runtime.
</td>
</tr>
<tr>
<td class="EXIT">N</td>
<td class="na">Failure</td>
<td class="XEXIT">N</td>
<td class="na">Success</td>
<td class="na">
Component compiled and linked successfully but exited with
a non-zero status of N.
</td>
</tr>
<tr>
<td class="DIFF">DIFF</td>
<td class="na">Failure</td>
<td class="XDIFF">XDIFF</td>
<td class="na">Success</td>
<td class="na">
Component compiled and linked successfully, exited with
a status of 0, but produced unexpected output.
</td>
</tr>
<tr>
<td class="SIGNAL">[SIG]&lt;name&gt;</td>
<td class="na">Failure</td>
<td class="XSIGNAL">X[SIG]&lt;name&gt;</td>
<td class="na">Success</td>
<td class="na">
Component compiled and linked successfully, but exited
with the named signal (for example, SIGABRT).
</td>
</tr>
<tr>
<td class="ASSERT">(N)</td>
<td class="na">Failure</td>
<td class="XASSERT">(N)</td>
<td class="na">Success</td>
<td class="na">
Component compiled and linked successfully, exited with
a status of 0, but failed N assertions at runtime.
</td>
</tr>
</tbody>
</table>
<h2><a name="buildtypes"></a>Build Types</h2>
<table>
<thead>
<tr>
<td class="header">Library:</td>
<th colspan="2">Archive Library</th>
<th colspan="2">Shared Library</th>
<th colspan="2">Shared Archive (AIX)</th>
</tr>
<tr>
<td class="header">Number/Symbol</td>
<td class="header">s<br>(32-bit)</td>
<td class="header">S<br>(64-bit)</td>
<td class="header">d<br>(32-bit)</td>
<td class="header">D<br>(64-bit)</td>
<td class="header">a<br>(32-bit)</td>
<td class="header">A<br>(64-bit)</td>
</tr>
</thead>
<tbody>
<tr>
<td class="header"><b>8</b><br>(optimized)</td>
<td class="na">
<b>8s</b>: Debugging off, optimized, not reentrant.
</td>
<td class="na">
<b>8S</b>: Debugging off, optimized, not reentrant.
</td>
<td class="na">
<b>8d</b>: Debugging off, optimized, not reentrant.
</td>
<td class="na">
<b>8D</b>: Debugging off, optimized, not reentrant.
</td>
<td class="na">
<b>8a</b>: Debugging off, optimized, not reentrant.
</td>
<td class="na">
<b>8A</b>: Debugging off, optimized, not reentrant.
</td>
</tr>
<tr>
<td class="header"><b>11</b><br>(debug)</td>
<td class="na">
<b>11s</b>: Debug, not optimized, not reentrant.
</td>
<td class="na">
<b>11S</b>: Debug, not optimized, not reentrant.
</td>
<td class="na">
<b>11d</b>: Debug, not optimized, not reentrant.
</td>
<td class="na">
<b>11D</b>: Debug, not optimized, not reentrant.
</td>
<td class="na">
<b>11a</b>: Debug, not optimized, not reentrant.
</td>
<td class="na">
<b>11A</b>: Debug, not optimized, not reentrant.
</td>
</tr>
<tr>
<td class="header"><b>12</b><br>(optimized)</td>
<td class="na">
<b>12s</b>: Debugging off, optimized, reentrant.
</td>
<td class="na">
<b>12S</b>: Debugging off, optimized, reentrant.
</td>
<td class="na">
<b>12d</b>: Debugging off, optimized, reentrant.
</td>
<td class="na">
<b>12D</b>: Debugging off, optimized, reentrant.
</td>
<td class="na">
<b>12a</b>: Debugging off, optimized, reentrant.
</td>
<td class="na">
<b>12A</b>: Debugging off, optimized, reentrant.
</td>
</tr>
<tr>
<td class="header"><b>15</b><br>(debug)</td>
<td class="na">
<b>15s</b>: Debug, not optimized, reentrant.
</td>
<td class="na">
<b>15S</b>: Debug, not optimized, reentrant.
</td>
<td class="na">
<b>15d</b>: Debug, not optimized, reentrant.
</td>
<td class="na">
<b>15D</b>: Debug, not optimized, reentrant.
</td>
<td class="na">
<b>15a</b>: Debug, not optimized, reentrant.
</td>
<td class="na">
<b>15A</b>: Debug, not optimized, reentrant.
</td>
</tr>
</tbody>
</table>
</body>
</html>
EOF
######################################################################
if [ -z $no_clean ]; then
# clean up
if [ $verbose -eq 1 ]; then
echo "$myname: rm $textlogs $timings_file"
fi
rm -f $textlogs $timings_file
fi