[Buildbot-commits] buildbot/buildbot/scripts runner.py,1.31,1.32 tryclient.py,1.2,1.3

Brian Warner warner at users.sourceforge.net
Thu Aug 11 08:22:19 UTC 2005


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

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

make 'try' actually work, mostly

	* docs/buildbot.texinfo (try): add --port argument to PB style

	* buildbot/scripts/tryclient.py (SourceStampExtractor): return an
	actual SourceStamp. Still need to extract a branch name, somehow.
	(Try): finish implementing the try client side, still need a UI
	for specifying which builders to use
	(Try.getopt): factor our options/config-file reading
	* buildbot/test/test_scheduler.py (Scheduling.testTryUserpass):
	test it
	* buildbot/test/test_vc.py: match SourceStampExtractor change

	* buildbot/scripts/runner.py (Options.opt_verbose): --verbose
	causes the twisted log to be sent to stderr

	* buildbot/scheduler.py (Try_Userpass): implement the PB style

--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: runner.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/runner.py,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- runner.py	10 Aug 2005 08:15:44 -0000	1.31
+++ runner.py	11 Aug 2005 08:22:16 -0000	1.32
@@ -571,9 +571,9 @@
          "the directory (on the tryhost) where tryjobs are deposited"],
         ["username", "u", None, "Username performing the trial build"],
         # for PB, use --master, --username, and --passwd
-        ["passwd", None, None, "password for PB authentication"],
         ["master", "m", None,
          "Location of the buildmaster's PBListener (host:port)"],
+        ["passwd", None, None, "password for PB authentication"],
         
         ["vc", None, None,
          "The VC system in use, one of: cvs,svn,tla,baz,darcs"],
@@ -588,7 +588,8 @@
 
 def doTry(config):
     from buildbot.scripts import tryclient
