[Buildbot-commits] buildbot/buildbot/status client.py,1.19,1.20 builder.py,1.60,1.61 mail.py,1.17,1.18 words.py,1.37,1.38 html.py,1.64,1.65

Brian Warner warner at users.sourceforge.net
Tue Jul 19 23:12:03 UTC 2005


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

Modified Files:
	client.py builder.py mail.py words.py html.py 
Log Message:
Revision: arch at buildbot.sf.net--2004/buildbot--dev--0--patch-239
Creator:  Brian Warner <warner at monolith.lothar.com>

merge in build-on-branch code: Merged from warner at monolith.lothar.com--2005 (patch 0-18, 40-41)

Patches applied:

 * warner at monolith.lothar.com--2005/buildbot--dev--0--patch-40
   Merged from arch at buildbot.sf.net--2004 (patch 232-238)

 * warner at monolith.lothar.com--2005/buildbot--dev--0--patch-41
   Merged from local-usebranches (warner at monolith.lothar.com--2005/buildbot--usebranches--0( (patch 0-18)

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--base-0
   tag of warner at monolith.lothar.com--2005/buildbot--dev--0--patch-38

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-1
   rearrange build scheduling

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-2
   replace ugly 4-tuple with a distinct SourceStamp class

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-3
   document upcoming features, clean up CVS branch= argument

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-4
   Merged from arch at buildbot.sf.net--2004 (patch 227-231), warner at monolith.lothar.com--2005 (patch 39)

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-5
   implement per-Step Locks, add tests (which all fail)

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-6
   implement scheduler.Dependent, add (failing) tests

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-7
   make test_dependencies work

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-8
   finish making Locks work, tests now pass

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-9
   fix test failures when run against twisted >2.0.1

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-10
   rename test_interlock.py to test_locks.py

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-11
   add more Locks tests, add branch examples to manual

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-12
   rewrite test_vc.py, create repositories in setUp rather than offline

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-13
   make new tests work with twisted-1.3.0

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-14
   implement/test build-on-branch for most VC systems

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-15
   minor changes: test-case-name tags, init cleanup

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-16
   Merged from arch at buildbot.sf.net--2004 (patch 232-233)

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-17
   Merged from arch at buildbot.sf.net--2004 (patch 234-236)

 * warner at monolith.lothar.com--2005/buildbot--usebranches--0--patch-18
   Merged from arch at buildbot.sf.net--2004 (patch 237-238), warner at monolith.lothar.com--2005 (patch 40)


Index: builder.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/builder.py,v
retrieving revision 1.60
retrieving revision 1.61
diff -u -d -r1.60 -r1.61
--- builder.py	19 Jul 2005 19:49:36 -0000	1.60
+++ builder.py	19 Jul 2005 23:12:01 -0000	1.61
@@ -14,7 +14,7 @@
     import pickle
 
 # sibling imports
-from buildbot import interfaces, util
+from buildbot import interfaces, util, sourcestamp
 from buildbot.twcompat import implements
 
 SUCCESS, WARNINGS, FAILURE, SKIPPED, EXCEPTION = range(5)
@@ -180,14 +180,7 @@
     which new entries can easily be appended. The file on disk has a name
     like 12-log-compile-output, under the Builder's directory. The actual
     filename is generated (before the LogFile is created) by
-    L{Builder.generateLogfileName}.
-
-    @type  parent: L{BuildStepStatus}
-    @param parent: the Step that this log is a part of
-    @type  name: string
-    @param name: the name of this log, typically 'output'
-    @type  logfilename: string
-    @param logfilename: the Builder-relative pathname for the saved entries
+    L{BuildStatus.generateLogfileName}.
 
     Old LogFile pickles (which kept their contents in .entries) must be
     upgraded. The L{BuilderStatus} is responsible for doing this, when it
@@ -212,6 +205,14 @@
     openfile = None
 
     def __init__(self, parent, name, logfilename):
+        """
+        @type  parent: L{BuildStepStatus}
+        @param parent: the Step that this log is a part of
+        @type  name: string
+        @param name: the name of this log, typically 'output'
+        @type  logfilename: string
+        @param logfilename: the Builder-relative pathname for the saved entries
+        """
         self.step = parent
         self.name = name
         self.filename = logfilename
@@ -535,6 +536,31 @@
         return self.logs
 
 
+class BuildSetStatus:
+    if implements:
+        implements(interfaces.IBuildSetStatus)
+    else:
+        __implements__ = interfaces.IBuildSetStatus,
+
+    def __init__(self):
+        # TODO
+        pass
+
+    def setSourceStamp(self, sourceStamp):
+        self.source = sourceStamp
+    def setReason(self, reason):
+        self.reason = reason
+    def setResults(self, results):
+        self.results = results
+
+    def getSourceStamp(self):
+        return self.source
+    def getReason(self):
+        return self.reason
+    def getResults(self):
+        return self.results
+
+
 class BuildStepStatus:
     """
     I represent a collection of output status for a
@@ -779,7 +805,7 @@
     else:
         __implements__ = interfaces.IBuildStatus, interfaces.IStatusEvent
 
-    sourceStamp = None
+    source = None
     reason = None
     changes = []
     blamelist = []
@@ -830,7 +856,7 @@
         return self.builder.getBuild(self.number-1)
 
     def getSourceStamp(self):
-        return self.sourceStamp
+        return (self.source.branch, self.source.revision, self.source.patch)
 
     def getReason(self):
         return self.reason
@@ -955,12 +981,12 @@
     def addTestResult(self, result):
         self.testResults[result.getName()] = result
 
-    def setSourceStamp(self, revision, patch=None):
-        self.sourceStamp = (revision, patch)
+    def setSourceStamp(self, sourceStamp):
+        self.source = sourceStamp
+        self.changes = self.source.changes
+
     def setReason(self, reason):
         self.reason = reason
-    def setChanges(self, changes):
-        self.changes = changes
     def setBlamelist(self, blamelist):
         self.blamelist = blamelist
     def setProgress(self, progress):
@@ -1081,6 +1107,16 @@
         self.watchers = []
         self.updates = {}
         self.finishedWatchers = []
+        if d.has_key('sourceStamp'):
+            revision, patch = d['sourceStamp']
+            changes = d.get('changes', [])
+            source = sourcestamp.SourceStamp(branch=None,
+                                             revision=revision,
+                                             patch=patch,
+                                             changes=changes)
+            self.source = source
+            self.changes = source.changes
+            del self.sourceStamp
 
     def upgradeLogfiles(self):
         # upgrade any LogFiles that need it. This must occur after we've been
@@ -1155,7 +1191,6 @@
     category = None
     currentBuild = None
     currentBigState = "offline" # or idle/waiting/interlocked/building
-    ETA = None
     nextBuildNumber = 0
     basedir = None # filled in by our parent
 
@@ -1170,7 +1205,6 @@
         #self.currentBig = None
         #self.currentSmall = None
         self.nextBuild = None
-        self.eta = None
         self.watchers = []
         self.buildCache = [] # TODO: age builds out of the cache
 
@@ -1252,21 +1286,12 @@
         for b in self.builds[0:-self.stepHorizon]:
             b.pruneSteps()
 
-    def getETA(self):
-        eta = self.ETA # absolute time, set by currentlyWaiting
-        state = self.currentBigState
-        if state == "waiting":
-            eta = self.ETA - util.now()
-        elif state == "building":
-            eta = self.currentBuild.getETA()
-        return eta
-
     # IBuilderStatus methods
     def getName(self):
         return self.name
 
     def getState(self):
-        return (self.currentBigState, self.getETA(), self.currentBuild)
+        return (self.currentBigState, self.currentBuild)
 
     def getSlave(self):
         return self.status.getSlave(self.slavename)
@@ -1361,62 +1386,21 @@
         self.events.append(e)
         return e # for consistency, but they really shouldn't touch it
 
-    def currentlyOffline(self):
-        log.msg("currentlyOffline")
-        self.currentBigState = "offline"
-        self.publishState()
-
-    def currentlyIdle(self):
-        self.currentBigState = "idle"
-        self.ETA = None
-        self.currentBuild = None
-        self.publishState()
-
-    def currentlyWaiting(self, when):
-        self.currentBigState = "waiting"
-        self.ETA = when
-        self.currentBuild = None
-        self.publishState()
-
-    def currentlyInterlocked(self, interlocks):
-        self.currentBigState = "interlocked"
-        self.ETA = None
-        self.currentBuild = None
-        #names = [interlock.name for interlock in interlocks]
-        #self.currentBig = Event(color="yellow",
-        #                        text=["interlocked"] + names)
-        self.publishState()
-
-    def buildETAText(self, text):
-        # UNUSED, should live in the clients
-        if self.eta:
-            done = self.eta.eta()
-            if done != None:
-                text += [time.strftime("ETA: %H:%M:%S", time.localtime(done)),
-                         "[%d seconds]" % (done - util.now())]
-            else:
-                text += ["ETA: ?"]
-        
-    def NOTcurrentlyBuilding(self, build, eta):
-        # eta is a progress.BuildProgress object
-        self.currentBigState = "building"
-        self.currentBuild = build
-        if eta:
-            self.ETA = eta.eta()
-        else:
-            self.ETA = None
-        self.publishState()
+    def setBigState(self, state):
+        needToUpdate = state != self.currentBuild
+        self.currentBigState = state
+        if needToUpdate:
+            self.publishState()
 
     def publishState(self, target=None):
         state = self.currentBigState
-        eta = self.getETA()
 
         if target is not None:
             # unicast
-            target.builderChangedState(self.name, state, eta)
+            target.builderChangedState(self.name, state)
             return
         for w in self.watchers:
-            w.builderChangedState(self.name, state, eta)
+            w.builderChangedState(self.name, state)
 
     def newBuild(self):
         """The Builder has decided to start a build, but the Build object is
@@ -1424,6 +1408,8 @@
         Steps). Create a BuildStatus object that it can use."""
         number = self.nextBuildNumber
         self.nextBuildNumber += 1
+        # TODO: self.saveYourself(), to make sure we don't forget about the
+        # build number we've just allocated
         s = BuildStatus(self, number)
         s.waitUntilFinished().addCallback(self._buildFinished)
         return s
@@ -1436,9 +1422,7 @@
         assert s.builder is self # paranoia
         assert s.number == self.nextBuildNumber - 1
         self.currentBuild = s
-        self.currentBigState = "building"
         self.addBuildToCache(self.currentBuild)
-        self.publishState()
 
         # now that the BuildStatus is prepared to answer queries, we can
         # announce the new build to all our watchers
@@ -1453,8 +1437,6 @@
 
     def _buildFinished(self, s):
         assert s is self.currentBuild
-        self.currentBigState = "idle"
-        self.ETA = None
         self.currentBuild.saveYourself()
         self.currentBuild = None
 
@@ -1467,13 +1449,6 @@
 
 
     # waterfall display (history)
-    
-    # top-row: last-build status 
-    def setLastBuildStatus(self, event):
-        log.msg("setLastBuildStatus", event)
-        self.lastBuildStatus = event
-        for w in self.watchers:
-            self.sendLastBuildStatus(w)
 
     # I want some kind of build event that holds everything about the build:
     # why, what changes went into it, the results of the build, itemized
@@ -1497,67 +1472,13 @@
             client.currentlyOffline()
         elif state == "idle":
             client.currentlyIdle()
-        elif state == "waiting":
-            client.currentlyWaiting(self.nextBuild - util.now())
-        elif state == "interlocked":
-            client.currentlyInterlocked()
         elif state == "building":
-            client.currentlyBuilding(self.eta)
-            # let them format the time as they wish
+            client.currentlyBuilding()
         else:
             log.msg("Hey, self.currentBigState is weird:", state)
             
-
-    # current-activity-small
-    def OFFsetCurrentActivity(self, event):
-        self.pushEvent(event)
-        self.currentSmall = event
-        for s in self.subscribers:
-            s.newEvent(event)
-
-    def OFFpushEvent(self, event):
-        if self.events:
-            next = self.events[-1].number + 1
-        else:
-            next = 0
-        event.setName(self, next)
-        self.events.append(event)
-        self.pruneEvents()
-
-
-    def OFFupdateCurrentActivity(self, **kwargs):
-        self.currentSmall.update(**kwargs)
-    def OFFaddFileToCurrentActivity(self, name, logfile):
-        self.currentSmall.addFile(name, logfile)
-    def OFFfinishCurrentActivity(self):
-        self.currentSmall.finish()
-
-    def setCurrentBuild(self):
-        pass
-    def finishCurrentBuild(self):
-        pass
     
     ## HTML display interface
-    def getLastBuildStatus(self):
-        return self.lastBuildStatus
-    def getCurrentBig(self):
-        state = self.currentBigState
-        if state == "waiting":
-            when = self.nextBuild
-            return Event(color="yellow",
-                         text=["waiting", "next build",
-                               time.strftime("%H:%M:%S",
-                                             time.localtime(when)),
-                               "[%d seconds]" % (when - util.now())
-                               ])
-        elif state == "building":
-            text = ["building"]
-            self.buildETAText(text)
-            return Event(color="yellow", text=text)
-        else:
-            return self.currentBig
-    def getCurrentSmall(self):
-        return self.currentSmall
 
     def getEventNumbered(self, num):
         # deal with dropped events, pruned events
@@ -1722,7 +1643,7 @@
 
         if not os.path.isdir(builder_status.basedir):
             os.mkdir(builder_status.basedir)
-        builder_status.currentlyOffline()
+        builder_status.setBigState("offline")
 
         for t in self.watchers:
             self.announceNewBuilder(t, name, builder_status)

Index: client.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/client.py,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- client.py	18 May 2005 00:50:51 -0000	1.19
+++ client.py	19 Jul 2005 23:12:01 -0000	1.20
@@ -30,8 +30,8 @@
         return self.b.getName()
 
     def remote_getState(self):
-        state, ETA, build = self.b.getState()
-        return (state, ETA, makeRemote(build))
+        state, build = self.b.getState()
+        return (state, None, makeRemote(build)) # TODO: remove leftover ETA
 
     def remote_getSlave(self):
         return IRemote(self.b.getSlave())
@@ -308,8 +308,9 @@
             return self
         return None
 
-    def builderChangedState(self, name, state, eta):
-        self.client.callRemote("builderChangedState", name, state, eta)
+    def builderChangedState(self, name, state):
+        self.client.callRemote("builderChangedState", name, state, None)
+        # TODO: remove leftover ETA argument
 
     def builderRemoved(self, name):
         if name in self.subscribed_to_builders:

Index: html.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/html.py,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -d -r1.64 -r1.65
--- html.py	17 May 2005 10:14:09 -0000	1.64
+++ html.py	19 Jul 2005 23:12:01 -0000	1.65
@@ -677,24 +677,16 @@
         return time.strftime("%H:%M:%S", time.localtime(util.now()+eta))
 
     def getBox(self):
-        state, ETA, build = self.original.getState()
+        state, build = self.original.getState()
         color = "white"
-        if state in ("waiting", "interlocked", "building"):
+        if state == "building":
             color = "yellow"
         text = [state]
         if state == "offline":
             color = "red"
-        if state == "waiting":
-            if ETA is not None:
-                text.extend(["next build",
-                             self.formatETA(ETA),
-                             "[%d seconds]" % ETA])
         if state == "building":
-            if ETA is not None:
-                text.extend(["ETA: %s" % self.formatETA(ETA),
-                             "[%d seconds]" % ETA])
-            else:
-                text.extend(["ETA: ?"])
+            # TODO: ETA calculation
+            pass
 
         return Box(text, color=color, class_="Activity " + state)
 components.registerAdapter(CurrentBox, builder.BuilderStatus, ICurrentBox)
@@ -988,7 +980,7 @@
         for b in builders:
             text = ""
             color = "#ca88f7"
-            state, ETA, build = b.getState()
+            state, build = b.getState()
             if state != "offline":
                 text += "%s<br />\n" % state #b.getCurrentBig().text[0]
             else:
@@ -1473,9 +1465,9 @@
                         will be used for the 'favicon.ico' resource. Many
                         browsers automatically request this file and use it
                         as an icon in any bookmark generated from this site.
-                        Defaults to the L{buildbot.png} image provided in the
-                        distribution. Can be set to None to avoid using
-                        a favicon at all.
+                        Defaults to the L{buildbot/buildbot.png} image
+                        provided in the distribution. Can be set to None to
+                        avoid using a favicon at all.
                         
         """
         base.StatusReceiverMultiService.__init__(self)

Index: mail.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/mail.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- mail.py	18 May 2005 00:29:43 -0000	1.17
+++ mail.py	19 Jul 2005 23:12:01 -0000	1.18
@@ -243,11 +243,16 @@
         if ss is None:
             source = "unavailable"
         else:
-            revision, patch = ss
-            if patch is None:
-                source = revision
+            branch, revision, patch = ss
+            source = ""
+            if branch:
+                source += "[branch %s] "
+            if revision:
+                source += revision
             else:
-                source = "%s (plus patch)" % revision
+                source += "HEAD"
+            if patch is not None:
+                source += " (plus patch)"
         text += "Build Source Stamp: %s\n" % source
 
         text += "Blamelist: %s\n" % ",".join(build.getResponsibleUsers())

Index: words.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/status/words.py,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- words.py	18 May 2005 01:03:49 -0000	1.37
+++ words.py	19 Jul 2005 23:12:01 -0000	1.38
@@ -24,6 +24,38 @@
     def __init__(self, string = "Invalid usage", *more):
         ValueError.__init__(self, string, *more)
 
+class IrcBuildRequest:
+    hasStarted = False
+    timer = None
+
+    def __init__(self, parent, reply):
+        self.parent = parent
+        self.reply = reply
+        self.timer = reactor.callLater(5, self.soon)
+
+    def soon(self):
+        del self.timer
+        if not self.hasStarted:
+            self.parent.reply(self.reply,
+                              "The build has been queued, I'll give a shout"
+                              " when it starts")
+
+    def started(self, c):
+        self.hasStarted = True
+        if self.timer:
+            self.timer.cancel()
+            del self.timer
+        s = c.getStatus()
+        eta = s.getETA()
+        response = "build #%d forced" % s.getNumber()
+        if eta is not None:
+            response = "build forced [ETA %s]" % self.parent.convertTime(eta)
+        self.parent.reply(reply, response)
+        self.parent.reply(reply, "I'll give a shout when the build finishes")
+        d = s.waitUntilFinished()
+        d.addCallback(self.parent.buildFinished, reply)
+
+
 class IrcStatusBot(irc.IRCClient):
     silly = {
         "What happen ?": "Somebody set up us the bomb.",
@@ -266,7 +298,9 @@
         # 'reply' argument.
         r = "forced: by IRC user <%s>: %s" % (user, reason)
         try:
-            c = bc.forceBuild(who, r)
+            # TODO: replace this with bc.requestBuild, and maybe give certain
+            # users the ability to request builds of certain branches
+            d = bc.forceBuild(who, r)
         except interfaces.NoSlaveError:
             self.reply(reply,
                        "sorry, I can't force a build: the slave is offline")
@@ -275,19 +309,14 @@
             self.reply(reply,
                        "sorry, I can't force a build: the slave is in use")
             return
-        if not c:
+        if not d:
             self.reply(reply, "sorry, I can't force a build: I must have "
                        "left the builder in my other pants")
             return
-        s = c.getStatus()
-        eta = s.getETA()
-        response = "build #%d forced" % s.getNumber()
-        if eta is not None:
-            response = "build forced [ETA %s]" % self.convertTime(eta)
-        self.reply(reply, response)
-        self.reply(reply, "I'll give a shout when the build finishes")
-        d = s.waitUntilFinished()
-        d.addCallback(self.buildFinished, reply)
+
+        req = IrcBuildRequest(self, reply)
+        d.addCallback(req.started)
+
     command_FORCE.usage = "force build <which> <reason> - Force a build"
 
     def command_STOP(self, user, reply, args):





More information about the Commits mailing list