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-shellcheck": {
1047 ("run", "script/check-shell-scripts.sh ."),
1053 ("random-sleep", random_sleep(60, 600)),
1054 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1056 ("install", "make install"),
1057 ("test", "make test"),
1059 ("clean", "make clean"),
1060 ("configure-no-lmdb", "./configure ${ENABLE_COVERAGE} --enable-developer --without-ldb-lmdb -C ${PREFIX}"),
1061 ("make-no-lmdb", "make"),
1062 ("test-no-lmdb", "make test"),
1063 ("lcov-no-lmdb", LCOV_CMD
),
1064 ("install-no-lmdb", "make install"),
1065 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1066 ("distcheck", "make distcheck"),
1067 ("clean", "make clean"),
1073 ("random-sleep", random_sleep(60, 600)),
1074 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1076 ("install", "make install"),
1077 ("test", "make test"),
1079 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1080 ("distcheck", "make distcheck"),
1081 ("clean", "make clean"),
1087 ("random-sleep", random_sleep(60, 600)),
1088 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1090 ("install", "make install"),
1091 ("test", "make test"),
1093 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1094 ("distcheck", "make distcheck"),
1095 ("clean", "make clean"),
1101 ("random-sleep", random_sleep(60, 600)),
1102 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1104 ("install", "make install"),
1105 ("test", "make test"),
1107 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1108 ("distcheck", "make distcheck"),
1109 ("clean", "make clean"),
1115 ("random-sleep", random_sleep(60, 600)),
1116 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1118 ("install", "make install"),
1119 ("test", "make test"),
1121 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1122 ("distcheck", "make distcheck"),
1123 ("clean", "make clean"),
1128 "git-clone-required": True,
1130 ("random-sleep", random_sleep(60, 600)),
1131 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}"),
1132 ("touch", "touch *.yp"),
1134 ("test", "make test"),
1135 ("install", "make install"),
1136 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm"),
1137 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1138 ("clean", "make clean"),
1142 # these are useful for debugging autobuild
1145 ("pass", 'echo passing && /bin/true'),
1150 ("fail", 'echo failing && /bin/false'),
1155 defaulttasks
= list(tasks
.keys())
1157 defaulttasks
.remove("pass")
1158 defaulttasks
.remove("fail")
1160 # The build tasks will be brought in by the test tasks as needed
1161 defaulttasks
.remove("samba-def-build")
1162 defaulttasks
.remove("samba-nt4-build")
1163 defaulttasks
.remove("samba-mit-build")
1164 defaulttasks
.remove("samba-h5l-build")
1165 defaulttasks
.remove("samba-no-opath-build")
1167 # This is not a normal test, but a task to support manually running
1168 # one test under autobuild
1169 defaulttasks
.remove("samba-test-only")
1171 # Only built on GitLab CI and not in the default autobuild because it
1172 # uses too much space (4GB of semi-static binaries)
1173 defaulttasks
.remove("samba-fuzz")
1175 # The FIPS build runs only in GitLab CI on a current Fedora Docker
1176 # container where a simulated FIPS mode is possible.
1177 defaulttasks
.remove("samba-fips")
1179 # The MIT build runs on a current Fedora where an up to date MIT KDC
1180 # is already packaged. This avoids needing to backport a current MIT
1181 # to the default Ubuntu 18.04, particularly during development, and
1182 # the need to install on the shared sn-devel-184.
1184 defaulttasks
.remove("samba-mitkrb5")
1185 defaulttasks
.remove("samba-admem-mit")
1186 defaulttasks
.remove("samba-addc-mit-1")
1187 defaulttasks
.remove("samba-addc-mit-4a")
1188 defaulttasks
.remove("samba-addc-mit-4b")
1190 defaulttasks
.remove("samba-32bit")
1192 if os
.environ
.get("AUTOBUILD_SKIP_SAMBA_O3", "0") == "1":
1193 defaulttasks
.remove("samba-o3")
1207 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
1209 do_debug("Running: '%s' in '%s'" % (cmd
, dir))
1211 do_print("Running: '%s' in '%s'" % (cmd
, dir))
1214 out
= check_output([cmd
], shell
=True, cwd
=dir)
1215 return out
.decode(encoding
='utf-8', errors
='backslashreplace')
1217 return check_call(cmd
, shell
=True, cwd
=dir)
1219 return call(cmd
, shell
=True, cwd
=dir)
1221 def rmdir_force(dirname
, re_raise
=True):
1223 run_cmd("test -d %s && chmod -R +w %s; rm -rf %s" % (
1224 dirname
, dirname
, dirname
), output
=True, show
=True)
1225 except CalledProcessError
as e
:
1226 do_print("Failed: '%s'" % (str(e
)))
1227 run_cmd("tree %s" % dirname
, output
=True, show
=True)
1233 class builder(object):
1234 '''handle build of one directory'''
1236 def __init__(self
, name
, definition
):
1238 self
.dir = builddirs
.get(name
, '.')
1239 self
.tag
= self
.name
.replace('/', '_')
1240 self
.definition
= definition
1241 self
.sequence
= definition
["sequence"]
1242 self
.git_clone_required
= False
1243 if "git-clone-required" in definition
:
1244 self
.git_clone_required
= bool(definition
["git-clone-required"])
1248 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
1249 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
1250 do_debug("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
1251 do_debug("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
1252 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
1253 self
.stdout
= open(self
.stdout_path
, 'w')
1254 self
.stderr
= open(self
.stderr_path
, 'w')
1255 self
.stdin
= open("/dev/null", 'r')
1256 self
.builder_dir
= "%s/%s" % (testbase
, self
.tag
)
1257 self
.test_source_dir
= self
.builder_dir
1258 self
.cwd
= "%s/%s" % (self
.builder_dir
, self
.dir)
1259 self
.selftest_prefix
= "%s/bin/ab" % (self
.cwd
)
1260 self
.prefix
= "%s/%s" % (test_prefix
, self
.tag
)
1262 self
.producer
= None
1264 if self
.git_clone_required
:
1265 assert "dependency" not in definition
1267 def mark_existing(self
):
1268 do_debug('%s: Mark as existing dependency' % self
.name
)
1269 self
.next
= len(self
.sequence
)
1272 def add_consumer(self
, consumer
):
1273 do_debug("%s: add consumer: %s" % (self
.name
, consumer
.name
))
1274 consumer
.producer
= self
1275 consumer
.test_source_dir
= self
.test_source_dir
1276 self
.consumers
.append(consumer
)
1278 def start_next(self
):
1279 if self
.producer
is not None:
1280 if not self
.producer
.done
:
1281 do_debug("%s: Waiting for producer: %s" % (self
.name
, self
.producer
.name
))
1285 rmdir_force(self
.builder_dir
)
1286 rmdir_force(self
.prefix
)
1287 if self
.producer
is not None:
1288 run_cmd("mkdir %s" % (self
.builder_dir
), dir=test_master
, show
=True)
1289 elif not self
.git_clone_required
:
1290 run_cmd("cp -R -a -l %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1292 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1294 if self
.next
== len(self
.sequence
):
1296 do_print('%s: Completed OK' % self
.name
)
1298 if not options
.nocleanup
and len(self
.consumers
) == 0:
1299 do_print('%s: Cleaning up' % self
.name
)
1300 rmdir_force(self
.builder_dir
)
1301 rmdir_force(self
.prefix
)
1302 for consumer
in self
.consumers
:
1303 if consumer
.next
!= 0:
1305 do_print('%s: Starting consumer %s' % (self
.name
, consumer
.name
))
1306 consumer
.start_next()
1307 if self
.producer
is not None:
1308 self
.producer
.consumers
.remove(self
)
1309 assert self
.producer
.done
1310 self
.producer
.start_next()
1311 do_print('%s: Remaining consumers %u' % (self
.name
, len(self
.consumers
)))
1313 (self
.stage
, self
.cmd
) = self
.sequence
[self
.next
]
1314 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}",
1315 get_path(name
='platlib',
1316 scheme
="posix_prefix",
1317 vars={"base": self
.prefix
,
1318 "platbase": self
.prefix
}))
1319 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
1320 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
1321 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
1322 self
.cmd
= self
.cmd
.replace("${TEST_SOURCE_DIR}", self
.test_source_dir
)
1323 self
.cmd
= self
.cmd
.replace("${SELFTEST_PREFIX}", self
.selftest_prefix
)
1324 self
.cmd
= self
.cmd
.replace("${LOG_BASE}", options
.log_base
)
1325 self
.cmd
= self
.cmd
.replace("${NAME}", self
.name
)
1326 self
.cmd
= self
.cmd
.replace("${ENABLE_COVERAGE}", options
.enable_coverage
)
1327 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, self
.cwd
))
1328 self
.proc
= Popen(self
.cmd
, shell
=True,
1329 close_fds
=True, cwd
=self
.cwd
,
1330 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
1333 def expand_dependencies(n
):
1335 if "dependency" in tasks
[n
]:
1336 depname
= tasks
[n
]["dependency"]
1337 assert depname
in tasks
1338 sdeps
= expand_dependencies(depname
)
1339 assert n
not in sdeps
1342 deps
.append(depname
)
1346 class buildlist(object):
1347 '''handle build of multiple directories'''
1349 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
1350 self
.tail_proc
= None
1353 if options
.restrict_tests
:
1354 tasknames
= ["samba-test-only"]
1356 tasknames
= defaulttasks
1358 given_tasknames
= tasknames
.copy()
1359 implicit_tasknames
= []
1360 for n
in given_tasknames
:
1361 deps
= expand_dependencies(n
)
1363 if dep
in given_tasknames
:
1365 if dep
in implicit_tasknames
:
1367 implicit_tasknames
.append(dep
)
1369 tasknames
= implicit_tasknames
.copy()
1370 tasknames
.extend(given_tasknames
)
1371 do_debug("given_tasknames: %s" % given_tasknames
)
1372 do_debug("implicit_tasknames: %s" % implicit_tasknames
)
1373 do_debug("tasknames: %s" % tasknames
)
1374 self
.tlist
= [builder(n
, tasks
[n
]) for n
in tasknames
]
1377 rebase_remote
= "rebaseon"
1379 "git-clone-required": True,
1383 git remote add -t %s %s %s
1387 git describe %s/%s > old_remote_branch.desc
1389 git describe %s/%s > remote_branch.desc
1390 diff old_remote_branch.desc remote_branch.desc
1393 rebase_branch
, rebase_remote
, rebase_url
,
1395 rebase_remote
, rebase_branch
,
1397 rebase_remote
, rebase_branch
1400 self
.retry
= builder('retry', retry_task
)
1401 self
.need_retry
= False
1403 if options
.skip_dependencies
:
1404 for b
in self
.tlist
:
1405 if b
.name
in implicit_tasknames
:
1408 for b
in self
.tlist
:
1409 do_debug("b.name=%s" % b
.name
)
1410 if "dependency" not in b
.definition
:
1412 depname
= b
.definition
["dependency"]
1413 do_debug("b.name=%s: dependency:%s" % (b
.name
, depname
))
1414 for p
in self
.tlist
:
1415 if p
.name
== depname
:
1418 def kill_kids(self
):
1419 if self
.tail_proc
is not None:
1420 self
.tail_proc
.terminate()
1421 self
.tail_proc
.wait()
1422 self
.tail_proc
= None
1423 if self
.retry
is not None:
1424 self
.retry
.proc
.terminate()
1425 self
.retry
.proc
.wait()
1427 for b
in self
.tlist
:
1428 if b
.proc
is not None:
1429 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.test_source_dir
, checkfail
=False)
1437 for b
in self
.tlist
:
1440 none_running
= False
1441 b
.status
= b
.proc
.poll()
1442 if b
.status
is None:
1447 ret
= self
.retry
.proc
.poll()
1449 self
.need_retry
= True
1457 for b
in self
.tlist
:
1460 self
.retry
.start_next()
1463 if options
.retry
and self
.need_retry
:
1465 do_print("retry needed")
1466 return (0, None, None, None, "retry")
1469 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
1471 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
1474 return (0, None, None, None, "All OK")
1476 def write_system_info(self
, filename
):
1477 with
open(filename
, 'w') as f
:
1478 for cmd
in ['uname -a',
1482 'cat /proc/cpuinfo',
1485 'df -m %s' % testbase
]:
1487 out
= run_cmd(cmd
, output
=True, checkfail
=False)
1488 except CalledProcessError
as e
:
1489 out
= "<failed: %s>" % str(e
)
1490 print('### %s' % cmd
, file=f
)
1494 def tarlogs(self
, fname
):
1495 with tarfile
.open(fname
, "w:gz") as tar
:
1496 for b
in self
.tlist
:
1497 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
1498 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
1499 if os
.path
.exists("autobuild.log"):
1500 tar
.add("autobuild.log")
1501 filename
= 'system-info.txt'
1502 self
.write_system_info(filename
)
1505 def remove_logs(self
):
1506 for b
in self
.tlist
:
1507 os
.unlink(b
.stdout_path
)
1508 os
.unlink(b
.stderr_path
)
1510 def start_tail(self
):
1511 cmd
= ["tail", "-f"]
1512 for b
in self
.tlist
:
1513 cmd
.append(b
.stdout_path
)
1514 cmd
.append(b
.stderr_path
)
1515 self
.tail_proc
= Popen(cmd
, close_fds
=True)
1518 def cleanup(do_raise
=False):
1519 if options
.nocleanup
:
1521 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
1522 run_cmd("stat %s" % testbase
, show
=True)
1523 do_print("Cleaning up %r" % cleanup_list
)
1524 for d
in cleanup_list
:
1525 ok
= rmdir_force(d
, re_raise
=False)
1528 if os
.path
.isdir(d
):
1529 do_print("Killing, waiting and retry")
1530 run_cmd("killbysubdir %s > /dev/null 2>&1" % d
, checkfail
=False)
1532 do_print("Waiting and retry")
1534 rmdir_force(d
, re_raise
=do_raise
)
1537 def daemonize(logfile
):
1539 if pid
== 0: # Parent
1542 if pid
!= 0: # Actual daemon
1547 import resource
# Resource usage information.
1548 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
1549 if maxfd
== resource
.RLIM_INFINITY
:
1550 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
1551 for fd
in range(0, maxfd
):
1556 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
1561 def write_pidfile(fname
):
1562 '''write a pid file, cleanup on exit'''
1563 with
open(fname
, mode
='w') as f
:
1564 f
.write("%u\n" % os
.getpid())
1567 def rebase_tree(rebase_url
, rebase_branch
="master"):
1568 rebase_remote
= "rebaseon"
1569 do_print("Rebasing on %s" % rebase_url
)
1570 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1571 run_cmd("git remote add -t %s %s %s" %
1572 (rebase_branch
, rebase_remote
, rebase_url
),
1573 show
=True, dir=test_master
)
1574 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
1575 if options
.fix_whitespace
:
1576 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
1577 (rebase_remote
, rebase_branch
),
1578 show
=True, dir=test_master
)
1580 run_cmd("git rebase --force-rebase %s/%s" %
1581 (rebase_remote
, rebase_branch
),
1582 show
=True, dir=test_master
)
1583 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
1584 (rebase_remote
, rebase_branch
),
1585 dir=test_master
, output
=True)
1587 do_print("No differences between HEAD and %s/%s - exiting" %
1588 (rebase_remote
, rebase_branch
))
1590 run_cmd("git describe %s/%s" %
1591 (rebase_remote
, rebase_branch
),
1592 show
=True, dir=test_master
)
1593 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1594 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
1595 (rebase_remote
, rebase_branch
),
1596 show
=True, dir=test_master
)
1599 def push_to(push_url
, push_branch
="master"):
1600 push_remote
= "pushto"
1601 do_print("Pushing to %s" % push_url
)
1603 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
1604 run_cmd("git commit --amend -c HEAD", dir=test_master
)
1605 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
1606 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
1607 run_cmd("git remote add -t %s %s %s" %
1608 (push_branch
, push_remote
, push_url
),
1609 show
=True, dir=test_master
)
1610 run_cmd("git push %s +HEAD:%s" %
1611 (push_remote
, push_branch
),
1612 show
=True, dir=test_master
)
1615 def send_email(subject
, text
, log_tar
):
1616 if options
.email
is None:
1617 do_print("not sending email because the recipient is not set")
1618 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
1621 outer
= MIMEMultipart()
1622 outer
['Subject'] = subject
1623 outer
['To'] = options
.email
1624 outer
['From'] = options
.email_from
1625 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
1626 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
1627 outer
.attach(MIMEText(text
, 'plain', 'utf-8'))
1628 if options
.attach_logs
:
1629 with
open(log_tar
, 'rb') as fp
:
1630 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
1631 # Set the filename parameter
1632 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
1634 content
= outer
.as_string()
1635 s
= smtplib
.SMTP(options
.email_server
)
1636 email_user
= os
.getenv('SMTP_USERNAME')
1637 email_password
= os
.getenv('SMTP_PASSWORD')
1638 if email_user
is not None:
1640 s
.login(email_user
, email_password
)
1642 s
.sendmail(options
.email_from
, [options
.email
], content
)
1647 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1648 elapsed_time
, log_base
=None, add_log_tail
=True):
1649 '''send an email to options.email about the failure'''
1650 elapsed_minutes
= elapsed_time
/ 60.0
1651 if log_base
is None:
1656 Your autobuild on %s failed after %.1f minutes
1657 when trying to test %s with the following error:
1661 the autobuild has been abandoned. Please fix the error and resubmit.
1663 A summary of the autobuild process is here:
1666 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
1668 if options
.restrict_tests
:
1670 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1672 if failed_task
!= 'rebase':
1674 You can see logs of the failed task here:
1679 or you can get full logs of all tasks in this job here:
1683 The top commit for the tree that was built was:
1687 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
1689 log_stdout
= "%s/%s.stdout" % (gitroot
, failed_tag
)
1690 if add_log_tail
and os
.access(log_stdout
, os
.R_OK
):
1691 f
= open(log_stdout
, 'r')
1692 lines
= f
.readlines()
1693 log_tail
= "".join(lines
[-50:])
1694 num_lines
= len(lines
)
1695 log_stderr
= "%s/%s.stderr" % (gitroot
, failed_tag
)
1696 if num_lines
< 50 and os
.access(log_stderr
, os
.R_OK
):
1697 # Also include stderr (compile failures) if < 50 lines of stdout
1698 f
= open(log_stderr
, 'r')
1699 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
1702 The last 50 lines of log messages:
1708 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1709 send_email('autobuild[%s] failure on %s for task %s during %s'
1710 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
1714 def email_success(elapsed_time
, log_base
=None):
1715 '''send an email to options.email about a successful build'''
1716 if log_base
is None:
1721 Your autobuild on %s has succeeded after %.1f minutes.
1723 ''' % (platform
.node(), elapsed_time
/ 60.)
1725 if options
.restrict_tests
:
1727 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1729 if options
.keeplogs
:
1732 you can get full logs of all tasks in this job here:
1739 The top commit for the tree that was built was:
1742 ''' % top_commit_msg
1744 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1745 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
1749 # get the top commit message, for emails
1750 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
1753 if options
.skip_dependencies
:
1754 run_cmd("stat %s" % testbase
, dir=testbase
, output
=True)
1756 os
.makedirs(testbase
)
1757 except Exception as reason
:
1758 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
1759 cleanup_list
.append(testbase
)
1762 logfile
= os
.path
.join(testbase
, "log")
1763 do_print("Forking into the background, writing progress to %s" % logfile
)
1766 write_pidfile(gitroot
+ "/autobuild.pid")
1768 start_time
= time
.time()
1772 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
1773 os
.makedirs(test_tmpdir
)
1774 # The waf uninstall code removes empty directories all the way
1775 # up the tree. Creating a file in test_tmpdir stops it from
1777 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
1778 ".directory-is-not-empty"), show
=True)
1779 run_cmd("stat %s" % test_tmpdir
, show
=True)
1780 run_cmd("stat %s" % testbase
, show
=True)
1781 if options
.skip_dependencies
:
1782 run_cmd("stat %s" % test_master
, dir=testbase
, output
=True)
1784 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
1790 if options
.rebase
is not None:
1791 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
1793 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1795 elapsed_time
= time
.time() - start_time
1796 email_failure(-1, 'rebase', 'rebase', 'rebase',
1797 'rebase on %s failed' % options
.branch
,
1798 elapsed_time
, log_base
=options
.log_base
)
1802 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1805 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1806 if status
!= 0 or errstr
!= "retry":
1808 cleanup(do_raise
=True)
1813 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1819 do_print("waiting for tail to flush")
1822 elapsed_time
= time
.time() - start_time
1824 if options
.passcmd
is not None:
1825 do_print("Running passcmd: %s" % options
.passcmd
)
1826 run_cmd(options
.passcmd
, dir=test_master
)
1827 if options
.pushto
is not None:
1828 push_to(options
.pushto
, push_branch
=options
.branch
)
1829 if options
.keeplogs
or options
.attach_logs
:
1830 blist
.tarlogs("logs.tar.gz")
1831 do_print("Logs in logs.tar.gz")
1832 if options
.always_email
:
1833 email_success(elapsed_time
, log_base
=options
.log_base
)
1839 # something failed, gather a tar of the logs
1840 blist
.tarlogs("logs.tar.gz")
1842 if options
.email
is not None:
1843 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1844 elapsed_time
, log_base
=options
.log_base
)
1846 elapsed_minutes
= elapsed_time
/ 60.0
1849 ####################################################################
1853 Your autobuild[%s] on %s failed after %.1f minutes
1854 when trying to test %s with the following error:
1858 the autobuild has been abandoned. Please fix the error and resubmit.
1860 ####################################################################
1862 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1866 do_print("Logs in logs.tar.gz")