-    tryclient.doTry(config)
+    t = tryclient.Try(config)
+    t.run()
 
 class TryServerOptions(usage.Options):
     optParameters = [
@@ -599,8 +600,8 @@
     jobdir = os.path.expanduser(config["jobdir"])
     job = sys.stdin.read()
     # now do a 'safecat'-style write to jobdir/tmp, then move atomically to
-    # jobdir/new . I'm just going to MD5 the contents and prepend a
-    # timestamp.
+    # jobdir/new . Rather than come up with a unique name randomly, I'm just
+    # going to MD5 the contents and prepend a timestamp.
     timestring = "%d" % time.time()
     jobhash = md5.new(job).hexdigest()
     fn = "%s-%s" % (timestring, jobhash)
@@ -650,6 +651,10 @@
         print "Buildbot version: %s" % buildbot.version
         usage.Options.opt_version(self)
 
+    def opt_verbose(self):
+        from twisted.python import log
+        log.startLogging(sys.stderr)
+
     def postOptions(self):
         if not hasattr(self, 'subOptions'):
             raise usage.UsageError("must specify a command")

Index: tryclient.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/scripts/tryclient.py,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- tryclient.py	10 Aug 2005 08:15:44 -0000	1.2
+++ tryclient.py	11 Aug 2005 08:22:16 -0000	1.3
@@ -1,17 +1,23 @@
 # -*- test-case-name: buildbot.test.test_scheduler,buildbot.test.test_vc -*-
 
 import os, re
-from twisted.internet import utils, protocol, defer
+from twisted.internet import utils, protocol, defer, reactor
+from twisted.spread import pb
+from twisted.cred import credentials
+from twisted.python import log
 
+from buildbot.sourcestamp import SourceStamp
 from buildbot.scripts import runner
 
 class SourceStampExtractor:
+    branch = None
     def __init__(self, treetop):
         self.treetop = treetop
     def do(self, cmd):
         return utils.getProcessOutput(cmd[0], cmd[1:], env=os.environ,
                                       path=self.treetop)
     def get(self):
+        """Return a Deferred that fires with a SourceStamp instance."""
         d = self.getBaseRevision()
         d.addCallback(self.getPatch)
         d.addCallback(self.done)
@@ -19,7 +25,9 @@
     def readPatch(self, res, patchlevel):
         self.patch = (patchlevel, res)
     def done(self, res):
-        return (self.baserev, self.patch)
+        # TODO: figure out the branch too
+        ss = SourceStamp(self.branch, self.baserev, self.patch)
+        return ss
 
 class SVNExtractor(SourceStampExtractor):
     patchlevel = 0
@@ -115,7 +123,7 @@
 def ns(s):
     return "%d:%s," % (len(s), s)
 
-def createJob(bsid, branch, baserev, patchlevel, diff, builderNames):
+def createJobfile(bsid, branch, baserev, patchlevel, diff, builderNames):
     job = ""
     job += ns("1")
     job += ns(bsid)
@@ -147,54 +155,139 @@
         self.d.callback((sig, rc))
 
 class Try:
-    def run(self, config):
-        opts = runner.loadOptions()
+    buildsetStatus = None
+    quiet = False
+
+    def __init__(self, config):
+        self.config = config
+        self.opts = runner.loadOptions()
+        self.connect = self.getopt('connect', 'try_connect')
+        print "using '%s' connect method" % self.connect
+        self.builderNames = ["a", "b"] # TODO: add UI for this
+
+    def getopt(self, config_name, options_name, default=None):
+        value = self.config.get(config_name)
+        if value is None:
+            value = self.opts.get(options_name)
+        if value is None:
+            value = default
+        assert value is not None
+        return value
+
+    def createJob(self):
+        # returns a Deferred which fires when the job parameters have been
+        # created
+        config = self.config
+        opts = self.opts
+        self.bsid = "buildsetID" # TODO: generate a random (unique) string
+
         # common options
-        vc = config.get("vc", opts.get("try_vc"))
+        vc = self.getopt("vc", "try_vc")
 
         if vc in ("cvs", "svn"):
             # we need to find the tree-top
-            topdir = config.get("try_topdir", opts.get("try_topdir"))
+            topdir = self.getopt("try_topdir", "try_topdir")
             if topdir:
                 treedir = os.path.expanduser(topdir)
             else:
-                topfile = config.get("try-topfile", opts.get("try_topfile"))
+                topfile = self.getopt("try-topfile", "try_topfile")
                 treedir = getTopdir(topfile)
         else:
             treedir = os.getcwd()
-        ss = getSourceStamp(vc, treedir)
-        builderNames = [] # TODO??
-
-        wait = bool(config.get("wait", opts.get("try_wait")))
-        bsid = "buildsetID" # TODO: generate a random (unique) string
+        d = getSourceStamp(vc, treedir)
+        d.addCallback(self._createJob_1)
+        return d
+    def _createJob_1(self, ss):
+        self.sourcestamp = ss
+        if self.connect == "ssh":
+            patchlevel, diff = ss.patch
+            self.jobfile = createJobfile(bsid, ss.branch or "", ss.revision,
+                                         patchlevel, diff,
+                                         self.builderNames)
 
+    def deliverJob(self):
+        # returns a Deferred that fires when the job has been delivered
+        config = self.config
+        opts = self.opts
 
-        connect = config.get('connect', opts.get('try_connect'))
-        if connect == "ssh":
-            tryhost = config.get("tryhost", opts.get("try_host"))
-            tryuser = config.get("username", opts.get("try_username"))
-            trydir = config.get("trydir", opts.get("try_dir"))
+        if self.connect == "ssh":
+            tryhost = self.getopt("tryhost", "try_host")
+            tryuser = self.getopt("username", "try_username")
+            trydir = self.getopt("trydir", "try_dir")
 
-            patchlevel, diff = ss.patch
-            job = createJob(bsid, ss.branch or "", ss.revision, patchlevel, diff,
-                            builderNames)
             argv = ["ssh", "-l", tryuser, tryhost,
                     "buildbot", "tryserver", trydir]
             # now run this command and feed the contents of 'job' into stdin
 
-            pp = RemoteTryPP(job)
+            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", "try_username")
+            passwd = self.getopt("passwd", "try_password")
+            master = self.getopt("master", "try_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 done(self, res):
-        reactor.stop()
+    def _deliverJob_pb(self, remote):
+        ss = self.sourcestamp
+        d = remote.callRemote("try",
+                              ss.branch, ss.revision, ss.patch,
+                              self.builderNames)
+        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 self.buildsetStatus:
+            # contact the status port, acquire a remotereference to the
+            # corresponding BuildSetStatus object.
+            pass
+        pass
+
+    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
+        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()
+
+    def logErr(self, why):
+        log.err(why)
+        print "error during 'try' processing"
+        print why
+
+    def cleanup(self, res=None):
+        print "cleaning up"
+        if self.buildsetStatus:
+            self.buildsetStatus.broker.transport.loseConnection()
 
-def doTry(config):
-    t = Try()
-    d = t.run(config)
-    d.addBoth(t.done)
-    reactor.run()
 
     





More information about the Commits mailing list