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 __future__
import print_function
7 from subprocess
import call
, check_call
, Popen
, PIPE
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'
42 "samba-fileserver": ".",
47 "samba-libs-py3": ".",
49 "samba-none-env": ".",
51 "samba-ad-dc-py3": ".",
53 "samba-ad-dc-2-py3": ".",
54 "samba-systemkrb5": ".",
55 "samba-nopython": ".",
56 "samba-buildpy3-only": ".",
57 "samba-purepy3-none-env": ".",
58 "samba-purepy3-ad-dc-2": ".",
61 "talloc": "lib/talloc",
62 "replace": "lib/replace",
63 "tevent": "lib/tevent",
67 defaulttasks
= builddirs
.keys()
69 if os
.environ
.get("AUTOBUILD_SKIP_SAMBA_O3", "0") == "1":
70 defaulttasks
.remove("samba-o3")
72 ctdb_configure_params
= " --enable-developer --picky-developer ${PREFIX}"
73 samba_configure_params
= " --picky-developer ${PREFIX} ${EXTRA_PYTHON} --with-profiling-data"
75 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH"
76 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
77 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
78 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check --enable-debug --picky-developer -C ${PREFIX}"
79 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=cmocka,popt,NONE ${EXTRA_PYTHON}"
80 samba_libs_configure_bundled_libs
= " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent,!popt"
81 samba_libs_configure_samba
= samba_libs_configure_base
+ samba_libs_configure_bundled_libs
+ " ${EXTRA_PYTHON}"
83 if os
.environ
.get("AUTOBUILD_NO_EXTRA_PYTHON", "0") == "1":
86 extra_python
= "--extra-python=/usr/bin/python3"
89 "ctdb": [("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
90 ("configure", "./configure " + ctdb_configure_params
, "text/plain"),
91 ("make", "make all", "text/plain"),
92 ("install", "make install", "text/plain"),
93 ("test", "make autotest", "text/plain"),
94 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
95 ("clean", "make clean", "text/plain")],
97 # We have 'test' before 'install' because, 'test' should work without 'install (runs ad_dc_ntvfs and all the other envs)'
98 "samba": [("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
99 ("make", "make -j", "text/plain"),
100 ("test", "make test FAIL_IMMEDIATELY=1 "
102 "--exclude-env=none "
103 "--exclude-env=nt4_dc "
104 "--exclude-env=nt4_member "
105 "--exclude-env=ad_dc "
106 "--exclude-env=ad_dc_no_nss "
107 "--exclude-env=fl2003dc "
108 "--exclude-env=fl2008r2dc "
109 "--exclude-env=ad_member "
110 "--exclude-env=ad_member_idmap_rid "
111 "--exclude-env=ad_member_idmap_ad "
112 "--exclude-env=chgdcpass "
113 "--exclude-env=vampire_2000_dc "
114 "--exclude-env=fl2000dc "
115 "--exclude-env=fileserver "
116 "--exclude-env=backupfromdc "
117 "--exclude-env=restoredc "
118 "--exclude-env=renamedc "
119 "--exclude-env=offlinebackupdc "
120 "--exclude-env=labdc "
123 ("install", "make install", "text/plain"),
124 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
125 ("clean", "make clean", "text/plain")],
127 # We split out this so the isolated nt4_dc tests do not wait for ad_dc or ad_dc_ntvfs tests (which are long)
128 "samba-nt4": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
129 ("configure", "./configure.developer --without-ads --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
130 ("make", "make -j", "text/plain"),
131 ("test", "make test FAIL_IMMEDIATELY=1 "
133 "--include-env=nt4_dc --include-env=nt4_member'", "text/plain"),
134 ("install", "make install", "text/plain"),
135 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
136 ("clean", "make clean", "text/plain")],
138 # We split out this so the isolated ad_dc tests do not wait for ad_dc_ntvfs tests (which are long)
139 "samba-fileserver": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
140 ("configure", "./configure.developer --without-ad-dc --without-ldap --without-ads --without-json --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
141 ("make", "make -j", "text/plain"),
142 ("test", "make test FAIL_IMMEDIATELY=1 "
144 "--include-env=fileserver'", "text/plain"),
145 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain")],
147 # We split out this so the isolated ad_dc tests do not wait for ad_dc_ntvfs tests (which are long)
148 "samba-ad-dc": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
149 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
150 ("make", "make -j", "text/plain"),
151 ("test", "make test FAIL_IMMEDIATELY=1 "
153 "--include-env=ad_dc "
154 "--include-env=fl2003dc "
155 "--include-env=fl2008r2dc "
156 "--include-env=ad_member "
157 "--include-env=ad_member_idmap_rid "
158 "--include-env=ad_member_idmap_ad'", "text/plain"),
159 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain")],
161 # We split out this so the isolated ad_dc tests do not wait for ad_dc_ntvfs tests (which are long)
162 "samba-ad-dc-2": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
163 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
164 ("make", "make -j", "text/plain"),
165 ("test", "make test FAIL_IMMEDIATELY=1 "
167 "--include-env=chgdcpass "
168 "--include-env=vampire_2000_dc "
169 "--include-env=fl2000dc "
170 "--include-env=ad_dc_no_nss "
171 "--include-env=backupfromdc "
172 "--include-env=restoredc "
173 "--include-env=renamedc "
174 "--include-env=offlinebackupdc "
175 "--include-env=labdc "
178 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain")],
180 "samba-test-only": [("configure", "./configure.developer --with-selftest-prefix=./bin/ab --abi-check-disable" + samba_configure_params
, "text/plain"),
181 ("make", "make -j", "text/plain"),
182 ("test", 'make test FAIL_IMMEDIATELY=1 TESTS="${TESTS}"', "text/plain")],
184 # Test cross-compile infrastructure
185 "samba-xc": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
186 ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
187 ("configure-cross-execute", "./configure.developer --out ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
188 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
, "text/plain"),
189 ("configure-cross-answers", "./configure.developer --out ./bin-xa --cross-compile" \
190 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
, "text/plain"),
191 ("compare-results", "script/compare_cc_results.py "
192 "./bin/c4che/default{} "
193 "./bin-xe/c4che/default{} "
194 "./bin-xa/c4che/default{}".format(*([CACHE_SUFFIX
]*3)), "text/plain")],
196 # test build with -O3 -- catches extra warnings and bugs, tests the ad_dc environments
197 "samba-o3": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
198 ("configure", "ADDITIONAL_CFLAGS='-O3' ./configure.developer --with-selftest-prefix=./bin/ab --abi-check-disable" + samba_configure_params
, "text/plain"),
199 ("make", "make -j", "text/plain"),
200 ("test", "make quicktest FAIL_IMMEDIATELY=1 "
202 "--include-env=ad_dc'", "text/plain"),
203 ("install", "make install", "text/plain"),
204 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
205 ("clean", "make clean", "text/plain")],
207 "samba-ctdb": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
209 # make sure we have tdb around:
210 ("tdb-configure", "cd lib/tdb && PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig ./configure --bundled-libraries=NONE --abi-check --enable-debug -C ${PREFIX}", "text/plain"),
211 ("tdb-make", "cd lib/tdb && make", "text/plain"),
212 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
215 # build samba with cluster support (also building ctdb):
216 ("samba-configure", "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH PKG_CONFIG_PATH=${PREFIX_DIR}/lib/pkgconfig:${PKG_CONFIG_PATH} ./configure.developer --picky-developer ${PREFIX} --with-selftest-prefix=./bin/ab --with-cluster-support --bundled-libraries=!tdb", "text/plain"),
217 ("samba-make", "make", "text/plain"),
218 ("samba-check", "./bin/smbd -b | grep CLUSTER_SUPPORT", "text/plain"),
219 ("samba-install", "make install", "text/plain"),
220 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd", "text/plain"),
223 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
224 ("clean", "make clean", "text/plain"),
225 ("ctdb-clean", "cd ./ctdb && make clean", "text/plain")],
228 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
229 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
, "text/plain"),
230 ("talloc-make", "cd lib/talloc && make", "text/plain"),
231 ("talloc-install", "cd lib/talloc && make install", "text/plain"),
233 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
, "text/plain"),
234 ("tdb-make", "cd lib/tdb && make", "text/plain"),
235 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
237 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
, "text/plain"),
238 ("tevent-make", "cd lib/tevent && make", "text/plain"),
239 ("tevent-install", "cd lib/tevent && make install", "text/plain"),
241 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
, "text/plain"),
242 ("ldb-make", "cd lib/ldb && make", "text/plain"),
243 ("ldb-install", "cd lib/ldb && make install", "text/plain"),
245 ("nondevel-configure", "./configure ${PREFIX}", "text/plain"),
246 ("nondevel-make", "make -j", "text/plain"),
247 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0", "text/plain"),
248 ("nondevel-install", "make install", "text/plain"),
249 ("nondevel-dist", "make dist", "text/plain"),
251 # retry with all modules shared
252 ("allshared-distclean", "make distclean", "text/plain"),
253 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL", "text/plain"),
254 ("allshared-make", "make -j", "text/plain")],
257 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
258 ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
259 ("make", "make -j", "text/plain"),
260 ("test", "make test "
261 "FAIL_IMMEDIATELY=1 "
263 "--include-env=none'",
267 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
268 # build with all modules static
269 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL", "text/plain"),
270 ("allstatic-make", "make -j", "text/plain"),
271 ("allstatic-test", "make test "
272 "FAIL_IMMEDIATELY=1 "
273 "TESTS='samba3.smb2.create.*nt4_dc'",
276 # retry without any required modules
277 ("none-distclean", "make distclean", "text/plain"),
278 ("none-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT", "text/plain"),
279 ("none-make", "make -j", "text/plain"),
281 # retry with nonshared smbd and smbtorture
282 ("nonshared-distclean", "make distclean", "text/plain"),
283 ("nonshared-configure", "./configure.developer " + samba_configure_params
+ " --bundled-libraries=talloc,tdb,pytdb,ldb,pyldb,tevent,pytevent --with-static-modules=ALL --nonshared-binary=smbtorture,smbd/smbd", "text/plain"),
284 ("nonshared-make", "make -j", "text/plain")],
286 "samba-systemkrb5": [
287 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
288 ("configure", "./configure.developer " + samba_configure_params
+ " --with-system-mitkrb5 --without-ad-dc", "text/plain"),
289 ("make", "make -j", "text/plain"),
290 # we currently cannot run a full make test, a limited list of tests could be run
291 # via "make test TESTS=sometests"
292 ("test", "make test FAIL_IMMEDIATELY=1 "
294 "--include-env=ktest'", "text/plain"),
295 ("install", "make install", "text/plain"),
296 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
297 ("clean", "make clean", "text/plain")
300 # Test Samba without python still builds. When this test fails
301 # due to more use of Python, the expectations is that the newly
302 # failing part of the code should be disabled when
303 # --disable-python is set (rather than major work being done to
304 # support this environment). The target here is for vendors
305 # shipping a minimal smbd.
307 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
308 ("configure", "./configure.developer --picky-developer ${PREFIX} --with-profiling-data --disable-python --without-ad-dc", "text/plain"),
309 ("make", "make -j", "text/plain"),
310 ("install", "make install", "text/plain"),
311 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
312 ("clean", "make clean", "text/plain"),
314 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python", "text/plain"),
315 ("talloc-make", "cd lib/talloc && make", "text/plain"),
316 ("talloc-install", "cd lib/talloc && make install", "text/plain"),
318 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python", "text/plain"),
319 ("tdb-make", "cd lib/tdb && make", "text/plain"),
320 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
322 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python", "text/plain"),
323 ("tevent-make", "cd lib/tevent && make", "text/plain"),
324 ("tevent-install", "cd lib/tevent && make install", "text/plain"),
326 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_base
+ " --bundled-libraries=cmocka,NONE --disable-python", "text/plain"),
327 ("ldb-make", "cd lib/ldb && make", "text/plain"),
328 ("ldb-install", "cd lib/ldb && make install", "text/plain"),
330 # retry against installed library packages
331 ("libs-configure", samba_libs_configure_base
+ samba_libs_configure_bundled_libs
+ " --disable-python --without-ad-dc", "text/plain"),
332 ("libs-make", "make -j", "text/plain"),
333 ("libs-install", "make install", "text/plain"),
334 ("libs-check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
335 ("libs-clean", "make clean", "text/plain")
341 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
342 ("configure", "./configure --enable-developer -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
343 ("make", "make", "text/plain"),
344 ("install", "make install", "text/plain"),
345 ("test", "make test", "text/plain"),
346 ("configure-no-lmdb", "./configure --enable-developer --without-ldb-lmdb -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
347 ("make-no-lmdb", "make", "text/plain"),
348 ("install-no-lmdb", "make install", "text/plain"),
349 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
350 ("distcheck", "make distcheck", "text/plain"),
351 ("clean", "make clean", "text/plain")],
354 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
355 ("configure", "./configure --enable-developer -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
356 ("make", "make", "text/plain"),
357 ("install", "make install", "text/plain"),
358 ("test", "make test", "text/plain"),
359 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
360 ("distcheck", "make distcheck", "text/plain"),
361 ("clean", "make clean", "text/plain")],
364 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
365 ("configure", "./configure --enable-developer -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
366 ("make", "make", "text/plain"),
367 ("install", "make install", "text/plain"),
368 ("test", "make test", "text/plain"),
369 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
370 ("distcheck", "make distcheck", "text/plain"),
371 ("clean", "make clean", "text/plain")],
374 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
375 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
376 ("make", "make", "text/plain"),
377 ("install", "make install", "text/plain"),
378 ("test", "make test", "text/plain"),
379 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
380 ("distcheck", "make distcheck", "text/plain"),
381 ("clean", "make clean", "text/plain")],
384 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
385 ("configure", "./configure --enable-developer -C ${PREFIX} ${EXTRA_PYTHON}", "text/plain"),
386 ("make", "make", "text/plain"),
387 ("install", "make install", "text/plain"),
388 ("test", "make test", "text/plain"),
389 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
390 ("distcheck", "make distcheck", "text/plain"),
391 ("clean", "make clean", "text/plain")],
394 ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
395 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}", "text/plain"),
396 ("touch", "touch *.yp", "text/plain"),
397 ("make", "make", "text/plain"),
398 ("test", "make test", "text/plain"),
399 ("install", "make install", "text/plain"),
400 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm", "text/plain"),
401 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
402 ("clean", "make clean", "text/plain")],
404 "samba-buildpy3-only": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
405 ("configure", "PYTHON='python3' ./configure.developer --with-selftest-prefix=./bin/ab " + samba_configure_params
, "text/plain"),
406 ("make", "PYTHON='python3' make -j", "text/plain"),
407 ("install", "PYTHON='python3' make install", "text/plain"),
408 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
409 ("clean", "PYTHON='python3' make clean", "text/plain")],
411 "samba-purepy3-none-env": [
412 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
413 ("configure", "PYTHON='python3' ./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
414 ("make", "PYTHON='python3' make -j", "text/plain"),
415 ("test", "PYTHON='python3' make test "
416 "FAIL_IMMEDIATELY=1 "
418 "--include-env=none'",
420 "samba-purepy3-ad-dc-2": [("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
421 ("configure", "PYTHON='python3' ./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
422 ("make", "PYTHON='python3' make -j", "text/plain"),
423 ("test", "PYTHON='python3' make test FAIL_IMMEDIATELY=1 "
425 "--include-env=chgdcpass "
426 "--include-env=vampire_2000_dc "
427 "--include-env=fl2000dc "
428 "--include-env=ad_dc_no_nss "
429 "--include-env=backupfromdc "
430 "--include-env=restoredc "
431 "--include-env=renamedc "
432 "--include-env=offlinebackupdc "
433 "--include-env=labdc "
436 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain")],
438 # these are useful for debugging autobuild
439 'pass': [("pass", 'echo passing && /bin/true', "text/plain")],
440 'fail': [("fail", 'echo failing && /bin/false', "text/plain")]
452 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
454 show
= options
.verbose
456 do_print("Running: '%s' in '%s'" % (cmd
, dir))
458 return Popen([cmd
], shell
=True, stdout
=PIPE
, cwd
=dir, close_fds
=True).communicate()[0]
460 return check_call(cmd
, shell
=True, cwd
=dir)
462 return call(cmd
, shell
=True, cwd
=dir)
465 class builder(object):
466 '''handle build of one directory'''
468 def __init__(self
, name
, sequence
, cp
=True, py3
=False):
471 if name
in builddirs
:
472 self
.dir = builddirs
[name
]
476 self
.tag
= self
.name
.replace('/', '_')
477 self
.sequence
= sequence
479 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
480 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
482 do_print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
483 do_print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
484 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
485 self
.stdout
= open(self
.stdout_path
, 'w')
486 self
.stderr
= open(self
.stderr_path
, 'w')
487 self
.stdin
= open("/dev/null", 'r')
488 self
.sdir
= "%s/%s" % (testbase
, self
.tag
)
489 self
.prefix
= "%s/%s" % (test_prefix
, self
.tag
)
490 run_cmd("rm -rf %s" % self
.sdir
)
491 run_cmd("rm -rf %s" % self
.prefix
)
493 run_cmd("cp --recursive --link --archive %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
495 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
498 def start_next(self
):
499 if self
.next
== len(self
.sequence
):
500 if not options
.nocleanup
:
501 run_cmd("rm -rf %s" % self
.sdir
)
502 run_cmd("rm -rf %s" % self
.prefix
)
503 do_print('%s: Completed OK' % self
.name
)
506 (self
.stage
, self
.cmd
, self
.output_mime_type
) = self
.sequence
[self
.next
]
507 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(standard_lib
=1, prefix
=self
.prefix
))
508 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
510 self
.cmd
= self
.cmd
.replace("${EXTRA_PYTHON}", "%s" % extra_python
)
511 # The trailing space is important
512 self
.cmd
= self
.cmd
.replace("${PY3_ONLY}", "python3 ")
514 self
.cmd
= self
.cmd
.replace("${EXTRA_PYTHON}", "")
515 self
.cmd
= self
.cmd
.replace("${PY3_ONLY}", "")
516 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
517 self
.cmd
= self
.cmd
.replace("${TESTS}", options
.restrict_tests
)
518 # if self.output_mime_type == "text/x-subunit":
519 # self.cmd += " | %s --immediate" % (os.path.join(os.path.dirname(__file__), "selftest/format-subunit"))
521 os
.chdir("%s/%s" % (self
.sdir
, self
.dir))
522 do_print('%s: [%s] Running %s in %r' % (self
.name
, self
.stage
, self
.cmd
, os
.getcwd()))
523 self
.proc
= Popen(self
.cmd
, shell
=True,
525 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
530 class buildlist(object):
531 '''handle build of multiple directories'''
533 def __init__(self
, tasknames
, rebase_url
, rebase_branch
="master"):
536 self
.tail_proc
= None
539 if options
.restrict_tests
:
540 tasknames
= ["samba-test-only"]
542 tasknames
= defaulttasks
544 # If we are only running one test,
545 # do not sleep randomly to wait for it to start
546 os
.environ
['AUTOBUILD_RANDOM_SLEEP_OVERRIDE'] = '1'
549 if n
not in tasks
and n
.endswith("-py3"):
555 b
= builder(n
, tasks
[n
], cp
=n
is not "pidl")
558 rebase_remote
= "rebaseon"
559 retry_task
= [("retry",
561 git remote add -t %s %s %s
565 git describe %s/%s > old_remote_branch.desc
567 git describe %s/%s > remote_branch.desc
568 diff old_remote_branch.desc remote_branch.desc
571 rebase_branch
, rebase_remote
, rebase_url
,
573 rebase_remote
, rebase_branch
,
575 rebase_remote
, rebase_branch
579 self
.retry
= builder('retry', retry_task
, cp
=False)
580 self
.need_retry
= False
583 if self
.tail_proc
is not None:
584 self
.tail_proc
.terminate()
585 self
.tail_proc
.wait()
586 self
.tail_proc
= None
587 if self
.retry
is not None:
588 self
.retry
.proc
.terminate()
589 self
.retry
.proc
.wait()
592 if b
.proc
is not None:
593 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.sdir
, checkfail
=False)
605 b
.status
= b
.proc
.poll()
611 ret
= self
.retry
.proc
.poll()
613 self
.need_retry
= True
623 if options
.retry
and self
.need_retry
:
625 do_print("retry needed")
626 return (0, None, None, None, "retry")
629 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
631 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
634 return (0, None, None, None, "All OK")
636 def write_system_info(self
):
637 filename
= 'system-info.txt'
638 f
= open(filename
, 'w')
639 for cmd
in ['uname -a', 'free', 'cat /proc/cpuinfo',
640 'cc --version', 'df -m .', 'df -m %s' % testbase
]:
641 print('### %s' % cmd
, file=f
)
642 print(run_cmd(cmd
, output
=True, checkfail
=False), file=f
)
647 def tarlogs(self
, fname
):
648 tar
= tarfile
.open(fname
, "w:gz")
650 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
651 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
652 if os
.path
.exists("autobuild.log"):
653 tar
.add("autobuild.log")
654 sys_info
= self
.write_system_info()
658 def remove_logs(self
):
660 os
.unlink(b
.stdout_path
)
661 os
.unlink(b
.stderr_path
)
663 def start_tail(self
):
666 cmd
.append(b
.stdout_path
)
667 cmd
.append(b
.stderr_path
)
668 self
.tail_proc
= Popen(cmd
, close_fds
=True)
672 if options
.nocleanup
:
674 run_cmd("stat %s || true" % test_tmpdir
, show
=True)
675 run_cmd("stat %s" % testbase
, show
=True)
676 do_print("Cleaning up %r" % cleanup_list
)
677 for d
in cleanup_list
:
678 run_cmd("rm -rf %s" % d
)
682 '''get to the top of the git repo'''
685 if os
.path
.isdir(os
.path
.join(p
, ".git")):
687 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
691 def daemonize(logfile
):
693 if pid
== 0: # Parent
696 if pid
!= 0: # Actual daemon
701 import resource
# Resource usage information.
702 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
703 if maxfd
== resource
.RLIM_INFINITY
:
704 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
705 for fd
in range(0, maxfd
):
710 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
715 def write_pidfile(fname
):
716 '''write a pid file, cleanup on exit'''
717 f
= open(fname
, mode
='w')
718 f
.write("%u\n" % os
.getpid())
722 def rebase_tree(rebase_url
, rebase_branch
="master"):
723 rebase_remote
= "rebaseon"
724 do_print("Rebasing on %s" % rebase_url
)
725 run_cmd("git describe HEAD", show
=True, dir=test_master
)
726 run_cmd("git remote add -t %s %s %s" %
727 (rebase_branch
, rebase_remote
, rebase_url
),
728 show
=True, dir=test_master
)
729 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
730 if options
.fix_whitespace
:
731 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
732 (rebase_remote
, rebase_branch
),
733 show
=True, dir=test_master
)
735 run_cmd("git rebase --force-rebase %s/%s" %
736 (rebase_remote
, rebase_branch
),
737 show
=True, dir=test_master
)
738 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
739 (rebase_remote
, rebase_branch
),
740 dir=test_master
, output
=True)
742 do_print("No differences between HEAD and %s/%s - exiting" %
743 (rebase_remote
, rebase_branch
))
745 run_cmd("git describe %s/%s" %
746 (rebase_remote
, rebase_branch
),
747 show
=True, dir=test_master
)
748 run_cmd("git describe HEAD", show
=True, dir=test_master
)
749 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
750 (rebase_remote
, rebase_branch
),
751 show
=True, dir=test_master
)
754 def push_to(push_url
, push_branch
="master"):
755 push_remote
= "pushto"
756 do_print("Pushing to %s" % push_url
)
758 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
759 run_cmd("git commit --amend -c HEAD", dir=test_master
)
760 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
761 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
762 run_cmd("git remote add -t %s %s %s" %
763 (push_branch
, push_remote
, push_url
),
764 show
=True, dir=test_master
)
765 run_cmd("git push %s +HEAD:%s" %
766 (push_remote
, push_branch
),
767 show
=True, dir=test_master
)
770 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
772 gitroot
= find_git_root()
774 raise Exception("Failed to find git root")
776 parser
= OptionParser()
777 parser
.add_option("", "--tail", help="show output while running", default
=False, action
="store_true")
778 parser
.add_option("", "--keeplogs", help="keep logs", default
=False, action
="store_true")
779 parser
.add_option("", "--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
780 parser
.add_option("", "--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
781 default
=def_testbase
)
782 parser
.add_option("", "--passcmd", help="command to run on success", default
=None)
783 parser
.add_option("", "--verbose", help="show all commands as they are run",
784 default
=False, action
="store_true")
785 parser
.add_option("", "--rebase", help="rebase on the given tree before testing",
786 default
=None, type='str')
787 parser
.add_option("", "--pushto", help="push to a git url on success",
788 default
=None, type='str')
789 parser
.add_option("", "--mark", help="add a Tested-By signoff before pushing",
790 default
=False, action
="store_true")
791 parser
.add_option("", "--fix-whitespace", help="fix whitespace on rebase",
792 default
=False, action
="store_true")
793 parser
.add_option("", "--retry", help="automatically retry if master changes",
794 default
=False, action
="store_true")
795 parser
.add_option("", "--email", help="send email to the given address on failure",
796 type='str', default
=None)
797 parser
.add_option("", "--email-from", help="send email from the given address",
798 type='str', default
="autobuild@samba.org")
799 parser
.add_option("", "--email-server", help="send email via the given server",
800 type='str', default
='localhost')
801 parser
.add_option("", "--always-email", help="always send email, even on success",
803 parser
.add_option("", "--daemon", help="daemonize after initial setup",
805 parser
.add_option("", "--branch", help="the branch to work on (default=master)",
806 default
="master", type='str')
807 parser
.add_option("", "--log-base", help="location where the logs can be found (default=cwd)",
808 default
=gitroot
, type='str')
809 parser
.add_option("", "--attach-logs", help="Attach logs to mails sent on success/failure?",
810 default
=False, action
="store_true")
811 parser
.add_option("", "--restrict-tests", help="run as make test with this TESTS= regex",
815 def send_email(subject
, text
, log_tar
):
816 if options
.email
is None:
817 do_print("not sending email because the recipient is not set")
818 do_print("the text content would have been:\n\nSubject: %s\n\n%s" %
821 outer
= MIMEMultipart()
822 outer
['Subject'] = subject
823 outer
['To'] = options
.email
824 outer
['From'] = options
.email_from
825 outer
['Date'] = email
.utils
.formatdate(localtime
=True)
826 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
827 outer
.attach(MIMEText(text
, 'plain'))
828 if options
.attach_logs
:
829 fp
= open(log_tar
, 'rb')
830 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
832 # Set the filename parameter
833 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
835 content
= outer
.as_string()
836 s
= smtplib
.SMTP(options
.email_server
)
837 s
.sendmail(options
.email_from
, [options
.email
], content
)
842 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
843 elapsed_time
, log_base
=None, add_log_tail
=True):
844 '''send an email to options.email about the failure'''
845 elapsed_minutes
= elapsed_time
/ 60.0
851 Your autobuild on %s failed after %.1f minutes
852 when trying to test %s with the following error:
856 the autobuild has been abandoned. Please fix the error and resubmit.
858 A summary of the autobuild process is here:
861 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
863 if options
.restrict_tests
:
865 The build was restricted to tests matching %s\n""" % options
.restrict_tests
867 if failed_task
!= 'rebase':
869 You can see logs of the failed task here:
874 or you can get full logs of all tasks in this job here:
878 The top commit for the tree that was built was:
882 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
885 f
= open("%s/%s.stdout" % (gitroot
, failed_tag
), 'r')
886 lines
= f
.readlines()
887 log_tail
= "".join(lines
[-50:])
888 num_lines
= len(lines
)
890 # Also include stderr (compile failures) if < 50 lines of stdout
891 f
= open("%s/%s.stderr" % (gitroot
, failed_tag
), 'r')
892 log_tail
+= "".join(f
.readlines()[-(50 - num_lines
):])
895 The last 50 lines of log messages:
901 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
902 send_email('autobuild[%s] failure on %s for task %s during %s'
903 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
907 def email_success(elapsed_time
, log_base
=None):
908 '''send an email to options.email about a successful build'''
914 Your autobuild on %s has succeeded after %.1f minutes.
916 ''' % (platform
.node(), elapsed_time
/ 60.)
918 if options
.restrict_tests
:
920 The build was restricted to tests matching %s\n""" % options
.restrict_tests
925 you can get full logs of all tasks in this job here:
932 The top commit for the tree that was built was:
937 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
938 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
942 (options
, args
) = parser
.parse_args()
945 if options
.rebase
is None:
946 raise Exception('You can only use --retry if you also rebase')
948 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
949 test_master
= "%s/master" % testbase
950 test_prefix
= "%s/prefix" % testbase
951 test_tmpdir
= "%s/tmp" % testbase
952 os
.environ
['TMPDIR'] = test_tmpdir
954 # get the top commit message, for emails
955 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
958 os
.makedirs(testbase
)
959 except Exception as reason
:
960 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
961 cleanup_list
.append(testbase
)
964 logfile
= os
.path
.join(testbase
, "log")
965 do_print("Forking into the background, writing progress to %s" % logfile
)
968 write_pidfile(gitroot
+ "/autobuild.pid")
970 start_time
= time
.time()
974 run_cmd("rm -rf %s" % test_tmpdir
, show
=True)
975 os
.makedirs(test_tmpdir
)
976 # The waf uninstall code removes empty directories all the way
977 # up the tree. Creating a file in test_tmpdir stops it from
979 run_cmd("touch %s" % os
.path
.join(test_tmpdir
,
980 ".directory-is-not-empty"), show
=True)
981 run_cmd("stat %s" % test_tmpdir
, show
=True)
982 run_cmd("stat %s" % testbase
, show
=True)
983 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
990 if options
.rebase
is not None:
991 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
993 cleanup_list
.append(gitroot
+ "/autobuild.pid")
995 elapsed_time
= time
.time() - start_time
996 email_failure(-1, 'rebase', 'rebase', 'rebase',
997 'rebase on %s failed' % options
.branch
,
998 elapsed_time
, log_base
=options
.log_base
)
1000 blist
= buildlist(args
, options
.rebase
, rebase_branch
=options
.branch
)
1003 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
1004 if status
!= 0 or errstr
!= "retry":
1011 cleanup_list
.append(gitroot
+ "/autobuild.pid")
1017 do_print("waiting for tail to flush")
1020 elapsed_time
= time
.time() - start_time
1022 if options
.passcmd
is not None:
1023 do_print("Running passcmd: %s" % options
.passcmd
)
1024 run_cmd(options
.passcmd
, dir=test_master
)
1025 if options
.pushto
is not None:
1026 push_to(options
.pushto
, push_branch
=options
.branch
)
1027 if options
.keeplogs
or options
.attach_logs
:
1028 blist
.tarlogs("logs.tar.gz")
1029 do_print("Logs in logs.tar.gz")
1030 if options
.always_email
:
1031 email_success(elapsed_time
, log_base
=options
.log_base
)
1037 # something failed, gather a tar of the logs
1038 blist
.tarlogs("logs.tar.gz")
1040 if options
.email
is not None:
1041 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
1042 elapsed_time
, log_base
=options
.log_base
)
1044 elapsed_minutes
= elapsed_time
/ 60.0
1047 ####################################################################
1051 Your autobuild[%s] on %s failed after %.1f minutes
1052 when trying to test %s with the following error:
1056 the autobuild has been abandoned. Please fix the error and resubmit.
1058 ####################################################################
1060 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
))
1064 do_print("Logs in logs.tar.gz")