1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16  from twisted.python import log, failure 
 17  from twisted.internet import defer 
 18   
 19  from buildbot.process import buildstep 
 20  from buildbot.steps.source import Source, _ComputeRepositoryURL 
 21  from buildbot.interfaces import BuildSlaveTooOldError 
 22   
 23 -class Git(Source): 
  24      """ Class for Git with all the smarts """ 
 25      name='git' 
 26      renderables = [ "repourl"] 
 27   
 28 -    def __init__(self, repourl=None, branch='master', mode='incremental', 
 29                   method=None, submodule=False, shallow=False, progress=False, 
 30                   retryFetch=False, clobberOnFailure=False, **kwargs): 
  31          """ 
 32          @type  repourl: string 
 33          @param repourl: the URL which points at the git repository 
 34   
 35          @type  branch: string 
 36          @param branch: The branch or tag to check out by default. If 
 37                         a build specifies a different branch, it will 
 38                         be used instead of this. 
 39   
 40          @type  submodules: boolean 
 41          @param submodules: Whether or not to update (and initialize) 
 42                         git submodules. 
 43   
 44          @type  mode: string 
 45          @param mode: Type of checkout. Described in docs. 
 46   
 47          @type  method: string 
 48          @param method: Full builds can be done is different ways. This parameter 
 49                         specifies which method to use. 
 50   
 51          @type  progress: boolean 
 52          @param progress: Pass the --progress option when fetching. This 
 53                           can solve long fetches getting killed due to 
 54                           lack of output, but requires Git 1.7.2+. 
 55          @type  shallow: boolean 
 56          @param shallow: Use a shallow or clone, if possible 
 57   
 58          @type  retryFetch: boolean 
 59          @param retryFetch: Retry fetching before failing source checkout. 
 60          """ 
 61   
 62          self.branch    = branch 
 63          self.method    = method 
 64          self.prog  = progress 
 65          self.repourl   = repourl 
 66          self.retryFetch = retryFetch 
 67          self.submodule = submodule 
 68          self.shallow   = shallow 
 69          self.fetchcount = 0 
 70          self.clobberOnFailure = clobberOnFailure 
 71          Source.__init__(self, **kwargs) 
 72          self.addFactoryArguments(branch=branch, 
 73                                   mode=mode, 
 74                                   method=method, 
 75                                   progress=progress, 
 76                                   repourl=repourl, 
 77                                   submodule=submodule, 
 78                                   shallow=shallow, 
 79                                   retryFetch=retryFetch, 
 80                                   clobberOnFailure= 
 81                                   clobberOnFailure, 
 82                                   ) 
 83   
 84          self.mode = mode 
 85          assert self.mode in ['incremental', 'full'] 
 86          assert self.repourl is not None 
 87          if self.mode == 'full': 
 88              assert self.method in ['clean', 'fresh', 'clobber', 'copy', None] 
 89          self.repourl = self.repourl and _ComputeRepositoryURL(self.repourl) 
  90   
 91 -    def startVC(self, branch, revision, patch): 
 102          d.addCallback(checkInstall) 
103   
104   
105          if self.mode == 'incremental': 
106              d.addCallback(lambda _: self.incremental()) 
107          elif self.mode == 'full': 
108              d.addCallback(lambda _: self.full()) 
109          d.addCallback(self.parseGotRevision) 
110          d.addCallback(self.finish) 
111          d.addErrback(self.failed) 
112          return d 
 113   
114      @defer.deferredGenerator 
116          if self.method == 'clobber': 
117              wfd = defer.waitForDeferred(self.clobber()) 
118              yield wfd 
119              wfd.getResult() 
120              return 
121          elif self.method == 'copy': 
122              wfd = defer.waitForDeferred(self.copy()) 
123              yield wfd 
124              wfd.getResult() 
125              return 
126   
127          wfd = defer.waitForDeferred(self._sourcedirIsUpdatable()) 
128          yield wfd 
129          updatable = wfd.getResult() 
130          if not updatable: 
131              log.msg("No git repo present, making full clone") 
132              d = self._doFull() 
133          elif self.method == 'clean': 
134              d = self.clean() 
135          elif self.method == 'fresh': 
136              d = self.fresh() 
137          else: 
138              raise ValueError("Unknown method, check your configuration") 
139          wfd = defer.waitForDeferred(d) 
140          yield wfd 
141          wfd.getResult() 
 142   
144          d = self._sourcedirIsUpdatable() 
145          def fetch(res): 
146               
147               
148              if res == 0: 
149                  return self._dovccmd(['reset', '--hard', self.revision]) 
150              else: 
151                  return self._doFetch(None) 
 152   
