2 # run tests on all Samba subprojects and push to a git tree on success
3 # Copyright Andrew Tridgell 2010
4 # released under GNU GPL v3 or later
6 from subprocess
import call
, check_call
, check_output
, Popen
, PIPE
, CalledProcessError
12 from optparse
import OptionParser
15 from email
.mime
.text
import MIMEText
16 from email
.mime
.base
import MIMEBase
17 from email
.mime
.application
import MIMEApplication
18 from email
.mime
.multipart
import MIMEMultipart
19 from distutils
.sysconfig
import get_python_lib
23 from waflib
.Build
import CACHE_SUFFIX
25 sys
.path
.insert(0, "./third_party/waf")
26 from waflib
.Build
import CACHE_SUFFIX
29 os
.environ
["PYTHONUNBUFFERED"] = "1"
31 # This speeds up testing remarkably.
32 os
.environ
['TDB_NO_FSYNC'] = '1'
34 # allow autobuild to run within git rebase -i
35 if "GIT_DIR" in os
.environ
:
36 del os
.environ
["GIT_DIR"]
37 if "GIT_WORK_TREE" in os
.environ
:
38 del os
.environ
["GIT_WORK_TREE"]
41 '''get to the top of the git repo'''
44 if os
.path
.exists(os
.path
.join(p
, ".git")):
46 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
50 gitroot
= find_git_root()
52 raise Exception("Failed to find git root")
55 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
57 parser
= OptionParser()
58 parser
.add_option("--tail", help="show output while running", default
=False, action
="store_true")
59 parser
.add_option("--keeplogs", help="keep logs", default
=False, action
="store_true")
60 parser
.add_option("--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
61 parser
.add_option("--skip-dependencies", help="skip to run task dependency tasks", default
=False, action
="store_true")
62 parser
.add_option("--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
64 parser
.add_option("--full-testbase", help="full base directory to run tests in (default %s/b$PID)" % def_testbase
,
66 parser
.add_option("--passcmd", help="command to run on success", default
=None)
67 parser
.add_option("--verbose", help="show all commands as they are run",
68 default
=False, action
="store_true")
69 parser
.add_option("--rebase", help="rebase on the given tree before testing",
70 default
=None, type='str')
71 parser
.add_option("--pushto", help="push to a git url on success",
72 default
=None, type='str')
73 parser
.add_option("--mark", help="add a Tested-By signoff before pushing",
74 default
=False, action
="store_true")
75 parser
.add_option("--fix-whitespace", help="fix whitespace on rebase",
76 default
=False, action
="store_true")
77 parser
.add_option("--retry", help="automatically retry if master changes",
78 default
=False, action
="store_true")
79 parser
.add_option("--email", help="send email to the given address on failure",
80 type='str', default
=None)
81 parser
.add_option("--email-from", help="send email from the given address",
82 type='str', default
="autobuild@samba.org")
83 parser
.add_option("--email-server", help="send email via the given server",
84 type='str', default
='localhost')
85 parser
.add_option("--always-email", help="always send email, even on success",
87 parser
.add_option("--daemon", help="daemonize after initial setup",
89 parser
.add_option("--branch", help="the branch to work on (default=master)",
90 default
="master", type='str')
91 parser
.add_option("--log-base", help="location where the logs can be found (default=cwd)",
92 default
=gitroot
, type='str')
93 parser
.add_option("--attach-logs", help="Attach logs to mails sent on success/failure?",
94 default
=False, action
="store_true")
95 parser
.add_option("--restrict-tests", help="run as make test with this TESTS= regex",
97 parser
.add_option("--enable-coverage", dest
='enable_coverage',
98 action
="store_const", const
='--enable-coverage', default
='',
99 help="Add --enable-coverage option while configure")
101 (options
, args
) = parser
.parse_args()
104 if options
.rebase
is None:
105 raise Exception('You can only use --retry if you also rebase')
107 if options
.full_testbase
is not None:
108 testbase
= options
.full_testbase
110 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
111 test_master
= "%s/master" % testbase
112 test_prefix
= "%s/prefix" % testbase
113 test_tmpdir
= "%s/tmp" % testbase
114 os
.environ
['TMPDIR'] = test_tmpdir
116 if options
.enable_coverage
:
117 LCOV_CMD
= "cd ${TEST_SOURCE_DIR} && lcov --capture --directory . --output-file ${LOG_BASE}/${NAME}.info --rc 'geninfo_adjust_src_path=${TEST_SOURCE_DIR}/'"
119 LCOV_CMD
= 'echo "lcov skipped since no --enable-coverage specified"'
121 if options
.enable_coverage
:
122 PUBLISH_DOCS
= "mkdir -p ${LOG_BASE}/public && mv output/htmldocs ${LOG_BASE}/public/htmldocs"
124 PUBLISH_DOCS
= 'echo "HTML documentation publishing skipped since no --enable-coverage specified"'
126 CLEAN_SOURCE_TREE_CMD
= "cd ${TEST_SOURCE_DIR} && script/clean-source-tree.sh"
129 def check_symbols(sofile
, expected_symbols
=""):
130 return "objdump --dynamic-syms " + sofile
+ " | " + \
131 "awk \'$0 !~ /" + expected_symbols
+ "/ {if ($2 == \"g\" && $3 ~ /D(F|O)/ && $4 ~ /(.bss|.text)/ && $7 !~ /(__gcov_|mangle_path)/) exit 1}\'"
134 # If we are only running specific test,
135 # do not sleep randomly to wait for it to start
136 def random_sleep(low
, high
):
139 def random_sleep(low
, high
):
140 return 'sleep {}'.format(random
.randint(low
, high
))
148 "talloc": "lib/talloc",
149 "replace": "lib/replace",
150 "tevent": "lib/tevent",
152 "docs-xml": "docs-xml"
155 ctdb_configure_params
= " --enable-developer ${PREFIX}"
156 samba_configure_params
= " ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data"
158 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH"
159 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
160 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
161 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check ${ENABLE_COVERAGE} --enable-debug -C ${PREFIX}"
162 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=cmocka,popt,NONE"
163 samba_libs_configure_bundled_libs
= " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent,!popt"
164 samba_libs_configure_samba
= samba_libs_configure_base
+ samba_libs_configure_bundled_libs
167 def format_option(name
, value
=None):
168 """Format option as str list."""
169 if value
is None: # boolean option
171 if not isinstance(value
, list): # single value option
174 return ['{}={}'.format(name
, item
) for item
in value
]
179 INJECT_SELFTEST_PREFIX
=1,
186 test_options
= format_option('--include-env', include_envs
)
188 test_options
= format_option('--exclude-env', exclude_envs
)
190 # join envs options to original test options
191 TESTS
= (TESTS
+ ' ' + ' '.join(test_options
)).strip()
195 # Allow getting a full CI with
196 # git push -o ci.variable='AUTOBUILD_FAIL_IMMEDIATELY=0'
198 FAIL_IMMEDIATELY
= os
.getenv("AUTOBUILD_FAIL_IMMEDIATELY", "1")
200 if int(FAIL_IMMEDIATELY
):
201 _options
.append('FAIL_IMMEDIATELY=1')
203 _options
.append("TESTS='{}'".format(TESTS
))
205 if INJECT_SELFTEST_PREFIX
:
206 _options
.append("TEST_OPTIONS='--with-selftest-prefix={}'".format("${SELFTEST_PREFIX}"))
207 _options
.append("--directory='{}'".format("${TEST_SOURCE_DIR}"))
209 return ' '.join([cmd
] + _options
)
212 # When updating this list, also update .gitlab-ci.yml to add the job
213 # and to make it a dependency of 'page' for the coverage report.
218 ("random-sleep", random_sleep(300, 900)),
219 ("configure", "./configure " + ctdb_configure_params
),
220 ("make", "make all"),
221 ("install", "make install"),
222 ("test", "make autotest"),
223 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
224 ("clean", "make clean"),
229 ("random-sleep", random_sleep(300, 900)),
230 ("autoconf", "autoconf"),
231 ("configure", "./configure"),
232 ("make", "make html htmlman"),
233 ("publish-docs", PUBLISH_DOCS
),
234 ("clean", "make clean"),
239 "git-clone-required": True,
241 ("configure", "./configure.developer" + samba_configure_params
),
243 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
244 ("chmod-R-a-w", "chmod -R a-w ."),
249 "git-clone-required": True,
251 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
253 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
254 ("chmod-R-a-w", "chmod -R a-w ."),
259 "git-clone-required": True,
261 ("configure", "./configure.developer --without-ad-dc --without-ldap --without-ads --without-json" + samba_configure_params
),
263 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
264 ("chmod-R-a-w", "chmod -R a-w ."),
269 "git-clone-required": True,
271 ("configure", "./configure.developer --without-ad-dc --with-system-heimdalkrb5" + samba_configure_params
),
273 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
274 ("chmod-R-a-w", "chmod -R a-w ."),
278 "samba-without-smb1-build": {
279 "git-clone-required": True,
281 ("configure", "./configure.developer --without-smb1-server --without-ad-dc" + samba_configure_params
),
283 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
284 ("chmod-R-a-w", "chmod -R a-w ."),
288 "samba-no-opath-build": {
289 "git-clone-required": True,
291 ("configure", "ADDITIONAL_CFLAGS='-DDISABLE_OPATH=1' ./configure.developer --without-ad-dc " + samba_configure_params
),
293 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
294 ("chmod-R-a-w", "chmod -R a-w ."),
298 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
301 ("random-sleep", random_sleep(300, 900)),
302 ("configure", "./configure.developer" + samba_configure_params
),
304 ("test", make_test(exclude_envs
=[
317 "ad_dc_default_smb1",
325 "ad_member_idmap_rid",
326 "admem_idmap_autorid",
327 "ad_member_idmap_ad",
335 "fileserver_smb1_done",
349 "ad_dc_default_smb1",
350 "ad_dc_default_smb1_done",
358 ("test-slow-none", make_test(cmd
='make test', TESTS
="--include=selftest/slow-none", include_envs
=["none"])),
360 ("install", "make install"),
361 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
362 ("clean", "make clean"),
366 # We have 'test' before 'install' because, 'test' should work without 'install (runs all the other envs)'
369 ("random-sleep", random_sleep(300, 900)),
370 ("configure", "./configure.developer --with-system-mitkrb5 --with-experimental-mit-ad-dc" + samba_configure_params
),
372 ("test", make_test(exclude_envs
=[
385 "ad_dc_default_smb1",
386 "ad_dc_default_smb1_done",
394 "ad_member_idmap_rid",
395 "admem_idmap_autorid",
396 "ad_member_idmap_ad",
404 "fileserver_smb1_done",
418 "ad_dc_default_smb1",
419 "ad_dc_default_smb1_done",
428 ("install", "make install"),
429 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
430 ("clean", "make clean"),
435 "dependency": "samba-nt4-build",
437 ("random-sleep", random_sleep(300, 900)),
438 ("test", make_test(include_envs
=[
447 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
451 "samba-fileserver": {
452 "dependency": "samba-h5l-build",
454 ("random-sleep", random_sleep(300, 900)),
455 ("test", make_test(include_envs
=[
458 "fileserver_smb1_done",
460 "ktest", # ktest is also tested in samba-ktest-mit samba
461 # and samba-mitkrb5 but is tested here against
465 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
469 "samba-fileserver-without-smb1": {
470 "dependency": "samba-without-smb1-build",
472 ("random-sleep", random_sleep(300, 900)),
473 ("test", make_test(include_envs
=["fileserver"])),
475 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
479 # This is a full build without the AD DC so we test the build with
480 # MIT Kerberos from the current system. Runtime behaviour is
481 # confirmed via the ktest (static ccache and keytab) environment
483 # This environment also used to confirm we can still build with --with-libunwind
486 ("random-sleep", random_sleep(300, 900)),
487 ("configure", "./configure.developer --without-ad-dc --with-libunwind --with-system-mitkrb5 " + samba_configure_params
),
489 ("test", make_test(include_envs
=[
490 "ktest", # ktest is also tested in fileserver, samba and
491 # samba-mitkrb5 but is tested here against a
495 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
500 "dependency": "samba-def-build",
502 ("random-sleep", random_sleep(300, 900)),
503 ("test", make_test(include_envs
=[
505 "ad_member_idmap_rid",
506 "admem_idmap_autorid",
507 "ad_member_idmap_ad",
509 "ad_member_offlogon",
512 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
517 "dependency": "samba-no-opath-build",
519 ("random-sleep", random_sleep(300, 900)),
521 cmd
="make testonly DISABLE_OPATH=1",
531 ("check-clean-tree", "script/clean-source-tree.sh"),
536 "dependency": "samba-no-opath-build",
538 ("random-sleep", random_sleep(300, 900)),
540 cmd
="make testonly DISABLE_OPATH=1",
544 "fileserver_smb1_done",
547 ("check-clean-tree", "script/clean-source-tree.sh"),
552 "dependency": "samba-def-build",
554 ("random-sleep", random_sleep(1, 1)),
555 ("test", make_test(include_envs
=[
563 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
568 "dependency": "samba-def-build",
570 ("random-sleep", random_sleep(1, 1)),
571 ("test", make_test(include_envs
=[
577 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
582 "dependency": "samba-def-build",
584 ("random-sleep", random_sleep(1, 1)),
585 ("test", make_test(include_envs
=[
592 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
597 "dependency": "samba-def-build",
599 ("random-sleep", random_sleep(1, 1)),
600 ("test", make_test(include_envs
=[
606 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
610 "dependency": "samba-def-build",
612 ("random-sleep", random_sleep(1, 1)),
613 ("test", make_test(include_envs
=[
618 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
623 "dependency": "samba-def-build",
625 ("random-sleep", random_sleep(1, 1)),
626 ("test", make_test(include_envs
=[
627 "ad_dc_default", "ad_dc_default_smb1", "ad_dc_default_smb1_done"])),
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
=["ad_dc_slowtests", "ad_dc_backup"])),
639 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
643 "samba-schemaupgrade": {
644 "dependency": "samba-def-build",
646 ("random-sleep", random_sleep(1, 1)),
647 ("test", make_test(include_envs
=["schema_dc", "schema_pair_dc"])),
649 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
653 # We split out the ad_dc_ntvfs tests (which are long) so other test do not wait
654 # This is currently the longest task, so we don't randomly delay it.
655 "samba-ad-dc-ntvfs": {
656 "dependency": "samba-def-build",
658 ("random-sleep", random_sleep(1, 1)),
659 ("test", make_test(include_envs
=["ad_dc_ntvfs"])),
661 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
665 # Test fips compliance
667 "dependency": "samba-mit-build",
669 ("random-sleep", random_sleep(1, 1)),
670 ("test", make_test(include_envs
=["ad_dc_fips", "ad_member_fips"])),
671 # TODO: This seems to generate only an empty samba-fips.info ("lcov", LCOV_CMD),
672 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
676 # run the backup/restore testenvs separately as they're fairly standalone
677 # (and CI seems to max out at ~3 different DCs running at once)
679 "dependency": "samba-def-build",
681 ("random-sleep", random_sleep(300, 900)),
682 ("test", make_test(include_envs
=[
688 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
692 "dependency": "samba-def-build",
694 ("random-sleep", random_sleep(300, 900)),
695 ("test", make_test(include_envs
=[
701 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
706 "dependency": "samba-mit-build",
708 ("random-sleep", random_sleep(1, 1)),
709 ("test", make_test(include_envs
=[
711 "ad_member_idmap_rid",
712 "admem_idmap_autorid",
713 "ad_member_idmap_ad",
715 "ad_member_offlogon",
718 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
722 "samba-addc-mit-1": {
723 "dependency": "samba-mit-build",
725 ("random-sleep", random_sleep(1, 1)),
726 ("test", make_test(include_envs
=[
734 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
738 "samba-addc-mit-4a": {
739 "dependency": "samba-mit-build",
741 ("random-sleep", random_sleep(1, 1)),
742 ("test", make_test(include_envs
=[
748 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
751 "samba-addc-mit-4b": {
752 "dependency": "samba-mit-build",
754 ("random-sleep", random_sleep(1, 1)),
755 ("test", make_test(include_envs
=[
760 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
766 ("configure", "./configure.developer --abi-check-disable" + samba_configure_params
),
768 ("test", make_test(TESTS
="${TESTS}")),
773 # Test cross-compile infrastructure
776 ("random-sleep", random_sleep(900, 1500)),
777 ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
),
778 ("configure-cross-execute", "./configure.developer --out ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
779 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
),
780 ("verify-cross-execute-output", "grep '^Checking value of NSIG' ./bin-xe/cross-answers.txt"),
781 ("configure-cross-answers", "./configure.developer --out ./bin-xa --cross-compile" \
782 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
),
783 ("compare-results", "script/compare_cc_results.py "
784 "./bin/c4che/default{} "
785 "./bin-xe/c4che/default{} "
786 "./bin-xa/c4che/default{}".format(*([CACHE_SUFFIX
]*3))),
787 ("modify-cross-answers", "sed -i.bak -e 's/^\\(Checking value of NSIG:\\) .*/\\1 \"1234\"/' ./bin-xe/cross-answers.txt"),
788 ("configure-cross-answers-modified", "./configure.developer --out ./bin-xa2 --cross-compile" \
789 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa2/ab" + samba_configure_params
),
790 ("verify-cross-answers", "test $(sed -n -e 's/VALUEOF_NSIG = \\(.*\\)/\\1/p' ./bin-xa2/c4che/default{})" \
791 " = \"'1234'\"".format(CACHE_SUFFIX
)),
792 ("invalidate-cross-answers", "sed -i.bak -e '/^Checking value of NSIG/d' ./bin-xe/cross-answers.txt"),
793 ("configure-cross-answers-fail", "./configure.developer --out ./bin-xa3 --cross-compile" \
794 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa3/ab" + samba_configure_params
+ \
799 # test build with -O3 -- catches extra warnings and bugs, tests the ad_dc environments
802 ("random-sleep", random_sleep(300, 900)),
803 ("configure", "ADDITIONAL_CFLAGS='-O3 -Wp,-D_FORTIFY_SOURCE=2' ./configure.developer --abi-check-disable" + samba_configure_params
),
805 ("test", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
806 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
808 ("install", "make install"),
809 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
810 ("clean", "make clean"),
816 ("random-sleep", random_sleep(300, 900)),
817 ("configure", "./configure.developer --abi-check-disable --disable-warnings-as-errors" + samba_configure_params
),
819 ("nonetest", make_test(cmd
='make test', TESTS
="--exclude=selftest/slow-none", include_envs
=["none"])),
820 ("quicktest", make_test(cmd
='make quicktest', include_envs
=["ad_dc", "ad_dc_smb1", "ad_dc_smb1_done"])),
821 ("ktest", make_test(cmd
='make test', include_envs
=["ktest"])),
822 ("install", "make install"),
823 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
824 ("clean", "make clean"),
830 ("random-sleep", random_sleep(900, 1500)),
832 # make sure we have tdb around:
833 ("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}"),
834 ("tdb-make", "cd lib/tdb && make"),
835 ("tdb-install", "cd lib/tdb && make install"),
837 # build samba with cluster support (also building ctdb):
839 "PYTHONPATH=${PYTHON_PREFIX}:$PYTHONPATH "
840 "PKG_CONFIG_PATH=${PREFIX_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH} "
841 "./configure.developer ${PREFIX} "
842 "--with-selftest-prefix=./bin/ab "
843 "--with-cluster-support "
845 "--bundled-libraries=!tdb"),
846 ("samba-make", "make"),
847 ("samba-check", "./bin/smbd --configfile=/dev/null -b | grep CLUSTER_SUPPORT"),
848 ("samba-install", "make install"),
849 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd"),
853 INJECT_SELFTEST_PREFIX
=0,
854 include_envs
=["clusteredmember"])
858 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
859 ("clean", "make clean"),
860 ("ctdb-clean", "cd ./ctdb && make clean"),
866 ("random-sleep", random_sleep(300, 900)),
867 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
),
868 ("talloc-make", "cd lib/talloc && make"),
869 ("talloc-install", "cd lib/talloc && make install"),
871 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
),
872 ("tdb-make", "cd lib/tdb && make"),
873 ("tdb-install", "cd lib/tdb && make install"),
875 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
),
876 ("tevent-make", "cd lib/tevent && make"),
877 ("tevent-install", "cd lib/tevent && make install"),
879 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
),
880 ("ldb-make", "cd lib/ldb && make"),
881 ("ldb-install", "cd lib/ldb && make install"),
883 ("nondevel-configure", samba_libs_envvars
+ " ./configure ${PREFIX}"),
884 ("nondevel-make", "make -j"),
885 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0"),
886 ("nondevel-no-libtalloc", "find ./bin | grep -v 'libtalloc-report' | grep 'libtalloc' && exit 1; exit 0"),
887 ("nondevel-no-libtdb", "find ./bin | grep -v 'libtdb-wrap' | grep 'libtdb' && exit 1; exit 0"),
888 ("nondevel-no-libtevent", "find ./bin | grep -v 'libtevent-util' | grep 'libtevent' && exit 1; exit 0"),
889 ("nondevel-no-libldb", "find ./bin | grep -v 'module' | grep -v 'libldbsamba' | grep 'libldb' && exit 1; exit 0"),
890 ("nondevel-no-samba-nss_winbind", "ldd ./bin/plugins/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
891 ("nondevel-no-samba-nss_wins", "ldd ./bin/plugins/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
892 ("nondevel-no-samba-libwbclient", "ldd ./bin/shared/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
893 ("nondevel-no-samba-pam_winbind", "ldd ./bin/plugins/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
894 ("nondevel-no-public-nss_winbind",
895 check_symbols("./bin/plugins/libnss_winbind.so.2", "_nss_winbind_")),
896 ("nondevel-no-public-nss_wins",
897 check_symbols("./bin/plugins/libnss_wins.so.2", "_nss_wins_")),
898 ("nondevel-no-public-libwbclient",
899 check_symbols("./bin/shared/libwbclient.so.0", "wbc")),
900 ("nondevel-no-public-pam_winbind",
901 check_symbols("./bin/plugins/pam_winbind.so", "pam_sm_")),
902 ("nondevel-no-public-winbind_krb5_locator",
903 check_symbols("./bin/plugins/winbind_krb5_locator.so", "service_locator")),
904 ("nondevel-no-public-async_dns_krb5_locator",
905 check_symbols("./bin/plugins/async_dns_krb5_locator.so", "service_locator")),
906 ("nondevel-install", "make -j install"),
907 ("nondevel-dist", "make dist"),
909 ("prefix-no-private-libtalloc", "find ${PREFIX_DIR} | grep -v 'libtalloc-report' | grep 'private.*libtalloc' && exit 1; exit 0"),
910 ("prefix-no-private-libtdb", "find ${PREFIX_DIR} | grep -v 'libtdb-wrap' | grep 'private.*libtdb' && exit 1; exit 0"),
911 ("prefix-no-private-libtevent", "find ${PREFIX_DIR} | grep -v 'libtevent-util' | grep 'private.*libtevent' && exit 1; exit 0"),
912 ("prefix-no-private-libldb", "find ${PREFIX_DIR} | grep -v 'module' | grep -v 'libldbsamba' | grep 'private.*libldb' && exit 1; exit 0"),
913 ("prefix-no-samba-nss_winbind", "ldd ${PREFIX_DIR}/lib/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
914 ("prefix-no-samba-nss_wins", "ldd ${PREFIX_DIR}/lib/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
915 ("prefix-no-samba-libwbclient", "ldd ${PREFIX_DIR}/lib/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
916 ("prefix-no-samba-pam_winbind", "ldd ${PREFIX_DIR}/lib/security/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
917 ("prefix-no-public-nss_winbind",
918 check_symbols("${PREFIX_DIR}/lib/libnss_winbind.so.2", "_nss_winbind_")),
919 ("prefix-no-public-nss_wins",
920 check_symbols("${PREFIX_DIR}/lib/libnss_wins.so.2", "_nss_wins_")),
921 ("prefix-no-public-libwbclient",
922 check_symbols("${PREFIX_DIR}/lib/libwbclient.so.0", "wbc")),
923 ("prefix-no-public-pam_winbind",
924 check_symbols("${PREFIX_DIR}/lib/security/pam_winbind.so", "pam_sm_")),
925 ("prefix-no-public-winbind_krb5_locator",
926 check_symbols("${PREFIX_DIR}/lib/krb5/winbind_krb5_locator.so",
928 ("prefix-no-public-async_dns_krb5_locator",
929 check_symbols("${PREFIX_DIR}/lib/krb5/async_dns_krb5_locator.so",
932 # retry with all modules shared
933 ("allshared-distclean", "make distclean"),
934 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL"),
935 ("allshared-make", "make -j"),
936 ("allshared-no-libtalloc", "find ./bin | grep -v 'libtalloc-report' | grep 'libtalloc' && exit 1; exit 0"),
937 ("allshared-no-libtdb", "find ./bin | grep -v 'libtdb-wrap' | grep 'libtdb' && exit 1; exit 0"),
938 ("allshared-no-libtevent", "find ./bin | grep -v 'libtevent-util' | grep 'libtevent' && exit 1; exit 0"),
939 ("allshared-no-libldb", "find ./bin | grep -v 'module' | grep -v 'libldbsamba' | grep 'libldb' && exit 1; exit 0"),
940 ("allshared-no-samba-nss_winbind", "ldd ./bin/plugins/libnss_winbind.so.2 | grep 'samba' && exit 1; exit 0"),
941 ("allshared-no-samba-nss_wins", "ldd ./bin/plugins/libnss_wins.so.2 | grep 'samba' && exit 1; exit 0"),
942 ("allshared-no-samba-libwbclient", "ldd ./bin/shared/libwbclient.so.0 | grep 'samba' && exit 1; exit 0"),
943 ("allshared-no-samba-pam_winbind", "ldd ./bin/plugins/pam_winbind.so | grep -v 'libtalloc.so.2' | grep 'samba' && exit 1; exit 0"),
944 ("allshared-no-public-nss_winbind",
945 check_symbols("./bin/plugins/libnss_winbind.so.2", "_nss_winbind_")),
946 ("allshared-no-public-nss_wins",
947 check_symbols("./bin/plugins/libnss_wins.so.2", "_nss_wins_")),
948 ("allshared-no-public-libwbclient",
949 check_symbols("./bin/shared/libwbclient.so.0", "wbc")),
950 ("allshared-no-public-pam_winbind",
951 check_symbols("./bin/plugins/pam_winbind.so", "pam_sm_")),
952 ("allshared-no-public-winbind_krb5_locator",
953 check_symbols("./bin/plugins/winbind_krb5_locator.so", "service_locator")),
954 ("allshared-no-public-async_dns_krb5_locator",
955 check_symbols("./bin/plugins/async_dns_krb5_locator.so", "service_locator")),
961 # build the fuzzers (static) via the oss-fuzz script
962 ("fuzzers-mkdir-prefix", "mkdir -p ${PREFIX_DIR}"),
963 ("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"),
967 # * Test smbd and smbtorture can build semi-static
969 # * Test Samba without python still builds.
971 # When this test fails due to more use of Python, the expectations
972 # is that the newly failing part of the code should be disabled
973 # when --disable-python is set (rather than major work being done
974 # to support this environment).
976 # The target here is for vendors shipping a minimal smbd.
977 "samba-minimal-smbd": {
979 ("random-sleep", random_sleep(300, 900)),
981 # build with all modules static
982 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL"),
983 ("allstatic-make", "make -j"),
984 ("allstatic-test", make_test(TESTS
="samba3.smb2.create.*nt4_dc")),
985 ("allstatic-lcov", LCOV_CMD
),
987 # retry with nonshared smbd and smbtorture
988 ("nonshared-distclean", "make distclean"),
989 ("nonshared-configure", "./configure.developer " + samba_configure_params
+ " --bundled-libraries=ALL --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd"),
990 ("nonshared-make", "make -j"),
991 # TODO ("nonshared-test", make_test(TESTS="samba3.smb2.create.*nt4_dc")),
992 # TODO ("nonshared-lcov", LCOV_CMD),
994 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
995 ("clean", "make clean"),
1001 ("random-sleep", random_sleep(300, 900)),
1003 ("configure", "./configure.developer ${ENABLE_COVERAGE} ${PREFIX} --with-profiling-data --disable-python --without-ad-dc"),
1004 ("make", "make -j"),
1005 ("find-python", "script/find_python.sh ${PREFIX}"),
1006 ("test", "make test-nopython"),
1008 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1009 ("clean", "make clean"),
1011 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1012 ("talloc-make", "cd lib/talloc && make"),
1013 ("talloc-install", "cd lib/talloc && make install"),
1015 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1016 ("tdb-make", "cd lib/tdb && make"),
1017 ("tdb-install", "cd lib/tdb && make install"),
1019 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1020 ("tevent-make", "cd lib/tevent && make"),
1021 ("tevent-install", "cd lib/tevent && make install"),
1023 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python"),
1024 ("ldb-make", "cd lib/ldb && make"),
1025 ("ldb-install", "cd lib/ldb && make install"),
1027 # retry against installed library packages, but no required modules
1028 ("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"),
1029 ("libs-make", "make -j"),
1030 ("libs-install", "make install"),
1031 ("libs-check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1032 ("libs-clean", "make clean"),
1037 "samba-shellcheck": {
1039 ("run", "script/check-shell-scripts.sh ."),
1045 ("random-sleep", random_sleep(60, 600)),
1046 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1048 ("install", "make install"),
1049 ("test", "make test"),
1051 ("clean", "make clean"),
1052 ("configure-no-lmdb", "./configure ${ENABLE_COVERAGE} --enable-developer --without-ldb-lmdb -C ${PREFIX}"),
1053 ("make-no-lmdb", "make"),
1054 ("test-no-lmdb", "make test"),
1055 ("lcov-no-lmdb", LCOV_CMD
),
1056 ("install-no-lmdb", "make install"),
1057 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1058 ("distcheck", "make distcheck"),
1059 ("clean", "make clean"),
1065 ("random-sleep", random_sleep(60, 600)),
1066 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1068 ("install", "make install"),
1069 ("test", "make test"),
1071 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1072 ("distcheck", "make distcheck"),
1073 ("clean", "make clean"),
1079 ("random-sleep", random_sleep(60, 600)),
1080 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1082 ("install", "make install"),
1083 ("test", "make test"),
1085 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1086 ("distcheck", "make distcheck"),
1087 ("clean", "make clean"),
1093 ("random-sleep", random_sleep(60, 600)),
1094 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1096 ("install", "make install"),
1097 ("test", "make test"),
1099 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1100 ("distcheck", "make distcheck"),
1101 ("clean", "make clean"),
1107 ("random-sleep", random_sleep(60, 600)),
1108 ("configure", "./configure ${ENABLE_COVERAGE} --enable-developer -C ${PREFIX}"),
1110 ("install", "make install"),
1111 ("test", "make test"),
1113 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1114 ("distcheck", "make distcheck"),
1115 ("clean", "make clean"),
1120 "git-clone-required": True,
1122 ("random-sleep", random_sleep(60, 600)),
1123 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}"),
1124 ("touch", "touch *.yp"),
1126 ("test", "make test"),
1127 ("install", "make install"),
1128 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm"),
1129 ("check-clean-tree", CLEAN_SOURCE_TREE_CMD
),
1130 ("clean", "make clean"),
1134 # these are useful for debugging autobuild
1137 ("pass", 'echo passing && /bin/true'),
1142 ("fail", 'echo failing && /bin/false'),
1147 defaulttasks
= list(tasks
.keys())
1149 defaulttasks
.remove("pass")
1150 defaulttasks
.remove("fail")
1152 # The build tasks will be brought in by the test tasks as needed
1153 defaulttasks
.remove("samba-def-build")
1154 defaulttasks
.remove("samba-nt4-build")
1155 defaulttasks
.remove("samba-mit-build")
1156 defaulttasks
.remove("samba-h5l-build")
1157 defaulttasks
.remove("samba-no-opath-build")
1159 # This is not a normal test, but a task to support manually running
1160 # one test under autobuild
1161 defaulttasks
.remove("samba-test-only")
1163 # Only built on GitLab CI and not in the default autobuild because it
1164 # uses too much space (4GB of semi-static binaries)
1165 defaulttasks
.remove("samba-fuzz")
1167 # The FIPS build runs only in GitLab CI on a current Fedora Docker
1168 # container where a simulated FIPS mode is possible.
1169 defaulttasks
.remove("samba-fips")
1171 # The MIT build runs on a current Fedora where an up to date MIT KDC
1172 # is already packaged. This avoids needing to backport a current MIT
1173 # to the default Ubuntu 18.04, particularly during development, and
1174 # the need to install on the shared sn-devel-184.
1176 defaulttasks
.remove("samba-mitkrb5")
1177 defaulttasks
.remove("samba-admem-mit")
1178 defaulttasks
.remove("samba-addc-mit-1")
1179 defaulttasks
.remove("samba-addc-mit-4a")
1180 defaulttasks
.remove("samba-addc-mit-4b")
1182 defaulttasks
.remove("samba-32bit")
1184 if os
.environ
.get("AUTOBUILD_SKIP_SAMBA_O3", "0") == "1":
1185 defaulttasks
.remove("samba-o3")
1194 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
1196 show
= options
.verbose
1198 do_print("Running: '%s' in '%s'" % (cmd
, dir))
1200 out
= check_output([cmd
], shell
=True, cwd
=dir)
1201 return out
.decode(encoding
='utf-8', errors
='backslashreplace')
1203 return check_call(cmd
, shell
=True, cwd
=dir)
1205 return call(cmd
, shell
=True, cwd
=dir)
1207 def rmdir_force(dirname
, re_raise
=True):
1209 run_cmd("test -d %s && chmod -R +w %s; rm -rf %s" % (
1210 dirname
, dirname
, dirname
), output
=True, show
=True)
1211 except CalledProcessError
as e
:
1212 do_print("Failed: '%s'" % (str(e
)))
1213 run_cmd("tree %s" % dirname
, output
=True, show
=True)
1219 class builder(object):
1220 '''handle build of one directory'''
1222 def __init__(self
, name
, definition
):
1224 self
.dir = builddirs
.get(name
, '.')
1225 self
.tag
= self
.name
.replace('/', '_')
1226 self
.definition
= definition
1227 self
.sequence
= definition
["sequence"]
1228 self
.git_clone_required
= False
1229 if "git-clone-required" in definition
:
1230 self
.git_clone_required
= bool(definition
["git-clone-required"])
1234 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
1235 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
1237 do_print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
1238 do_print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
1239 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
1240 self
.stdout
= open(self
.stdout_path
, 'w')
1241 self
.stderr
= open(self
.stderr_path
, 'w')
1242 self
.stdin
= open("/dev/null", 'r')
1243 self
.builder_dir
= "%s/%s" % (testbase
, self
.tag
)
1244 self
.test_source_dir
= self
.builder_dir
1245 self
.cwd
= "%s/%s" % (self
.builder_dir
, self
.dir)
1246 self
.selftest_prefix
= "%s/bin/ab" % (self
.cwd
)
1247 self
.prefix
= "%s/%s" % (test_prefix
, self
.tag
)
1249 self
.producer
= None
1251 if self
.git_clone_required
:
1252 assert "dependency" not in definition
1254 def mark_existing(self
):
1255 do_print('%s: Mark as existing dependency' % self
.name
)
1256 self
.next
= len(self
.sequence
)
1259 def add_consumer(self
, consumer
):
1260 do_print("%s: add consumer: %s" % (self
.name
, consumer
.name
))
1261 consumer
.producer
= self
1262 consumer
.test_source_dir
= self
.test_source_dir
1263 self
.consumers
.append(consumer
)
1265 def start_next(self
):
1266 if self
.producer
is not None:
1267 if not self
.producer
.done
:
1268 do_print("%s: Waiting for producer: %s" % (self
.name
, self
.producer
.name
))
1272 rmdir_force(self
.builder_dir
)
1273 rmdir_force(self
.prefix
)
1274 if self
.producer
is not None:
1275 run_cmd("mkdir %s" % (self
.builder_dir
), dir=test_master
, show
=True)
1276 elif not self
.git_clone_required
:
1277 run_cmd("cp -R -a -l %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1279 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.builder_dir
), dir=test_master
, show
=True)
1281 if self
.next
== len(self
.sequence
):
1283 do_print('%s: Completed OK' % self
.name
)
1285 if not options
.nocleanup
and len(self
.consumers
) == 0:
1286 do_print('%s: Cleaning up' % self
.name
)
1287 rmdir_force(self
.builder_dir
)
1288 rmdir_force(self
.prefix
)
1289 for consumer
in self
.consumers
:
1290 if consumer
.next
!= 0:
1292 do_print('%s: Starting consumer %s' % (self
.name
, consumer
.name
))
1293 consumer
.start_next()
1294 if self
.producer
is not None:
1295 self
.producer
.consumers
.remove(self
)
1296 assert self
.producer
.done
1297 self
.producer
.start_next()
1298 do_print('%s: Remaining consumers %u' % (self
.name
, len(self
.consumers
)))
1300 (self
.stage
, self
.cmd
) = self
.sequence
[self
.next
]
1301 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(plat_specific
=1, standard_lib
=0, prefix
=self
.prefix
))
1302 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
1303 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
1304 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
1305 self
.cmd
= self
.cmd
.replace("${TEST_SOURCE_DIR}", self
.test_source_dir
)
1306 self
.cmd
= self
.cmd
.replace("${SELFTEST_PREFIX}", self
.selftest_prefix
)
1307 self
.cmd
= self
.cmd
.replace("${LOG_BASE}", options
.log_base
)
1308 self
.cmd
= self
.cmd
.replace("${NAME}", self
.name
)
1309 self
.cmd
= self
.cmd
.replace("${ENABLE_COVERAGE}", options
.enable_coverage
)
1310 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, self
.cwd
))
1311 self
.proc
= Popen(self
.cmd
, shell
=True,
1312 close_fds
=True, cwd
=self
.cwd
,
1313 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
1316 def expand_dependencies(n
):
1318 if "dependency" in tasks
[n
]:
1319 depname
= tasks
[n
]["dependency"]
1320 assert depname
in tasks
1321 sdeps
= expand_dependencies(depname
)
1322 assert n
not in sdeps
1325 deps
.append(depname
)
1329 class buildlist(object):
1330 '''handle build of multiple directories'''
1332 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
1333 self
.tail_proc
= None
1336 if options
.restrict_tests
:
1337 tasknames
= ["samba-test-only"]
1339 tasknames
= defaulttasks
1341 given_tasknames
= tasknames
.copy()
1342 implicit_tasknames
= []
1343 for n
in given_tasknames
:
1344 deps
= expand_dependencies(n
)
1346 if dep
in given_tasknames
:
1348 if dep
in implicit_tasknames
:
1350 implicit_tasknames
.append(dep
)
1352 tasknames
= implicit_tasknames
.copy()
1353 tasknames
.extend(given_tasknames
)
1354 do_print("given_tasknames: %s" % given_tasknames
)
1355 do_print("implicit_tasknames: %s" % implicit_tasknames
)
1356 do_print("tasknames: %s" % tasknames
)
1357 self
.tlist
= [builder(n
, tasks
[n
]) for n
in tasknames
]
1360 rebase_remote
= "rebaseon"
1362 "git-clone-required": True,
1366 git remote add -t %s %s %s
1370 git describe %s/%s > old_remote_branch.desc
1372 git describe %s/%s > remote_branch.desc
1373 diff old_remote_branch.desc remote_branch.desc
1376 rebase_branch
, rebase_remote
, rebase_url
,
1378 rebase_remote
, rebase_branch
,
1380 rebase_remote
, rebase_branch
1383 self
.retry
= builder('retry', retry_task
)
1384 self
.need_retry
= False
1386 if options
.skip_dependencies
:
1387 for b
in self
.tlist
:
1388 if b
.name
in implicit_tasknames
:
1391 for b
in self
.tlist
:
1392 do_print("b.name=%s" % b
.name
)
1393 if "dependency" not in b
.definition
:
1395 depname
= b
.definition
["dependency"]
1396 do_print("b.name=%s: dependency:%s" % (b
.name
, depname
))
1397 for p
in self
.tlist
:
1398 if p
.name
== depname
:
1401 def kill_kids(self
):
1402 if self
.tail_proc
is not None:
1403 self
.tail_proc
.terminate()
1404 self
.tail_proc
.wait()
1405 self
.tail_proc
= None
1406 if self
.retry
is not None:
1407 self
.retry
.proc
.terminate()
1408 self
.retry
.proc
.wait()
1410 for b
in self
.tlist
:
1411 if b
.proc
is not None:
1412 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.test_source_dir
, checkfail
=False)
1420 for b
in self
.tlist
:
1423 none_running
= False
1424 b
.status
= b
.proc
.poll()
1425 if b
.status
is None:
1430 ret
= self
.retry
.proc
.poll()
1432 self
.need_retry
= True
1440 for b
in self
.tlist
:
1443 self
.retry
.start_next()
1446 if options
.retry
and self
.need_retry
:
1448 do_print("retry needed")
1449 return (0, None, None, None, "retry")
1452 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
1454 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
1457 return (0, None, None, None, "All OK")
1459 def write_system_info(self
, filename
):
1460 with
open(filename
, 'w') as f
:
1461 for cmd
in ['uname -a',
1465 'cat /proc/cpuinfo',
1468 'df -m %s' % testbase
]:
1470 out
= run_cmd(cmd
, output
=True, checkfail
=False)
1471 except CalledProcessError
as e
:
1472 out
= "<failed: %s>" % str(e
)
1473 print('### %s' % cmd
, file=f
)
1477 def tarlogs(self
, fname
):
1478 with tarfile
.open(fname
, "w:gz") as tar
:
1479 for b
in self
.tlist
:
1480 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
1481 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
1482 if os
.path
.exists("autobuild.log"):
1483 tar
.add("autobuild.log")
1484 filename
= 'system-info.txt'
1485 self
.write_system_info(filename
)
1488 def remove_logs(self
):
1489 for b
in self
.tlist
:
1490 os
.unlink(b
.stdout_path
)
1491 os
.unlink(b
.stderr_path
)
1493 def start_tail(self
):
1494 cmd
= ["tail", "-f"]
1495 for b
in self
.tlist
:
1496 cmd
.append(b
.stdout_path
)
1497 cmd
.append(b
.stderr_path
)
1498 self
.tail_proc
= Popen(cmd
, close_fds
=True)
1501 def cleanup(do_raise
=False):
1502 if options
.nocleanup
:
1504 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
1505 run_cmd("stat %s" % testbase
, show
=True)
1506 do_print("Cleaning up %r" % cleanup_list
)
1507 for d
in cleanup_list
:
1508 ok
= rmdir_force(d
, re_raise
=False)
1511 if os
.path
.isdir(d
):
1512 do_print("Killing, waiting and retry")
1513 run_cmd("killbysubdir %s > /dev/null 2>&1" % d
, checkfail
=False)
1515 do_print("Waiting and retry")
1517 rmdir_force(d
, re_raise
=do_raise
)
1520 def daemonize(logfile
):
1522 if pid
== 0: # Parent
1525 if pid
!= 0: # Actual daemon
1530 import resource
# Resource usage information.
1531 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
1532 if maxfd
== resource
.RLIM_INFINITY
:
1533 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
1534 for fd
in range(0, maxfd
):
1539 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
1544 def write_pidfile(fname
):
1545 '''write a pid file, cleanup on exit'''
1546 with
open(fname
, mode
='w') as f
:
1547 f
.write("%u\n" % os
.getpid())
1550 def rebase_tree(rebase_url
, rebase_branch
="master"):
1551 rebase_remote
= "rebaseon"
1552 do_print("Rebasing on %s" % rebase_url
)
1553 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1554 run_cmd("git remote add -t %s %s %s" %
1555 (rebase_branch
, rebase_remote
, rebase_url
),
1556 show
=True, dir=test_master
)
1557 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
1558 if options
.fix_whitespace
:
1559 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
1560 (rebase_remote
, rebase_branch
),
1561 show
=True, dir=test_master
)
1563 run_cmd("git rebase --force-rebase %s/%s" %
1564 (rebase_remote
, rebase_branch
),
1565 show
=True, dir=test_master
)
1566 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
1567 (rebase_remote
, rebase_branch
),
1568 dir=test_master
, output
=True)
1570 do_print("No differences between HEAD and %s/%s - exiting" %
1571 (rebase_remote
, rebase_branch
))
1573 run_cmd("git describe %s/%s" %
1574 (rebase_remote
, rebase_branch
),
1575 show
=True, dir=test_master
)
1576 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1577 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
1578 (rebase_remote
, rebase_branch
),
1579 show
=True, dir=test_master
)
1582 def push_to(push_url
, push_branch
="master"):
1583 push_remote
= "pushto"
1584 do_print("Pushing to %s" % push_url
)
1586 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
1587 run_cmd("git commit --amend -c HEAD", dir=test_master
)
1588 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
1589 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
1590 run_cmd("git remote add -t %s %s %s" %
1591 (push_branch
, push_remote
, push_url
),
1592 show
=True, dir=test_master
)
1593 run_cmd("git push %s +HEAD:%s" %
1594 (push_remote
, push_branch
),
1595 show
=True, dir=test_master
)
1598 def send_email(subject
, text
, log_tar
):
1599 if options
.email
is None:
1600 do_print("not sending email because the recipient is not set")
1601 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
1604 outer
= MIMEMultipart()
1605 outer
['Subject'] = subject
1606 outer
['To'] = options
.email
1607 outer
['From'] = options
.email_from
1608 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
1609 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
1610 outer
.attach(MIMEText(text
, 'plain', 'utf-8'))
1611 if options
.attach_logs
:
1612 with
open(log_tar
, 'rb') as fp
:
1613 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
1614 # Set the filename parameter
1615 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
1617 content
= outer
.as_string()
1618 s
= smtplib
.SMTP(options
.email_server
)
1619 email_user
= os
.getenv('SMTP_USERNAME')
1620 email_password
= os
.getenv('SMTP_PASSWORD')
1621 if email_user
is not None:
1623 s
.login(email_user
, email_password
)
1625 s
.sendmail(options
.email_from
, [options
.email
], content
)
1630 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1631 elapsed_time
, log_base
=None, add_log_tail
=True):
1632 '''send an email to options.email about the failure'''
1633 elapsed_minutes
= elapsed_time
/ 60.0
1634 if log_base
is None:
1639 Your autobuild on %s failed after %.1f minutes
1640 when trying to test %s with the following error:
1644 the autobuild has been abandoned. Please fix the error and resubmit.
1646 A summary of the autobuild process is here:
1649 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
1651 if options
.restrict_tests
:
1653 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1655 if failed_task
!= 'rebase':
1657 You can see logs of the failed task here:
1662 or you can get full logs of all tasks in this job here:
1666 The top commit for the tree that was built was:
1670 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
1673 f
= open("%s/%s.stdout" % (gitroot
, failed_tag
), 'r')
1674 lines
= f
.readlines()
1675 log_tail
= "".join(lines
[-50:])
1676 num_lines
= len(lines
)
1678 # Also include stderr (compile failures) if < 50 lines of stdout
1679 f
= open("%s/%s.stderr" % (gitroot
, failed_tag
), 'r')
1680 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
1683 The last 50 lines of log messages:
1689 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1690 send_email('autobuild[%s] failure on %s for task %s during %s'
1691 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
1695 def email_success(elapsed_time
, log_base
=None):
1696 '''send an email to options.email about a successful build'''
1697 if log_base
is None:
1702 Your autobuild on %s has succeeded after %.1f minutes.
1704 ''' % (platform
.node(), elapsed_time
/ 60.)
1706 if options
.restrict_tests
:
1708 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1710 if options
.keeplogs
:
1713 you can get full logs of all tasks in this job here:
1720 The top commit for the tree that was built was:
1723 ''' % top_commit_msg
1725 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1726 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
1730 # get the top commit message, for emails
1731 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
1734 if options
.skip_dependencies
:
1735 run_cmd("stat %s" % testbase
, dir=testbase
, output
=True)
1737 os
.makedirs(testbase
)
1738 except Exception as reason
:
1739 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
1740 cleanup_list
.append(testbase
)
1743 logfile
= os
.path
.join(testbase
, "log")
1744 do_print("Forking into the background, writing progress to %s" % logfile
)
1747 write_pidfile(gitroot
+ "/autobuild.pid")
1749 start_time
= time
.time()
1753 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
1754 os
.makedirs(test_tmpdir
)
1755 # The waf uninstall code removes empty directories all the way
1756 # up the tree. Creating a file in test_tmpdir stops it from
1758 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
1759 ".directory-is-not-empty"), show
=True)
1760 run_cmd("stat %s" % test_tmpdir
, show
=True)
1761 run_cmd("stat %s" % testbase
, show
=True)
1762 if options
.skip_dependencies
:
1763 run_cmd("stat %s" % test_master
, dir=testbase
, output
=True)
1765 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
1771 if options
.rebase
is not None:
1772 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
1774 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1776 elapsed_time
= time
.time() - start_time
1777 email_failure(-1, 'rebase', 'rebase', 'rebase',
1778 'rebase on %s failed' % options
.branch
,
1779 elapsed_time
, log_base
=options
.log_base
)
1783 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1786 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1787 if status
!= 0 or errstr
!= "retry":
1789 cleanup(do_raise
=True)
1794 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1800 do_print("waiting for tail to flush")
1803 elapsed_time
= time
.time() - start_time
1805 if options
.passcmd
is not None:
1806 do_print("Running passcmd: %s" % options
.passcmd
)
1807 run_cmd(options
.passcmd
, dir=test_master
)
1808 if options
.pushto
is not None:
1809 push_to(options
.pushto
, push_branch
=options
.branch
)
1810 if options
.keeplogs
or options
.attach_logs
:
1811 blist
.tarlogs("logs.tar.gz")
1812 do_print("Logs in logs.tar.gz")
1813 if options
.always_email
:
1814 email_success(elapsed_time
, log_base
=options
.log_base
)
1820 # something failed, gather a tar of the logs
1821 blist
.tarlogs("logs.tar.gz")
1823 if options
.email
is not None:
1824 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1825 elapsed_time
, log_base
=options
.log_base
)
1827 elapsed_minutes
= elapsed_time
/ 60.0
1830 ####################################################################
1834 Your autobuild[%s] on %s failed after %.1f minutes
1835 when trying to test %s with the following error:
1839 the autobuild has been abandoned. Please fix the error and resubmit.
1841 ####################################################################
1843 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1847 do_print("Logs in logs.tar.gz")