|
# This file is part of Buildbot. Buildbot is free software: you can # redistribute it and/or modify it under the terms of the GNU General Public # License as published by the Free Software Foundation, version 2. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # Copyright Buildbot Team Members
pass
# we want IRemote(None) to be None, but you can't really do that with # adapters, so we fake it return None
return self.b.getSourceStamp()
return self.b.getReason()
return self.b.getID()
return self.b.getBuilderNames() # note: passes along the Deferred
"""Returns a list of (builderName, BuildRequest) tuples.""" d = self.b.getBuilderNamesAndBuildRequests() def add_remote(buildrequests): for k,v in buildrequests.iteritems(): buildrequests[k] = IRemote(v) return buildrequests.items() d.addCallback(add_remote) return d
return self.b.isFinished()
d = self.b.waitUntilFinished() d.addCallback(lambda res: self) return d
return self.b.getResults()
interfaces.IBuildSetStatus, IRemote)
self.b = builder
return self.b.getName()
return self.b.getCategory()
state, builds = self.b.getState() return (state, None, # TODO: remove leftover ETA [makeRemote(b) for b in builds])
return [IRemote(s) for s in self.b.getSlaves()]
return makeRemote(self.b.getLastFinishedBuild())
return [IRemote(b) for b in self.b.getCurrentBuilds()]
return makeRemote(self.b.getBuild(number))
return IRemote(self.b.getEvent(number))
interfaces.IBuilderStatus, IRemote)
self.b = buildreq # mapping of observers (RemoteReference instances) to local callable # objects that have been passed to BuildRequestStatus.subscribe self.observers = []
# note that this now returns a Deferred return self.b.getSourceStamp()
return self.b.getBuilderName()
"""The observer's remote_newbuild method will be called (with two arguments: the RemoteBuild object, and our builderName) for each new Build that is created to handle this BuildRequest.""" def send(bs): d = observer.callRemote("newbuild", IRemote(bs), self.b.getBuilderName()) d.addErrback(twlog.err, "while calling client-side remote_newbuild") self.observers.append((observer, send)) self.b.subscribe(send)
for i, (obs, send) in enumerate(self.observers): if obs == observer: del self.observers[i] self.b.unsubscribe(send) break
interfaces.IBuildRequestStatus, IRemote)
self.b = build self.observers = []
return self.b.getBuilder().getName()
return self.b.getNumber()
return self.b.getReason()
return [IRemote(c) for c in self.b.getChanges()]
return self.b.getRevisions()
return self.b.getResponsibleUsers()
return [IRemote(s) for s in self.b.getSteps()]
return self.b.getTimes()
return self.b.isFinished()
# the Deferred returned by callRemote() will fire when this build is # finished d = self.b.waitUntilFinished() d.addCallback(lambda res: self) return d
return self.b.getETA()
return makeRemote(self.b.getCurrentStep())
return self.b.getText()
return self.b.getResults()
logs = {} for name,log in self.b.getLogs().items(): logs[name] = IRemote(log) return logs
"""The observer will have remote_stepStarted(buildername, build, stepname, step), remote_stepFinished(buildername, build, stepname, step, results), and maybe remote_buildETAUpdate(buildername, build, eta)) messages sent to it.""" self.observers.append(observer) s = BuildSubscriber(observer) self.b.subscribe(s, updateInterval)
# TODO: is the observer automatically unsubscribed when the build # finishes? Or are they responsible for unsubscribing themselves # anyway? How do we avoid a race condition here? for o in self.observers: if o == observer: self.observers.remove(o)
interfaces.IBuildStatus, IRemote)
self.observer = observer
self.observer.callRemote("buildETAUpdate", build.getBuilder().getName(), IRemote(build), eta)
self.observer.callRemote("stepStarted", build.getBuilder().getName(), IRemote(build), step.getName(), IRemote(step)) return None
self.observer.callRemote("stepFinished", build.getBuilder().getName(), IRemote(build), step.getName(), IRemote(step), results)
self.s = step
return self.s.getName()
return IRemote(self.s.getBuild())
return self.s.getTimes()
return self.s.getExpectations()
logs = {} for log in self.s.getLogs(): logs[log.getName()] = IRemote(log) return logs
return self.s.isFinished()
return self.s.waitUntilFinished() # returns a Deferred
return self.s.getETA()
return self.s.getText()
return self.s.getResults()
interfaces.IBuildStepStatus, IRemote)
self.s = slave
return self.s.getName() return self.s.getAdmin() return self.s.getHost() return self.s.isConnected()
interfaces.ISlaveStatus, IRemote)
self.e = event
return self.s.getTimes() return self.s.getText()
interfaces.IStatusEvent, IRemote)
self.l = log
return self.l.getName()
return self.l.isFinished() d = self.l.waitUntilFinished() d.addCallback(lambda res: self) return d
return self.l.getText() return self.l.getTextWithHeaders() return self.l.getChunks() # TODO: subscription interface
# TODO: something similar for builder.HTMLLogfile ?
self.c = change
return self.c.who return self.c.files return self.c.comments
d = self.__dict__.copy() d['client'] = None return d
#twlog.msg("StatusClientPerspective.attached") return self
twlog.msg("PB client detached") self.client = None for name in self.subscribed_to_builders: twlog.msg(" unsubscribing from Builder(%s)" % name) self.status.getBuilder(name).unsubscribe(self) for s in self.subscribed_to: twlog.msg(" unsubscribe from %s" % s) s.unsubscribe(self) self.subscribed = None
"""The remote client wishes to subscribe to some set of events. 'target' will be sent remote messages when these events happen. 'mode' indicates which events are desired: it is a string with one of the following values:
'builders': builderAdded, builderRemoved 'builds': those plus builderChangedState, buildStarted, buildFinished 'steps': all those plus buildETAUpdate, stepStarted, stepFinished 'logs': all those plus stepETAUpdate, logStarted, logFinished 'full': all those plus logChunk (with the log contents)
Messages are defined by buildbot.interfaces.IStatusReceiver . 'interval' is used to specify how frequently ETAUpdate messages should be sent.
Raising or lowering the subscription level will take effect starting with the next build or step."""
assert mode in ("builders", "builds", "steps", "logs", "full") assert target twlog.msg("PB subscribe(%s)" % mode)
self.client = target self.subscribed = mode self.interval = interval self.subscribed_to.append(self.status) # wait a moment before subscribing, so the new-builder messages # won't appear before this remote method finishes reactor.callLater(0, self.status.subscribe, self) return None
twlog.msg("PB unsubscribe") self.status.unsubscribe(self) self.subscribed_to.remove(self.status) self.client = None
"""This returns tuples of (buildset, bsid), because that is much more convenient for tryclient."""
return self.status.getBuilderNames()
b = self.status.getBuilder(name) return IRemote(b)
s = self.status.getSlave(name) return IRemote(s)
"""Ping method to allow pb clients to validate their connections.""" return "pong"
# IStatusReceiver methods, invoked if we've subscribed
# mode >= builder self.client.callRemote("builderAdded", name, IRemote(builder)) if self.subscribed in ("builds", "steps", "logs", "full"): self.subscribed_to_builders.append(name) return self return None
self.client.callRemote("builderChangedState", name, state, None) # TODO: remove leftover ETA argument
if name in self.subscribed_to_builders: self.subscribed_to_builders.remove(name) self.client.callRemote("builderRemoved", name)
# TODO: deliver to client, somehow pass
# mode >= builds self.client.callRemote("buildStarted", name, IRemote(build)) if self.subscribed in ("steps", "logs", "full"): self.subscribed_to.append(build) return (self, self.interval) return None
if build in self.subscribed_to: # we might have joined during the build self.subscribed_to.remove(build) self.client.callRemote("buildFinished", name, IRemote(build), results)
# mode >= steps self.client.callRemote("buildETAUpdate", build.getBuilder().getName(), IRemote(build), eta)
# we add some information here so the client doesn't have to do an # extra round-trip self.client.callRemote("stepStarted", build.getBuilder().getName(), IRemote(build), step.getName(), IRemote(step)) if self.subscribed in ("logs", "full"): self.subscribed_to.append(step) return (self, self.interval) return None
self.client.callRemote("stepFinished", build.getBuilder().getName(), IRemote(build), step.getName(), IRemote(step), results) if step in self.subscribed_to: # eventually (through some new subscription method) we could # join in the middle of the step self.subscribed_to.remove(step)
# mode >= logs self.client.callRemote("stepETAUpdate", build.getBuilder().getName(), IRemote(build), step.getName(), IRemote(step), ETA, expectations)
# TODO: make the HTMLLog adapter rlog = IRemote(log, None) if not rlog: print "hey, couldn't adapt %s to IRemote" % log self.client.callRemote("logStarted", build.getBuilder().getName(), IRemote(build), step.getName(), IRemote(step), log.getName(), IRemote(log, None)) if self.subscribed in ("full",): self.subscribed_to.append(log) return self return None
self.client.callRemote("logFinished", build.getBuilder().getName(), IRemote(build), step.getName(), IRemote(step), log.getName(), IRemote(log, None)) if log in self.subscribed_to: self.subscribed_to.remove(log)
# mode >= full self.client.callRemote("logChunk", build.getBuilder().getName(), IRemote(build), step.getName(), IRemote(step), log.getName(), IRemote(log), channel, text)
"""I am a listener for PB-based status clients."""
base.StatusReceiverMultiService.__init__(self) if type(port) is int: port = "tcp:%d" % port self.port = port self.cred = (user, passwd) p = portal.Portal(self) c = checkers.InMemoryUsernamePasswordDatabaseDontUse() c.addUser(user, passwd) p.registerChecker(c) f = pb.PBServerFactory(p) s = strports.service(port, f) s.setServiceParent(self)
base.StatusReceiverMultiService.setServiceParent(self, parent) self.status = parent
assert interface == pb.IPerspective p = StatusClientPerspective(self.status) p.attached(mind) # perhaps .callLater(0) ? return (pb.IPerspective, p, lambda p=p,mind=mind: p.detached(mind)) |