##// END OF EJS Templates
Mercurial: fixed lookup for hg 4.9
marcink -
r657:377e31e9 default
parent child Browse files
Show More
@@ -1,803 +1,801 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2019 RhodeCode GmbH
2 # Copyright (C) 2014-2019 RhodeCode GmbH
3 #
3 #
4 # This program is free software; you can redistribute it and/or modify
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
7 # (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import io
18 import io
19 import logging
19 import logging
20 import stat
20 import stat
21 import urllib
21 import urllib
22 import urllib2
22 import urllib2
23 import traceback
23
24
24 from hgext import largefiles, rebase
25 from hgext import largefiles, rebase
25 from hgext.strip import strip as hgext_strip
26 from hgext.strip import strip as hgext_strip
26 from mercurial import commands
27 from mercurial import commands
27 from mercurial import unionrepo
28 from mercurial import unionrepo
28 from mercurial import verify
29 from mercurial import verify
29
30
30 import vcsserver
31 import vcsserver
31 from vcsserver import exceptions
32 from vcsserver import exceptions
32 from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original
33 from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original
33 from vcsserver.hgcompat import (
34 from vcsserver.hgcompat import (
34 archival, bin, clone, config as hgconfig, diffopts, hex,
35 archival, bin, clone, config as hgconfig, diffopts, hex, revsymbol,
35 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
36 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
36 makepeer, instance, match, memctx, exchange, memfilectx, nullrev,
37 makepeer, instance, match, memctx, exchange, memfilectx, nullrev,
37 patch, peer, revrange, ui, hg_tag, Abort, LookupError, RepoError,
38 patch, peer, revrange, ui, hg_tag, Abort, LookupError, RepoError,
38 RepoLookupError, InterventionRequired, RequirementError)
39 RepoLookupError, ProgrammingError, InterventionRequired, RequirementError)
39
40
40 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
41
42
42
43
43 def make_ui_from_config(repo_config):
44 def make_ui_from_config(repo_config):
44 baseui = ui.ui()
45 baseui = ui.ui()
45
46
46 # clean the baseui object
47 # clean the baseui object
47 baseui._ocfg = hgconfig.config()
48 baseui._ocfg = hgconfig.config()
48 baseui._ucfg = hgconfig.config()
49 baseui._ucfg = hgconfig.config()
49 baseui._tcfg = hgconfig.config()
50 baseui._tcfg = hgconfig.config()
50
51
51 for section, option, value in repo_config:
52 for section, option, value in repo_config:
52 baseui.setconfig(section, option, value)
53 baseui.setconfig(section, option, value)
53
54
54 # make our hgweb quiet so it doesn't print output
55 # make our hgweb quiet so it doesn't print output
55 baseui.setconfig('ui', 'quiet', 'true')
56 baseui.setconfig('ui', 'quiet', 'true')
56
57
57 baseui.setconfig('ui', 'paginate', 'never')
58 baseui.setconfig('ui', 'paginate', 'never')
59 # for better Error reporting of Mercurial
60 baseui.setconfig('ui', 'message-output', 'stderr')
61
58 # force mercurial to only use 1 thread, otherwise it may try to set a
62 # force mercurial to only use 1 thread, otherwise it may try to set a
59 # signal in a non-main thread, thus generating a ValueError.
63 # signal in a non-main thread, thus generating a ValueError.
60 baseui.setconfig('worker', 'numcpus', 1)
64 baseui.setconfig('worker', 'numcpus', 1)
61
65
62 # If there is no config for the largefiles extension, we explicitly disable
66 # If there is no config for the largefiles extension, we explicitly disable
63 # it here. This overrides settings from repositories hgrc file. Recent
67 # it here. This overrides settings from repositories hgrc file. Recent
64 # mercurial versions enable largefiles in hgrc on clone from largefile
68 # mercurial versions enable largefiles in hgrc on clone from largefile
65 # repo.
69 # repo.
66 if not baseui.hasconfig('extensions', 'largefiles'):
70 if not baseui.hasconfig('extensions', 'largefiles'):
67 log.debug('Explicitly disable largefiles extension for repo.')
71 log.debug('Explicitly disable largefiles extension for repo.')
68 baseui.setconfig('extensions', 'largefiles', '!')
72 baseui.setconfig('extensions', 'largefiles', '!')
69
73
70 return baseui
74 return baseui
71
75
72
76
73 def reraise_safe_exceptions(func):
77 def reraise_safe_exceptions(func):
74 """Decorator for converting mercurial exceptions to something neutral."""
78 """Decorator for converting mercurial exceptions to something neutral."""
75 def wrapper(*args, **kwargs):
79 def wrapper(*args, **kwargs):
76 try:
80 try:
77 return func(*args, **kwargs)
81 return func(*args, **kwargs)
78 except (Abort, InterventionRequired) as e:
82 except (Abort, InterventionRequired) as e:
79 raise_from_original(exceptions.AbortException(e))
83 raise_from_original(exceptions.AbortException(e))
80 except RepoLookupError as e:
84 except RepoLookupError as e:
81 raise_from_original(exceptions.LookupException(e))
85 raise_from_original(exceptions.LookupException(e))
82 except RequirementError as e:
86 except RequirementError as e:
83 raise_from_original(exceptions.RequirementException(e))
87 raise_from_original(exceptions.RequirementException(e))
84 except RepoError as e:
88 except RepoError as e:
85 raise_from_original(exceptions.VcsException(e))
89 raise_from_original(exceptions.VcsException(e))
86 except LookupError as e:
90 except LookupError as e:
87 raise_from_original(exceptions.LookupException(e))
91 raise_from_original(exceptions.LookupException(e))
88 except Exception as e:
92 except Exception as e:
89 if not hasattr(e, '_vcs_kind'):
93 if not hasattr(e, '_vcs_kind'):
90 log.exception("Unhandled exception in hg remote call")
94 log.exception("Unhandled exception in hg remote call")
91 raise_from_original(exceptions.UnhandledException(e))
95 raise_from_original(exceptions.UnhandledException(e))
92
96
93 raise
97 raise
94 return wrapper
98 return wrapper
95
99
96
100
97 class MercurialFactory(RepoFactory):
101 class MercurialFactory(RepoFactory):
98 repo_type = 'hg'
102 repo_type = 'hg'
99
103
100 def _create_config(self, config, hooks=True):
104 def _create_config(self, config, hooks=True):
101 if not hooks:
105 if not hooks:
102 hooks_to_clean = frozenset((
106 hooks_to_clean = frozenset((
103 'changegroup.repo_size', 'preoutgoing.pre_pull',
107 'changegroup.repo_size', 'preoutgoing.pre_pull',
104 'outgoing.pull_logger', 'prechangegroup.pre_push'))
108 'outgoing.pull_logger', 'prechangegroup.pre_push'))
105 new_config = []
109 new_config = []
106 for section, option, value in config:
110 for section, option, value in config:
107 if section == 'hooks' and option in hooks_to_clean:
111 if section == 'hooks' and option in hooks_to_clean:
108 continue
112 continue
109 new_config.append((section, option, value))
113 new_config.append((section, option, value))
110 config = new_config
114 config = new_config
111
115
112 baseui = make_ui_from_config(config)
116 baseui = make_ui_from_config(config)
113 return baseui
117 return baseui
114
118
115 def _create_repo(self, wire, create):
119 def _create_repo(self, wire, create):
116 baseui = self._create_config(wire["config"])
120 baseui = self._create_config(wire["config"])
117 return instance(baseui, wire["path"], create)
121 return instance(baseui, wire["path"], create)
118
122
119
123
120 class HgRemote(object):
124 class HgRemote(object):
121
125
122 def __init__(self, factory):
126 def __init__(self, factory):
123 self._factory = factory
127 self._factory = factory
124
128
125 self._bulk_methods = {
129 self._bulk_methods = {
126 "affected_files": self.ctx_files,
130 "affected_files": self.ctx_files,
127 "author": self.ctx_user,
131 "author": self.ctx_user,
128 "branch": self.ctx_branch,
132 "branch": self.ctx_branch,
129 "children": self.ctx_children,
133 "children": self.ctx_children,
130 "date": self.ctx_date,
134 "date": self.ctx_date,
131 "message": self.ctx_description,
135 "message": self.ctx_description,
132 "parents": self.ctx_parents,
136 "parents": self.ctx_parents,
133 "status": self.ctx_status,
137 "status": self.ctx_status,
134 "obsolete": self.ctx_obsolete,
138 "obsolete": self.ctx_obsolete,
135 "phase": self.ctx_phase,
139 "phase": self.ctx_phase,
136 "hidden": self.ctx_hidden,
140 "hidden": self.ctx_hidden,
137 "_file_paths": self.ctx_list,
141 "_file_paths": self.ctx_list,
138 }
142 }
139
143
140 @reraise_safe_exceptions
144 @reraise_safe_exceptions
141 def discover_hg_version(self):
145 def discover_hg_version(self):
142 from mercurial import util
146 from mercurial import util
143 return util.version()
147 return util.version()
144
148
145 @reraise_safe_exceptions
149 @reraise_safe_exceptions
146 def archive_repo(self, archive_path, mtime, file_info, kind):
150 def archive_repo(self, archive_path, mtime, file_info, kind):
147 if kind == "tgz":
151 if kind == "tgz":
148 archiver = archival.tarit(archive_path, mtime, "gz")
152 archiver = archival.tarit(archive_path, mtime, "gz")
149 elif kind == "tbz2":
153 elif kind == "tbz2":
150 archiver = archival.tarit(archive_path, mtime, "bz2")
154 archiver = archival.tarit(archive_path, mtime, "bz2")
151 elif kind == 'zip':
155 elif kind == 'zip':
152 archiver = archival.zipit(archive_path, mtime)
156 archiver = archival.zipit(archive_path, mtime)
153 else:
157 else:
154 raise exceptions.ArchiveException()(
158 raise exceptions.ArchiveException()(
155 'Remote does not support: "%s".' % kind)
159 'Remote does not support: "%s".' % kind)
156
160
157 for f_path, f_mode, f_is_link, f_content in file_info:
161 for f_path, f_mode, f_is_link, f_content in file_info:
158 archiver.addfile(f_path, f_mode, f_is_link, f_content)
162 archiver.addfile(f_path, f_mode, f_is_link, f_content)
159 archiver.done()
163 archiver.done()
160
164
161 @reraise_safe_exceptions
165 @reraise_safe_exceptions
162 def bookmarks(self, wire):
166 def bookmarks(self, wire):
163 repo = self._factory.repo(wire)
167 repo = self._factory.repo(wire)
164 return dict(repo._bookmarks)
168 return dict(repo._bookmarks)
165
169
166 @reraise_safe_exceptions
170 @reraise_safe_exceptions
167 def branches(self, wire, normal, closed):
171 def branches(self, wire, normal, closed):
168 repo = self._factory.repo(wire)
172 repo = self._factory.repo(wire)
169 iter_branches = repo.branchmap().iterbranches()
173 iter_branches = repo.branchmap().iterbranches()
170 bt = {}
174 bt = {}
171 for branch_name, _heads, tip, is_closed in iter_branches:
175 for branch_name, _heads, tip, is_closed in iter_branches:
172 if normal and not is_closed:
176 if normal and not is_closed:
173 bt[branch_name] = tip
177 bt[branch_name] = tip
174 if closed and is_closed:
178 if closed and is_closed:
175 bt[branch_name] = tip
179 bt[branch_name] = tip
176
180
177 return bt
181 return bt
178
182
179 @reraise_safe_exceptions
183 @reraise_safe_exceptions
180 def bulk_request(self, wire, rev, pre_load):
184 def bulk_request(self, wire, rev, pre_load):
181 result = {}
185 result = {}
182 for attr in pre_load:
186 for attr in pre_load:
183 try:
187 try:
184 method = self._bulk_methods[attr]
188 method = self._bulk_methods[attr]
185 result[attr] = method(wire, rev)
189 result[attr] = method(wire, rev)
186 except KeyError as e:
190 except KeyError as e:
187 raise exceptions.VcsException(e)(
191 raise exceptions.VcsException(e)(
188 'Unknown bulk attribute: "%s"' % attr)
192 'Unknown bulk attribute: "%s"' % attr)
189 return result
193 return result
190
194
191 @reraise_safe_exceptions
195 @reraise_safe_exceptions
192 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
196 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
193 baseui = self._factory._create_config(wire["config"], hooks=hooks)
197 baseui = self._factory._create_config(wire["config"], hooks=hooks)
194 clone(baseui, source, dest, noupdate=not update_after_clone)
198 clone(baseui, source, dest, noupdate=not update_after_clone)
195
199
196 @reraise_safe_exceptions
200 @reraise_safe_exceptions
197 def commitctx(
201 def commitctx(
198 self, wire, message, parents, commit_time, commit_timezone,
202 self, wire, message, parents, commit_time, commit_timezone,
199 user, files, extra, removed, updated):
203 user, files, extra, removed, updated):
200
204
201 def _filectxfn(_repo, memctx, path):
205 def _filectxfn(_repo, memctx, path):
202 """
206 """
203 Marks given path as added/changed/removed in a given _repo. This is
207 Marks given path as added/changed/removed in a given _repo. This is
204 for internal mercurial commit function.
208 for internal mercurial commit function.
205 """
209 """
206
210
207 # check if this path is removed
211 # check if this path is removed
208 if path in removed:
212 if path in removed:
209 # returning None is a way to mark node for removal
213 # returning None is a way to mark node for removal
210 return None
214 return None
211
215
212 # check if this path is added
216 # check if this path is added
213 for node in updated:
217 for node in updated:
214 if node['path'] == path:
218 if node['path'] == path:
215 return memfilectx(
219 return memfilectx(
216 _repo,
220 _repo,
217 changectx=memctx,
221 changectx=memctx,
218 path=node['path'],
222 path=node['path'],
219 data=node['content'],
223 data=node['content'],
220 islink=False,
224 islink=False,
221 isexec=bool(node['mode'] & stat.S_IXUSR),
225 isexec=bool(node['mode'] & stat.S_IXUSR),
222 copied=False)
226 copied=False)
223
227
224 raise exceptions.AbortException()(
228 raise exceptions.AbortException()(
225 "Given path haven't been marked as added, "
229 "Given path haven't been marked as added, "
226 "changed or removed (%s)" % path)
230 "changed or removed (%s)" % path)
227
231
228 repo = self._factory.repo(wire)
232 repo = self._factory.repo(wire)
229
233
230 commit_ctx = memctx(
234 commit_ctx = memctx(
231 repo=repo,
235 repo=repo,
232 parents=parents,
236 parents=parents,
233 text=message,
237 text=message,
234 files=files,
238 files=files,
235 filectxfn=_filectxfn,
239 filectxfn=_filectxfn,
236 user=user,
240 user=user,
237 date=(commit_time, commit_timezone),
241 date=(commit_time, commit_timezone),
238 extra=extra)
242 extra=extra)
239
243
240 n = repo.commitctx(commit_ctx)
244 n = repo.commitctx(commit_ctx)
241 new_id = hex(n)
245 new_id = hex(n)
242
246
243 return new_id
247 return new_id
244
248
245 @reraise_safe_exceptions
249 @reraise_safe_exceptions
246 def ctx_branch(self, wire, revision):
250 def ctx_branch(self, wire, revision):
247 repo = self._factory.repo(wire)
251 repo = self._factory.repo(wire)
248 ctx = repo[revision]
252 ctx = repo[revision]
249 return ctx.branch()
253 return ctx.branch()
250
254
251 @reraise_safe_exceptions
255 @reraise_safe_exceptions
252 def ctx_children(self, wire, revision):
256 def ctx_children(self, wire, revision):
253 repo = self._factory.repo(wire)
257 repo = self._factory.repo(wire)
254 ctx = repo[revision]
258 ctx = repo[revision]
255 return [child.rev() for child in ctx.children()]
259 return [child.rev() for child in ctx.children()]
256
260
257 @reraise_safe_exceptions
261 @reraise_safe_exceptions
258 def ctx_date(self, wire, revision):
262 def ctx_date(self, wire, revision):
259 repo = self._factory.repo(wire)
263 repo = self._factory.repo(wire)
260 ctx = repo[revision]
264 ctx = repo[revision]
261 return ctx.date()
265 return ctx.date()
262
266
263 @reraise_safe_exceptions
267 @reraise_safe_exceptions
264 def ctx_description(self, wire, revision):
268 def ctx_description(self, wire, revision):
265 repo = self._factory.repo(wire)
269 repo = self._factory.repo(wire)
266 ctx = repo[revision]
270 ctx = repo[revision]
267 return ctx.description()
271 return ctx.description()
268
272
269 # @reraise_safe_exceptions
270 # def ctx_diff(
271 # self, wire, revision, git=True, ignore_whitespace=True, context=3):
272 # repo = self._factory.repo(wire)
273 # ctx = repo[revision]
274 # result = ctx.diff(
275 # git=git, ignore_whitespace=ignore_whitespace, context=context)
276 # return list(result)
277
278 @reraise_safe_exceptions
273 @reraise_safe_exceptions
279 def ctx_files(self, wire, revision):
274 def ctx_files(self, wire, revision):
280 repo = self._factory.repo(wire)
275 repo = self._factory.repo(wire)
281 ctx = repo[revision]
276 ctx = repo[revision]
282 return ctx.files()
277 return ctx.files()
283
278
284 @reraise_safe_exceptions
279 @reraise_safe_exceptions
285 def ctx_list(self, path, revision):
280 def ctx_list(self, path, revision):
286 repo = self._factory.repo(path)
281 repo = self._factory.repo(path)
287 ctx = repo[revision]
282 ctx = repo[revision]
288 return list(ctx)
283 return list(ctx)
289
284
290 @reraise_safe_exceptions
285 @reraise_safe_exceptions
291 def ctx_parents(self, wire, revision):
286 def ctx_parents(self, wire, revision):
292 repo = self._factory.repo(wire)
287 repo = self._factory.repo(wire)
293 ctx = repo[revision]
288 ctx = repo[revision]
294 return [parent.rev() for parent in ctx.parents()]
289 return [parent.rev() for parent in ctx.parents()]
295
290
296 @reraise_safe_exceptions
291 @reraise_safe_exceptions
297 def ctx_phase(self, wire, revision):
292 def ctx_phase(self, wire, revision):
298 repo = self._factory.repo(wire)
293 repo = self._factory.repo(wire)
299 ctx = repo[revision]
294 ctx = repo[revision]
300 # public=0, draft=1, secret=3
295 # public=0, draft=1, secret=3
301 return ctx.phase()
296 return ctx.phase()
302
297
303 @reraise_safe_exceptions
298 @reraise_safe_exceptions
304 def ctx_obsolete(self, wire, revision):
299 def ctx_obsolete(self, wire, revision):
305 repo = self._factory.repo(wire)
300 repo = self._factory.repo(wire)
306 ctx = repo[revision]
301 ctx = repo[revision]
307 return ctx.obsolete()
302 return ctx.obsolete()
308
303
309 @reraise_safe_exceptions
304 @reraise_safe_exceptions
310 def ctx_hidden(self, wire, revision):
305 def ctx_hidden(self, wire, revision):
311 repo = self._factory.repo(wire)
306 repo = self._factory.repo(wire)
312 ctx = repo[revision]
307 ctx = repo[revision]
313 return ctx.hidden()
308 return ctx.hidden()
314
309
315 @reraise_safe_exceptions
310 @reraise_safe_exceptions
316 def ctx_substate(self, wire, revision):
311 def ctx_substate(self, wire, revision):
317 repo = self._factory.repo(wire)
312 repo = self._factory.repo(wire)
318 ctx = repo[revision]
313 ctx = repo[revision]
319 return ctx.substate
314 return ctx.substate
320
315
321 @reraise_safe_exceptions
316 @reraise_safe_exceptions
322 def ctx_status(self, wire, revision):
317 def ctx_status(self, wire, revision):
323 repo = self._factory.repo(wire)
318 repo = self._factory.repo(wire)
324 ctx = repo[revision]
319 ctx = repo[revision]
325 status = repo[ctx.p1().node()].status(other=ctx.node())
320 status = repo[ctx.p1().node()].status(other=ctx.node())
326 # object of status (odd, custom named tuple in mercurial) is not
321 # object of status (odd, custom named tuple in mercurial) is not
327 # correctly serializable, we make it a list, as the underling
322 # correctly serializable, we make it a list, as the underling
328 # API expects this to be a list
323 # API expects this to be a list
329 return list(status)
324 return list(status)
330
325
331 @reraise_safe_exceptions
326 @reraise_safe_exceptions
332 def ctx_user(self, wire, revision):
327 def ctx_user(self, wire, revision):
333 repo = self._factory.repo(wire)
328 repo = self._factory.repo(wire)
334 ctx = repo[revision]
329 ctx = repo[revision]
335 return ctx.user()
330 return ctx.user()
336
331
337 @reraise_safe_exceptions
332 @reraise_safe_exceptions
338 def check_url(self, url, config):
333 def check_url(self, url, config):
339 _proto = None
334 _proto = None
340 if '+' in url[:url.find('://')]:
335 if '+' in url[:url.find('://')]:
341 _proto = url[0:url.find('+')]
336 _proto = url[0:url.find('+')]
342 url = url[url.find('+') + 1:]
337 url = url[url.find('+') + 1:]
343 handlers = []
338 handlers = []
344 url_obj = url_parser(url)
339 url_obj = url_parser(url)
345 test_uri, authinfo = url_obj.authinfo()
340 test_uri, authinfo = url_obj.authinfo()
346 url_obj.passwd = '*****' if url_obj.passwd else url_obj.passwd
341 url_obj.passwd = '*****' if url_obj.passwd else url_obj.passwd
347 url_obj.query = obfuscate_qs(url_obj.query)
342 url_obj.query = obfuscate_qs(url_obj.query)
348
343
349 cleaned_uri = str(url_obj)
344 cleaned_uri = str(url_obj)
350 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
345 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
351
346
352 if authinfo:
347 if authinfo:
353 # create a password manager
348 # create a password manager
354 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
349 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
355 passmgr.add_password(*authinfo)
350 passmgr.add_password(*authinfo)
356
351
357 handlers.extend((httpbasicauthhandler(passmgr),
352 handlers.extend((httpbasicauthhandler(passmgr),
358 httpdigestauthhandler(passmgr)))
353 httpdigestauthhandler(passmgr)))
359
354
360 o = urllib2.build_opener(*handlers)
355 o = urllib2.build_opener(*handlers)
361 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
356 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
362 ('Accept', 'application/mercurial-0.1')]
357 ('Accept', 'application/mercurial-0.1')]
363
358
364 q = {"cmd": 'between'}
359 q = {"cmd": 'between'}
365 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
360 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
366 qs = '?%s' % urllib.urlencode(q)
361 qs = '?%s' % urllib.urlencode(q)
367 cu = "%s%s" % (test_uri, qs)
362 cu = "%s%s" % (test_uri, qs)
368 req = urllib2.Request(cu, None, {})
363 req = urllib2.Request(cu, None, {})
369
364
370 try:
365 try:
371 log.debug("Trying to open URL %s", cleaned_uri)
366 log.debug("Trying to open URL %s", cleaned_uri)
372 resp = o.open(req)
367 resp = o.open(req)
373 if resp.code != 200:
368 if resp.code != 200:
374 raise exceptions.URLError()('Return Code is not 200')
369 raise exceptions.URLError()('Return Code is not 200')
375 except Exception as e:
370 except Exception as e:
376 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
371 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
377 # means it cannot be cloned
372 # means it cannot be cloned
378 raise exceptions.URLError(e)("[%s] org_exc: %s" % (cleaned_uri, e))
373 raise exceptions.URLError(e)("[%s] org_exc: %s" % (cleaned_uri, e))
379
374
380 # now check if it's a proper hg repo, but don't do it for svn
375 # now check if it's a proper hg repo, but don't do it for svn
381 try:
376 try:
382 if _proto == 'svn':
377 if _proto == 'svn':
383 pass
378 pass
384 else:
379 else:
385 # check for pure hg repos
380 # check for pure hg repos
386 log.debug(
381 log.debug(
387 "Verifying if URL is a Mercurial repository: %s",
382 "Verifying if URL is a Mercurial repository: %s",
388 cleaned_uri)
383 cleaned_uri)
389 ui = make_ui_from_config(config)
384 ui = make_ui_from_config(config)
390 peer_checker = makepeer(ui, url)
385 peer_checker = makepeer(ui, url)
391 peer_checker.lookup('tip')
386 peer_checker.lookup('tip')
392 except Exception as e:
387 except Exception as e:
393 log.warning("URL is not a valid Mercurial repository: %s",
388 log.warning("URL is not a valid Mercurial repository: %s",
394 cleaned_uri)
389 cleaned_uri)
395 raise exceptions.URLError(e)(
390 raise exceptions.URLError(e)(
396 "url [%s] does not look like an hg repo org_exc: %s"
391 "url [%s] does not look like an hg repo org_exc: %s"
397 % (cleaned_uri, e))
392 % (cleaned_uri, e))
398
393
399 log.info("URL is a valid Mercurial repository: %s", cleaned_uri)
394 log.info("URL is a valid Mercurial repository: %s", cleaned_uri)
400 return True
395 return True
401
396
402 @reraise_safe_exceptions
397 @reraise_safe_exceptions
403 def diff(
398 def diff(
404 self, wire, rev1, rev2, file_filter, opt_git, opt_ignorews,
399 self, wire, rev1, rev2, file_filter, opt_git, opt_ignorews,
405 context):
400 context):
406 repo = self._factory.repo(wire)
401 repo = self._factory.repo(wire)
407
402
408 if file_filter:
403 if file_filter:
409 match_filter = match(file_filter[0], '', [file_filter[1]])
404 match_filter = match(file_filter[0], '', [file_filter[1]])
410 else:
405 else:
411 match_filter = file_filter
406 match_filter = file_filter
412 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
407 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
413
408
414 try:
409 try:
415 return "".join(patch.diff(
410 return "".join(patch.diff(
416 repo, node1=rev1, node2=rev2, match=match_filter, opts=opts))
411 repo, node1=rev1, node2=rev2, match=match_filter, opts=opts))
417 except RepoLookupError as e:
412 except RepoLookupError as e:
418 raise exceptions.LookupException(e)()
413 raise exceptions.LookupException(e)()
419
414
420 @reraise_safe_exceptions
415 @reraise_safe_exceptions
421 def node_history(self, wire, revision, path, limit):
416 def node_history(self, wire, revision, path, limit):
422 repo = self._factory.repo(wire)
417 repo = self._factory.repo(wire)
423
418
424 ctx = repo[revision]
419 ctx = repo[revision]
425 fctx = ctx.filectx(path)
420 fctx = ctx.filectx(path)
426
421
427 def history_iter():
422 def history_iter():
428 limit_rev = fctx.rev()
423 limit_rev = fctx.rev()
429 for obj in reversed(list(fctx.filelog())):
424 for obj in reversed(list(fctx.filelog())):
430 obj = fctx.filectx(obj)
425 obj = fctx.filectx(obj)
431 if limit_rev >= obj.rev():
426 if limit_rev >= obj.rev():
432 yield obj
427 yield obj
433
428
434 history = []
429 history = []
435 for cnt, obj in enumerate(history_iter()):
430 for cnt, obj in enumerate(history_iter()):
436 if limit and cnt >= limit:
431 if limit and cnt >= limit:
437 break
432 break
438 history.append(hex(obj.node()))
433 history.append(hex(obj.node()))
439
434
440 return [x for x in history]
435 return [x for x in history]
441
436
442 @reraise_safe_exceptions
437 @reraise_safe_exceptions
443 def node_history_untill(self, wire, revision, path, limit):
438 def node_history_untill(self, wire, revision, path, limit):
444 repo = self._factory.repo(wire)
439 repo = self._factory.repo(wire)
445 ctx = repo[revision]
440 ctx = repo[revision]
446 fctx = ctx.filectx(path)
441 fctx = ctx.filectx(path)
447
442
448 file_log = list(fctx.filelog())
443 file_log = list(fctx.filelog())
449 if limit:
444 if limit:
450 # Limit to the last n items
445 # Limit to the last n items
451 file_log = file_log[-limit:]
446 file_log = file_log[-limit:]
452
447
453 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
448 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
454
449
455 @reraise_safe_exceptions
450 @reraise_safe_exceptions
456 def fctx_annotate(self, wire, revision, path):
451 def fctx_annotate(self, wire, revision, path):
457 repo = self._factory.repo(wire)
452 repo = self._factory.repo(wire)
458 ctx = repo[revision]
453 ctx = repo[revision]
459 fctx = ctx.filectx(path)
454 fctx = ctx.filectx(path)
460
455
461 result = []
456 result = []
462 for i, annotate_obj in enumerate(fctx.annotate(), 1):
457 for i, annotate_obj in enumerate(fctx.annotate(), 1):
463 ln_no = i
458 ln_no = i
464 sha = hex(annotate_obj.fctx.node())
459 sha = hex(annotate_obj.fctx.node())
465 content = annotate_obj.text
460 content = annotate_obj.text
466 result.append((ln_no, sha, content))
461 result.append((ln_no, sha, content))
467 return result
462 return result
468
463
469 @reraise_safe_exceptions
464 @reraise_safe_exceptions
470 def fctx_data(self, wire, revision, path):
465 def fctx_data(self, wire, revision, path):
471 repo = self._factory.repo(wire)
466 repo = self._factory.repo(wire)
472 ctx = repo[revision]
467 ctx = repo[revision]
473 fctx = ctx.filectx(path)
468 fctx = ctx.filectx(path)
474 return fctx.data()
469 return fctx.data()
475
470
476 @reraise_safe_exceptions
471 @reraise_safe_exceptions
477 def fctx_flags(self, wire, revision, path):
472 def fctx_flags(self, wire, revision, path):
478 repo = self._factory.repo(wire)
473 repo = self._factory.repo(wire)
479 ctx = repo[revision]
474 ctx = repo[revision]
480 fctx = ctx.filectx(path)
475 fctx = ctx.filectx(path)
481 return fctx.flags()
476 return fctx.flags()
482
477
483 @reraise_safe_exceptions
478 @reraise_safe_exceptions
484 def fctx_size(self, wire, revision, path):
479 def fctx_size(self, wire, revision, path):
485 repo = self._factory.repo(wire)
480 repo = self._factory.repo(wire)
486 ctx = repo[revision]
481 ctx = repo[revision]
487 fctx = ctx.filectx(path)
482 fctx = ctx.filectx(path)
488 return fctx.size()
483 return fctx.size()
489
484
490 @reraise_safe_exceptions
485 @reraise_safe_exceptions
491 def get_all_commit_ids(self, wire, name):
486 def get_all_commit_ids(self, wire, name):
492 repo = self._factory.repo(wire)
487 repo = self._factory.repo(wire)
493 revs = repo.filtered(name).changelog.index
488 repo = repo.filtered(name)
494 return map(lambda x: hex(x[7]), revs)[:-1]
489 revs = map(lambda x: hex(x[7]), repo.changelog.index)
490 return revs
495
491
496 @reraise_safe_exceptions
492 @reraise_safe_exceptions
497 def get_config_value(self, wire, section, name, untrusted=False):
493 def get_config_value(self, wire, section, name, untrusted=False):
498 repo = self._factory.repo(wire)
494 repo = self._factory.repo(wire)
499 return repo.ui.config(section, name, untrusted=untrusted)
495 return repo.ui.config(section, name, untrusted=untrusted)
500
496
501 @reraise_safe_exceptions
497 @reraise_safe_exceptions
502 def get_config_bool(self, wire, section, name, untrusted=False):
498 def get_config_bool(self, wire, section, name, untrusted=False):
503 repo = self._factory.repo(wire)
499 repo = self._factory.repo(wire)
504 return repo.ui.configbool(section, name, untrusted=untrusted)
500 return repo.ui.configbool(section, name, untrusted=untrusted)
505
501
506 @reraise_safe_exceptions
502 @reraise_safe_exceptions
507 def get_config_list(self, wire, section, name, untrusted=False):
503 def get_config_list(self, wire, section, name, untrusted=False):
508 repo = self._factory.repo(wire)
504 repo = self._factory.repo(wire)
509 return repo.ui.configlist(section, name, untrusted=untrusted)
505 return repo.ui.configlist(section, name, untrusted=untrusted)
510
506
511 @reraise_safe_exceptions
507 @reraise_safe_exceptions
512 def is_large_file(self, wire, path):
508 def is_large_file(self, wire, path):
513 return largefiles.lfutil.isstandin(path)
509 return largefiles.lfutil.isstandin(path)
514
510
515 @reraise_safe_exceptions
511 @reraise_safe_exceptions
516 def in_largefiles_store(self, wire, sha):
512 def in_largefiles_store(self, wire, sha):
517 repo = self._factory.repo(wire)
513 repo = self._factory.repo(wire)
518 return largefiles.lfutil.instore(repo, sha)
514 return largefiles.lfutil.instore(repo, sha)
519
515
520 @reraise_safe_exceptions
516 @reraise_safe_exceptions
521 def in_user_cache(self, wire, sha):
517 def in_user_cache(self, wire, sha):
522 repo = self._factory.repo(wire)
518 repo = self._factory.repo(wire)
523 return largefiles.lfutil.inusercache(repo.ui, sha)
519 return largefiles.lfutil.inusercache(repo.ui, sha)
524
520
525 @reraise_safe_exceptions
521 @reraise_safe_exceptions
526 def store_path(self, wire, sha):
522 def store_path(self, wire, sha):
527 repo = self._factory.repo(wire)
523 repo = self._factory.repo(wire)
528 return largefiles.lfutil.storepath(repo, sha)
524 return largefiles.lfutil.storepath(repo, sha)
529
525
530 @reraise_safe_exceptions
526 @reraise_safe_exceptions
531 def link(self, wire, sha, path):
527 def link(self, wire, sha, path):
532 repo = self._factory.repo(wire)
528 repo = self._factory.repo(wire)
533 largefiles.lfutil.link(
529 largefiles.lfutil.link(
534 largefiles.lfutil.usercachepath(repo.ui, sha), path)
530 largefiles.lfutil.usercachepath(repo.ui, sha), path)
535
531
536 @reraise_safe_exceptions
532 @reraise_safe_exceptions
537 def localrepository(self, wire, create=False):
533 def localrepository(self, wire, create=False):
538 self._factory.repo(wire, create=create)
534 self._factory.repo(wire, create=create)
539
535
540 @reraise_safe_exceptions
536 @reraise_safe_exceptions
541 def lookup(self, wire, revision, both):
537 def lookup(self, wire, revision, both):
542
538
543 repo = self._factory.repo(wire)
539 repo = self._factory.repo(wire)
544
540
545 if isinstance(revision, int):
541 if isinstance(revision, int):
546 # NOTE(marcink):
542 # NOTE(marcink):
547 # since Mercurial doesn't support indexes properly
543 # since Mercurial doesn't support negative indexes properly
548 # we need to shift accordingly by one to get proper index, e.g
544 # we need to shift accordingly by one to get proper index, e.g
549 # repo[-1] => repo[-2]
545 # repo[-1] => repo[-2]
550 # repo[0] => repo[-1]
546 # repo[0] => repo[-1]
551 # repo[1] => repo[2] we also never call repo[0] because
552 # it's actually second commit
553 if revision <= 0:
547 if revision <= 0:
554 revision = revision + -1
548 revision = revision + -1
555 else:
549 try:
556 revision = revision + 1
557
558 try:
550 try:
559 ctx = repo[revision]
551 ctx = repo[revision]
560 except RepoLookupError as e:
552 except ProgrammingError:
553 # we're unable to find the rev using a regular lookup, we fallback
554 # to slower, but backward compat revsymbol usage
555 ctx = revsymbol(repo, revision)
556 except (TypeError, RepoLookupError) as e:
557 e._org_exc_tb = traceback.format_exc()
561 raise exceptions.LookupException(e)(revision)
558 raise exceptions.LookupException(e)(revision)
562 except LookupError as e:
559 except LookupError as e:
560 e._org_exc_tb = traceback.format_exc()
563 raise exceptions.LookupException(e)(e.name)
561 raise exceptions.LookupException(e)(e.name)
564
562
565 if not both:
563 if not both:
566 return ctx.hex()
564 return ctx.hex()
567
565
568 ctx = repo[ctx.hex()]
566 ctx = repo[ctx.hex()]
569 return ctx.hex(), ctx.rev()
567 return ctx.hex(), ctx.rev()
570
568
571 @reraise_safe_exceptions
569 @reraise_safe_exceptions
572 def pull(self, wire, url, commit_ids=None):
570 def pull(self, wire, url, commit_ids=None):
573 repo = self._factory.repo(wire)
571 repo = self._factory.repo(wire)
574 # Disable any prompts for this repo
572 # Disable any prompts for this repo
575 repo.ui.setconfig('ui', 'interactive', 'off', '-y')
573 repo.ui.setconfig('ui', 'interactive', 'off', '-y')
576
574
577 remote = peer(repo, {}, url)
575 remote = peer(repo, {}, url)
578 # Disable any prompts for this remote
576 # Disable any prompts for this remote
579 remote.ui.setconfig('ui', 'interactive', 'off', '-y')
577 remote.ui.setconfig('ui', 'interactive', 'off', '-y')
580
578
581 if commit_ids:
579 if commit_ids:
582 commit_ids = [bin(commit_id) for commit_id in commit_ids]
580 commit_ids = [bin(commit_id) for commit_id in commit_ids]
583
581
584 return exchange.pull(
582 return exchange.pull(
585 repo, remote, heads=commit_ids, force=None).cgresult
583 repo, remote, heads=commit_ids, force=None).cgresult
586
584
587 @reraise_safe_exceptions
585 @reraise_safe_exceptions
588 def sync_push(self, wire, url):
586 def sync_push(self, wire, url):
589 if not self.check_url(url, wire['config']):
587 if not self.check_url(url, wire['config']):
590 return
588 return
591
589
592 repo = self._factory.repo(wire)
590 repo = self._factory.repo(wire)
593
591
594 # Disable any prompts for this repo
592 # Disable any prompts for this repo
595 repo.ui.setconfig('ui', 'interactive', 'off', '-y')
593 repo.ui.setconfig('ui', 'interactive', 'off', '-y')
596
594
597 bookmarks = dict(repo._bookmarks).keys()
595 bookmarks = dict(repo._bookmarks).keys()
598 remote = peer(repo, {}, url)
596 remote = peer(repo, {}, url)
599 # Disable any prompts for this remote
597 # Disable any prompts for this remote
600 remote.ui.setconfig('ui', 'interactive', 'off', '-y')
598 remote.ui.setconfig('ui', 'interactive', 'off', '-y')
601
599
602 return exchange.push(
600 return exchange.push(
603 repo, remote, newbranch=True, bookmarks=bookmarks).cgresult
601 repo, remote, newbranch=True, bookmarks=bookmarks).cgresult
604
602
605 @reraise_safe_exceptions
603 @reraise_safe_exceptions
606 def revision(self, wire, rev):
604 def revision(self, wire, rev):
607 repo = self._factory.repo(wire)
605 repo = self._factory.repo(wire)
608 ctx = repo[rev]
606 ctx = repo[rev]
609 return ctx.rev()
607 return ctx.rev()
610
608
611 @reraise_safe_exceptions
609 @reraise_safe_exceptions
612 def rev_range(self, wire, filter):
610 def rev_range(self, wire, filter):
613 repo = self._factory.repo(wire)
611 repo = self._factory.repo(wire)
614 revisions = [rev for rev in revrange(repo, filter)]
612 revisions = [rev for rev in revrange(repo, filter)]
615 return revisions
613 return revisions
616
614
617 @reraise_safe_exceptions
615 @reraise_safe_exceptions
618 def rev_range_hash(self, wire, node):
616 def rev_range_hash(self, wire, node):
619 repo = self._factory.repo(wire)
617 repo = self._factory.repo(wire)
620
618
621 def get_revs(repo, rev_opt):
619 def get_revs(repo, rev_opt):
622 if rev_opt:
620 if rev_opt:
623 revs = revrange(repo, rev_opt)
621 revs = revrange(repo, rev_opt)
624 if len(revs) == 0:
622 if len(revs) == 0:
625 return (nullrev, nullrev)
623 return (nullrev, nullrev)
626 return max(revs), min(revs)
624 return max(revs), min(revs)
627 else:
625 else:
628 return len(repo) - 1, 0
626 return len(repo) - 1, 0
629
627
630 stop, start = get_revs(repo, [node + ':'])
628 stop, start = get_revs(repo, [node + ':'])
631 revs = [hex(repo[r].node()) for r in xrange(start, stop + 1)]
629 revs = [hex(repo[r].node()) for r in xrange(start, stop + 1)]
632 return revs
630 return revs
633
631
634 @reraise_safe_exceptions
632 @reraise_safe_exceptions
635 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
633 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
636 other_path = kwargs.pop('other_path', None)
634 other_path = kwargs.pop('other_path', None)
637
635
638 # case when we want to compare two independent repositories
636 # case when we want to compare two independent repositories
639 if other_path and other_path != wire["path"]:
637 if other_path and other_path != wire["path"]:
640 baseui = self._factory._create_config(wire["config"])
638 baseui = self._factory._create_config(wire["config"])
641 repo = unionrepo.makeunionrepository(baseui, other_path, wire["path"])
639 repo = unionrepo.makeunionrepository(baseui, other_path, wire["path"])
642 else:
640 else:
643 repo = self._factory.repo(wire)
641 repo = self._factory.repo(wire)
644 return list(repo.revs(rev_spec, *args))
642 return list(repo.revs(rev_spec, *args))
645
643
646 @reraise_safe_exceptions
644 @reraise_safe_exceptions
647 def strip(self, wire, revision, update, backup):
645 def strip(self, wire, revision, update, backup):
648 repo = self._factory.repo(wire)
646 repo = self._factory.repo(wire)
649 ctx = repo[revision]
647 ctx = repo[revision]
650 hgext_strip(
648 hgext_strip(
651 repo.baseui, repo, ctx.node(), update=update, backup=backup)
649 repo.baseui, repo, ctx.node(), update=update, backup=backup)
652
650
653 @reraise_safe_exceptions
651 @reraise_safe_exceptions
654 def verify(self, wire,):
652 def verify(self, wire,):
655 repo = self._factory.repo(wire)
653 repo = self._factory.repo(wire)
656 baseui = self._factory._create_config(wire['config'])
654 baseui = self._factory._create_config(wire['config'])
657 baseui.setconfig('ui', 'quiet', 'false')
655 baseui.setconfig('ui', 'quiet', 'false')
658 output = io.BytesIO()
656 output = io.BytesIO()
659
657
660 def write(data, **unused_kwargs):
658 def write(data, **unused_kwargs):
661 output.write(data)
659 output.write(data)
662 baseui.write = write
660 baseui.write = write
663
661
664 repo.ui = baseui
662 repo.ui = baseui
665 verify.verify(repo)
663 verify.verify(repo)
666 return output.getvalue()
664 return output.getvalue()
667
665
668 @reraise_safe_exceptions
666 @reraise_safe_exceptions
669 def tag(self, wire, name, revision, message, local, user,
667 def tag(self, wire, name, revision, message, local, user,
670 tag_time, tag_timezone):
668 tag_time, tag_timezone):
671 repo = self._factory.repo(wire)
669 repo = self._factory.repo(wire)
672 ctx = repo[revision]
670 ctx = repo[revision]
673 node = ctx.node()
671 node = ctx.node()
674
672
675 date = (tag_time, tag_timezone)
673 date = (tag_time, tag_timezone)
676 try:
674 try:
677 hg_tag.tag(repo, name, node, message, local, user, date)
675 hg_tag.tag(repo, name, node, message, local, user, date)
678 except Abort as e:
676 except Abort as e:
679 log.exception("Tag operation aborted")
677 log.exception("Tag operation aborted")
680 # Exception can contain unicode which we convert
678 # Exception can contain unicode which we convert
681 raise exceptions.AbortException(e)(repr(e))
679 raise exceptions.AbortException(e)(repr(e))
682
680
683 @reraise_safe_exceptions
681 @reraise_safe_exceptions
684 def tags(self, wire):
682 def tags(self, wire):
685 repo = self._factory.repo(wire)
683 repo = self._factory.repo(wire)
686 return repo.tags()
684 return repo.tags()
687
685
688 @reraise_safe_exceptions
686 @reraise_safe_exceptions
689 def update(self, wire, node=None, clean=False):
687 def update(self, wire, node=None, clean=False):
690 repo = self._factory.repo(wire)
688 repo = self._factory.repo(wire)
691 baseui = self._factory._create_config(wire['config'])
689 baseui = self._factory._create_config(wire['config'])
692 commands.update(baseui, repo, node=node, clean=clean)
690 commands.update(baseui, repo, node=node, clean=clean)
693
691
694 @reraise_safe_exceptions
692 @reraise_safe_exceptions
695 def identify(self, wire):
693 def identify(self, wire):
696 repo = self._factory.repo(wire)
694 repo = self._factory.repo(wire)
697 baseui = self._factory._create_config(wire['config'])
695 baseui = self._factory._create_config(wire['config'])
698 output = io.BytesIO()
696 output = io.BytesIO()
699 baseui.write = output.write
697 baseui.write = output.write
700 # This is required to get a full node id
698 # This is required to get a full node id
701 baseui.debugflag = True
699 baseui.debugflag = True
702 commands.identify(baseui, repo, id=True)
700 commands.identify(baseui, repo, id=True)
703
701
704 return output.getvalue()
702 return output.getvalue()
705
703
706 @reraise_safe_exceptions
704 @reraise_safe_exceptions
707 def pull_cmd(self, wire, source, bookmark=None, branch=None, revision=None,
705 def pull_cmd(self, wire, source, bookmark=None, branch=None, revision=None,
708 hooks=True):
706 hooks=True):
709 repo = self._factory.repo(wire)
707 repo = self._factory.repo(wire)
710 baseui = self._factory._create_config(wire['config'], hooks=hooks)
708 baseui = self._factory._create_config(wire['config'], hooks=hooks)
711
709
712 # Mercurial internally has a lot of logic that checks ONLY if
710 # Mercurial internally has a lot of logic that checks ONLY if
713 # option is defined, we just pass those if they are defined then
711 # option is defined, we just pass those if they are defined then
714 opts = {}
712 opts = {}
715 if bookmark:
713 if bookmark:
716 opts['bookmark'] = bookmark
714 opts['bookmark'] = bookmark
717 if branch:
715 if branch:
718 opts['branch'] = branch
716 opts['branch'] = branch
719 if revision:
717 if revision:
720 opts['rev'] = revision
718 opts['rev'] = revision
721
719
722 commands.pull(baseui, repo, source, **opts)
720 commands.pull(baseui, repo, source, **opts)
723
721
724 @reraise_safe_exceptions
722 @reraise_safe_exceptions
725 def heads(self, wire, branch=None):
723 def heads(self, wire, branch=None):
726 repo = self._factory.repo(wire)
724 repo = self._factory.repo(wire)
727 baseui = self._factory._create_config(wire['config'])
725 baseui = self._factory._create_config(wire['config'])
728 output = io.BytesIO()
726 output = io.BytesIO()
729
727
730 def write(data, **unused_kwargs):
728 def write(data, **unused_kwargs):
731 output.write(data)
729 output.write(data)
732
730
733 baseui.write = write
731 baseui.write = write
734 if branch:
732 if branch:
735 args = [branch]
733 args = [branch]
736 else:
734 else:
737 args = []
735 args = []
738 commands.heads(baseui, repo, template='{node} ', *args)
736 commands.heads(baseui, repo, template='{node} ', *args)
739
737
740 return output.getvalue()
738 return output.getvalue()
741
739
742 @reraise_safe_exceptions
740 @reraise_safe_exceptions
743 def ancestor(self, wire, revision1, revision2):
741 def ancestor(self, wire, revision1, revision2):
744 repo = self._factory.repo(wire)
742 repo = self._factory.repo(wire)
745 changelog = repo.changelog
743 changelog = repo.changelog
746 lookup = repo.lookup
744 lookup = repo.lookup
747 a = changelog.ancestor(lookup(revision1), lookup(revision2))
745 a = changelog.ancestor(lookup(revision1), lookup(revision2))
748 return hex(a)
746 return hex(a)
749
747
750 @reraise_safe_exceptions
748 @reraise_safe_exceptions
751 def push(self, wire, revisions, dest_path, hooks=True,
749 def push(self, wire, revisions, dest_path, hooks=True,
752 push_branches=False):
750 push_branches=False):
753 repo = self._factory.repo(wire)
751 repo = self._factory.repo(wire)
754 baseui = self._factory._create_config(wire['config'], hooks=hooks)
752 baseui = self._factory._create_config(wire['config'], hooks=hooks)
755 commands.push(baseui, repo, dest=dest_path, rev=revisions,
753 commands.push(baseui, repo, dest=dest_path, rev=revisions,
756 new_branch=push_branches)
754 new_branch=push_branches)
757
755
758 @reraise_safe_exceptions
756 @reraise_safe_exceptions
759 def merge(self, wire, revision):
757 def merge(self, wire, revision):
760 repo = self._factory.repo(wire)
758 repo = self._factory.repo(wire)
761 baseui = self._factory._create_config(wire['config'])
759 baseui = self._factory._create_config(wire['config'])
762 repo.ui.setconfig('ui', 'merge', 'internal:dump')
760 repo.ui.setconfig('ui', 'merge', 'internal:dump')
763
761
764 # In case of sub repositories are used mercurial prompts the user in
762 # In case of sub repositories are used mercurial prompts the user in
765 # case of merge conflicts or different sub repository sources. By
763 # case of merge conflicts or different sub repository sources. By
766 # setting the interactive flag to `False` mercurial doesn't prompt the
764 # setting the interactive flag to `False` mercurial doesn't prompt the
767 # used but instead uses a default value.
765 # used but instead uses a default value.
768 repo.ui.setconfig('ui', 'interactive', False)
766 repo.ui.setconfig('ui', 'interactive', False)
769
767
770 commands.merge(baseui, repo, rev=revision)
768 commands.merge(baseui, repo, rev=revision)
771
769
772 @reraise_safe_exceptions
770 @reraise_safe_exceptions
773 def commit(self, wire, message, username, close_branch=False):
771 def commit(self, wire, message, username, close_branch=False):
774 repo = self._factory.repo(wire)
772 repo = self._factory.repo(wire)
775 baseui = self._factory._create_config(wire['config'])
773 baseui = self._factory._create_config(wire['config'])
776 repo.ui.setconfig('ui', 'username', username)
774 repo.ui.setconfig('ui', 'username', username)
777 commands.commit(baseui, repo, message=message, close_branch=close_branch)
775 commands.commit(baseui, repo, message=message, close_branch=close_branch)
778
776
779 @reraise_safe_exceptions
777 @reraise_safe_exceptions
780 def rebase(self, wire, source=None, dest=None, abort=False):
778 def rebase(self, wire, source=None, dest=None, abort=False):
781 repo = self._factory.repo(wire)
779 repo = self._factory.repo(wire)
782 baseui = self._factory._create_config(wire['config'])
780 baseui = self._factory._create_config(wire['config'])
783 repo.ui.setconfig('ui', 'merge', 'internal:dump')
781 repo.ui.setconfig('ui', 'merge', 'internal:dump')
784 rebase.rebase(
782 rebase.rebase(
785 baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
783 baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
786
784
787 @reraise_safe_exceptions
785 @reraise_safe_exceptions
788 def bookmark(self, wire, bookmark, revision=None):
786 def bookmark(self, wire, bookmark, revision=None):
789 repo = self._factory.repo(wire)
787 repo = self._factory.repo(wire)
790 baseui = self._factory._create_config(wire['config'])
788 baseui = self._factory._create_config(wire['config'])
791 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
789 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
792
790
793 @reraise_safe_exceptions
791 @reraise_safe_exceptions
794 def install_hooks(self, wire, force=False):
792 def install_hooks(self, wire, force=False):
795 # we don't need any special hooks for Mercurial
793 # we don't need any special hooks for Mercurial
796 pass
794 pass
797
795
798 @reraise_safe_exceptions
796 @reraise_safe_exceptions
799 def get_hooks_info(self, wire):
797 def get_hooks_info(self, wire):
800 return {
798 return {
801 'pre_version': vcsserver.__version__,
799 'pre_version': vcsserver.__version__,
802 'post_version': vcsserver.__version__,
800 'post_version': vcsserver.__version__,
803 }
801 }
@@ -1,63 +1,63 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2019 RhodeCode GmbH
2 # Copyright (C) 2014-2019 RhodeCode GmbH
3 #
3 #
4 # This program is free software; you can redistribute it and/or modify
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
7 # (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 """
18 """
19 Mercurial libs compatibility
19 Mercurial libs compatibility
20 """
20 """
21
21
22 import mercurial
22 import mercurial
23 from mercurial import demandimport
23 from mercurial import demandimport
24 # patch demandimport, due to bug in mercurial when it always triggers
24 # patch demandimport, due to bug in mercurial when it always triggers
25 # demandimport.enable()
25 # demandimport.enable()
26 demandimport.enable = lambda *args, **kwargs: 1
26 demandimport.enable = lambda *args, **kwargs: 1
27
27
28 from mercurial import ui
28 from mercurial import ui
29 from mercurial import patch
29 from mercurial import patch
30 from mercurial import config
30 from mercurial import config
31 from mercurial import extensions
31 from mercurial import extensions
32 from mercurial import scmutil
32 from mercurial import scmutil
33 from mercurial import archival
33 from mercurial import archival
34 from mercurial import discovery
34 from mercurial import discovery
35 from mercurial import unionrepo
35 from mercurial import unionrepo
36 from mercurial import localrepo
36 from mercurial import localrepo
37 from mercurial import merge as hg_merge
37 from mercurial import merge as hg_merge
38 from mercurial import subrepo
38 from mercurial import subrepo
39 from mercurial import tags as hg_tag
39 from mercurial import tags as hg_tag
40
40
41 from mercurial.commands import clone, nullid, pull
41 from mercurial.commands import clone, nullid, pull
42 from mercurial.context import memctx, memfilectx
42 from mercurial.context import memctx, memfilectx
43 from mercurial.error import (
43 from mercurial.error import (
44 LookupError, RepoError, RepoLookupError, Abort, InterventionRequired,
44 LookupError, RepoError, RepoLookupError, Abort, InterventionRequired,
45 RequirementError)
45 RequirementError, ProgrammingError)
46 from mercurial.hgweb import hgweb_mod
46 from mercurial.hgweb import hgweb_mod
47 from mercurial.localrepo import instance
47 from mercurial.localrepo import instance
48 from mercurial.match import match
48 from mercurial.match import match
49 from mercurial.mdiff import diffopts
49 from mercurial.mdiff import diffopts
50 from mercurial.node import bin, hex
50 from mercurial.node import bin, hex
51 from mercurial.encoding import tolocal
51 from mercurial.encoding import tolocal
52 from mercurial.discovery import findcommonoutgoing
52 from mercurial.discovery import findcommonoutgoing
53 from mercurial.hg import peer
53 from mercurial.hg import peer
54 from mercurial.httppeer import makepeer
54 from mercurial.httppeer import makepeer
55 from mercurial.util import url as hg_url
55 from mercurial.util import url as hg_url
56 from mercurial.scmutil import revrange
56 from mercurial.scmutil import revrange, revsymbol
57 from mercurial.node import nullrev
57 from mercurial.node import nullrev
58 from mercurial import exchange
58 from mercurial import exchange
59 from hgext import largefiles
59 from hgext import largefiles
60
60
61 # those authnadlers are patched for python 2.6.5 bug an
61 # those authnadlers are patched for python 2.6.5 bug an
62 # infinit looping when given invalid resources
62 # infinit looping when given invalid resources
63 from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
63 from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
General Comments 0
You need to be logged in to leave comments. Login now