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
,Popen
, PIPE
7 import os
, tarfile
, sys
, time
8 from optparse
import OptionParser
11 from email
.mime
.text
import MIMEText
12 from email
.mime
.base
import MIMEBase
13 from email
.mime
.application
import MIMEApplication
14 from email
.mime
.multipart
import MIMEMultipart
15 from distutils
.sysconfig
import get_python_lib
18 # This speeds up testing remarkably.
19 os
.environ
['TDB_NO_FSYNC'] = '1'
32 "talloc" : "lib/talloc",
33 "replace" : "lib/replace",
34 "tevent" : "lib/tevent",
41 defaulttasks
= [ "ctdb", "samba", "samba-xc", "samba-ctdb", "samba-libs", "samba-static", "ldb", "tdb", "talloc", "replace", "tevent", "pidl" ]
43 samba_configure_params
= " --picky-developer ${PREFIX} --with-profiling-data"
45 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH"
46 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
47 samba_libs_envvars
+= " ADDITIONAL_CFLAGS='-Wmissing-prototypes'"
48 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check --enable-debug --picky-developer -C ${PREFIX}"
49 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=NONE"
50 samba_libs_configure_samba
= samba_libs_configure_base
+ " --bundled-libraries=!talloc,!pytalloc-util,!tdb,!pytdb,!ldb,!pyldb,!pyldb-util,!tevent,!pytevent"
53 "ctdb" : [ ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
54 ("configure", "./configure ${PREFIX}", "text/plain"),
55 ("make", "make all", "text/plain"),
56 ("install", "make install", "text/plain"),
57 ("test", "make autotest", "text/plain"),
58 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
59 ("clean", "make clean", "text/plain") ],
61 # We have 'test' before 'install' because, 'test' should work without 'install'
62 "samba" : [ ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
63 ("make", "make -j", "text/plain"),
64 ("test", "make test FAIL_IMMEDIATELY=1", "text/plain"),
65 ("install", "make install", "text/plain"),
66 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
67 ("clean", "make clean", "text/plain") ],
69 # Test cross-compile infrastructure
70 "samba-xc" : [ ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
71 ("configure-cross-execute", "./configure.developer -b ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
72 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
, "text/plain"),
73 ("configure-cross-answers", "./configure.developer -b ./bin-xa --cross-compile" \
74 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
, "text/plain"),
75 ("compare-results", "script/compare_cc_results.py ./bin/c4che/default.cache.py ./bin-xe/c4che/default.cache.py ./bin-xa/c4che/default.cache.py", "text/plain")],
78 "samba-ctdb" : [ ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
80 # make sure we have tdb around:
81 ("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"),
82 ("tdb-make", "cd lib/tdb && make", "text/plain"),
83 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
86 # build samba with cluster support (also building ctdb):
87 ("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"),
88 ("samba-make", "make", "text/plain"),
89 ("samba-check", "./bin/smbd -b | grep CLUSTER_SUPPORT", "text/plain"),
90 ("samba-install", "make install", "text/plain"),
91 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd", "text/plain"),
94 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
95 ("clean", "make clean", "text/plain"),
96 ("ctdb-clean", "cd ./ctdb && make clean", "text/plain") ],
99 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
100 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
, "text/plain"),
101 ("talloc-make", "cd lib/talloc && make", "text/plain"),
102 ("talloc-install", "cd lib/talloc && make install", "text/plain"),
104 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
, "text/plain"),
105 ("tdb-make", "cd lib/tdb && make", "text/plain"),
106 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
108 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
, "text/plain"),
109 ("tevent-make", "cd lib/tevent && make", "text/plain"),
110 ("tevent-install", "cd lib/tevent && make install", "text/plain"),
112 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
, "text/plain"),
113 ("ldb-make", "cd lib/ldb && make", "text/plain"),
114 ("ldb-install", "cd lib/ldb && make install", "text/plain"),
116 ("nondevel-configure", "./configure ${PREFIX}", "text/plain"),
117 ("nondevel-make", "make -j", "text/plain"),
118 ("nondevel-check", "./bin/smbd -b | grep WITH_NTVFS_FILESERVER && exit 1; exit 0", "text/plain"),
119 ("nondevel-install", "make install", "text/plain"),
120 ("nondevel-dist", "make dist", "text/plain"),
122 # retry with all modules shared
123 ("allshared-distclean", "make distclean", "text/plain"),
124 ("allshared-configure", samba_libs_configure_samba
+ " --with-shared-modules=ALL", "text/plain"),
125 ("allshared-make", "make -j", "text/plain")],
128 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
129 # build with all modules static
130 ("allstatic-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=ALL", "text/plain"),
131 ("allstatic-make", "make -j", "text/plain"),
133 # retry without any required modules
134 ("none-distclean", "make distclean", "text/plain"),
135 ("none-configure", "./configure.developer " + samba_configure_params
+ " --with-static-modules=!FORCED,!DEFAULT --with-shared-modules=!FORCED,!DEFAULT", "text/plain"),
136 ("none-make", "make -j", "text/plain"),
138 # retry with nonshared smbd and smbtorture
139 ("nonshared-distclean", "make distclean", "text/plain"),
140 ("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"),
141 ("nonshared-make", "make -j", "text/plain")],
144 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
145 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
146 ("make", "make", "text/plain"),
147 ("install", "make install", "text/plain"),
148 ("test", "make test", "text/plain"),
149 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
150 ("distcheck", "make distcheck", "text/plain"),
151 ("clean", "make clean", "text/plain") ],
154 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
155 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
156 ("make", "make", "text/plain"),
157 ("install", "make install", "text/plain"),
158 ("test", "make test", "text/plain"),
159 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
160 ("distcheck", "make distcheck", "text/plain"),
161 ("clean", "make clean", "text/plain") ],
164 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
165 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
166 ("make", "make", "text/plain"),
167 ("install", "make install", "text/plain"),
168 ("test", "make test", "text/plain"),
169 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
170 ("distcheck", "make distcheck", "text/plain"),
171 ("clean", "make clean", "text/plain") ],
174 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
175 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
176 ("make", "make", "text/plain"),
177 ("install", "make install", "text/plain"),
178 ("test", "make test", "text/plain"),
179 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
180 ("distcheck", "make distcheck", "text/plain"),
181 ("clean", "make clean", "text/plain") ],
184 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
185 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
186 ("make", "make", "text/plain"),
187 ("install", "make install", "text/plain"),
188 ("test", "make test", "text/plain"),
189 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
190 ("distcheck", "make distcheck", "text/plain"),
191 ("clean", "make clean", "text/plain") ],
194 ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
195 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}", "text/plain"),
196 ("touch", "touch *.yp", "text/plain"),
197 ("make", "make", "text/plain"),
198 ("test", "make test", "text/plain"),
199 ("install", "make install", "text/plain"),
200 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm", "text/plain"),
201 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
202 ("clean", "make clean", "text/plain") ],
204 # these are useful for debugging autobuild
205 'pass' : [ ("pass", 'echo passing && /bin/true', "text/plain") ],
206 'fail' : [ ("fail", 'echo failing && /bin/false', "text/plain") ]
209 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
211 show
= options
.verbose
213 print("Running: '%s' in '%s'" % (cmd
, dir))
215 return Popen([cmd
], shell
=True, stdout
=PIPE
, cwd
=dir).communicate()[0]
217 return check_call(cmd
, shell
=True, cwd
=dir)
219 return call(cmd
, shell
=True, cwd
=dir)
222 class builder(object):
223 '''handle build of one directory'''
225 def __init__(self
, name
, sequence
, cp
=True):
227 self
.dir = builddirs
[name
]
229 self
.tag
= self
.name
.replace('/', '_')
230 self
.sequence
= sequence
232 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
233 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
235 print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
236 print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
237 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
238 self
.stdout
= open(self
.stdout_path
, 'w')
239 self
.stderr
= open(self
.stderr_path
, 'w')
240 self
.stdin
= open("/dev/null", 'r')
241 self
.sdir
= "%s/%s" % (testbase
, self
.tag
)
242 self
.prefix
= "%s/prefix/%s" % (testbase
, self
.tag
)
243 run_cmd("rm -rf %s" % self
.sdir
)
244 cleanup_list
.append(self
.sdir
)
245 cleanup_list
.append(self
.prefix
)
246 os
.makedirs(self
.sdir
)
247 run_cmd("rm -rf %s" % self
.sdir
)
249 run_cmd("cp --recursive --link --archive %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
251 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
254 def start_next(self
):
255 if self
.next
== len(self
.sequence
):
256 print '%s: Completed OK' % self
.name
259 (self
.stage
, self
.cmd
, self
.output_mime_type
) = self
.sequence
[self
.next
]
260 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(standard_lib
=1, prefix
=self
.prefix
))
261 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
262 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
263 # if self.output_mime_type == "text/x-subunit":
264 # self.cmd += " | %s --immediate" % (os.path.join(os.path.dirname(__file__), "selftest/format-subunit"))
265 print '%s: [%s] Running %s' % (self
.name
, self
.stage
, self
.cmd
)
267 os
.chdir("%s/%s" % (self
.sdir
, self
.dir))
268 self
.proc
= Popen(self
.cmd
, shell
=True,
269 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
274 class buildlist(object):
275 '''handle build of multiple directories'''
277 def __init__(self
, tasklist
, tasknames
, rebase_url
, rebase_branch
="master"):
280 self
.tail_proc
= None
283 tasknames
= defaulttasks
285 # If we are only running one test,
286 # do not sleep randomly to wait for it to start
287 os
.environ
['AUTOBUILD_RANDOM_SLEEP_OVERRIDE'] = '1'
290 b
= builder(n
, tasks
[n
], cp
=n
is not "pidl")
293 rebase_remote
= "rebaseon"
294 retry_task
= [ ("retry",
296 git remote add -t %s %s %s
300 git describe %s/%s > old_remote_branch.desc
302 git describe %s/%s > remote_branch.desc
303 diff old_remote_branch.desc remote_branch.desc
306 rebase_branch
, rebase_remote
, rebase_url
,
308 rebase_remote
, rebase_branch
,
310 rebase_remote
, rebase_branch
314 self
.retry
= builder('retry', retry_task
, cp
=False)
315 self
.need_retry
= False
318 if self
.tail_proc
is not None:
319 self
.tail_proc
.terminate()
320 self
.tail_proc
.wait()
321 self
.tail_proc
= None
322 if self
.retry
is not None:
323 self
.retry
.proc
.terminate()
324 self
.retry
.proc
.wait()
327 if b
.proc
is not None:
328 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.sdir
, checkfail
=False)
340 b
.status
= b
.proc
.poll()
346 ret
= self
.retry
.proc
.poll()
348 self
.need_retry
= True
358 if options
.retry
and self
.need_retry
:
360 print("retry needed")
361 return (0, None, None, None, "retry")
364 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
366 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
369 return (0, None, None, None, "All OK")
371 def write_system_info(self
):
372 filename
= 'system-info.txt'
373 f
= open(filename
, 'w')
374 for cmd
in ['uname -a', 'free', 'cat /proc/cpuinfo']:
375 print >>f
, '### %s' % cmd
376 print >>f
, run_cmd(cmd
, output
=True, checkfail
=False)
381 def tarlogs(self
, fname
):
382 tar
= tarfile
.open(fname
, "w:gz")
384 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
385 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
386 if os
.path
.exists("autobuild.log"):
387 tar
.add("autobuild.log")
388 sys_info
= self
.write_system_info()
392 def remove_logs(self
):
394 os
.unlink(b
.stdout_path
)
395 os
.unlink(b
.stderr_path
)
397 def start_tail(self
):
399 cmd
= "tail -f *.stdout *.stderr"
401 self
.tail_proc
= Popen(cmd
, shell
=True)
406 if options
.nocleanup
:
408 print("Cleaning up ....")
409 for d
in cleanup_list
:
410 run_cmd("rm -rf %s" % d
)
414 '''get to the top of the git repo'''
417 if os
.path
.isdir(os
.path
.join(p
, ".git")):
419 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
423 def daemonize(logfile
):
425 if pid
== 0: # Parent
428 if pid
!= 0: # Actual daemon
433 import resource
# Resource usage information.
434 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
435 if maxfd
== resource
.RLIM_INFINITY
:
436 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
437 for fd
in range(0, maxfd
):
442 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
446 def write_pidfile(fname
):
447 '''write a pid file, cleanup on exit'''
448 f
= open(fname
, mode
='w')
449 f
.write("%u\n" % os
.getpid())
453 def rebase_tree(rebase_url
, rebase_branch
= "master"):
454 rebase_remote
= "rebaseon"
455 print("Rebasing on %s" % rebase_url
)
456 run_cmd("git describe HEAD", show
=True, dir=test_master
)
457 run_cmd("git remote add -t %s %s %s" %
458 (rebase_branch
, rebase_remote
, rebase_url
),
459 show
=True, dir=test_master
)
460 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
461 if options
.fix_whitespace
:
462 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
463 (rebase_remote
, rebase_branch
),
464 show
=True, dir=test_master
)
466 run_cmd("git rebase --force-rebase %s/%s" %
467 (rebase_remote
, rebase_branch
),
468 show
=True, dir=test_master
)
469 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
470 (rebase_remote
, rebase_branch
),
471 dir=test_master
, output
=True)
473 print("No differences between HEAD and %s/%s - exiting" %
474 (rebase_remote
, rebase_branch
))
476 run_cmd("git describe %s/%s" %
477 (rebase_remote
, rebase_branch
),
478 show
=True, dir=test_master
)
479 run_cmd("git describe HEAD", show
=True, dir=test_master
)
480 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
481 (rebase_remote
, rebase_branch
),
482 show
=True, dir=test_master
)
484 def push_to(push_url
, push_branch
= "master"):
485 push_remote
= "pushto"
486 print("Pushing to %s" % push_url
)
488 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
489 run_cmd("git commit --amend -c HEAD", dir=test_master
)
490 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
491 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
492 run_cmd("git remote add -t %s %s %s" %
493 (push_branch
, push_remote
, push_url
),
494 show
=True, dir=test_master
)
495 run_cmd("git push %s +HEAD:%s" %
496 (push_remote
, push_branch
),
497 show
=True, dir=test_master
)
499 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
501 gitroot
= find_git_root()
503 raise Exception("Failed to find git root")
505 parser
= OptionParser()
506 parser
.add_option("", "--tail", help="show output while running", default
=False, action
="store_true")
507 parser
.add_option("", "--keeplogs", help="keep logs", default
=False, action
="store_true")
508 parser
.add_option("", "--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
509 parser
.add_option("", "--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
510 default
=def_testbase
)
511 parser
.add_option("", "--passcmd", help="command to run on success", default
=None)
512 parser
.add_option("", "--verbose", help="show all commands as they are run",
513 default
=False, action
="store_true")
514 parser
.add_option("", "--rebase", help="rebase on the given tree before testing",
515 default
=None, type='str')
516 parser
.add_option("", "--pushto", help="push to a git url on success",
517 default
=None, type='str')
518 parser
.add_option("", "--mark", help="add a Tested-By signoff before pushing",
519 default
=False, action
="store_true")
520 parser
.add_option("", "--fix-whitespace", help="fix whitespace on rebase",
521 default
=False, action
="store_true")
522 parser
.add_option("", "--retry", help="automatically retry if master changes",
523 default
=False, action
="store_true")
524 parser
.add_option("", "--email", help="send email to the given address on failure",
525 type='str', default
=None)
526 parser
.add_option("", "--email-from", help="send email from the given address",
527 type='str', default
="autobuild@samba.org")
528 parser
.add_option("", "--email-server", help="send email via the given server",
529 type='str', default
='localhost')
530 parser
.add_option("", "--always-email", help="always send email, even on success",
532 parser
.add_option("", "--daemon", help="daemonize after initial setup",
534 parser
.add_option("", "--branch", help="the branch to work on (default=master)",
535 default
="master", type='str')
536 parser
.add_option("", "--log-base", help="location where the logs can be found (default=cwd)",
537 default
=gitroot
, type='str')
538 parser
.add_option("", "--attach-logs", help="Attach logs to mails sent on success/failure?",
539 default
=False, action
="store_true")
541 def send_email(subject
, text
, log_tar
):
542 outer
= MIMEMultipart()
543 outer
['Subject'] = subject
544 outer
['To'] = options
.email
545 outer
['From'] = options
.email_from
546 outer
['Date'] = email
.utils
.formatdate(localtime
= True)
547 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
548 outer
.attach(MIMEText(text
, 'plain'))
549 if options
.attach_logs
:
550 fp
= open(log_tar
, 'rb')
551 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
553 # Set the filename parameter
554 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
556 content
= outer
.as_string()
557 s
= smtplib
.SMTP(options
.email_server
)
558 s
.sendmail(options
.email_from
, [options
.email
], content
)
562 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
563 elapsed_time
, log_base
=None, add_log_tail
=True):
564 '''send an email to options.email about the failure'''
565 elapsed_minutes
= elapsed_time
/ 60.0
566 user
= os
.getenv("USER")
572 Your autobuild on %s failed after %.1f minutes
573 when trying to test %s with the following error:
577 the autobuild has been abandoned. Please fix the error and resubmit.
579 A summary of the autobuild process is here:
582 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
584 if failed_task
!= 'rebase':
586 You can see logs of the failed task here:
591 or you can get full logs of all tasks in this job here:
595 The top commit for the tree that was built was:
599 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
602 f
= open("%s/%s.stdout" % (gitroot
, failed_tag
), 'r')
603 lines
= f
.readlines()
604 log_tail
= "".join(lines
[-50:])
605 num_lines
= len(lines
)
607 # Also include stderr (compile failures) if < 50 lines of stdout
608 f
= open("%s/%s.stderr" % (gitroot
, failed_tag
), 'r')
609 log_tail
+= "".join(f
.readlines()[-(50-num_lines
):])
612 The last 50 lines of log messages:
618 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
619 send_email('autobuild[%s] failure on %s for task %s during %s'
620 % (options
.branch
, platform
.node(), failed_task
, failed_stage
),
623 def email_success(elapsed_time
, log_base
=None):
624 '''send an email to options.email about a successful build'''
625 user
= os
.getenv("USER")
631 Your autobuild on %s has succeeded after %.1f minutes.
633 ''' % (platform
.node(), elapsed_time
/ 60.)
638 you can get full logs of all tasks in this job here:
645 The top commit for the tree that was built was:
650 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
651 send_email('autobuild[%s] success on %s' % (options
.branch
, platform
.node()),
655 (options
, args
) = parser
.parse_args()
658 if options
.rebase
is None:
659 raise Exception('You can only use --retry if you also rebase')
661 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
662 test_master
= "%s/master" % testbase
664 # get the top commit message, for emails
665 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
668 os
.makedirs(testbase
)
669 except Exception, reason
:
670 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
671 cleanup_list
.append(testbase
)
674 logfile
= os
.path
.join(testbase
, "log")
675 print "Forking into the background, writing progress to %s" % logfile
678 write_pidfile(gitroot
+ "/autobuild.pid")
680 start_time
= time
.time()
684 run_cmd("rm -rf %s" % test_master
)
685 cleanup_list
.append(test_master
)
686 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
693 if options
.rebase
is not None:
694 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
696 cleanup_list
.append(gitroot
+ "/autobuild.pid")
698 elapsed_time
= time
.time() - start_time
699 email_failure(-1, 'rebase', 'rebase', 'rebase',
700 'rebase on %s failed' % options
.branch
,
701 elapsed_time
, log_base
=options
.log_base
)
703 blist
= buildlist(tasks
, args
, options
.rebase
, rebase_branch
=options
.branch
)
706 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
707 if status
!= 0 or errstr
!= "retry":
714 cleanup_list
.append(gitroot
+ "/autobuild.pid")
718 print("waiting for tail to flush")
721 elapsed_time
= time
.time() - start_time
724 if options
.passcmd
is not None:
725 print("Running passcmd: %s" % options
.passcmd
)
726 run_cmd(options
.passcmd
, dir=test_master
)
727 if options
.pushto
is not None:
728 push_to(options
.pushto
, push_branch
=options
.branch
)
729 if options
.keeplogs
or options
.attach_logs
:
730 blist
.tarlogs("logs.tar.gz")
731 print("Logs in logs.tar.gz")
732 if options
.always_email
:
733 email_success(elapsed_time
, log_base
=options
.log_base
)
739 # something failed, gather a tar of the logs
740 blist
.tarlogs("logs.tar.gz")
742 if options
.email
is not None:
743 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
744 elapsed_time
, log_base
=options
.log_base
)
746 elapsed_minutes
= elapsed_time
/ 60.0
749 ####################################################################
753 Your autobuild[%s] on %s failed after %.1f minutes
754 when trying to test %s with the following error:
758 the autobuild has been abandoned. Please fix the error and resubmit.
760 ####################################################################
762 ''' % (options
.branch
, platform
.node(), elapsed_minutes
, failed_task
, errstr
)
766 print("Logs in logs.tar.gz")