| Index: third_party/buildbot_7_12/buildbot/scripts/tryclient.py
|
| diff --git a/third_party/buildbot_7_12/buildbot/scripts/tryclient.py b/third_party/buildbot_7_12/buildbot/scripts/tryclient.py
|
| deleted file mode 100644
|
| index 53ec1e3e9d1668c56a77a43266f5c2ada1733b8f..0000000000000000000000000000000000000000
|
| --- a/third_party/buildbot_7_12/buildbot/scripts/tryclient.py
|
| +++ /dev/null
|
| @@ -1,699 +0,0 @@
|
| -# -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*-
|
| -
|
| -import sys, os, re, time, random
|
| -from twisted.internet import utils, protocol, defer, reactor, task
|
| -from twisted.spread import pb
|
| -from twisted.cred import credentials
|
| -from twisted.python import log
|
| -from twisted.python.procutils import which
|
| -
|
| -from buildbot.sourcestamp import SourceStamp
|
| -from buildbot.scripts import runner
|
| -from buildbot.util import now
|
| -from buildbot.status import builder
|
| -
|
| -class SourceStampExtractor:
|
| -
|
| - def __init__(self, treetop, branch):
|
| - self.treetop = treetop
|
| - self.branch = branch
|
| - self.exe = which(self.vcexe)[0]
|
| -
|
| - def dovc(self, cmd):
|
| - """This accepts the arguments of a command, without the actual
|
| - command itself."""
|
| - env = os.environ.copy()
|
| - env['LC_ALL'] = "C"
|
| - d = utils.getProcessOutputAndValue(self.exe, cmd, env=env,
|
| - path=self.treetop)
|
| - d.addCallback(self._didvc, cmd)
|
| - return d
|
| - def _didvc(self, res, cmd):
|
| - (stdout, stderr, code) = res
|
| - # 'bzr diff' sets rc=1 if there were any differences. tla, baz, and
|
| - # cvs do something similar, so don't bother requring rc=0.
|
| - return stdout
|
| -
|
| - def get(self):
|
| - """Return a Deferred that fires with a SourceStamp instance."""
|
| - d = self.getBaseRevision()
|
| - d.addCallback(self.getPatch)
|
| - d.addCallback(self.done)
|
| - return d
|
| - def readPatch(self, res, patchlevel):
|
| - self.patch = (patchlevel, res)
|
| - def done(self, res):
|
| - # TODO: figure out the branch too
|
| - ss = SourceStamp(self.branch, self.baserev, self.patch)
|
| - return ss
|
| -
|
| -class CVSExtractor(SourceStampExtractor):
|
| - patchlevel = 0
|
| - vcexe = "cvs"
|
| - def getBaseRevision(self):
|
| - # this depends upon our local clock and the repository's clock being
|
| - # reasonably synchronized with each other. We express everything in
|
| - # UTC because the '%z' format specifier for strftime doesn't always
|
| - # work.
|
| - self.baserev = time.strftime("%Y-%m-%d %H:%M:%S +0000",
|
| - time.gmtime(now()))
|
| - return defer.succeed(None)
|
| -
|
| - def getPatch(self, res):
|
| - # the -q tells CVS to not announce each directory as it works
|
| - if self.branch is not None:
|
| - # 'cvs diff' won't take both -r and -D at the same time (it
|
| - # ignores the -r). As best I can tell, there is no way to make
|
| - # cvs give you a diff relative to a timestamp on the non-trunk
|
| - # branch. A bare 'cvs diff' will tell you about the changes
|
| - # relative to your checked-out versions, but I know of no way to
|
| - # find out what those checked-out versions are.
|
| - raise RuntimeError("Sorry, CVS 'try' builds don't work with "
|
| - "branches")
|
| - args = ['-q', 'diff', '-u', '-D', self.baserev]
|
| - d = self.dovc(args)
|
| - d.addCallback(self.readPatch, self.patchlevel)
|
| - return d
|
| -
|
| -class SVNExtractor(SourceStampExtractor):
|
| - patchlevel = 0
|
| - vcexe = "svn"
|
| -
|
| - def getBaseRevision(self):
|
| - d = self.dovc(["status", "-u"])
|
| - d.addCallback(self.parseStatus)
|
| - return d
|
| - def parseStatus(self, res):
|
| - # svn shows the base revision for each file that has been modified or
|
| - # which needs an update. You can update each file to a different
|
| - # version, so each file is displayed with its individual base
|
| - # revision. It also shows the repository-wide latest revision number
|
| - # on the last line ("Status against revision: \d+").
|
| -
|
| - # for our purposes, we use the latest revision number as the "base"
|
| - # revision, and get a diff against that. This means we will get
|
| - # reverse-diffs for local files that need updating, but the resulting
|
| - # tree will still be correct. The only weirdness is that the baserev
|
| - # that we emit may be different than the version of the tree that we
|
| - # first checked out.
|
| -
|
| - # to do this differently would probably involve scanning the revision
|
| - # numbers to find the max (or perhaps the min) revision, and then
|
| - # using that as a base.
|
| -
|
| - for line in res.split("\n"):
|
| - m = re.search(r'^Status against revision:\s+(\d+)', line)
|
| - if m:
|
| - self.baserev = int(m.group(1))
|
| - return
|
| - raise IndexError("Could not find 'Status against revision' in "
|
| - "SVN output: %s" % res)
|
| - def getPatch(self, res):
|
| - d = self.dovc(["diff", "-r%d" % self.baserev])
|
| - d.addCallback(self.readPatch, self.patchlevel)
|
| - return d
|
| -
|
| -class BazExtractor(SourceStampExtractor):
|
| - patchlevel = 1
|
| - vcexe = "baz"
|
| - def getBaseRevision(self):
|
| - d = self.dovc(["tree-id"])
|
| - d.addCallback(self.parseStatus)
|
| - return d
|
| - def parseStatus(self, res):
|
| - tid = res.strip()
|
| - slash = tid.index("/")
|
| - dd = tid.rindex("--")
|
| - self.branch = tid[slash+1:dd]
|
| - self.baserev = tid[dd+2:]
|
| - def getPatch(self, res):
|
| - d = self.dovc(["diff"])
|
| - d.addCallback(self.readPatch, self.patchlevel)
|
| - return d
|
| -
|
| -class TlaExtractor(SourceStampExtractor):
|
| - patchlevel = 1
|
| - vcexe = "tla"
|
| - def getBaseRevision(self):
|
| - # 'tla logs --full' gives us ARCHIVE/BRANCH--REVISION
|
| - # 'tla logs' gives us REVISION
|
| - d = self.dovc(["logs", "--full", "--reverse"])
|
| - d.addCallback(self.parseStatus)
|
| - return d
|
| - def parseStatus(self, res):
|
| - tid = res.split("\n")[0].strip()
|
| - slash = tid.index("/")
|
| - dd = tid.rindex("--")
|
| - self.branch = tid[slash+1:dd]
|
| - self.baserev = tid[dd+2:]
|
| -
|
| - def getPatch(self, res):
|
| - d = self.dovc(["changes", "--diffs"])
|
| - d.addCallback(self.readPatch, self.patchlevel)
|
| - return d
|
| -
|
| -class BzrExtractor(SourceStampExtractor):
|
| - patchlevel = 0
|
| - vcexe = "bzr"
|
| - def getBaseRevision(self):
|
| - d = self.dovc(["revision-info","-rsubmit:"])
|
| - d.addCallback(self.get_revision_number)
|
| - return d
|
| -
|
| - def get_revision_number(self, out):
|
| - revno, revid= out.split()
|
| - self.baserev = 'revid:' + revid
|
| - return
|
| -
|
| - def getPatch(self, res):
|
| - d = self.dovc(["diff","-r%s.." % self.baserev])
|
| - d.addCallback(self.readPatch, self.patchlevel)
|
| - return d
|
| -
|
| -class MercurialExtractor(SourceStampExtractor):
|
| - patchlevel = 1
|
| - vcexe = "hg"
|
| - def getBaseRevision(self):
|
| - d = self.dovc(["identify"])
|
| - d.addCallback(self.parseStatus)
|
| - return d
|
| - def parseStatus(self, output):
|
| - m = re.search(r'^(\w+)', output)
|
| - self.baserev = m.group(0)
|
| - def getPatch(self, res):
|
| - d = self.dovc(["diff"])
|
| - d.addCallback(self.readPatch, self.patchlevel)
|
| - return d
|
| -
|
| -class DarcsExtractor(SourceStampExtractor):
|
| - patchlevel = 1
|
| - vcexe = "darcs"
|
| - def getBaseRevision(self):
|
| - d = self.dovc(["changes", "--context"])
|
| - d.addCallback(self.parseStatus)
|
| - return d
|
| - def parseStatus(self, res):
|
| - self.baserev = res # the whole context file
|
| - def getPatch(self, res):
|
| - d = self.dovc(["diff", "-u"])
|
| - d.addCallback(self.readPatch, self.patchlevel)
|
| - return d
|
| -
|
| -class GitExtractor(SourceStampExtractor):
|
| - patchlevel = 1
|
| - vcexe = "git"
|
| -
|
| - def getBaseRevision(self):
|
| - d = self.dovc(["branch", "--no-color", "-v", "--no-abbrev"])
|
| - d.addCallback(self.parseStatus)
|
| - return d
|
| -
|
| - def readConfig(self):
|
| - d = self.dovc(["config", "-l"])
|
| - d.addCallback(self.parseConfig)
|
| - return d
|
| -
|
| - def parseConfig(self, res):
|
| - git_config = {}
|
| - for l in res.split("\n"):
|
| - if l.strip():
|
| - parts = l.strip().split("=", 2)
|
| - git_config[parts[0]] = parts[1]
|
| -
|
| - # If we're tracking a remote, consider that the base.
|
| - remote = git_config.get("branch." + self.branch + ".remote")
|
| - ref = git_config.get("branch." + self.branch + ".merge")
|
| - if remote and ref:
|
| - remote_branch = ref.split("/", 3)[-1]
|
| - d = self.dovc(["rev-parse", remote + "/" + remote_branch])
|
| - d.addCallback(self.override_baserev)
|
| - return d
|
| -
|
| - def override_baserev(self, res):
|
| - self.baserev = res.strip()
|
| -
|
| - def parseStatus(self, res):
|
| - # The current branch is marked by '*' at the start of the
|
| - # line, followed by the branch name and the SHA1.
|
| - #
|
| - # Branch names may contain pretty much anything but whitespace.
|
| - m = re.search(r'^\* (\S+)\s+([0-9a-f]{40})', res, re.MULTILINE)
|
| - if m:
|
| - self.baserev = m.group(2)
|
| - # If a branch is specified, parse out the rev it points to
|
| - # and extract the local name (assuming it has a slash).
|
| - # This may break if someone specifies the name of a local
|
| - # branch that has a slash in it and has no corresponding
|
| - # remote branch (or something similarly contrived).
|
| - if self.branch:
|
| - d = self.dovc(["rev-parse", self.branch])
|
| - if '/' in self.branch:
|
| - self.branch = self.branch.split('/', 1)[1]
|
| - d.addCallback(self.override_baserev)
|
| - return d
|
| - else:
|
| - self.branch = m.group(1)
|
| - return self.readConfig()
|
| - raise IndexError("Could not find current GIT branch: %s" % res)
|
| -
|
| - def getPatch(self, res):
|
| - d = self.dovc(["diff", self.baserev])
|
| - d.addCallback(self.readPatch, self.patchlevel)
|
| - return d
|
| -
|
| -def getSourceStamp(vctype, treetop, branch=None):
|
| - if vctype == "cvs":
|
| - e = CVSExtractor(treetop, branch)
|
| - elif vctype == "svn":
|
| - e = SVNExtractor(treetop, branch)
|
| - elif vctype == "baz":
|
| - e = BazExtractor(treetop, branch)
|
| - elif vctype == "bzr":
|
| - e = BzrExtractor(treetop, branch)
|
| - elif vctype == "tla":
|
| - e = TlaExtractor(treetop, branch)
|
| - elif vctype == "hg":
|
| - e = MercurialExtractor(treetop, branch)
|
| - elif vctype == "darcs":
|
| - e = DarcsExtractor(treetop, branch)
|
| - elif vctype == "git":
|
| - e = GitExtractor(treetop, branch)
|
| - else:
|
| - raise KeyError("unknown vctype '%s'" % vctype)
|
| - return e.get()
|
| -
|
| -
|
| -def ns(s):
|
| - return "%d:%s," % (len(s), s)
|
| -
|
| -def createJobfile(bsid, branch, baserev, patchlevel, diff, builderNames):
|
| - job = ""
|
| - job += ns("1")
|
| - job += ns(bsid)
|
| - job += ns(branch)
|
| - job += ns(str(baserev))
|
| - job += ns("%d" % patchlevel)
|
| - job += ns(diff)
|
| - for bn in builderNames:
|
| - job += ns(bn)
|
| - return job
|
| -
|
| -def getTopdir(topfile, start=None):
|
| - """walk upwards from the current directory until we find this topfile"""
|
| - if not start:
|
| - start = os.getcwd()
|
| - here = start
|
| - toomany = 20
|
| - while toomany > 0:
|
| - if os.path.exists(os.path.join(here, topfile)):
|
| - return here
|
| - next = os.path.dirname(here)
|
| - if next == here:
|
| - break # we've hit the root
|
| - here = next
|
| - toomany -= 1
|
| - raise ValueError("Unable to find topfile '%s' anywhere from %s upwards"
|
| - % (topfile, start))
|
| -
|
| -class RemoteTryPP(protocol.ProcessProtocol):
|
| - def __init__(self, job):
|
| - self.job = job
|
| - self.d = defer.Deferred()
|
| - def connectionMade(self):
|
| - self.transport.write(self.job)
|
| - self.transport.closeStdin()
|
| - def outReceived(self, data):
|
| - sys.stdout.write(data)
|
| - def errReceived(self, data):
|
| - sys.stderr.write(data)
|
| - def processEnded(self, status_object):
|
| - sig = status_object.value.signal
|
| - rc = status_object.value.exitCode
|
| - if sig != None or rc != 0:
|
| - self.d.errback(RuntimeError("remote 'buildbot tryserver' failed"
|
| - ": sig=%s, rc=%s" % (sig, rc)))
|
| - return
|
| - self.d.callback((sig, rc))
|
| -
|
| -class BuildSetStatusGrabber:
|
| - retryCount = 5 # how many times to we try to grab the BuildSetStatus?
|
| - retryDelay = 3 # seconds to wait between attempts
|
| -
|
| - def __init__(self, status, bsid):
|
| - self.status = status
|
| - self.bsid = bsid
|
| -
|
| - def grab(self):
|
| - # return a Deferred that either fires with the BuildSetStatus
|
| - # reference or errbacks because we were unable to grab it
|
| - self.d = defer.Deferred()
|
| - # wait a second before querying to give the master's maildir watcher
|
| - # a chance to see the job
|
| - reactor.callLater(1, self.go)
|
| - return self.d
|
| -
|
| - def go(self, dummy=None):
|
| - if self.retryCount == 0:
|
| - raise RuntimeError("couldn't find matching buildset")
|
| - self.retryCount -= 1
|
| - d = self.status.callRemote("getBuildSets")
|
| - d.addCallback(self._gotSets)
|
| -
|
| - def _gotSets(self, buildsets):
|
| - for bs,bsid in buildsets:
|
| - if bsid == self.bsid:
|
| - # got it
|
| - self.d.callback(bs)
|
| - return
|
| - d = defer.Deferred()
|
| - d.addCallback(self.go)
|
| - reactor.callLater(self.retryDelay, d.callback, None)
|
| -
|
| -
|
| -class Try(pb.Referenceable):
|
| - buildsetStatus = None
|
| - quiet = False
|
| -
|
| - def __init__(self, config):
|
| - self.config = config
|
| - self.connect = self.getopt('connect')
|
| - assert self.connect, "you must specify a connect style: ssh or pb"
|
| - self.builderNames = self.getopt('builders')
|
| -
|
| - def getopt(self, config_name, default=None):
|
| - value = self.config.get(config_name)
|
| - if value is None or value == []:
|
| - value = default
|
| - return value
|
| -
|
| - def createJob(self):
|
| - # returns a Deferred which fires when the job parameters have been
|
| - # created
|
| -
|
| - # generate a random (unique) string. It would make sense to add a
|
| - # hostname and process ID here, but a) I suspect that would cause
|
| - # windows portability problems, and b) really this is good enough
|
| - self.bsid = "%d-%s" % (time.time(), random.randint(0, 1000000))
|
| -
|
| - # common options
|
| - branch = self.getopt("branch")
|
| -
|
| - difffile = self.config.get("diff")
|
| - if difffile:
|
| - baserev = self.config.get("baserev")
|
| - if difffile == "-":
|
| - diff = sys.stdin.read()
|
| - else:
|
| - diff = open(difffile,"r").read()
|
| - patch = (self.config['patchlevel'], diff)
|
| - ss = SourceStamp(branch, baserev, patch)
|
| - d = defer.succeed(ss)
|
| - else:
|
| - vc = self.getopt("vc")
|
| - if vc in ("cvs", "svn"):
|
| - # we need to find the tree-top
|
| - topdir = self.getopt("try-topdir")
|
| - if topdir:
|
| - treedir = os.path.expanduser(topdir)
|
| - else:
|
| - topfile = self.getopt("try-topfile")
|
| - treedir = getTopdir(topfile)
|
| - else:
|
| - treedir = os.getcwd()
|
| - d = getSourceStamp(vc, treedir, branch)
|
| - d.addCallback(self._createJob_1)
|
| - return d
|
| -
|
| - def _createJob_1(self, ss):
|
| - self.sourcestamp = ss
|
| - if self.connect == "ssh":
|
| - patchlevel, diff = ss.patch
|
| - revspec = ss.revision
|
| - if revspec is None:
|
| - revspec = ""
|
| - self.jobfile = createJobfile(self.bsid,
|
| - ss.branch or "", revspec,
|
| - patchlevel, diff,
|
| - self.builderNames)
|
| -
|
| - def fakeDeliverJob(self):
|
| - # Display the job to be delivered, but don't perform delivery.
|
| - ss = self.sourcestamp
|
| - print ("Job:\n\tBranch: %s\n\tRevision: %s\n\tBuilders: %s\n%s"
|
| - % (ss.branch,
|
| - ss.revision,
|
| - self.builderNames,
|
| - ss.patch[1]))
|
| - d = defer.Deferred()
|
| - d.callback(True)
|
| - return d
|
| -
|
| - def deliverJob(self):
|
| - # returns a Deferred that fires when the job has been delivered
|
| -
|
| - if self.connect == "ssh":
|
| - tryhost = self.getopt("tryhost")
|
| - tryuser = self.getopt("username")
|
| - trydir = self.getopt("trydir")
|
| -
|
| - argv = ["ssh", "-l", tryuser, tryhost,
|
| - "buildbot", "tryserver", "--jobdir", trydir]
|
| - # now run this command and feed the contents of 'job' into stdin
|
| -
|
| - pp = RemoteTryPP(self.jobfile)
|
| - p = reactor.spawnProcess(pp, argv[0], argv, os.environ)
|
| - d = pp.d
|
| - return d
|
| - if self.connect == "pb":
|
| - user = self.getopt("username")
|
| - passwd = self.getopt("passwd")
|
| - master = self.getopt("master")
|
| - tryhost, tryport = master.split(":")
|
| - tryport = int(tryport)
|
| - f = pb.PBClientFactory()
|
| - d = f.login(credentials.UsernamePassword(user, passwd))
|
| - reactor.connectTCP(tryhost, tryport, f)
|
| - d.addCallback(self._deliverJob_pb)
|
| - return d
|
| - raise RuntimeError("unknown connecttype '%s', should be 'ssh' or 'pb'"
|
| - % self.connect)
|
| -
|
| - def _deliverJob_pb(self, remote):
|
| - ss = self.sourcestamp
|
| -
|
| - d = remote.callRemote("try",
|
| - ss.branch,
|
| - ss.revision,
|
| - ss.patch,
|
| - self.builderNames,
|
| - self.config.get('properties', {}))
|
| - d.addCallback(self._deliverJob_pb2)
|
| - return d
|
| - def _deliverJob_pb2(self, status):
|
| - self.buildsetStatus = status
|
| - return status
|
| -
|
| - def getStatus(self):
|
| - # returns a Deferred that fires when the builds have finished, and
|
| - # may emit status messages while we wait
|
| - wait = bool(self.getopt("wait", "try_wait", False))
|
| - if not wait:
|
| - # TODO: emit the URL where they can follow the builds. This
|
| - # requires contacting the Status server over PB and doing
|
| - # getURLForThing() on the BuildSetStatus. To get URLs for
|
| - # individual builds would require we wait for the builds to
|
| - # start.
|
| - print "not waiting for builds to finish"
|
| - return
|
| - d = self.running = defer.Deferred()
|
| - if self.buildsetStatus:
|
| - self._getStatus_1()
|
| - # contact the status port
|
| - # we're probably using the ssh style
|
| - master = self.getopt("master")
|
| - host, port = master.split(":")
|
| - port = int(port)
|
| - self.announce("contacting the status port at %s:%d" % (host, port))
|
| - f = pb.PBClientFactory()
|
| - creds = credentials.UsernamePassword("statusClient", "clientpw")
|
| - d = f.login(creds)
|
| - reactor.connectTCP(host, port, f)
|
| - d.addCallback(self._getStatus_ssh_1)
|
| - return self.running
|
| -
|
| - def _getStatus_ssh_1(self, remote):
|
| - # find a remotereference to the corresponding BuildSetStatus object
|
| - self.announce("waiting for job to be accepted")
|
| - g = BuildSetStatusGrabber(remote, self.bsid)
|
| - d = g.grab()
|
| - d.addCallback(self._getStatus_1)
|
| - return d
|
| -
|
| - def _getStatus_1(self, res=None):
|
| - if res:
|
| - self.buildsetStatus = res
|
| - # gather the set of BuildRequests
|
| - d = self.buildsetStatus.callRemote("getBuildRequests")
|
| - d.addCallback(self._getStatus_2)
|
| -
|
| - def _getStatus_2(self, brs):
|
| - self.builderNames = []
|
| - self.buildRequests = {}
|
| -
|
| - # self.builds holds the current BuildStatus object for each one
|
| - self.builds = {}
|
| -
|
| - # self.outstanding holds the list of builderNames which haven't
|
| - # finished yet
|
| - self.outstanding = []
|
| -
|
| - # self.results holds the list of build results. It holds a tuple of
|
| - # (result, text)
|
| - self.results = {}
|
| -
|
| - # self.currentStep holds the name of the Step that each build is
|
| - # currently running
|
| - self.currentStep = {}
|
| -
|
| - # self.ETA holds the expected finishing time (absolute time since
|
| - # epoch)
|
| - self.ETA = {}
|
| -
|
| - for n,br in brs:
|
| - self.builderNames.append(n)
|
| - self.buildRequests[n] = br
|
| - self.builds[n] = None
|
| - self.outstanding.append(n)
|
| - self.results[n] = [None,None]
|
| - self.currentStep[n] = None
|
| - self.ETA[n] = None
|
| - # get new Builds for this buildrequest. We follow each one until
|
| - # it finishes or is interrupted.
|
| - br.callRemote("subscribe", self)
|
| -
|
| - # now that those queries are in transit, we can start the
|
| - # display-status-every-30-seconds loop
|
| - self.printloop = task.LoopingCall(self.printStatus)
|
| - self.printloop.start(3, now=False)
|
| -
|
| -
|
| - # these methods are invoked by the status objects we've subscribed to
|
| -
|
| - def remote_newbuild(self, bs, builderName):
|
| - if self.builds[builderName]:
|
| - self.builds[builderName].callRemote("unsubscribe", self)
|
| - self.builds[builderName] = bs
|
| - bs.callRemote("subscribe", self, 20)
|
| - d = bs.callRemote("waitUntilFinished")
|
| - d.addCallback(self._build_finished, builderName)
|
| -
|
| - def remote_stepStarted(self, buildername, build, stepname, step):
|
| - self.currentStep[buildername] = stepname
|
| -
|
| - def remote_stepFinished(self, buildername, build, stepname, step, results):
|
| - pass
|
| -
|
| - def remote_buildETAUpdate(self, buildername, build, eta):
|
| - self.ETA[buildername] = now() + eta
|
| -
|
| - def _build_finished(self, bs, builderName):
|
| - # we need to collect status from the newly-finished build. We don't
|
| - # remove the build from self.outstanding until we've collected
|
| - # everything we want.
|
| - self.builds[builderName] = None
|
| - self.ETA[builderName] = None
|
| - self.currentStep[builderName] = "finished"
|
| - d = bs.callRemote("getResults")
|
| - d.addCallback(self._build_finished_2, bs, builderName)
|
| - return d
|
| - def _build_finished_2(self, results, bs, builderName):
|
| - self.results[builderName][0] = results
|
| - d = bs.callRemote("getText")
|
| - d.addCallback(self._build_finished_3, builderName)
|
| - return d
|
| - def _build_finished_3(self, text, builderName):
|
| - self.results[builderName][1] = text
|
| -
|
| - self.outstanding.remove(builderName)
|
| - if not self.outstanding:
|
| - # all done
|
| - return self.statusDone()
|
| -
|
| - def printStatus(self):
|
| - names = self.buildRequests.keys()
|
| - names.sort()
|
| - for n in names:
|
| - if n not in self.outstanding:
|
| - # the build is finished, and we have results
|
| - code,text = self.results[n]
|
| - t = builder.Results[code]
|
| - if text:
|
| - t += " (%s)" % " ".join(text)
|
| - elif self.builds[n]:
|
| - t = self.currentStep[n] or "building"
|
| - if self.ETA[n]:
|
| - t += " [ETA %ds]" % (self.ETA[n] - now())
|
| - else:
|
| - t = "no build"
|
| - self.announce("%s: %s" % (n, t))
|
| - self.announce("")
|
| -
|
| - def statusDone(self):
|
| - self.printloop.stop()
|
| - print "All Builds Complete"
|
| - # TODO: include a URL for all failing builds
|
| - names = self.buildRequests.keys()
|
| - names.sort()
|
| - happy = True
|
| - for n in names:
|
| - code,text = self.results[n]
|
| - t = "%s: %s" % (n, builder.Results[code])
|
| - if text:
|
| - t += " (%s)" % " ".join(text)
|
| - print t
|
| - if self.results[n] != builder.SUCCESS:
|
| - happy = False
|
| -
|
| - if happy:
|
| - self.exitcode = 0
|
| - else:
|
| - self.exitcode = 1
|
| - self.running.callback(self.exitcode)
|
| -
|
| - def announce(self, message):
|
| - if not self.quiet:
|
| - print message
|
| -
|
| - def run(self):
|
| - # we can't do spawnProcess until we're inside reactor.run(), so get
|
| - # funky
|
| - print "using '%s' connect method" % self.connect
|
| - self.exitcode = 0
|
| - d = defer.Deferred()
|
| - d.addCallback(lambda res: self.createJob())
|
| - d.addCallback(lambda res: self.announce("job created"))
|
| - deliver = self.deliverJob
|
| - if bool(self.config.get("dryrun")):
|
| - deliver = self.fakeDeliverJob
|
| - d.addCallback(lambda res: deliver())
|
| - d.addCallback(lambda res: self.announce("job has been delivered"))
|
| - d.addCallback(lambda res: self.getStatus())
|
| - d.addErrback(log.err)
|
| - d.addCallback(self.cleanup)
|
| - d.addCallback(lambda res: reactor.stop())
|
| -
|
| - reactor.callLater(0, d.callback, None)
|
| - reactor.run()
|
| - sys.exit(self.exitcode)
|
| -
|
| - def logErr(self, why):
|
| - log.err(why)
|
| - print "error during 'try' processing"
|
| - print why
|
| -
|
| - def cleanup(self, res=None):
|
| - if self.buildsetStatus:
|
| - self.buildsetStatus.broker.transport.loseConnection()
|
| -
|
| -
|
| -
|
|
|