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'
31 "talloc" : "lib/talloc",
32 "replace" : "lib/replace",
33 "tevent" : "lib/tevent",
40 defaulttasks
= [ "ctdb", "samba", "samba-xc", "samba-ctdb", "samba-libs", "ldb", "tdb", "talloc", "replace", "tevent", "pidl" ]
42 samba_configure_params
= " --picky-developer ${PREFIX} --with-profiling-data"
44 samba_libs_envvars
= "PYTHONPATH=${PYTHON_PREFIX}/site-packages:$PYTHONPATH"
45 samba_libs_envvars
+= " PKG_CONFIG_PATH=$PKG_CONFIG_PATH:${PREFIX_DIR}/lib/pkgconfig"
46 samba_libs_configure_base
= samba_libs_envvars
+ " ./configure --abi-check --enable-debug -C ${PREFIX}"
47 samba_libs_configure_libs
= samba_libs_configure_base
+ " --bundled-libraries=NONE"
48 samba_libs_configure_samba
= samba_libs_configure_base
+ " --bundled-libraries=!talloc,!tdb,!pytdb,!ldb,!pyldb,!tevent,!pytevent"
51 "ctdb" : [ ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
52 ("configure", "./configure ${PREFIX}", "text/plain"),
53 ("make", "make all", "text/plain"),
54 ("install", "make install", "text/plain"),
55 ("test", "make autotest", "text/plain"),
56 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
57 ("clean", "make clean", "text/plain") ],
59 # We have 'test' before 'install' because, 'test' should work without 'install'
60 "samba" : [ ("configure", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
61 ("make", "make -j", "text/plain"),
62 ("test", "make test FAIL_IMMEDIATELY=1", "text/plain"),
63 ("install", "make install", "text/plain"),
64 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
65 ("clean", "make clean", "text/plain") ],
67 # Test cross-compile infrastructure
68 "samba-xc" : [ ("configure-native", "./configure.developer --with-selftest-prefix=./bin/ab" + samba_configure_params
, "text/plain"),
69 ("configure-cross-execute", "./configure.developer -b ./bin-xe --cross-compile --cross-execute=script/identity_cc.sh" \
70 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xe/ab" + samba_configure_params
, "text/plain"),
71 ("configure-cross-answers", "./configure.developer -b ./bin-xa --cross-compile" \
72 " --cross-answers=./bin-xe/cross-answers.txt --with-selftest-prefix=./bin-xa/ab" + samba_configure_params
, "text/plain"),
73 ("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")],
76 "samba-ctdb" : [ ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
78 # make sure we have tdb around:
79 ("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"),
80 ("tdb-make", "cd lib/tdb && make", "text/plain"),
81 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
84 # build samba with cluster support (also building ctdb):
85 ("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"),
86 ("samba-make", "make", "text/plain"),
87 ("samba-check", "./bin/smbd -b | grep CLUSTER_SUPPORT", "text/plain"),
88 ("samba-install", "make install", "text/plain"),
89 ("ctdb-check", "test -e ${PREFIX_DIR}/sbin/ctdbd", "text/plain"),
92 ("check-clean-tree", "script/clean-source-tree.sh", "text/plain"),
93 ("clean", "make clean", "text/plain"),
94 ("ctdb-clean", "cd ./ctdb && make clean", "text/plain") ],
97 ("random-sleep", "script/random-sleep.sh 60 600", "text/plain"),
98 ("talloc-configure", "cd lib/talloc && " + samba_libs_configure_libs
, "text/plain"),
99 ("talloc-make", "cd lib/talloc && make", "text/plain"),
100 ("talloc-install", "cd lib/talloc && make install", "text/plain"),
102 ("tdb-configure", "cd lib/tdb && " + samba_libs_configure_libs
, "text/plain"),
103 ("tdb-make", "cd lib/tdb && make", "text/plain"),
104 ("tdb-install", "cd lib/tdb && make install", "text/plain"),
106 ("tevent-configure", "cd lib/tevent && " + samba_libs_configure_libs
, "text/plain"),
107 ("tevent-make", "cd lib/tevent && make", "text/plain"),
108 ("tevent-install", "cd lib/tevent && make install", "text/plain"),
110 ("ldb-configure", "cd lib/ldb && " + samba_libs_configure_libs
, "text/plain"),
111 ("ldb-make", "cd lib/ldb && make", "text/plain"),
112 ("ldb-install", "cd lib/ldb && make install", "text/plain"),
114 ("configure", samba_libs_configure_samba
, "text/plain"),
115 ("make", "make", "text/plain"),
116 ("install", "make install", "text/plain"),
117 ("dist", "make dist", "text/plain")],
120 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
121 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
122 ("make", "make", "text/plain"),
123 ("install", "make install", "text/plain"),
124 ("test", "make test", "text/plain"),
125 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
126 ("distcheck", "make distcheck", "text/plain"),
127 ("clean", "make clean", "text/plain") ],
130 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
131 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
132 ("make", "make", "text/plain"),
133 ("install", "make install", "text/plain"),
134 ("test", "make test", "text/plain"),
135 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
136 ("distcheck", "make distcheck", "text/plain"),
137 ("clean", "make clean", "text/plain") ],
140 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
141 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
142 ("make", "make", "text/plain"),
143 ("install", "make install", "text/plain"),
144 ("test", "make test", "text/plain"),
145 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
146 ("distcheck", "make distcheck", "text/plain"),
147 ("clean", "make clean", "text/plain") ],
150 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
151 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
152 ("make", "make", "text/plain"),
153 ("install", "make install", "text/plain"),
154 ("test", "make test", "text/plain"),
155 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
156 ("distcheck", "make distcheck", "text/plain"),
157 ("clean", "make clean", "text/plain") ],
160 ("random-sleep", "../../script/random-sleep.sh 60 600", "text/plain"),
161 ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
162 ("make", "make", "text/plain"),
163 ("install", "make install", "text/plain"),
164 ("test", "make test", "text/plain"),
165 ("check-clean-tree", "../../script/clean-source-tree.sh", "text/plain"),
166 ("distcheck", "make distcheck", "text/plain"),
167 ("clean", "make clean", "text/plain") ],
170 ("random-sleep", "../script/random-sleep.sh 60 600", "text/plain"),
171 ("configure", "perl Makefile.PL PREFIX=${PREFIX_DIR}", "text/plain"),
172 ("touch", "touch *.yp", "text/plain"),
173 ("make", "make", "text/plain"),
174 ("test", "make test", "text/plain"),
175 ("install", "make install", "text/plain"),
176 ("checkout-yapp-generated", "git checkout lib/Parse/Pidl/IDL.pm lib/Parse/Pidl/Expr.pm", "text/plain"),
177 ("check-clean-tree", "../script/clean-source-tree.sh", "text/plain"),
178 ("clean", "make clean", "text/plain") ],
180 # these are useful for debugging autobuild
181 'pass' : [ ("pass", 'echo passing && /bin/true', "text/plain") ],
182 'fail' : [ ("fail", 'echo failing && /bin/false', "text/plain") ]
185 def run_cmd(cmd
, dir=".", show
=None, output
=False, checkfail
=True):
187 show
= options
.verbose
189 print("Running: '%s' in '%s'" % (cmd
, dir))
191 return Popen([cmd
], shell
=True, stdout
=PIPE
, cwd
=dir).communicate()[0]
193 return check_call(cmd
, shell
=True, cwd
=dir)
195 return call(cmd
, shell
=True, cwd
=dir)
198 class builder(object):
199 '''handle build of one directory'''
201 def __init__(self
, name
, sequence
):
203 self
.dir = builddirs
[name
]
205 self
.tag
= self
.name
.replace('/', '_')
206 self
.sequence
= sequence
208 self
.stdout_path
= "%s/%s.stdout" % (gitroot
, self
.tag
)
209 self
.stderr_path
= "%s/%s.stderr" % (gitroot
, self
.tag
)
211 print("stdout for %s in %s" % (self
.name
, self
.stdout_path
))
212 print("stderr for %s in %s" % (self
.name
, self
.stderr_path
))
213 run_cmd("rm -f %s %s" % (self
.stdout_path
, self
.stderr_path
))
214 self
.stdout
= open(self
.stdout_path
, 'w')
215 self
.stderr
= open(self
.stderr_path
, 'w')
216 self
.stdin
= open("/dev/null", 'r')
217 self
.sdir
= "%s/%s" % (testbase
, self
.tag
)
218 self
.prefix
= "%s/prefix/%s" % (testbase
, self
.tag
)
219 run_cmd("rm -rf %s" % self
.sdir
)
220 cleanup_list
.append(self
.sdir
)
221 cleanup_list
.append(self
.prefix
)
222 os
.makedirs(self
.sdir
)
223 run_cmd("rm -rf %s" % self
.sdir
)
224 run_cmd("git clone --recursive --shared %s %s" % (test_master
, self
.sdir
), dir=test_master
, show
=True)
227 def start_next(self
):
228 if self
.next
== len(self
.sequence
):
229 print '%s: Completed OK' % self
.name
232 (self
.stage
, self
.cmd
, self
.output_mime_type
) = self
.sequence
[self
.next
]
233 self
.cmd
= self
.cmd
.replace("${PYTHON_PREFIX}", get_python_lib(standard_lib
=1, prefix
=self
.prefix
))
234 self
.cmd
= self
.cmd
.replace("${PREFIX}", "--prefix=%s" % self
.prefix
)
235 self
.cmd
= self
.cmd
.replace("${PREFIX_DIR}", "%s" % self
.prefix
)
236 # if self.output_mime_type == "text/x-subunit":
237 # self.cmd += " | %s --immediate" % (os.path.join(os.path.dirname(__file__), "selftest/format-subunit"))
238 print '%s: [%s] Running %s' % (self
.name
, self
.stage
, self
.cmd
)
240 os
.chdir("%s/%s" % (self
.sdir
, self
.dir))
241 self
.proc
= Popen(self
.cmd
, shell
=True,
242 stdout
=self
.stdout
, stderr
=self
.stderr
, stdin
=self
.stdin
)
247 class buildlist(object):
248 '''handle build of multiple directories'''
250 def __init__(self
, tasklist
, tasknames
, rebase_url
, rebase_branch
="master"):
253 self
.tail_proc
= None
256 tasknames
= defaulttasks
258 # If we are only running one test,
259 # do not sleep randomly to wait for it to start
260 os
.environ
['AUTOBUILD_RANDOM_SLEEP_OVERRIDE'] = '1'
263 b
= builder(n
, tasks
[n
])
266 rebase_remote
= "rebaseon"
267 retry_task
= [ ("retry",
269 git remote add -t %s %s %s
273 git describe %s/%s > old_remote_branch.desc
275 git describe %s/%s > remote_branch.desc
276 diff old_remote_branch.desc remote_branch.desc
279 rebase_branch
, rebase_remote
, rebase_url
,
281 rebase_remote
, rebase_branch
,
283 rebase_remote
, rebase_branch
287 self
.retry
= builder('retry', retry_task
)
288 self
.need_retry
= False
291 if self
.tail_proc
is not None:
292 self
.tail_proc
.terminate()
293 self
.tail_proc
.wait()
294 self
.tail_proc
= None
295 if self
.retry
is not None:
296 self
.retry
.proc
.terminate()
297 self
.retry
.proc
.wait()
300 if b
.proc
is not None:
301 run_cmd("killbysubdir %s > /dev/null 2>&1" % b
.sdir
, checkfail
=False)
313 b
.status
= b
.proc
.poll()
319 ret
= self
.retry
.proc
.poll()
321 self
.need_retry
= True
331 if options
.retry
and self
.need_retry
:
333 print("retry needed")
334 return (0, None, None, None, "retry")
337 if os
.WIFSIGNALED(b
.status
) or os
.WEXITSTATUS(b
.status
) != 0:
339 return (b
.status
, b
.name
, b
.stage
, b
.tag
, "%s: [%s] failed '%s' with status %d" % (b
.name
, b
.stage
, b
.cmd
, b
.status
))
342 return (0, None, None, None, "All OK")
344 def tarlogs(self
, fname
):
345 tar
= tarfile
.open(fname
, "w:gz")
347 tar
.add(b
.stdout_path
, arcname
="%s.stdout" % b
.tag
)
348 tar
.add(b
.stderr_path
, arcname
="%s.stderr" % b
.tag
)
349 if os
.path
.exists("autobuild.log"):
350 tar
.add("autobuild.log")
353 def remove_logs(self
):
355 os
.unlink(b
.stdout_path
)
356 os
.unlink(b
.stderr_path
)
358 def start_tail(self
):
360 cmd
= "tail -f *.stdout *.stderr"
362 self
.tail_proc
= Popen(cmd
, shell
=True)
367 if options
.nocleanup
:
369 print("Cleaning up ....")
370 for d
in cleanup_list
:
371 run_cmd("rm -rf %s" % d
)
375 '''get to the top of the git repo'''
378 if os
.path
.isdir(os
.path
.join(p
, ".git")):
380 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
384 def daemonize(logfile
):
386 if pid
== 0: # Parent
389 if pid
!= 0: # Actual daemon
394 import resource
# Resource usage information.
395 maxfd
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)[1]
396 if maxfd
== resource
.RLIM_INFINITY
:
397 maxfd
= 1024 # Rough guess at maximum number of open file descriptors.
398 for fd
in range(0, maxfd
):
403 os
.open(logfile
, os
.O_RDWR | os
.O_CREAT
)
407 def write_pidfile(fname
):
408 '''write a pid file, cleanup on exit'''
409 f
= open(fname
, mode
='w')
410 f
.write("%u\n" % os
.getpid())
414 def rebase_tree(rebase_url
, rebase_branch
= "master"):
415 rebase_remote
= "rebaseon"
416 print("Rebasing on %s" % rebase_url
)
417 run_cmd("git describe HEAD", show
=True, dir=test_master
)
418 run_cmd("git remote add -t %s %s %s" %
419 (rebase_branch
, rebase_remote
, rebase_url
),
420 show
=True, dir=test_master
)
421 run_cmd("git fetch %s" % rebase_remote
, show
=True, dir=test_master
)
422 if options
.fix_whitespace
:
423 run_cmd("git rebase --force-rebase --whitespace=fix %s/%s" %
424 (rebase_remote
, rebase_branch
),
425 show
=True, dir=test_master
)
427 run_cmd("git rebase --force-rebase %s/%s" %
428 (rebase_remote
, rebase_branch
),
429 show
=True, dir=test_master
)
430 diff
= run_cmd("git --no-pager diff HEAD %s/%s" %
431 (rebase_remote
, rebase_branch
),
432 dir=test_master
, output
=True)
434 print("No differences between HEAD and %s/%s - exiting" %
435 (rebase_remote
, rebase_branch
))
437 run_cmd("git describe %s/%s" %
438 (rebase_remote
, rebase_branch
),
439 show
=True, dir=test_master
)
440 run_cmd("git describe HEAD", show
=True, dir=test_master
)
441 run_cmd("git --no-pager diff --stat HEAD %s/%s" %
442 (rebase_remote
, rebase_branch
),
443 show
=True, dir=test_master
)
445 def push_to(push_url
, push_branch
= "master"):
446 push_remote
= "pushto"
447 print("Pushing to %s" % push_url
)
449 run_cmd("git config --replace-all core.editor script/commit_mark.sh", dir=test_master
)
450 run_cmd("git commit --amend -c HEAD", dir=test_master
)
451 # the notes method doesn't work yet, as metze hasn't allowed refs/notes/* in master
452 # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD", dir=test_master)
453 run_cmd("git remote add -t %s %s %s" %
454 (push_branch
, push_remote
, push_url
),
455 show
=True, dir=test_master
)
456 run_cmd("git push %s +HEAD:%s" %
457 (push_remote
, push_branch
),
458 show
=True, dir=test_master
)
460 def_testbase
= os
.getenv("AUTOBUILD_TESTBASE", "/memdisk/%s" % os
.getenv('USER'))
462 gitroot
= find_git_root()
464 raise Exception("Failed to find git root")
466 parser
= OptionParser()
467 parser
.add_option("", "--tail", help="show output while running", default
=False, action
="store_true")
468 parser
.add_option("", "--keeplogs", help="keep logs", default
=False, action
="store_true")
469 parser
.add_option("", "--nocleanup", help="don't remove test tree", default
=False, action
="store_true")
470 parser
.add_option("", "--testbase", help="base directory to run tests in (default %s)" % def_testbase
,
471 default
=def_testbase
)
472 parser
.add_option("", "--passcmd", help="command to run on success", default
=None)
473 parser
.add_option("", "--verbose", help="show all commands as they are run",
474 default
=False, action
="store_true")
475 parser
.add_option("", "--rebase", help="rebase on the given tree before testing",
476 default
=None, type='str')
477 parser
.add_option("", "--pushto", help="push to a git url on success",
478 default
=None, type='str')
479 parser
.add_option("", "--mark", help="add a Tested-By signoff before pushing",
480 default
=False, action
="store_true")
481 parser
.add_option("", "--fix-whitespace", help="fix whitespace on rebase",
482 default
=False, action
="store_true")
483 parser
.add_option("", "--retry", help="automatically retry if master changes",
484 default
=False, action
="store_true")
485 parser
.add_option("", "--email", help="send email to the given address on failure",
486 type='str', default
=None)
487 parser
.add_option("", "--email-from", help="send email from the given address",
488 type='str', default
="autobuild@samba.org")
489 parser
.add_option("", "--email-server", help="send email via the given server",
490 type='str', default
='localhost')
491 parser
.add_option("", "--always-email", help="always send email, even on success",
493 parser
.add_option("", "--daemon", help="daemonize after initial setup",
495 parser
.add_option("", "--branch", help="the branch to work on (default=master)",
496 default
="master", type='str')
497 parser
.add_option("", "--log-base", help="location where the logs can be found (default=cwd)",
498 default
=gitroot
, type='str')
499 parser
.add_option("", "--attach-logs", help="Attach logs to mails sent on success/failure?",
500 default
=False, action
="store_true")
502 def send_email(subject
, text
, log_tar
):
503 outer
= MIMEMultipart()
504 outer
['Subject'] = subject
505 outer
['To'] = options
.email
506 outer
['From'] = options
.email_from
507 outer
['Date'] = email
.utils
.formatdate(localtime
= True)
508 outer
.preamble
= 'Autobuild mails are now in MIME because we optionally attach the logs.\n'
509 outer
.attach(MIMEText(text
, 'plain'))
510 if options
.attach_logs
:
511 fp
= open(log_tar
, 'rb')
512 msg
= MIMEApplication(fp
.read(), 'gzip', email
.encoders
.encode_base64
)
514 # Set the filename parameter
515 msg
.add_header('Content-Disposition', 'attachment', filename
=os
.path
.basename(log_tar
))
517 content
= outer
.as_string()
518 s
= smtplib
.SMTP(options
.email_server
)
519 s
.sendmail(options
.email_from
, [options
.email
], content
)
523 def email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
524 elapsed_time
, log_base
=None):
525 '''send an email to options.email about the failure'''
526 elapsed_minutes
= elapsed_time
/ 60.0
527 user
= os
.getenv("USER")
533 Your autobuild on %s failed after %.1f minutes
534 when trying to test %s with the following error:
538 the autobuild has been abandoned. Please fix the error and resubmit.
540 A summary of the autobuild process is here:
543 ''' % (platform
.node(), elapsed_minutes
, failed_task
, errstr
, log_base
)
545 if failed_task
!= 'rebase':
547 You can see logs of the failed task here:
552 or you can get full logs of all tasks in this job here:
556 The top commit for the tree that was built was:
560 ''' % (log_base
, failed_tag
, log_base
, failed_tag
, log_base
, top_commit_msg
)
562 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
563 send_email('autobuild failure on %s for task %s during %s'
564 % (platform
.node(), failed_task
, failed_stage
),
567 def email_success(elapsed_time
, log_base
=None):
568 '''send an email to options.email about a successful build'''
569 user
= os
.getenv("USER")
575 Your autobuild on %s has succeeded after %.1f minutes.
577 ''' % (platform
.node(), elapsed_time
/ 60.)
582 you can get full logs of all tasks in this job here:
589 The top commit for the tree that was built was:
594 logs
= os
.path
.join(gitroot
, 'logs.tar.gz')
595 send_email('autobuild sucess on %s ' % platform
.node(),
599 (options
, args
) = parser
.parse_args()
602 if options
.rebase
is None:
603 raise Exception('You can only use --retry if you also rebase')
605 testbase
= "%s/b%u" % (options
.testbase
, os
.getpid())
606 test_master
= "%s/master" % testbase
608 # get the top commit message, for emails
609 top_commit_msg
= run_cmd("git log -1", dir=gitroot
, output
=True)
612 os
.makedirs(testbase
)
613 except Exception, reason
:
614 raise Exception("Unable to create %s : %s" % (testbase
, reason
))
615 cleanup_list
.append(testbase
)
618 logfile
= os
.path
.join(testbase
, "log")
619 print "Forking into the background, writing progress to %s" % logfile
622 write_pidfile(gitroot
+ "/autobuild.pid")
624 start_time
= time
.time()
628 run_cmd("rm -rf %s" % test_master
)
629 cleanup_list
.append(test_master
)
630 run_cmd("git clone --recursive --shared %s %s" % (gitroot
, test_master
), show
=True, dir=gitroot
)
637 if options
.rebase
is not None:
638 rebase_tree(options
.rebase
, rebase_branch
=options
.branch
)
640 cleanup_list
.append(gitroot
+ "/autobuild.pid")
642 elapsed_time
= time
.time() - start_time
643 email_failure(-1, 'rebase', 'rebase', 'rebase',
644 'rebase on %s failed' % options
.branch
,
645 elapsed_time
, log_base
=options
.log_base
)
647 blist
= buildlist(tasks
, args
, options
.rebase
, rebase_branch
=options
.branch
)
650 (status
, failed_task
, failed_stage
, failed_tag
, errstr
) = blist
.run()
651 if status
!= 0 or errstr
!= "retry":
658 cleanup_list
.append(gitroot
+ "/autobuild.pid")
662 print("waiting for tail to flush")
665 elapsed_time
= time
.time() - start_time
668 if options
.passcmd
is not None:
669 print("Running passcmd: %s" % options
.passcmd
)
670 run_cmd(options
.passcmd
, dir=test_master
)
671 if options
.pushto
is not None:
672 push_to(options
.pushto
, push_branch
=options
.branch
)
673 if options
.keeplogs
or options
.attach_logs
:
674 blist
.tarlogs("logs.tar.gz")
675 print("Logs in logs.tar.gz")
676 if options
.always_email
:
677 email_success(elapsed_time
, log_base
=options
.log_base
)
683 # something failed, gather a tar of the logs
684 blist
.tarlogs("logs.tar.gz")
686 if options
.email
is not None:
687 email_failure(status
, failed_task
, failed_stage
, failed_tag
, errstr
,
688 elapsed_time
, log_base
=options
.log_base
)
692 print("Logs in logs.tar.gz")