Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(134)

Side by Side Diff: third_party/buildbot_7_12/buildbot/status/client.py

Issue 12207158: Bye bye buildbot 0.7.12. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: buildbot.test.test_status -*-
2
3 from twisted.spread import pb
4 from twisted.python import components, log as twlog
5 from twisted.internet import reactor
6 from twisted.application import strports
7 from twisted.cred import portal, checkers
8
9 from buildbot import interfaces
10 from zope.interface import Interface, implements
11 from buildbot.status import builder, base
12 from buildbot.changes import changes
13
14 class IRemote(Interface):
15 pass
16
17 def makeRemote(obj):
18 # we want IRemote(None) to be None, but you can't really do that with
19 # adapters, so we fake it
20 if obj is None:
21 return None
22 return IRemote(obj)
23
24
25 class RemoteBuildSet(pb.Referenceable):
26 def __init__(self, buildset):
27 self.b = buildset
28
29 def remote_getSourceStamp(self):
30 return self.b.getSourceStamp()
31
32 def remote_getReason(self):
33 return self.b.getReason()
34
35 def remote_getID(self):
36 return self.b.getID()
37
38 def remote_getBuilderNames(self):
39 return self.b.getBuilderNames()
40
41 def remote_getBuildRequests(self):
42 """Returns a list of (builderName, BuildRequest) tuples."""
43 return [(br.getBuilderName(), IRemote(br))
44 for br in self.b.getBuildRequests()]
45
46 def remote_isFinished(self):
47 return self.b.isFinished()
48
49 def remote_waitUntilSuccess(self):
50 d = self.b.waitUntilSuccess()
51 d.addCallback(lambda res: self)
52 return d
53
54 def remote_waitUntilFinished(self):
55 d = self.b.waitUntilFinished()
56 d.addCallback(lambda res: self)
57 return d
58
59 def remote_getResults(self):
60 return self.b.getResults()
61
62 components.registerAdapter(RemoteBuildSet,
63 interfaces.IBuildSetStatus, IRemote)
64
65
66 class RemoteBuilder(pb.Referenceable):
67 def __init__(self, builder):
68 self.b = builder
69
70 def remote_getName(self):
71 return self.b.getName()
72
73 def remote_getCategory(self):
74 return self.b.getCategory()
75
76 def remote_getState(self):
77 state, builds = self.b.getState()
78 return (state,
79 None, # TODO: remove leftover ETA
80 [makeRemote(b) for b in builds])
81
82 def remote_getSlaves(self):
83 return [IRemote(s) for s in self.b.getSlaves()]
84
85 def remote_getLastFinishedBuild(self):
86 return makeRemote(self.b.getLastFinishedBuild())
87
88 def remote_getCurrentBuilds(self):
89 return [IRemote(b) for b in self.b.getCurrentBuilds()]
90
91 def remote_getBuild(self, number):
92 return makeRemote(self.b.getBuild(number))
93
94 def remote_getEvent(self, number):
95 return IRemote(self.b.getEvent(number))
96
97 components.registerAdapter(RemoteBuilder,
98 interfaces.IBuilderStatus, IRemote)
99
100
101 class RemoteBuildRequest(pb.Referenceable):
102 def __init__(self, buildreq):
103 self.b = buildreq
104 self.observers = []
105
106 def remote_getSourceStamp(self):
107 return self.b.getSourceStamp()
108
109 def remote_getBuilderName(self):
110 return self.b.getBuilderName()
111
112 def remote_subscribe(self, observer):
113 """The observer's remote_newbuild method will be called (with two
114 arguments: the RemoteBuild object, and our builderName) for each new
115 Build that is created to handle this BuildRequest."""
116 self.observers.append(observer)
117 def send(bs):
118 d = observer.callRemote("newbuild",
119 IRemote(bs), self.b.getBuilderName())
120 d.addErrback(lambda err: None)
121 reactor.callLater(0, self.b.subscribe, send)
122
123 def remote_unsubscribe(self, observer):
124 # PB (well, at least oldpb) doesn't re-use RemoteReference instances,
125 # so sending the same object across the wire twice will result in two
126 # separate objects that compare as equal ('a is not b' and 'a == b').
127 # That means we can't use a simple 'self.observers.remove(observer)'
128 # here.
129 for o in self.observers:
130 if o == observer:
131 self.observers.remove(o)
132
133 components.registerAdapter(RemoteBuildRequest,
134 interfaces.IBuildRequestStatus, IRemote)
135
136 class RemoteBuild(pb.Referenceable):
137 def __init__(self, build):
138 self.b = build
139 self.observers = []
140
141 def remote_getBuilderName(self):
142 return self.b.getBuilder().getName()
143
144 def remote_getNumber(self):
145 return self.b.getNumber()
146
147 def remote_getReason(self):
148 return self.b.getReason()
149
150 def remote_getChanges(self):
151 return [IRemote(c) for c in self.b.getChanges()]
152
153 def remote_getResponsibleUsers(self):
154 return self.b.getResponsibleUsers()
155
156 def remote_getSteps(self):
157 return [IRemote(s) for s in self.b.getSteps()]
158
159 def remote_getTimes(self):
160 return self.b.getTimes()
161
162 def remote_isFinished(self):
163 return self.b.isFinished()
164
165 def remote_waitUntilFinished(self):
166 # the Deferred returned by callRemote() will fire when this build is
167 # finished
168 d = self.b.waitUntilFinished()
169 d.addCallback(lambda res: self)
170 return d
171
172 def remote_getETA(self):
173 return self.b.getETA()
174
175 def remote_getCurrentStep(self):
176 return makeRemote(self.b.getCurrentStep())
177
178 def remote_getText(self):
179 return self.b.getText()
180
181 def remote_getResults(self):
182 return self.b.getResults()
183
184 def remote_getLogs(self):
185 logs = {}
186 for name,log in self.b.getLogs().items():
187 logs[name] = IRemote(log)
188 return logs
189
190 def remote_subscribe(self, observer, updateInterval=None):
191 """The observer will have remote_stepStarted(buildername, build,
192 stepname, step), remote_stepFinished(buildername, build, stepname,
193 step, results), and maybe remote_buildETAUpdate(buildername, build,
194 eta)) messages sent to it."""
195 self.observers.append(observer)
196 s = BuildSubscriber(observer)
197 self.b.subscribe(s, updateInterval)
198
199 def remote_unsubscribe(self, observer):
200 # TODO: is the observer automatically unsubscribed when the build
201 # finishes? Or are they responsible for unsubscribing themselves
202 # anyway? How do we avoid a race condition here?
203 for o in self.observers:
204 if o == observer:
205 self.observers.remove(o)
206
207
208 components.registerAdapter(RemoteBuild,
209 interfaces.IBuildStatus, IRemote)
210
211 class BuildSubscriber:
212 def __init__(self, observer):
213 self.observer = observer
214
215 def buildETAUpdate(self, build, eta):
216 self.observer.callRemote("buildETAUpdate",
217 build.getBuilder().getName(),
218 IRemote(build),
219 eta)
220
221 def stepStarted(self, build, step):
222 self.observer.callRemote("stepStarted",
223 build.getBuilder().getName(),
224 IRemote(build),
225 step.getName(), IRemote(step))
226 return None
227
228 def stepFinished(self, build, step, results):
229 self.observer.callRemote("stepFinished",
230 build.getBuilder().getName(),
231 IRemote(build),
232 step.getName(), IRemote(step),
233 results)
234
235
236 class RemoteBuildStep(pb.Referenceable):
237 def __init__(self, step):
238 self.s = step
239
240 def remote_getName(self):
241 return self.s.getName()
242
243 def remote_getBuild(self):
244 return IRemote(self.s.getBuild())
245
246 def remote_getTimes(self):
247 return self.s.getTimes()
248
249 def remote_getExpectations(self):
250 return self.s.getExpectations()
251
252 def remote_getLogs(self):
253 logs = {}
254 for log in self.s.getLogs():
255 logs[log.getName()] = IRemote(log)
256 return logs
257
258 def remote_isFinished(self):
259 return self.s.isFinished()
260
261 def remote_waitUntilFinished(self):
262 return self.s.waitUntilFinished() # returns a Deferred
263
264 def remote_getETA(self):
265 return self.s.getETA()
266
267 def remote_getText(self):
268 return self.s.getText()
269
270 def remote_getResults(self):
271 return self.s.getResults()
272
273 components.registerAdapter(RemoteBuildStep,
274 interfaces.IBuildStepStatus, IRemote)
275
276 class RemoteSlave:
277 def __init__(self, slave):
278 self.s = slave
279
280 def remote_getName(self):
281 return self.s.getName()
282 def remote_getAdmin(self):
283 return self.s.getAdmin()
284 def remote_getHost(self):
285 return self.s.getHost()
286 def remote_isConnected(self):
287 return self.s.isConnected()
288
289 components.registerAdapter(RemoteSlave,
290 interfaces.ISlaveStatus, IRemote)
291
292 class RemoteEvent:
293 def __init__(self, event):
294 self.e = event
295
296 def remote_getTimes(self):
297 return self.s.getTimes()
298 def remote_getText(self):
299 return self.s.getText()
300
301 components.registerAdapter(RemoteEvent,
302 interfaces.IStatusEvent, IRemote)
303
304 class RemoteLog(pb.Referenceable):
305 def __init__(self, log):
306 self.l = log
307
308 def remote_getName(self):
309 return self.l.getName()
310
311 def remote_isFinished(self):
312 return self.l.isFinished()
313 def remote_waitUntilFinished(self):
314 d = self.l.waitUntilFinished()
315 d.addCallback(lambda res: self)
316 return d
317
318 def remote_getText(self):
319 return self.l.getText()
320 def remote_getTextWithHeaders(self):
321 return self.l.getTextWithHeaders()
322 def remote_getChunks(self):
323 return self.l.getChunks()
324 # TODO: subscription interface
325
326 components.registerAdapter(RemoteLog, builder.LogFile, IRemote)
327 # TODO: something similar for builder.HTMLLogfile ?
328
329 class RemoteChange:
330 def __init__(self, change):
331 self.c = change
332
333 def getWho(self):
334 return self.c.who
335 def getFiles(self):
336 return self.c.files
337 def getComments(self):
338 return self.c.comments
339
340 components.registerAdapter(RemoteChange, changes.Change, IRemote)
341
342
343 class StatusClientPerspective(base.StatusReceiverPerspective):
344
345 subscribed = None
346 client = None
347
348 def __init__(self, status):
349 self.status = status # the IStatus
350 self.subscribed_to_builders = [] # Builders to which we're subscribed
351 self.subscribed_to = [] # everything else we're subscribed to
352
353 def __getstate__(self):
354 d = self.__dict__.copy()
355 d['client'] = None
356 return d
357
358 def attached(self, mind):
359 #twlog.msg("StatusClientPerspective.attached")
360 return self
361
362 def detached(self, mind):
363 twlog.msg("PB client detached")
364 self.client = None
365 for name in self.subscribed_to_builders:
366 twlog.msg(" unsubscribing from Builder(%s)" % name)
367 self.status.getBuilder(name).unsubscribe(self)
368 for s in self.subscribed_to:
369 twlog.msg(" unsubscribe from %s" % s)
370 s.unsubscribe(self)
371 self.subscribed = None
372
373 def perspective_subscribe(self, mode, interval, target):
374 """The remote client wishes to subscribe to some set of events.
375 'target' will be sent remote messages when these events happen.
376 'mode' indicates which events are desired: it is a string with one
377 of the following values:
378
379 'builders': builderAdded, builderRemoved
380 'builds': those plus builderChangedState, buildStarted, buildFinished
381 'steps': all those plus buildETAUpdate, stepStarted, stepFinished
382 'logs': all those plus stepETAUpdate, logStarted, logFinished
383 'full': all those plus logChunk (with the log contents)
384
385
386 Messages are defined by buildbot.interfaces.IStatusReceiver .
387 'interval' is used to specify how frequently ETAUpdate messages
388 should be sent.
389
390 Raising or lowering the subscription level will take effect starting
391 with the next build or step."""
392
393 assert mode in ("builders", "builds", "steps", "logs", "full")
394 assert target
395 twlog.msg("PB subscribe(%s)" % mode)
396
397 self.client = target
398 self.subscribed = mode
399 self.interval = interval
400 self.subscribed_to.append(self.status)
401 # wait a moment before subscribing, so the new-builder messages
402 # won't appear before this remote method finishes
403 reactor.callLater(0, self.status.subscribe, self)
404 return None
405
406 def perspective_unsubscribe(self):
407 twlog.msg("PB unsubscribe")
408 self.status.unsubscribe(self)
409 self.subscribed_to.remove(self.status)
410 self.client = None
411
412 def perspective_getBuildSets(self):
413 """This returns tuples of (buildset, bsid), because that is much more
414 convenient for tryclient."""
415 return [(IRemote(s), s.getID()) for s in self.status.getBuildSets()]
416
417 def perspective_getBuilderNames(self):
418 return self.status.getBuilderNames()
419
420 def perspective_getBuilder(self, name):
421 b = self.status.getBuilder(name)
422 return IRemote(b)
423
424 def perspective_getSlave(self, name):
425 s = self.status.getSlave(name)
426 return IRemote(s)
427
428 def perspective_ping(self):
429 """Ping method to allow pb clients to validate their connections."""
430 return "pong"
431
432 # IStatusReceiver methods, invoked if we've subscribed
433
434 # mode >= builder
435 def builderAdded(self, name, builder):
436 self.client.callRemote("builderAdded", name, IRemote(builder))
437 if self.subscribed in ("builds", "steps", "logs", "full"):
438 self.subscribed_to_builders.append(name)
439 return self
440 return None
441
442 def builderChangedState(self, name, state):
443 self.client.callRemote("builderChangedState", name, state, None)
444 # TODO: remove leftover ETA argument
445
446 def builderRemoved(self, name):
447 if name in self.subscribed_to_builders:
448 self.subscribed_to_builders.remove(name)
449 self.client.callRemote("builderRemoved", name)
450
451 def buildsetSubmitted(self, buildset):
452 # TODO: deliver to client, somehow
453 pass
454
455 # mode >= builds
456 def buildStarted(self, name, build):
457 self.client.callRemote("buildStarted", name, IRemote(build))
458 if self.subscribed in ("steps", "logs", "full"):
459 self.subscribed_to.append(build)
460 return (self, self.interval)
461 return None
462
463 def buildFinished(self, name, build, results):
464 if build in self.subscribed_to:
465 # we might have joined during the build
466 self.subscribed_to.remove(build)
467 self.client.callRemote("buildFinished",
468 name, IRemote(build), results)
469
470 # mode >= steps
471 def buildETAUpdate(self, build, eta):
472 self.client.callRemote("buildETAUpdate",
473 build.getBuilder().getName(), IRemote(build),
474 eta)
475
476 def stepStarted(self, build, step):
477 # we add some information here so the client doesn't have to do an
478 # extra round-trip
479 self.client.callRemote("stepStarted",
480 build.getBuilder().getName(), IRemote(build),
481 step.getName(), IRemote(step))
482 if self.subscribed in ("logs", "full"):
483 self.subscribed_to.append(step)
484 return (self, self.interval)
485 return None
486
487 def stepFinished(self, build, step, results):
488 self.client.callRemote("stepFinished",
489 build.getBuilder().getName(), IRemote(build),
490 step.getName(), IRemote(step),
491 results)
492 if step in self.subscribed_to:
493 # eventually (through some new subscription method) we could
494 # join in the middle of the step
495 self.subscribed_to.remove(step)
496
497 # mode >= logs
498 def stepETAUpdate(self, build, step, ETA, expectations):
499 self.client.callRemote("stepETAUpdate",
500 build.getBuilder().getName(), IRemote(build),
501 step.getName(), IRemote(step),
502 ETA, expectations)
503
504 def logStarted(self, build, step, log):
505 # TODO: make the HTMLLog adapter
506 rlog = IRemote(log, None)
507 if not rlog:
508 print "hey, couldn't adapt %s to IRemote" % log
509 self.client.callRemote("logStarted",
510 build.getBuilder().getName(), IRemote(build),
511 step.getName(), IRemote(step),
512 log.getName(), IRemote(log, None))
513 if self.subscribed in ("full",):
514 self.subscribed_to.append(log)
515 return self
516 return None
517
518 def logFinished(self, build, step, log):
519 self.client.callRemote("logFinished",
520 build.getBuilder().getName(), IRemote(build),
521 step.getName(), IRemote(step),
522 log.getName(), IRemote(log, None))
523 if log in self.subscribed_to:
524 self.subscribed_to.remove(log)
525
526 # mode >= full
527 def logChunk(self, build, step, log, channel, text):
528 self.client.callRemote("logChunk",
529 build.getBuilder().getName(), IRemote(build),
530 step.getName(), IRemote(step),
531 log.getName(), IRemote(log),
532 channel, text)
533
534
535 class PBListener(base.StatusReceiverMultiService):
536 """I am a listener for PB-based status clients."""
537
538 compare_attrs = ["port", "cred"]
539 implements(portal.IRealm)
540
541 def __init__(self, port, user="statusClient", passwd="clientpw"):
542 base.StatusReceiverMultiService.__init__(self)
543 if type(port) is int:
544 port = "tcp:%d" % port
545 self.port = port
546 self.cred = (user, passwd)
547 p = portal.Portal(self)
548 c = checkers.InMemoryUsernamePasswordDatabaseDontUse()
549 c.addUser(user, passwd)
550 p.registerChecker(c)
551 f = pb.PBServerFactory(p)
552 s = strports.service(port, f)
553 s.setServiceParent(self)
554
555 def setServiceParent(self, parent):
556 base.StatusReceiverMultiService.setServiceParent(self, parent)
557 self.setup()
558
559 def setup(self):
560 self.status = self.parent.getStatus()
561
562 def requestAvatar(self, avatarID, mind, interface):
563 assert interface == pb.IPerspective
564 p = StatusClientPerspective(self.status)
565 p.attached(mind) # perhaps .callLater(0) ?
566 return (pb.IPerspective, p,
567 lambda p=p,mind=mind: p.detached(mind))
OLDNEW
« no previous file with comments | « third_party/buildbot_7_12/buildbot/status/builder.py ('k') | third_party/buildbot_7_12/buildbot/status/html.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698