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, "parents", "--template", "{node}\\n"]
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