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
181 svn cleanup && svn revert -R . && svn st | cut -d' ' -f5- | xargs rm -v
185 exec ${CONFIG_SHELL-/bin/sh} $SOURCE/contrib/patch_tester.sh $args
189 svn_branch=`grep "^branch:" $PATCH | sed -e "s/^branch://g" -e "s/ //g"`
190 if [ x$svn_branch = x ]; then
194 svn_revision=`grep "^revision:" $PATCH | sed -e "s/^revision://g" -e "s/ //g"`
195 if [ x$svn_revision = x ]; then
203 if ! svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/trunk &> $TESTING/svn ; then
204 report "failed to update svn sources with"
205 report "svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/trunk"
211 svn://gcc.gnu.org/svn/gcc/*)
212 if ! svn switch -r $svn_revision $svn_branch &> $TESTING/svn ; then
213 report "failed to update svn sources with"
214 report "svn switch -r $svn_revision $svn_branch"
221 if ! svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/branches/$svn_branch &> $TESTING/svn ; then
222 report "failed to update svn sources with"
223 report "svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/branches/$svn_branch"
230 current_version=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
231 if [[ $VERSION < $current_version ]]; then
232 if [ -f $SOURCE/contrib/patch_tester.sh ]; then
241 if [ $nogpg = false ]; then
242 if ! gpg --batch --verify $PATCH &> $TESTING/gpgverify ; then
243 report "your patch failed to verify:"
244 freport $TESTING/gpgverify
249 # Detect if the patch was created in toplev GCC.
250 grep "^Index: " $PATCH | grep "gcc/"
253 if ! patch -p0 < $PATCH &> $TESTING/patching ; then
254 report "your patch failed to apply:"
255 freport $TESTING/patching
260 if ! patch -p0 < $PATCH &> $TESTING/patching ; then
261 report "your patch failed to apply:"
262 freport $TESTING/patching
269 for COMPILER in $COMPILERS ; do
270 if [ -f $BUILD/$COMPILER ]; then
271 cp $BUILD/$COMPILER $PRISTINE
281 CONFIG_OPTIONS=`grep "^configure:" $PATCH | sed -e "s/^configure://g"`
282 if ! $SOURCE/configure $CONFIG_OPTIONS &> $1/configure ; then
283 report "configure failed with:"
288 if ! make $dashj `grep "^make:" $PATCH | sed -e "s/^make://g"` bootstrap &> $1/bootstrap ; then
289 report "bootstrap failed with last lines:"
290 tail -30 $1/bootstrap > $1/last_bootstrap
291 freport $1/last_bootstrap
292 report "grep --context=20 Error bootstrap:"
293 grep --context=20 Error $1/bootstrap > $1/bootstrap_error
294 freport $1/bootstrap_error
298 CHECK_OPTIONS=`grep "^check:" $PATCH | sed -e "s/^check://g"`
299 make $dashj $CHECK_OPTIONS -k check &> $1/check
301 for LOG in $TESTLOGS ; do
302 if [ -f $BUILD/$LOG ]; then
304 mv `echo "$BUILD/$LOG" | sed -e "s/\.sum/\.log/g"` $1
311 bootntest_patched () {
314 apply_patch && bootntest $PATCHED
318 # Build the pristine tree with exactly the same options as the patch under test.
319 bootntest_pristine () {
321 current_branch=`svn info $SOURCE | grep "^URL:" | sed -e "s/URL: //g" -e "s/svn:\/\/gcc.gnu.org\/svn\/gcc\///g"`
322 current_version=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
323 PRISTINE=$STATE/$current_branch/$current_version
325 if [ -d $PRISTINE ]; then
326 ln -s $PRISTINE $TESTING/pristine
330 ln -s $PRISTINE $TESTING/pristine
333 if [ $RETVAL = 0 -a $savecompilers = true ]; then
346 for LOG in $TESTLOGS ; do
348 if [ -f $1/$NLOG ]; then
349 awk '/^FAIL: / { print "'$NLOG'",$2; }' $1/$NLOG
351 done | sort | uniq > $1/failed
353 comm -12 $1/failed $1/passes >> $1/regress
354 NUMREGRESS=`wc -l < $1/regress | tr -d ' '`
356 if [ $NUMREGRESS -eq 0 ] ; then
357 for LOG in $TESTLOGS ; do
359 if [ -f $1/$NLOG ] ; then
360 awk '/^PASS: / { print "'$NLOG'",$2; }' $1/$NLOG
362 done | sort | uniq | comm -23 - $1/failed > $1/passes
363 echo "there are no regressions with your patch." >> $1/report
365 echo "with your patch there are $NUMREGRESS regressions." >> $1/report
366 echo "list of regressions with your patch:" >> $1/report
367 cat $1/regress >> $1/report
371 contrib_compare_tests () {
372 report "comparing logs with contrib/compare_tests:"
373 for LOG in $TESTLOGS ; do
375 if [ -f $PRISTINE/$NLOG -a -f $PATCHED/$NLOG ]; then
376 $SOURCE/contrib/compare_tests $PRISTINE/$NLOG $PATCHED/$NLOG > $TESTING/compare_$NLOG
377 freport $TESTING/compare_$NLOG
384 cp $PRISTINE/passes $PATCHED
386 freport $PATCHED/report
387 report "FAILs with patched version:"
388 freport $PATCHED/failed
389 report "FAILs with pristine version:"
390 freport $PRISTINE/failed
392 # contrib_compare_tests
396 backup_patched=$STATE/patched/`now`
397 report "The files used for the validation of your patch are stored in $backup_patched on the tester machine."
399 EMAIL=`grep "^email:" $PATCH | sed -e "s/^email://g" -e "s/ //g"`
400 if [ x$EMAIL != x ]; then
401 mutt -s "[regtest] Results for `basename $PATCH` on $TARGET" -i $REPORT -a $PATCH $EMAIL
404 mv $TESTING $backup_patched
408 EMAIL=`grep "^email:" $PATCH | sed -e "s/^email://g" -e "s/ //g"`
409 if [ x$EMAIL != x ]; then
411 START_REPORT=$TESTING/start_report
412 echo "Hi, " >> $START_REPORT
413 echo "I'm the automatic tester running on $TARGET." >> $START_REPORT
414 echo "I just started to look at your patch `basename $PATCH`." >> $START_REPORT
415 echo "Bye, your automatic tester." >> $START_REPORT
416 mutt -s "[regtest] Starting bootstrap for `basename $PATCH` on $TARGET" -i $START_REPORT $EMAIL
420 # After selfexec, $TESTING is already set up.
421 if [ -d $TESTING ]; then
422 # The only file in $TESTING is the patch.
423 PATCH=`ls -rt -1 $TESTING | head -1`
424 PATCH=$TESTING/$PATCH
425 if [ -f $PATCH ]; then
426 bootntest_patched && bootntest_pristine && compare_passes
432 PATCH=`ls -rt -1 $PATCHES | head -1`
433 if [ x$PATCH = x ]; then
436 sysload=`uptime | cut -d, -f 5`
437 if [[ $sysload > $watermark ]]; then
438 # Wait a bit when system load is too high.
442 mv $PATCHES/$PATCH $TESTING/
443 PATCH=$TESTING/$PATCH
446 update && bootntest_patched && bootntest_pristine && compare_passes