1 #!/bin/sh -*- mode: shell-script; sh-indentation: 8; indent-tabs-mode: t; -*-
3 # build_farm -- distributed build/test architecture for samba, rsync, etc
5 # Copyright (C) 2001 by Andrew Tridgell <tridge@samba.org>
6 # Copyright (C) 2001 by Andrew Bartlett <abartlet@samba.org>
7 # Copyright (C) 2001, 2003 by Martin Pool <mbp@samba.org>
9 # default maximum runtime for any command
11 # default maximum memory size (100M) for any command
13 RUN_FROM_BUILD_FARM=yes
14 export RUN_FROM_BUILD_FARM
18 build_test_fns_id='$Id$'
20 #############################
21 # build a signature of a tree, used to see if we
28 find $sum_tree_test_root/$sum_tree_tree -type f -print | grep -v version.h | sort | xargs sum > $sum_tree_sum
29 sum build_test build_test.fns >> $sum_tree_sum
31 if [ -f "$host.fns" ]; then
32 sum $host.fns >> $sum_tree_sum
34 sum generic.fns >> $sum_tree_sum
37 if [ -f "$test_root/$tree.$scm" ]; then
38 sum "$test_root/$tree.$scm" >> $sum_tree_sum
41 for d in $deptrees; do
42 dscm=`choose_scm "$d"`
43 if [ -f "$test_root/$d.$dscm" ]; then
44 sum "$test_root/$d.$dscm" >> $sum_tree_sum
49 #############################
50 # send the logs to the master site
52 if [ "$nologreturn" = "yes" ]; then
53 echo "skipping log transfer"
59 chmod 0644 "$log" "$err"
61 # xargs -i is implemented differently or not at all.
62 # GNU xargs did not implement "-I" until 4.2.9:
63 xargs --version 2>&1 | grep "^GNU xargs" > /dev/null
65 if [ x"$status" = x"0" ]; then
69 if [ x"$XARGS_IS_GNU" = x"yes" ]; then
72 XARGS_I="xargs -I '{}'"
75 find $log -size +40000 | $XARGS_I sh -c 'dd if={} bs=1024 count=20000 of={}.tmp && mv {}.tmp {} && echo "\n***LOG TRUNCATED***" >> {}'
76 find $err -size +40000 | $XARGS_I sh -c 'dd if={} bs=1024 count=20000 of={}.tmp && mv {}.tmp {} && echo "\n***LOG TRUNCATED***" >> {}'
78 rsync $* -c -q --password-file=.password -z --timeout=200 \
79 "$log" "$err" $host@build.samba.org::build_farm_data/
83 #############################
84 # send the logs when they haven't changed
85 # the aim is to just update the servers timestamp.
86 # sending with a very large rsync block size does this
87 # with minimal network traffic
90 send_logs "$1" "$2" -B 10000000
93 ############################
94 # fetch the latest copy of the tree
96 if [ "$norsync" = "yes" ]; then
97 echo "skipping tree transfer"
100 if rsync --exclude=autom4te.cache/ --exclude=.svn/ --exclude=.git/ \
101 --delete-excluded -q --partial --timeout=200 -ctrlpz --delete --ignore-errors \
102 samba.org::ftp/unpacked/$fetchtree/ $test_root/$fetchtree; then
103 echo "transferred $fetchtree OK"
105 echo "transfer of $fetchtree failed code $?"
112 ############################
113 # fetch the latest copy of the rev meta info
118 test -z "$scm" && return 1
119 test x"$scm" = x"unknown" && return 1
120 test x"$scm" = x"cvs" && return 1
122 if [ "$norsync" = "yes" ]; then
123 echo "skipping .revinfo.$scm transfer"
125 if [ -r $test_root/$tree.$scm ]; then
126 rm -f $test_root/$tree.$scm.old
127 mv $test_root/$tree.$scm $test_root/$tree.$scm.old
129 rsync -q --timeout=200 -clz --ignore-errors \
130 samba.org::ftp/unpacked/$tree/.revinfo.$scm $test_root/$tree.$scm
132 if [ -r $test_root/$tree.$scm ]; then
138 ############################
139 # choose the scm that is used for the given project
144 samba* | rsync | libreplace | talloc | tdb | ldb | pidl | ccache)
156 ############################
157 # grab a lock file. Not atomic, but close :)
158 # tries to cope with NFS
160 if [ -z "$lock_root" ]; then
164 machine=`cat "$lckf" 2> /dev/null | cut -d: -f1`
165 pid=`cat "$lckf" 2> /dev/null | cut -d: -f2`
167 if [ "$pid" = "$$" ]; then
168 locknesting=`expr $locknesting + 1`
169 echo "lock nesting now $locknesting"
173 if test -f "$lckf"; then
174 test $machine = $host || {
175 echo "lock file $lckf is valid for other machine $machine"
179 echo "lock file $lckf is valid for process $pid"
182 echo "stale lock file $lckf for $machine:$pid"
186 echo "$host:$$" > "$lckf"
190 ############################
193 if [ -z "$lock_root" ]; then
196 if [ "$locknesting" != "0" ]; then
197 locknesting=`expr $locknesting - 1`
198 echo "lock nesting now $locknesting"
205 ############################
206 # run make, and print trace
215 # some trees don't need as much time
217 rsync | tdb | talloc | libreplace | ccache)
218 if [ "$compiler" != "checker" ]; then
219 MMTIME=`expr $MMTIME / 5`
226 if [ x"$BUILD_FARM_NUM_JOBS" = x ]; then
228 ./timelimit $MMTIME "$MAKE" "$t"
231 # we can parallelize everything and all targets
232 if [ x"$t" = xeverything ] || [ x"$t" = xall]; then
233 echo "$MAKE" "-j$BUILD_FARM_NUM_JOBS" "$t"
234 ./timelimit $MMTIME "$MAKE" "-j$BUILD_FARM_NUM_JOBS" "$t"
238 ./timelimit $MMTIME "$MAKE" "$t"
243 if [ $status != 0 ]; then
252 ############################
255 if [ ! -x $srcdir/configure ]; then
256 ls -l $srcdir/configure
257 echo "$srcdir/configure is missing"
259 echo "CONFIGURE STATUS: $cstatus"
262 echo "CFLAGS=$CFLAGS"
263 echo configure options: $config_and_prefix
264 echo CC="$CCACHE $compiler" $srcdir/configure $config_and_prefix
265 CC="$CCACHE $compiler"
267 ./timelimit $MAXTIME $srcdir/configure $config_and_prefix
269 if [ x"$cstatus" != x"0" ]; then
270 if [ -f config.log ]; then
271 echo "contents of config.log:"
274 if [ -f bin/config.log ]; then
275 echo "contents of config.log:"
279 echo "CONFIGURE STATUS: $cstatus"
283 ############################
284 # show the configure log
285 action_config_log() {
286 log_files="config.log bin/config.log"
287 for f in $log_files; do
289 echo "contents of config.log:"
297 ############################
299 action_config_header() {
300 hdr_files="config.h include/config.h bin/default/source4/include/config.h bin/default/source3/include/config.h"
301 for h in $hdr_files; do
303 echo "contents of $h:"
314 rsync -a --delete $Tsrc/ $Tdst
317 s4selftest_create() {
318 lock_file "s4selftest.lck" || {
322 # we currently only need smbtorture
323 mkdir -p $s4selftest/source/bin
324 rsync -aL $builddir/bin/smbtorture.static $s4selftest/source/bin/smbtorture || {
326 unlock_file "s4selftest.lck";
330 unlock_file "s4selftest.lck"
333 copy_dir $builddir/bin $s4selftest/source/bin || {
335 unlock_file "s4selftest.lck";
339 copy_dir $srcdir/setup $s4selftest/source/setup || {
341 unlock_file "s4selftest.lck";
345 copy_dir $srcdir/../testprogs $s4selftest/testprogs || {
347 unlock_file "s4selftest.lck";
351 copy_dir $srcdir/selftest $s4selftest/source/selftest || {
353 unlock_file "s4selftest.lck";
357 copy_dir $srcdir/script $s4selftest/source/script || {
359 unlock_file "s4selftest.lck";
363 mkdir -p $s4selftest/source/scripting || {
365 unlock_file "s4selftest.lck";
369 unlock_file "s4selftest.lck"
372 s4selftest_update() {
373 lock_file "s4selftest.lck" || {
377 echo tmp.$tree.$compiler.$$ >tmp.dirname
378 tempdir=`cut -b1-32 tmp.dirname`
381 copy_dir $s4selftest $tempdir || {
383 unlock_file "s4selftest.lck";
387 rm -rf $s4selftest.$tree.$compiler
388 mv $tempdir $s4selftest.$tree.$compiler
390 unlock_file "s4selftest.lck"
393 ############################
400 if test x"$bstatus" != x"0"; then
401 # the 2nd 'make everything' is to work around a bug
407 if test x"$bstatus" != x"0"; then
412 if test x"$bstatus" = x"0"; then
418 do_make everything torture
427 echo "BUILD STATUS: $bstatus"
432 ############################
433 # show static analysis results
434 action_cc_checker() {
436 # default to passing the cc_checker
439 if [ -f ibm_checker.out ]; then
441 cccstatus=`cat ibm_checker.out | grep '^\-\- ' | wc -l`
444 echo "CC_CHECKER STATUS: $cccstatus"
448 ############################
451 if [ -d $prefix ]; then
452 if [ "$noclean" != "yes" ]; then
459 echo "INSTALL STATUS: $istatus"
463 ############################
465 action_test_samba() {
468 # if we produced a test summary then show it
469 [ -f st/summary ] && {
473 return "$totalstatus"
476 action_test_generic() {
481 echo "TEST STATUS: $totalstatus"
482 return "$totalstatus"
485 action_test_lorikeet_heimdal() {
488 SOCKET_WRAPPER_DIR=`pwd`/sw
489 mkdir $SOCKET_WRAPPER_DIR
490 export SOCKET_WRAPPER_DIR
494 export SOCKET_WRAPPER_DIR
495 echo "TEST STATUS: $totalstatus"
496 return "$totalstatus"
500 #############################
501 # attempt some basic tests of functionaility
502 # starting as basic as possible, and getting incresingly complex
505 # Samba needs crufty code of its own for backward
506 # compatiblity. I think a better way to do this in the future
507 # is to just call 'make installcheck'.
509 samba*|smb-build|pidl)
513 action_test_lorikeet_heimdal
521 ###########################
522 # do a test build of a particular tree
530 if [ "$compiler" = "gcc" ] && [ "$tree" != "ccache" ] && ccache -V > /dev/null; then
537 # limit our resource usage
538 ulimit -t $MAXTIME 2> /dev/null
541 ulimit -m $MAXMEM 2> /dev/null
544 # darn, this affects sparse files too! disable it
545 # ulimit -f 100000 2> /dev/null
547 # try and limit the number of open files to 250. That means we'll discover
549 ulimit -n 250 2> /dev/null
554 if [ -z "$test_root" ]; then
558 log="build.$tree.$host.$compiler.log"
559 err="build.$tree.$host.$compiler.err"
560 sum="build.$tree.$host.$compiler.sum"
561 lck="build.$tree.lck"
562 srcdir="$test_root/$tree/$source"
564 lock_file "$lck" || {
568 # work out what other trees this package depends on
572 deptrees="libreplace";
575 deptrees="samba_4_0_test"
579 scm=`choose_scm "$tree"`
581 # pull the entries, if any
582 if fetch_revinfo "$tree" "$scm"; then
583 for d in $deptrees; do
584 dscm=`choose_scm "$d"`
585 if [ -f "$test_root/$d.$dscm" ]; then
586 if [ "$d" != "$tree" ]; then
587 cat "$test_root/$d.$dscm" >> $test_root/$tree.$scm
591 rm -f $test_root/$tree.$compiler.$scm.old
592 mv $test_root/$tree.$compiler.$scm $test_root/$tree.$compiler.$scm.old
593 cp $test_root/$tree.$scm $test_root/$tree.$compiler.$scm
594 if cmp $test_root/$tree.$compiler.$scm $test_root/$tree.$compiler.$scm.old > /dev/null; then
595 echo "skip: $tree.$compiler nothing changed in $scm"
597 send_logs_skip "$log" "$err"
604 fetch_tree "$tree" || {
610 if [ ! -x $srcdir/configure ] && [ "$tree" != "pidl" ]; then
611 echo "skip: $tree.$compiler configure not present, try again next time!"
617 echo "Starting build of $tree.$compiler in process $$ at `date`"
621 builddir="$test_root/tmp.$tree.$compiler"
623 if [ -d $builddir ]; then
636 if [ ! x$USER = x"" ]; then
639 if [ ! x$LOGNAME = x"" ]; then
646 prefix="$test_root/prefix/$tree.$compiler"
649 s4selftest=$test_root/s4selftest
656 sw_config="$config --enable-socket-wrapper"
659 sw_config="$config --enable-socket-wrapper"
660 sw_config="$sw_config --enable-nss-wrapper"
661 sw_config="$sw_config --enable-uid-wrapper"
664 sw_config="$config --enable-socket-wrapper"
665 sw_config="$sw_config --enable-nss-wrapper"
666 s4selftest_update "$tree" "$compiler" && {
667 t="$s4selftest.$tree.$compiler/source"
668 #sw_config="$sw_config --with-samba4srcdir=$t"
669 t="$t/bin/smbtorture"
670 sw_config="$sw_config --with-smbtorture4-path=$t"
674 PKG_CONFIG_PATH="$test_root/prefix/samba_4_0_test.$compiler/lib/pkgconfig"
675 export PKG_CONFIG_PATH
678 fetch_tree libreplace
685 if [ "$LCOV_REPORT" = "yes" ]; then
686 GCOV_FLAGS="--coverage"
687 CFLAGS="$CFLAGS $GCOV_FLAGS"
688 LDFLAGS="$LDFLAGS $GCOV_FLAGS"
689 export CFLAGS LDFLAGS
692 config_and_prefix="$sw_config --prefix=$prefix"
694 # see if we need to rebuild
695 sum_tree $test_root $tree $sum $scm
696 echo "CFLAGS=$CFLAGS $config_and_prefix" >> $sum
698 if cmp "$sum" "$sum.old" > /dev/null; then
699 echo "skip: $tree.$compiler nothing changed"
701 send_logs_skip "$log" "$err"
703 echo "Ending build of $tree.$compiler in process $$ at `date`"
707 # we do need to rebuild - save the old sum
713 if [ "$actions" = "" ]; then
714 actions="configure config_log config_header build install test"
720 # we all want to be able to read the output...
727 echo "build_test : $build_test_id"
728 echo "build_test.fns : $build_test_fns_id"
729 echo "local settings file : $build_test_settings_local_file"
730 echo "local functions file: $build_test_fns_local_file"
731 echo "used .fns file : $build_test_used_fns_file"
734 # we need to be able to see if a build farm machine is accumulating
735 # stuck processes. We do this in two ways, as we don't know what style
738 ps -fu $USER 2> /dev/null
740 echo "building $tree with CC=$compiler on $host at "`date`
741 echo "builddir=$builddir"
742 echo "prefix=$prefix"
744 echo "Showing limits"
745 ulimit -a 2> /dev/null
747 # build the timelimit utility
748 echo "Building timelimit"
750 $compiler $TIMELIMIT_FLAGS -o $builddir/timelimit $test_root/timelimit.c || exit 1
752 # the following is for non-samba builds only
753 if [ "$scm" = "svn" -a -r $test_root/$tree.svn ]; then
754 h_rev=`grep 'Revision: ' $test_root/$tree.svn | cut -d ':' -f2 | cut -d ' ' -f2 | sed 1q`
755 if [ -n "$h_rev" ]; then
756 echo "HIGHEST SVN REVISION: $h_rev"
758 rev=`grep 'Last Changed Rev: ' $test_root/$tree.svn | cut -d ':' -f2 | cut -d ' ' -f2 | sed 1q`
759 if [ -n "$rev" ]; then
760 echo "BUILD REVISION: $rev"
762 elif [ "$scm" = "git" -a -r $test_root/$tree.git ]; then
763 csha1=`cat $test_root/$tree.git |head -3 | tail -1`
764 if [ -n "$csha1" ]; then
765 echo "BUILD COMMIT REVISION: $csha1"
767 cdate=`cat $test_root/$tree.git |head -4 | tail -1`
768 if [ -n "$cdate" ]; then
769 echo "BUILD COMMIT DATE: $cdate"
771 ctime=`cat $test_root/$tree.git |head -2 | tail -1`
772 if [ -n "$ctime" ]; then
773 echo "BUILD COMMIT TIME: $ctime"
777 if [ "$tree" = "pidl" ]
780 perl ./Makefile.PL "$prefix"
783 for action in $actions; do
785 echo Running action $action
789 cd $builddir || exit 1
800 if [ $action_status != 0 ]; then
801 echo "ACTION FAILED: $action";
803 echo "ACTION PASSED: $action";
806 if [ $action_status != 0 ]; then
812 if [ "$LCOV_REPORT" = "yes" ]; then
815 lcov --directory $builddir --capture --output-file $builddir/$tree.lcov.info
818 lcov --base-directory $builddir --directory $builddir/.. --capture --output-file $builddir/$tree.lcov.info
821 # ugly hack for s4, as lcov is otherwise not able to find
823 rm -f heimdal/lib/*/{lex,parse,sel-lex}.{gcda,gcno}
824 lcov --base-directory $builddir --directory $builddir/.. --capture --output-file $builddir/$tree.lcov.info
827 lcov --base-directory $builddir --directory $builddir --capture --output-file $builddir/$tree.lcov.info
830 genhtml -o $builddir/coverage $builddir/$tree.lcov.info
833 if [ "$noclean" = "yes" ]; then
834 echo cleanup skipped!
840 } 3>&2 2>&1 1>&3 | tee "$err"
842 # be aware the above channel swap may sometimes result in unordered
843 # stdout/stderr merge
845 if [ "$LCOV_REPORT" = "yes" ]; then
846 chmod u=rwX,g=rX,o=rX -R $builddir/coverage
847 rsync -rct -q --password-file=.password -z --timeout=200 \
848 $builddir/coverage/ $host@build.samba.org::lcov_data/$host/$tree/
854 if [ "$usingtmpbuild" = "1" ]; then
855 if [ "$noclean" = "yes" ]; then
856 echo builddir cleanup skipped!
858 /bin/rm -rf $builddir
861 # send the logs to the master site
862 send_logs "$log" "$err"
865 echo "Ending build of $tree.$compiler in process $$ at `date`"
869 #########################################################
870 # if you want to build only one project at a time
871 # add 'global_lock' after 'per_run_hook' and
872 # 'global_unlock' to the end of the file
874 lock_file "global.lck" || {
879 unlock_file "global.lck"
882 #########################################################
883 # enable this on a per host basis only when needed please
884 # (at least for the moment)
885 kill_old_processes() {
886 # this should work on systems with linux like ps
887 (ps uxfw | grep /build | grep -v grep | egrep 'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec' | awk '{print $2}' | xargs kill -9) 2> /dev/null
888 # and this should work on sysv style ps
889 (ps -fu $USER | grep /build | grep -v grep | egrep 'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec' | awk '{print $2}' | xargs kill -9) 2> /dev/null
895 test -z "$otree" && return 0;
902 rm -rf s4selftest.$otree.*
903 rm -rf build.$otree.*
906 # this is a special fn that allows us to add a "special" hook to the build
907 # farm that we want to do to the build farm. never leave it empty. instead,
908 # use ":" as the fn body.
910 # kill old processes on systems with a known problem
913 echo "just a placeholder";
922 # trim the log if too large
923 if [ "`wc -c < build.log`" -gt 2000000 ]; then
927 delete_old_tree "samba_3_2"
928 delete_old_tree "samba_3_2_test"
929 delete_old_tree "samba4"
930 delete_old_tree "samba_3_X_test"
931 delete_old_tree "samba_3_X_devel"
935 ######################################################
936 # main code that is run on each call to the build code
937 rsync --timeout=200 -q -az build.samba.org::build_farm/*.c .
940 # build.log can grow to an excessive size, trim it beyond 50M
941 if [ -f build.log ]; then
942 find build.log -size +100000 -exec /bin/rm '{}' \;