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