1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17  from twisted.spread import pb 
 18  from twisted.python import components, log as twlog 
 19  from twisted.internet import reactor 
 20  from twisted.application import strports 
 21  from twisted.cred import portal, checkers 
 22   
 23  from buildbot import interfaces 
 24  from zope.interface import Interface, implements 
 25  from buildbot.status import logfile, base 
 26  from buildbot.changes import changes 
 27   
 30   
 32       
 33       
 34      if obj is None: 
 35          return None 
 36      return IRemote(obj) 
  37   
 38   
 42   
 45   
 48   
 51   
 54   
 62          d.addCallback(add_remote) 
 63          return d 
  64   
 67   
 72   
 75   
 76  components.registerAdapter(RemoteBuildSet, 
 77                             interfaces.IBuildSetStatus, IRemote)     
 78   
 79   
 83   
 86   
 89   
 95   
 98   
101   
104   
107   
 110   
111  components.registerAdapter(RemoteBuilder, 
112                             interfaces.IBuilderStatus, IRemote)     
113   
114   
117          self.b = buildreq 
118           
119           
120          self.observers = [] 
 121   
125   
128   
130          """The observer's remote_newbuild method will be called (with two 
131          arguments: the RemoteBuild object, and our builderName) for each new 
132          Build that is created to handle this BuildRequest.""" 
133          def send(bs): 
134              d = observer.callRemote("newbuild", 
135                                      IRemote(bs), self.b.getBuilderName()) 
136              d.addErrback(twlog.err, 
137                      "while calling client-side remote_newbuild") 
 138          self.observers.append((observer, send)) 
139          self.b.subscribe(send) 
 140   
142          for i, (obs, send) in enumerate(self.observers): 
143              if obs == observer: 
144                  del self.observers[i] 
145                  self.b.unsubscribe(send) 
146                  break 
 147   
148  components.registerAdapter(RemoteBuildRequest, 
149                             interfaces.IBuildRequestStatus, IRemote)     
150   
153          self.b = build 
154          self.observers = [] 
 155   
158   
161   
164   
167   
170   
173   
176   
179   
182   
184           
185           
186          d = self.b.waitUntilFinished() 
187          d.addCallback(lambda res: self) 
188          return d 
 189   
192   
195   
196 -    def remote_getText(self): 
 197          return self.b.getText() 
 198   
201   
207   
209          """The observer will have remote_stepStarted(buildername, build, 
210          stepname, step), remote_stepFinished(buildername, build, stepname, 
211          step, results), and maybe remote_buildETAUpdate(buildername, build, 
212          eta)) messages sent to it.""" 
213          self.observers.append(observer) 
214          s = BuildSubscriber(observer) 
215          self.b.subscribe(s, updateInterval) 
 216   
218           
219           
220           
221          for o in self.observers: 
222              if o == observer: 
223                  self.observers.remove(o) 
  224   
225   
226  components.registerAdapter(RemoteBuild, 
227                             interfaces.IBuildStatus, IRemote)     
228   
231          self.observer = observer 
 232   
238   
245   
 252   
253   
290   
291  components.registerAdapter(RemoteBuildStep, 
292                             interfaces.IBuildStepStatus, IRemote)     
293   
306   
307  components.registerAdapter(RemoteSlave, 
308                             interfaces.ISlaveStatus, IRemote) 
309   
318   
319  components.registerAdapter(RemoteEvent, 
320                             interfaces.IStatusEvent, IRemote) 
321   
342       
343   
344  components.registerAdapter(RemoteLog, logfile.LogFile, IRemote) 
345   
346   
357   
358  components.registerAdapter(RemoteChange, changes.Change, IRemote) 
359   
360   
362   
363      subscribed = None 
364      client = None 
365   
367          self.status = status  
368          self.subscribed_to_builders = []  
369          self.subscribed_to = []  
 370   
372          d = self.__dict__.copy() 
373          d['client'] = None 
374          return d 
 375   
379   
390   
392          """The remote client wishes to subscribe to some set of events. 
393          'target' will be sent remote messages when these events happen. 
394          'mode' indicates which events are desired: it is a string with one 
395          of the following values: 
396   
397          'builders': builderAdded, builderRemoved 
398          'builds': those plus builderChangedState, buildStarted, buildFinished 
399          'steps': all those plus buildETAUpdate, stepStarted, stepFinished 
400          'logs': all those plus stepETAUpdate, logStarted, logFinished 
401          'full': all those plus logChunk (with the log contents) 
402           
403   
404          Messages are defined by buildbot.interfaces.IStatusReceiver . 
405          'interval' is used to specify how frequently ETAUpdate messages 
406          should be sent. 
407   
408          Raising or lowering the subscription level will take effect starting 
409          with the next build or step.""" 
410   
411          assert mode in ("builders", "builds", "steps", "logs", "full") 
412          assert target 
413          twlog.msg("PB subscribe(%s)" % mode) 
414   
415          self.client = target 
416          self.subscribed = mode 
417          self.interval = interval 
418          self.subscribed_to.append(self.status) 
419           
420           
421          reactor.callLater(0, self.status.subscribe, self) 
422          return None 
 423   
429   
431          """This returns tuples of (buildset, bsid), because that is much more 
432          convenient for tryclient.""" 
433          d = self.status.getBuildSets() 
434          def make_remotes(buildsets): 
435              return [(IRemote(s), s.id) for s in buildsets] 
 436          d.addCallback(make_remotes) 
437          return d 
 438   
441   
445   
449   
451          """Ping method to allow pb clients to validate their connections.""" 
452          return "pong" 
 453   
454       
455   
456       
463   
466           
467   
469          if name in self.subscribed_to_builders: 
470              self.subscribed_to_builders.remove(name) 
471          self.client.callRemote("builderRemoved", name) 
 472   
476   
477       
484   
491   
492       
497   
508   
518   
519       
525   
527           
528          rlog = IRemote(log, None) 
529          if not rlog: 
530              print "hey, couldn't adapt %s to IRemote" % log 
531          self.client.callRemote("logStarted", 
532                                 build.getBuilder().getName(), IRemote(build), 
533                                 step.getName(), IRemote(step), 
534                                 log.getName(), IRemote(log, None)) 
535          if self.subscribed in ("full",): 
536              self.subscribed_to.append(log) 
537              return self 
538          return None 
 539   
547   
548       
549 -    def logChunk(self, build, step, log, channel, text): 
 555   
556   
557 -class PBListener(base.StatusReceiverMultiService): 
 558      """I am a listener for PB-based status clients.""" 
559   
560      compare_attrs = ["port", "cred"] 
561      implements(portal.IRealm) 
562   
563 -    def __init__(self, port, user="statusClient", passwd="clientpw"): 
 564          base.StatusReceiverMultiService.__init__(self) 
565          if type(port) is int: 
566              port = "tcp:%d" % port 
567          self.port = port 
568          self.cred = (user, passwd) 
569          p = portal.Portal(self) 
570          c = checkers.InMemoryUsernamePasswordDatabaseDontUse() 
571          c.addUser(user, passwd) 
572          p.registerChecker(c) 
573          f = pb.PBServerFactory(p) 
574          s = strports.service(port, f) 
575          s.setServiceParent(self) 
 576   
580   
 587