1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16  import os 
 17   
 18  from twisted.internet import defer 
 19  from twisted.python import log 
 20  from twisted.protocols import basic 
 21   
 22  from buildbot import pbutil 
 23  from buildbot.util.maildir import MaildirService 
 24  from buildbot.util import json 
 25  from buildbot.util import netstrings 
 26  from buildbot.process.properties import Properties 
 27  from buildbot.schedulers import base 
 28  from buildbot.status.buildset import BuildSetStatus 
 29   
 30   
 31 -class TryBase(base.BaseScheduler): 
  32   
 34          """ 
 35          Make sure that C{builderNames} is a subset of the configured 
 36          C{self.builderNames}, returning an empty list if not.  If 
 37          C{builderNames} is empty, use C{self.builderNames}. 
 38   
 39          @returns: list of builder names to build on 
 40          """ 
 41   
 42           
 43           
 44           
 45           
 46          if builderNames: 
 47              for b in builderNames: 
 48                  if not b in self.builderNames: 
 49                      log.msg("%s got with builder %s" % (self, b)) 
 50                      log.msg(" but that wasn't in our list: %s" 
 51                              % (self.builderNames,)) 
 52                      return [] 
 53          else: 
 54              builderNames = self.builderNames 
 55          return builderNames 
   56   
 60   
 68   
 71   
 72      compare_attrs = TryBase.compare_attrs + ('jobdir',) 
 73   
 74 -    def __init__(self, name, builderNames, jobdir, 
 75                   properties={}): 
  81   
 90   
 92           
 93           
 94           
 95           
 96           
 97           
 98           
 99           
100           
101           
102           
103           
104           
105           
106           
107           
108           
109           
110           
111           
112          p = netstrings.NetstringParser() 
113          f.seek(0,2) 
114          if f.tell() > basic.NetstringReceiver.MAX_LENGTH: 
115              raise BadJobfile("The patch size is greater that NetStringReceiver.MAX_LENGTH. Please Set this higher in the master.cfg") 
116          f.seek(0,0) 
117          try: 
118              p.feed(f.read()) 
119          except basic.NetstringParseError: 
120              raise BadJobfile("unable to parse netstrings") 
121          if not p.strings: 
122              raise BadJobfile("could not find any complete netstrings") 
123          ver = p.strings.pop(0) 
124   
125          v1_keys = ['jobid', 'branch', 'baserev', 'patch_level', 'patch_body'] 
126          v2_keys = v1_keys + ['repository', 'project'] 
127          v3_keys = v2_keys + ['who'] 
128          v4_keys = v3_keys + ['comment'] 
129          keys = [v1_keys, v2_keys, v3_keys, v4_keys] 
130           
131   
132          parsed_job = {} 
133   
134          def extract_netstrings(p, keys): 
135              for i, key in enumerate(keys): 
136                  parsed_job[key] = p.strings[i] 
 137   
138          def postprocess_parsed_job(): 
139               
140              parsed_job['branch'] = parsed_job['branch'] or None 
141              parsed_job['baserev'] = parsed_job['baserev'] or None 
142              parsed_job['patch_level'] = int(parsed_job['patch_level']) 
143              for key in 'repository project who comment'.split(): 
144                  parsed_job[key] = parsed_job.get(key, '') 
145              parsed_job['properties'] = parsed_job.get('properties', {}) 
 146   
