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 sysconfig
import get_path
25 from waflib
.Build
import CACHE_SUFFIX
27 sys
.path
.insert(0, "./third_party/waf")
28 from waflib
.Build
import CACHE_SUFFIX
30 logging
.basicConfig(format
='%(asctime)s %(message)s')
31 logger
= logging
.getLogger('autobuild')
32 logger
.setLevel(logging
.INFO
)
34 os
.environ
["PYTHONUNBUFFERED"] = "1"
36 # This speeds up testing remarkably.
37 os
.environ
['TDB_NO_FSYNC'] = '1'
39 # allow autobuild to run within git rebase -i
40 if "GIT_DIR" in os
.environ
:
41 del os
.environ
["GIT_DIR"]
42 if "GIT_WORK_TREE" in os
.environ
:
43 del os
.environ
["GIT_WORK_TREE"]
46 '''get to the top of the git repo'''
49 if os
.path
.exists(os
.path
.join(p
, ".git")):
51 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
55 gitroot
= find_git_root()
57 raise Exception("Failed to find git root")
60 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
62 parser
= OptionParser()
63 parser
.add_option("--tail", help="show output while running", default
=False, action
="store_true")
64 parser
.add_option("--keeplogs", help="keep logs", default
=False, action
="store_true")
65 parser
.add_option("--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
66 parser
.add_option("--skip-dependencies", help="skip to run task dependency tasks", default
=False, action
="store_true")
67 parser
.add_option("--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
69 parser
.add_option("--full-testbase", help="full base directory to run tests in (default %s/b$PID)" % def_testbase
,
71 parser
.add_option("--passcmd", help="command to run on success", default
=None)
72 parser
.add_option("--verbose", help="show all commands as they are run",
73 default
=False, action
="store_true")
74 parser
.add_option("--rebase", help="rebase on the given tree before testing",
75 default
=None, type='str')
76 parser
.add_option("--pushto", help="push to a git url on success",
77 default
=None, type='str')
78 parser
.add_option("--mark", help="add a Tested-By signoff before pushing",
79 default
=False, action
="store_true")
80 parser
.add_option("--fix-whitespace", help="fix whitespace on rebase",
81 default
=False, action
="store_true")
82 parser
.add_option("--retry", help="automatically retry if master changes",
83 default
=False, action
="store_true")
84 parser
.add_option("--email", help="send email to the given address on failure",
85 type='str', default
=None)
86 parser
.add_option("--email-from", help="send email from the given address",
87 type='str', default
="autobuild@samba.org")
88 parser
.add_option("--email-server", help="send email via the given server",
89 type='str', default
='localhost')
90 parser
.add_option("--always-email", help="always send email, even on success",
92 parser
.add_option("--daemon", help="daemonize after initial setup",
94 parser
.add_option("--branch", help="the branch to work on (default=master)",
95 default
="master", type='str')
96 parser
.add_option("--log-base", help="location where the logs can be found (default=cwd)",
97 default
=gitroot
, type='str')
98 parser
.add_option("--attach-logs", help="Attach logs to mails sent on success/failure?",
99 default
=False, action
="store_true")
100 parser
.add_option("--restrict-tests", help="run as make test with this TESTS= regex",
102 parser
.add_option("--enable-coverage", dest
='enable_coverage',
103 action
="store_const", const
='--enable-coverage', default
='',
104 help="Add --enable-coverage option while configure")
106 (options
, args
) = parser
.parse_args()
109 if options
.rebase
is None:
110 raise Exception('You can only use --retry if you also rebase')
113 logger
.setLevel(logging
.DEBUG
)
115 if options
.full_testbase
is not None:
116 testbase
= options
.full_testbase
118 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
119 test_master
= "%s/master" % testbase
120 test_prefix
= "%s/prefix" % testbase
121 test_tmpdir
= "%s/tmp" % testbase
122 os
.environ
['TMPDIR'] = test_tmpdir
124 if options
.enable_coverage
:
125 LCOV_CMD
= "cd ${TEST_SOURCE_DIR} && lcov --capture --directory . --output-file ${LOG_BASE}/${NAME}.info --rc 'geninfo_adjust_src_path=${TEST_SOURCE_DIR}/'"
127 LCOV_CMD
= 'echo "lcov skipped since no --enable-coverage specified"'
129 if options
.enable_coverage
:
130 PUBLISH_DOCS
= "mkdir -p ${LOG_BASE}/public && mv output/htmldocs ${LOG_BASE}/public/htmldocs"
132 PUBLISH_DOCS
= 'echo "HTML documentation publishing skipped since no --enable-coverage specified"'
134 CLEAN_SOURCE_TREE_CMD
= "cd ${TEST_SOURCE_DIR} && script/clean-source-tree.sh"
137 def check_symbols(sofile
, expected_symbols
=""):
138 return "objdump --dynamic-syms " + sofile
+ " | " + \
139 "awk \'$0 !~ /" + expected_symbols
+ "/ {if ($2 == \"g\" && $3 ~ /D(F|O)/ && $4 ~ /(.bss|.text)/ && $7 !~ /(__gcov_|mangle_path)/) exit 1}\'"
142 # If we are only running specific test,
143 # do not sleep randomly to wait for it to start
144 def random_sleep(low
, high
):
147 def random_sleep(low
, high
):
148 return 'sleep {}'.format(random
.randint(low
, high
))
156 "talloc": "lib/talloc",
157 "replace": "lib/replace",
158 "tevent": "lib/tevent",
160 "docs-xml": "docs-xml"
163 ctdb_configure_params
= " --enable-developer ${PREFIX}"
164 samba_configure_params
= " ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data"
166 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH"
167 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
168 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
169 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check ${ENABLE_COVERAGE} --enable-debug -C ${PREFIX}"
170 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=cmocka,popt,NONE"
171 samba_libs_configure_bundled_libs
= " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent,!popt"
172 samba_libs_configure_samba
= samba_libs_configure_base
+ samba_libs_configure_bundled_libs
175 def format_option(name
, value
=None):
176 """Format option as str list."""
177 if value
is None: # boolean option
179 if not isinstance(value
, list): # single value option
182 return ['{}={}'.format(name
, item
) for item
in value
]
187 INJECT_SELFTEST_PREFIX
=1,
194 test_options
= format_option('--include-env', include_envs
)
196 test_options
= format_option('--exclude-env', exclude_envs
)
198 # join envs options to original test options
199 TESTS
= (TESTS
+ ' ' + ' '.join(test_options
)).strip()
203 # Allow getting a full CI with
204 # git push -o ci.variable='AUTOBUILD_FAIL_IMMEDIATELY=0'
206 FAIL_IMMEDIATELY
= os
.getenv("AUTOBUILD_FAIL_IMMEDIATELY", "1")
208 if int(FAIL_IMMEDIATELY
):
209 _options
.append('FAIL_IMMEDIATELY=1')
211 _options
.append("TESTS='{}'".format(TESTS
))
213 if INJECT_SELFTEST_PREFIX
:
214 _options
.append("TEST_OPTIONS='--with-selftest-prefix={}'".format("${SELFTEST_PREFIX}"))
215 _options
.append("--directory='{}'".format("${TEST_SOURCE_DIR}"))
217 return ' '.join([cmd
] + _options
)
220 # When updating this list, also update .gitlab-ci.yml to add the job
221 # and to make it a dependency of 'page' for the coverage report.
226 ("random-sleep", random_sleep(300, 900)),
227 ("configure", "./configure " + ctdb_configure_params
),
228 ("make", "make all"),
229 ("install", "make install"),
230 ("test", "make autotest"),
231 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
232 ("clean", "make clean"),
237 ("random-sleep", random_sleep(300, 900)),
238 ("autoconf", "autoconf"),
239 ("configure", "./configure"),
240 ("make", "make html htmlman"),
241 ("publish-docs", PUBLISH_DOCS
),
242 ("clean", "make clean"),
247 "git-clone-required": True,
249 ("configure", "./configure.developer" + samba_configure_params
),
251 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
252 ("chmod-R-a-w", "chmod -R a-w ."),
257 "git-clone-required": True,
259 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
261 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
262 ("chmod-R-a-w", "chmod -R a-w ."),
267 "git-clone-required": True,
269 ("configure", "./configure.developer --without-ad-dc --without-ldap --without-ads --without-json" + samba_configure_params
),
271 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
272 ("chmod-R-a-w", "chmod -R a-w ."),
277 "git-clone-required": True,
279 ("configure", "./configure.developer --without-ad-dc --with-system-heimdalkrb5" + samba_configure_params
),
281 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
282 ("chmod-R-a-w", "chmod -R a-w ."),
286 "samba-without-smb1-build": {
287 "git-clone-required": True,
289 ("configure", "./configure.developer --without-smb1-server --without-ad-dc" + samba_configure_params
),
291 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
292 ("chmod-R-a-w", "chmod -R a-w ."),
296 "samba-no-opath-build": {
297 "git-clone-required": True,
299 ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1' ./configure.developer --without-ad-dc " + samba_configure_params
),
301 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
302 ("chmod-R-a-w", "chmod -R a-w ."),
306 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
309 ("random-sleep", random_sleep(300, 900)),
310 ("configure", "./configure.developer" + samba_configure_params
),
312 ("test", make_test(exclude_envs
=[
325 "ad_dc_default_smb1",
333 "ad_member_idmap_rid",
334 "admem_idmap_autorid",
335 "ad_member_idmap_ad",
343 "fileserver_smb1_done",
357 "ad_dc_default_smb1",
358 "ad_dc_default_smb1_done",
366 ("test-slow-none", make_test(cmd
='make test', TESTS
="--include=selftest/slow-none", include_envs
=["none"])),
368 ("install", "make install"),
369 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
370 ("clean", "make clean"),
374 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
377 ("random-sleep", random_sleep(300, 900)),
378 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
380 ("test", make_test(exclude_envs
=[
393 "ad_dc_default_smb1",
394 "ad_dc_default_smb1_done",
402 "ad_member_idmap_rid",
403 "admem_idmap_autorid",
404 "ad_member_idmap_ad",
412 "fileserver_smb1_done",
426 "ad_dc_default_smb1",
427 "ad_dc_default_smb1_done",
436 ("install", "make install"),
437 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
438 ("clean", "make clean"),
443 "dependency": "samba-nt4-build",
445 ("random-sleep", random_sleep(300, 900)),
446 ("test", make_test(include_envs
=[
455 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
459 "samba-fileserver": {
460 "dependency": "samba-h5l-build",
462 ("random-sleep", random_sleep(300, 900)),
463 ("test", make_test(include_envs
=[
466 "fileserver_smb1_done",
468 "ktest", # ktest is also tested in samba-ktest-mit samba
469 # and samba-mitkrb5 but is tested here against
473 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
477 "samba-fileserver-without-smb1": {
478 "dependency": "samba-without-smb1-build",
480 ("random-sleep", random_sleep(300, 900)),
481 ("test", make_test(include_envs
=["fileserver"])),
483 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
487 # This is a full build without the AD DC so we test the build with
488 # MIT Kerberos from the current system. Runtime behaviour is
489 # confirmed via the ktest (static ccache and keytab) environment
491 # This environment also used to confirm we can still build with --with-libunwind
494 ("random-sleep", random_sleep(300, 900)),
495 ("configure", "./configure.developer --without-ad-dc --with-libunwind --with-system-mitkrb5 " + samba_configure_params
),
497 ("test", make_test(include_envs
=[
498 "ktest", # ktest is also tested in fileserver, samba and
499 # samba-mitkrb5 but is tested here against a
503 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
508 "dependency": "samba-def-build",
510 ("random-sleep", random_sleep(300, 900)),
511 ("test", make_test(include_envs
=[
513 "ad_member_idmap_rid",
514 "admem_idmap_autorid",
515 "ad_member_idmap_ad",
517 "ad_member_offlogon",
520 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
525 "dependency": "samba-no-opath-build",
527 ("random-sleep", random_sleep(300, 900)),
529 cmd
="make testonly DISABLE_OPATH=1",
539 ("check-clean-tree", "script/clean-source-tree.sh"),
544 "dependency": "samba-no-opath-build",
546 ("random-sleep", random_sleep(300, 900)),
548 cmd
="make testonly DISABLE_OPATH=1",
552 "fileserver_smb1_done",
555 ("check-clean-tree", "script/clean-source-tree.sh"),
560 "dependency": "samba-def-build",
562 ("random-sleep", random_sleep(1, 1)),
563 ("test", make_test(include_envs
=[
571 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
576 "dependency": "samba-def-build",
578 ("random-sleep", random_sleep(1, 1)),
579 ("test", make_test(include_envs
=[
585 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
590 "dependency": "samba-def-build",
592 ("random-sleep", random_sleep(1, 1)),
593 ("test", make_test(include_envs
=[
600 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
605 "dependency": "samba-def-build",
607 ("random-sleep", random_sleep(1, 1)),
608 ("test", make_test(include_envs
=[
614 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
618 "dependency": "samba-def-build",
620 ("random-sleep", random_sleep(1, 1)),
621 ("test", make_test(include_envs
=[
626 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
631 "dependency": "samba-def-build",
633 ("random-sleep", random_sleep(1, 1)),
634 ("test", make_test(include_envs
=[
635 "ad_dc_default", "ad_dc_default_smb1", "ad_dc_default_smb1_done"])),
637 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
642 "dependency": "samba-def-build",
644 ("random-sleep", random_sleep(1, 1)),
645 ("test", make_test(include_envs
=["ad_dc_slowtests", "ad_dc_backup"])),
647 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
651 "samba-schemaupgrade": {
652 "dependency": "samba-def-build",
654 ("random-sleep", random_sleep(1, 1)),
655 ("test", make_test(include_envs
=["schema_dc", "schema_pair_dc"])),
657 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
661 # We split out the ad_dc_ntvfs tests (which are long) so other test do not wait
662 # This is currently the longest task, so we don't randomly delay it.
663 "samba-ad-dc-ntvfs": {
664 "dependency": "samba-def-build",
666 ("random-sleep", random_sleep(1, 1)),
667 ("test", make_test(include_envs
=["ad_dc_ntvfs"])),
669 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
673 # Test fips compliance
675 "dependency": "samba-mit-build",
677 ("random-sleep", random_sleep(1, 1)),
678 ("test", make_test(include_envs
=["ad_dc_fips", "ad_member_fips"])),
679 # TODO: This seems to generate only an empty samba-fips.info ("lcov", LCOV_CMD),
680 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
684 # run the backup/restore testenvs separately as they're fairly standalone
685 # (and CI seems to max out at ~3 different DCs running at once)
687 "dependency": "samba-def-build",
689 ("random-sleep", random_sleep(300, 900)),
690 ("test", make_test(include_envs
=[
696 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
700 "dependency": "samba-def-build",
702 ("random-sleep", random_sleep(300, 900)),
703 ("test", make_test(include_envs
=[
709 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
714 "dependency": "samba-mit-build",
716 ("random-sleep", random_sleep(1, 1)),
717 ("test", make_test(include_envs
=[
719 "ad_member_idmap_rid",
720 "admem_idmap_autorid",
721 "ad_member_idmap_ad",
723 "ad_member_offlogon",
726 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
730 "samba-addc-mit-1": {
731 "dependency": "samba-mit-build",
733 ("random-sleep", random_sleep(1, 1)),
734 ("test", make_test(include_envs
=[
742 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
746 "samba-addc-mit-4a": {
747 "dependency": "samba-mit-build",
749 ("random-sleep", random_sleep(1, 1)),
750 ("test", make_test(include_envs
=[
756 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
759 "samba-addc-mit-4b": {
760 "dependency": "samba-mit-build",
762 ("random-sleep", random_sleep(1, 1)),
763 ("test", make_test(include_envs
=[
768 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
774 ("configure", "./configure.developer --abi-check-disable" + samba_configure_params
),
776 ("test", make_test(TESTS
="${TESTS}")),
781 # Test cross-compile infrastructure
784 ("random-sleep", random_sleep(900, 1500)),
785 ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
786 ("configure-cross-execute", "./configure.developer --out ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
787 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
),
788 ("verify-cross-execute-output", "grep '^Checking value of NSIG' ./bin-xe/cross-answers.txt"),
789 ("configure-cross-answers", "./configure.developer --out ./bin-xa --cross-compile" \
790 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
),
791 ("compare-results", "script/compare_cc_results.py "
792 "./bin/c4che/default{} "
793 "./bin-xe/c4che/default{} "
794 "./bin-xa/c4che/default{}".format(*([CACHE_SUFFIX
]*3))),
795 ("modify-cross-answers", "sed -i.bak -e 's/^\\(Checking value of NSIG:\\) .*/\\1 \"1234\"/' ./bin-xe/cross-answers.txt"),
796 ("configure-cross-answers-modified", "./configure.developer --out ./bin-xa2 --cross-compile" \
797 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa2/ab" + samba_configure_params
),
798 ("verify-cross-answers", "test $(sed -n -e 's/VALUEOF_NSIG = \\(.*\\)/\\1/p' ./bin-xa2/c4che/default{})" \
799 " = \"'1234'\"".format(CACHE_SUFFIX
)),
800 ("invalidate-cross-answers", "sed -i.bak -e '/^Checking value of NSIG/d' ./bin-xe/cross-answers.txt"),
801 ("configure-cross-answers-fail", "./configure.developer --out ./bin-xa3 --cross-compile" \
802 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa3/ab" + samba_configure_params
+ \
807 # test build with -O3 -- catches extra warnings and bugs, tests the ad_dc environments
810 ("random-sleep", random_sleep(300, 900)),
811 ("configure", "ADDITIONAL_CFLAGS='-O3 -Wp,-D_FORTIFY_SOURCE=2' ./configure.developer --abi-check-disable" + samba_configure_params
),
813 ("test", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
814 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
816 ("install", "make install"),
817 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
818 ("clean", "make clean"),
824 ("random-sleep", random_sleep(300, 900)),
825 ("configure", "./configure.developer --abi-check-disable --disable-warnings-as-errors" + samba_configure_params
),
827 ("nonetest", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
828 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
829 ("ktest", make_test(cmd
='make test', include_envs
=["ktest"])),
830 ("install", "make install"),
831 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
832 ("clean", "make clean"),
838 ("random-sleep", random_sleep(900, 1500)),
840 # make sure we have tdb around:
841 ("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}"),
842 ("tdb-make", "cd lib/tdb && make"),
843 ("tdb-install", "cd lib/tdb && make install"),
845 # build samba with cluster support (also building ctdb):
847 "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH "
848 "PKG_CONFIG_PATH=${PREFIX_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH} "
849 "./configure.developer ${PREFIX} "
850 "--with-selftest-prefix=./bin/ab "
851 "--with-cluster-support "
853 "--bundled-libraries=!tdb"),
854 ("samba-make", "make"),
855 ("samba-check", "./bin/smbd --configfile=/dev/null -b | grep CLUSTER_SUPPORT"),
856 ("samba-install", "make install"),
857 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd"),
861 INJECT_SELFTEST_PREFIX
=0,
862 include_envs
=["clusteredmember"])
866 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
867 ("clean", "make clean"),
868 ("ctdb-clean", "cd ./ctdb && make clean"),
874 ("random-sleep", random_sleep(300, 900)),
875 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
),
876 ("talloc-make", "cd lib/talloc && make"),
877 ("talloc-install", "cd lib/talloc && make install"),
879 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
),
880 ("tdb-make", "cd lib/tdb && make"),
881 ("tdb-install", "cd lib/tdb && make install"),
883 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
),
884 ("tevent-make", "cd lib/tevent && make"),
885 ("tevent-install", "cd lib/tevent && make install"),
887 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
),
888 ("ldb-make", "cd lib/ldb && make"),
889 ("ldb-install", "cd lib/ldb && make install"),
891 ("nondevel-configure", samba_libs_envvars
+ " ./configure ${PREFIX}"),
892 ("nondevel-make", "make -j"),
893 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0"),
894 ("nondevel-no-libtalloc", "find ./bin | grep -v 'libtalloc-report' | grep 'libtalloc' && exit 1; exit 0"),
895 ("nondevel-no-libtdb", "find ./bin | grep -v 'libtdb-wrap' | grep 'libtdb' && exit 1; exit 0"),
896 ("nondevel-no-libtevent", "find ./bin | grep -v 'libtevent-util' | grep 'libtevent' && exit 1; exit 0"),
897 ("nondevel-no-libldb", "find ./bin | grep -v 'module' | grep -v 'libldbsamba' | grep 'libldb' && exit 1; exit 0"),
898 ("nondevel-no-samba-nss_winbind", "ldd ./bin/plugins/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
899 ("nondevel-no-samba-nss_wins", "ldd ./bin/plugins/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
900 ("nondevel-no-samba-libwbclient", "ldd ./bin/shared/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
901 ("nondevel-no-samba-pam_winbind", "ldd ./bin/plugins/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
902 ("nondevel-no-public-nss_winbind",
903 check_symbols("./bin/plugins/libnss_winbind.so.2", "_nss_winbind_")),
904 ("nondevel-no-public-nss_wins",
905 check_symbols("./bin/plugins/libnss_wins.so.2", "_nss_wins_")),
906 ("nondevel-no-public-libwbclient",
907 check_symbols("./bin/shared/libwbclient.so.0", "wbc")),
908 ("nondevel-no-public-pam_winbind",
909 check_symbols("./bin/plugins/pam_winbind.so", "pam_sm_")),
910 ("nondevel-no-public-winbind_krb5_locator",
911 check_symbols("./bin/plugins/winbind_krb5_locator.so", "service_locator")),
912 ("nondevel-no-public-async_dns_krb5_locator",
913 check_symbols("./bin/plugins/async_dns_krb5_locator.so", "service_locator")),
914 ("nondevel-install", "make -j install"),
915 ("nondevel-dist", "make dist"),
917 ("prefix-no-private-libtalloc", "find ${PREFIX_DIR} | grep -v 'libtalloc-report' | grep 'private.*libtalloc' && exit 1; exit 0"),
918 ("prefix-no-private-libtdb", "find ${PREFIX_DIR} | grep -v 'libtdb-wrap' | grep 'private.*libtdb' && exit 1; exit 0"),
919 ("prefix-no-private-libtevent", "find ${PREFIX_DIR} | grep -v 'libtevent-util' | grep 'private.*libtevent' && exit 1; exit 0"),
920 ("prefix-no-private-libldb", "find ${PREFIX_DIR} | grep -v 'module' | grep -v 'libldbsamba' | grep 'private.*libldb' && exit 1; exit 0"),
921 ("prefix-no-samba-nss_winbind", "ldd ${PREFIX_DIR}/lib/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
922 ("prefix-no-samba-nss_wins", "ldd ${PREFIX_DIR}/lib/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
923 ("prefix-no-samba-libwbclient", "ldd ${PREFIX_DIR}/lib/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
924 ("prefix-no-samba-pam_winbind", "ldd ${PREFIX_DIR}/lib/security/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
925 ("prefix-no-public-nss_winbind",
926 check_symbols("${PREFIX_DIR}/lib/libnss_winbind.so.2", "_nss_winbind_")),
927 ("prefix-no-public-nss_wins",
928 check_symbols("${PREFIX_DIR}/lib/libnss_wins.so.2", "_nss_wins_")),
929 ("prefix-no-public-libwbclient",
930 check_symbols("${PREFIX_DIR}/lib/libwbclient.so.0", "wbc")),
931 ("prefix-no-public-pam_winbind",
932 check_symbols("${PREFIX_DIR}/lib/security/pam_winbind.so", "pam_sm_")),
933 ("prefix-no-public-winbind_krb5_locator",
934 check_symbols("${PREFIX_DIR}/lib/krb5/winbind_krb5_locator.so",
936 ("prefix-no-public-async_dns_krb5_locator",
937 check_symbols("${PREFIX_DIR}/lib/krb5/async_dns_krb5_locator.so",
940 # retry with all modules shared
941 ("allshared-distclean", "make distclean"),
942 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL"),
943 ("allshared-make", "make -j"),
944 ("allshared-no-libtalloc", "find ./bin | grep -v 'libtalloc-report' | grep 'libtalloc' && exit 1; exit 0"),
945 ("allshared-no-libtdb", "find ./bin | grep -v 'libtdb-wrap' | grep 'libtdb' && exit 1; exit 0"),
946 ("allshared-no-libtevent", "find ./bin | grep -v 'libtevent-util' | grep 'libtevent' && exit 1; exit 0"),
947 ("allshared-no-libldb", "find ./bin | grep -v 'module' | grep -v 'libldbsamba' | grep 'libldb' && exit 1; exit 0"),
948 ("allshared-no-samba-nss_winbind", "ldd ./bin/plugins/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
949 ("allshared-no-samba-nss_wins", "ldd ./bin/plugins/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
950 ("allshared-no-samba-libwbclient", "ldd ./bin/shared/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
951 ("allshared-no-samba-pam_winbind", "ldd ./bin/plugins/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
952 ("allshared-no-public-nss_winbind",
953 check_symbols("./bin/plugins/libnss_winbind.so.2", "_nss_winbind_")),
954 ("allshared-no-public-nss_wins",
955 check_symbols("./bin/plugins/libnss_wins.so.2", "_nss_wins_")),
956 ("allshared-no-public-libwbclient",
957 check_symbols("./bin/shared/libwbclient.so.0", "wbc")),
958 ("allshared-no-public-pam_winbind",
959 check_symbols("./bin/plugins/pam_winbind.so", "pam_sm_")),
960 ("allshared-no-public-winbind_krb5_locator",
961 check_symbols("./bin/plugins/winbind_krb5_locator.so", "service_locator")),
962 ("allshared-no-public-async_dns_krb5_locator",
963 check_symbols("./bin/plugins/async_dns_krb5_locator.so", "service_locator")),
969 # build the fuzzers (static) via the oss-fuzz script
970 ("fuzzers-mkdir-prefix", "mkdir -p ${PREFIX_DIR}"),
971 ("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"),
975 # * Test smbd and smbtorture can build semi-static
977 # * Test Samba without python still builds.
979 # When this test fails due to more use of Python, the expectations
980 # is that the newly failing part of the code should be disabled
981 # when --disable-python is set (rather than major work being done
982 # to support this environment).
984 # The target here is for vendors shipping a minimal smbd.
985 "samba-minimal-smbd": {
987 ("random-sleep", random_sleep(300, 900)),
989 # build with all modules static
990 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL"),
991 ("allstatic-make", "make -j"),
992 ("allstatic-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
993 ("allstatic-lcov", LCOV_CMD
),
995 # retry with nonshared smbd and smbtorture
996 ("nonshared-distclean", "make distclean"),
997 ("nonshared-configure", "./configure.developer " + samba_configure_params
+ " --bundled-libraries=ALL --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd"),
998 ("nonshared-make", "make -j"),
999 # TODO ("nonshared-test", make_test(TESTS="samba3.smb2.create.*nt4_dc")),
1000 # TODO ("nonshared-lcov", LCOV_CMD),
1002 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1003 ("clean", "make clean"),
1009 ("random-sleep", random_sleep(300, 900)),
1011 ("configure", "./configure.developer ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data --disable-python --without-ad-dc"),
1012 ("make", "make -j"),
1013 ("find-python", "script/find_python.sh ${PREFIX}"),
1014 ("test", "make test-nopython"),
1016 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1017 ("clean", "make clean"),
1019 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1020 ("talloc-make", "cd lib/talloc && make"),
1021 ("talloc-install", "cd lib/talloc && make install"),
1023 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1024 ("tdb-make", "cd lib/tdb && make"),
1025 ("tdb-install", "cd lib/tdb && make install"),
1027 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1028 ("tevent-make", "cd lib/tevent && make"),
1029 ("tevent-install", "cd lib/tevent && make install"),
1031 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1032 ("ldb-make", "cd lib/ldb && make"),
1033 ("ldb-install", "cd lib/ldb && make install"),
1035 # retry against installed library packages, but no required modules
1036 ("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"),
1037 ("libs-make", "make -j"),
1038 ("libs-install", "make install"),
1039 ("libs-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1040 ("libs-clean", "make clean"),
1045 "samba-codecheck": {
1047 ("run", "script/check-shell-scripts.sh ."),
1048 ("run", "script/codespell.sh ."),
1054 ("random-sleep", random_sleep(60, 600)),
1055 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1057 ("install", "make install"),
1058 ("test", "make test"),
1060 ("clean", "make clean"),
1061 ("configure-no-lmdb", "./configure ${ENABLE_COVERAGE} --enable-developer --without-ldb-lmdb -C ${PREFIX}"),
1062 ("make-no-lmdb", "make"),
1063 ("test-no-lmdb", "make test"),
1064 ("lcov-no-lmdb", LCOV_CMD
),
1065 ("install-no-lmdb", "make install"),
1066 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1067 ("distcheck", "make distcheck"),
1068 ("clean", "make clean"),
1074 ("random-sleep", random_sleep(60, 600)),
1075 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1077 ("install", "make install"),
1078 ("test", "make test"),
1080 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1081 ("distcheck", "make distcheck"),
1082 ("clean", "make clean"),
1088 ("random-sleep", random_sleep(60, 600)),
1089 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1091 ("install", "make install"),
1092 ("test", "make test"),
1094 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1095 ("distcheck", "make distcheck"),
1096 ("clean", "make clean"),
1102 ("random-sleep", random_sleep(60, 600)),
1103 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1105 ("install", "make install"),
1106 ("test", "make test"),
1108 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1109 ("distcheck", "make distcheck"),
1110 ("clean", "make clean"),
1116 ("random-sleep", random_sleep(60, 600)),
1117 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1119 ("install", "make install"),
1120 ("test", "make test"),
1122 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1123 ("distcheck", "make distcheck"),
1124 ("clean", "make clean"),
1129 "git-clone-required": True,
1131 ("random-sleep", random_sleep(60, 600)),
1132 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}"),
1133 ("touch", "touch *.yp"),
1135 ("test", "make test"),
1136 ("install", "make install"),
1137 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm"),
1138 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1139 ("clean", "make clean"),
1143 # these are useful for debugging autobuild
1146 ("pass", 'echo passing && /bin/true'),
1151 ("fail", 'echo failing && /bin/false'),
1156 defaulttasks
= list(tasks
.keys())
1158 defaulttasks
.remove("pass")
1159 defaulttasks
.remove("fail")
1161 # The build tasks will be brought in by the test tasks as needed
1162 defaulttasks
.remove("samba-def-build")
1163 defaulttasks
.remove("samba-nt4-build")
1164 defaulttasks
.remove("samba-mit-build")
1165 defaulttasks
.remove("samba-h5l-build")
1166 defaulttasks
.remove("samba-no-opath-build")
1168 # This is not a normal test, but a task to support manually running
1169 # one test under autobuild
1170 defaulttasks
.remove("samba-test-only")
1172 # Only built on GitLab CI and not in the default autobuild because it
1173 # uses too much space (4GB of semi-static binaries)
1174 defaulttasks
.remove("samba-fuzz")
1176 # The FIPS build runs only in GitLab CI on a current Fedora Docker
1177 # container where a simulated FIPS mode is possible.
1178 defaulttasks
.remove("samba-fips")
1180 # The MIT build runs on a current Fedora where an up to date MIT KDC
1181 # is already packaged. This avoids needing to backport a current MIT
1182 # to the default Ubuntu 18.04, particularly during development, and
1183 # the need to install on the shared sn-devel-184.
1185 defaulttasks
.remove("samba-mitkrb5")
1186 defaulttasks
.remove("samba-admem-mit")
1187 defaulttasks
.remove("samba-addc-mit-1")
1188 defaulttasks
.remove("samba-addc-mit-4a")
1189 defaulttasks
.remove("samba-addc-mit-4b")
1191 defaulttasks
.remove("samba-32bit")
1193 if os
.environ
.get("AUTOBUILD_SKIP_SAMBA_O3", "0") == "1":
1194 defaulttasks
.remove("samba-o3")
1208 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
1210 do_debug("Running: '%s' in '%s'" % (cmd
, dir))
1212 do_print("Running: '%s' in '%s'" % (cmd
, dir))
1215 out
= check_output([cmd
], shell
=True, cwd
=dir)
1216 return out
.decode(encoding
='utf-8', errors
='backslashreplace')
1218 return check_call(cmd
, shell
=True, cwd
=dir)
1220 return call(cmd
, shell
=True, cwd
=dir)
1222 def rmdir_force(dirname
, re_raise
=True):
1224 run_cmd("test -d %s && chmod -R +w %s; rm -rf %s" % (
1225 dirname
, dirname
, dirname
), output
=True, show
=True)
1226 except CalledProcessError
as e
:
1227 do_print("Failed: '%s'" % (str(e
)))
1228 run_cmd("tree %s" % dirname
, output
=True, show
=True)
1234 class builder(object):
1235 '''handle build of one directory'''
1237 def __init__(self
, name
, definition
):
1239 self
.dir = builddirs
.get(name
, '.')
1240 self
.tag
= self
.name
.replace('/', '_')
1241 self
.definition
= definition
1242 self
.sequence
= definition
["sequence"]
1243 self
.git_clone_required
= False
1244 if "git-clone-required" in definition
:
1245 self
.git_clone_required
= bool(definition
["git-clone-required"])
1249 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
1250 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
1251 do_debug("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
1252 do_debug("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
1253 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
1254 self
.stdout
= open(self
.stdout_path
, 'w')
1255 self
.stderr
= open(self
.stderr_path
, 'w')
1256 self
.stdin
= open("/dev/null", 'r')
1257 self
.builder_dir
= "%s/%s" % (testbase
, self
.tag
)
1258 self
.test_source_dir
= self
.builder_dir
1259 self
.cwd
= "%s/%s" % (self
.builder_dir
, self
.dir)
1260 self
.selftest_prefix
= "%s/bin/ab" % (self
.cwd
)
1261 self
.prefix
= "%s/%s" % (test_prefix
, self
.tag
)
1263 self
.producer
= None
1265 if self
.git_clone_required
:
1266 assert "dependency" not in definition
1268 def mark_existing(self
):
1269 do_debug('%s: Mark as existing dependency' % self
.name
)
1270 self
.next
= len(self
.sequence
)
1273 def add_consumer(self
, consumer
):
1274 do_debug("%s: add consumer: %s" % (self
.name
, consumer
.name
))
1275 consumer
.producer
= self
1276 consumer
.test_source_dir
= self
.test_source_dir
1277 self
.consumers
.append(consumer
)
1279 def start_next(self
):
1280 if self
.producer
is not None:
1281 if not self
.producer
.done
:
1282 do_debug("%s: Waiting for producer: %s" % (self
.name
, self
.producer
.name
))
1286 rmdir_force(self
.builder_dir
)
1287 rmdir_force(self
.prefix
)
1288 if self
.producer
is not None:
1289 run_cmd("mkdir %s" % (self
.builder_dir
), dir=test_master
, show
=True)
1290 elif not self
.git_clone_required
:
1291 run_cmd("cp -R -a -l %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1293 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1295 if self
.next
== len(self
.sequence
):
1297 do_print('%s: Completed OK' % self
.name
)
1299 if not options
.nocleanup
and len(self
.consumers
) == 0:
1300 do_print('%s: Cleaning up' % self
.name
)
1301 rmdir_force(self
.builder_dir
)
1302 rmdir_force(self
.prefix
)
1303 for consumer
in self
.consumers
:
1304 if consumer
.next
!= 0:
1306 do_print('%s: Starting consumer %s' % (self
.name
, consumer
.name
))
1307 consumer
.start_next()
1308 if self
.producer
is not None:
1309 self
.producer
.consumers
.remove(self
)
1310 assert self
.producer
.done
1311 self
.producer
.start_next()
1312 do_print('%s: Remaining consumers %u' % (self
.name
, len(self
.consumers
)))
1314 (self
.stage
, self
.cmd
) = self
.sequence
[self
.next
]
1315 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}",
1316 get_path(name
='platlib',
1317 scheme
="posix_prefix",
1318 vars={"base": self
.prefix
,
1319 "platbase": self
.prefix
}))
1320 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
1321 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
1322 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
1323 self
.cmd
= self
.cmd
.replace("${TEST_SOURCE_DIR}", self
.test_source_dir
)
1324 self
.cmd
= self
.cmd
.replace("${SELFTEST_PREFIX}", self
.selftest_prefix
)
1325 self
.cmd
= self
.cmd
.replace("${LOG_BASE}", options
.log_base
)
1326 self
.cmd
= self
.cmd
.replace("${NAME}", self
.name
)
1327 self
.cmd
= self
.cmd
.replace("${ENABLE_COVERAGE}", options
.enable_coverage
)
1328 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, self
.cwd
))
1329 self
.proc
= Popen(self
.cmd
, shell
=True,
1330 close_fds
=True, cwd
=self
.cwd
,
1331 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
1334 def expand_dependencies(n
):
1336 if "dependency" in tasks
[n
]:
1337 depname
= tasks
[n
]["dependency"]
1338 assert depname
in tasks
1339 sdeps
= expand_dependencies(depname
)
1340 assert n
not in sdeps
1343 deps
.append(depname
)
1347 class buildlist(object):
1348 '''handle build of multiple directories'''
1350 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
1351 self
.tail_proc
= None
1354 if options
.restrict_tests
:
1355 tasknames
= ["samba-test-only"]
1357 tasknames
= defaulttasks
1359 given_tasknames
= tasknames
.copy()
1360 implicit_tasknames
= []
1361 for n
in given_tasknames
:
1362 deps
= expand_dependencies(n
)
1364 if dep
in given_tasknames
:
1366 if dep
in implicit_tasknames
:
1368 implicit_tasknames
.append(dep
)
1370 tasknames
= implicit_tasknames
.copy()
1371 tasknames
.extend(given_tasknames
)
1372 do_debug("given_tasknames: %s" % given_tasknames
)
1373 do_debug("implicit_tasknames: %s" % implicit_tasknames
)
1374 do_debug("tasknames: %s" % tasknames
)
1375 self
.tlist
= [builder(n
, tasks
[n
]) for n
in tasknames
]
1378 rebase_remote
= "rebaseon"
1380 "git-clone-required": True,
1384 git remote add -t %s %s %s
1388 git describe %s/%s > old_remote_branch.desc
1390 git describe %s/%s > remote_branch.desc
1391 diff old_remote_branch.desc remote_branch.desc
1394 rebase_branch
, rebase_remote
, rebase_url
,
1396 rebase_remote
, rebase_branch
,
1398 rebase_remote
, rebase_branch
1401 self
.retry
= builder('retry', retry_task
)
1402 self
.need_retry
= False
1404 if options
.skip_dependencies
:
1405 for b
in self
.tlist
:
1406 if b
.name
in implicit_tasknames
:
1409 for b
in self
.tlist
:
1410 do_debug("b.name=%s" % b
.name
)
1411 if "dependency" not in b
.definition
:
1413 depname
= b
.definition
["dependency"]
1414 do_debug("b.name=%s: dependency:%s" % (b
.name
, depname
))
1415 for p
in self
.tlist
:
1416 if p
.name
== depname
:
1419 def kill_kids(self
):
1420 if self
.tail_proc
is not None:
1421 self
.tail_proc
.terminate()
1422 self
.tail_proc
.wait()
1423 self
.tail_proc
= None
1424 if self
.retry
is not None:
1425 self
.retry
.proc
.terminate()
1426 self
.retry
.proc
.wait()
1428 for b
in self
.tlist
:
1429 if b
.proc
is not None:
1430 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.test_source_dir
, checkfail
=False)
1438 for b
in self
.tlist
:
1441 none_running
= False
1442 b
.status
= b
.proc
.poll()
1443 if b
.status
is None:
1448 ret
= self
.retry
.proc
.poll()
1450 self
.need_retry
= True
1458 for b
in self
.tlist
:
1461 self
.retry
.start_next()
1464 if options
.retry
and self
.need_retry
:
1466 do_print("retry needed")
1467 return (0, None, None, None, "retry")
1470 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
1472 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
1475 return (0, None, None, None, "All OK")
1477 def write_system_info(self
, filename
):
1478 with
open(filename
, 'w') as f
:
1479 for cmd
in ['uname -a',
1483 'cat /proc/cpuinfo',
1486 'df -m %s' % testbase
]:
1488 out
= run_cmd(cmd
, output
=True, checkfail
=False)
1489 except CalledProcessError
as e
:
1490 out
= "<failed: %s>" % str(e
)
1491 print('### %s' % cmd
, file=f
)
1495 def tarlogs(self
, fname
):
1496 with tarfile
.open(fname
, "w:gz") as tar
:
1497 for b
in self
.tlist
:
1498 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
1499 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
1500 if os
.path
.exists("autobuild.log"):
1501 tar
.add("autobuild.log")
1502 filename
= 'system-info.txt'
1503 self
.write_system_info(filename
)
1506 def remove_logs(self
):
1507 for b
in self
.tlist
:
1508 os
.unlink(b
.stdout_path
)
1509 os
.unlink(b
.stderr_path
)
1511 def start_tail(self
):
1512 cmd
= ["tail", "-f"]
1513 for b
in self
.tlist
:
1514 cmd
.append(b
.stdout_path
)
1515 cmd
.append(b
.stderr_path
)
1516 self
.tail_proc
= Popen(cmd
, close_fds
=True)
1519 def cleanup(do_raise
=False):
1520 if options
.nocleanup
:
1522 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
1523 run_cmd("stat %s" % testbase
, show
=True)
1524 do_print("Cleaning up %r" % cleanup_list
)
1525 for d
in cleanup_list
:
1526 ok
= rmdir_force(d
, re_raise
=False)
1529 if os
.path
.isdir(d
):
1530 do_print("Killing, waiting and retry")
1531 run_cmd("killbysubdir %s > /dev/null 2>&1" % d
, checkfail
=False)
1533 do_print("Waiting and retry")
1535 rmdir_force(d
, re_raise
=do_raise
)
1538 def daemonize(logfile
):
1540 if pid
== 0: # Parent
1543 if pid
!= 0: # Actual daemon
1548 import resource
# Resource usage information.
1549 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
1550 if maxfd
== resource
.RLIM_INFINITY
:
1551 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
1552 for fd
in range(0, maxfd
):
1557 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
1562 def write_pidfile(fname
):
1563 '''write a pid file, cleanup on exit'''
1564 with
open(fname
, mode
='w') as f
:
1565 f
.write("%u\n" % os
.getpid())
1568 def rebase_tree(rebase_url
, rebase_branch
="master"):
1569 rebase_remote
= "rebaseon"
1570 do_print("Rebasing on %s" % rebase_url
)
1571 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1572 run_cmd("git remote add -t %s %s %s" %
1573 (rebase_branch
, rebase_remote
, rebase_url
),
1574 show
=True, dir=test_master
)
1575 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
1576 if options
.fix_whitespace
:
1577 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
1578 (rebase_remote
, rebase_branch
),
1579 show
=True, dir=test_master
)
1581 run_cmd("git rebase --force-rebase %s/%s" %
1582 (rebase_remote
, rebase_branch
),
1583 show
=True, dir=test_master
)
1584 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
1585 (rebase_remote
, rebase_branch
),
1586 dir=test_master
, output
=True)
1588 do_print("No differences between HEAD and %s/%s - exiting" %
1589 (rebase_remote
, rebase_branch
))
1591 run_cmd("git describe %s/%s" %
1592 (rebase_remote
, rebase_branch
),
1593 show
=True, dir=test_master
)
1594 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1595 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
1596 (rebase_remote
, rebase_branch
),
1597 show
=True, dir=test_master
)
1600 def push_to(push_url
, push_branch
="master"):
1601 push_remote
= "pushto"
1602 do_print("Pushing to %s" % push_url
)
1604 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
1605 run_cmd("git commit --amend -c HEAD", dir=test_master
)
1606 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
1607 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
1608 run_cmd("git remote add -t %s %s %s" %
1609 (push_branch
, push_remote
, push_url
),
1610 show
=True, dir=test_master
)
1611 run_cmd("git push %s +HEAD:%s" %
1612 (push_remote
, push_branch
),
1613 show
=True, dir=test_master
)
1616 def send_email(subject
, text
, log_tar
):
1617 if options
.email
is None:
1618 do_print("not sending email because the recipient is not set")
1619 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
1622 outer
= MIMEMultipart()
1623 outer
['Subject'] = subject
1624 outer
['To'] = options
.email
1625 outer
['From'] = options
.email_from
1626 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
1627 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
1628 outer
.attach(MIMEText(text
, 'plain', 'utf-8'))
1629 if options
.attach_logs
:
1630 with
open(log_tar
, 'rb') as fp
:
1631 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
1632 # Set the filename parameter
1633 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
1635 content
= outer
.as_string()
1636 s
= smtplib
.SMTP(options
.email_server
)
1637 email_user
= os
.getenv('SMTP_USERNAME')
1638 email_password
= os
.getenv('SMTP_PASSWORD')
1639 if email_user
is not None:
1641 s
.login(email_user
, email_password
)
1643 s
.sendmail(options
.email_from
, [options
.email
], content
)
1648 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1649 elapsed_time
, log_base
=None, add_log_tail
=True):
1650 '''send an email to options.email about the failure'''
1651 elapsed_minutes
= elapsed_time
/ 60.0
1652 if log_base
is None:
1657 Your autobuild on %s failed after %.1f minutes
1658 when trying to test %s with the following error:
1662 the autobuild has been abandoned. Please fix the error and resubmit.
1664 A summary of the autobuild process is here:
1667 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
1669 if options
.restrict_tests
:
1671 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1673 if failed_task
!= 'rebase':
1675 You can see logs of the failed task here:
1680 or you can get full logs of all tasks in this job here:
1684 The top commit for the tree that was built was:
1688 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
1690 log_stdout
= "%s/%s.stdout" % (gitroot
, failed_tag
)
1691 if add_log_tail
and os
.access(log_stdout
, os
.R_OK
):
1692 f
= open(log_stdout
, 'r')
1693 lines
= f
.readlines()
1694 log_tail
= "".join(lines
[-50:])
1695 num_lines
= len(lines
)
1696 log_stderr
= "%s/%s.stderr" % (gitroot
, failed_tag
)
1697 if num_lines
< 50 and os
.access(log_stderr
, os
.R_OK
):
1698 # Also include stderr (compile failures) if < 50 lines of stdout
1699 f
= open(log_stderr
, 'r')
1700 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
1703 The last 50 lines of log messages:
1709 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1710 send_email('autobuild[%s] failure on %s for task %s during %s'
1711 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
1715 def email_success(elapsed_time
, log_base
=None):
1716 '''send an email to options.email about a successful build'''
1717 if log_base
is None:
1722 Your autobuild on %s has succeeded after %.1f minutes.
1724 ''' % (platform
.node(), elapsed_time
/ 60.)
1726 if options
.restrict_tests
:
1728 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1730 if options
.keeplogs
:
1733 you can get full logs of all tasks in this job here:
1740 The top commit for the tree that was built was:
1743 ''' % top_commit_msg
1745 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1746 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
1750 # get the top commit message, for emails
1751 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
1754 if options
.skip_dependencies
:
1755 run_cmd("stat %s" % testbase
, dir=testbase
, output
=True)
1757 os
.makedirs(testbase
)
1758 except Exception as reason
:
1759 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
1760 cleanup_list
.append(testbase
)
1763 logfile
= os
.path
.join(testbase
, "log")
1764 do_print("Forking into the background, writing progress to %s" % logfile
)
1767 write_pidfile(gitroot
+ "/autobuild.pid")
1769 start_time
= time
.time()
1773 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
1774 os
.makedirs(test_tmpdir
)
1775 # The waf uninstall code removes empty directories all the way
1776 # up the tree. Creating a file in test_tmpdir stops it from
1778 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
1779 ".directory-is-not-empty"), show
=True)
1780 run_cmd("stat %s" % test_tmpdir
, show
=True)
1781 run_cmd("stat %s" % testbase
, show
=True)
1782 if options
.skip_dependencies
:
1783 run_cmd("stat %s" % test_master
, dir=testbase
, output
=True)
1785 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
1791 if options
.rebase
is not None:
1792 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
1794 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1796 elapsed_time
= time
.time() - start_time
1797 email_failure(-1, 'rebase', 'rebase', 'rebase',
1798 'rebase on %s failed' % options
.branch
,
1799 elapsed_time
, log_base
=options
.log_base
)
1803 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1806 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1807 if status
!= 0 or errstr
!= "retry":
1809 cleanup(do_raise
=True)
1814 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1820 do_print("waiting for tail to flush")
1823 elapsed_time
= time
.time() - start_time
1825 if options
.passcmd
is not None:
1826 do_print("Running passcmd: %s" % options
.passcmd
)
1827 run_cmd(options
.passcmd
, dir=test_master
)
1828 if options
.pushto
is not None:
1829 push_to(options
.pushto
, push_branch
=options
.branch
)
1830 if options
.keeplogs
or options
.attach_logs
:
1831 blist
.tarlogs("logs.tar.gz")
1832 do_print("Logs in logs.tar.gz")
1833 if options
.always_email
:
1834 email_success(elapsed_time
, log_base
=options
.log_base
)
1840 # something failed, gather a tar of the logs
1841 blist
.tarlogs("logs.tar.gz")
1843 if options
.email
is not None:
1844 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1845 elapsed_time
, log_base
=options
.log_base
)
1847 elapsed_minutes
= elapsed_time
/ 60.0
1850 ####################################################################
1854 Your autobuild[%s] on %s failed after %.1f minutes
1855 when trying to test %s with the following error:
1859 the autobuild has been abandoned. Please fix the error and resubmit.
1861 ####################################################################
1863 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1867 do_print("Logs in logs.tar.gz")