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