3 # Tests a set of patches from a directory.
4 # Copyright (C) 2007 Free Software Foundation, Inc.
5 # Contributed by Sebastian Pop <sebastian.pop@amd.com>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 WARNING: This script should only be fed with patches from known
24 authorized and trusted sources. Don't even think about
25 hooking it up to a raw feed from the gcc-patches list or
34 standby=$default_standby
35 default_watermark=0.60
36 watermark=$default_watermark
42 patch_tester.sh [-j<N>] [-standby N] [-watermark N] [-savecompilers] [-nogpg]
43 <source_dir> [patches_dir [state_dir [build_dir]]]
45 J is the flag passed to make. Default is empty string.
47 STANDBY is the number of minutes between checks for new patches in
48 PATCHES_DIR. Default is ${default_standby} minutes.
50 WATERMARK is the 5 minute average system charge under which a new
51 compile can start. Default is ${default_watermark}. Note that the comparison
52 is done in lexicographical order, so don't forget the leading 0.
54 SAVECOMPILERS copies the compilers in the same directory as the
55 test results for the non patched version. Default is not copy.
57 NOGPG can be used to avoid checking the GPG signature of patches.
59 SOURCE_DIR is the directory containing GCC's toplevel configure.
61 PATCHES_DIR is the directory containing the patches to be tested.
62 Default is SOURCE_DIR/patches.
64 STATE_DIR is where the tester maintains its internal state.
65 Default is SOURCE_DIR/state.
67 BUILD_DIR is the build tree, a temporary directory that this
68 script will delete and recreate. Default is SOURCE_DIR/obj.
74 while [ $# -ne 0 ]; do
81 standby=$2; shift; shift
85 watermark=$2; shift; shift
88 savecompilers=true; shift
94 echo "Invalid option: $1"
103 test $# -eq 0 && usage
110 if [[ $# < 2 ]]; then
111 PATCHES=$SOURCE/patches
115 if [[ $# < 3 ]]; then
120 if [[ $# < 4 ]]; then
126 [ -d $PATCHES ] || mkdir -p $PATCHES
127 [ -d $STATE ] || mkdir -p $STATE
128 [ -d $STATE/patched ] || mkdir -p $STATE/patched
129 [ -d $SOURCE ] || mkdir -p $SOURCE
130 [ -f $SOURCE/config.guess ] || {
132 svn -q co svn://gcc.gnu.org/svn/gcc/trunk .
135 VERSION=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
137 exec >> $STATE/tester.log 2>&1 || exit 1
140 TESTING=$STATE/testing
141 REPORT=$TESTING/report
142 PRISTINE=$TESTING/pristine
143 PATCHED=$TESTING/patched
145 TARGET=`$SOURCE/config.guess || exit 1`
146 TESTLOGS="gcc/testsuite/gcc/gcc.sum
147 gcc/testsuite/gfortran/gfortran.sum
148 gcc/testsuite/g++/g++.sum
149 gcc/testsuite/objc/objc.sum
150 $TARGET/libstdc++-v3/testsuite/libstdc++.sum
151 $TARGET/libffi/testsuite/libffi.sum
152 $TARGET/libjava/testsuite/libjava.sum
153 $TARGET/libgomp/testsuite/libgomp.sum
154 $TARGET/libmudflap/testsuite/libmudflap.sum"
164 echo `TZ=UTC date +"%Y_%m_%d_%H_%M_%S"`
168 echo "Checker: (`now`): $@" >> $REPORT
182 # FORNOW: Until this script is not committed to trunk, save and restore it.
183 mv $SOURCE/contrib/patch_tester.sh $STATE
184 svn cleanup && svn revert -R . && svn st | cut -d' ' -f5- | xargs rm -v
185 mv $STATE/patch_tester.sh $SOURCE/contrib/
189 exec ${CONFIG_SHELL-/bin/sh} $SOURCE/contrib/patch_tester.sh $args
193 svn_branch=`grep "^branch:" $PATCH | sed -e "s/^branch://g" -e "s/ //g"`
194 if [ x$svn_branch = x ]; then
198 svn_revision=`grep "^revision:" $PATCH | sed -e "s/^revision://g" -e "s/ //g"`
199 if [ x$svn_revision = x ]; then
207 if ! svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/trunk &> $TESTING/svn ; then
208 report "failed to update svn sources with"
209 report "svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/trunk"
215 svn://gcc.gnu.org/svn/gcc/*)
216 if ! svn switch -r $svn_revision $svn_branch &> $TESTING/svn ; then
217 report "failed to update svn sources with"
218 report "svn switch -r $svn_revision $svn_branch"
225 if ! svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/branches/$svn_branch &> $TESTING/svn ; then
226 report "failed to update svn sources with"
227 report "svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/branches/$svn_branch"
234 current_version=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
235 if [[ $VERSION < $current_version ]]; then
236 if [ -f $SOURCE/contrib/patch_tester.sh ]; then
245 if [ $nogpg = false ]; then
246 if ! gpg --batch --verify $PATCH &> $TESTING/gpgverify ; then
247 report "your patch failed to verify:"
248 freport $TESTING/gpgverify
253 # Detect if the patch was created in toplev GCC.
254 grep "^Index: " $PATCH | grep "gcc/"
257 if ! patch -p0 < $PATCH &> $TESTING/patching ; then
258 report "your patch failed to apply:"
259 freport $TESTING/patching
264 if ! patch -p0 < $PATCH &> $TESTING/patching ; then
265 report "your patch failed to apply:"
266 freport $TESTING/patching
273 for COMPILER in $COMPILERS ; do
274 if [ -f $BUILD/$COMPILER ]; then
275 cp $BUILD/$COMPILER $PRISTINE
285 CONFIG_OPTIONS=`grep "^configure:" $PATCH | sed -e "s/^configure://g"`
286 if ! $SOURCE/configure $CONFIG_OPTIONS &> $1/configure ; then
287 report "configure failed with:"
292 if ! make $dashj `grep "^make:" $PATCH | sed -e "s/^make://g"` bootstrap &> $1/bootstrap ; then
293 report "bootstrap failed with last lines:"
294 tail -30 $1/bootstrap > $1/last_bootstrap
295 freport $1/last_bootstrap
296 report "grep --context=20 Error bootstrap:"
297 grep --context=20 Error $1/bootstrap > $1/bootstrap_error
298 freport $1/bootstrap_error
302 CHECK_OPTIONS=`grep "^check:" $PATCH | sed -e "s/^check://g"`
303 make $dashj $CHECK_OPTIONS -k check &> $1/check
305 for LOG in $TESTLOGS ; do
306 if [ -f $BUILD/$LOG ]; then
308 mv `echo "$BUILD/$LOG" | sed -e "s/\.sum/\.log/g"` $1
315 bootntest_patched () {
318 apply_patch && bootntest $PATCHED
322 # Build the pristine tree with exactly the same options as the patch under test.
323 bootntest_pristine () {
325 current_branch=`svn info $SOURCE | grep "^URL:" | sed -e "s/URL: //g" -e "s/svn:\/\/gcc.gnu.org\/svn\/gcc\///g"`
326 current_version=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
327 PRISTINE=$STATE/$current_branch/$current_version
329 if [ -d $PRISTINE ]; then
330 ln -s $PRISTINE $TESTING/pristine
334 ln -s $PRISTINE $TESTING/pristine
337 if [ $RETVAL = 0 -a $savecompilers = true ]; then
350 for LOG in $TESTLOGS ; do
352 if [ -f $1/$NLOG ]; then
353 awk '/^FAIL: / { print "'$NLOG'",$2; }' $1/$NLOG
355 done | sort | uniq > $1/failed
357 comm -12 $1/failed $1/passes >> $1/regress
358 NUMREGRESS=`wc -l < $1/regress | tr -d ' '`
360 if [ $NUMREGRESS -eq 0 ] ; then
361 for LOG in $TESTLOGS ; do
363 if [ -f $1/$NLOG ] ; then
364 awk '/^PASS: / { print "'$NLOG'",$2; }' $1/$NLOG
366 done | sort | uniq | comm -23 - $1/failed > $1/passes
367 echo "there are no regressions with your patch." >> $1/report
369 echo "with your patch there are $NUMREGRESS regressions." >> $1/report
370 echo "list of regressions with your patch:" >> $1/report
371 cat $1/regress >> $1/report
375 contrib_compare_tests () {
376 report "comparing logs with contrib/compare_tests:"
377 for LOG in $TESTLOGS ; do
379 if [ -f $PRISTINE/$NLOG -a -f $PATCHED/$NLOG ]; then
380 $SOURCE/contrib/compare_tests $PRISTINE/$NLOG $PATCHED/$NLOG > $TESTING/compare_$NLOG
381 freport $TESTING/compare_$NLOG
388 cp $PRISTINE/passes $PATCHED
390 freport $PATCHED/report
391 report "FAILs with patched version:"
392 freport $PATCHED/failed
393 report "FAILs with pristine version:"
394 freport $PRISTINE/failed
396 # contrib_compare_tests
400 backup_patched=$STATE/patched/`now`
401 report "The files used for the validation of your patch are stored in $backup_patched on the tester machine."
403 EMAIL=`grep "^email:" $PATCH | sed -e "s/^email://g" -e "s/ //g"`
404 if [ x$EMAIL != x ]; then
405 mutt -s "[regtest] Results for `basename $PATCH` on $TARGET" -i $REPORT -a $PATCH $EMAIL
408 mv $TESTING $backup_patched
412 EMAIL=`grep "^email:" $PATCH | sed -e "s/^email://g" -e "s/ //g"`
413 if [ x$EMAIL != x ]; then
415 START_REPORT=$TESTING/start_report
416 echo "Hi, " >> $START_REPORT
417 echo "I'm the automatic tester running on $TARGET." >> $START_REPORT
418 echo "I just started to look at your patch `basename $PATCH`." >> $START_REPORT
419 echo "Bye, your automatic tester." >> $START_REPORT
420 mutt -s "[regtest] Starting bootstrap for `basename $PATCH` on $TARGET" -i $START_REPORT $EMAIL
424 # After selfexec, $TESTING is already set up.
425 if [ -d $TESTING ]; then
426 # The only file in $TESTING is the patch.
427 PATCH=`ls -rt -1 $TESTING | head -1`
428 PATCH=$TESTING/$PATCH
429 if [ -f $PATCH ]; then
430 bootntest_patched && bootntest_pristine && compare_passes
436 PATCH=`ls -rt -1 $PATCHES | head -1`
437 if [ x$PATCH = x ]; then
440 sysload=`uptime | cut -d, -f 5`
441 if [[ $sysload > $watermark ]]; then
442 # Wait a bit when system load is too high.
446 mv $PATCHES/$PATCH $TESTING/
447 PATCH=$TESTING/$PATCH
450 update && bootntest_patched && bootntest_pristine && compare_passes