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   
181           
182           
183          d = self.b.waitUntilFinished() 
184          d.addCallback(lambda res: self) 
185          return d 
 186   
189   
192   
193 -    def remote_getText(self): 
 194          return self.b.getText() 
 195   
198   
204   
206          """The observer will have remote_stepStarted(buildername, build, 
207          stepname, step), remote_stepFinished(buildername, build, stepname, 
208          step, results), and maybe remote_buildETAUpdate(buildername, build, 
209          eta)) messages sent to it.""" 
210          self.observers.append(observer) 
211          s = BuildSubscriber(observer) 
212          self.b.subscribe(s, updateInterval) 
 213   
215           
216           
217           
218          for o in self.observers: 
219              if o == observer: 
220                  self.observers.remove(o) 
  221   
222   
223  components.registerAdapter(RemoteBuild, 
224                             interfaces.IBuildStatus, IRemote)     
225   
228          self.observer = observer 
 229   
235   
242   
 249   
250   
287   
288  components.registerAdapter(RemoteBuildStep, 
289                             interfaces.IBuildStepStatus, IRemote)     
290   
303   
304  components.registerAdapter(RemoteSlave, 
305                             interfaces.ISlaveStatus, IRemote) 
306   
315   
316  components.registerAdapter(RemoteEvent, 
317                             interfaces.IStatusEvent, IRemote) 
318   
339       
340   
341  components.registerAdapter(RemoteLog, logfile.LogFile, IRemote) 
342   
343   
354   
355  components.registerAdapter(RemoteChange, changes.Change, IRemote) 
356   
357   
359   
360      subscribed = None 
361      client = None 
362   
364          self.status = status  
365          self.subscribed_to_builders = []  
366          self.subscribed_to = []  
 367   
369          d = self.__dict__.copy() 
370          d['client'] = None 
371          return d 
 372   
376   
387   
389          """The remote client wishes to subscribe to some set of events. 
390          'target' will be sent remote messages when these events happen. 
391          'mode' indicates which events are desired: it is a string with one 
392          of the following values: 
393   
394          'builders': builderAdded, builderRemoved 
395          'builds': those plus builderChangedState, buildStarted, buildFinished 
396          'steps': all those plus buildETAUpdate, stepStarted, stepFinished 
397          'logs': all those plus stepETAUpdate, logStarted, logFinished 
398          'full': all those plus logChunk (with the log contents) 
399           
400   
401          Messages are defined by buildbot.interfaces.IStatusReceiver . 
402          'interval' is used to specify how frequently ETAUpdate messages 
403          should be sent. 
404   
405          Raising or lowering the subscription level will take effect starting 
406          with the next build or step.""" 
407   
408          assert mode in ("builders", "builds", "steps", "logs", "full") 
409          assert target 
410          twlog.msg("PB subscribe(%s)" % mode) 
411   
412          self.client = target 
413          self.subscribed = mode 
414          self.interval = interval 
415          self.subscribed_to.append(self.status) 
416           
417           
418          reactor.callLater(0, self.status.subscribe, self) 
419          return None 
 420   
426   
428          """This returns tuples of (buildset, bsid), because that is much more 
429          convenient for tryclient.""" 
430          d = self.status.getBuildSets() 
431          def make_remotes(buildsets): 
432              return [(IRemote(s), s.id) for s in buildsets] 
 433          d.addCallback(make_remotes) 
434          return d 
 435   
438   
442   
446   
448          """Ping method to allow pb clients to validate their connections.""" 
449          return "pong" 
 450   
451       
452   
453       
460   
463           
464   
466          if name in self.subscribed_to_builders: 
467              self.subscribed_to_builders.remove(name) 
468          self.client.callRemote("builderRemoved", name) 
 469   
473   
474       
481   
488   
489       
494   
505   
515   
516       
522   
524           
525          rlog = IRemote(log, None) 
526          if not rlog: 
527              print "hey, couldn't adapt %s to IRemote" % log 
528          self.client.callRemote("logStarted", 
529                                 build.getBuilder().getName(), IRemote(build), 
530                                 step.getName(), IRemote(step), 
531                                 log.getName(), IRemote(log, None)) 
532          if self.subscribed in ("full",): 
533              self.subscribed_to.append(log) 
534              return self 
535          return None 
 536   
544   
545       
546 -    def logChunk(self, build, step, log, channel, text): 
 552   
553   
554 -class PBListener(base.StatusReceiverMultiService): 
 555      """I am a listener for PB-based status clients.""" 
556   
557      compare_attrs = ["port", "cred"] 
558      implements(portal.IRealm) 
559   
560 -    def __init__(self, port, user="statusClient", passwd="clientpw"): 
 561          base.StatusReceiverMultiService.__init__(self) 
562          if type(port) is int: 
563              port = "tcp:%d" % port 
564          self.port = port 
565          self.cred = (user, passwd) 
566          p = portal.Portal(self) 
567          c = checkers.InMemoryUsernamePasswordDatabaseDontUse() 
568          c.addUser(user, passwd) 
569          p.registerChecker(c) 
570          f = pb.PBServerFactory(p) 
571          s = strports.service(port, f) 
572          s.setServiceParent(self) 
 573   
577   
580   
 587