147          if ver <= "4": 
148              i = int(ver) - 1 
149              extract_netstrings(p, keys[i]) 
150              parsed_job['builderNames'] = p.strings[len(keys[i]):] 
151              postprocess_parsed_job() 
152          elif ver == "5": 
153              try: 
154                  parsed_job = json.loads(p.strings[0]) 
155              except ValueError: 
156                  raise BadJobfile("unable to parse JSON") 
157              postprocess_parsed_job() 
158          else: 
159              raise BadJobfile("unknown version '%s'" % ver) 
160          return parsed_job 
161   
163          try: 
164              parsed_job = self.parseJob(f) 
165              builderNames = parsed_job['builderNames'] 
166          except BadJobfile: 
167              log.msg("%s reports a bad jobfile in %s" % (self, filename)) 
168              log.err() 
169              return defer.succeed(None) 
170   
171           
172          builderNames = self.filterBuilderList(builderNames) 
173          if not builderNames: 
174              log.msg( 
175                  "incoming Try job did not specify any allowed builder names") 
176              return defer.succeed(None) 
177   
178          who = "" 
179          if parsed_job['who']: 
180              who = parsed_job['who'] 
181   
182          comment = "" 
183          if parsed_job['comment']: 
184              comment = parsed_job['comment'] 
185   
186          d = self.master.db.sourcestampsets.addSourceStampSet() 
187   
188          def addsourcestamp(setid): 
189              self.master.db.sourcestamps.addSourceStamp( 
190                  sourcestampsetid=setid, 
191                  branch=parsed_job['branch'], 
192                  revision=parsed_job['baserev'], 
193                  patch_body=parsed_job['patch_body'], 
194                  patch_level=parsed_job['patch_level'], 
195                  patch_author=who, 
196                  patch_comment=comment, 
197                  patch_subdir='',   
198                  project=parsed_job['project'], 
199                  repository=parsed_job['repository']) 
200              return setid 
 201   
202          d.addCallback(addsourcestamp) 
203   
204          def create_buildset(setid): 
205              reason = "'try' job" 
206              if parsed_job['who']: 
207                  reason += " by user %s" % parsed_job['who'] 
208              properties = parsed_job['properties'] 
209              requested_props = Properties() 
210              requested_props.update(properties, "try build") 
211              return self.addBuildsetForSourceStamp( 
212                  ssid=None, setid=setid, 
213                  reason=reason, external_idstring=parsed_job['jobid'], 
214                  builderNames=builderNames, properties=requested_props) 
215          d.addCallback(create_buildset) 
216          return d 
217   
220 -    def __init__(self, scheduler, username): 
 223   
224      @defer.inlineCallbacks 
225 -    def perspective_try(self, branch, revision, patch, repository, project, 
226                          builderNames, who="", comment="", properties={}): 
 227          db = self.scheduler.master.db 
228          log.msg("user %s requesting build on builders %s" % (self.username, 
229                                                               builderNames)) 
230   
231           
232          builderNames = self.scheduler.filterBuilderList(builderNames) 
233          if not builderNames: 
234              return 
235   
236          reason = "'try' job" 
237   
238          if who: 
239              reason += " by user %s" % who 
240   
241          if comment: 
242              reason += " (%s)" % comment 
243   
244          sourcestampsetid = yield db.sourcestampsets.addSourceStampSet() 
245   
246          yield db.sourcestamps.addSourceStamp( 
247              branch=branch, revision=revision, repository=repository, 
248              project=project, patch_level=patch[0], patch_body=patch[1], 
249              patch_subdir='', patch_author=who or '', 
250              patch_comment=comment or '', 
251              sourcestampsetid=sourcestampsetid) 
252                       
253   
254          requested_props = Properties() 
255          requested_props.update(properties, "try build") 
256          (bsid, brids) = yield self.scheduler.addBuildsetForSourceStamp( 
257                  setid=sourcestampsetid, reason=reason, 
258                  properties=requested_props, builderNames=builderNames) 
259   
260           
261          bsdict = yield db.buildsets.getBuildset(bsid) 
262   
263          bss = BuildSetStatus(bsdict, self.scheduler.master.status) 
264          from buildbot.status.client import makeRemote 
265          defer.returnValue(makeRemote(bss)) 
 266   
 273   
276      compare_attrs = ('name', 'builderNames', 'port', 'userpass', 'properties') 
277   
278 -    def __init__(self, name, builderNames, port, userpass, 
279                   properties={}): 
 284   
291          self.registrations = [] 
292          for user, passwd in self.userpass: 
293              self.registrations.append( 
294                  self.master.pbmanager.register( 
295                      self.port, user, passwd, factory)) 
 296   
298          d = defer.maybeDeferred(TryBase.stopService, self) 
299   
300          def unreg(_): 
301              return defer.gatherResults( 
302                  [reg.unregister() for reg in self.registrations]) 
 303          d.addCallback(unreg) 
304          return d 
305