1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 from twisted.python import log, failure
19 from twisted.internet import defer
20
21 from buildbot.process import buildstep
22 from buildbot.steps.source import Source, _ComputeRepositoryURL
23 from buildbot.interfaces import BuildSlaveTooOldError
26 """ Class for Mercurial with all the smarts """
27 name = "hg"
28
29 renderables = [ "repourl", "baseURL" ]
30
31 - def __init__(self, repourl=None, baseURL=None, mode='incremental',
32 method=None, defaultBranch=None, branchType='dirname',
33 clobberOnBranchChange=True, **kwargs):
34
35 """
36 @type repourl: string
37 @param repourl: the URL which points at the Mercurial repository.
38 This uses the 'default' branch unless defaultBranch is
39 specified below and the C{branchType} is set to
40 'inrepo'. It is an error to specify a branch without
41 setting the C{branchType} to 'inrepo'.
42
43 @param baseURL: if 'dirname' branches are enabled, this is the base URL
44 to which a branch name will be appended. It should
45 probably end in a slash. Use exactly one of C{repourl}
46 and C{baseURL}.
47
48 @param defaultBranch: if branches are enabled, this is the branch
49 to use if the Build does not specify one
50 explicitly.
51 For 'dirname' branches, It will simply be
52 appended to C{baseURL} and the result handed to
53 the 'hg update' command.
54 For 'inrepo' branches, this specifies the named
55 revision to which the tree will update after a
56 clone.
57
58 @param branchType: either 'dirname' or 'inrepo' depending on whether
59 the branch name should be appended to the C{baseURL}
60 or the branch is a mercurial named branch and can be
61 found within the C{repourl}
62
63 @param clobberOnBranchChange: boolean, defaults to True. If set and
64 using inrepos branches, clobber the tree
65 at each branch change. Otherwise, just
66 update to the branch.
67 """
68
69 self.repourl = repourl
70 self.baseURL = baseURL
71 self.defaultBranch = self.branch = defaultBranch
72 self.branchType = branchType
73 self.method = method
74 self.clobberOnBranchChange = clobberOnBranchChange
75 Source.__init__(self, **kwargs)
76 self.mode = mode
77 self.addFactoryArguments(repourl=repourl,
78 baseURL=baseURL,
79 mode=mode,
80 method=method,
81 defaultBranch=defaultBranch,
82 branchType=branchType,
83 clobberOnBranchChange=
84 clobberOnBranchChange,
85 )
86
87 assert self.mode in ['incremental', 'full']
88
89 if repourl and baseURL:
90 raise ValueError("you must provide exactly one of repourl and"
91 " baseURL")
92
93 if repourl is None and baseURL is None:
94 raise ValueError("you must privide at least one of repourl and"
95 " baseURL")
96
97 self.repourl = self.repourl and _ComputeRepositoryURL(self.repourl)
98 self.baseURL = self.baseURL and _ComputeRepositoryURL(self.baseURL)
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 assert self.repourl is None
112 self.repourl = self.baseURL + (branch or '')
113 self.branch = self.defaultBranch
114 self.update_branch = branch
115 elif self.branchType == 'inrepo':
116 assert self.baseURL is None
117 self.update_branch = (branch or 'default')
118 else:
119 raise ValueError("Invalid branch type")
120
121 if self.mode == 'full':
122 d.addCallback(lambda _: self.full())
123 elif self.mode == 'incremental':
124 d.addCallback(lambda _: self.incremental())
125 d.addCallback(self.parseGotRevision)
126 d.addCallback(self.finish)
127 d.addErrback(self.failed)
128
129 @defer.deferredGenerator
131 if self.method == 'clobber':
132 d = self.clobber(None)
133 wfd = defer.waitForDeferred(d)
134 yield wfd
135 return
136
137 wfd = defer.waitForDeferred(self._sourcedirIsUpdatable())
138 yield wfd
139 updatable = wfd.getResult()
140 if not updatable:
141 d = self._dovccmd(['clone', self.repourl, '.'])
142 elif self.method == 'clean':
143 d = self.clean(None)
144 elif self.method == 'fresh':
145 d = self.fresh(None)
146 else:
147 raise ValueError("Unknow method, check your configuration")
148 wfd = defer.waitForDeferred(d)
149 yield wfd
150
152 if self.method is not None:
153 raise ValueError(self.method)
154
155 d = self._sourcedirIsUpdatable()
156 def _cmd(updatable):
157 if updatable:
158 command = ['pull', self.repourl, '--update']
159 else:
160 command = ['clone', self.repourl, '.', '--noupdate']
161 return command
162
163 d.addCallback(_cmd)
164 d.addCallback(self._dovccmd)
165 d.addCallback(self._checkBranchChange)
166 return d
167
169 command = ['--config', 'extensions.purge=', 'purge']
170 d = self._dovccmd(command)
171 d.addCallback(self._pullUpdate)
172 return d
173
182
184 command = ['--config', 'extensions.purge=', 'purge', '--all']
185 d = self._dovccmd(command)
186 d.addCallback(self._pullUpdate)
187 return d
188
194 d.addCallback(_gotResults)
195 d.addCallbacks(self.finished, self.checkDisconnect)
196 return d
197
199 d = self._dovccmd(['identify', '--id', '--debug'])
200 def _setrev(res):
201 revision = self.getLog('stdio').readlines()[-1].strip()
202 if len(revision) != 40:
203 raise ValueError("Incorrect revision id")
204 log.msg("Got Mercurial revision %s" % (revision, ))
205 self.setProperty('got_revision', revision, 'Source')
206 return res
207 d.addCallback(_setrev)
208 return d
209
210 @defer.deferredGenerator
212 d = self._getCurrentBranch()
213 wfd = defer.waitForDeferred(d)
214 yield wfd
215 current_branch = wfd.getResult()
216 msg = "Working dir is on in-repo branch '%s' and build needs '%s'." % \
217 (current_branch, self.update_branch)
218 if current_branch != self.update_branch:
219 if self.clobberOnBranchChange:
220 msg += ' Clobbering.'
221 log.msg(msg)
222 d = self.clobber(None)
223 else:
224 msg += ' Updating.'
225 log.msg(msg)
226 d = self._update(None)
227 else:
228 msg += ' Updating.'
229 log.msg(msg)
230 d = self._update(None)
231
232 wfd = defer.waitForDeferred(d)
233 yield wfd
234
236 command = ['pull' , self.repourl]
237 if self.revision:
238 command.extend(['--rev', self.revision])
239 d = self._dovccmd(command)
240 d.addCallback(self._checkBranchChange)
241 return d
242
255 d.addCallback(lambda _: evaluateCommand(cmd))
256 return d
257
259 if not changes:
260 return None
261
262
263
264
265 if len(changes) > 1:
266 log.msg("Mercurial.computeSourceRevision: warning: "
267 "there are %d changes here, assuming the last one is "
268 "the most recent" % len(changes))
269 return changes[-1].revision
270
272 if self.branchType == 'dirname':
273 return defer.succeed(self.branch)
274 else:
275 d = self._dovccmd(['identify', '--branch'])
276 def _getbranch(res):
277 branch = self.getLog('stdio').readlines()[-1].strip()
278 return branch
279 d.addCallback(_getbranch).addErrback
280 return d
281
283 if self.method is not None and self.mode != 'incremental':
284 return self.method
285 elif self.mode == 'incremental':
286 return None
287 elif self.method is None and self.mode == 'full':
288 return 'fresh'
289
298 d.addCallback(_fail)
299 return d
300
307
309 d = self._dovccmd(['--version'])
310 def check(res):
311 if res == 0:
312 return True
313 return False
314 d.addCallback(check)
315 return d
316