1 #!/bin/sh -*- mode: shell-script; -*-
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
10 MAXTIME=25200 # 7 hours
11 SMBD_MAXTIME=18000 # 5 hours for a samba process ..
12 # default maximum memory size (100M) for any command
14 RUN_FROM_BUILD_FARM=yes
15 export RUN_FROM_BUILD_FARM
19 build_test_fns_id='$Id$'
25 echo rsync -a --delete $Tsrc/ $Tdst
26 rsync -a --delete $Tsrc/ $Tdst || return 1
30 #############################
31 # build a signature of a tree, used to see if we
33 #############################
40 find $sum_tree_test_root/$sum_tree_tree -type f -print | grep -v version.h | sort | xargs sum > $sum_tree_sum
41 sum build_test build_test.fns >> $sum_tree_sum
43 if [ -f "$host.fns" ]; then
44 sum $host.fns >> $sum_tree_sum
46 sum generic.fns >> $sum_tree_sum
49 if [ -f "$test_root/$tree.$scm" ]; then
50 sum "$test_root/$tree.$scm" >> $sum_tree_sum
53 for d in $deptrees; do
54 dscm=`choose_scm "$d"`
55 if [ -f "$test_root/$d.$dscm" ]; then
56 sum "$test_root/$d.$dscm" >> $sum_tree_sum
61 #############################
62 # send the logs to the master site
63 #############################
66 if [ "$nologreturn" = "yes" ]; then
67 echo "skipping log transfer"
73 chmod 0644 "$log" "$err"
75 # xargs -i is implemented differently or not at all.
76 # GNU xargs did not implement "-I" until 4.2.9:
77 xargs --version 2>&1 | grep "^GNU xargs" > /dev/null
79 if [ x"$status" = x"0" ]; then
83 if [ x"$XARGS_IS_GNU" = x"yes" ]; then
86 XARGS_I="xargs -I '{}'"
89 find $log -size +40000 | $XARGS_I sh -c 'dd if={} bs=1024 count=20000 of={}.tmp && mv {}.tmp {} && echo "\n***LOG TRUNCATED***" >> {}'
90 find $err -size +40000 | $XARGS_I sh -c 'dd if={} bs=1024 count=20000 of={}.tmp && mv {}.tmp {} && echo "\n***LOG TRUNCATED***" >> {}'
92 rsync $* -c -q --password-file=.password -z --timeout=200 \
93 "$log" "$err" $host@build.samba.org::build_farm_data/
97 #############################
98 # send the logs when they haven't changed
99 # the aim is to just update the servers timestamp.
100 # sending with a very large rsync block size does this
101 # with minimal network traffic
102 #############################
106 send_logs "$1" "$2" -B 10000000
109 ############################
110 # fetch the latest copy of the tree
111 ############################
114 if [ "$norsync" = "yes" ]; then
115 echo "skipping tree transfer"
118 if rsync --exclude=autom4te.cache/ --exclude=.svn/ --exclude=.git/ \
119 --delete-excluded -q --partial --timeout=200 -ctrlpz --delete --ignore-errors \
120 samba.org::ftp/unpacked/$fetchtree/ $test_root/$fetchtree; then
121 echo "transferred $fetchtree OK"
123 echo "transfer of $fetchtree failed code $?"
130 ############################
131 # fetch the latest copy of the rev meta info
132 ############################
138 test -z "$scm" && return 1
139 test x"$scm" = x"unknown" && return 1
140 test x"$scm" = x"cvs" && return 1
142 if [ "$norsync" = "yes" ]; then
143 echo "skipping .revinfo.$scm transfer"
145 if [ -r $test_root/$tree.$scm ]; then
146 [ -f $test_root/$tree.$scm.old ] && rm -f $test_root/$tree.$scm.old
147 [ -f $test_root/$tree.$scm ] && mv $test_root/$tree.$scm $test_root/$tree.$scm.old
149 rsync -q --timeout=200 -clz --ignore-errors \
150 samba.org::ftp/unpacked/$tree/.revinfo.$scm $test_root/$tree.$scm
152 if [ -r $test_root/$tree.$scm ]; then
158 ############################
159 # choose the scm that is used for the given project
160 ############################
166 samba* | rsync | libreplace | talloc | tdb | ldb | pidl | ccache*)
178 ############################
179 # grab a lock file. Not atomic, but close :)
180 # tries to cope with NFS
181 ############################
184 if [ -z "$lock_root" ]; then
189 machine=`cat "$lckf" 2> /dev/null | cut -d: -f1`
190 pid=`cat "$lckf" 2> /dev/null | cut -d: -f2`
192 if [ "$pid" = "$$" ]; then
193 locknesting=`expr $locknesting + 1`
194 echo "lock nesting now $locknesting"
198 if test -f "$lckf"; then
199 test $machine = $host || {
200 echo "lock file $lckf is valid for other machine $machine"
205 echo "lock file $lckf is valid for process $pid"
209 echo "stale lock file $lckf for $machine:$pid"
213 echo "$host:$$" > "$lckf"
217 ############################
219 ############################
222 if [ -z "$lock_root" ]; then
225 if [ "$locknesting" != "0" ]; then
226 locknesting=`expr $locknesting - 1`
227 echo "lock nesting now $locknesting"
234 ############################
235 # run make, and print trace
236 ############################
239 if [ x"$MAKE" = x ]; then
244 # some trees don't need as much time
246 rsync | tdb | talloc | libreplace | ccache*)
247 if [ "$compiler" != "checker" ]; then
248 MMTIME=`expr $MMTIME / 5`
255 if [ x"$BUILD_FARM_NUM_JOBS" = x ]; then
257 $builddir/timelimit $MMTIME "$MAKE" "$t"
260 # we can parallelize everything and all targets
261 if [ x"$t" = xeverything ] || [ x"$t" = xall]; then
262 echo "$MAKE" "-j$BUILD_FARM_NUM_JOBS" "$t"
263 $builddir/timelimit $MMTIME "$MAKE" "-j$BUILD_FARM_NUM_JOBS" "$t"
267 $builddir/timelimit $MMTIME "$MAKE" "$t"
272 if [ $status != 0 ]; then
274 test|check|installcheck)
277 #run again with V=1, so we see failed commands
278 $builddir/timelimit $MMTIME "$MAKE" "$t" V=1
284 if [ $status != 0 ]; then
294 ############################
295 # do the coverage report
296 ############################
298 action_lcovreport() {
299 if [ "$LCOV_REPORT" = "yes" ]; then
302 lcov --directory $builddir --capture --output-file $builddir/$tree.lcov.info
305 lcov --base-directory $builddir --directory $builddir/.. --capture --output-file $builddir/$tree.lcov.info
308 # rm -f heimdal/lib/*/{lex,parse,sel-lex}.{gcda,gcno}
309 lcov --base-directory $builddir --directory $builddir/.. --capture --output-file $builddir/$tree.lcov.info
312 lcov --base-directory $builddir --directory $builddir --capture --output-file $builddir/$tree.lcov.info
315 genhtml -o $builddir/coverage $builddir/$tree.lcov.info
317 echo "return code: $rc"
319 echo "LCOV_REPORT not set and lcovreport asked"
320 echo "Most probably an error please fix !"
326 ############################
328 ############################
332 if [ ! -x $srcdir/configure -a -r $srcdir/Makefile.PL ]; then
333 perl $srcdir/Makefile.PL PREFIX="$prefix"
335 echo "CONFIGURE STATUS: $cstatus"
339 if [ ! -x $srcdir/configure ]; then
340 ls -l $srcdir/configure
341 echo "$srcdir/configure is missing"
343 echo "CONFIGURE STATUS: $cstatus"
347 echo "CFLAGS=$CFLAGS"
348 echo configure options: $config_and_prefix
349 echo CC="$CCACHE $compiler" $srcdir/configure $config_and_prefix
351 CC="$CCACHE $compiler"
353 $builddir/timelimit $MAXTIME $srcdir/configure $config_and_prefix
356 if [ x"$cstatus" != x"0" ]; then
357 if [ -f config.log ]; then
358 echo "contents of config.log:"
363 if [ -f bin/config.log ]; then
364 echo "contents of config.log:"
368 echo "CONFIGURE STATUS: $cstatus"
372 ############################
373 # show the configure log
374 ############################
376 action_config_log() {
378 log_files="config.log bin/config.log"
379 for f in $log_files; do
381 echo "contents of config.log:"
389 ############################
391 ############################
393 action_config_header() {
394 hdr_files="config.h include/config.h bin/default/config.h bin/default/source4/include/config.h bin/default/source3/include/config.h"
395 for h in $hdr_files; do
397 echo "contents of $h:"
408 ############################
410 ############################
418 do_make everything torture
427 echo "BUILD STATUS: $bstatus"
432 ############################
433 # show static analysis results
434 ############################
436 action_cc_checker() {
438 # default to passing the cc_checker
441 if [ -f ibm_checker.out ]; then
443 cccstatus=`cat ibm_checker.out | grep '^\-\- ' | wc -l`
446 echo "CC_CHECKER STATUS: $cccstatus"
450 ############################
452 ############################
455 if [ -d $prefix ]; then
456 if [ "$noclean" != "yes" ]; then
463 echo "INSTALL STATUS: $istatus"
467 ############################
469 action_test_samba() {
473 # if we produced a test summary then show it
474 [ -f st/summary ] && {
479 return "$totalstatus"
482 action_test_generic() {
487 echo "TEST STATUS: $totalstatus"
488 return "$totalstatus"
491 action_test_lorikeet_heimdal() {
494 SOCKET_WRAPPER_DIR=`pwd`/sw
495 mkdir $SOCKET_WRAPPER_DIR
496 export SOCKET_WRAPPER_DIR
500 export SOCKET_WRAPPER_DIR
501 echo "TEST STATUS: $totalstatus"
502 return "$totalstatus"
506 #############################
507 # attempt some basic tests of functionaility
508 # starting as basic as possible, and getting incresingly complex
509 #############################
512 # Samba needs crufty code of its own for backward
513 # compatiblity. I think a better way to do this in the future
514 # is to just call 'make installcheck'.
516 samba*|smb-build|pidl)
520 action_test_lorikeet_heimdal
528 ###########################
529 # do a test build of a particular tree
530 # This is the master function called by generic.fns or
532 ###########################
541 echo "Starting to deal with tree $tree with compiler $compiler"
542 if [ "$compiler" = "gcc" ] && [ "$tree" != "ccache" ] && [ "$tree" != "ccache-maint" ] && ccache -V > /dev/null 2>/dev/null; then
549 # limit our resource usage
550 ulimit -t $MAXTIME 2> /dev/null
553 ulimit -m $MAXMEM 2> /dev/null
556 # darn, this affects sparse files too! disable it
557 # ulimit -f 100000 2> /dev/null
559 # try and limit the number of open files to 250. That means we'll discover
561 ulimit -n 250 2> /dev/null
566 if [ -z "$test_root" ]; then
570 log="build.$tree.$host.$compiler.log"
571 err="build.$tree.$host.$compiler.err"
572 sum="build.$tree.$host.$compiler.sum"
573 lck="build.$tree.lck"
574 srcdir="$test_root/$tree/$source"
576 lock_file "$lck" || {
580 # work out what other trees this package depends on
584 deptrees="samba_4_0_test"
588 scm=`choose_scm "$tree"`
590 # pull the entries, if any
591 # Remove old .svn or .git files
592 # Move the current .svn org .git to .svn.old or
593 # .git.old then fetch the new from rsync
594 if fetch_revinfo "$tree" "$scm"; then
595 for d in $deptrees; do
596 # If there is dependency substree(s) we add info
597 # from the dependency tree so that we
598 # can rebuild in case one of them has changed
599 dscm=`choose_scm "$d"`
600 if [ -f "$test_root/$d.$dscm" ]; then
601 if [ "$d" != "$tree" ]; then
602 cat "$test_root/$d.$dscm" >> $test_root/$tree.$scm
606 [ -f $test_root/$tree.$compiler.$scm.old ] && rm -f $test_root/$tree.$compiler.$scm.old
607 [ -f $test_root/$tree.$compiler.$scm ] && mv $test_root/$tree.$compiler.$scm $test_root/$tree.$compiler.$scm.old
608 [ -f $test_root/$tree.$scm ] && cp $test_root/$tree.$scm $test_root/$tree.$compiler.$scm
610 if [ -f $test_root/$tree.$compiler.$scm.old ] && \
611 cmp $test_root/$tree.$compiler.$scm $test_root/$tree.$compiler.$scm.old > /dev/null; then
613 echo "skip: $tree.$compiler nothing changed in $scm"
615 send_logs_skip "$log" "$err"
622 fetch_tree "$tree" || {
628 if [ ! -x $srcdir/configure ] && [ "$tree" != "pidl" ]; then
629 echo "skip: $tree.$compiler configure not present, try again next time!"
635 echo "Starting build of $tree.$compiler in process $$ at `date`"
638 # Parameters for the build depending on the tree
641 builddir="$test_root/tmp.$tree.$compiler"
643 if [ -d $builddir ]; then
657 if [ ! x$USER = x"" ]; then
660 if [ ! x$LOGNAME = x"" ]; then
667 # build the timelimit utility
668 echo "Building timelimit"
670 echo $compiler $TIMELIMIT_FLAGS -o $builddir/timelimit $test_root/timelimit.c
671 $compiler $TIMELIMIT_FLAGS -o $builddir/timelimit $test_root/timelimit.c || exit 1
673 # build the killbysubdir utility
674 echo "Building killbysubdir"
675 echo $compiler -o $builddir/killbysubdir $test_root/killbysubdir.c
676 $compiler -o $builddir/killbysubdir $test_root/killbysubdir.c
678 prefix="$test_root/prefix/$tree.$compiler"
681 # This can be defined in <host>.fns files
686 sw_config="$config --enable-socket-wrapper"
689 sw_config="$config --enable-socket-wrapper"
690 sw_config="$sw_config --enable-nss-wrapper"
691 sw_config="$sw_config --enable-uid-wrapper"
694 sw_config="$config --enable-socket-wrapper"
695 sw_config="$sw_config --enable-nss-wrapper"
698 PKG_CONFIG_PATH="$test_root/prefix/samba_4_0_test.$compiler/lib/pkgconfig"
699 export PKG_CONFIG_PATH
706 if [ "$LCOV_REPORT" = "yes" ]; then
707 GCOV_FLAGS="--coverage"
708 CFLAGS="$CFLAGS $GCOV_FLAGS"
709 LDFLAGS="$LDFLAGS $GCOV_FLAGS"
710 export CFLAGS LDFLAGS
713 config_and_prefix="$sw_config --prefix=$prefix"
715 # see if we need to rebuild
716 sum_tree $test_root $tree $sum $scm
717 echo "CFLAGS=$CFLAGS $config_and_prefix" >> $sum
719 if [ -f "$sum.old" ] && cmp "$sum" "$sum.old" > /dev/null; then
720 echo "skip: $tree.$compiler nothing changed"
722 send_logs_skip "$log" "$err"
724 echo "Ending build of $tree.$compiler in process $$ at `date`"
728 # we do need to rebuild - save the old sum
729 [ -f $sum.old ] && /bin/rm -f $sum.old
732 #Action == what to do ie. configure config_log ...
735 if [ "$actions" = "" ]; then
736 actions="configure config_log config_header build install test"
742 # we all want to be able to read the output...
749 echo "build_test : $build_test_id"
750 echo "build_test.fns : $build_test_fns_id"
751 echo "local settings file : $build_test_settings_local_file"
752 echo "local functions file: $build_test_fns_local_file"
753 echo "used .fns file : $build_test_used_fns_file"
756 # we need to be able to see if a build farm machine is accumulating
757 # stuck processes. We do this in two ways, as we don't know what style
760 ps -fu $USER 2> /dev/null
762 echo "building $tree with CC=$compiler on $host at "`date`
763 echo "builddir=$builddir"
764 echo "prefix=$prefix"
766 echo "Showing limits"
767 ulimit -a 2> /dev/null
769 # the following is for non-samba builds only
770 if [ "$scm" = "svn" -a -r $test_root/$tree.svn ]; then
771 h_rev=`grep 'Revision: ' $test_root/$tree.svn | cut -d ':' -f2 | cut -d ' ' -f2 | sed 1q`
772 if [ -n "$h_rev" ]; then
773 echo "HIGHEST SVN REVISION: $h_rev"
775 rev=`grep 'Last Changed Rev: ' $test_root/$tree.svn | cut -d ':' -f2 | cut -d ' ' -f2 | sed 1q`
776 if [ -n "$rev" ]; then
777 echo "BUILD REVISION: $rev"
779 elif [ "$scm" = "git" -a -r $test_root/$tree.git ]; then
780 csha1=`cat $test_root/$tree.git |head -3 | tail -1`
781 if [ -n "$csha1" ]; then
782 echo "BUILD COMMIT REVISION: $csha1"
784 cdate=`cat $test_root/$tree.git |head -4 | tail -1`
785 if [ -n "$cdate" ]; then
786 echo "BUILD COMMIT DATE: $cdate"
788 ctime=`cat $test_root/$tree.git |head -2 | tail -1`
789 if [ -n "$ctime" ]; then
790 echo "BUILD COMMIT TIME: $ctime"
794 if [ -x $builddir/killbysubdir ]; then
795 echo "$builddir/killbysubdir $builddir in `pwd`"
796 $builddir/killbysubdir $builddir
799 for action in $actions; do
801 echo Running action $action
805 cd $builddir || exit 1
811 if [ "x$PREHOOKS" != "x" ]; then
812 for hooks in $PREHOOKS; do
813 if [ "x$hooks" = "x$action" ]; then
822 if [ "x$POSTHOOKS" != "x" ]; then
823 for hooks in $POSTHOOKS; do
824 if [ "x$hooks" = "x$action" ]; then
832 if [ $action_status != 0 ]; then
833 echo "ACTION FAILED: $action";
834 echo " return code $action_status $action";
836 echo "ACTION PASSED: $action";
839 if [ $action_status != 0 ]; then
845 if [ "$noclean" = "yes" ]; then
846 echo cleanup skipped!
852 } 3>&2 2>&1 1>&3 | tee "$err"
854 # be aware the above channel swap may sometimes result in unordered
855 # stdout/stderr merge
857 if [ "$LCOV_REPORT" = "yes" ]; then
858 chmod u=rwX,g=rX,o=rX -R $builddir/coverage
859 rsync -rct -q --password-file=.password -z --timeout=200 \
860 $builddir/coverage/ $host@build.samba.org::lcov_data/$host/$tree/
866 if [ "$usingtmpbuild" = "1" ]; then
867 if [ "$noclean" = "yes" ]; then
868 echo builddir cleanup skipped!
870 /bin/rm -rf $builddir
873 # send the logs to the master site
874 send_logs "$log" "$err"
877 echo "Ending build of $tree.$compiler in process $$ at `date`"
881 #########################################################
882 # if you want to build only one project at a time
883 # add 'global_lock' after 'per_run_hook' and
884 # 'global_unlock' to the end of the file
885 #########################################################
888 lock_file "global.lck" || {
894 unlock_file "global.lck"
899 test -z "$otree" && return 0;
906 rm -rf build.$otree.*
909 # this is a special fn that allows us to add a "special" hook to the build
910 # farm that we want to do to the build farm. never leave it empty. instead,
911 # use ":" as the fn body.
913 # kill old processes on systems with a known problem
916 echo "just a placeholder";
923 # trim the log if too large
924 if [ "`wc -c < build.log`" -gt 2000000 ]; then
928 old_trees="web popt distcc samba-gtk smb-build lorikeet-heimdal samba_3_2"
929 old_trees="$old_tree samba_3_2_test samba4 samba_4_0_waf samba_4_0_waf.metze"
930 old_trees="$old_tree samba_3_X_test samba_3_X_devel samba_3_X_devel"
931 for d in $old_trees; do
937 ######################################################
938 # main code that is run on each call to the build code
939 ######################################################
940 rsync --timeout=200 -q -az build.samba.org::build_farm/*.c .
943 # build.log can grow to an excessive size, trim it beyond 50M
944 if [ -f build.log ]; then
945 find build.log -size +100000 -exec /bin/rm '{}' \;