2 # run tests on all Samba subprojects and push to a git tree on success
3 # Copyright Andrew Tridgell 2010
4 # released under GNU GPL v3 or later
6 from subprocess
import call
, check_call
, check_output
, Popen
, PIPE
, CalledProcessError
12 from optparse
import OptionParser
15 from email
.mime
.text
import MIMEText
16 from email
.mime
.base
import MIMEBase
17 from email
.mime
.application
import MIMEApplication
18 from email
.mime
.multipart
import MIMEMultipart
19 from distutils
.sysconfig
import get_python_lib
23 from waflib
.Build
import CACHE_SUFFIX
25 sys
.path
.insert(0, "./third_party/waf")
26 from waflib
.Build
import CACHE_SUFFIX
29 os
.environ
["PYTHONUNBUFFERED"] = "1"
31 # This speeds up testing remarkably.
32 os
.environ
['TDB_NO_FSYNC'] = '1'
36 '''get to the top of the git repo'''
39 if os
.path
.exists(os
.path
.join(p
, ".git")):
41 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
45 gitroot
= find_git_root()
47 raise Exception("Failed to find git root")
50 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
52 parser
= OptionParser()
53 parser
.add_option("--tail", help="show output while running", default
=False, action
="store_true")
54 parser
.add_option("--keeplogs", help="keep logs", default
=False, action
="store_true")
55 parser
.add_option("--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
56 parser
.add_option("--skip-dependencies", help="skip to run task dependency tasks", default
=False, action
="store_true")
57 parser
.add_option("--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
59 parser
.add_option("--full-testbase", help="full base directory to run tests in (default %s/b$PID)" % def_testbase
,
61 parser
.add_option("--passcmd", help="command to run on success", default
=None)
62 parser
.add_option("--verbose", help="show all commands as they are run",
63 default
=False, action
="store_true")
64 parser
.add_option("--rebase", help="rebase on the given tree before testing",
65 default
=None, type='str')
66 parser
.add_option("--pushto", help="push to a git url on success",
67 default
=None, type='str')
68 parser
.add_option("--mark", help="add a Tested-By signoff before pushing",
69 default
=False, action
="store_true")
70 parser
.add_option("--fix-whitespace", help="fix whitespace on rebase",
71 default
=False, action
="store_true")
72 parser
.add_option("--retry", help="automatically retry if master changes",
73 default
=False, action
="store_true")
74 parser
.add_option("--email", help="send email to the given address on failure",
75 type='str', default
=None)
76 parser
.add_option("--email-from", help="send email from the given address",
77 type='str', default
="autobuild@samba.org")
78 parser
.add_option("--email-server", help="send email via the given server",
79 type='str', default
='localhost')
80 parser
.add_option("--always-email", help="always send email, even on success",
82 parser
.add_option("--daemon", help="daemonize after initial setup",
84 parser
.add_option("--branch", help="the branch to work on (default=master)",
85 default
="master", type='str')
86 parser
.add_option("--log-base", help="location where the logs can be found (default=cwd)",
87 default
=gitroot
, type='str')
88 parser
.add_option("--attach-logs", help="Attach logs to mails sent on success/failure?",
89 default
=False, action
="store_true")
90 parser
.add_option("--restrict-tests", help="run as make test with this TESTS= regex",
92 parser
.add_option("--enable-coverage", dest
='enable_coverage',
93 action
="store_const", const
='--enable-coverage', default
='',
94 help="Add --enable-coverage option while configure")
96 (options
, args
) = parser
.parse_args()
99 if options
.rebase
is None:
100 raise Exception('You can only use --retry if you also rebase')
102 if options
.full_testbase
is not None:
103 testbase
= options
.full_testbase
105 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
106 test_master
= "%s/master" % testbase
107 test_prefix
= "%s/prefix" % testbase
108 test_tmpdir
= "%s/tmp" % testbase
109 os
.environ
['TMPDIR'] = test_tmpdir
111 if options
.enable_coverage
:
112 LCOV_CMD
= "cd ${TEST_SOURCE_DIR} && lcov --capture --directory . --output-file ${LOG_BASE}/${NAME}.info --rc 'geninfo_adjust_src_path=${TEST_SOURCE_DIR}/'"
114 LCOV_CMD
= 'echo "lcov skipped since no --enable-coverage specified"'
116 if options
.enable_coverage
:
117 PUBLISH_DOCS
= "mkdir -p ${LOG_BASE}/public && mv output/htmldocs ${LOG_BASE}/public/htmldocs"
119 PUBLISH_DOCS
= 'echo "HTML documentation publishing skipped since no --enable-coverage specified"'
121 CLEAN_SOURCE_TREE_CMD
= "cd ${TEST_SOURCE_DIR} && script/clean-source-tree.sh"
124 # If we are only running specific test,
125 # do not sleep randomly to wait for it to start
126 def random_sleep(low
, high
):
129 def random_sleep(low
, high
):
130 return 'sleep {}'.format(random
.randint(low
, high
))
138 "talloc": "lib/talloc",
139 "replace": "lib/replace",
140 "tevent": "lib/tevent",
142 "docs-xml": "docs-xml"
145 ctdb_configure_params
= " --enable-developer ${PREFIX}"
146 samba_configure_params
= " ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data"
148 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH"
149 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
150 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
151 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check ${ENABLE_COVERAGE} --enable-debug -C ${PREFIX}"
152 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=cmocka,popt,NONE"
153 samba_libs_configure_bundled_libs
= " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent,!popt"
154 samba_libs_configure_samba
= samba_libs_configure_base
+ samba_libs_configure_bundled_libs
157 def format_option(name
, value
=None):
158 """Format option as str list."""
159 if value
is None: # boolean option
161 if not isinstance(value
, list): # single value option
164 return ['{}={}'.format(name
, item
) for item
in value
]
170 INJECT_SELFTEST_PREFIX
=1,
177 test_options
= format_option('--include-env', include_envs
)
179 test_options
= format_option('--exclude-env', exclude_envs
)
181 # join envs options to original test options
182 TESTS
= (TESTS
+ ' ' + ' '.join(test_options
)).strip()
186 _options
.append('FAIL_IMMEDIATELY=1')
188 _options
.append("TESTS='{}'".format(TESTS
))
190 if INJECT_SELFTEST_PREFIX
:
191 _options
.append("TEST_OPTIONS='--with-selftest-prefix={}'".format("${SELFTEST_PREFIX}"))
192 _options
.append("--directory='{}'".format("${TEST_SOURCE_DIR}"))
194 return ' '.join([cmd
] + _options
)
197 # When updating this list, also update .gitlab-ci.yml to add the job
198 # and to make it a dependency of 'page' for the coverage report.
203 ("random-sleep", random_sleep(300, 900)),
204 ("configure", "./configure " + ctdb_configure_params
),
205 ("make", "make all"),
206 ("install", "make install"),
207 ("test", "make autotest"),
208 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
209 ("clean", "make clean"),
214 ("random-sleep", random_sleep(300, 900)),
215 ("autoconf", "autoconf"),
216 ("configure", "./configure"),
217 ("make", "make html htmlman"),
218 ("publish-docs", PUBLISH_DOCS
),
219 ("clean", "make clean"),
224 "git-clone-required": True,
226 ("configure", "./configure.developer" + samba_configure_params
),
228 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
229 ("chmod-R-a-w", "chmod -R a-w ."),
234 "git-clone-required": True,
236 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
238 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
239 ("chmod-R-a-w", "chmod -R a-w ."),
244 "git-clone-required": True,
246 ("configure", "./configure.developer --without-ad-dc --without-ldap --without-ads --without-json" + samba_configure_params
),
248 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
249 ("chmod-R-a-w", "chmod -R a-w ."),
254 "git-clone-required": True,
256 ("configure", "./configure.developer --without-ad-dc --with-system-heimdalkrb5" + samba_configure_params
),
258 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
259 ("chmod-R-a-w", "chmod -R a-w ."),
263 "samba-no-opath-build": {
264 "git-clone-required": True,
266 ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1' ./configure.developer --without-ad-dc " + samba_configure_params
),
268 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
269 ("chmod-R-a-w", "chmod -R a-w ."),
273 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
276 ("random-sleep", random_sleep(300, 900)),
277 ("configure", "./configure.developer" + samba_configure_params
),
279 ("test", make_test(exclude_envs
=[
292 "ad_dc_default_smb1",
300 "ad_member_idmap_rid",
301 "ad_member_idmap_ad",
308 "fileserver_smb1_done",
322 "ad_dc_default_smb1",
323 "ad_dc_default_smb1_done",
329 ("test-slow-none", make_test(cmd
='make test', TESTS
="--include=selftest/slow-none", include_envs
=["none"])),
331 ("install", "make install"),
332 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
333 ("clean", "make clean"),
337 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
340 ("random-sleep", random_sleep(300, 900)),
341 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
343 ("test", make_test(exclude_envs
=[
356 "ad_dc_default_smb1",
357 "ad_dc_default_smb1_done",
365 "ad_member_idmap_rid",
366 "ad_member_idmap_ad",
373 "fileserver_smb1_done",
387 "ad_dc_default_smb1",
388 "ad_dc_default_smb1_done",
395 ("install", "make install"),
396 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
397 ("clean", "make clean"),
402 "dependency": "samba-nt4-build",
404 ("random-sleep", random_sleep(300, 900)),
405 ("test", make_test(include_envs
=[
414 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
418 "samba-fileserver": {
419 "dependency": "samba-h5l-build",
421 ("random-sleep", random_sleep(300, 900)),
422 ("test", make_test(include_envs
=[
425 "fileserver_smb1_done",
427 "ktest", # ktest is also tested in samba and samba-mitkrb5
428 # but is tested here against a system Heimdal
431 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
436 "dependency": "samba-def-build",
438 ("random-sleep", random_sleep(300, 900)),
439 ("test", make_test(include_envs
=[
441 "ad_member_idmap_rid",
442 "ad_member_idmap_ad",
444 "ad_member_offlogon",
447 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
452 "dependency": "samba-no-opath-build",
454 ("random-sleep", random_sleep(300, 900)),
456 cmd
="make testonly DISABLE_OPATH=1",
466 ("check-clean-tree", "script/clean-source-tree.sh"),
471 "dependency": "samba-no-opath-build",
473 ("random-sleep", random_sleep(300, 900)),
475 cmd
="make testonly DISABLE_OPATH=1",
479 "fileserver_smb1_done",
482 ("check-clean-tree", "script/clean-source-tree.sh"),
487 "dependency": "samba-def-build",
489 ("random-sleep", random_sleep(1, 1)),
490 ("test", make_test(include_envs
=[
498 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
503 "dependency": "samba-def-build",
505 ("random-sleep", random_sleep(1, 1)),
506 ("test", make_test(include_envs
=[
512 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
517 "dependency": "samba-def-build",
519 ("random-sleep", random_sleep(1, 1)),
520 ("test", make_test(include_envs
=[
527 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
532 "dependency": "samba-def-build",
534 ("random-sleep", random_sleep(1, 1)),
535 ("test", make_test(include_envs
=[
540 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
544 "dependency": "samba-def-build",
546 ("random-sleep", random_sleep(1, 1)),
547 ("test", make_test(include_envs
=[
552 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
557 "dependency": "samba-def-build",
559 ("random-sleep", random_sleep(1, 1)),
560 ("test", make_test(include_envs
=[
561 "ad_dc_default", "ad_dc_default_smb1", "ad_dc_default_smb1_done"])),
563 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
568 "dependency": "samba-def-build",
570 ("random-sleep", random_sleep(1, 1)),
571 ("test", make_test(include_envs
=["ad_dc_slowtests", "ad_dc_backup"])),
573 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
577 "samba-schemaupgrade": {
578 "dependency": "samba-def-build",
580 ("random-sleep", random_sleep(1, 1)),
581 ("test", make_test(include_envs
=["schema_dc", "schema_pair_dc"])),
583 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
587 # We split out the ad_dc_ntvfs tests (which are long) so other test do not wait
588 # This is currently the longest task, so we don't randomly delay it.
589 "samba-ad-dc-ntvfs": {
590 "dependency": "samba-def-build",
592 ("random-sleep", random_sleep(1, 1)),
593 ("test", make_test(include_envs
=["ad_dc_ntvfs"])),
595 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
599 # Test fips compliance
601 "dependency": "samba-mit-build",
603 ("random-sleep", random_sleep(1, 1)),
604 ("test", make_test(include_envs
=["ad_dc_fips", "ad_member_fips"])),
605 # TODO: This seems to generate only an empty samba-fips.info ("lcov", LCOV_CMD),
606 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
610 # run the backup/restore testenvs separately as they're fairly standalone
611 # (and CI seems to max out at ~3 different DCs running at once)
613 "dependency": "samba-def-build",
615 ("random-sleep", random_sleep(300, 900)),
616 ("test", make_test(include_envs
=[
622 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
626 "dependency": "samba-def-build",
628 ("random-sleep", random_sleep(300, 900)),
629 ("test", make_test(include_envs
=[
635 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
640 "dependency": "samba-mit-build",
642 ("random-sleep", random_sleep(1, 1)),
643 ("test", make_test(include_envs
=[
645 "ad_member_idmap_rid",
646 "ad_member_idmap_ad",
648 "ad_member_offlogon",
651 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
655 "samba-ad-dc-1-mitkrb5": {
656 "dependency": "samba-mit-build",
658 ("random-sleep", random_sleep(1, 1)),
659 ("test", make_test(include_envs
=[
667 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
671 "samba-ad-dc-4a-mitkrb5": {
672 "dependency": "samba-mit-build",
674 ("random-sleep", random_sleep(1, 1)),
675 ("test", make_test(include_envs
=[
680 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
683 "samba-ad-dc-4b-mitkrb5": {
684 "dependency": "samba-mit-build",
686 ("random-sleep", random_sleep(1, 1)),
687 ("test", make_test(include_envs
=[
692 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
698 ("configure", "./configure.developer --abi-check-disable" + samba_configure_params
),
700 ("test", make_test(TESTS
="${TESTS}")),
705 # Test cross-compile infrastructure
708 ("random-sleep", random_sleep(900, 1500)),
709 ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
710 ("configure-cross-execute", "./configure.developer --out ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
711 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
),
712 ("verify-cross-execute-output", "grep '^Checking value of NSIG' ./bin-xe/cross-answers.txt"),
713 ("configure-cross-answers", "./configure.developer --out ./bin-xa --cross-compile" \
714 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
),
715 ("compare-results", "script/compare_cc_results.py "
716 "./bin/c4che/default{} "
717 "./bin-xe/c4che/default{} "
718 "./bin-xa/c4che/default{}".format(*([CACHE_SUFFIX
]*3))),
719 ("modify-cross-answers", "sed -i.bak -e 's/^\\(Checking value of NSIG:\\) .*/\\1 \"1234\"/' ./bin-xe/cross-answers.txt"),
720 ("configure-cross-answers-modified", "./configure.developer --out ./bin-xa2 --cross-compile" \
721 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa2/ab" + samba_configure_params
),
722 ("verify-cross-answers", "test $(sed -n -e 's/VALUEOF_NSIG = \\(.*\\)/\\1/p' ./bin-xa2/c4che/default{})" \
723 " = \"'1234'\"".format(CACHE_SUFFIX
)),
724 ("invalidate-cross-answers", "sed -i.bak -e '/^Checking value of NSIG/d' ./bin-xe/cross-answers.txt"),
725 ("configure-cross-answers-fail", "./configure.developer --out ./bin-xa3 --cross-compile" \
726 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa3/ab" + samba_configure_params
+ \
731 # test build with -O3 -- catches extra warnings and bugs, tests the ad_dc environments
734 ("random-sleep", random_sleep(300, 900)),
735 ("configure", "ADDITIONAL_CFLAGS='-O3 -Wp,-D_FORTIFY_SOURCE=2' ./configure.developer --abi-check-disable" + samba_configure_params
),
737 ("test", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
738 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
740 ("install", "make install"),
741 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
742 ("clean", "make clean"),
748 ("random-sleep", random_sleep(900, 1500)),
750 # make sure we have tdb around:
751 ("tdb-configure", "cd lib/tdb && PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}"),
752 ("tdb-make", "cd lib/tdb && make"),
753 ("tdb-install", "cd lib/tdb && make install"),
755 # build samba with cluster support (also building ctdb):
757 "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH "
758 "PKG_CONFIG_PATH=${PREFIX_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH} "
759 "./configure.developer ${PREFIX} "
760 "--with-selftest-prefix=./bin/ab "
762 "--with-cluster-support "
764 "--bundled-libraries=!tdb"),
765 ("samba-make", "make"),
766 ("samba-check", "./bin/smbd --configfile=/dev/null -b | grep CLUSTER_SUPPORT"),
767 ("samba-install", "make install"),
768 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd"),
772 INJECT_SELFTEST_PREFIX
=0,
773 include_envs
=["clusteredmember"])
777 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
778 ("clean", "make clean"),
779 ("ctdb-clean", "cd ./ctdb && make clean"),
785 ("random-sleep", random_sleep(300, 900)),
786 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
),
787 ("talloc-make", "cd lib/talloc && make"),
788 ("talloc-install", "cd lib/talloc && make install"),
790 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
),
791 ("tdb-make", "cd lib/tdb && make"),
792 ("tdb-install", "cd lib/tdb && make install"),
794 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
),
795 ("tevent-make", "cd lib/tevent && make"),
796 ("tevent-install", "cd lib/tevent && make install"),
798 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
),
799 ("ldb-make", "cd lib/ldb && make"),
800 ("ldb-install", "cd lib/ldb && make install"),
802 ("nondevel-configure", "./configure ${PREFIX}"),
803 ("nondevel-make", "make -j"),
804 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0"),
805 ("nondevel-install", "make install"),
806 ("nondevel-dist", "make dist"),
808 # retry with all modules shared
809 ("allshared-distclean", "make distclean"),
810 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL"),
811 ("allshared-make", "make -j"),
817 # build the fuzzers (static) via the oss-fuzz script
818 ("fuzzers-mkdir-prefix", "mkdir -p ${PREFIX_DIR}"),
819 ("fuzzers-build", "OUT=${PREFIX_DIR} LIB_FUZZING_ENGINE= SANITIZER=address CXX= CFLAGS= ADDITIONAL_LDFLAGS='-fuse-ld=bfd' ./lib/fuzzing/oss-fuzz/build_samba.sh --enable-afl-fuzzer"),
823 # * Test smbd and smbtorture can build semi-static
825 # * Test Samba without python still builds.
827 # When this test fails due to more use of Python, the expectations
828 # is that the newly failing part of the code should be disabled
829 # when --disable-python is set (rather than major work being done
830 # to support this environment).
832 # The target here is for vendors shipping a minimal smbd.
833 "samba-minimal-smbd": {
835 ("random-sleep", random_sleep(300, 900)),
837 # build with all modules static
838 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL"),
839 ("allstatic-make", "make -j"),
840 ("allstatic-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
841 ("allstatic-lcov", LCOV_CMD
),
843 # retry with nonshared smbd and smbtorture
844 ("nonshared-distclean", "make distclean"),
845 ("nonshared-configure", "./configure.developer " + samba_configure_params
+ " --bundled-libraries=ALL --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd"),
846 ("nonshared-make", "make -j"),
847 # TODO ("nonshared-test", make_test(TESTS="samba3.smb2.create.*nt4_dc")),
848 # TODO ("nonshared-lcov", LCOV_CMD),
850 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
851 ("clean", "make clean"),
857 ("random-sleep", random_sleep(300, 900)),
859 ("configure", "./configure.developer ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data --disable-python --without-ad-dc"),
861 ("find-python", "script/find_python.sh ${PREFIX}"),
862 ("test", "make test-nopython"),
864 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
865 ("clean", "make clean"),
867 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
868 ("talloc-make", "cd lib/talloc && make"),
869 ("talloc-install", "cd lib/talloc && make install"),
871 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
872 ("tdb-make", "cd lib/tdb && make"),
873 ("tdb-install", "cd lib/tdb && make install"),
875 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
876 ("tevent-make", "cd lib/tevent && make"),
877 ("tevent-install", "cd lib/tevent && make install"),
879 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
880 ("ldb-make", "cd lib/ldb && make"),
881 ("ldb-install", "cd lib/ldb && make install"),
883 # retry against installed library packages, but no required modules
884 ("libs-configure", samba_libs_configure_base
+ samba_libs_configure_bundled_libs
+ " --disable-python --without-ad-dc --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT"),
885 ("libs-make", "make -j"),
886 ("libs-install", "make install"),
887 ("libs-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
888 ("libs-clean", "make clean"),
895 ("random-sleep", random_sleep(60, 600)),
896 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
898 ("install", "make install"),
899 ("test", "make test"),
901 ("clean", "make clean"),
902 ("configure-no-lmdb", "./configure ${ENABLE_COVERAGE} --enable-developer --without-ldb-lmdb -C ${PREFIX}"),
903 ("make-no-lmdb", "make"),
904 ("test-no-lmdb", "make test"),
905 ("lcov-no-lmdb", LCOV_CMD
),
906 ("install-no-lmdb", "make install"),
907 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
908 ("distcheck", "make distcheck"),
909 ("clean", "make clean"),
915 ("random-sleep", random_sleep(60, 600)),
916 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
918 ("install", "make install"),
919 ("test", "make test"),
921 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
922 ("distcheck", "make distcheck"),
923 ("clean", "make clean"),
929 ("random-sleep", random_sleep(60, 600)),
930 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
932 ("install", "make install"),
933 ("test", "make test"),
935 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
936 ("distcheck", "make distcheck"),
937 ("clean", "make clean"),
943 ("random-sleep", random_sleep(60, 600)),
944 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
946 ("install", "make install"),
947 ("test", "make test"),
949 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
950 ("distcheck", "make distcheck"),
951 ("clean", "make clean"),
957 ("random-sleep", random_sleep(60, 600)),
958 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
960 ("install", "make install"),
961 ("test", "make test"),
963 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
964 ("distcheck", "make distcheck"),
965 ("clean", "make clean"),
970 "git-clone-required": True,
972 ("random-sleep", random_sleep(60, 600)),
973 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}"),
974 ("touch", "touch *.yp"),
976 ("test", "make test"),
977 ("install", "make install"),
978 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm"),
979 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
980 ("clean", "make clean"),
984 # these are useful for debugging autobuild
987 ("pass", 'echo passing && /bin/true'),
992 ("fail", 'echo failing && /bin/false'),
997 defaulttasks
= list(tasks
.keys())
999 defaulttasks
.remove("pass")
1000 defaulttasks
.remove("fail")
1001 defaulttasks
.remove("samba-def-build")
1002 defaulttasks
.remove("samba-nt4-build")
1003 defaulttasks
.remove("samba-mit-build")
1004 defaulttasks
.remove("samba-h5l-build")
1005 defaulttasks
.remove("samba-no-opath-build")
1006 defaulttasks
.remove("samba-test-only")
1007 defaulttasks
.remove("samba-fuzz")
1008 defaulttasks
.remove("samba-fips")
1009 if os
.environ
.get("AUTOBUILD_SKIP_SAMBA_O3", "0") == "1":
1010 defaulttasks
.remove("samba-o3")
1019 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
1021 show
= options
.verbose
1023 do_print("Running: '%s' in '%s'" % (cmd
, dir))
1025 out
= check_output([cmd
], shell
=True, cwd
=dir)
1026 return out
.decode(encoding
='utf-8', errors
='backslashreplace')
1028 return check_call(cmd
, shell
=True, cwd
=dir)
1030 return call(cmd
, shell
=True, cwd
=dir)
1032 def rmdir_force(dirname
, re_raise
=True):
1034 run_cmd("test -d %s && chmod -R +w %s; rm -rf %s" % (
1035 dirname
, dirname
, dirname
), output
=True, show
=True)
1036 except CalledProcessError
as e
:
1037 do_print("Failed: '%s'" % (str(e
)))
1038 run_cmd("tree %s" % dirname
, output
=True, show
=True)
1044 class builder(object):
1045 '''handle build of one directory'''
1047 def __init__(self
, name
, definition
):
1049 self
.dir = builddirs
.get(name
, '.')
1050 self
.tag
= self
.name
.replace('/', '_')
1051 self
.definition
= definition
1052 self
.sequence
= definition
["sequence"]
1053 self
.git_clone_required
= False
1054 if "git-clone-required" in definition
:
1055 self
.git_clone_required
= bool(definition
["git-clone-required"])
1059 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
1060 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
1062 do_print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
1063 do_print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
1064 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
1065 self
.stdout
= open(self
.stdout_path
, 'w')
1066 self
.stderr
= open(self
.stderr_path
, 'w')
1067 self
.stdin
= open("/dev/null", 'r')
1068 self
.builder_dir
= "%s/%s" % (testbase
, self
.tag
)
1069 self
.test_source_dir
= self
.builder_dir
1070 self
.cwd
= "%s/%s" % (self
.builder_dir
, self
.dir)
1071 self
.selftest_prefix
= "%s/bin/ab" % (self
.cwd
)
1072 self
.prefix
= "%s/%s" % (test_prefix
, self
.tag
)
1074 self
.producer
= None
1076 if self
.git_clone_required
:
1077 assert "dependency" not in definition
1079 def mark_existing(self
):
1080 do_print('%s: Mark as existing dependency' % self
.name
)
1081 self
.next
= len(self
.sequence
)
1084 def add_consumer(self
, consumer
):
1085 do_print("%s: add consumer: %s" % (self
.name
, consumer
.name
))
1086 consumer
.producer
= self
1087 consumer
.test_source_dir
= self
.test_source_dir
1088 self
.consumers
.append(consumer
)
1090 def start_next(self
):
1091 if self
.producer
is not None:
1092 if not self
.producer
.done
:
1093 do_print("%s: Waiting for producer: %s" % (self
.name
, self
.producer
.name
))
1097 rmdir_force(self
.builder_dir
)
1098 rmdir_force(self
.prefix
)
1099 if self
.producer
is not None:
1100 run_cmd("mkdir %s" % (self
.builder_dir
), dir=test_master
, show
=True)
1101 elif not self
.git_clone_required
:
1102 run_cmd("cp -R -a -l %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1104 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1106 if self
.next
== len(self
.sequence
):
1108 do_print('%s: Completed OK' % self
.name
)
1110 if not options
.nocleanup
and len(self
.consumers
) == 0:
1111 do_print('%s: Cleaning up' % self
.name
)
1112 rmdir_force(self
.builder_dir
)
1113 rmdir_force(self
.prefix
)
1114 for consumer
in self
.consumers
:
1115 if consumer
.next
!= 0:
1117 do_print('%s: Starting consumer %s' % (self
.name
, consumer
.name
))
1118 consumer
.start_next()
1119 if self
.producer
is not None:
1120 self
.producer
.consumers
.remove(self
)
1121 assert self
.producer
.done
1122 self
.producer
.start_next()
1123 do_print('%s: Remaining consumers %u' % (self
.name
, len(self
.consumers
)))
1125 (self
.stage
, self
.cmd
) = self
.sequence
[self
.next
]
1126 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(plat_specific
=1, standard_lib
=0, prefix
=self
.prefix
))
1127 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
1128 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
1129 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
1130 self
.cmd
= self
.cmd
.replace("${TEST_SOURCE_DIR}", self
.test_source_dir
)
1131 self
.cmd
= self
.cmd
.replace("${SELFTEST_PREFIX}", self
.selftest_prefix
)
1132 self
.cmd
= self
.cmd
.replace("${LOG_BASE}", options
.log_base
)
1133 self
.cmd
= self
.cmd
.replace("${NAME}", self
.name
)
1134 self
.cmd
= self
.cmd
.replace("${ENABLE_COVERAGE}", options
.enable_coverage
)
1135 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, self
.cwd
))
1136 self
.proc
= Popen(self
.cmd
, shell
=True,
1137 close_fds
=True, cwd
=self
.cwd
,
1138 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
1141 def expand_dependencies(n
):
1143 if "dependency" in tasks
[n
]:
1144 depname
= tasks
[n
]["dependency"]
1145 assert depname
in tasks
1146 sdeps
= expand_dependencies(depname
)
1147 assert n
not in sdeps
1150 deps
.append(depname
)
1154 class buildlist(object):
1155 '''handle build of multiple directories'''
1157 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
1158 self
.tail_proc
= None
1161 if options
.restrict_tests
:
1162 tasknames
= ["samba-test-only"]
1164 tasknames
= defaulttasks
1166 given_tasknames
= tasknames
.copy()
1167 implicit_tasknames
= []
1168 for n
in given_tasknames
:
1169 deps
= expand_dependencies(n
)
1171 if dep
in given_tasknames
:
1173 if dep
in implicit_tasknames
:
1175 implicit_tasknames
.append(dep
)
1177 tasknames
= implicit_tasknames
.copy()
1178 tasknames
.extend(given_tasknames
)
1179 do_print("given_tasknames: %s" % given_tasknames
)
1180 do_print("implicit_tasknames: %s" % implicit_tasknames
)
1181 do_print("tasknames: %s" % tasknames
)
1182 self
.tlist
= [builder(n
, tasks
[n
]) for n
in tasknames
]
1185 rebase_remote
= "rebaseon"
1187 "git-clone-required": True,
1191 git remote add -t %s %s %s
1195 git describe %s/%s > old_remote_branch.desc
1197 git describe %s/%s > remote_branch.desc
1198 diff old_remote_branch.desc remote_branch.desc
1201 rebase_branch
, rebase_remote
, rebase_url
,
1203 rebase_remote
, rebase_branch
,
1205 rebase_remote
, rebase_branch
1208 self
.retry
= builder('retry', retry_task
)
1209 self
.need_retry
= False
1211 if options
.skip_dependencies
:
1212 for b
in self
.tlist
:
1213 if b
.name
in implicit_tasknames
:
1216 for b
in self
.tlist
:
1217 do_print("b.name=%s" % b
.name
)
1218 if "dependency" not in b
.definition
:
1220 depname
= b
.definition
["dependency"]
1221 do_print("b.name=%s: dependency:%s" % (b
.name
, depname
))
1222 for p
in self
.tlist
:
1223 if p
.name
== depname
:
1226 def kill_kids(self
):
1227 if self
.tail_proc
is not None:
1228 self
.tail_proc
.terminate()
1229 self
.tail_proc
.wait()
1230 self
.tail_proc
= None
1231 if self
.retry
is not None:
1232 self
.retry
.proc
.terminate()
1233 self
.retry
.proc
.wait()
1235 for b
in self
.tlist
:
1236 if b
.proc
is not None:
1237 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.test_source_dir
, checkfail
=False)
1245 for b
in self
.tlist
:
1248 none_running
= False
1249 b
.status
= b
.proc
.poll()
1250 if b
.status
is None:
1255 ret
= self
.retry
.proc
.poll()
1257 self
.need_retry
= True
1265 for b
in self
.tlist
:
1268 self
.retry
.start_next()
1271 if options
.retry
and self
.need_retry
:
1273 do_print("retry needed")
1274 return (0, None, None, None, "retry")
1277 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
1279 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
1282 return (0, None, None, None, "All OK")
1284 def write_system_info(self
, filename
):
1285 with
open(filename
, 'w') as f
:
1286 for cmd
in ['uname -a',
1290 'cat /proc/cpuinfo',
1293 'df -m %s' % testbase
]:
1295 out
= run_cmd(cmd
, output
=True, checkfail
=False)
1296 except CalledProcessError
as e
:
1297 out
= "<failed: %s>" % str(e
)
1298 print('### %s' % cmd
, file=f
)
1302 def tarlogs(self
, fname
):
1303 with tarfile
.open(fname
, "w:gz") as tar
:
1304 for b
in self
.tlist
:
1305 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
1306 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
1307 if os
.path
.exists("autobuild.log"):
1308 tar
.add("autobuild.log")
1309 filename
= 'system-info.txt'
1310 self
.write_system_info(filename
)
1313 def remove_logs(self
):
1314 for b
in self
.tlist
:
1315 os
.unlink(b
.stdout_path
)
1316 os
.unlink(b
.stderr_path
)
1318 def start_tail(self
):
1319 cmd
= ["tail", "-f"]
1320 for b
in self
.tlist
:
1321 cmd
.append(b
.stdout_path
)
1322 cmd
.append(b
.stderr_path
)
1323 self
.tail_proc
= Popen(cmd
, close_fds
=True)
1326 def cleanup(do_raise
=False):
1327 if options
.nocleanup
:
1329 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
1330 run_cmd("stat %s" % testbase
, show
=True)
1331 do_print("Cleaning up %r" % cleanup_list
)
1332 for d
in cleanup_list
:
1333 ok
= rmdir_force(d
, re_raise
=False)
1336 if os
.path
.isdir(d
):
1337 do_print("Killing, waiting and retry")
1338 run_cmd("killbysubdir %s > /dev/null 2>&1" % d
, checkfail
=False)
1340 do_print("Waiting and retry")
1342 rmdir_force(d
, re_raise
=do_raise
)
1345 def daemonize(logfile
):
1347 if pid
== 0: # Parent
1350 if pid
!= 0: # Actual daemon
1355 import resource
# Resource usage information.
1356 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
1357 if maxfd
== resource
.RLIM_INFINITY
:
1358 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
1359 for fd
in range(0, maxfd
):
1364 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
1369 def write_pidfile(fname
):
1370 '''write a pid file, cleanup on exit'''
1371 with
open(fname
, mode
='w') as f
:
1372 f
.write("%u\n" % os
.getpid())
1375 def rebase_tree(rebase_url
, rebase_branch
="master"):
1376 rebase_remote
= "rebaseon"
1377 do_print("Rebasing on %s" % rebase_url
)
1378 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1379 run_cmd("git remote add -t %s %s %s" %
1380 (rebase_branch
, rebase_remote
, rebase_url
),
1381 show
=True, dir=test_master
)
1382 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
1383 if options
.fix_whitespace
:
1384 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
1385 (rebase_remote
, rebase_branch
),
1386 show
=True, dir=test_master
)
1388 run_cmd("git rebase --force-rebase %s/%s" %
1389 (rebase_remote
, rebase_branch
),
1390 show
=True, dir=test_master
)
1391 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
1392 (rebase_remote
, rebase_branch
),
1393 dir=test_master
, output
=True)
1395 do_print("No differences between HEAD and %s/%s - exiting" %
1396 (rebase_remote
, rebase_branch
))
1398 run_cmd("git describe %s/%s" %
1399 (rebase_remote
, rebase_branch
),
1400 show
=True, dir=test_master
)
1401 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1402 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
1403 (rebase_remote
, rebase_branch
),
1404 show
=True, dir=test_master
)
1407 def push_to(push_url
, push_branch
="master"):
1408 push_remote
= "pushto"
1409 do_print("Pushing to %s" % push_url
)
1411 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
1412 run_cmd("git commit --amend -c HEAD", dir=test_master
)
1413 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
1414 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
1415 run_cmd("git remote add -t %s %s %s" %
1416 (push_branch
, push_remote
, push_url
),
1417 show
=True, dir=test_master
)
1418 run_cmd("git push %s +HEAD:%s" %
1419 (push_remote
, push_branch
),
1420 show
=True, dir=test_master
)
1423 def send_email(subject
, text
, log_tar
):
1424 if options
.email
is None:
1425 do_print("not sending email because the recipient is not set")
1426 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
1429 outer
= MIMEMultipart()
1430 outer
['Subject'] = subject
1431 outer
['To'] = options
.email
1432 outer
['From'] = options
.email_from
1433 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
1434 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
1435 outer
.attach(MIMEText(text
, 'plain', 'utf-8'))
1436 if options
.attach_logs
:
1437 with
open(log_tar
, 'rb') as fp
:
1438 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
1439 # Set the filename parameter
1440 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
1442 content
= outer
.as_string()
1443 s
= smtplib
.SMTP(options
.email_server
)
1444 email_user
= os
.getenv('SMTP_USERNAME')
1445 email_password
= os
.getenv('SMTP_PASSWORD')
1446 if email_user
is not None:
1448 s
.login(email_user
, email_password
)
1450 s
.sendmail(options
.email_from
, [options
.email
], content
)
1455 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1456 elapsed_time
, log_base
=None, add_log_tail
=True):
1457 '''send an email to options.email about the failure'''
1458 elapsed_minutes
= elapsed_time
/ 60.0
1459 if log_base
is None:
1464 Your autobuild on %s failed after %.1f minutes
1465 when trying to test %s with the following error:
1469 the autobuild has been abandoned. Please fix the error and resubmit.
1471 A summary of the autobuild process is here:
1474 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
1476 if options
.restrict_tests
:
1478 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1480 if failed_task
!= 'rebase':
1482 You can see logs of the failed task here:
1487 or you can get full logs of all tasks in this job here:
1491 The top commit for the tree that was built was:
1495 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
1498 f
= open("%s/%s.stdout" % (gitroot
, failed_tag
), 'r')
1499 lines
= f
.readlines()
1500 log_tail
= "".join(lines
[-50:])
1501 num_lines
= len(lines
)
1503 # Also include stderr (compile failures) if < 50 lines of stdout
1504 f
= open("%s/%s.stderr" % (gitroot
, failed_tag
), 'r')
1505 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
1508 The last 50 lines of log messages:
1514 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1515 send_email('autobuild[%s] failure on %s for task %s during %s'
1516 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
1520 def email_success(elapsed_time
, log_base
=None):
1521 '''send an email to options.email about a successful build'''
1522 if log_base
is None:
1527 Your autobuild on %s has succeeded after %.1f minutes.
1529 ''' % (platform
.node(), elapsed_time
/ 60.)
1531 if options
.restrict_tests
:
1533 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1535 if options
.keeplogs
:
1538 you can get full logs of all tasks in this job here:
1545 The top commit for the tree that was built was:
1548 ''' % top_commit_msg
1550 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1551 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
1555 # get the top commit message, for emails
1556 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
1559 if options
.skip_dependencies
:
1560 run_cmd("stat %s" % testbase
, dir=testbase
, output
=True)
1562 os
.makedirs(testbase
)
1563 except Exception as reason
:
1564 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
1565 cleanup_list
.append(testbase
)
1568 logfile
= os
.path
.join(testbase
, "log")
1569 do_print("Forking into the background, writing progress to %s" % logfile
)
1572 write_pidfile(gitroot
+ "/autobuild.pid")
1574 start_time
= time
.time()
1578 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
1579 os
.makedirs(test_tmpdir
)
1580 # The waf uninstall code removes empty directories all the way
1581 # up the tree. Creating a file in test_tmpdir stops it from
1583 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
1584 ".directory-is-not-empty"), show
=True)
1585 run_cmd("stat %s" % test_tmpdir
, show
=True)
1586 run_cmd("stat %s" % testbase
, show
=True)
1587 if options
.skip_dependencies
:
1588 run_cmd("stat %s" % test_master
, dir=testbase
, output
=True)
1590 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
1596 if options
.rebase
is not None:
1597 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
1599 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1601 elapsed_time
= time
.time() - start_time
1602 email_failure(-1, 'rebase', 'rebase', 'rebase',
1603 'rebase on %s failed' % options
.branch
,
1604 elapsed_time
, log_base
=options
.log_base
)
1608 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1611 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1612 if status
!= 0 or errstr
!= "retry":
1614 cleanup(do_raise
=True)
1619 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1625 do_print("waiting for tail to flush")
1628 elapsed_time
= time
.time() - start_time
1630 if options
.passcmd
is not None:
1631 do_print("Running passcmd: %s" % options
.passcmd
)
1632 run_cmd(options
.passcmd
, dir=test_master
)
1633 if options
.pushto
is not None:
1634 push_to(options
.pushto
, push_branch
=options
.branch
)
1635 if options
.keeplogs
or options
.attach_logs
:
1636 blist
.tarlogs("logs.tar.gz")
1637 do_print("Logs in logs.tar.gz")
1638 if options
.always_email
:
1639 email_success(elapsed_time
, log_base
=options
.log_base
)
1645 # something failed, gather a tar of the logs
1646 blist
.tarlogs("logs.tar.gz")
1648 if options
.email
is not None:
1649 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1650 elapsed_time
, log_base
=options
.log_base
)
1652 elapsed_minutes
= elapsed_time
/ 60.0
1655 ####################################################################
1659 Your autobuild[%s] on %s failed after %.1f minutes
1660 when trying to test %s with the following error:
1664 the autobuild has been abandoned. Please fix the error and resubmit.
1666 ####################################################################
1668 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1672 do_print("Logs in logs.tar.gz")