153          def checkout(updatable): 
154              if updatable: 
155                  if self.revision: 
156                      d = self._dovccmd(['cat-file', '-e', self.revision]) 
157                  else: 
158                      d = defer.succeed(1) 
159                  d.addCallback(fetch) 
160              else: 
161                  d = self._doFull() 
162              return d 
163   
164          d.addCallback(checkout) 
165          d.addCallback(self._updateSubmodule) 
166          return d 
167   
169          command = ['clean', '-f', '-d'] 
170          d = self._dovccmd(command) 
171          d.addCallback(self._doFetch) 
172          d.addCallback(self._updateSubmodule) 
173          d.addCallback(self._cleanSubmodule) 
174          return d 
 175   
184          d.addCallback(lambda _: checkRemoval(cmd.rc)) 
185          d.addCallback(lambda _: self._doFull()) 
186          return d 
187   
189          command = ['clean', '-f', '-d', '-x'] 
190          d = self._dovccmd(command) 
191          d.addCallback(self._doFetch) 
192          d.addCallback(self._updateSubmodule) 
193          d.addCallback(self._cleanSubmodule) 
194          return d 
 195   
210          d.addCallback(copy) 
211          def resetWorkdir(_): 
212              self.workdir = 'build' 
213              return 0 
214   
215          d.addCallback(resetWorkdir) 
216          return d 
217   
219          d = defer.succeed(res) 
220          def _gotResults(results): 
221              self.setStatus(self.cmd, results) 
222              log.msg("Closing log, sending result of the command %s " % \ 
223                          (self.cmd)) 
224              return results 
 225          d.addCallback(_gotResults) 
226          d.addCallbacks(self.finished, self.checkDisconnect) 
227          return d 
228   
238          d.addCallback(setrev) 
239          return d 
240   
241 -    def _dovccmd(self, command, abandonOnFailure=True): 
 251          d.addCallback(lambda _: evaluateCommand(cmd)) 
252          return d 
253   
255          command = ['fetch', '-t', self.repourl, self.branch] 
256           
257           
258           
259           
260          if self.prog: 
261              command.append('--progress') 
262   
263          d = self._dovccmd(command) 
264          def checkout(_): 
265              if self.revision: 
266                  rev = self.revision 
267              else: 
268                  rev = 'FETCH_HEAD' 
269              command = ['reset', '--hard', rev] 
270              abandonOnFailure = not self.retryFetch and not self.clobberOnFailure 
271              return self._dovccmd(command, abandonOnFailure) 
 272          d.addCallback(checkout) 
273          return d 
274   
275      @defer.deferredGenerator 
277          """ 
278          Handles fallbacks for failure of fetch, 
279          wrapper for self._fetch 
280          """ 
281          wfd = defer.waitForDeferred(self._fetch(None)) 
282          yield wfd 
283          res = wfd.getResult() 
284          if res == 0: 
285              yield res 
286              return 
287          elif self.retryFetch: 
288              d = self._fetch(None) 
289          elif self.clobberOnFailure: 
290              d = self.clobber() 
291          else: 
292              raise failure.Failure(res) 
293   
294          wfd = defer.waitForDeferred(d) 
295          yield wfd 
296          res = wfd.getResult() 
 297   
299          if self.shallow: 
300              command = ['clone', '--depth', '1', self.repourl, '.'] 
301          else: 
302              command = ['clone', self.repourl, '.'] 
303           
304          if self.prog: 
305              command.append('--progress') 
306   
307          d = self._dovccmd(command, not self.clobberOnFailure) 
308           
309          if self.revision: 
310              d.addCallback(lambda _: self._dovccmd(['reset', '--hard', 
311                                                     self.revision], 
312                                                    not self.clobberOnFailure)) 
313           
314           
315          if self.submodule: 
316              d.addCallback(lambda _: self._dovccmd(['submodule', 'update', 
317                                                     '--init', '--recursive'], 
318                                                    not self.clobberOnFailure)) 
319          return d 
 320   
322          d = self._full() 
323          def clobber(res): 
324              if res != 0: 
325                  if self.clobberOnFailure: 
326                      return self.clobber() 
327                  else: 
328                      raise failure.Failure(res) 
329              else: 
330                  return res 
 331          d.addCallback(clobber) 
332          return d 
333   
338   
348          d.addCallback(_fail) 
349          return d 
350   
352          if self.submodule: 
353              return self._dovccmd(['submodule', 'update', '--recursive']) 
354          else: 
355              return defer.succeed(0) 
 356   
358          if self.submodule: 
359              command = ['submodule', 'foreach', 'git', 'clean', '-f', '-d'] 
360              if self.mode == 'full' and self.method == 'fresh': 
361                  command.append('-x') 
362              return self._dovccmd(command) 
363          else: 
364              return defer.succeed(0) 
 365   
367          if self.method is not None and self.mode != 'incremental': 
368              return self.method 
369          elif self.mode == 'incremental': 
370              return None 
371          elif self.method is None and self.mode == 'full': 
372              return 'fresh' 
 373   
375          d = self._dovccmd(['--version']) 
376          def check(res): 
377              if res == 0: 
378                  return True 
379              return False 
 380          d.addCallback(check) 
381          return d 
382