OSDN Git Service

2007-12-15 Sebastian Pop <sebastian.pop@amd.com>
authorspop <spop@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 16 Dec 2007 00:08:17 +0000 (00:08 +0000)
committerspop <spop@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 16 Dec 2007 00:08:17 +0000 (00:08 +0000)
* patch_tester.sh: New.
* prepare_patch.sh: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@130981 138bc75d-0d04-0410-961f-82ee72b054a4

contrib/ChangeLog
contrib/patch_tester.sh [new file with mode: 0755]
contrib/prepare_patch.sh [new file with mode: 0755]

index e2f4ede..197221d 100644 (file)
@@ -1,3 +1,8 @@
+2007-12-15  Sebastian Pop  <sebastian.pop@amd.com>
+
+       * patch_tester.sh: New.
+       * prepare_patch.sh: New.
+
 2007-11-26  Alexandre Oliva  <aoliva@redhat.com>
 
        * compare-debug: Introduce -p flag to preserve .stripped files.
diff --git a/contrib/patch_tester.sh b/contrib/patch_tester.sh
new file mode 100755 (executable)
index 0000000..9866b3d
--- /dev/null
@@ -0,0 +1,454 @@
+#!/bin/sh
+
+# Tests a set of patches from a directory.
+# Copyright (C) 2007  Free Software Foundation, Inc.
+# Contributed by Sebastian Pop <sebastian.pop@amd.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+cat <<EOF
+
+WARNING: This script should only be fed with patches from known
+         authorized and trusted sources.  Don't even think about
+         hooking it up to a raw feed from the gcc-patches list or
+         you'll regret it.
+
+EOF
+
+args=$@
+
+dashj=
+default_standby=1
+standby=$default_standby
+default_watermark=0.60
+watermark=$default_watermark
+savecompilers=false
+nogpg=false
+
+usage() {
+    cat <<EOF
+patch_tester.sh [-j<N>] [-standby N] [-watermark N] [-savecompilers] [-nogpg]
+                <source_dir> [patches_dir [state_dir [build_dir]]]
+
+    J is the flag passed to make.  Default is empty string.
+
+    STANDBY is the number of minutes between checks for new patches in
+    PATCHES_DIR.  Default is ${default_standby} minutes.
+
+    WATERMARK is the 5 minute average system charge under which a new
+    compile can start.  Default is ${default_watermark}.  Note that the comparison 
+    is done in lexicographical order, so don't forget the leading 0.
+
+    SAVECOMPILERS copies the compilers in the same directory as the
+    test results for the non patched version.  Default is not copy.
+
+    NOGPG can be used to avoid checking the GPG signature of patches.
+
+    SOURCE_DIR is the directory containing GCC's toplevel configure.
+
+    PATCHES_DIR is the directory containing the patches to be tested.
+    Default is SOURCE_DIR/patches.
+
+    STATE_DIR is where the tester maintains its internal state.
+    Default is SOURCE_DIR/state.
+
+    BUILD_DIR is the build tree, a temporary directory that this
+    script will delete and recreate.  Default is SOURCE_DIR/obj.
+
+EOF
+    exit 1
+}
+
+while [ $# -ne 0 ]; do
+    case $1 in
+       -j*)
+           dashj=$1; shift
+           ;;
+       -standby)
+           [[ $# > 2 ]] || usage
+           standby=$2; shift; shift
+           ;;
+       -watermark)
+           [[ $# > 2 ]] || usage
+           watermark=$2; shift; shift
+           ;;
+       -savecompilers)
+           savecompilers=true; shift
+           ;;
+       -nogpg)
+           nogpg=true; shift
+           ;;
+       -*) 
+           echo "Invalid option: $1"
+           usage
+           ;;
+       *)
+           break
+           ;;
+    esac
+done
+
+test $# -eq 0 && usage
+
+SOURCE=$1
+PATCHES=
+STATE=
+BUILD=
+
+if [[ $# < 2 ]]; then
+    PATCHES=$SOURCE/patches
+else
+    PATCHES=$2
+fi
+if [[ $# < 3 ]]; then
+    STATE=$SOURCE/state
+else
+    STATE=$3
+fi
+if [[ $# < 4 ]]; then
+    BUILD=$SOURCE/obj
+else
+    BUILD=$4
+fi
+
+[ -d $PATCHES ] || mkdir -p $PATCHES
+[ -d $STATE ] || mkdir -p $STATE
+[ -d $STATE/patched ] || mkdir -p $STATE/patched
+[ -d $SOURCE ] || mkdir -p $SOURCE
+[ -f $SOURCE/config.guess ] || {
+    cd $SOURCE
+    svn -q co svn://gcc.gnu.org/svn/gcc/trunk .
+}
+
+VERSION=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
+
+exec >> $STATE/tester.log 2>&1 || exit 1
+set -x
+
+TESTING=$STATE/testing
+REPORT=$TESTING/report
+PRISTINE=$TESTING/pristine
+PATCHED=$TESTING/patched
+PATCH=
+TARGET=`$SOURCE/config.guess || exit 1` 
+TESTLOGS="gcc/testsuite/gcc/gcc.sum
+gcc/testsuite/gfortran/gfortran.sum
+gcc/testsuite/g++/g++.sum
+gcc/testsuite/objc/objc.sum
+$TARGET/libstdc++-v3/testsuite/libstdc++.sum
+$TARGET/libffi/testsuite/libffi.sum
+$TARGET/libjava/testsuite/libjava.sum
+$TARGET/libgomp/testsuite/libgomp.sum
+$TARGET/libmudflap/testsuite/libmudflap.sum"
+COMPILERS="gcc/cc1
+gcc/cc1obj
+gcc/cc1plus
+gcc/f951
+gcc/jc1
+gcc/gnat1
+gcc/tree1"
+
+now () {
+    echo `TZ=UTC date +"%Y_%m_%d_%H_%M_%S"`
+}
+
+report () {
+    echo "Checker: (`now`): $@" >> $REPORT
+}
+
+freport () {
+    if [ -s $1 ]; then
+       report "(cat $1"
+       cat $1 >> $REPORT
+       report "tac)"
+    fi
+}
+
+cleanup () {
+    cd $SOURCE
+
+    # FORNOW: Until this script is not committed to trunk, save and restore it.
+    mv $SOURCE/contrib/patch_tester.sh $STATE
+    svn cleanup && svn revert -R . && svn st | cut -d' ' -f5- | xargs rm -v
+    mv $STATE/patch_tester.sh $SOURCE/contrib/
+}
+
+selfexec () {
+    exec ${CONFIG_SHELL-/bin/sh} $SOURCE/contrib/patch_tester.sh $args
+}
+
+update () {
+    svn_branch=`grep "^branch:" $PATCH | sed -e "s/^branch://g" -e "s/ //g"`
+    if [ x$svn_branch = x ]; then
+       svn_branch=trunk
+    fi
+
+    svn_revision=`grep "^revision:" $PATCH | sed -e "s/^revision://g" -e "s/ //g"`
+    if [ x$svn_revision = x ]; then
+       svn_revision=HEAD
+    fi
+
+    cleanup
+    cd $SOURCE
+    case $svn_branch in
+       trunk)
+           if ! svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/trunk &> $TESTING/svn ; then
+               report "failed to update svn sources with"
+               report "svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/trunk"
+               freport $TESTING/svn
+               return 1
+           fi
+           ;;
+
+       svn://gcc.gnu.org/svn/gcc/*)
+           if ! svn switch -r $svn_revision $svn_branch &> $TESTING/svn ; then
+               report "failed to update svn sources with"
+               report "svn switch -r $svn_revision $svn_branch"
+               freport $TESTING/svn
+               return 1
+           fi
+           ;;
+
+       *)
+           if ! svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/branches/$svn_branch &> $TESTING/svn ; then
+               report "failed to update svn sources with"
+               report "svn switch -r $svn_revision svn://gcc.gnu.org/svn/gcc/branches/$svn_branch"
+               freport $TESTING/svn
+               return 1
+           fi
+           ;;
+    esac
+
+    current_version=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
+    if [[ $VERSION < $current_version ]]; then
+       if [ -f $SOURCE/contrib/patch_tester.sh ]; then
+           selfexec
+       fi
+    fi
+
+    return 0
+}
+
+apply_patch () {
+    if [ $nogpg = false ]; then
+       if ! gpg --batch --verify $PATCH &> $TESTING/gpgverify ; then
+           report "your patch failed to verify:"
+           freport $TESTING/gpgverify
+           return 1
+       fi
+    fi
+
+    # Detect if the patch was created in toplev GCC.
+    grep "^Index: " $PATCH | grep "gcc/"
+    if [ $? = 0 ]; then
+       cd $SOURCE
+       if ! patch -p0 < $PATCH &> $TESTING/patching ; then
+           report "your patch failed to apply:"
+           freport $TESTING/patching
+           return 1
+       fi
+    else
+       cd $SOURCE/gcc
+       if ! patch -p0 < $PATCH &> $TESTING/patching ; then
+           report "your patch failed to apply:"
+           freport $TESTING/patching
+           return 1
+       fi
+    fi
+}
+
+save_compilers () {
+    for COMPILER in $COMPILERS ; do
+       if [ -f $BUILD/$COMPILER ]; then
+           cp $BUILD/$COMPILER $PRISTINE
+       fi
+    done
+}
+
+bootntest () {
+    rm -rf $BUILD
+    mkdir $BUILD
+    cd $BUILD
+
+    CONFIG_OPTIONS=`grep "^configure:" $PATCH | sed -e "s/^configure://g"`
+    if ! $SOURCE/configure $CONFIG_OPTIONS &> $1/configure ; then
+       report "configure failed with:"
+       freport $1/configure
+       return 1
+    fi
+
+    if ! make $dashj `grep "^make:" $PATCH | sed -e "s/^make://g"` bootstrap &> $1/bootstrap ; then
+       report "bootstrap failed with last lines:"
+       tail -30 $1/bootstrap > $1/last_bootstrap
+       freport $1/last_bootstrap
+       report "grep --context=20 Error bootstrap:"
+       grep --context=20 Error $1/bootstrap > $1/bootstrap_error
+       freport $1/bootstrap_error
+       return 1
+    fi
+
+    CHECK_OPTIONS=`grep "^check:" $PATCH | sed -e "s/^check://g"`
+    make $dashj $CHECK_OPTIONS -k check &> $1/check
+
+    for LOG in $TESTLOGS ; do
+       if [ -f $BUILD/$LOG ]; then
+           mv $BUILD/$LOG $1
+           mv `echo "$BUILD/$LOG" | sed -e "s/\.sum/\.log/g"` $1
+       fi
+    done
+
+    return 0
+}
+
+bootntest_patched () {
+    cleanup
+    mkdir -p $PATCHED
+    apply_patch && bootntest $PATCHED
+    return $?
+}
+
+# Build the pristine tree with exactly the same options as the patch under test.
+bootntest_pristine () {
+    cleanup
+    current_branch=`svn info $SOURCE | grep "^URL:" | sed -e "s/URL: //g" -e "s/svn:\/\/gcc.gnu.org\/svn\/gcc\///g"`
+    current_version=`svn info $SOURCE | grep "^Revision:" | sed -e "s/^Revision://g" -e "s/ //g"`
+    PRISTINE=$STATE/$current_branch/$current_version
+
+    if [ -d $PRISTINE ]; then
+       ln -s $PRISTINE $TESTING/pristine
+       return 0
+    else
+       mkdir -p $PRISTINE
+       ln -s $PRISTINE $TESTING/pristine
+       bootntest $PRISTINE
+       RETVAL=$?
+       if [ $RETVAL = 0 -a $savecompilers = true ]; then
+           save_compilers
+       fi
+       return $RETVAL
+    fi
+}
+
+regtest () {
+    touch $1/report
+    touch $1/passes
+    touch $1/failed
+    touch $1/regress
+
+    for LOG in $TESTLOGS ; do
+       NLOG=`basename $LOG`
+       if [ -f $1/$NLOG ]; then
+           awk '/^FAIL: / { print "'$NLOG'",$2; }' $1/$NLOG
+       fi
+    done | sort | uniq > $1/failed
+
+    comm -12 $1/failed $1/passes >> $1/regress
+    NUMREGRESS=`wc -l < $1/regress | tr -d ' '`
+
+    if [ $NUMREGRESS -eq 0 ] ; then
+       for LOG in $TESTLOGS ; do
+           NLOG=`basename $LOG`
+           if [ -f $1/$NLOG ] ; then
+               awk '/^PASS: / { print "'$NLOG'",$2; }' $1/$NLOG
+           fi
+       done | sort | uniq | comm -23 - $1/failed > $1/passes
+       echo "there are no regressions with your patch." >> $1/report
+    else
+       echo "with your patch there are $NUMREGRESS regressions." >> $1/report
+       echo "list of regressions with your patch:" >> $1/report
+       cat $1/regress >> $1/report
+    fi
+}
+
+contrib_compare_tests () {
+    report "comparing logs with contrib/compare_tests:"
+    for LOG in $TESTLOGS ; do
+       NLOG=`basename $LOG`
+       if [ -f $PRISTINE/$NLOG -a -f $PATCHED/$NLOG ]; then
+           $SOURCE/contrib/compare_tests $PRISTINE/$NLOG $PATCHED/$NLOG > $TESTING/compare_$NLOG
+           freport $TESTING/compare_$NLOG
+       fi
+    done
+}
+
+compare_passes () {
+    regtest $PRISTINE
+    cp $PRISTINE/passes $PATCHED
+    regtest $PATCHED
+    freport $PATCHED/report
+    report "FAILs with patched version:"
+    freport $PATCHED/failed
+    report "FAILs with pristine version:"
+    freport $PRISTINE/failed
+
+    # contrib_compare_tests
+}
+
+write_report () {
+    backup_patched=$STATE/patched/`now`
+    report "The files used for the validation of your patch are stored in $backup_patched on the tester machine."
+
+    EMAIL=`grep "^email:" $PATCH | sed -e "s/^email://g" -e "s/ //g"`
+    if [ x$EMAIL != x ]; then
+       mutt -s "[regtest] Results for `basename $PATCH` on $TARGET" -i $REPORT -a $PATCH $EMAIL
+    fi
+
+    mv $TESTING $backup_patched
+}
+
+announce () {
+    EMAIL=`grep "^email:" $PATCH | sed -e "s/^email://g" -e "s/ //g"`
+    if [ x$EMAIL != x ]; then
+
+       START_REPORT=$TESTING/start_report
+       echo "Hi, " >> $START_REPORT
+       echo "I'm the automatic tester running on $TARGET." >> $START_REPORT
+       echo "I just started to look at your patch `basename $PATCH`." >> $START_REPORT
+       echo "Bye, your automatic tester." >> $START_REPORT
+       mutt -s "[regtest] Starting bootstrap for `basename $PATCH` on $TARGET" -i $START_REPORT $EMAIL
+    fi
+}
+
+# After selfexec, $TESTING is already set up.  
+if [ -d $TESTING ]; then
+    # The only file in $TESTING is the patch.
+    PATCH=`ls -rt -1 $TESTING | head -1`
+    PATCH=$TESTING/$PATCH
+    if [ -f $PATCH ]; then
+       bootntest_patched && bootntest_pristine && compare_passes
+       write_report
+    fi
+fi
+
+while true; do
+    PATCH=`ls -rt -1 $PATCHES | head -1`
+    if [ x$PATCH = x ]; then
+       sleep ${standby}m
+    else
+       sysload=`uptime | cut -d, -f 5`
+       if [[ $sysload > $watermark ]]; then
+           # Wait a bit when system load is too high.
+           sleep ${standby}m
+       else
+           mkdir -p $TESTING
+           mv $PATCHES/$PATCH $TESTING/
+           PATCH=$TESTING/$PATCH
+
+           announce
+           update && bootntest_patched && bootntest_pristine && compare_passes
+           write_report
+       fi
+    fi
+done
diff --git a/contrib/prepare_patch.sh b/contrib/prepare_patch.sh
new file mode 100755 (executable)
index 0000000..5770e5a
--- /dev/null
@@ -0,0 +1,96 @@
+#!/bin/sh
+#set -x
+
+# Prepares a patch for the patch tester.
+# Copyright (C) 2007  Free Software Foundation, Inc.
+# Contributed by Sebastian Pop <sebastian.pop@amd.com>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+usage() {
+    cat <<EOF
+prepare_patch.sh <source_dir> [patches_dir]
+
+    SOURCE_DIR is the directory containing GCC's toplevel configure.
+
+    PATCHES_DIR is the directory where the patch will be copied to.
+    Default is SOURCE_DIR/patches.
+
+EOF
+    exit 1
+}
+
+test $# -eq 0 && usage
+
+SOURCE=$1
+PATCHES=
+
+if [[ "$#" < 2 ]]; then
+    PATCHES=$SOURCE/patches
+else
+    PATCHES=$2
+fi
+
+[ -f $SOURCE/config.guess ] || usage
+[ -d $PATCHES ] || mkdir -p $PATCHES
+
+echo "Enter a name for this patch: "
+read name
+PATCH=$PATCHES/`TZ=UTC date +"%Y_%m_%d_%H_%M_%S"`_$name.diff
+
+echo "Enter the email where the report should be sent: "
+read email
+echo "email:$email" >> $PATCH
+
+branch=`svn info $SOURCE | grep URL: | sed -e "s/^URL: //g"`
+echo "Enter svn branch (svn info in $SOURCE reports $branch, default is trunk): "
+read svn_branch
+if [ x$svn_branch = x ]; then
+    svn_branch=trunk
+fi
+echo "branch:$svn_branch" >> $PATCH
+
+revision=`svn info $SOURCE | grep Revision: | sed -e "s/^Revision: //g"`
+echo "Enter svn revision (svn info in $SOURCE reports $revision, default is HEAD): "
+read svn_revision
+if [ x$svn_revision = x ]; then
+    svn_revision=HEAD
+fi
+echo "revision:$svn_revision" >> $PATCH
+
+echo "Enter configure options: "
+read configure_options
+echo "configure:$configure_options" >> $PATCH
+
+echo "Enter make options: "
+read make_options
+echo "make:$make_options" >> $PATCH
+
+echo "Enter make check options: "
+read check_options
+echo "check:$check_options" >> $PATCH
+
+echo "" >> $PATCH
+
+svn diff $SOURCE | tee -a $PATCH
+
+cat <<EOF
+
+You can now edit your patch, include a ChangeLog, and before
+submitting to the patch tester, don't forget to sign it with:
+
+  gpg --clearsign $PATCH
+
+EOF