Remove obsolete land-remote.py and land.py scripts.
authorJelmer Vernooij <jelmer@samba.org>
Tue, 25 Sep 2012 22:47:02 +0000 (00:47 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Wed, 26 Sep 2012 05:58:31 +0000 (07:58 +0200)
script/land-remote.py [deleted file]
script/land.py [deleted file]

diff --git a/script/land-remote.py b/script/land-remote.py
deleted file mode 100755 (executable)
index 1009e6b..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-#!/usr/bin/python
-# Ship a local branch to a remote host (sn-104?) over ssh and run autobuild in it.
-# Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
-# Published under the GPL, v3 or later
-
-import optparse
-import os
-import subprocess
-import sys
-
-samba_master = os.getenv('SAMBA_MASTER', 'git://git.samba.org/samba.git')
-
-parser = optparse.OptionParser("autoland-remote [options] [trees...]")
-parser.add_option("--remote-repo", help="Location of remote repository (default: temporary repository)", type=str, default=None)
-parser.add_option("--host", help="Host to land on (SSH connection string)", type=str, default="sn-devel-104.sn.samba.org")
-parser.add_option("--foreground", help="Don't daemonize", action="store_true", default=False)
-parser.add_option("--email", help="Email address to send build/test output to", type=str, default=None, metavar="EMAIL")
-parser.add_option("--always-email", help="always send email, even on success", action="store_true")
-parser.add_option("--rebase-master", help="rebase on master before testing", default=False, action='store_true')
-parser.add_option("--push-master", help="push to samba.org master on success",
-                  default=False, action='store_true')
-parser.add_option("--pushto", help="push to a git url on success",
-                  default=None, type='str')
-parser.add_option("--rebase", help="rebase on the given tree before testing", default=None, type='str')
-parser.add_option("--passcmd", help="command to run on success", default=None)
-parser.add_option("--tail", help="show output while running", default=False, action="store_true")
-parser.add_option("--keeplogs", help="keep logs", default=False, action="store_true")
-parser.add_option("--nocleanup", help="don't remove test tree", default=False, action="store_true")
-parser.add_option("--revision", help="revision to compile if not HEAD", default=None, type=str)
-parser.add_option("--fix-whitespace", help="fix whitespace on rebase",
-                  default=False, action="store_true")
-parser.add_option("--fail-slowly", help="continue running tests even after one has already failed",
-                  action="store_true")
-
-(opts, extra_args) = parser.parse_args()
-
-if opts.email is None and os.getenv("EMAIL") is not None:
-    opts.email = os.getenv("EMAIL")
-
-if opts.email:
-    print "Sending email to %s" % opts.email
-
-if not opts.foreground and not opts.email:
-    print "Not running in foreground and --email not specified."
-    sys.exit(1)
-
-if not opts.foreground and opts.push_master:
-    print "Pushing to master, forcing run in foreground."
-    opts.foreground = True
-
-if not opts.remote_repo:
-    print "%s$ mktemp -d" % opts.host
-    f = subprocess.Popen(["ssh", opts.host, "mktemp", "-d"], stdout=subprocess.PIPE)
-    (stdout, stderr) = f.communicate()
-    if f.returncode != 0:
-        sys.exit(1)
-    remote_repo = stdout.rstrip()
-    print "Remote tempdir: %s" % remote_repo
-    # Bootstrap, git.samba.org is usually more easily accessible.
-    #remote_args = ["git", "clone", samba_master, remote_repo]
-    remote_args = ["if [ -d /data/git/samba.git ]; then git clone --shared /data/git/samba.git %s; else git clone --shared %s %s; fi" % (remote_repo, samba_master, remote_repo)]
-    #remote_args = ["git", "init", remote_repo]
-    print "%s$ %s" % (opts.host, " ".join(remote_args))
-    subprocess.check_call(["ssh", opts.host] + remote_args)
-else:
-    remote_repo = opts.remote_repo
-
-print "Pushing local branch"
-
-if opts.revision is not None:
-    revision = opts.revision
-else:
-    revision = "HEAD"
-args = ["git", "push", "--force", "git+ssh://%s/%s" % (opts.host, remote_repo), "%s:land" % revision]
-print "$ " + " ".join(args)
-subprocess.check_call(args)
-remote_args = ["cd", remote_repo, ";", "git", "checkout", "land", ";", "python", "-u", "./script/land.py", "--repository=%s" % remote_repo]
-
-if (opts.email and not (opts.foreground or opts.pushto or opts.push_master)):
-    # Force always emailing if there's nothing else to do
-    opts.always_email = True
-
-if opts.email:
-    remote_args.append("--email=%s" % opts.email)
-if opts.always_email:
-    remote_args.append("--always-email")
-if not opts.foreground:
-    remote_args.append("--daemon")
-if opts.nocleanup:
-    remote_args.append("--nocleanup")
-if opts.fix_whitespace:
-    remote_args.append("--fix-whitespace")
-if opts.tail:
-    remote_args.append("--tail")
-if opts.keeplogs:
-    remote_args.append("--keeplogs")
-if opts.rebase_master:
-    remote_args.append("--rebase-master")
-if opts.rebase:
-    remote_args.append("--rebase=%s" % opts.rebase)
-if opts.passcmd:
-    remote_args.append("--passcmd=%s" % opts.passcmd)
-if opts.pushto:
-    remote_args.append("--pushto=%s" % opts.pushto)
-if opts.push_master:
-    remote_args.append("--push-master")
-if opts.fail_slowly:
-    remote_args.append("--fail-slowly")
-
-remote_args += extra_args
-print "%s$ %s" % (opts.host, " ".join(remote_args))
-args = ["ssh", "-A", opts.host] + remote_args
-sys.exit(subprocess.call(args))
diff --git a/script/land.py b/script/land.py
deleted file mode 100755 (executable)
index 72bdd4b..0000000
+++ /dev/null
@@ -1,741 +0,0 @@
-#!/usr/bin/env python
-# run tests on all Samba subprojects and push to a git tree on success
-# Copyright Andrew Tridgell 2010
-# Copyright Jelmer Vernooij 2010
-# released under GNU GPL v3 or later
-
-from cStringIO import StringIO
-import fcntl
-from subprocess import call, check_call, Popen, PIPE
-import os, tarfile, sys, time
-from optparse import OptionParser
-import smtplib
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../selftest"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/testtools"))
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../lib/subunit/python"))
-import subunit
-import testtools
-import subunithelper
-import tempfile
-from email.mime.application import MIMEApplication
-from email.mime.text import MIMEText
-from email.mime.multipart import MIMEMultipart
-
-samba_master = os.getenv('SAMBA_MASTER', 'git://git.samba.org/samba.git')
-samba_master_ssh = os.getenv('SAMBA_MASTER_SSH', 'git+ssh://git.samba.org/data/git/samba.git')
-
-cleanup_list = []
-
-os.environ['CC'] = "ccache gcc"
-
-tasks = {
-    "source3" : [ ("autogen", "./autogen.sh", "text/plain"),
-                  ("configure", "./configure.developer ${PREFIX}", "text/plain"),
-                  ("make basics", "make basics", "text/plain"),
-                  ("make", "make -j 4 everything", "text/plain"), # don't use too many processes
-                  ("install", "make install", "text/plain"),
-                  ("test", "TDB_NO_FSYNC=1 make subunit-test", "text/x-subunit") ],
-
-    "source4" : [ ("configure", "./configure.developer ${PREFIX}", "text/plain"),
-                  ("make", "make -j", "text/plain"),
-                  ("install", "make install", "text/plain"),
-                  ("test", "TDB_NO_FSYNC=1 make subunit-test", "text/x-subunit") ],
-
-    "lib/ldb" : [ ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
-                          ("make", "make -j", "text/plain"),
-                          ("install", "make install", "text/plain"),
-                          ("test", "make test", "text/plain") ],
-
-    "lib/tdb" : [ ("autogen", "./autogen-waf.sh", "text/plain"),
-                  ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
-                  ("make", "make -j", "text/plain"),
-                  ("install", "make install", "text/plain"),
-                  ("test", "make test", "text/plain") ],
-
-    "lib/talloc" : [ ("autogen", "./autogen-waf.sh", "text/plain"),
-                     ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
-                     ("make", "make -j", "text/plain"),
-                     ("install", "make install", "text/plain"),
-                     ("test", "make test", "text/x-subunit"), ],
-
-    "lib/replace" : [ ("autogen", "./autogen-waf.sh", "text/plain"),
-                      ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
-                      ("make", "make -j", "text/plain"),
-                      ("install", "make install", "text/plain"),
-                      ("test", "make test", "text/plain"), ],
-
-    "lib/tevent" : [ ("configure", "./configure --enable-developer -C ${PREFIX}", "text/plain"),
-                     ("make", "make -j", "text/plain"),
-                     ("install", "make install", "text/plain"),
-                     ("test", "make test", "text/plain"), ],
-}
-
-
-def run_cmd(cmd, dir=None, show=None, output=False, checkfail=True, shell=False):
-    if show is None:
-        show = options.verbose
-    if show:
-        print("Running: '%s' in '%s'" % (cmd, dir))
-    if output:
-        return Popen(cmd, stdout=PIPE, cwd=dir, shell=shell).communicate()[0]
-    elif checkfail:
-        return check_call(cmd, cwd=dir, shell=shell)
-    else:
-        return call(cmd, cwd=dir, shell=shell)
-
-
-def clone_gitroot(test_master, revision="HEAD"):
-    run_cmd(["git", "clone", "--shared", gitroot, test_master])
-    if revision != "HEAD":
-        run_cmd(["git", "checkout", revision])
-
-
-class RetryChecker(object):
-    """Check whether it is necessary to retry."""
-
-    def __init__(self, dir):
-        run_cmd(["git", "remote", "add", "-t", "master", "master", samba_master])
-        run_cmd(["git", "fetch", "master"])
-        cmd = '''set -e
-                while :; do
-                  sleep 60
-                  git describe master/master > old_master.desc
-                  git fetch master
-                  git describe master/master > master.desc
-                  diff old_master.desc master.desc
-                done
-               '''
-        self.proc = Popen(cmd, shell=True, cwd=self.dir)
-
-    def poll(self):
-        return self.proc.poll()
-
-    def kill(self):
-        self.proc.terminate()
-        self.proc.wait()
-        self.retry.proc = None
-
-
-class TreeStageBuilder(object):
-    """Handle building of a particular stage for a tree.
-    """
-
-    def __init__(self, tree, name, command, fail_quickly=False):
-        self.tree = tree
-        self.name = name
-        self.command = command
-        self.fail_quickly = fail_quickly
-        self.exitcode = None
-        self.stdin = open(os.devnull, 'r')
-
-    def start(self):
-        raise NotImplementedError(self.start)
-
-    def poll(self):
-        self.exitcode = self.proc.poll()
-        return self.exitcode
-
-    def kill(self):
-        if self.proc is not None:
-            try:
-                run_cmd(["killbysubdir", self.tree.sdir], checkfail=False)
-            except OSError:
-                # killbysubdir doesn't exist ?
-                pass
-            self.proc.terminate()
-            self.proc.wait()
-            self.proc = None
-
-    @property
-    def failure_reason(self):
-        raise NotImplementedError(self.failure_reason)
-
-    @property
-    def failed(self):
-        return (self.exitcode != 0)
-
-
-class PlainTreeStageBuilder(TreeStageBuilder):
-
-    def start(self):
-        print '%s: [%s] Running %s' % (self.name, self.name, self.command)
-        self.proc = Popen(self.command, shell=True, cwd=self.tree.dir,
-                          stdout=self.tree.stdout, stderr=self.tree.stderr,
-                          stdin=self.stdin)
-
-    @property
-    def failure_reason(self):
-        return "failed '%s' with exit code %d" % (self.command, self.exitcode)
-
-
-class AbortingTestResult(subunithelper.TestsuiteEnabledTestResult):
-
-    def __init__(self, stage):
-        super(AbortingTestResult, self).__init__()
-        self.stage = stage
-
-    def addError(self, test, details=None):
-        self.stage.proc.terminate()
-
-    def addFailure(self, test, details=None):
-        self.stage.proc.terminate()
-
-
-class FailureTrackingTestResult(subunithelper.TestsuiteEnabledTestResult):
-
-    def __init__(self, stage):
-        super(FailureTrackingTestResult, self).__init__()
-        self.stage = stage
-
-    def addError(self, test, details=None):
-        if self.stage.failed_test is None:
-            self.stage.failed_test = ("error", test)
-
-    def addFailure(self, test, details=None):
-        if self.stage.failed_test is None:
-            self.stage.failed_test = ("failure", test)
-
-
-class SubunitTreeStageBuilder(TreeStageBuilder):
-
-    def __init__(self, tree, name, command, fail_quickly=False):
-        super(SubunitTreeStageBuilder, self).__init__(tree, name, command,
-                fail_quickly)
-        self.failed_test = None
-        self.subunit_path = os.path.join(gitroot,
-            "%s.%s.subunit" % (self.tree.tag, self.name))
-        self.tree.logfiles.append(
-            (self.subunit_path, os.path.basename(self.subunit_path),
-             "text/x-subunit"))
-        self.subunit = open(self.subunit_path, 'w')
-
-        formatter = subunithelper.PlainFormatter(False, True, {})
-        clients = [formatter, subunit.TestProtocolClient(self.subunit),
-                   FailureTrackingTestResult(self)]
-        if fail_quickly:
-            clients.append(AbortingTestResult(self))
-        self.subunit_server = subunit.TestProtocolServer(
-            testtools.MultiTestResult(*clients),
-            self.subunit)
-        self.buffered = ""
-
-    def start(self):
-        print '%s: [%s] Running' % (self.tree.name, self.name)
-        self.proc = Popen(self.command, shell=True, cwd=self.tree.dir,
-            stdout=PIPE, stderr=self.tree.stderr, stdin=self.stdin)
-        fd = self.proc.stdout.fileno()
-        fl = fcntl.fcntl(fd, fcntl.F_GETFL)
-        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
-
-    def poll(self):
-        try:
-            data = self.proc.stdout.read()
-        except IOError:
-            return None
-        else:
-            self.buffered += data
-            buffered = ""
-            for l in self.buffered.splitlines(True):
-                if l[-1] == "\n":
-                    self.subunit_server.lineReceived(l)
-                else:
-                    buffered += l
-            self.buffered = buffered
-            self.exitcode = self.proc.poll()
-            if self.exitcode is not None:
-                self.subunit.close()
-            return self.exitcode
-
-    @property
-    def failure_reason(self):
-        if self.failed_test:
-            return "failed '%s' with %s in test %s" (self.command, self.failed_test[0], self.failed_test[1])
-        else:
-            return "failed '%s' with exit code %d in unknown test" % (self.command, self.exitcode)
-
-
-class TreeBuilder(object):
-    '''handle build of one directory'''
-
-    def __init__(self, name, sequence, fail_quickly=False):
-        self.name = name
-        self.fail_quickly = fail_quickly
-
-        self.tag = self.name.replace('/', '_')
-        self.sequence = sequence
-        self.next = 0
-        self.stages = []
-        self.stdout_path = os.path.join(gitroot, "%s.stdout" % (self.tag, ))
-        self.stderr_path = os.path.join(gitroot, "%s.stderr" % (self.tag, ))
-        self.logfiles = [
-            (self.stdout_path, os.path.basename(self.stdout_path), "text/plain"),
-            (self.stderr_path, os.path.basename(self.stderr_path), "text/plain"),
-            ]
-        if options.verbose:
-            print("stdout for %s in %s" % (self.name, self.stdout_path))
-            print("stderr for %s in %s" % (self.name, self.stderr_path))
-        if os.path.exists(self.stdout_path):
-            os.unlink(self.stdout_path)
-        if os.path.exists(self.stderr_path):
-            os.unlink(self.stderr_path)
-        self.stdout = open(self.stdout_path, 'w')
-        self.stderr = open(self.stderr_path, 'w')
-        self.sdir = os.path.join(testbase, self.tag)
-        if name in ['pass', 'fail', 'retry']:
-            self.dir = self.sdir
-        else:
-            self.dir = os.path.join(self.sdir, self.name)
-        self.prefix = os.path.join(testbase, "prefix", self.tag)
-        run_cmd(["rm", "-rf", self.sdir])
-        cleanup_list.append(self.sdir)
-        cleanup_list.append(self.prefix)
-        os.makedirs(self.sdir)
-        run_cmd(["rm",  "-rf", self.sdir])
-        clone_gitroot(self.sdir, revision)
-        self.start_next()
-        self.exitcode = None
-
-    def start_next(self):
-        if self.next == len(self.sequence):
-            print '%s: Completed OK' % self.name
-            self.done = True
-            self.stdout.close()
-            self.stderr.close()
-            return
-        (stage_name, cmd, output_mime_type) = self.sequence[self.next]
-        cmd = cmd.replace("${PREFIX}", "--prefix=%s" % self.prefix)
-        if output_mime_type == "text/plain":
-            self.current_stage = PlainTreeStageBuilder(self, stage_name, cmd,
-                self.fail_quickly)
-        elif output_mime_type == "text/x-subunit":
-            self.current_stage = SubunitTreeStageBuilder(self, stage_name, cmd,
-                self.fail_quickly)
-        else:
-            raise Exception("Unknown output mime type %s" % output_mime_type)
-        self.stages.append(self.current_stage)
-        self.current_stage.start()
-        self.next += 1
-
-    def remove_logs(self):
-        for path, name, mime_type in self.logfiles:
-            os.unlink(path)
-
-    def poll(self):
-        self.exitcode = self.current_stage.poll()
-        if self.exitcode is not None:
-            self.current_stage = None
-        return self.exitcode
-
-    def kill(self):
-        if self.current_stage is not None:
-            self.current_stage.kill()
-            self.current_stage = None
-
-    @property
-    def failed(self):
-        return any([s.failed for s in self.stages])
-
-    @property
-    def failed_stage(self):
-        for s in self.stages:
-            if s.failed:
-                return s
-        return s
-
-    @property
-    def failure_reason(self):
-        return "%s: [%s] %s" % (self.name, self.failed_stage.name,
-            self.failed_stage.failure_reason)
-
-
-class BuildList(object):
-    '''handle build of multiple directories'''
-
-    def __init__(self, tasklist, tasknames):
-        global tasks
-        self.tlist = []
-        self.tail_proc = None
-        self.retry = None
-        if tasknames == ['pass']:
-            tasks = { 'pass' : [ ("pass", '/bin/true', "text/plain") ]}
-        if tasknames == ['fail']:
-            tasks = { 'fail' : [ ("fail", '/bin/false', "text/plain") ]}
-        if tasknames == []:
-            tasknames = tasklist
-        for n in tasknames:
-            b = TreeBuilder(n, tasks[n], not options.fail_slowly)
-            self.tlist.append(b)
-        if options.retry:
-            self.retry = RetryChecker(self.sdir)
-            self.need_retry = False
-
-    def kill_kids(self):
-        if self.tail_proc is not None:
-            self.tail_proc.terminate()
-            self.tail_proc.wait()
-            self.tail_proc = None
-        if self.retry is not None:
-            self.retry.kill()
-        for b in self.tlist:
-            b.kill()
-
-    def wait_one(self):
-        while True:
-            none_running = True
-            for b in self.tlist:
-                if b.current_stage is None:
-                    continue
-                none_running = False
-                if b.poll() is None:
-                    continue
-                return b
-            if options.retry:
-                ret = self.retry.poll()
-                if ret:
-                    self.need_retry = True
-                    self.retry = None
-                    return None
-            if none_running:
-                return None
-            time.sleep(0.1)
-
-    def run(self):
-        while True:
-            b = self.wait_one()
-            if options.retry and self.need_retry:
-                self.kill_kids()
-                print("retry needed")
-                return (0, None, None, None, "retry")
-            if b is None:
-                break
-            if b.failed:
-                self.kill_kids()
-                return (b.exitcode, b.name, b.failed_stage, b.tag, b.failure_reason)
-            b.start_next()
-        self.kill_kids()
-        return (0, None, None, None, "All OK")
-
-    def tarlogs(self, name=None, fileobj=None):
-        tar = tarfile.open(name=name, fileobj=fileobj, mode="w:gz")
-        for b in self.tlist:
-            for (path, name, mime_type) in b.logfiles:
-                tar.add(path, arcname=name)
-        if os.path.exists("autobuild.log"):
-            tar.add("autobuild.log")
-        tar.close()
-
-    def attach_logs(self, outer):
-        f = StringIO()
-        self.tarlogs(fileobj=f)
-        msg = MIMEApplication(f.getvalue(), "x-gzip")
-        msg.add_header('Content-Disposition', 'attachment',
-                       filename="logs.tar.gz")
-        outer.attach(msg)
-
-    def remove_logs(self):
-        for b in self.tlist:
-            b.remove_logs()
-
-    def start_tail(self):
-        cmd = "tail -f *.stdout *.stderr"
-        self.tail_proc = Popen(cmd, shell=True, cwd=gitroot)
-
-
-def cleanup():
-    if options.nocleanup:
-        return
-    print("Cleaning up ....")
-    for d in cleanup_list:
-        run_cmd(["rm", "-rf", d])
-
-
-def find_git_root(p):
-    '''get to the top of the git repo'''
-    while p != '/':
-        if os.path.isdir(os.path.join(p, ".git")):
-            return p
-        p = os.path.abspath(os.path.join(p, '..'))
-    return None
-
-
-def daemonize(logfile):
-    pid = os.fork()
-    if pid == 0: # Parent
-        os.setsid()
-        pid = os.fork()
-        if pid != 0: # Actual daemon
-            os._exit(0)
-    else: # Grandparent
-        os._exit(0)
-
-    import resource      # Resource usage information.
-    maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
-    if maxfd == resource.RLIM_INFINITY:
-        maxfd = 1024 # Rough guess at maximum number of open file descriptors.
-    for fd in range(0, maxfd):
-        try:
-            os.close(fd)
-        except OSError:
-            pass
-    os.open(logfile, os.O_RDWR | os.O_CREAT)
-    os.dup2(0, 1)
-    os.dup2(0, 2)
-
-
-def rebase_tree(url):
-    print("Rebasing on %s" % url)
-    run_cmd(["git", "remote", "add", "-t", "master", "master", url], show=True,
-            dir=test_master)
-    run_cmd(["git", "fetch", "master"], show=True, dir=test_master)
-    if options.fix_whitespace:
-        run_cmd(["git", "rebase", "--whitespace=fix", "master/master"],
-                show=True, dir=test_master)
-    else:
-        run_cmd(["git", "rebase", "master/master"], show=True, dir=test_master)
-    diff = run_cmd(["git", "--no-pager", "diff", "HEAD", "master/master"],
-        dir=test_master, output=True)
-    if diff == '':
-        print("No differences between HEAD and master/master - exiting")
-        sys.exit(0)
-
-def push_to(url):
-    print("Pushing to %s" % url)
-    if options.mark:
-        run_cmd("EDITOR=script/commit_mark.sh git commit --amend -c HEAD",
-            dir=test_master, shell=True)
-        # the notes method doesn't work yet, as metze hasn't allowed
-        # refs/notes/* in master
-        # run_cmd("EDITOR=script/commit_mark.sh git notes edit HEAD",
-        #     dir=test_master)
-    run_cmd(["git", "remote", "add", "-t", "master", "pushto", url], show=True,
-        dir=test_master)
-    run_cmd(["git", "push", "pushto", "+HEAD:master"], show=True,
-        dir=test_master)
-
-def_testbase = os.getenv("AUTOBUILD_TESTBASE")
-if def_testbase is None:
-    if os.path.exists("/memdisk"):
-        def_testbase = "/memdisk/%s" % os.getenv('USER')
-    else:
-        def_testbase = os.path.join(tempfile.gettempdir(), "autobuild-%s" % os.getenv("USER"))
-
-parser = OptionParser()
-parser.add_option("--repository", help="repository to run tests for", default=None, type=str)
-parser.add_option("--revision", help="revision to compile if not HEAD", default=None, type=str)
-parser.add_option("--tail", help="show output while running", default=False, action="store_true")
-parser.add_option("--keeplogs", help="keep logs", default=False, action="store_true")
-parser.add_option("--nocleanup", help="don't remove test tree", default=False, action="store_true")
-parser.add_option("--testbase", help="base directory to run tests in (default %s)" % def_testbase,
-                  default=def_testbase)
-parser.add_option("--passcmd", help="command to run on success", default=None)
-parser.add_option("--verbose", help="show all commands as they are run",
-                  default=False, action="store_true")
-parser.add_option("--rebase", help="rebase on the given tree before testing",
-                  default=None, type='str')
-parser.add_option("--rebase-master", help="rebase on %s before testing" % samba_master,
-                  default=False, action='store_true')
-parser.add_option("--pushto", help="push to a git url on success",
-                  default=None, type='str')
-parser.add_option("--push-master", help="push to %s on success" % samba_master_ssh,
-                  default=False, action='store_true')
-parser.add_option("--mark", help="add a Tested-By signoff before pushing",
-                  default=False, action="store_true")
-parser.add_option("--fix-whitespace", help="fix whitespace on rebase",
-                  default=False, action="store_true")
-parser.add_option("--retry", help="automatically retry if master changes",
-                  default=False, action="store_true")
-parser.add_option("--email", help="send email to the given address on failure",
-                  type='str', default=None)
-parser.add_option("--always-email", help="always send email, even on success",
-                  action="store_true")
-parser.add_option("--daemon", help="daemonize after initial setup",
-                  action="store_true")
-parser.add_option("--fail-slowly", help="continue running tests even after one has already failed",
-                  action="store_true")
-
-
-def email_failure(blist, exitcode, failed_task, failed_stage, failed_tag, errstr):
-    '''send an email to options.email about the failure'''
-    user = os.getenv("USER")
-    text = '''
-Dear Developer,
-
-Your autobuild failed when trying to test %s with the following error:
-   %s
-
-the autobuild has been abandoned. Please fix the error and resubmit.
-
-You can see logs of the failed task here:
-
-  http://git.samba.org/%s/samba-autobuild/%s.stdout
-  http://git.samba.org/%s/samba-autobuild/%s.stderr
-
-A summary of the autobuild process is here:
-
-  http://git.samba.org/%s/samba-autobuild/autobuild.log
-
-or you can get full logs of all tasks in this job here:
-
-  http://git.samba.org/%s/samba-autobuild/logs.tar.gz
-
-The top commit for the tree that was built was:
-
-%s
-
-''' % (failed_task, errstr, user, failed_tag, user, failed_tag, user, user,
-       get_top_commit_msg(test_master))
-
-    msg = MIMEMultipart()
-    msg['Subject'] = 'autobuild failure for task %s during %s' % (
-        failed_task, failed_stage.name)
-    msg['From'] = 'autobuild@samba.org'
-    msg['To'] = options.email
-
-    main = MIMEText(text)
-    msg.attach(main)
-
-    blist.attach_logs(msg)
-
-    s = smtplib.SMTP()
-    s.connect()
-    s.sendmail(msg['From'], [msg['To']], msg.as_string())
-    s.quit()
-
-def email_success(blist):
-    '''send an email to options.email about a successful build'''
-    user = os.getenv("USER")
-    text = '''
-Dear Developer,
-
-Your autobuild has succeeded.
-
-'''
-
-    if options.keeplogs:
-        text += '''
-
-you can get full logs of all tasks in this job here:
-
-  http://git.samba.org/%s/samba-autobuild/logs.tar.gz
-
-''' % user
-
-    text += '''
-The top commit for the tree that was built was:
-
-%s
-''' % (get_top_commit_msg(test_master),)
-
-    msg = MIMEMultipart()
-    msg['Subject'] = 'autobuild success'
-    msg['From'] = 'autobuild@samba.org'
-    msg['To'] = options.email
-
-    main = MIMEText(text, 'plain')
-    msg.attach(main)
-
-    blist.attach_logs(msg)
-
-    s = smtplib.SMTP()
-    s.connect()
-    s.sendmail(msg['From'], [msg['To']], msg.as_string())
-    s.quit()
-
-
-(options, args) = parser.parse_args()
-
-if options.retry:
-    if not options.rebase_master and options.rebase is None:
-        raise Exception('You can only use --retry if you also rebase')
-
-testbase = os.path.join(options.testbase, "b%u" % (os.getpid(),))
-test_master = os.path.join(testbase, "master")
-
-if options.repository is not None:
-    repository = options.repository
-else:
-    repository = os.getcwd()
-
-gitroot = find_git_root(repository)
-if gitroot is None:
-    raise Exception("Failed to find git root under %s" % repository)
-
-# get the top commit message, for emails
-if options.revision is not None:
-    revision = options.revision
-else:
-    revision = "HEAD"
-
-def get_top_commit_msg(reporoot):
-    return run_cmd(["git", "log", "-1"], dir=reporoot, output=True)
-
-try:
-    os.makedirs(testbase)
-except Exception, reason:
-    raise Exception("Unable to create %s : %s" % (testbase, reason))
-cleanup_list.append(testbase)
-
-if options.daemon:
-    logfile = os.path.join(testbase, "log")
-    print "Forking into the background, writing progress to %s" % logfile
-    daemonize(logfile)
-
-while True:
-    try:
-        run_cmd(["rm", "-rf", test_master])
-        cleanup_list.append(test_master)
-        clone_gitroot(test_master, revision)
-    except:
-        cleanup()
-        raise
-
-    try:
-        if options.rebase is not None:
-            rebase_tree(options.rebase)
-        elif options.rebase_master:
-            rebase_tree(samba_master)
-        blist = BuildList(tasks, args)
-        if options.tail:
-            blist.start_tail()
-        (exitcode, failed_task, failed_stage, failed_tag, errstr) = blist.run()
-        if exitcode != 0 or errstr != "retry":
-            break
-        cleanup()
-    except:
-        cleanup()
-        raise
-
-blist.kill_kids()
-if options.tail:
-    print("waiting for tail to flush")
-    time.sleep(1)
-
-if exitcode == 0:
-    print errstr
-    if options.passcmd is not None:
-        print("Running passcmd: %s" % options.passcmd)
-        run_cmd(options.passcmd, dir=test_master, shell=True)
-    if options.pushto is not None:
-        push_to(options.pushto)
-    elif options.push_master:
-        push_to(samba_master_ssh)
-    if options.keeplogs:
-        blist.tarlogs("logs.tar.gz")
-        print("Logs in logs.tar.gz")
-    if options.always_email:
-        email_success(blist)
-    blist.remove_logs()
-    cleanup()
-    print(errstr)
-else:
-    # something failed, gather a tar of the logs
-    blist.tarlogs("logs.tar.gz")
-
-    if options.email is not None:
-        email_failure(blist, exitcode, failed_task, failed_stage, failed_tag,
-            errstr)
-
-    cleanup()
-    print(errstr)
-    print("Logs in logs.tar.gz")
-sys.exit(exitcode)