1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16  import os, re 
 17   
 18  from twisted.python import log, runtime 
 19   
 20  from buildslave.commands.base import SourceBaseCommand, AbandonChain 
 21  from buildslave import runprocess 
 22  from buildslave.util import remove_userpassword 
 23   
 24   
 26      """Mercurial specific VC operation. In addition to the arguments 
 27      handled by SourceBaseCommand, this command reads the following keys: 
 28   
 29      ['repourl'] (required): the Mercurial repository string 
 30      ['clobberOnBranchChange']: Document me. See ticket #462. 
 31      """ 
 32   
 33      header = "mercurial operation" 
 34   
 36          SourceBaseCommand.setup(self, args) 
 37          self.repourl = args['repourl'] 
 38          self.clobberOnBranchChange = args.get('clobberOnBranchChange', True) 
 39          self.sourcedata = "%s\n" % self.repourl 
 40          self.branchType = args.get('branchType', 'dirname') 
 41          self.stdout = "" 
 42          self.stderr = "" 
 43          self.clobbercount = 0  
  44   
 48   
 50          hg = self.getCommand('hg') 
 51          d = os.path.join(self.builder.basedir, self.srcdir) 
 52          command = [hg, 'pull', '--verbose', self.repourl] 
 53          c = runprocess.RunProcess(self.builder, command, d, 
 54                           sendRC=False, timeout=self.timeout, 
 55                           maxTime=self.maxTime, keepStdout=True, 
 56                           logEnviron=self.logEnviron, usePTY=False) 
 57          self.command = c 
 58          d = c.start() 
 59          d.addCallback(self._handleEmptyUpdate) 
 60          d.addCallback(self._update) 
 61          return d 
  62   
 64          if type(res) is int and res == 1: 
 65              if self.command.stdout.find("no changes found") != -1: 
 66                   
 67                   
 68                   
 69                   
 70                  return 0 
 71          return res 
  72   
 74          hg = self.getCommand('hg') 
 75          command = [hg, 'clone', '--verbose', '--noupdate'] 
 76   
 77           
 78           
 79          if self.args.get('revision') and self.mode == 'clobber' and self.branchType == 'dirname': 
 80              command.extend(['--rev', self.args.get('revision')]) 
 81          command.extend([self.repourl, self.srcdir]) 
 82   
 83          c = runprocess.RunProcess(self.builder, command, self.builder.basedir, 
 84                           sendRC=False, timeout=self.timeout, 
 85                           maxTime=self.maxTime, logEnviron=self.logEnviron, 
 86                           usePTY=False) 
 87          self.command = c 
 88          cmd1 = c.start() 
 89          cmd1.addCallback(self._update) 
 90          return cmd1 
  91   
 93          self.clobbercount += 1 
 94   
 95          if self.clobbercount > 3: 
 96              raise Exception, "Too many clobber attempts. Aborting step" 
 97   
 98          def _vcfull(res): 
 99              return self.doVCFull() 
 100   
101          c = self.doClobber(dummy, dirname) 
102          c.addCallback(_vcfull) 
103   
104          return c 
 105   
106 -    def _purge(self, dummy, dirname): 
 107          hg = self.getCommand('hg') 
108          d = os.path.join(self.builder.basedir, self.srcdir) 
109          purge = [hg, 'purge', '--all'] 
110          purgeCmd = runprocess.RunProcess(self.builder, purge, d, 
111                                  keepStdout=True, keepStderr=True, 
112                                  logEnviron=self.logEnviron, usePTY=False) 
113   
114          def _clobber(res): 
115              if res != 0: 
116                   
117                  msg = "'hg purge' failed: %s\n%s. Clobbering." % (purgeCmd.stdout, purgeCmd.stderr) 
118                  self.sendStatus({'header': msg + "\n"}) 
119                  log.msg(msg) 
120   
121                  return self._clobber(dummy, dirname) 
122   
123               
124              return res 
 125   
