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 -DDISABLE_VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS=1 -DDISABLE_PROC_FDS=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",
337 "ad_member_idmap_nss",
344 "fileserver_smb1_done",
358 "ad_dc_default_smb1",
359 "ad_dc_default_smb1_done",
367 ("test-slow-none", make_test(cmd
='make test', TESTS
="--include=selftest/slow-none", include_envs
=["none"])),
369 ("install", "make install"),
370 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
371 ("clean", "make clean"),
375 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
378 ("random-sleep", random_sleep(300, 900)),
379 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
381 ("test", make_test(exclude_envs
=[
394 "ad_dc_default_smb1",
395 "ad_dc_default_smb1_done",
403 "ad_member_idmap_rid",
404 "admem_idmap_autorid",
405 "ad_member_idmap_ad",
407 "ad_member_idmap_nss",
414 "fileserver_smb1_done",
428 "ad_dc_default_smb1",
429 "ad_dc_default_smb1_done",
438 ("install", "make install"),
439 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
440 ("clean", "make clean"),
445 "dependency": "samba-nt4-build",
447 ("random-sleep", random_sleep(300, 900)),
448 ("test", make_test(include_envs
=[
457 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
461 "samba-fileserver": {
462 "dependency": "samba-h5l-build",
464 ("random-sleep", random_sleep(300, 900)),
465 ("test", make_test(include_envs
=[
468 "fileserver_smb1_done",
470 "ktest", # ktest is also tested in samba-ktest-mit samba
471 # and samba-mitkrb5 but is tested here against
475 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
479 "samba-fileserver-without-smb1": {
480 "dependency": "samba-without-smb1-build",
482 ("random-sleep", random_sleep(300, 900)),
483 ("test", make_test(include_envs
=["fileserver"])),
485 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
489 # This is a full build without the AD DC so we test the build with
490 # MIT Kerberos from the current system. Runtime behaviour is
491 # confirmed via the ktest (static ccache and keytab) environment
493 # This environment also used to confirm we can still build with --with-libunwind
496 ("random-sleep", random_sleep(300, 900)),
497 ("configure", "./configure.developer --without-ad-dc --with-libunwind --with-system-mitkrb5 " + samba_configure_params
),
499 ("test", make_test(include_envs
=[
500 "ktest", # ktest is also tested in fileserver, samba and
501 # samba-mitkrb5 but is tested here against a
505 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
510 "dependency": "samba-def-build",
512 ("random-sleep", random_sleep(300, 900)),
513 ("test", make_test(include_envs
=[
515 "ad_member_idmap_rid",
516 "admem_idmap_autorid",
517 "ad_member_idmap_ad",
519 "ad_member_idmap_nss",
520 "ad_member_offlogon",
523 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
528 "dependency": "samba-no-opath-build",
530 ("random-sleep", random_sleep(300, 900)),
532 cmd
="make testonly DISABLE_OPATH=1",
542 ("check-clean-tree", "script/clean-source-tree.sh"),
547 "dependency": "samba-no-opath-build",
549 ("random-sleep", random_sleep(300, 900)),
551 cmd
="make testonly DISABLE_OPATH=1",
555 "fileserver_smb1_done",
558 ("check-clean-tree", "script/clean-source-tree.sh"),
563 "dependency": "samba-def-build",
565 ("random-sleep", random_sleep(1, 1)),
566 ("test", make_test(include_envs
=[
574 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
579 "dependency": "samba-def-build",
581 ("random-sleep", random_sleep(1, 1)),
582 ("test", make_test(include_envs
=[
588 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
593 "dependency": "samba-def-build",
595 ("random-sleep", random_sleep(1, 1)),
596 ("test", make_test(include_envs
=[
603 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
608 "dependency": "samba-def-build",
610 ("random-sleep", random_sleep(1, 1)),
611 ("test", make_test(include_envs
=[
617 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
621 "dependency": "samba-def-build",
623 ("random-sleep", random_sleep(1, 1)),
624 ("test", make_test(include_envs
=[
629 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
634 "dependency": "samba-def-build",
636 ("random-sleep", random_sleep(1, 1)),
637 ("test", make_test(include_envs
=[
638 "ad_dc_default", "ad_dc_default_smb1", "ad_dc_default_smb1_done"])),
640 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
645 "dependency": "samba-def-build",
647 ("random-sleep", random_sleep(1, 1)),
648 ("test", make_test(include_envs
=["ad_dc_slowtests", "ad_dc_backup"])),
650 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
654 "samba-schemaupgrade": {
655 "dependency": "samba-def-build",
657 ("random-sleep", random_sleep(1, 1)),
658 ("test", make_test(include_envs
=["schema_dc", "schema_pair_dc"])),
660 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
664 # We split out the ad_dc_ntvfs tests (which are long) so other test do not wait
665 # This is currently the longest task, so we don't randomly delay it.
666 "samba-ad-dc-ntvfs": {
667 "dependency": "samba-def-build",
669 ("random-sleep", random_sleep(1, 1)),
670 ("test", make_test(include_envs
=["ad_dc_ntvfs"])),
672 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
676 # Test fips compliance
678 "dependency": "samba-mit-build",
680 ("random-sleep", random_sleep(1, 1)),
681 ("test", make_test(include_envs
=["ad_dc_fips", "ad_member_fips"])),
682 # TODO: This seems to generate only an empty samba-fips.info ("lcov", LCOV_CMD),
683 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
687 # run the backup/restore testenvs separately as they're fairly standalone
688 # (and CI seems to max out at ~3 different DCs running at once)
690 "dependency": "samba-def-build",
692 ("random-sleep", random_sleep(300, 900)),
693 ("test", make_test(include_envs
=[
699 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
703 "dependency": "samba-def-build",
705 ("random-sleep", random_sleep(300, 900)),
706 ("test", make_test(include_envs
=[
712 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
717 "dependency": "samba-mit-build",
719 ("random-sleep", random_sleep(1, 1)),
720 ("test", make_test(include_envs
=[
722 "ad_member_idmap_rid",
723 "admem_idmap_autorid",
724 "ad_member_idmap_ad",
726 "ad_member_idmap_nss",
727 "ad_member_offlogon",
730 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
734 "samba-addc-mit-1": {
735 "dependency": "samba-mit-build",
737 ("random-sleep", random_sleep(1, 1)),
738 ("test", make_test(include_envs
=[
746 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
750 "samba-addc-mit-4a": {
751 "dependency": "samba-mit-build",
753 ("random-sleep", random_sleep(1, 1)),
754 ("test", make_test(include_envs
=[
760 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
763 "samba-addc-mit-4b": {
764 "dependency": "samba-mit-build",
766 ("random-sleep", random_sleep(1, 1)),
767 ("test", make_test(include_envs
=[
772 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
778 ("configure", "./configure.developer --abi-check-disable" + samba_configure_params
),
780 ("test", make_test(TESTS
="${TESTS}")),
785 # Test cross-compile infrastructure
788 ("random-sleep", random_sleep(900, 1500)),
789 ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
790 ("configure-cross-execute", "./configure.developer --out ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
791 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
),
792 ("verify-cross-execute-output", "grep '^Checking value of NSIG' ./bin-xe/cross-answers.txt"),
793 ("configure-cross-answers", "./configure.developer --out ./bin-xa --cross-compile" \
794 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
),
795 ("compare-results", "script/compare_cc_results.py "
796 "./bin/c4che/default{} "
797 "./bin-xe/c4che/default{} "
798 "./bin-xa/c4che/default{}".format(*([CACHE_SUFFIX
]*3))),
799 ("modify-cross-answers", "sed -i.bak -e 's/^\\(Checking value of NSIG:\\) .*/\\1 \"1234\"/' ./bin-xe/cross-answers.txt"),
800 ("configure-cross-answers-modified", "./configure.developer --out ./bin-xa2 --cross-compile" \
801 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa2/ab" + samba_configure_params
),
802 ("verify-cross-answers", "test $(sed -n -e 's/VALUEOF_NSIG = \\(.*\\)/\\1/p' ./bin-xa2/c4che/default{})" \
803 " = \"'1234'\"".format(CACHE_SUFFIX
)),
804 ("invalidate-cross-answers", "sed -i.bak -e '/^Checking value of NSIG/d' ./bin-xe/cross-answers.txt"),
805 ("configure-cross-answers-fail", "./configure.developer --out ./bin-xa3 --cross-compile" \
806 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa3/ab" + samba_configure_params
+ \
811 # test build with -O3 -- catches extra warnings and bugs, tests the ad_dc environments
814 ("random-sleep", random_sleep(300, 900)),
815 ("configure", "ADDITIONAL_CFLAGS='-O3 -Wp,-D_FORTIFY_SOURCE=2' ./configure.developer --abi-check-disable" + samba_configure_params
),
817 ("test", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
818 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
820 ("install", "make install"),
821 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
822 ("clean", "make clean"),
828 ("random-sleep", random_sleep(300, 900)),
829 ("configure", "./configure.developer --abi-check-disable --disable-warnings-as-errors" + samba_configure_params
),
831 ("nonetest", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
832 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
833 ("ktest", make_test(cmd
='make test', include_envs
=["ktest"])),
834 ("install", "make install"),
835 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
836 ("clean", "make clean"),
842 ("random-sleep", random_sleep(900, 1500)),
844 # make sure we have tdb around:
845 ("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}"),
846 ("tdb-make", "cd lib/tdb && make"),
847 ("tdb-install", "cd lib/tdb && make install"),
849 # build samba with cluster support (also building ctdb):
851 "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH "
852 "PKG_CONFIG_PATH=${PREFIX_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH} "
853 "./configure.developer ${PREFIX} "
854 "--with-selftest-prefix=./bin/ab "
855 "--with-cluster-support "
857 "--bundled-libraries=!tdb"),
858 ("samba-make", "make"),
859 ("samba-check", "./bin/smbd --configfile=/dev/null -b | grep CLUSTER_SUPPORT"),
860 ("samba-install", "make install"),
861 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd"),
864 cmd
='PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH make test',
865 INJECT_SELFTEST_PREFIX
=0,
866 include_envs
=["clusteredmember"])
870 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
871 ("clean", "make clean"),
872 ("ctdb-clean", "cd ./ctdb && make clean"),
878 ("random-sleep", random_sleep(300, 900)),
879 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
),
880 ("talloc-make", "cd lib/talloc && make"),
881 ("talloc-install", "cd lib/talloc && make install"),
883 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
),
884 ("tdb-make", "cd lib/tdb && make"),
885 ("tdb-install", "cd lib/tdb && make install"),
887 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
),
888 ("tevent-make", "cd lib/tevent && make"),
889 ("tevent-install", "cd lib/tevent && make install"),
891 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
),
892 ("ldb-make", "cd lib/ldb && make"),
893 ("ldb-install", "cd lib/ldb && make install"),
895 ("nondevel-configure", samba_libs_envvars
+ " ./configure ${PREFIX}"),
896 ("nondevel-make", "make -j"),
897 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0"),
898 ("nondevel-no-libtalloc", "find ./bin | grep -v 'libtalloc-report' | grep 'libtalloc' && exit 1; exit 0"),
899 ("nondevel-no-libtdb", "find ./bin | grep -v 'libtdb-wrap' | grep 'libtdb' && exit 1; exit 0"),
900 ("nondevel-no-libtevent", "find ./bin | grep -v 'libtevent-util' | grep 'libtevent' && exit 1; exit 0"),
901 ("nondevel-no-libldb", "find ./bin | grep -v 'module' | grep -v 'libldbsamba' | grep 'libldb' && exit 1; exit 0"),
902 ("nondevel-no-samba-nss_winbind", "ldd ./bin/plugins/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
903 ("nondevel-no-samba-nss_wins", "ldd ./bin/plugins/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
904 ("nondevel-no-samba-libwbclient", "ldd ./bin/shared/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
905 ("nondevel-no-samba-pam_winbind", "ldd ./bin/plugins/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
906 ("nondevel-no-public-nss_winbind",
907 check_symbols("./bin/plugins/libnss_winbind.so.2", "_nss_winbind_")),
908 ("nondevel-no-public-nss_wins",
909 check_symbols("./bin/plugins/libnss_wins.so.2", "_nss_wins_")),
910 ("nondevel-no-public-libwbclient",
911 check_symbols("./bin/shared/libwbclient.so.0", "wbc")),
912 ("nondevel-no-public-pam_winbind",
913 check_symbols("./bin/plugins/pam_winbind.so", "pam_sm_")),
914 ("nondevel-no-public-winbind_krb5_locator",
915 check_symbols("./bin/plugins/winbind_krb5_locator.so", "service_locator")),
916 ("nondevel-no-public-async_dns_krb5_locator",
917 check_symbols("./bin/plugins/async_dns_krb5_locator.so", "service_locator")),
918 ("nondevel-install", "make -j install"),
919 ("nondevel-dist", "make dist"),
921 ("prefix-no-private-libtalloc", "find ${PREFIX_DIR} | grep -v 'libtalloc-report' | grep 'private.*libtalloc' && exit 1; exit 0"),
922 ("prefix-no-private-libtdb", "find ${PREFIX_DIR} | grep -v 'libtdb-wrap' | grep 'private.*libtdb' && exit 1; exit 0"),
923 ("prefix-no-private-libtevent", "find ${PREFIX_DIR} | grep -v 'libtevent-util' | grep 'private.*libtevent' && exit 1; exit 0"),
924 ("prefix-no-private-libldb", "find ${PREFIX_DIR} | grep -v 'module' | grep -v 'libldbsamba' | grep 'private.*libldb' && exit 1; exit 0"),
925 ("prefix-no-samba-nss_winbind", "ldd ${PREFIX_DIR}/lib/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
926 ("prefix-no-samba-nss_wins", "ldd ${PREFIX_DIR}/lib/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
927 ("prefix-no-samba-libwbclient", "ldd ${PREFIX_DIR}/lib/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
928 ("prefix-no-samba-pam_winbind", "ldd ${PREFIX_DIR}/lib/security/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
929 ("prefix-no-public-nss_winbind",
930 check_symbols("${PREFIX_DIR}/lib/libnss_winbind.so.2", "_nss_winbind_")),
931 ("prefix-no-public-nss_wins",
932 check_symbols("${PREFIX_DIR}/lib/libnss_wins.so.2", "_nss_wins_")),
933 ("prefix-no-public-libwbclient",
934 check_symbols("${PREFIX_DIR}/lib/libwbclient.so.0", "wbc")),
935 ("prefix-no-public-pam_winbind",
936 check_symbols("${PREFIX_DIR}/lib/security/pam_winbind.so", "pam_sm_")),
937 ("prefix-no-public-winbind_krb5_locator",
938 check_symbols("${PREFIX_DIR}/lib/krb5/winbind_krb5_locator.so",
940 ("prefix-no-public-async_dns_krb5_locator",
941 check_symbols("${PREFIX_DIR}/lib/krb5/async_dns_krb5_locator.so",
944 # retry with all modules shared
945 ("allshared-distclean", "make distclean"),
946 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL"),
947 ("allshared-make", "make -j"),
948 ("allshared-no-libtalloc", "find ./bin | grep -v 'libtalloc-report' | grep 'libtalloc' && exit 1; exit 0"),
949 ("allshared-no-libtdb", "find ./bin | grep -v 'libtdb-wrap' | grep 'libtdb' && exit 1; exit 0"),
950 ("allshared-no-libtevent", "find ./bin | grep -v 'libtevent-util' | grep 'libtevent' && exit 1; exit 0"),
951 ("allshared-no-libldb", "find ./bin | grep -v 'module' | grep -v 'libldbsamba' | grep 'libldb' && exit 1; exit 0"),
952 ("allshared-no-samba-nss_winbind", "ldd ./bin/plugins/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
953 ("allshared-no-samba-nss_wins", "ldd ./bin/plugins/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
954 ("allshared-no-samba-libwbclient", "ldd ./bin/shared/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
955 ("allshared-no-samba-pam_winbind", "ldd ./bin/plugins/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
956 ("allshared-no-public-nss_winbind",
957 check_symbols("./bin/plugins/libnss_winbind.so.2", "_nss_winbind_")),
958 ("allshared-no-public-nss_wins",
959 check_symbols("./bin/plugins/libnss_wins.so.2", "_nss_wins_")),
960 ("allshared-no-public-libwbclient",
961 check_symbols("./bin/shared/libwbclient.so.0", "wbc")),
962 ("allshared-no-public-pam_winbind",
963 check_symbols("./bin/plugins/pam_winbind.so", "pam_sm_")),
964 ("allshared-no-public-winbind_krb5_locator",
965 check_symbols("./bin/plugins/winbind_krb5_locator.so", "service_locator")),
966 ("allshared-no-public-async_dns_krb5_locator",
967 check_symbols("./bin/plugins/async_dns_krb5_locator.so", "service_locator")),
973 # build the fuzzers (static) via the oss-fuzz script
974 ("fuzzers-mkdir-prefix", "mkdir -p ${PREFIX_DIR}"),
975 ("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"),
979 # * Test smbd and smbtorture can build semi-static
981 # * Test Samba without python still builds.
983 # When this test fails due to more use of Python, the expectations
984 # is that the newly failing part of the code should be disabled
985 # when --disable-python is set (rather than major work being done
986 # to support this environment).
988 # The target here is for vendors shipping a minimal smbd.
989 "samba-minimal-smbd": {
991 ("random-sleep", random_sleep(300, 900)),
993 # build with all modules static
994 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL"),
995 ("allstatic-make", "make -j"),
996 ("allstatic-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
997 ("allstatic-lcov", LCOV_CMD
),
998 ("allstatic-def-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
999 ("allstatic-def-clean", "make clean"),
1001 # force all libraries as private
1002 ("allprivate-def-distclean", "make distclean"),
1003 ("allprivate-def-configure", "./configure.developer " + samba_configure_params
+ " --private-libraries=ALL"),
1004 ("allprivate-def-make", "make -j"),
1005 # note wrapper libraries need to be public
1006 ("allprivate-def-no-public", "ls ./bin/shared | egrep -v '^private$|lib[nprsu][saeoi][smscd].*-wrapper.so$|pam_set_items.so' | wc -l | grep -q '^0'"),
1007 ("allprivate-def-only-private-ext", "ls ./bin/shared/private | egrep 'private-samba' | wc -l | grep -q '^0' && exit 1; exit 0"),
1008 ("allprivate-def-no-non-private-ext", "ls ./bin/shared/private | egrep -v 'private-samba|^libpypamtest.so$' | wc -l | grep -q '^0'"),
1009 ("allprivate-def-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
1010 ("allprivate-def-lcov", LCOV_CMD
),
1011 ("allprivate-def-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1012 ("allprivate-def-clean", "make clean"),
1014 # force all libraries as private with a non default
1015 # extension and 2 exceptions
1016 ("allprivate-ext-distclean", "make distclean"),
1017 ("allprivate-ext-configure", "./configure.developer " + samba_configure_params
+ " --private-libraries=ALL --private-library-extension=private-library --private-extension-exception=pac,ndr"),
1018 ("allprivate-ext-make", "make -j"),
1019 # note wrapper libraries need to be public
1020 ("allprivate-ext-no-public", "ls ./bin/shared | egrep -v '^private$|lib[nprsu][saeoi][smscd].*-wrapper.so$|pam_set_items.so' | wc -l | grep -q '^0'"),
1021 ("allprivate-ext-no-private-default-ext", "ls ./bin/shared/private | grep 'private-samba' | wc -l | grep -q '^0'"),
1022 ("allprivate-ext-has-private-ext", "ls ./bin/shared/private | grep 'private-library' | wc -l | grep -q '^0' && exit 1; exit 0"),
1023 ("allprivate-ext-libndr-no-private-ext", "ls ./bin/shared/private | grep -v 'private-library' | grep 'libndr' | wc -l | grep -q '^1'"),
1024 ("allprivate-ext-libpac-no-private-ext", "ls ./bin/shared/private | grep -v 'private-library' | grep 'libpac' | wc -l | grep -q '^1'"),
1025 ("allprivate-ext-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
1026 ("allprivate-ext-lcov", LCOV_CMD
),
1027 ("allprivate-ext-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1028 ("allprivate-ext-clean", "make clean"),
1030 # retry with nonshared smbd and smbtorture
1031 ("nonshared-distclean", "make distclean"),
1032 ("nonshared-configure", "./configure.developer " + samba_configure_params
+ " --bundled-libraries=ALL --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd"),
1033 ("nonshared-make", "make -j"),
1034 ("nonshared-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
1035 ("nonshared-lcov", LCOV_CMD
),
1036 ("nonshared-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1037 ("nonshared-clean", "make clean"),
1043 ("random-sleep", random_sleep(300, 900)),
1045 ("configure", "./configure.developer ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data --disable-python --without-ad-dc"),
1046 ("make", "make -j"),
1047 ("find-python", "script/find_python.sh ${PREFIX}"),
1048 ("test", "make test-nopython"),
1050 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1051 ("clean", "make clean"),
1053 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1054 ("talloc-make", "cd lib/talloc && make"),
1055 ("talloc-install", "cd lib/talloc && make install"),
1057 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1058 ("tdb-make", "cd lib/tdb && make"),
1059 ("tdb-install", "cd lib/tdb && make install"),
1061 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1062 ("tevent-make", "cd lib/tevent && make"),
1063 ("tevent-install", "cd lib/tevent && make install"),
1065 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1066 ("ldb-make", "cd lib/ldb && make"),
1067 ("ldb-install", "cd lib/ldb && make install"),
1069 # retry against installed library packages, but no required modules
1070 ("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"),
1071 ("libs-make", "make -j"),
1072 ("libs-install", "make install"),
1073 ("libs-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1074 ("libs-clean", "make clean"),
1079 "samba-codecheck": {
1081 ("run", "script/check-shell-scripts.sh ."),
1082 ("run", "script/codespell.sh ."),
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 ("clean", "make clean"),
1095 ("configure-no-lmdb", "./configure ${ENABLE_COVERAGE} --enable-developer --without-ldb-lmdb -C ${PREFIX}"),
1096 ("make-no-lmdb", "make"),
1097 ("test-no-lmdb", "make test"),
1098 ("lcov-no-lmdb", LCOV_CMD
),
1099 ("install-no-lmdb", "make install"),
1100 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1101 ("distcheck", "make distcheck"),
1102 ("clean", "make clean"),
1108 ("random-sleep", random_sleep(60, 600)),
1109 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1111 ("install", "make install"),
1112 ("test", "make test"),
1114 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1115 ("distcheck", "make distcheck"),
1116 ("clean", "make clean"),
1122 ("random-sleep", random_sleep(60, 600)),
1123 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1125 ("install", "make install"),
1126 ("test", "make test"),
1128 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1129 ("distcheck", "make distcheck"),
1130 ("clean", "make clean"),
1136 ("random-sleep", random_sleep(60, 600)),
1137 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1139 ("install", "make install"),
1140 ("test", "make test"),
1142 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1143 ("distcheck", "make distcheck"),
1144 ("clean", "make clean"),
1150 ("random-sleep", random_sleep(60, 600)),
1151 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1153 ("install", "make install"),
1154 ("test", "make test"),
1156 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1157 ("distcheck", "make distcheck"),
1158 ("clean", "make clean"),
1163 "git-clone-required": True,
1165 ("random-sleep", random_sleep(60, 600)),
1166 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}"),
1167 ("touch", "touch *.yp"),
1169 ("test", "make test"),
1170 ("install", "make install"),
1171 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm"),
1172 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1173 ("clean", "make clean"),
1177 # these are useful for debugging autobuild
1180 ("pass", 'echo passing && /bin/true'),
1185 ("fail", 'echo failing && /bin/false'),
1190 defaulttasks
= list(tasks
.keys())
1192 defaulttasks
.remove("pass")
1193 defaulttasks
.remove("fail")
1195 # The build tasks will be brought in by the test tasks as needed
1196 defaulttasks
.remove("samba-def-build")
1197 defaulttasks
.remove("samba-nt4-build")
1198 defaulttasks
.remove("samba-mit-build")
1199 defaulttasks
.remove("samba-h5l-build")
1200 defaulttasks
.remove("samba-no-opath-build")
1202 # This is not a normal test, but a task to support manually running
1203 # one test under autobuild
1204 defaulttasks
.remove("samba-test-only")
1206 # Only built on GitLab CI and not in the default autobuild because it
1207 # uses too much space (4GB of semi-static binaries)
1208 defaulttasks
.remove("samba-fuzz")
1210 # The FIPS build runs only in GitLab CI on a current Fedora Docker
1211 # container where a simulated FIPS mode is possible.
1212 defaulttasks
.remove("samba-fips")
1214 # The MIT build runs on a current Fedora where an up to date MIT KDC
1215 # is already packaged. This avoids needing to backport a current MIT
1216 # to the default Ubuntu 18.04, particularly during development, and
1217 # the need to install on the shared sn-devel-184.
1219 defaulttasks
.remove("samba-mitkrb5")
1220 defaulttasks
.remove("samba-admem-mit")
1221 defaulttasks
.remove("samba-addc-mit-1")
1222 defaulttasks
.remove("samba-addc-mit-4a")
1223 defaulttasks
.remove("samba-addc-mit-4b")
1225 defaulttasks
.remove("samba-32bit")
1227 if os
.environ
.get("AUTOBUILD_SKIP_SAMBA_O3", "0") == "1":
1228 defaulttasks
.remove("samba-o3")
1242 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
1244 do_debug("Running: '%s' in '%s'" % (cmd
, dir))
1246 do_print("Running: '%s' in '%s'" % (cmd
, dir))
1249 out
= check_output([cmd
], shell
=True, cwd
=dir)
1250 return out
.decode(encoding
='utf-8', errors
='backslashreplace')
1252 return check_call(cmd
, shell
=True, cwd
=dir)
1254 return call(cmd
, shell
=True, cwd
=dir)
1256 def rmdir_force(dirname
, re_raise
=True):
1258 run_cmd("test -d %s && chmod -R +w %s; rm -rf %s" % (
1259 dirname
, dirname
, dirname
), output
=True, show
=True)
1260 except CalledProcessError
as e
:
1261 do_print("Failed: '%s'" % (str(e
)))
1262 run_cmd("tree %s" % dirname
, output
=True, show
=True)
1268 class builder(object):
1269 '''handle build of one directory'''
1271 def __init__(self
, name
, definition
):
1273 self
.dir = builddirs
.get(name
, '.')
1274 self
.tag
= self
.name
.replace('/', '_')
1275 self
.definition
= definition
1276 self
.sequence
= definition
["sequence"]
1277 self
.git_clone_required
= False
1278 if "git-clone-required" in definition
:
1279 self
.git_clone_required
= bool(definition
["git-clone-required"])
1283 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
1284 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
1285 do_debug("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
1286 do_debug("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
1287 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
1288 self
.stdout
= open(self
.stdout_path
, 'w')
1289 self
.stderr
= open(self
.stderr_path
, 'w')
1290 self
.stdin
= open("/dev/null", 'r')
1291 self
.builder_dir
= "%s/%s" % (testbase
, self
.tag
)
1292 self
.test_source_dir
= self
.builder_dir
1293 self
.cwd
= "%s/%s" % (self
.builder_dir
, self
.dir)
1294 self
.selftest_prefix
= "%s/bin/ab" % (self
.cwd
)
1295 self
.prefix
= "%s/%s" % (test_prefix
, self
.tag
)
1297 self
.producer
= None
1299 if self
.git_clone_required
:
1300 assert "dependency" not in definition
1302 def mark_existing(self
):
1303 do_debug('%s: Mark as existing dependency' % self
.name
)
1304 self
.next
= len(self
.sequence
)
1307 def add_consumer(self
, consumer
):
1308 do_debug("%s: add consumer: %s" % (self
.name
, consumer
.name
))
1309 consumer
.producer
= self
1310 consumer
.test_source_dir
= self
.test_source_dir
1311 self
.consumers
.append(consumer
)
1313 def start_next(self
):
1314 if self
.producer
is not None:
1315 if not self
.producer
.done
:
1316 do_debug("%s: Waiting for producer: %s" % (self
.name
, self
.producer
.name
))
1320 rmdir_force(self
.builder_dir
)
1321 rmdir_force(self
.prefix
)
1322 if self
.producer
is not None:
1323 run_cmd("mkdir %s" % (self
.builder_dir
), dir=test_master
, show
=True)
1324 elif not self
.git_clone_required
:
1325 run_cmd("cp -R -a -l %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1327 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1329 if self
.next
== len(self
.sequence
):
1331 do_print('%s: Completed OK' % self
.name
)
1333 if not options
.nocleanup
and len(self
.consumers
) == 0:
1334 do_print('%s: Cleaning up' % self
.name
)
1335 rmdir_force(self
.builder_dir
)
1336 rmdir_force(self
.prefix
)
1337 for consumer
in self
.consumers
:
1338 if consumer
.next
!= 0:
1340 do_print('%s: Starting consumer %s' % (self
.name
, consumer
.name
))
1341 consumer
.start_next()
1342 if self
.producer
is not None:
1343 self
.producer
.consumers
.remove(self
)
1344 assert self
.producer
.done
1345 self
.producer
.start_next()
1346 do_print('%s: Remaining consumers %u' % (self
.name
, len(self
.consumers
)))
1348 (self
.stage
, self
.cmd
) = self
.sequence
[self
.next
]
1349 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}",
1350 get_path(name
='platlib',
1351 scheme
="posix_prefix",
1352 vars={"base": self
.prefix
,
1353 "platbase": self
.prefix
}))
1354 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
1355 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
1356 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
1357 self
.cmd
= self
.cmd
.replace("${TEST_SOURCE_DIR}", self
.test_source_dir
)
1358 self
.cmd
= self
.cmd
.replace("${SELFTEST_PREFIX}", self
.selftest_prefix
)
1359 self
.cmd
= self
.cmd
.replace("${LOG_BASE}", options
.log_base
)
1360 self
.cmd
= self
.cmd
.replace("${NAME}", self
.name
)
1361 self
.cmd
= self
.cmd
.replace("${ENABLE_COVERAGE}", options
.enable_coverage
)
1362 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, self
.cwd
))
1363 self
.proc
= Popen(self
.cmd
, shell
=True,
1364 close_fds
=True, cwd
=self
.cwd
,
1365 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
1368 def expand_dependencies(n
):
1370 if "dependency" in tasks
[n
]:
1371 depname
= tasks
[n
]["dependency"]
1372 assert depname
in tasks
1373 sdeps
= expand_dependencies(depname
)
1374 assert n
not in sdeps
1377 deps
.append(depname
)
1381 class buildlist(object):
1382 '''handle build of multiple directories'''
1384 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
1385 self
.tail_proc
= None
1388 if options
.restrict_tests
:
1389 tasknames
= ["samba-test-only"]
1391 tasknames
= defaulttasks
1393 given_tasknames
= tasknames
.copy()
1394 implicit_tasknames
= []
1395 for n
in given_tasknames
:
1396 deps
= expand_dependencies(n
)
1398 if dep
in given_tasknames
:
1400 if dep
in implicit_tasknames
:
1402 implicit_tasknames
.append(dep
)
1404 tasknames
= implicit_tasknames
.copy()
1405 tasknames
.extend(given_tasknames
)
1406 do_debug("given_tasknames: %s" % given_tasknames
)
1407 do_debug("implicit_tasknames: %s" % implicit_tasknames
)
1408 do_debug("tasknames: %s" % tasknames
)
1409 self
.tlist
= [builder(n
, tasks
[n
]) for n
in tasknames
]
1412 rebase_remote
= "rebaseon"
1414 "git-clone-required": True,
1418 git remote add -t %s %s %s
1422 git describe %s/%s > old_remote_branch.desc
1424 git describe %s/%s > remote_branch.desc
1425 diff old_remote_branch.desc remote_branch.desc
1428 rebase_branch
, rebase_remote
, rebase_url
,
1430 rebase_remote
, rebase_branch
,
1432 rebase_remote
, rebase_branch
1435 self
.retry
= builder('retry', retry_task
)
1436 self
.need_retry
= False
1438 if options
.skip_dependencies
:
1439 for b
in self
.tlist
:
1440 if b
.name
in implicit_tasknames
:
1443 for b
in self
.tlist
:
1444 do_debug("b.name=%s" % b
.name
)
1445 if "dependency" not in b
.definition
:
1447 depname
= b
.definition
["dependency"]
1448 do_debug("b.name=%s: dependency:%s" % (b
.name
, depname
))
1449 for p
in self
.tlist
:
1450 if p
.name
== depname
:
1453 def kill_kids(self
):
1454 if self
.tail_proc
is not None:
1455 self
.tail_proc
.terminate()
1456 self
.tail_proc
.wait()
1457 self
.tail_proc
= None
1458 if self
.retry
is not None:
1459 self
.retry
.proc
.terminate()
1460 self
.retry
.proc
.wait()
1462 for b
in self
.tlist
:
1463 if b
.proc
is not None:
1464 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.test_source_dir
, checkfail
=False)
1472 for b
in self
.tlist
:
1475 none_running
= False
1476 b
.status
= b
.proc
.poll()
1477 if b
.status
is None:
1482 ret
= self
.retry
.proc
.poll()
1484 self
.need_retry
= True
1492 for b
in self
.tlist
:
1495 self
.retry
.start_next()
1498 if options
.retry
and self
.need_retry
:
1500 do_print("retry needed")
1501 return (0, None, None, None, "retry")
1504 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
1506 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
1509 return (0, None, None, None, "All OK")
1511 def write_system_info(self
, filename
):
1512 with
open(filename
, 'w') as f
:
1513 for cmd
in ['uname -a',
1517 'cat /proc/cpuinfo',
1520 'df -m %s' % testbase
]:
1522 out
= run_cmd(cmd
, output
=True, checkfail
=False)
1523 except CalledProcessError
as e
:
1524 out
= "<failed: %s>" % str(e
)
1525 print('### %s' % cmd
, file=f
)
1529 def tarlogs(self
, fname
):
1530 with tarfile
.open(fname
, "w:gz") as tar
:
1531 for b
in self
.tlist
:
1532 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
1533 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
1534 if os
.path
.exists("autobuild.log"):
1535 tar
.add("autobuild.log")
1536 filename
= 'system-info.txt'
1537 self
.write_system_info(filename
)
1540 def remove_logs(self
):
1541 for b
in self
.tlist
:
1542 os
.unlink(b
.stdout_path
)
1543 os
.unlink(b
.stderr_path
)
1545 def start_tail(self
):
1546 cmd
= ["tail", "-f"]
1547 for b
in self
.tlist
:
1548 cmd
.append(b
.stdout_path
)
1549 cmd
.append(b
.stderr_path
)
1550 self
.tail_proc
= Popen(cmd
, close_fds
=True)
1553 def cleanup(do_raise
=False):
1554 if options
.nocleanup
:
1556 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
1557 run_cmd("stat %s" % testbase
, show
=True)
1558 do_print("Cleaning up %r" % cleanup_list
)
1559 for d
in cleanup_list
:
1560 ok
= rmdir_force(d
, re_raise
=False)
1563 if os
.path
.isdir(d
):
1564 do_print("Killing, waiting and retry")
1565 run_cmd("killbysubdir %s > /dev/null 2>&1" % d
, checkfail
=False)
1567 do_print("Waiting and retry")
1569 rmdir_force(d
, re_raise
=do_raise
)
1572 def daemonize(logfile
):
1574 if pid
== 0: # Parent
1577 if pid
!= 0: # Actual daemon
1582 import resource
# Resource usage information.
1583 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
1584 if maxfd
== resource
.RLIM_INFINITY
:
1585 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
1586 for fd
in range(0, maxfd
):
1591 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
1596 def write_pidfile(fname
):
1597 '''write a pid file, cleanup on exit'''
1598 with
open(fname
, mode
='w') as f
:
1599 f
.write("%u\n" % os
.getpid())
1602 def rebase_tree(rebase_url
, rebase_branch
="master"):
1603 rebase_remote
= "rebaseon"
1604 do_print("Rebasing on %s" % rebase_url
)
1605 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1606 run_cmd("git remote add -t %s %s %s" %
1607 (rebase_branch
, rebase_remote
, rebase_url
),
1608 show
=True, dir=test_master
)
1609 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
1610 if options
.fix_whitespace
:
1611 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
1612 (rebase_remote
, rebase_branch
),
1613 show
=True, dir=test_master
)
1615 run_cmd("git rebase --force-rebase %s/%s" %
1616 (rebase_remote
, rebase_branch
),
1617 show
=True, dir=test_master
)
1618 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
1619 (rebase_remote
, rebase_branch
),
1620 dir=test_master
, output
=True)
1622 do_print("No differences between HEAD and %s/%s - exiting" %
1623 (rebase_remote
, rebase_branch
))
1625 run_cmd("git describe %s/%s" %
1626 (rebase_remote
, rebase_branch
),
1627 show
=True, dir=test_master
)
1628 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1629 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
1630 (rebase_remote
, rebase_branch
),
1631 show
=True, dir=test_master
)
1634 def push_to(push_url
, push_branch
="master"):
1635 push_remote
= "pushto"
1636 do_print("Pushing to %s" % push_url
)
1638 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
1639 run_cmd("git commit --amend -c HEAD", dir=test_master
)
1640 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
1641 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
1642 run_cmd("git remote add -t %s %s %s" %
1643 (push_branch
, push_remote
, push_url
),
1644 show
=True, dir=test_master
)
1645 run_cmd("git push %s +HEAD:%s" %
1646 (push_remote
, push_branch
),
1647 show
=True, dir=test_master
)
1650 def send_email(subject
, text
, log_tar
):
1651 if options
.email
is None:
1652 do_print("not sending email because the recipient is not set")
1653 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
1656 outer
= MIMEMultipart()
1657 outer
['Subject'] = subject
1658 outer
['To'] = options
.email
1659 outer
['From'] = options
.email_from
1660 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
1661 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
1662 outer
.attach(MIMEText(text
, 'plain', 'utf-8'))
1663 if options
.attach_logs
:
1664 with
open(log_tar
, 'rb') as fp
:
1665 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
1666 # Set the filename parameter
1667 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
1669 content
= outer
.as_string()
1670 s
= smtplib
.SMTP(options
.email_server
)
1671 email_user
= os
.getenv('SMTP_USERNAME')
1672 email_password
= os
.getenv('SMTP_PASSWORD')
1673 if email_user
is not None:
1675 s
.login(email_user
, email_password
)
1677 s
.sendmail(options
.email_from
, [options
.email
], content
)
1682 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1683 elapsed_time
, log_base
=None, add_log_tail
=True):
1684 '''send an email to options.email about the failure'''
1685 elapsed_minutes
= elapsed_time
/ 60.0
1686 if log_base
is None:
1691 Your autobuild on %s failed after %.1f minutes
1692 when trying to test %s with the following error:
1696 the autobuild has been abandoned. Please fix the error and resubmit.
1698 A summary of the autobuild process is here:
1701 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
1703 if options
.restrict_tests
:
1705 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1707 if failed_task
!= 'rebase':
1709 You can see logs of the failed task here:
1714 or you can get full logs of all tasks in this job here:
1718 The top commit for the tree that was built was:
1722 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
1724 log_stdout
= "%s/%s.stdout" % (gitroot
, failed_tag
)
1725 if add_log_tail
and os
.access(log_stdout
, os
.R_OK
):
1726 f
= open(log_stdout
, 'r')
1727 lines
= f
.readlines()
1728 log_tail
= "".join(lines
[-50:])
1729 num_lines
= len(lines
)
1730 log_stderr
= "%s/%s.stderr" % (gitroot
, failed_tag
)
1731 if num_lines
< 50 and os
.access(log_stderr
, os
.R_OK
):
1732 # Also include stderr (compile failures) if < 50 lines of stdout
1733 f
= open(log_stderr
, 'r')
1734 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
1737 The last 50 lines of log messages:
1743 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1744 send_email('autobuild[%s] failure on %s for task %s during %s'
1745 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
1749 def email_success(elapsed_time
, log_base
=None):
1750 '''send an email to options.email about a successful build'''
1751 if log_base
is None:
1756 Your autobuild on %s has succeeded after %.1f minutes.
1758 ''' % (platform
.node(), elapsed_time
/ 60.)
1760 if options
.restrict_tests
:
1762 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1764 if options
.keeplogs
:
1767 you can get full logs of all tasks in this job here:
1774 The top commit for the tree that was built was:
1777 ''' % top_commit_msg
1779 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1780 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
1784 # get the top commit message, for emails
1785 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
1788 if options
.skip_dependencies
:
1789 run_cmd("stat %s" % testbase
, dir=testbase
, output
=True)
1791 os
.makedirs(testbase
)
1792 except Exception as reason
:
1793 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
1794 cleanup_list
.append(testbase
)
1797 logfile
= os
.path
.join(testbase
, "log")
1798 do_print("Forking into the background, writing progress to %s" % logfile
)
1801 write_pidfile(gitroot
+ "/autobuild.pid")
1803 start_time
= time
.time()
1807 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
1808 os
.makedirs(test_tmpdir
)
1809 # The waf uninstall code removes empty directories all the way
1810 # up the tree. Creating a file in test_tmpdir stops it from
1812 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
1813 ".directory-is-not-empty"), show
=True)
1814 run_cmd("stat %s" % test_tmpdir
, show
=True)
1815 run_cmd("stat %s" % testbase
, show
=True)
1816 if options
.skip_dependencies
:
1817 run_cmd("stat %s" % test_master
, dir=testbase
, output
=True)
1819 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
1825 if options
.rebase
is not None:
1826 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
1828 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1830 elapsed_time
= time
.time() - start_time
1831 email_failure(-1, 'rebase', 'rebase', 'rebase',
1832 'rebase on %s failed' % options
.branch
,
1833 elapsed_time
, log_base
=options
.log_base
)
1837 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1840 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1841 if status
!= 0 or errstr
!= "retry":
1843 cleanup(do_raise
=True)
1848 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1854 do_print("waiting for tail to flush")
1857 elapsed_time
= time
.time() - start_time
1859 if options
.passcmd
is not None:
1860 do_print("Running passcmd: %s" % options
.passcmd
)
1861 run_cmd(options
.passcmd
, dir=test_master
)
1862 if options
.pushto
is not None:
1863 push_to(options
.pushto
, push_branch
=options
.branch
)
1864 if options
.keeplogs
or options
.attach_logs
:
1865 blist
.tarlogs("logs.tar.gz")
1866 do_print("Logs in logs.tar.gz")
1867 if options
.always_email
:
1868 email_success(elapsed_time
, log_base
=options
.log_base
)
1874 # something failed, gather a tar of the logs
1875 blist
.tarlogs("logs.tar.gz")
1877 if options
.email
is not None:
1878 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1879 elapsed_time
, log_base
=options
.log_base
)
1881 elapsed_minutes
= elapsed_time
/ 60.0
1884 ####################################################################
1888 Your autobuild[%s] on %s failed after %.1f minutes
1889 when trying to test %s with the following error:
1893 the autobuild has been abandoned. Please fix the error and resubmit.
1895 ####################################################################
1897 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1901 do_print("Logs in logs.tar.gz")