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