1
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
16
18
19
20 if obj is None:
21 return None
22 return IRemote(obj)
23
24
28
31
34
37
40
45
48
53
58
61
62 components.registerAdapter(RemoteBuildSet,
63 interfaces.IBuildSetStatus, IRemote)
64
65
69
72
75
77 state, builds = self.b.getState()
78 return (state,
79 None,
80 [makeRemote(b) for b in builds])
81
84
87
90
93
96
97 components.registerAdapter(RemoteBuilder,
98 interfaces.IBuilderStatus, IRemote)
99
100
103 self.b = buildreq
104 self.observers = []
105
108
111
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
124
125
126
127
128
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
138 self.b = build
139 self.observers = []
140
143
146
149
152
155
158
161
164
171
174
177
178 - def remote_getText(self):
179 return self.b.getText()
180
183
189
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
200
201
202
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
213 self.observer = observer
214
220
227
234
235
272
273 components.registerAdapter(RemoteBuildStep,
274 interfaces.IBuildStepStatus, IRemote)
275
288
289 components.registerAdapter(RemoteSlave,
290 interfaces.ISlaveStatus, IRemote)
291
300
301 components.registerAdapter(RemoteEvent,
302 interfaces.IStatusEvent, IRemote)
303
324
325
326 components.registerAdapter(RemoteLog, builder.LogFile, IRemote)
327
328
339
340 components.registerAdapter(RemoteChange, changes.Change, IRemote)
341
342
344
345 subscribed = None
346 client = None
347
349 self.status = status
350 self.subscribed_to_builders = []
351 self.subscribed_to = []
352
354 d = self.__dict__.copy()
355 d['client'] = None
356 return d
357
361
372
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
402
403 reactor.callLater(0, self.status.subscribe, self)
404 return None
405
411
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
419
423
427
429 """Ping method to allow pb clients to validate their connections."""
430 return "pong"
431
432
433
434
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
443 self.client.callRemote("builderChangedState", name, state, None)
444
445
447 if name in self.subscribed_to_builders:
448 self.subscribed_to_builders.remove(name)
449 self.client.callRemote("builderRemoved", name)
450
454
455
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
469
470
475
486
496
497
503
505
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
525
526
527 - def logChunk(self, build, step, log, 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
558
561
568