126          p = purgeCmd.start() 
127          p.addCallback(_clobber) 
128          return p 
129   
131          hg = self.getCommand('hg') 
132          if res != 0: 
133              return res 
134   
135           
136          self.update_branch = self.args.get('branch',  'default') 
137   
138          d = os.path.join(self.builder.basedir, self.srcdir) 
139          parentscmd = [hg, 'identify', '--num', '--branch'] 
140          cmd = runprocess.RunProcess(self.builder, parentscmd, d, 
141                             sendRC=False, timeout=self.timeout, keepStdout=True, 
142                             keepStderr=True, logEnviron=self.logEnviron, 
143                             usePTY=False) 
144   
145          self.clobber = None 
146   
147          def _parseIdentify(res): 
148              if res != 0: 
149                  msg = "'hg identify' failed." 
150                  self.sendStatus({'header': msg + "\n"}) 
151                  log.msg(msg) 
152                  raise AbandonChain(-1) 
153   
154              log.msg('Output: %s' % cmd.stdout) 
155   
156              match = re.search(r'^(.+) (.+)$', cmd.stdout) 
157              if not match: 
158                  msg = "'hg identify' did not give a recognizable output" 
159                  self.sendStatus({'header': msg + "\n"}) 
160                  log.msg(msg) 
161                  raise AbandonChain(-1) 
162   
163              rev = match.group(1) 
164              current_branch = match.group(2) 
165   
166              if rev == '-1': 
167                  msg = "Fresh hg repo, don't worry about in-repo branch name" 
168                  log.msg(msg) 
169   
170              elif self.sourcedirIsPatched(): 
171                  self.clobber = self._purge 
172   
173              elif self.update_branch != current_branch: 
174                  msg = "Working dir is on in-repo branch '%s' and build needs '%s'." % (current_branch, self.update_branch) 
175                  if self.clobberOnBranchChange: 
176                      msg += ' Cloberring.' 
177                  else: 
178                      msg += ' Updating.' 
179   
180                  self.sendStatus({'header': msg + "\n"}) 
181                  log.msg(msg) 
182   
183                   
184                  if self.clobberOnBranchChange: 
185                      self.clobber = self._purge 
186   
187              else: 
188                  msg = "Working dir on same in-repo branch as build (%s)." % (current_branch) 
189                  log.msg(msg) 
190   
191              return 0 
 192   
193          def _checkRepoURL(res): 
194              hg = self.getCommand('hg') 
195              parentscmd = [hg, 'paths', 'default'] 
196              cmd2 = runprocess.RunProcess(self.builder, parentscmd, d, 
197                                 keepStdout=True, keepStderr=True, usePTY=False, 
198                                 timeout=self.timeout, sendRC=False, 
199                                 logEnviron=self.logEnviron) 
200   
201              def _parseRepoURL(res): 
202                  if res == 1: 
203                      if "not found!" == cmd2.stderr.strip(): 
204                          msg = "hg default path not set. Not checking repo url for clobber test" 
205                          log.msg(msg) 
206                          return 0 
207                      else: 
208                          msg = "'hg paths default' failed." 
209                          log.msg(msg) 
210                          return 1 
211   
212                  oldurl = cmd2.stdout.strip() 
213   
214                  log.msg("Repo cloned from: '%s'" % oldurl) 
215   
216                  if runtime.platformType  == 'win32': 
217                      oldurl = oldurl.lower().replace('\\', '/') 
218                      repourl = self.repourl.lower().replace('\\', '/') 
219                  else: 
220                      repourl = self.repourl 
221   
222                  if repourl.startswith('file://'): 
223                      repourl = repourl.split('file://')[1] 
224                  if oldurl.startswith('file://'): 
225                      oldurl = oldurl.split('file://')[1] 
226   
227                  oldurl = remove_userpassword(oldurl) 
228                  repourl = remove_userpassword(repourl) 
229   
230                  if oldurl.rstrip('/') != repourl.rstrip('/'): 
231                      self.clobber = self._clobber 
232                      msg = "RepoURL changed from '%s' in wc to '%s' in update. Clobbering" % (oldurl, repourl) 
233                      log.msg(msg) 
234   
235                  return 0 
236   
237              c = cmd2.start() 
238              c.addCallback(_parseRepoURL) 
239              return c 
240   
241          def _maybeClobber(res): 
242              if self.clobber: 
243                  msg = "Clobber flag set. Doing clobbering" 
244                  log.msg(msg) 
245   
246                  return self.clobber(None, self.srcdir) 
247   
248              return 0 
249   
250          c = cmd.start() 
251          c.addCallback(_parseIdentify) 
252          c.addCallback(_checkRepoURL) 
253          c.addCallback(_maybeClobber) 
254          c.addCallback(self._update2) 
255          return c 
256   
258          hg = self.getCommand('hg') 
259          updatecmd=[hg, 'update', '--clean', '--repository', self.srcdir] 
260          if self.args.get('revision'): 
261              updatecmd.extend(['--rev', self.args['revision']]) 
262          else: 
263              updatecmd.extend(['--rev', self.args.get('branch',  'default')]) 
264          self.command = runprocess.RunProcess(self.builder, updatecmd, 
265              self.builder.basedir, sendRC=False, 
266              timeout=self.timeout, maxTime=self.maxTime, 
267              logEnviron=self.logEnviron, usePTY=False) 
268          return self.command.start() 
 269   
271          hg = self.getCommand('hg') 
272           
273          command = [hg, "identify", "--id", "--debug"]  
274          c = runprocess.RunProcess(self.builder, command, 
275                           os.path.join(self.builder.basedir, self.srcdir), 
276                           environ=self.env, timeout=self.timeout, 
277                           sendRC=False, 
278                           keepStdout=True, usePTY=False, 
279                           logEnviron=self.logEnviron) 
280          d = c.start() 
281          def _parse(res): 
282              m = re.search(r'^(\w+)', c.stdout) 
283              return m.group(1) 
 284          d.addCallback(_parse) 
285          return d 
286