1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 from twisted.python import log
19 from twisted.internet import defer
20
21 from buildbot.process import buildstep
22 from buildbot.steps.source import Source
23 from buildbot.interfaces import BuildSlaveTooOldError
24 from buildbot.config import ConfigErrors
27 """ Class for Mercurial with all the smarts """
28 name = "hg"
29
30 renderables = [ "repourl" ]
31 possible_modes = ('incremental', 'full')
32 possible_methods = (None, 'clean', 'fresh', 'clobber')
33 possible_branchTypes = ('inrepo', 'dirname')
34
35 - def __init__(self, repourl=None, mode='incremental',
36 method=None, defaultBranch=None, branchType='dirname',
37 clobberOnBranchChange=True, **kwargs):
38
39 """
40 @type repourl: string
41 @param repourl: the URL which points at the Mercurial repository.
42 if 'dirname' branches are enabled, this is the base URL
43 to which a branch name will be appended. It should
44 probably end in a slash.
45
46 @param defaultBranch: if branches are enabled, this is the branch
47 to use if the Build does not specify one
48 explicitly.
49 For 'dirname' branches, It will simply be
50 appended to C{repourl} and the result handed to
51 the 'hg update' command.
52 For 'inrepo' branches, this specifies the named
53 revision to which the tree will update after a
54 clone.
55
56 @param branchType: either 'dirname' or 'inrepo' depending on whether
57 the branch name should be appended to the C{repourl}
58 or the branch is a mercurial named branch and can be
59 found within the C{repourl}
60
61 @param clobberOnBranchChange: boolean, defaults to True. If set and
62 using inrepos branches, clobber the tree
63 at each branch change. Otherwise, just
64 update to the branch.
65 """
66
67 self.repourl = repourl
68 self.defaultBranch = self.branch = defaultBranch
69 self.branchType = branchType
70 self.method = method
71 self.clobberOnBranchChange = clobberOnBranchChange
72 self.mode = mode
73 Source.__init__(self, **kwargs)
74 self.addFactoryArguments(repourl=repourl,
75 mode=mode,
76 method=method,
77 defaultBranch=defaultBranch,
78 branchType=branchType,
79 clobberOnBranchChange=
80 clobberOnBranchChange,
81 )
82
83 errors = []
84 if self.mode not in self.possible_modes:
85 errors.append("mode %s is not one of %s" %
86 (self.mode, self.possible_modes))
87 if self.method not in self.possible_methods:
88 errors.append("method %s is not one of %s" %
89 (self.method, self.possible_methods))
90 if self.branchType not in self.possible_branchTypes:
91 errors.append("branchType %s is not one of %s" %
92 (self.branchType, self.possible_branchTypes))
93
94 if repourl is None:
95 errors.append("you must privide a repourl")
96
97 if errors:
98 raise ConfigErrors(errors)
99
100 - def startVC(self, branch, revision, patch):
101 self.revision = revision
102 self.method = self._getMethod()
103 self.stdio_log = self.addLog("stdio")
104 d = self.checkHg()
105 def checkInstall(hgInstalled):
106 if not hgInstalled:
107 raise BuildSlaveTooOldError("Mercurial is not installed on slave")
108 return 0
109
110 if self.branchType == 'dirname':
111 self.repourl = self.repourl + (branch or '')
112 self.branch = self.defaultBranch
113 self.update_branch = branch
114 elif self.branchType == 'inrepo':
115 self.update_branch = (branch or 'default')
116
117 if self.mode == 'full':
118 d.addCallback(lambda _: self.full())
119 elif self.mode == 'incremental':
120 d.addCallback(lambda _: self.incremental())
121 d.addCallback(self.parseGotRevision)
122 d.addCallback(self.finish)
123 d.addErrback(self.failed)
124
125 @defer.deferredGenerator
127 if self.method == 'clobber':
128 d = self.clobber(None)
129 wfd = defer.waitForDeferred(d)
130 yield wfd
131 wfd.getResult()
132 return
133
134 wfd = defer.waitForDeferred(self._sourcedirIsUpdatable())
135 yield wfd
136 updatable = wfd.getResult()
137 if not updatable:
138 d = self._dovccmd(['clone', self.repourl, '.'])
139 elif self.method == 'clean':
140 d = self.clean(None)
141 elif self.method == 'fresh':
142 d = self.fresh(None)
143 wfd = defer.waitForDeferred(d)
144 yield wfd
145 wfd.getResult()
146
148 if self.method is not None:
149 raise ValueError(self.method)
150
151 d = self._sourcedirIsUpdatable()
152 def _cmd(updatable):
153 if updatable:
154 command = ['pull', self.repourl, '--update']
155 else:
156 command = ['clone', self.repourl, '.', '--noupdate']
157 return command
158
159 d.addCallback(_cmd)
160 d.addCallback(self._dovccmd)
161 d.addCallback(self._checkBranchChange)
162 return d
163
165 command = ['--config', 'extensions.purge=', 'purge']
166 d = self._dovccmd(command)
167 d.addCallback(self._pullUpdate)
168 return d
169
171 cmd = buildstep.RemoteCommand('rmdir', {'dir': self.workdir,
172 'logEnviron':self.logEnviron})
173 cmd.useLog(self.stdio_log, False)
174 d = self.runCommand(cmd)
175 d.addCallback(lambda _: self._dovccmd(['clone', '--noupdate'
176 , self.repourl, "."]))
177 d.addCallback(self._update)
178 return d
179
181 command = ['--config', 'extensions.purge=', 'purge', '--all']
182 d = self._dovccmd(command)
183 d.addCallback(self._pullUpdate)
184 return d
185
191 d.addCallback(_gotResults)
192 d.addCallbacks(self.finished, self.checkDisconnect)
193 return d
194
196 d = self._dovccmd(['identify', '--id', '--debug'], collectStdout=True)
197 def _setrev(stdout):
198 revision = stdout.strip()
199 if len(revision) != 40:
200 raise ValueError("Incorrect revision id")
201 log.msg("Got Mercurial revision %s" % (revision, ))
202 self.setProperty('got_revision', revision, 'Source')
203 return 0
204 d.addCallback(_setrev)
205 return d
206
207 @defer.deferredGenerator
209 d = self._getCurrentBranch()
210 wfd = defer.waitForDeferred(d)
211 yield wfd
212 current_branch = wfd.getResult()
213 msg = "Working dir is on in-repo branch '%s' and build needs '%s'." % \
214 (current_branch, self.update_branch)
215 if current_branch != self.update_branch:
216 if self.clobberOnBranchChange:
217 msg += ' Clobbering.'
218 log.msg(msg)
219 d = self.clobber(None)
220 else:
221 msg += ' Updating.'
222 log.msg(msg)
223 d = self._update(None)
224 else:
225 msg += ' Updating.'
226 log.msg(msg)
227 d = self._update(None)
228
229 wfd = defer.waitForDeferred(d)
230 yield wfd
231 wfd.getResult()
232
234 command = ['pull' , self.repourl]
235 if self.revision:
236 command.extend(['--rev', self.revision])
237 d = self._dovccmd(command)
238 d.addCallback(self._checkBranchChange)
239 return d
240
241 - def _dovccmd(self, command, collectStdout=False):
259 d.addCallback(lambda _: evaluateCommand(cmd))
260 return d
261
263 if not changes:
264 return None
265
266
267
268
269 if len(changes) > 1:
270 log.msg("Mercurial.computeSourceRevision: warning: "
271 "there are %d changes here, assuming the last one is "
272 "the most recent" % len(changes))
273 return changes[-1].revision
274
276 if self.branchType == 'dirname':
277 return defer.succeed(self.branch)
278 else:
279 d = self._dovccmd(['identify', '--branch'], collectStdout=True)
280 def _getbranch(stdout):
281 return stdout.strip()
282 d.addCallback(_getbranch).addErrback
283 return d
284
286 if self.method is not None and self.mode != 'incremental':
287 return self.method
288 elif self.mode == 'incremental':
289 return None
290 elif self.method is None and self.mode == 'full':
291 return 'fresh'
292
302 d.addCallback(_fail)
303 return d
304
311
313 d = self._dovccmd(['--version'])
314 def check(res):
315 if res == 0:
316 return True
317 return False
318 d.addCallback(check)
319 return d
320