[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