##// END OF EJS Templates
hg: Add logging around check_url...
johbo -
r64:da50e6f0 default
parent child Browse files
Show More
@@ -1,700 +1,707 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 _proto = None
320 _proto = None
320 if '+' in url[:url.find('://')]:
321 if '+' in url[:url.find('://')]:
321 _proto = url[0:url.find('+')]
322 _proto = url[0:url.find('+')]
322 url = url[url.find('+') + 1:]
323 url = url[url.find('+') + 1:]
323 handlers = []
324 handlers = []
324 url_obj = hg_url(url)
325 url_obj = hg_url(url)
325 test_uri, authinfo = url_obj.authinfo()
326 test_uri, authinfo = url_obj.authinfo()
326 url_obj.passwd = '*****'
327 url_obj.passwd = '*****'
327 cleaned_uri = str(url_obj)
328 cleaned_uri = str(url_obj)
328
329
329 if authinfo:
330 if authinfo:
330 # create a password manager
331 # create a password manager
331 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
332 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
332 passmgr.add_password(*authinfo)
333 passmgr.add_password(*authinfo)
333
334
334 handlers.extend((httpbasicauthhandler(passmgr),
335 handlers.extend((httpbasicauthhandler(passmgr),
335 httpdigestauthhandler(passmgr)))
336 httpdigestauthhandler(passmgr)))
336
337
337 o = urllib2.build_opener(*handlers)
338 o = urllib2.build_opener(*handlers)
338 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
339 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
339 ('Accept', 'application/mercurial-0.1')]
340 ('Accept', 'application/mercurial-0.1')]
340
341
341 q = {"cmd": 'between'}
342 q = {"cmd": 'between'}
342 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
343 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
343 qs = '?%s' % urllib.urlencode(q)
344 qs = '?%s' % urllib.urlencode(q)
344 cu = "%s%s" % (test_uri, qs)
345 cu = "%s%s" % (test_uri, qs)
345 req = urllib2.Request(cu, None, {})
346 req = urllib2.Request(cu, None, {})
346
347
347 try:
348 try:
349 log.debug("Trying to open URL %s", url)
348 resp = o.open(req)
350 resp = o.open(req)
349 if resp.code != 200:
351 if resp.code != 200:
350 raise exceptions.URLError('Return Code is not 200')
352 raise exceptions.URLError('Return Code is not 200')
351 except Exception as e:
353 except Exception as e:
354 log.warning("URL cannot be opened: %s", url, exc_info=True)
352 # means it cannot be cloned
355 # means it cannot be cloned
353 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
356 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
354
357
355 # 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
356 try:
359 try:
357 if _proto == 'svn':
360 if _proto == 'svn':
358 pass
361 pass
359 else:
362 else:
360 # check for pure hg repos
363 # check for pure hg repos
364 log.debug(
365 "Verifying if URL is a Mercurial repository: %s", url)
361 httppeer(make_ui_from_config(config), url).lookup('tip')
366 httppeer(make_ui_from_config(config), url).lookup('tip')
362 except Exception as e:
367 except Exception as e:
368 log.warning("URL is not a valid Mercurial repository: %s", url)
363 raise exceptions.URLError(
369 raise exceptions.URLError(
364 "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"
365 % (cleaned_uri, e))
371 % (cleaned_uri, e))
366
372
373 log.info("URL is a valid Mercurial repository: %s", url)
367 return True
374 return True
368
375
369 @reraise_safe_exceptions
376 @reraise_safe_exceptions
370 def diff(
377 def diff(
371 self, wire, rev1, rev2, file_filter, opt_git, opt_ignorews,
378 self, wire, rev1, rev2, file_filter, opt_git, opt_ignorews,
372 context):
379 context):
373 repo = self._factory.repo(wire)
380 repo = self._factory.repo(wire)
374
381
375 if file_filter:
382 if file_filter:
376 filter = match(file_filter[0], '', [file_filter[1]])
383 filter = match(file_filter[0], '', [file_filter[1]])
377 else:
384 else:
378 filter = file_filter
385 filter = file_filter
379 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
386 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
380
387
381 try:
388 try:
382 return "".join(patch.diff(
389 return "".join(patch.diff(
383 repo, node1=rev1, node2=rev2, match=filter, opts=opts))
390 repo, node1=rev1, node2=rev2, match=filter, opts=opts))
384 except RepoLookupError:
391 except RepoLookupError:
385 raise exceptions.LookupException()
392 raise exceptions.LookupException()
386
393
387 @reraise_safe_exceptions
394 @reraise_safe_exceptions
388 def file_history(self, wire, revision, path, limit):
395 def file_history(self, wire, revision, path, limit):
389 repo = self._factory.repo(wire)
396 repo = self._factory.repo(wire)
390
397
391 ctx = repo[revision]
398 ctx = repo[revision]
392 fctx = ctx.filectx(path)
399 fctx = ctx.filectx(path)
393
400
394 def history_iter():
401 def history_iter():
395 limit_rev = fctx.rev()
402 limit_rev = fctx.rev()
396 for obj in reversed(list(fctx.filelog())):
403 for obj in reversed(list(fctx.filelog())):
397 obj = fctx.filectx(obj)
404 obj = fctx.filectx(obj)
398 if limit_rev >= obj.rev():
405 if limit_rev >= obj.rev():
399 yield obj
406 yield obj
400
407
401 history = []
408 history = []
402 for cnt, obj in enumerate(history_iter()):
409 for cnt, obj in enumerate(history_iter()):
403 if limit and cnt >= limit:
410 if limit and cnt >= limit:
404 break
411 break
405 history.append(hex(obj.node()))
412 history.append(hex(obj.node()))
406
413
407 return [x for x in history]
414 return [x for x in history]
408
415
409 @reraise_safe_exceptions
416 @reraise_safe_exceptions
410 def file_history_untill(self, wire, revision, path, limit):
417 def file_history_untill(self, wire, revision, path, limit):
411 repo = self._factory.repo(wire)
418 repo = self._factory.repo(wire)
412 ctx = repo[revision]
419 ctx = repo[revision]
413 fctx = ctx.filectx(path)
420 fctx = ctx.filectx(path)
414
421
415 file_log = list(fctx.filelog())
422 file_log = list(fctx.filelog())
416 if limit:
423 if limit:
417 # Limit to the last n items
424 # Limit to the last n items
418 file_log = file_log[-limit:]
425 file_log = file_log[-limit:]
419
426
420 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)]
421
428
422 @reraise_safe_exceptions
429 @reraise_safe_exceptions
423 def fctx_annotate(self, wire, revision, path):
430 def fctx_annotate(self, wire, revision, path):
424 repo = self._factory.repo(wire)
431 repo = self._factory.repo(wire)
425 ctx = repo[revision]
432 ctx = repo[revision]
426 fctx = ctx.filectx(path)
433 fctx = ctx.filectx(path)
427
434
428 result = []
435 result = []
429 for i, annotate_data in enumerate(fctx.annotate()):
436 for i, annotate_data in enumerate(fctx.annotate()):
430 ln_no = i + 1
437 ln_no = i + 1
431 sha = hex(annotate_data[0].node())
438 sha = hex(annotate_data[0].node())
432 result.append((ln_no, sha, annotate_data[1]))
439 result.append((ln_no, sha, annotate_data[1]))
433 return result
440 return result
434
441
435 @reraise_safe_exceptions
442 @reraise_safe_exceptions
436 def fctx_data(self, wire, revision, path):
443 def fctx_data(self, wire, revision, path):
437 repo = self._factory.repo(wire)
444 repo = self._factory.repo(wire)
438 ctx = repo[revision]
445 ctx = repo[revision]
439 fctx = ctx.filectx(path)
446 fctx = ctx.filectx(path)
440 return fctx.data()
447 return fctx.data()
441
448
442 @reraise_safe_exceptions
449 @reraise_safe_exceptions
443 def fctx_flags(self, wire, revision, path):
450 def fctx_flags(self, wire, revision, path):
444 repo = self._factory.repo(wire)
451 repo = self._factory.repo(wire)
445 ctx = repo[revision]
452 ctx = repo[revision]
446 fctx = ctx.filectx(path)
453 fctx = ctx.filectx(path)
447 return fctx.flags()
454 return fctx.flags()
448
455
449 @reraise_safe_exceptions
456 @reraise_safe_exceptions
450 def fctx_size(self, wire, revision, path):
457 def fctx_size(self, wire, revision, path):
451 repo = self._factory.repo(wire)
458 repo = self._factory.repo(wire)
452 ctx = repo[revision]
459 ctx = repo[revision]
453 fctx = ctx.filectx(path)
460 fctx = ctx.filectx(path)
454 return fctx.size()
461 return fctx.size()
455
462
456 @reraise_safe_exceptions
463 @reraise_safe_exceptions
457 def get_all_commit_ids(self, wire, name):
464 def get_all_commit_ids(self, wire, name):
458 repo = self._factory.repo(wire)
465 repo = self._factory.repo(wire)
459 revs = repo.filtered(name).changelog.index
466 revs = repo.filtered(name).changelog.index
460 return map(lambda x: hex(x[7]), revs)[:-1]
467 return map(lambda x: hex(x[7]), revs)[:-1]
461
468
462 @reraise_safe_exceptions
469 @reraise_safe_exceptions
463 def get_config_value(self, wire, section, name, untrusted=False):
470 def get_config_value(self, wire, section, name, untrusted=False):
464 repo = self._factory.repo(wire)
471 repo = self._factory.repo(wire)
465 return repo.ui.config(section, name, untrusted=untrusted)
472 return repo.ui.config(section, name, untrusted=untrusted)
466
473
467 @reraise_safe_exceptions
474 @reraise_safe_exceptions
468 def get_config_bool(self, wire, section, name, untrusted=False):
475 def get_config_bool(self, wire, section, name, untrusted=False):
469 repo = self._factory.repo(wire)
476 repo = self._factory.repo(wire)
470 return repo.ui.configbool(section, name, untrusted=untrusted)
477 return repo.ui.configbool(section, name, untrusted=untrusted)
471
478
472 @reraise_safe_exceptions
479 @reraise_safe_exceptions
473 def get_config_list(self, wire, section, name, untrusted=False):
480 def get_config_list(self, wire, section, name, untrusted=False):
474 repo = self._factory.repo(wire)
481 repo = self._factory.repo(wire)
475 return repo.ui.configlist(section, name, untrusted=untrusted)
482 return repo.ui.configlist(section, name, untrusted=untrusted)
476
483
477 @reraise_safe_exceptions
484 @reraise_safe_exceptions
478 def is_large_file(self, wire, path):
485 def is_large_file(self, wire, path):
479 return largefiles.lfutil.isstandin(path)
486 return largefiles.lfutil.isstandin(path)
480
487
481 @reraise_safe_exceptions
488 @reraise_safe_exceptions
482 def in_store(self, wire, sha):
489 def in_store(self, wire, sha):
483 repo = self._factory.repo(wire)
490 repo = self._factory.repo(wire)
484 return largefiles.lfutil.instore(repo, sha)
491 return largefiles.lfutil.instore(repo, sha)
485
492
486 @reraise_safe_exceptions
493 @reraise_safe_exceptions
487 def in_user_cache(self, wire, sha):
494 def in_user_cache(self, wire, sha):
488 repo = self._factory.repo(wire)
495 repo = self._factory.repo(wire)
489 return largefiles.lfutil.inusercache(repo.ui, sha)
496 return largefiles.lfutil.inusercache(repo.ui, sha)
490
497
491 @reraise_safe_exceptions
498 @reraise_safe_exceptions
492 def store_path(self, wire, sha):
499 def store_path(self, wire, sha):
493 repo = self._factory.repo(wire)
500 repo = self._factory.repo(wire)
494 return largefiles.lfutil.storepath(repo, sha)
501 return largefiles.lfutil.storepath(repo, sha)
495
502
496 @reraise_safe_exceptions
503 @reraise_safe_exceptions
497 def link(self, wire, sha, path):
504 def link(self, wire, sha, path):
498 repo = self._factory.repo(wire)
505 repo = self._factory.repo(wire)
499 largefiles.lfutil.link(
506 largefiles.lfutil.link(
500 largefiles.lfutil.usercachepath(repo.ui, sha), path)
507 largefiles.lfutil.usercachepath(repo.ui, sha), path)
501
508
502 @reraise_safe_exceptions
509 @reraise_safe_exceptions
503 def localrepository(self, wire, create=False):
510 def localrepository(self, wire, create=False):
504 self._factory.repo(wire, create=create)
511 self._factory.repo(wire, create=create)
505
512
506 @reraise_safe_exceptions
513 @reraise_safe_exceptions
507 def lookup(self, wire, revision, both):
514 def lookup(self, wire, revision, both):
508 # TODO Paris: Ugly hack to "deserialize" long for msgpack
515 # TODO Paris: Ugly hack to "deserialize" long for msgpack
509 if isinstance(revision, float):
516 if isinstance(revision, float):
510 revision = long(revision)
517 revision = long(revision)
511 repo = self._factory.repo(wire)
518 repo = self._factory.repo(wire)
512 try:
519 try:
513 ctx = repo[revision]
520 ctx = repo[revision]
514 except RepoLookupError:
521 except RepoLookupError:
515 raise exceptions.LookupException(revision)
522 raise exceptions.LookupException(revision)
516 except LookupError as e:
523 except LookupError as e:
517 raise exceptions.LookupException(e.name)
524 raise exceptions.LookupException(e.name)
518
525
519 if not both:
526 if not both:
520 return ctx.hex()
527 return ctx.hex()
521
528
522 ctx = repo[ctx.hex()]
529 ctx = repo[ctx.hex()]
523 return ctx.hex(), ctx.rev()
530 return ctx.hex(), ctx.rev()
524
531
525 @reraise_safe_exceptions
532 @reraise_safe_exceptions
526 def pull(self, wire, url, commit_ids=None):
533 def pull(self, wire, url, commit_ids=None):
527 repo = self._factory.repo(wire)
534 repo = self._factory.repo(wire)
528 remote = peer(repo, {}, url)
535 remote = peer(repo, {}, url)
529 if commit_ids:
536 if commit_ids:
530 commit_ids = [bin(commit_id) for commit_id in commit_ids]
537 commit_ids = [bin(commit_id) for commit_id in commit_ids]
531
538
532 return exchange.pull(
539 return exchange.pull(
533 repo, remote, heads=commit_ids, force=None).cgresult
540 repo, remote, heads=commit_ids, force=None).cgresult
534
541
535 @reraise_safe_exceptions
542 @reraise_safe_exceptions
536 def revision(self, wire, rev):
543 def revision(self, wire, rev):
537 repo = self._factory.repo(wire)
544 repo = self._factory.repo(wire)
538 ctx = repo[rev]
545 ctx = repo[rev]
539 return ctx.rev()
546 return ctx.rev()
540
547
541 @reraise_safe_exceptions
548 @reraise_safe_exceptions
542 def rev_range(self, wire, filter):
549 def rev_range(self, wire, filter):
543 repo = self._factory.repo(wire)
550 repo = self._factory.repo(wire)
544 revisions = [rev for rev in revrange(repo, filter)]
551 revisions = [rev for rev in revrange(repo, filter)]
545 return revisions
552 return revisions
546
553
547 @reraise_safe_exceptions
554 @reraise_safe_exceptions
548 def rev_range_hash(self, wire, node):
555 def rev_range_hash(self, wire, node):
549 repo = self._factory.repo(wire)
556 repo = self._factory.repo(wire)
550
557
551 def get_revs(repo, rev_opt):
558 def get_revs(repo, rev_opt):
552 if rev_opt:
559 if rev_opt:
553 revs = revrange(repo, rev_opt)
560 revs = revrange(repo, rev_opt)
554 if len(revs) == 0:
561 if len(revs) == 0:
555 return (nullrev, nullrev)
562 return (nullrev, nullrev)
556 return max(revs), min(revs)
563 return max(revs), min(revs)
557 else:
564 else:
558 return len(repo) - 1, 0
565 return len(repo) - 1, 0
559
566
560 stop, start = get_revs(repo, [node + ':'])
567 stop, start = get_revs(repo, [node + ':'])
561 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)]
562 return revs
569 return revs
563
570
564 @reraise_safe_exceptions
571 @reraise_safe_exceptions
565 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
572 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
566 other_path = kwargs.pop('other_path', None)
573 other_path = kwargs.pop('other_path', None)
567
574
568 # case when we want to compare two independent repositories
575 # case when we want to compare two independent repositories
569 if other_path and other_path != wire["path"]:
576 if other_path and other_path != wire["path"]:
570 baseui = self._factory._create_config(wire["config"])
577 baseui = self._factory._create_config(wire["config"])
571 repo = unionrepo.unionrepository(baseui, other_path, wire["path"])
578 repo = unionrepo.unionrepository(baseui, other_path, wire["path"])
572 else:
579 else:
573 repo = self._factory.repo(wire)
580 repo = self._factory.repo(wire)
574 return list(repo.revs(rev_spec, *args))
581 return list(repo.revs(rev_spec, *args))
575
582
576 @reraise_safe_exceptions
583 @reraise_safe_exceptions
577 def strip(self, wire, revision, update, backup):
584 def strip(self, wire, revision, update, backup):
578 repo = self._factory.repo(wire)
585 repo = self._factory.repo(wire)
579 ctx = repo[revision]
586 ctx = repo[revision]
580 hgext_strip(
587 hgext_strip(
581 repo.baseui, repo, ctx.node(), update=update, backup=backup)
588 repo.baseui, repo, ctx.node(), update=update, backup=backup)
582
589
583 @reraise_safe_exceptions
590 @reraise_safe_exceptions
584 def tag(self, wire, name, revision, message, local, user,
591 def tag(self, wire, name, revision, message, local, user,
585 tag_time, tag_timezone):
592 tag_time, tag_timezone):
586 repo = self._factory.repo(wire)
593 repo = self._factory.repo(wire)
587 ctx = repo[revision]
594 ctx = repo[revision]
588 node = ctx.node()
595 node = ctx.node()
589
596
590 date = (tag_time, tag_timezone)
597 date = (tag_time, tag_timezone)
591 try:
598 try:
592 repo.tag(name, node, message, local, user, date)
599 repo.tag(name, node, message, local, user, date)
593 except Abort:
600 except Abort:
594 log.exception("Tag operation aborted")
601 log.exception("Tag operation aborted")
595 raise exceptions.AbortException()
602 raise exceptions.AbortException()
596
603
597 @reraise_safe_exceptions
604 @reraise_safe_exceptions
598 def tags(self, wire):
605 def tags(self, wire):
599 repo = self._factory.repo(wire)
606 repo = self._factory.repo(wire)
600 return repo.tags()
607 return repo.tags()
601
608
602 @reraise_safe_exceptions
609 @reraise_safe_exceptions
603 def update(self, wire, node=None, clean=False):
610 def update(self, wire, node=None, clean=False):
604 repo = self._factory.repo(wire)
611 repo = self._factory.repo(wire)
605 baseui = self._factory._create_config(wire['config'])
612 baseui = self._factory._create_config(wire['config'])
606 commands.update(baseui, repo, node=node, clean=clean)
613 commands.update(baseui, repo, node=node, clean=clean)
607
614
608 @reraise_safe_exceptions
615 @reraise_safe_exceptions
609 def identify(self, wire):
616 def identify(self, wire):
610 repo = self._factory.repo(wire)
617 repo = self._factory.repo(wire)
611 baseui = self._factory._create_config(wire['config'])
618 baseui = self._factory._create_config(wire['config'])
612 output = io.BytesIO()
619 output = io.BytesIO()
613 baseui.write = output.write
620 baseui.write = output.write
614 # This is required to get a full node id
621 # This is required to get a full node id
615 baseui.debugflag = True
622 baseui.debugflag = True
616 commands.identify(baseui, repo, id=True)
623 commands.identify(baseui, repo, id=True)
617
624
618 return output.getvalue()
625 return output.getvalue()
619
626
620 @reraise_safe_exceptions
627 @reraise_safe_exceptions
621 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,
622 hooks=True):
629 hooks=True):
623 repo = self._factory.repo(wire)
630 repo = self._factory.repo(wire)
624 baseui = self._factory._create_config(wire['config'], hooks=hooks)
631 baseui = self._factory._create_config(wire['config'], hooks=hooks)
625
632
626 # Mercurial internally has a lot of logic that checks ONLY if
633 # Mercurial internally has a lot of logic that checks ONLY if
627 # 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
628 opts = {}
635 opts = {}
629 if bookmark:
636 if bookmark:
630 opts['bookmark'] = bookmark
637 opts['bookmark'] = bookmark
631 if branch:
638 if branch:
632 opts['branch'] = branch
639 opts['branch'] = branch
633 if revision:
640 if revision:
634 opts['rev'] = revision
641 opts['rev'] = revision
635
642
636 commands.pull(baseui, repo, source, **opts)
643 commands.pull(baseui, repo, source, **opts)
637
644
638 @reraise_safe_exceptions
645 @reraise_safe_exceptions
639 def heads(self, wire, branch=None):
646 def heads(self, wire, branch=None):
640 repo = self._factory.repo(wire)
647 repo = self._factory.repo(wire)
641 baseui = self._factory._create_config(wire['config'])
648 baseui = self._factory._create_config(wire['config'])
642 output = io.BytesIO()
649 output = io.BytesIO()
643
650
644 def write(data, **unused_kwargs):
651 def write(data, **unused_kwargs):
645 output.write(data)
652 output.write(data)
646
653
647 baseui.write = write
654 baseui.write = write
648 if branch:
655 if branch:
649 args = [branch]
656 args = [branch]
650 else:
657 else:
651 args = []
658 args = []
652 commands.heads(baseui, repo, template='{node} ', *args)
659 commands.heads(baseui, repo, template='{node} ', *args)
653
660
654 return output.getvalue()
661 return output.getvalue()
655
662
656 @reraise_safe_exceptions
663 @reraise_safe_exceptions
657 def ancestor(self, wire, revision1, revision2):
664 def ancestor(self, wire, revision1, revision2):
658 repo = self._factory.repo(wire)
665 repo = self._factory.repo(wire)
659 baseui = self._factory._create_config(wire['config'])
666 baseui = self._factory._create_config(wire['config'])
660 output = io.BytesIO()
667 output = io.BytesIO()
661 baseui.write = output.write
668 baseui.write = output.write
662 commands.debugancestor(baseui, repo, revision1, revision2)
669 commands.debugancestor(baseui, repo, revision1, revision2)
663
670
664 return output.getvalue()
671 return output.getvalue()
665
672
666 @reraise_safe_exceptions
673 @reraise_safe_exceptions
667 def push(self, wire, revisions, dest_path, hooks=True,
674 def push(self, wire, revisions, dest_path, hooks=True,
668 push_branches=False):
675 push_branches=False):
669 repo = self._factory.repo(wire)
676 repo = self._factory.repo(wire)
670 baseui = self._factory._create_config(wire['config'], hooks=hooks)
677 baseui = self._factory._create_config(wire['config'], hooks=hooks)
671 commands.push(baseui, repo, dest=dest_path, rev=revisions,
678 commands.push(baseui, repo, dest=dest_path, rev=revisions,
672 new_branch=push_branches)
679 new_branch=push_branches)
673
680
674 @reraise_safe_exceptions
681 @reraise_safe_exceptions
675 def merge(self, wire, revision):
682 def merge(self, wire, revision):
676 repo = self._factory.repo(wire)
683 repo = self._factory.repo(wire)
677 baseui = self._factory._create_config(wire['config'])
684 baseui = self._factory._create_config(wire['config'])
678 repo.ui.setconfig('ui', 'merge', 'internal:dump')
685 repo.ui.setconfig('ui', 'merge', 'internal:dump')
679 commands.merge(baseui, repo, rev=revision)
686 commands.merge(baseui, repo, rev=revision)
680
687
681 @reraise_safe_exceptions
688 @reraise_safe_exceptions
682 def commit(self, wire, message, username):
689 def commit(self, wire, message, username):
683 repo = self._factory.repo(wire)
690 repo = self._factory.repo(wire)
684 baseui = self._factory._create_config(wire['config'])
691 baseui = self._factory._create_config(wire['config'])
685 repo.ui.setconfig('ui', 'username', username)
692 repo.ui.setconfig('ui', 'username', username)
686 commands.commit(baseui, repo, message=message)
693 commands.commit(baseui, repo, message=message)
687
694
688 @reraise_safe_exceptions
695 @reraise_safe_exceptions
689 def rebase(self, wire, source=None, dest=None, abort=False):
696 def rebase(self, wire, source=None, dest=None, abort=False):
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', 'merge', 'internal:dump')
699 repo.ui.setconfig('ui', 'merge', 'internal:dump')
693 rebase.rebase(
700 rebase.rebase(
694 baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
701 baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
695
702
696 @reraise_safe_exceptions
703 @reraise_safe_exceptions
697 def bookmark(self, wire, bookmark, revision=None):
704 def bookmark(self, wire, bookmark, revision=None):
698 repo = self._factory.repo(wire)
705 repo = self._factory.repo(wire)
699 baseui = self._factory._create_config(wire['config'])
706 baseui = self._factory._create_config(wire['config'])
700 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
707 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
General Comments 0
You need to be logged in to leave comments. Login now