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