[Buildbot-commits] buildbot/buildbot/scripts tryclient.py,1.6,1.7

Brian Warner warner at users.sourceforge.net
Thu Aug 18 08:30:04 UTC 2005


Update of /cvsroot/buildbot/buildbot/buildbot/scripts
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21002/buildbot/scripts

Modified Files:
	tryclient.py 
Log Message:
Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-297
Creator:  Brian Warner <warner at lothar.com>

make 'try' status reporting actually work

	* buildbot/scripts/tryclient.py (Try): make 'try' status reporting
	actually work. It's functional but still kind of clunky. Also, it
	only works with the pb-style.. needs to be made to work with the
	jobdir-style too.

	* buildbot/status/client.py (RemoteBuildSet): new class
	(RemoteBuildRequest): same
	(RemoteBuild.remote_waitUntilFinished): return the RemoteBuild
	object, not the internal BuildStatus object.
	(RemoteBuild.remote_subscribe): new method to subscribe to builds
	outside of the usual buildStarted() return value.
	(BuildSubscriber): support class for RemoteBuild.remote_subscribe

	* buildbot/scheduler.py (Try_Jobdir): convey buildsetID properly
	(Try_Userpass_Perspective.perspective_try): return a remotely
	usable BuildSetStatus object

	* buildbot/interfaces.py (IBuildStatus): remove obsolete
	isStarted()/waitUntilStarted()

--This line, and those below, will be ignored--
Files to commit:
   <can't compute list>

This list might be incomplete or outdated if editing the log
message was not invoked from an up-to-date changes buffer!


Index: tryclient.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- tryclient.py	16 Aug 2005 00:23:52 -0000	1.6
+++ tryclient.py	18 Aug 2005 08:30:01 -0000	1.7
@@ -1,7 +1,7 @@
 # -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*-
 
-import os, re, time
-from twisted.internet import utils, protocol, defer, reactor
+import sys, os, re, time
+from twisted.internet import utils, protocol, defer, reactor, task
 from twisted.spread import pb
 from twisted.cred import credentials
 from twisted.python import log
@@ -9,6 +9,7 @@
 from buildbot.sourcestamp import SourceStamp
 from buildbot.scripts import runner
 from buildbot.util import now
+from buildbot.status import builder
 
 class SourceStampExtractor:
 
@@ -191,7 +192,7 @@
         rc = status_object.value.exitCode
         self.d.callback((sig, rc))
 
-class Try:
+class Try(pb.Referenceable):
     buildsetStatus = None
     quiet = False
 
@@ -291,12 +292,147 @@
         # 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 self.buildsetStatus:
-            # contact the status port, acquire a remotereference to the
-            # corresponding BuildSetStatus object.
-            pass
+        if not wait:
+            # TODO: emit the URL where they can follow the builds
+            return
+        d = self.running = defer.Deferred()
+        if self.buildsetStatus:
+            self._getStatus_1()
+        # TODO: contact the status port, acquire a remotereference to the
+        # corresponding BuildSetStatus object.
+        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
@@ -305,19 +441,20 @@
         # 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"))
         d.addCallback(lambda res: self.deliverJob())
         d.addCallback(lambda res: self.announce("job has been delivered"))
         d.addCallback(lambda res: self.getStatus())
-        d.addCallback(lambda res: self.announce("status object acquired"))
         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)
@@ -325,7 +462,6 @@
         print why
 
     def cleanup(self, res=None):
-        print "cleaning up"
         if self.buildsetStatus:
             self.buildsetStatus.broker.transport.loseConnection()
 





More information about the Commits mailing list