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
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}",
1302 get_path(name
='platlib',
1303 scheme
="posix_prefix",
1304 vars={"base": self
.prefix
,
1305 "platbase": self
.prefix
}))
1306 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
1307 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
1308 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
1309 self
.cmd
= self
.cmd
.replace("${TEST_SOURCE_DIR}", self
.test_source_dir
)
1310 self
.cmd
= self
.cmd
.replace("${SELFTEST_PREFIX}", self
.selftest_prefix
)
1311 self
.cmd
= self
.cmd
.replace("${LOG_BASE}", options
.log_base
)
1312 self
.cmd
= self
.cmd
.replace("${NAME}", self
.name
)
1313 self
.cmd
= self
.cmd
.replace("${ENABLE_COVERAGE}", options
.enable_coverage
)
1314 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, self
.cwd
))
1315 self
.proc
= Popen(self
.cmd
, shell
=True,
1316 close_fds
=True, cwd
=self
.cwd
,
1317 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
1320 def expand_dependencies(n
):
1322 if "dependency" in tasks
[n
]:
1323 depname
= tasks
[n
]["dependency"]
1324 assert depname
in tasks
1325 sdeps
= expand_dependencies(depname
)
1326 assert n
not in sdeps
1329 deps
.append(depname
)
1333 class buildlist(object):
1334 '''handle build of multiple directories'''
1336 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
1337 self
.tail_proc
= None
1340 if options
.restrict_tests
:
1341 tasknames
= ["samba-test-only"]
1343 tasknames
= defaulttasks
1345 given_tasknames
= tasknames
.copy()
1346 implicit_tasknames
= []
1347 for n
in given_tasknames
:
1348 deps
= expand_dependencies(n
)
1350 if dep
in given_tasknames
:
1352 if dep
in implicit_tasknames
:
1354 implicit_tasknames
.append(dep
)
1356 tasknames
= implicit_tasknames
.copy()
1357 tasknames
.extend(given_tasknames
)
1358 do_print("given_tasknames: %s" % given_tasknames
)
1359 do_print("implicit_tasknames: %s" % implicit_tasknames
)
1360 do_print("tasknames: %s" % tasknames
)
1361 self
.tlist
= [builder(n
, tasks
[n
]) for n
in tasknames
]
1364 rebase_remote
= "rebaseon"
1366 "git-clone-required": True,
1370 git remote add -t %s %s %s
1374 git describe %s/%s > old_remote_branch.desc
1376 git describe %s/%s > remote_branch.desc
1377 diff old_remote_branch.desc remote_branch.desc
1380 rebase_branch
, rebase_remote
, rebase_url
,
1382 rebase_remote
, rebase_branch
,
1384 rebase_remote
, rebase_branch
1387 self
.retry
= builder('retry', retry_task
)
1388 self
.need_retry
= False
1390 if options
.skip_dependencies
:
1391 for b
in self
.tlist
:
1392 if b
.name
in implicit_tasknames
:
1395 for b
in self
.tlist
:
1396 do_print("b.name=%s" % b
.name
)
1397 if "dependency" not in b
.definition
:
1399 depname
= b
.definition
["dependency"]
1400 do_print("b.name=%s: dependency:%s" % (b
.name
, depname
))
1401 for p
in self
.tlist
:
1402 if p
.name
== depname
:
1405 def kill_kids(self
):
1406 if self
.tail_proc
is not None:
1407 self
.tail_proc
.terminate()
1408 self
.tail_proc
.wait()
1409 self
.tail_proc
= None
1410 if self
.retry
is not None:
1411 self
.retry
.proc
.terminate()
1412 self
.retry
.proc
.wait()
1414 for b
in self
.tlist
:
1415 if b
.proc
is not None:
1416 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.test_source_dir
, checkfail
=False)
1424 for b
in self
.tlist
:
1427 none_running
= False
1428 b
.status
= b
.proc
.poll()
1429 if b
.status
is None:
1434 ret
= self
.retry
.proc
.poll()
1436 self
.need_retry
= True
1444 for b
in self
.tlist
:
1447 self
.retry
.start_next()
1450 if options
.retry
and self
.need_retry
:
1452 do_print("retry needed")
1453 return (0, None, None, None, "retry")
1456 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
1458 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
1461 return (0, None, None, None, "All OK")
1463 def write_system_info(self
, filename
):
1464 with
open(filename
, 'w') as f
:
1465 for cmd
in ['uname -a',
1469 'cat /proc/cpuinfo',
1472 'df -m %s' % testbase
]:
1474 out
= run_cmd(cmd
, output
=True, checkfail
=False)
1475 except CalledProcessError
as e
:
1476 out
= "<failed: %s>" % str(e
)
1477 print('### %s' % cmd
, file=f
)
1481 def tarlogs(self
, fname
):
1482 with tarfile
.open(fname
, "w:gz") as tar
:
1483 for b
in self
.tlist
:
1484 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
1485 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
1486 if os
.path
.exists("autobuild.log"):
1487 tar
.add("autobuild.log")
1488 filename
= 'system-info.txt'
1489 self
.write_system_info(filename
)
1492 def remove_logs(self
):
1493 for b
in self
.tlist
:
1494 os
.unlink(b
.stdout_path
)
1495 os
.unlink(b
.stderr_path
)
1497 def start_tail(self
):
1498 cmd
= ["tail", "-f"]
1499 for b
in self
.tlist
:
1500 cmd
.append(b
.stdout_path
)
1501 cmd
.append(b
.stderr_path
)
1502 self
.tail_proc
= Popen(cmd
, close_fds
=True)
1505 def cleanup(do_raise
=False):
1506 if options
.nocleanup
:
1508 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
1509 run_cmd("stat %s" % testbase
, show
=True)
1510 do_print("Cleaning up %r" % cleanup_list
)
1511 for d
in cleanup_list
:
1512 ok
= rmdir_force(d
, re_raise
=False)
1515 if os
.path
.isdir(d
):
1516 do_print("Killing, waiting and retry")
1517 run_cmd("killbysubdir %s > /dev/null 2>&1" % d
, checkfail
=False)
1519 do_print("Waiting and retry")
1521 rmdir_force(d
, re_raise
=do_raise
)
1524 def daemonize(logfile
):
1526 if pid
== 0: # Parent
1529 if pid
!= 0: # Actual daemon
1534 import resource
# Resource usage information.
1535 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
1536 if maxfd
== resource
.RLIM_INFINITY
:
1537 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
1538 for fd
in range(0, maxfd
):
1543 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
1548 def write_pidfile(fname
):
1549 '''write a pid file, cleanup on exit'''
1550 with
open(fname
, mode
='w') as f
:
1551 f
.write("%u\n" % os
.getpid())
1554 def rebase_tree(rebase_url
, rebase_branch
="master"):
1555 rebase_remote
= "rebaseon"
1556 do_print("Rebasing on %s" % rebase_url
)
1557 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1558 run_cmd("git remote add -t %s %s %s" %
1559 (rebase_branch
, rebase_remote
, rebase_url
),
1560 show
=True, dir=test_master
)
1561 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
1562 if options
.fix_whitespace
:
1563 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
1564 (rebase_remote
, rebase_branch
),
1565 show
=True, dir=test_master
)
1567 run_cmd("git rebase --force-rebase %s/%s" %
1568 (rebase_remote
, rebase_branch
),
1569 show
=True, dir=test_master
)
1570 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
1571 (rebase_remote
, rebase_branch
),
1572 dir=test_master
, output
=True)
1574 do_print("No differences between HEAD and %s/%s - exiting" %
1575 (rebase_remote
, rebase_branch
))
1577 run_cmd("git describe %s/%s" %
1578 (rebase_remote
, rebase_branch
),
1579 show
=True, dir=test_master
)
1580 run_cmd("git describe HEAD", show
=True, dir=test_master
)
1581 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
1582 (rebase_remote
, rebase_branch
),
1583 show
=True, dir=test_master
)
1586 def push_to(push_url
, push_branch
="master"):
1587 push_remote
= "pushto"
1588 do_print("Pushing to %s" % push_url
)
1590 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
1591 run_cmd("git commit --amend -c HEAD", dir=test_master
)
1592 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
1593 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
1594 run_cmd("git remote add -t %s %s %s" %
1595 (push_branch
, push_remote
, push_url
),
1596 show
=True, dir=test_master
)
1597 run_cmd("git push %s +HEAD:%s" %
1598 (push_remote
, push_branch
),
1599 show
=True, dir=test_master
)
1602 def send_email(subject
, text
, log_tar
):
1603 if options
.email
is None:
1604 do_print("not sending email because the recipient is not set")
1605 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
1608 outer
= MIMEMultipart()
1609 outer
['Subject'] = subject
1610 outer
['To'] = options
.email
1611 outer
['From'] = options
.email_from
1612 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
1613 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
1614 outer
.attach(MIMEText(text
, 'plain', 'utf-8'))
1615 if options
.attach_logs
:
1616 with
open(log_tar
, 'rb') as fp
:
1617 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
1618 # Set the filename parameter
1619 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
1621 content
= outer
.as_string()
1622 s
= smtplib
.SMTP(options
.email_server
)
1623 email_user
= os
.getenv('SMTP_USERNAME')
1624 email_password
= os
.getenv('SMTP_PASSWORD')
1625 if email_user
is not None:
1627 s
.login(email_user
, email_password
)
1629 s
.sendmail(options
.email_from
, [options
.email
], content
)
1634 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1635 elapsed_time
, log_base
=None, add_log_tail
=True):
1636 '''send an email to options.email about the failure'''
1637 elapsed_minutes
= elapsed_time
/ 60.0
1638 if log_base
is None:
1643 Your autobuild on %s failed after %.1f minutes
1644 when trying to test %s with the following error:
1648 the autobuild has been abandoned. Please fix the error and resubmit.
1650 A summary of the autobuild process is here:
1653 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
1655 if options
.restrict_tests
:
1657 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1659 if failed_task
!= 'rebase':
1661 You can see logs of the failed task here:
1666 or you can get full logs of all tasks in this job here:
1670 The top commit for the tree that was built was:
1674 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
1677 f
= open("%s/%s.stdout" % (gitroot
, failed_tag
), 'r')
1678 lines
= f
.readlines()
1679 log_tail
= "".join(lines
[-50:])
1680 num_lines
= len(lines
)
1682 # Also include stderr (compile failures) if < 50 lines of stdout
1683 f
= open("%s/%s.stderr" % (gitroot
, failed_tag
), 'r')
1684 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
1687 The last 50 lines of log messages:
1693 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1694 send_email('autobuild[%s] failure on %s for task %s during %s'
1695 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
1699 def email_success(elapsed_time
, log_base
=None):
1700 '''send an email to options.email about a successful build'''
1701 if log_base
is None:
1706 Your autobuild on %s has succeeded after %.1f minutes.
1708 ''' % (platform
.node(), elapsed_time
/ 60.)
1710 if options
.restrict_tests
:
1712 The build was restricted to tests matching %s\n""" % options
.restrict_tests
1714 if options
.keeplogs
:
1717 you can get full logs of all tasks in this job here:
1724 The top commit for the tree that was built was:
1727 ''' % top_commit_msg
1729 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
1730 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
1734 # get the top commit message, for emails
1735 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
1738 if options
.skip_dependencies
:
1739 run_cmd("stat %s" % testbase
, dir=testbase
, output
=True)
1741 os
.makedirs(testbase
)
1742 except Exception as reason
:
1743 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
1744 cleanup_list
.append(testbase
)
1747 logfile
= os
.path
.join(testbase
, "log")
1748 do_print("Forking into the background, writing progress to %s" % logfile
)
1751 write_pidfile(gitroot
+ "/autobuild.pid")
1753 start_time
= time
.time()
1757 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
1758 os
.makedirs(test_tmpdir
)
1759 # The waf uninstall code removes empty directories all the way
1760 # up the tree. Creating a file in test_tmpdir stops it from
1762 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
1763 ".directory-is-not-empty"), show
=True)
1764 run_cmd("stat %s" % test_tmpdir
, show
=True)
1765 run_cmd("stat %s" % testbase
, show
=True)
1766 if options
.skip_dependencies
:
1767 run_cmd("stat %s" % test_master
, dir=testbase
, output
=True)
1769 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
1775 if options
.rebase
is not None:
1776 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
1778 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1780 elapsed_time
= time
.time() - start_time
1781 email_failure(-1, 'rebase', 'rebase', 'rebase',
1782 'rebase on %s failed' % options
.branch
,
1783 elapsed_time
, log_base
=options
.log_base
)
1787 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1790 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1791 if status
!= 0 or errstr
!= "retry":
1793 cleanup(do_raise
=True)
1798 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1804 do_print("waiting for tail to flush")
1807 elapsed_time
= time
.time() - start_time
1809 if options
.passcmd
is not None:
1810 do_print("Running passcmd: %s" % options
.passcmd
)
1811 run_cmd(options
.passcmd
, dir=test_master
)
1812 if options
.pushto
is not None:
1813 push_to(options
.pushto
, push_branch
=options
.branch
)
1814 if options
.keeplogs
or options
.attach_logs
:
1815 blist
.tarlogs("logs.tar.gz")
1816 do_print("Logs in logs.tar.gz")
1817 if options
.always_email
:
1818 email_success(elapsed_time
, log_base
=options
.log_base
)
1824 # something failed, gather a tar of the logs
1825 blist
.tarlogs("logs.tar.gz")
1827 if options
.email
is not None:
1828 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1829 elapsed_time
, log_base
=options
.log_base
)
1831 elapsed_minutes
= elapsed_time
/ 60.0
1834 ####################################################################
1838 Your autobuild[%s] on %s failed after %.1f minutes
1839 when trying to test %s with the following error:
1843 the autobuild has been abandoned. Please fix the error and resubmit.
1845 ####################################################################
1847 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1851 do_print("Logs in logs.tar.gz")