#!/bin/sh #---------------------------------------------------------------------------# # Copyright (C) 2002-2003 The University of Melbourne. # This file may only be copied under the terms of the GNU General # Public License - see the file COPYING in the Mercury distribution. #---------------------------------------------------------------------------# # # submit_patch: # This implements a "commit server". # It takes as input a log message and a patch. # It checks out the Mercury sources, applies the patch, # and tests it (by bootchecking in a couple of grades). # If the tests pass, and --commit was specified, # it also commits the patch. # It locks the test directory, so you can submit # multiple patches at once and it will only run # one of them at a time. usage="\ Usage: $0 [options] Options: -d , --directory Run the tests in directory . -S , --space Require this amount of free disk space. --gcc Test the GCC-based native code back-end. -r , --repository Use the specified CVS repository for checking out mercury. -g , --gcc-repository Use the specified CVS repository for checking out GCC. --branch Use the specified branch tag for checking out the \`mercury' and \`tests' directories from the Mercury CVS repository. --gcc-branch Use the specified branch tag for checking out GCC. --mercury-gcc-branch Use the specified branch tag for checking out the \`mercury-gcc' directory from the Mercury CVS repository. --configure Use the specified options when configuring mercury. --gcc-configure Use the specified options when configuring GCC. -b , --bootcheck Bootcheck with the specified options, in addition the standard bootchecks (asm_fast.gc & hlc.gc). -u , --user Mail the output to the specified user. -t , --title <title> Specify a name for this patch. The patch title is used in the test sub-directory name, and is also included in the email subject line. -c, --commit Commit the patch, if the tests pass. -h, --help Display this usage message. " #---------------------------------------------------------------------------# # Default option settings # Name of this patch title=$$ # User to mail results to user=`whoami` # Place to run the tests test_root=/tmp/$user/mercury # Disk space needed (in megabytes) disk_space_required=300 # "true" if we should build with the GCC back-end, # so that `--target asm' works. do_gcc=false # CVS Repositories gcc_cvsroot=:pserver:anoncvs@gcc.gnu.org:/cvs/gcc mercury_cvsroot=/home/mercury1/repository if [ -d "$mercury_cvsroot/." ]; then : else mercury_cvsroot=:pserver:guest@cvs.mercury.cs.mu.oz.au:$mercury_cvsroot fi # CVS branches branch= gcc_branch= mercury_gcc_branch= # Configure options configure_opts= gcc_configure_opts="--enable-checking --enable-languages=c,mercury" # A "#"-separated list of bootchecks to run. bootchecks="--grade asm_fast.gc # --grade hlc.gc". # "true" if we should commit the patch if/when the tests pass. commit=false #-----------------------------------------------------------------------------# # # Parse the options # parse_options() { orig_command="$0 $*" while [ $# -gt 0 ]; do case "$1" in -t|--title) title="$2"; shift ;; -t*) title="` expr $1 : '-t\(.*\)' `"; ;; --gcc) do_gcc=true ;; -d|--directory) test_root="$2"; shift ;; -d*) test_root="` expr $1 : '-d\(.*\)' `"; ;; -r|--repository) mercury_cvsroot="$2"; shift ;; -r*) mercury_cvsroot="` expr $1 : '-r\(.*\)' `"; ;; -g|--gcc-repository) gcc_cvsroot="$2"; shift ;; -g*) gcc_cvsroot="` expr $1 : '-g\(.*\)' `"; ;; --branch) branch="-r$2"; shift ;; --gcc-branch) gcc_branch="-r$2"; shift ;; --mercury-gcc-branch) mercury_gcc_branch="-r$2"; shift ;; --configure) configure_opts="$2"; shift ;; --gcc-configure) gcc_configure_opts="$2"; shift ;; -s|--space) disk_space_required="$2"; shift ;; -s*) disk_space_required="` expr $1 : '-s\(.*\)' `"; ;; -b|--bootcheck) bootchecks="$bootchecks#$2"; shift ;; -b*) bootchecks="$bootchecks#` expr $1 : '-b\(.*\)' `"; ;; -u|--user) user="$2"; shift ;; -u*) user="` expr $1 : '-u\(.*\)' `"; ;; -c-|--no-commit) commit=false ;; -c|--commit) commit=true ;; -h|--help) echo "$usage"; exit 0 ;; --) shift; break ;; -*) echo "$0: unknown option \`$1'" 1>&2 echo "$usage" 1>&2 exit 1 ;; *) break ;; esac shift done if [ $# -ne 2 ]; then echo "$0: wrong number of arguments" 1>&2 echo "usage: $0 [options] <log message file> <patch file>" 1>&2 echo "Use \`--help' for help." 1>&2 exit 1 fi logmessage=$1 patchfile=$2 test_dir=$test_root/test_$title } #-----------------------------------------------------------------------------# obtain_lock() { until mkdir $test_root/lock; do sleep 60 done echo "Process $$ on host `hostname -f`" > $test_root/lock/info } release_lock() { rm -f $test_root/lock/info rmdir $test_root/lock } #-----------------------------------------------------------------------------# die() { host="`hostname -f 2>&1`" msg=" *** submit_patch failed: *** $@ Log file in $test_dir/OUTPUT on host $host. Leaving the build directory $test_dir intact in case you need to use it to debug the problem. You must to remove this directory when you have finished with it. " echo "$msg" 1>&2 echo "$msg" | mail -s "auto-test ($title) failed" $user release_lock exit 1 } succeed() { msg=" *** check_patch succeeded. Log file in $test_dir/OUTPUT. Leaving the build directory $test_dir intact in case you want to browse $test_dir/OUTPUT. You must to remove this directory when you have finished with it. " echo "$msg" 1>&2 echo "$msg" | mail -s "auto-test ($title) succeeded" $user } #-----------------------------------------------------------------------------# # check we've got a reasonable amount of free disk space -- no point # starting if we'll only run out of disk space. check_disk_space() { free=`df -m $test_root/. | awk ' NR == 2 && NF > 4 { print $4; exit; } NR == 3 { print $3; } '` echo "Free disk space: $free megabytes" [ "$free" -gt $disk_space_required ] || die "Insufficient disk space on $test_root" } #-----------------------------------------------------------------------------# apply_patch() { # We want the patch to apply properly regardless of whether it # includes "mercury/" prefixes on the file names for the files in # the "mercury" and "tests" directories. # So (1) we cd to the mercury directory before applying the patch, # so that it works if the "mercury/" prefix is omitted # but (2) we add a symlink "mercury" -> "." # so that it works if the prefix is included # and (3) we also add symlinks "gcc" -> "../gcc", cd mercury || die "cd mercury failed" ln -s . mercury || die "ln -s failed" ln -s ../tests tests || die "ln -s failed" ln -s ../gcc gcc || die "ln -s failed" ln -s ../mercury-gcc mercury-gcc || die "ln -s failed" patch -p0 < ../PATCH || die "applying patch failed" rm mercury tests gcc mercury-gcc || die "can't remove symlinks" cd .. || die "cd .. failed" } #-----------------------------------------------------------------------------# do_cvs_add_remove() { comm -13 FILES.old FILES.new > FILES.added || die "comm" comm -23 FILES.old FILES.new > FILES.removed || die "comm" if [ -s FILES.added ]; then cvs add `cat FILES.added` || die "cvs add failed" fi if [ -s FILES.removed ]; then cvs remove `cat FILES.removed` || die "cvs remove failed" fi return 0 } #-----------------------------------------------------------------------------# do_bootchecks() { old_IFS=$IFS IFS=# for bootcheck in $bootchecks; do IFS=$old_IFS eval tools/bootcheck $bootcheck || die "tools/bootcheck $bootcheck failed" IFS=# done IFS=$old_IFS } #-----------------------------------------------------------------------------# main() { parse_options "$@" || die "parse_options failed" [ -d $test_root ] || mkdir -p $test_root || die "creating dir $test_root failed" obtain_lock || die "can't obtain lock" trap 'die "interrupted"' 1 2 3 13 15 check_disk_space || die "insufficient disk space" mkdir $test_dir || die "mkdir $test_dir failed" echo "Testing in directory $test_dir" { set -x cp $patchfile $test_dir/PATCH || die "error copying $patchfile" cp $logmessage $test_dir/CVSLOG || die "error copying $logmessage" cd $test_dir || die "cd $test_dir failed" case $do_gcc in true) CVSROOT=$gcc_cvsroot export CVSROOT cvs checkout $gcc_branch gcc || die "GCC cvs checkout failed" (cd gcc && ./contrib/gcc_update --touch) CVSROOT=$mercury_cvsroot export CVSROOT cvs checkout $mercury_gcc_branch mercury-gcc \ || die "mercury-gcc checkout" (cd gcc/gcc && ln -s ../../mercury-gcc mercury) (cd gcc/gcc/mercury && ln -s ../mercury mercury) ;; esac CVSROOT=$mercury_cvsroot export CVSROOT cvs checkout $branch mercury || die "cvs checkout mercury failed" cvs checkout $branch tests || die "cvs checkout tests failed" touch FILES.old FILES.new find . | sort > FILES.old apply_patch || die "apply_patch failed" find . | sort > FILES.new do_cvs_add_remove || die "do_cvs_add_remove failed" cd mercury || die "cd mercury failed" autoconf || die "autoconf failed" sh configure --prefix=$test_dir/install $configure_opts \ || die "configure failed" case $do_gcc in true) cd ../gcc || die "cd ../gcc failed" sh configure --prefix=$test_dir/install $gcc_configure_opts \ || die "gcc configure failed" make bootstrap || die "gcc make bootstrap failed" cd ../mercury || die "cd ../mercury failed" ;; esac make || die "make failed" do_bootchecks || die "do_bootchecks failed" case $do_gcc in true) cd ../gcc || die "cd ../gcc failed" make -k check || die "gcc make -k check failed" cd ../mercury || die "cd ../mercury failed" ;; esac case $commit in true) cvs commit -m"`cat ../CVSLOG`" || die "cvs commit failed" ;; esac cd .. || die "cd .." rm -rf mercury tests mercury-gcc gcc || die "rm -rf failed" } </dev/null > $test_dir/OUTPUT 2>&1 release_lock set +x succeed exit 0 } #-----------------------------------------------------------------------------# main "$@" #-----------------------------------------------------------------------------#