##// END OF EJS Templates
mercurial: don't raise exceptions on AmbiguousPrefixLookupError
super-admin -
r1141:9ac2e7b2 default
parent child Browse files
Show More
@@ -1,1159 +1,1164 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-2023 RhodeCode GmbH
2 # Copyright (C) 2014-2023 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 import binascii
17 import binascii
18 import io
18 import io
19 import logging
19 import logging
20 import stat
20 import stat
21 import urllib.request
21 import urllib.request
22 import urllib.parse
22 import urllib.parse
23 import traceback
23 import traceback
24 import hashlib
24 import hashlib
25
25
26 from hgext import largefiles, rebase, purge
26 from hgext import largefiles, rebase, purge
27
27
28 from mercurial import commands
28 from mercurial import commands
29 from mercurial import unionrepo
29 from mercurial import unionrepo
30 from mercurial import verify
30 from mercurial import verify
31 from mercurial import repair
31 from mercurial import repair
32 from mercurial.error import AmbiguousPrefixLookupError
32
33
33 import vcsserver
34 import vcsserver
34 from vcsserver import exceptions
35 from vcsserver import exceptions
35 from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original, store_archive_in_cache, ArchiveNode, BytesEnvelope, \
36 from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original, store_archive_in_cache, ArchiveNode, BytesEnvelope, \
36 BinaryEnvelope
37 BinaryEnvelope
37 from vcsserver.hgcompat import (
38 from vcsserver.hgcompat import (
38 archival, bin, clone, config as hgconfig, diffopts, hex, get_ctx,
39 archival, bin, clone, config as hgconfig, diffopts, hex, get_ctx,
39 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
40 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
40 makepeer, instance, match, memctx, exchange, memfilectx, nullrev, hg_merge,
41 makepeer, instance, match, memctx, exchange, memfilectx, nullrev, hg_merge,
41 patch, peer, revrange, ui, hg_tag, Abort, LookupError, RepoError,
42 patch, peer, revrange, ui, hg_tag, Abort, LookupError, RepoError,
42 RepoLookupError, InterventionRequired, RequirementError,
43 RepoLookupError, InterventionRequired, RequirementError,
43 alwaysmatcher, patternmatcher, hgutil, hgext_strip)
44 alwaysmatcher, patternmatcher, hgutil, hgext_strip)
44 from vcsserver.str_utils import ascii_bytes, ascii_str, safe_str, safe_bytes
45 from vcsserver.str_utils import ascii_bytes, ascii_str, safe_str, safe_bytes
45 from vcsserver.vcs_base import RemoteBase
46 from vcsserver.vcs_base import RemoteBase
46 from vcsserver.config import hooks as hooks_config
47 from vcsserver.config import hooks as hooks_config
47
48
48
49
49 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
50
51
51
52
52 def make_ui_from_config(repo_config):
53 def make_ui_from_config(repo_config):
53
54
54 class LoggingUI(ui.ui):
55 class LoggingUI(ui.ui):
55
56
56 def status(self, *msg, **opts):
57 def status(self, *msg, **opts):
57 str_msg = map(safe_str, msg)
58 str_msg = map(safe_str, msg)
58 log.info(' '.join(str_msg).rstrip('\n'))
59 log.info(' '.join(str_msg).rstrip('\n'))
59 #super(LoggingUI, self).status(*msg, **opts)
60 #super(LoggingUI, self).status(*msg, **opts)
60
61
61 def warn(self, *msg, **opts):
62 def warn(self, *msg, **opts):
62 str_msg = map(safe_str, msg)
63 str_msg = map(safe_str, msg)
63 log.warning('ui_logger:'+' '.join(str_msg).rstrip('\n'))
64 log.warning('ui_logger:'+' '.join(str_msg).rstrip('\n'))
64 #super(LoggingUI, self).warn(*msg, **opts)
65 #super(LoggingUI, self).warn(*msg, **opts)
65
66
66 def error(self, *msg, **opts):
67 def error(self, *msg, **opts):
67 str_msg = map(safe_str, msg)
68 str_msg = map(safe_str, msg)
68 log.error('ui_logger:'+' '.join(str_msg).rstrip('\n'))
69 log.error('ui_logger:'+' '.join(str_msg).rstrip('\n'))
69 #super(LoggingUI, self).error(*msg, **opts)
70 #super(LoggingUI, self).error(*msg, **opts)
70
71
71 def note(self, *msg, **opts):
72 def note(self, *msg, **opts):
72 str_msg = map(safe_str, msg)
73 str_msg = map(safe_str, msg)
73 log.info('ui_logger:'+' '.join(str_msg).rstrip('\n'))
74 log.info('ui_logger:'+' '.join(str_msg).rstrip('\n'))
74 #super(LoggingUI, self).note(*msg, **opts)
75 #super(LoggingUI, self).note(*msg, **opts)
75
76
76 def debug(self, *msg, **opts):
77 def debug(self, *msg, **opts):
77 str_msg = map(safe_str, msg)
78 str_msg = map(safe_str, msg)
78 log.debug('ui_logger:'+' '.join(str_msg).rstrip('\n'))
79 log.debug('ui_logger:'+' '.join(str_msg).rstrip('\n'))
79 #super(LoggingUI, self).debug(*msg, **opts)
80 #super(LoggingUI, self).debug(*msg, **opts)
80
81
81 baseui = LoggingUI()
82 baseui = LoggingUI()
82
83
83 # clean the baseui object
84 # clean the baseui object
84 baseui._ocfg = hgconfig.config()
85 baseui._ocfg = hgconfig.config()
85 baseui._ucfg = hgconfig.config()
86 baseui._ucfg = hgconfig.config()
86 baseui._tcfg = hgconfig.config()
87 baseui._tcfg = hgconfig.config()
87
88
88 for section, option, value in repo_config:
89 for section, option, value in repo_config:
89 baseui.setconfig(ascii_bytes(section), ascii_bytes(option), ascii_bytes(value))
90 baseui.setconfig(ascii_bytes(section), ascii_bytes(option), ascii_bytes(value))
90
91
91 # make our hgweb quiet so it doesn't print output
92 # make our hgweb quiet so it doesn't print output
92 baseui.setconfig(b'ui', b'quiet', b'true')
93 baseui.setconfig(b'ui', b'quiet', b'true')
93
94
94 baseui.setconfig(b'ui', b'paginate', b'never')
95 baseui.setconfig(b'ui', b'paginate', b'never')
95 # for better Error reporting of Mercurial
96 # for better Error reporting of Mercurial
96 baseui.setconfig(b'ui', b'message-output', b'stderr')
97 baseui.setconfig(b'ui', b'message-output', b'stderr')
97
98
98 # force mercurial to only use 1 thread, otherwise it may try to set a
99 # force mercurial to only use 1 thread, otherwise it may try to set a
99 # signal in a non-main thread, thus generating a ValueError.
100 # signal in a non-main thread, thus generating a ValueError.
100 baseui.setconfig(b'worker', b'numcpus', 1)
101 baseui.setconfig(b'worker', b'numcpus', 1)
101
102
102 # If there is no config for the largefiles extension, we explicitly disable
103 # If there is no config for the largefiles extension, we explicitly disable
103 # it here. This overrides settings from repositories hgrc file. Recent
104 # it here. This overrides settings from repositories hgrc file. Recent
104 # mercurial versions enable largefiles in hgrc on clone from largefile
105 # mercurial versions enable largefiles in hgrc on clone from largefile
105 # repo.
106 # repo.
106 if not baseui.hasconfig(b'extensions', b'largefiles'):
107 if not baseui.hasconfig(b'extensions', b'largefiles'):
107 log.debug('Explicitly disable largefiles extension for repo.')
108 log.debug('Explicitly disable largefiles extension for repo.')
108 baseui.setconfig(b'extensions', b'largefiles', b'!')
109 baseui.setconfig(b'extensions', b'largefiles', b'!')
109
110
110 return baseui
111 return baseui
111
112
112
113
113 def reraise_safe_exceptions(func):
114 def reraise_safe_exceptions(func):
114 """Decorator for converting mercurial exceptions to something neutral."""
115 """Decorator for converting mercurial exceptions to something neutral."""
115
116
116 def wrapper(*args, **kwargs):
117 def wrapper(*args, **kwargs):
117 try:
118 try:
118 return func(*args, **kwargs)
119 return func(*args, **kwargs)
119 except (Abort, InterventionRequired) as e:
120 except (Abort, InterventionRequired) as e:
120 raise_from_original(exceptions.AbortException(e), e)
121 raise_from_original(exceptions.AbortException(e), e)
121 except RepoLookupError as e:
122 except RepoLookupError as e:
122 raise_from_original(exceptions.LookupException(e), e)
123 raise_from_original(exceptions.LookupException(e), e)
123 except RequirementError as e:
124 except RequirementError as e:
124 raise_from_original(exceptions.RequirementException(e), e)
125 raise_from_original(exceptions.RequirementException(e), e)
125 except RepoError as e:
126 except RepoError as e:
126 raise_from_original(exceptions.VcsException(e), e)
127 raise_from_original(exceptions.VcsException(e), e)
127 except LookupError as e:
128 except LookupError as e:
128 raise_from_original(exceptions.LookupException(e), e)
129 raise_from_original(exceptions.LookupException(e), e)
129 except Exception as e:
130 except Exception as e:
130 if not hasattr(e, '_vcs_kind'):
131 if not hasattr(e, '_vcs_kind'):
131 log.exception("Unhandled exception in hg remote call")
132 log.exception("Unhandled exception in hg remote call")
132 raise_from_original(exceptions.UnhandledException(e), e)
133 raise_from_original(exceptions.UnhandledException(e), e)
133
134
134 raise
135 raise
135 return wrapper
136 return wrapper
136
137
137
138
138 class MercurialFactory(RepoFactory):
139 class MercurialFactory(RepoFactory):
139 repo_type = 'hg'
140 repo_type = 'hg'
140
141
141 def _create_config(self, config, hooks=True):
142 def _create_config(self, config, hooks=True):
142 if not hooks:
143 if not hooks:
143
144
144 hooks_to_clean = {
145 hooks_to_clean = {
145
146
146 hooks_config.HOOK_REPO_SIZE,
147 hooks_config.HOOK_REPO_SIZE,
147 hooks_config.HOOK_PRE_PULL,
148 hooks_config.HOOK_PRE_PULL,
148 hooks_config.HOOK_PULL,
149 hooks_config.HOOK_PULL,
149
150
150 hooks_config.HOOK_PRE_PUSH,
151 hooks_config.HOOK_PRE_PUSH,
151 # TODO: what about PRETXT, this was disabled in pre 5.0.0
152 # TODO: what about PRETXT, this was disabled in pre 5.0.0
152 hooks_config.HOOK_PRETX_PUSH,
153 hooks_config.HOOK_PRETX_PUSH,
153
154
154 }
155 }
155 new_config = []
156 new_config = []
156 for section, option, value in config:
157 for section, option, value in config:
157 if section == 'hooks' and option in hooks_to_clean:
158 if section == 'hooks' and option in hooks_to_clean:
158 continue
159 continue
159 new_config.append((section, option, value))
160 new_config.append((section, option, value))
160 config = new_config
161 config = new_config
161
162
162 baseui = make_ui_from_config(config)
163 baseui = make_ui_from_config(config)
163 return baseui
164 return baseui
164
165
165 def _create_repo(self, wire, create):
166 def _create_repo(self, wire, create):
166 baseui = self._create_config(wire["config"])
167 baseui = self._create_config(wire["config"])
167 repo = instance(baseui, safe_bytes(wire["path"]), create)
168 repo = instance(baseui, safe_bytes(wire["path"]), create)
168 log.debug('repository created: got HG object: %s', repo)
169 log.debug('repository created: got HG object: %s', repo)
169 return repo
170 return repo
170
171
171 def repo(self, wire, create=False):
172 def repo(self, wire, create=False):
172 """
173 """
173 Get a repository instance for the given path.
174 Get a repository instance for the given path.
174 """
175 """
175 return self._create_repo(wire, create)
176 return self._create_repo(wire, create)
176
177
177
178
178 def patch_ui_message_output(baseui):
179 def patch_ui_message_output(baseui):
179 baseui.setconfig(b'ui', b'quiet', b'false')
180 baseui.setconfig(b'ui', b'quiet', b'false')
180 output = io.BytesIO()
181 output = io.BytesIO()
181
182
182 def write(data, **unused_kwargs):
183 def write(data, **unused_kwargs):
183 output.write(data)
184 output.write(data)
184
185
185 baseui.status = write
186 baseui.status = write
186 baseui.write = write
187 baseui.write = write
187 baseui.warn = write
188 baseui.warn = write
188 baseui.debug = write
189 baseui.debug = write
189
190
190 return baseui, output
191 return baseui, output
191
192
192
193
193 def get_obfuscated_url(url_obj):
194 def get_obfuscated_url(url_obj):
194 url_obj.passwd = b'*****' if url_obj.passwd else url_obj.passwd
195 url_obj.passwd = b'*****' if url_obj.passwd else url_obj.passwd
195 url_obj.query = obfuscate_qs(url_obj.query)
196 url_obj.query = obfuscate_qs(url_obj.query)
196 obfuscated_uri = str(url_obj)
197 obfuscated_uri = str(url_obj)
197 return obfuscated_uri
198 return obfuscated_uri
198
199
199
200
200 def normalize_url_for_hg(url: str):
201 def normalize_url_for_hg(url: str):
201 _proto = None
202 _proto = None
202
203
203 if '+' in url[:url.find('://')]:
204 if '+' in url[:url.find('://')]:
204 _proto = url[0:url.find('+')]
205 _proto = url[0:url.find('+')]
205 url = url[url.find('+') + 1:]
206 url = url[url.find('+') + 1:]
206 return url, _proto
207 return url, _proto
207
208
208
209
209 class HgRemote(RemoteBase):
210 class HgRemote(RemoteBase):
210
211
211 def __init__(self, factory):
212 def __init__(self, factory):
212 self._factory = factory
213 self._factory = factory
213 self._bulk_methods = {
214 self._bulk_methods = {
214 "affected_files": self.ctx_files,
215 "affected_files": self.ctx_files,
215 "author": self.ctx_user,
216 "author": self.ctx_user,
216 "branch": self.ctx_branch,
217 "branch": self.ctx_branch,
217 "children": self.ctx_children,
218 "children": self.ctx_children,
218 "date": self.ctx_date,
219 "date": self.ctx_date,
219 "message": self.ctx_description,
220 "message": self.ctx_description,
220 "parents": self.ctx_parents,
221 "parents": self.ctx_parents,
221 "status": self.ctx_status,
222 "status": self.ctx_status,
222 "obsolete": self.ctx_obsolete,
223 "obsolete": self.ctx_obsolete,
223 "phase": self.ctx_phase,
224 "phase": self.ctx_phase,
224 "hidden": self.ctx_hidden,
225 "hidden": self.ctx_hidden,
225 "_file_paths": self.ctx_list,
226 "_file_paths": self.ctx_list,
226 }
227 }
227 self._bulk_file_methods = {
228 self._bulk_file_methods = {
228 "size": self.fctx_size,
229 "size": self.fctx_size,
229 "data": self.fctx_node_data,
230 "data": self.fctx_node_data,
230 "flags": self.fctx_flags,
231 "flags": self.fctx_flags,
231 "is_binary": self.is_binary,
232 "is_binary": self.is_binary,
232 "md5": self.md5_hash,
233 "md5": self.md5_hash,
233 }
234 }
234
235
235 def _get_ctx(self, repo, ref):
236 def _get_ctx(self, repo, ref):
236 return get_ctx(repo, ref)
237 return get_ctx(repo, ref)
237
238
238 @reraise_safe_exceptions
239 @reraise_safe_exceptions
239 def discover_hg_version(self):
240 def discover_hg_version(self):
240 from mercurial import util
241 from mercurial import util
241 return safe_str(util.version())
242 return safe_str(util.version())
242
243
243 @reraise_safe_exceptions
244 @reraise_safe_exceptions
244 def is_empty(self, wire):
245 def is_empty(self, wire):
245 repo = self._factory.repo(wire)
246 repo = self._factory.repo(wire)
246
247
247 try:
248 try:
248 return len(repo) == 0
249 return len(repo) == 0
249 except Exception:
250 except Exception:
250 log.exception("failed to read object_store")
251 log.exception("failed to read object_store")
251 return False
252 return False
252
253
253 @reraise_safe_exceptions
254 @reraise_safe_exceptions
254 def bookmarks(self, wire):
255 def bookmarks(self, wire):
255 cache_on, context_uid, repo_id = self._cache_on(wire)
256 cache_on, context_uid, repo_id = self._cache_on(wire)
256 region = self._region(wire)
257 region = self._region(wire)
257
258
258 @region.conditional_cache_on_arguments(condition=cache_on)
259 @region.conditional_cache_on_arguments(condition=cache_on)
259 def _bookmarks(_context_uid, _repo_id):
260 def _bookmarks(_context_uid, _repo_id):
260 repo = self._factory.repo(wire)
261 repo = self._factory.repo(wire)
261 return {safe_str(name): ascii_str(hex(sha)) for name, sha in repo._bookmarks.items()}
262 return {safe_str(name): ascii_str(hex(sha)) for name, sha in repo._bookmarks.items()}
262
263
263 return _bookmarks(context_uid, repo_id)
264 return _bookmarks(context_uid, repo_id)
264
265
265 @reraise_safe_exceptions
266 @reraise_safe_exceptions
266 def branches(self, wire, normal, closed):
267 def branches(self, wire, normal, closed):
267 cache_on, context_uid, repo_id = self._cache_on(wire)
268 cache_on, context_uid, repo_id = self._cache_on(wire)
268 region = self._region(wire)
269 region = self._region(wire)
269
270
270 @region.conditional_cache_on_arguments(condition=cache_on)
271 @region.conditional_cache_on_arguments(condition=cache_on)
271 def _branches(_context_uid, _repo_id, _normal, _closed):
272 def _branches(_context_uid, _repo_id, _normal, _closed):
272 repo = self._factory.repo(wire)
273 repo = self._factory.repo(wire)
273 iter_branches = repo.branchmap().iterbranches()
274 iter_branches = repo.branchmap().iterbranches()
274 bt = {}
275 bt = {}
275 for branch_name, _heads, tip_node, is_closed in iter_branches:
276 for branch_name, _heads, tip_node, is_closed in iter_branches:
276 if normal and not is_closed:
277 if normal and not is_closed:
277 bt[safe_str(branch_name)] = ascii_str(hex(tip_node))
278 bt[safe_str(branch_name)] = ascii_str(hex(tip_node))
278 if closed and is_closed:
279 if closed and is_closed:
279 bt[safe_str(branch_name)] = ascii_str(hex(tip_node))
280 bt[safe_str(branch_name)] = ascii_str(hex(tip_node))
280
281
281 return bt
282 return bt
282
283
283 return _branches(context_uid, repo_id, normal, closed)
284 return _branches(context_uid, repo_id, normal, closed)
284
285
285 @reraise_safe_exceptions
286 @reraise_safe_exceptions
286 def bulk_request(self, wire, commit_id, pre_load):
287 def bulk_request(self, wire, commit_id, pre_load):
287 cache_on, context_uid, repo_id = self._cache_on(wire)
288 cache_on, context_uid, repo_id = self._cache_on(wire)
288 region = self._region(wire)
289 region = self._region(wire)
289
290
290 @region.conditional_cache_on_arguments(condition=cache_on)
291 @region.conditional_cache_on_arguments(condition=cache_on)
291 def _bulk_request(_repo_id, _commit_id, _pre_load):
292 def _bulk_request(_repo_id, _commit_id, _pre_load):
292 result = {}
293 result = {}
293 for attr in pre_load:
294 for attr in pre_load:
294 try:
295 try:
295 method = self._bulk_methods[attr]
296 method = self._bulk_methods[attr]
296 wire.update({'cache': False}) # disable cache for bulk calls so we don't double cache
297 wire.update({'cache': False}) # disable cache for bulk calls so we don't double cache
297 result[attr] = method(wire, commit_id)
298 result[attr] = method(wire, commit_id)
298 except KeyError as e:
299 except KeyError as e:
299 raise exceptions.VcsException(e)(
300 raise exceptions.VcsException(e)(
300 'Unknown bulk attribute: "%s"' % attr)
301 'Unknown bulk attribute: "%s"' % attr)
301 return result
302 return result
302
303
303 return _bulk_request(repo_id, commit_id, sorted(pre_load))
304 return _bulk_request(repo_id, commit_id, sorted(pre_load))
304
305
305 @reraise_safe_exceptions
306 @reraise_safe_exceptions
306 def ctx_branch(self, wire, commit_id):
307 def ctx_branch(self, wire, commit_id):
307 cache_on, context_uid, repo_id = self._cache_on(wire)
308 cache_on, context_uid, repo_id = self._cache_on(wire)
308 region = self._region(wire)
309 region = self._region(wire)
309
310
310 @region.conditional_cache_on_arguments(condition=cache_on)
311 @region.conditional_cache_on_arguments(condition=cache_on)
311 def _ctx_branch(_repo_id, _commit_id):
312 def _ctx_branch(_repo_id, _commit_id):
312 repo = self._factory.repo(wire)
313 repo = self._factory.repo(wire)
313 ctx = self._get_ctx(repo, commit_id)
314 ctx = self._get_ctx(repo, commit_id)
314 return ctx.branch()
315 return ctx.branch()
315 return _ctx_branch(repo_id, commit_id)
316 return _ctx_branch(repo_id, commit_id)
316
317
317 @reraise_safe_exceptions
318 @reraise_safe_exceptions
318 def ctx_date(self, wire, commit_id):
319 def ctx_date(self, wire, commit_id):
319 cache_on, context_uid, repo_id = self._cache_on(wire)
320 cache_on, context_uid, repo_id = self._cache_on(wire)
320 region = self._region(wire)
321 region = self._region(wire)
321
322
322 @region.conditional_cache_on_arguments(condition=cache_on)
323 @region.conditional_cache_on_arguments(condition=cache_on)
323 def _ctx_date(_repo_id, _commit_id):
324 def _ctx_date(_repo_id, _commit_id):
324 repo = self._factory.repo(wire)
325 repo = self._factory.repo(wire)
325 ctx = self._get_ctx(repo, commit_id)
326 ctx = self._get_ctx(repo, commit_id)
326 return ctx.date()
327 return ctx.date()
327 return _ctx_date(repo_id, commit_id)
328 return _ctx_date(repo_id, commit_id)
328
329
329 @reraise_safe_exceptions
330 @reraise_safe_exceptions
330 def ctx_description(self, wire, revision):
331 def ctx_description(self, wire, revision):
331 repo = self._factory.repo(wire)
332 repo = self._factory.repo(wire)
332 ctx = self._get_ctx(repo, revision)
333 ctx = self._get_ctx(repo, revision)
333 return ctx.description()
334 return ctx.description()
334
335
335 @reraise_safe_exceptions
336 @reraise_safe_exceptions
336 def ctx_files(self, wire, commit_id):
337 def ctx_files(self, wire, commit_id):
337 cache_on, context_uid, repo_id = self._cache_on(wire)
338 cache_on, context_uid, repo_id = self._cache_on(wire)
338 region = self._region(wire)
339 region = self._region(wire)
339
340
340 @region.conditional_cache_on_arguments(condition=cache_on)
341 @region.conditional_cache_on_arguments(condition=cache_on)
341 def _ctx_files(_repo_id, _commit_id):
342 def _ctx_files(_repo_id, _commit_id):
342 repo = self._factory.repo(wire)
343 repo = self._factory.repo(wire)
343 ctx = self._get_ctx(repo, commit_id)
344 ctx = self._get_ctx(repo, commit_id)
344 return ctx.files()
345 return ctx.files()
345
346
346 return _ctx_files(repo_id, commit_id)
347 return _ctx_files(repo_id, commit_id)
347
348
348 @reraise_safe_exceptions
349 @reraise_safe_exceptions
349 def ctx_list(self, path, revision):
350 def ctx_list(self, path, revision):
350 repo = self._factory.repo(path)
351 repo = self._factory.repo(path)
351 ctx = self._get_ctx(repo, revision)
352 ctx = self._get_ctx(repo, revision)
352 return list(ctx)
353 return list(ctx)
353
354
354 @reraise_safe_exceptions
355 @reraise_safe_exceptions
355 def ctx_parents(self, wire, commit_id):
356 def ctx_parents(self, wire, commit_id):
356 cache_on, context_uid, repo_id = self._cache_on(wire)
357 cache_on, context_uid, repo_id = self._cache_on(wire)
357 region = self._region(wire)
358 region = self._region(wire)
358
359
359 @region.conditional_cache_on_arguments(condition=cache_on)
360 @region.conditional_cache_on_arguments(condition=cache_on)
360 def _ctx_parents(_repo_id, _commit_id):
361 def _ctx_parents(_repo_id, _commit_id):
361 repo = self._factory.repo(wire)
362 repo = self._factory.repo(wire)
362 ctx = self._get_ctx(repo, commit_id)
363 ctx = self._get_ctx(repo, commit_id)
363 return [parent.hex() for parent in ctx.parents()
364 return [parent.hex() for parent in ctx.parents()
364 if not (parent.hidden() or parent.obsolete())]
365 if not (parent.hidden() or parent.obsolete())]
365
366
366 return _ctx_parents(repo_id, commit_id)
367 return _ctx_parents(repo_id, commit_id)
367
368
368 @reraise_safe_exceptions
369 @reraise_safe_exceptions
369 def ctx_children(self, wire, commit_id):
370 def ctx_children(self, wire, commit_id):
370 cache_on, context_uid, repo_id = self._cache_on(wire)
371 cache_on, context_uid, repo_id = self._cache_on(wire)
371 region = self._region(wire)
372 region = self._region(wire)
372
373
373 @region.conditional_cache_on_arguments(condition=cache_on)
374 @region.conditional_cache_on_arguments(condition=cache_on)
374 def _ctx_children(_repo_id, _commit_id):
375 def _ctx_children(_repo_id, _commit_id):
375 repo = self._factory.repo(wire)
376 repo = self._factory.repo(wire)
376 ctx = self._get_ctx(repo, commit_id)
377 ctx = self._get_ctx(repo, commit_id)
377 return [child.hex() for child in ctx.children()
378 return [child.hex() for child in ctx.children()
378 if not (child.hidden() or child.obsolete())]
379 if not (child.hidden() or child.obsolete())]
379
380
380 return _ctx_children(repo_id, commit_id)
381 return _ctx_children(repo_id, commit_id)
381
382
382 @reraise_safe_exceptions
383 @reraise_safe_exceptions
383 def ctx_phase(self, wire, commit_id):
384 def ctx_phase(self, wire, commit_id):
384 cache_on, context_uid, repo_id = self._cache_on(wire)
385 cache_on, context_uid, repo_id = self._cache_on(wire)
385 region = self._region(wire)
386 region = self._region(wire)
386
387
387 @region.conditional_cache_on_arguments(condition=cache_on)
388 @region.conditional_cache_on_arguments(condition=cache_on)
388 def _ctx_phase(_context_uid, _repo_id, _commit_id):
389 def _ctx_phase(_context_uid, _repo_id, _commit_id):
389 repo = self._factory.repo(wire)
390 repo = self._factory.repo(wire)
390 ctx = self._get_ctx(repo, commit_id)
391 ctx = self._get_ctx(repo, commit_id)
391 # public=0, draft=1, secret=3
392 # public=0, draft=1, secret=3
392 return ctx.phase()
393 return ctx.phase()
393 return _ctx_phase(context_uid, repo_id, commit_id)
394 return _ctx_phase(context_uid, repo_id, commit_id)
394
395
395 @reraise_safe_exceptions
396 @reraise_safe_exceptions
396 def ctx_obsolete(self, wire, commit_id):
397 def ctx_obsolete(self, wire, commit_id):
397 cache_on, context_uid, repo_id = self._cache_on(wire)
398 cache_on, context_uid, repo_id = self._cache_on(wire)
398 region = self._region(wire)
399 region = self._region(wire)
399
400
400 @region.conditional_cache_on_arguments(condition=cache_on)
401 @region.conditional_cache_on_arguments(condition=cache_on)
401 def _ctx_obsolete(_context_uid, _repo_id, _commit_id):
402 def _ctx_obsolete(_context_uid, _repo_id, _commit_id):
402 repo = self._factory.repo(wire)
403 repo = self._factory.repo(wire)
403 ctx = self._get_ctx(repo, commit_id)
404 ctx = self._get_ctx(repo, commit_id)
404 return ctx.obsolete()
405 return ctx.obsolete()
405 return _ctx_obsolete(context_uid, repo_id, commit_id)
406 return _ctx_obsolete(context_uid, repo_id, commit_id)
406
407
407 @reraise_safe_exceptions
408 @reraise_safe_exceptions
408 def ctx_hidden(self, wire, commit_id):
409 def ctx_hidden(self, wire, commit_id):
409 cache_on, context_uid, repo_id = self._cache_on(wire)
410 cache_on, context_uid, repo_id = self._cache_on(wire)
410 region = self._region(wire)
411 region = self._region(wire)
411
412
412 @region.conditional_cache_on_arguments(condition=cache_on)
413 @region.conditional_cache_on_arguments(condition=cache_on)
413 def _ctx_hidden(_context_uid, _repo_id, _commit_id):
414 def _ctx_hidden(_context_uid, _repo_id, _commit_id):
414 repo = self._factory.repo(wire)
415 repo = self._factory.repo(wire)
415 ctx = self._get_ctx(repo, commit_id)
416 ctx = self._get_ctx(repo, commit_id)
416 return ctx.hidden()
417 return ctx.hidden()
417 return _ctx_hidden(context_uid, repo_id, commit_id)
418 return _ctx_hidden(context_uid, repo_id, commit_id)
418
419
419 @reraise_safe_exceptions
420 @reraise_safe_exceptions
420 def ctx_substate(self, wire, revision):
421 def ctx_substate(self, wire, revision):
421 repo = self._factory.repo(wire)
422 repo = self._factory.repo(wire)
422 ctx = self._get_ctx(repo, revision)
423 ctx = self._get_ctx(repo, revision)
423 return ctx.substate
424 return ctx.substate
424
425
425 @reraise_safe_exceptions
426 @reraise_safe_exceptions
426 def ctx_status(self, wire, revision):
427 def ctx_status(self, wire, revision):
427 repo = self._factory.repo(wire)
428 repo = self._factory.repo(wire)
428 ctx = self._get_ctx(repo, revision)
429 ctx = self._get_ctx(repo, revision)
429 status = repo[ctx.p1().node()].status(other=ctx.node())
430 status = repo[ctx.p1().node()].status(other=ctx.node())
430 # object of status (odd, custom named tuple in mercurial) is not
431 # object of status (odd, custom named tuple in mercurial) is not
431 # correctly serializable, we make it a list, as the underling
432 # correctly serializable, we make it a list, as the underling
432 # API expects this to be a list
433 # API expects this to be a list
433 return list(status)
434 return list(status)
434
435
435 @reraise_safe_exceptions
436 @reraise_safe_exceptions
436 def ctx_user(self, wire, revision):
437 def ctx_user(self, wire, revision):
437 repo = self._factory.repo(wire)
438 repo = self._factory.repo(wire)
438 ctx = self._get_ctx(repo, revision)
439 ctx = self._get_ctx(repo, revision)
439 return ctx.user()
440 return ctx.user()
440
441
441 @reraise_safe_exceptions
442 @reraise_safe_exceptions
442 def check_url(self, url, config):
443 def check_url(self, url, config):
443 url, _proto = normalize_url_for_hg(url)
444 url, _proto = normalize_url_for_hg(url)
444 url_obj = url_parser(safe_bytes(url))
445 url_obj = url_parser(safe_bytes(url))
445
446
446 test_uri = safe_str(url_obj.authinfo()[0])
447 test_uri = safe_str(url_obj.authinfo()[0])
447 authinfo = url_obj.authinfo()[1]
448 authinfo = url_obj.authinfo()[1]
448 obfuscated_uri = get_obfuscated_url(url_obj)
449 obfuscated_uri = get_obfuscated_url(url_obj)
449 log.info("Checking URL for remote cloning/import: %s", obfuscated_uri)
450 log.info("Checking URL for remote cloning/import: %s", obfuscated_uri)
450
451
451 handlers = []
452 handlers = []
452 if authinfo:
453 if authinfo:
453 # create a password manager
454 # create a password manager
454 passmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
455 passmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
455 passmgr.add_password(*authinfo)
456 passmgr.add_password(*authinfo)
456
457
457 handlers.extend((httpbasicauthhandler(passmgr),
458 handlers.extend((httpbasicauthhandler(passmgr),
458 httpdigestauthhandler(passmgr)))
459 httpdigestauthhandler(passmgr)))
459
460
460 o = urllib.request.build_opener(*handlers)
461 o = urllib.request.build_opener(*handlers)
461 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
462 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
462 ('Accept', 'application/mercurial-0.1')]
463 ('Accept', 'application/mercurial-0.1')]
463
464
464 q = {"cmd": 'between'}
465 q = {"cmd": 'between'}
465 q.update({'pairs': "{}-{}".format('0' * 40, '0' * 40)})
466 q.update({'pairs': "{}-{}".format('0' * 40, '0' * 40)})
466 qs = '?%s' % urllib.parse.urlencode(q)
467 qs = '?%s' % urllib.parse.urlencode(q)
467 cu = f"{test_uri}{qs}"
468 cu = f"{test_uri}{qs}"
468 req = urllib.request.Request(cu, None, {})
469 req = urllib.request.Request(cu, None, {})
469
470
470 try:
471 try:
471 log.debug("Trying to open URL %s", obfuscated_uri)
472 log.debug("Trying to open URL %s", obfuscated_uri)
472 resp = o.open(req)
473 resp = o.open(req)
473 if resp.code != 200:
474 if resp.code != 200:
474 raise exceptions.URLError()('Return Code is not 200')
475 raise exceptions.URLError()('Return Code is not 200')
475 except Exception as e:
476 except Exception as e:
476 log.warning("URL cannot be opened: %s", obfuscated_uri, exc_info=True)
477 log.warning("URL cannot be opened: %s", obfuscated_uri, exc_info=True)
477 # means it cannot be cloned
478 # means it cannot be cloned
478 raise exceptions.URLError(e)(f"[{obfuscated_uri}] org_exc: {e}")
479 raise exceptions.URLError(e)(f"[{obfuscated_uri}] org_exc: {e}")
479
480
480 # now check if it's a proper hg repo, but don't do it for svn
481 # now check if it's a proper hg repo, but don't do it for svn
481 try:
482 try:
482 if _proto == 'svn':
483 if _proto == 'svn':
483 pass
484 pass
484 else:
485 else:
485 # check for pure hg repos
486 # check for pure hg repos
486 log.debug(
487 log.debug(
487 "Verifying if URL is a Mercurial repository: %s", obfuscated_uri)
488 "Verifying if URL is a Mercurial repository: %s", obfuscated_uri)
488 ui = make_ui_from_config(config)
489 ui = make_ui_from_config(config)
489 peer_checker = makepeer(ui, safe_bytes(url))
490 peer_checker = makepeer(ui, safe_bytes(url))
490 peer_checker.lookup(b'tip')
491 peer_checker.lookup(b'tip')
491 except Exception as e:
492 except Exception as e:
492 log.warning("URL is not a valid Mercurial repository: %s",
493 log.warning("URL is not a valid Mercurial repository: %s",
493 obfuscated_uri)
494 obfuscated_uri)
494 raise exceptions.URLError(e)(
495 raise exceptions.URLError(e)(
495 "url [%s] does not look like an hg repo org_exc: %s"
496 "url [%s] does not look like an hg repo org_exc: %s"
496 % (obfuscated_uri, e))
497 % (obfuscated_uri, e))
497
498
498 log.info("URL is a valid Mercurial repository: %s", obfuscated_uri)
499 log.info("URL is a valid Mercurial repository: %s", obfuscated_uri)
499 return True
500 return True
500
501
501 @reraise_safe_exceptions
502 @reraise_safe_exceptions
502 def diff(self, wire, commit_id_1, commit_id_2, file_filter, opt_git, opt_ignorews, context):
503 def diff(self, wire, commit_id_1, commit_id_2, file_filter, opt_git, opt_ignorews, context):
503 repo = self._factory.repo(wire)
504 repo = self._factory.repo(wire)
504
505
505 if file_filter:
506 if file_filter:
506 # unpack the file-filter
507 # unpack the file-filter
507 repo_path, node_path = file_filter
508 repo_path, node_path = file_filter
508 match_filter = match(safe_bytes(repo_path), b'', [safe_bytes(node_path)])
509 match_filter = match(safe_bytes(repo_path), b'', [safe_bytes(node_path)])
509 else:
510 else:
510 match_filter = file_filter
511 match_filter = file_filter
511 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context, showfunc=1)
512 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context, showfunc=1)
512
513
513 try:
514 try:
514 diff_iter = patch.diff(
515 diff_iter = patch.diff(
515 repo, node1=commit_id_1, node2=commit_id_2, match=match_filter, opts=opts)
516 repo, node1=commit_id_1, node2=commit_id_2, match=match_filter, opts=opts)
516 return BytesEnvelope(b"".join(diff_iter))
517 return BytesEnvelope(b"".join(diff_iter))
517 except RepoLookupError as e:
518 except RepoLookupError as e:
518 raise exceptions.LookupException(e)()
519 raise exceptions.LookupException(e)()
519
520
520 @reraise_safe_exceptions
521 @reraise_safe_exceptions
521 def node_history(self, wire, revision, path, limit):
522 def node_history(self, wire, revision, path, limit):
522 cache_on, context_uid, repo_id = self._cache_on(wire)
523 cache_on, context_uid, repo_id = self._cache_on(wire)
523 region = self._region(wire)
524 region = self._region(wire)
524
525
525 @region.conditional_cache_on_arguments(condition=cache_on)
526 @region.conditional_cache_on_arguments(condition=cache_on)
526 def _node_history(_context_uid, _repo_id, _revision, _path, _limit):
527 def _node_history(_context_uid, _repo_id, _revision, _path, _limit):
527 repo = self._factory.repo(wire)
528 repo = self._factory.repo(wire)
528
529
529 ctx = self._get_ctx(repo, revision)
530 ctx = self._get_ctx(repo, revision)
530 fctx = ctx.filectx(safe_bytes(path))
531 fctx = ctx.filectx(safe_bytes(path))
531
532
532 def history_iter():
533 def history_iter():
533 limit_rev = fctx.rev()
534 limit_rev = fctx.rev()
534 for obj in reversed(list(fctx.filelog())):
535 for obj in reversed(list(fctx.filelog())):
535 obj = fctx.filectx(obj)
536 obj = fctx.filectx(obj)
536 ctx = obj.changectx()
537 ctx = obj.changectx()
537 if ctx.hidden() or ctx.obsolete():
538 if ctx.hidden() or ctx.obsolete():
538 continue
539 continue
539
540
540 if limit_rev >= obj.rev():
541 if limit_rev >= obj.rev():
541 yield obj
542 yield obj
542
543
543 history = []
544 history = []
544 for cnt, obj in enumerate(history_iter()):
545 for cnt, obj in enumerate(history_iter()):
545 if limit and cnt >= limit:
546 if limit and cnt >= limit:
546 break
547 break
547 history.append(hex(obj.node()))
548 history.append(hex(obj.node()))
548
549
549 return [x for x in history]
550 return [x for x in history]
550 return _node_history(context_uid, repo_id, revision, path, limit)
551 return _node_history(context_uid, repo_id, revision, path, limit)
551
552
552 @reraise_safe_exceptions
553 @reraise_safe_exceptions
553 def node_history_untill(self, wire, revision, path, limit):
554 def node_history_untill(self, wire, revision, path, limit):
554 cache_on, context_uid, repo_id = self._cache_on(wire)
555 cache_on, context_uid, repo_id = self._cache_on(wire)
555 region = self._region(wire)
556 region = self._region(wire)
556
557
557 @region.conditional_cache_on_arguments(condition=cache_on)
558 @region.conditional_cache_on_arguments(condition=cache_on)
558 def _node_history_until(_context_uid, _repo_id):
559 def _node_history_until(_context_uid, _repo_id):
559 repo = self._factory.repo(wire)
560 repo = self._factory.repo(wire)
560 ctx = self._get_ctx(repo, revision)
561 ctx = self._get_ctx(repo, revision)
561 fctx = ctx.filectx(safe_bytes(path))
562 fctx = ctx.filectx(safe_bytes(path))
562
563
563 file_log = list(fctx.filelog())
564 file_log = list(fctx.filelog())
564 if limit:
565 if limit:
565 # Limit to the last n items
566 # Limit to the last n items
566 file_log = file_log[-limit:]
567 file_log = file_log[-limit:]
567
568
568 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
569 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
569 return _node_history_until(context_uid, repo_id, revision, path, limit)
570 return _node_history_until(context_uid, repo_id, revision, path, limit)
570
571
571 @reraise_safe_exceptions
572 @reraise_safe_exceptions
572 def bulk_file_request(self, wire, commit_id, path, pre_load):
573 def bulk_file_request(self, wire, commit_id, path, pre_load):
573 cache_on, context_uid, repo_id = self._cache_on(wire)
574 cache_on, context_uid, repo_id = self._cache_on(wire)
574 region = self._region(wire)
575 region = self._region(wire)
575
576
576 @region.conditional_cache_on_arguments(condition=cache_on)
577 @region.conditional_cache_on_arguments(condition=cache_on)
577 def _bulk_file_request(_repo_id, _commit_id, _path, _pre_load):
578 def _bulk_file_request(_repo_id, _commit_id, _path, _pre_load):
578 result = {}
579 result = {}
579 for attr in pre_load:
580 for attr in pre_load:
580 try:
581 try:
581 method = self._bulk_file_methods[attr]
582 method = self._bulk_file_methods[attr]
582 wire.update({'cache': False}) # disable cache for bulk calls so we don't double cache
583 wire.update({'cache': False}) # disable cache for bulk calls so we don't double cache
583 result[attr] = method(wire, _commit_id, _path)
584 result[attr] = method(wire, _commit_id, _path)
584 except KeyError as e:
585 except KeyError as e:
585 raise exceptions.VcsException(e)(f'Unknown bulk attribute: "{attr}"')
586 raise exceptions.VcsException(e)(f'Unknown bulk attribute: "{attr}"')
586 return result
587 return result
587
588
588 return BinaryEnvelope(_bulk_file_request(repo_id, commit_id, path, sorted(pre_load)))
589 return BinaryEnvelope(_bulk_file_request(repo_id, commit_id, path, sorted(pre_load)))
589
590
590 @reraise_safe_exceptions
591 @reraise_safe_exceptions
591 def fctx_annotate(self, wire, revision, path):
592 def fctx_annotate(self, wire, revision, path):
592 repo = self._factory.repo(wire)
593 repo = self._factory.repo(wire)
593 ctx = self._get_ctx(repo, revision)
594 ctx = self._get_ctx(repo, revision)
594 fctx = ctx.filectx(safe_bytes(path))
595 fctx = ctx.filectx(safe_bytes(path))
595
596
596 result = []
597 result = []
597 for i, annotate_obj in enumerate(fctx.annotate(), 1):
598 for i, annotate_obj in enumerate(fctx.annotate(), 1):
598 ln_no = i
599 ln_no = i
599 sha = hex(annotate_obj.fctx.node())
600 sha = hex(annotate_obj.fctx.node())
600 content = annotate_obj.text
601 content = annotate_obj.text
601 result.append((ln_no, ascii_str(sha), content))
602 result.append((ln_no, ascii_str(sha), content))
602 return BinaryEnvelope(result)
603 return BinaryEnvelope(result)
603
604
604 @reraise_safe_exceptions
605 @reraise_safe_exceptions
605 def fctx_node_data(self, wire, revision, path):
606 def fctx_node_data(self, wire, revision, path):
606 repo = self._factory.repo(wire)
607 repo = self._factory.repo(wire)
607 ctx = self._get_ctx(repo, revision)
608 ctx = self._get_ctx(repo, revision)
608 fctx = ctx.filectx(safe_bytes(path))
609 fctx = ctx.filectx(safe_bytes(path))
609 return BytesEnvelope(fctx.data())
610 return BytesEnvelope(fctx.data())
610
611
611 @reraise_safe_exceptions
612 @reraise_safe_exceptions
612 def fctx_flags(self, wire, commit_id, path):
613 def fctx_flags(self, wire, commit_id, path):
613 cache_on, context_uid, repo_id = self._cache_on(wire)
614 cache_on, context_uid, repo_id = self._cache_on(wire)
614 region = self._region(wire)
615 region = self._region(wire)
615
616
616 @region.conditional_cache_on_arguments(condition=cache_on)
617 @region.conditional_cache_on_arguments(condition=cache_on)
617 def _fctx_flags(_repo_id, _commit_id, _path):
618 def _fctx_flags(_repo_id, _commit_id, _path):
618 repo = self._factory.repo(wire)
619 repo = self._factory.repo(wire)
619 ctx = self._get_ctx(repo, commit_id)
620 ctx = self._get_ctx(repo, commit_id)
620 fctx = ctx.filectx(safe_bytes(path))
621 fctx = ctx.filectx(safe_bytes(path))
621 return fctx.flags()
622 return fctx.flags()
622
623
623 return _fctx_flags(repo_id, commit_id, path)
624 return _fctx_flags(repo_id, commit_id, path)
624
625
625 @reraise_safe_exceptions
626 @reraise_safe_exceptions
626 def fctx_size(self, wire, commit_id, path):
627 def fctx_size(self, wire, commit_id, path):
627 cache_on, context_uid, repo_id = self._cache_on(wire)
628 cache_on, context_uid, repo_id = self._cache_on(wire)
628 region = self._region(wire)
629 region = self._region(wire)
629
630
630 @region.conditional_cache_on_arguments(condition=cache_on)
631 @region.conditional_cache_on_arguments(condition=cache_on)
631 def _fctx_size(_repo_id, _revision, _path):
632 def _fctx_size(_repo_id, _revision, _path):
632 repo = self._factory.repo(wire)
633 repo = self._factory.repo(wire)
633 ctx = self._get_ctx(repo, commit_id)
634 ctx = self._get_ctx(repo, commit_id)
634 fctx = ctx.filectx(safe_bytes(path))
635 fctx = ctx.filectx(safe_bytes(path))
635 return fctx.size()
636 return fctx.size()
636 return _fctx_size(repo_id, commit_id, path)
637 return _fctx_size(repo_id, commit_id, path)
637
638
638 @reraise_safe_exceptions
639 @reraise_safe_exceptions
639 def get_all_commit_ids(self, wire, name):
640 def get_all_commit_ids(self, wire, name):
640 cache_on, context_uid, repo_id = self._cache_on(wire)
641 cache_on, context_uid, repo_id = self._cache_on(wire)
641 region = self._region(wire)
642 region = self._region(wire)
642
643
643 @region.conditional_cache_on_arguments(condition=cache_on)
644 @region.conditional_cache_on_arguments(condition=cache_on)
644 def _get_all_commit_ids(_context_uid, _repo_id, _name):
645 def _get_all_commit_ids(_context_uid, _repo_id, _name):
645 repo = self._factory.repo(wire)
646 repo = self._factory.repo(wire)
646 revs = [ascii_str(repo[x].hex()) for x in repo.filtered(b'visible').changelog.revs()]
647 revs = [ascii_str(repo[x].hex()) for x in repo.filtered(b'visible').changelog.revs()]
647 return revs
648 return revs
648 return _get_all_commit_ids(context_uid, repo_id, name)
649 return _get_all_commit_ids(context_uid, repo_id, name)
649
650
650 @reraise_safe_exceptions
651 @reraise_safe_exceptions
651 def get_config_value(self, wire, section, name, untrusted=False):
652 def get_config_value(self, wire, section, name, untrusted=False):
652 repo = self._factory.repo(wire)
653 repo = self._factory.repo(wire)
653 return repo.ui.config(ascii_bytes(section), ascii_bytes(name), untrusted=untrusted)
654 return repo.ui.config(ascii_bytes(section), ascii_bytes(name), untrusted=untrusted)
654
655
655 @reraise_safe_exceptions
656 @reraise_safe_exceptions
656 def is_large_file(self, wire, commit_id, path):
657 def is_large_file(self, wire, commit_id, path):
657 cache_on, context_uid, repo_id = self._cache_on(wire)
658 cache_on, context_uid, repo_id = self._cache_on(wire)
658 region = self._region(wire)
659 region = self._region(wire)
659
660
660 @region.conditional_cache_on_arguments(condition=cache_on)
661 @region.conditional_cache_on_arguments(condition=cache_on)
661 def _is_large_file(_context_uid, _repo_id, _commit_id, _path):
662 def _is_large_file(_context_uid, _repo_id, _commit_id, _path):
662 return largefiles.lfutil.isstandin(safe_bytes(path))
663 return largefiles.lfutil.isstandin(safe_bytes(path))
663
664
664 return _is_large_file(context_uid, repo_id, commit_id, path)
665 return _is_large_file(context_uid, repo_id, commit_id, path)
665
666
666 @reraise_safe_exceptions
667 @reraise_safe_exceptions
667 def is_binary(self, wire, revision, path):
668 def is_binary(self, wire, revision, path):
668 cache_on, context_uid, repo_id = self._cache_on(wire)
669 cache_on, context_uid, repo_id = self._cache_on(wire)
669 region = self._region(wire)
670 region = self._region(wire)
670
671
671 @region.conditional_cache_on_arguments(condition=cache_on)
672 @region.conditional_cache_on_arguments(condition=cache_on)
672 def _is_binary(_repo_id, _sha, _path):
673 def _is_binary(_repo_id, _sha, _path):
673 repo = self._factory.repo(wire)
674 repo = self._factory.repo(wire)
674 ctx = self._get_ctx(repo, revision)
675 ctx = self._get_ctx(repo, revision)
675 fctx = ctx.filectx(safe_bytes(path))
676 fctx = ctx.filectx(safe_bytes(path))
676 return fctx.isbinary()
677 return fctx.isbinary()
677
678
678 return _is_binary(repo_id, revision, path)
679 return _is_binary(repo_id, revision, path)
679
680
680 @reraise_safe_exceptions
681 @reraise_safe_exceptions
681 def md5_hash(self, wire, revision, path):
682 def md5_hash(self, wire, revision, path):
682 cache_on, context_uid, repo_id = self._cache_on(wire)
683 cache_on, context_uid, repo_id = self._cache_on(wire)
683 region = self._region(wire)
684 region = self._region(wire)
684
685
685 @region.conditional_cache_on_arguments(condition=cache_on)
686 @region.conditional_cache_on_arguments(condition=cache_on)
686 def _md5_hash(_repo_id, _sha, _path):
687 def _md5_hash(_repo_id, _sha, _path):
687 repo = self._factory.repo(wire)
688 repo = self._factory.repo(wire)
688 ctx = self._get_ctx(repo, revision)
689 ctx = self._get_ctx(repo, revision)
689 fctx = ctx.filectx(safe_bytes(path))
690 fctx = ctx.filectx(safe_bytes(path))
690 return hashlib.md5(fctx.data()).hexdigest()
691 return hashlib.md5(fctx.data()).hexdigest()
691
692
692 return _md5_hash(repo_id, revision, path)
693 return _md5_hash(repo_id, revision, path)
693
694
694 @reraise_safe_exceptions
695 @reraise_safe_exceptions
695 def in_largefiles_store(self, wire, sha):
696 def in_largefiles_store(self, wire, sha):
696 repo = self._factory.repo(wire)
697 repo = self._factory.repo(wire)
697 return largefiles.lfutil.instore(repo, sha)
698 return largefiles.lfutil.instore(repo, sha)
698
699
699 @reraise_safe_exceptions
700 @reraise_safe_exceptions
700 def in_user_cache(self, wire, sha):
701 def in_user_cache(self, wire, sha):
701 repo = self._factory.repo(wire)
702 repo = self._factory.repo(wire)
702 return largefiles.lfutil.inusercache(repo.ui, sha)
703 return largefiles.lfutil.inusercache(repo.ui, sha)
703
704
704 @reraise_safe_exceptions
705 @reraise_safe_exceptions
705 def store_path(self, wire, sha):
706 def store_path(self, wire, sha):
706 repo = self._factory.repo(wire)
707 repo = self._factory.repo(wire)
707 return largefiles.lfutil.storepath(repo, sha)
708 return largefiles.lfutil.storepath(repo, sha)
708
709
709 @reraise_safe_exceptions
710 @reraise_safe_exceptions
710 def link(self, wire, sha, path):
711 def link(self, wire, sha, path):
711 repo = self._factory.repo(wire)
712 repo = self._factory.repo(wire)
712 largefiles.lfutil.link(
713 largefiles.lfutil.link(
713 largefiles.lfutil.usercachepath(repo.ui, sha), path)
714 largefiles.lfutil.usercachepath(repo.ui, sha), path)
714
715
715 @reraise_safe_exceptions
716 @reraise_safe_exceptions
716 def localrepository(self, wire, create=False):
717 def localrepository(self, wire, create=False):
717 self._factory.repo(wire, create=create)
718 self._factory.repo(wire, create=create)
718
719
719 @reraise_safe_exceptions
720 @reraise_safe_exceptions
720 def lookup(self, wire, revision, both):
721 def lookup(self, wire, revision, both):
721 cache_on, context_uid, repo_id = self._cache_on(wire)
722 cache_on, context_uid, repo_id = self._cache_on(wire)
722 region = self._region(wire)
723 region = self._region(wire)
723
724
724 @region.conditional_cache_on_arguments(condition=cache_on)
725 @region.conditional_cache_on_arguments(condition=cache_on)
725 def _lookup(_context_uid, _repo_id, _revision, _both):
726 def _lookup(_context_uid, _repo_id, _revision, _both):
726 repo = self._factory.repo(wire)
727 repo = self._factory.repo(wire)
727 rev = _revision
728 rev = _revision
728 if isinstance(rev, int):
729 if isinstance(rev, int):
729 # NOTE(marcink):
730 # NOTE(marcink):
730 # since Mercurial doesn't support negative indexes properly
731 # since Mercurial doesn't support negative indexes properly
731 # we need to shift accordingly by one to get proper index, e.g
732 # we need to shift accordingly by one to get proper index, e.g
732 # repo[-1] => repo[-2]
733 # repo[-1] => repo[-2]
733 # repo[0] => repo[-1]
734 # repo[0] => repo[-1]
734 if rev <= 0:
735 if rev <= 0:
735 rev = rev + -1
736 rev = rev + -1
736 try:
737 try:
737 ctx = self._get_ctx(repo, rev)
738 ctx = self._get_ctx(repo, rev)
739 except (AmbiguousPrefixLookupError) as e:
740 e = RepoLookupError(rev)
741 e._org_exc_tb = traceback.format_exc()
742 raise exceptions.LookupException(e)(rev)
738 except (TypeError, RepoLookupError, binascii.Error) as e:
743 except (TypeError, RepoLookupError, binascii.Error) as e:
739 e._org_exc_tb = traceback.format_exc()
744 e._org_exc_tb = traceback.format_exc()
740 raise exceptions.LookupException(e)(rev)
745 raise exceptions.LookupException(e)(rev)
741 except LookupError as e:
746 except LookupError as e:
742 e._org_exc_tb = traceback.format_exc()
747 e._org_exc_tb = traceback.format_exc()
743 raise exceptions.LookupException(e)(e.name)
748 raise exceptions.LookupException(e)(e.name)
744
749
745 if not both:
750 if not both:
746 return ctx.hex()
751 return ctx.hex()
747
752
748 ctx = repo[ctx.hex()]
753 ctx = repo[ctx.hex()]
749 return ctx.hex(), ctx.rev()
754 return ctx.hex(), ctx.rev()
750
755
751 return _lookup(context_uid, repo_id, revision, both)
756 return _lookup(context_uid, repo_id, revision, both)
752
757
753 @reraise_safe_exceptions
758 @reraise_safe_exceptions
754 def sync_push(self, wire, url):
759 def sync_push(self, wire, url):
755 if not self.check_url(url, wire['config']):
760 if not self.check_url(url, wire['config']):
756 return
761 return
757
762
758 repo = self._factory.repo(wire)
763 repo = self._factory.repo(wire)
759
764
760 # Disable any prompts for this repo
765 # Disable any prompts for this repo
761 repo.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
766 repo.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
762
767
763 bookmarks = list(dict(repo._bookmarks).keys())
768 bookmarks = list(dict(repo._bookmarks).keys())
764 remote = peer(repo, {}, safe_bytes(url))
769 remote = peer(repo, {}, safe_bytes(url))
765 # Disable any prompts for this remote
770 # Disable any prompts for this remote
766 remote.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
771 remote.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
767
772
768 return exchange.push(
773 return exchange.push(
769 repo, remote, newbranch=True, bookmarks=bookmarks).cgresult
774 repo, remote, newbranch=True, bookmarks=bookmarks).cgresult
770
775
771 @reraise_safe_exceptions
776 @reraise_safe_exceptions
772 def revision(self, wire, rev):
777 def revision(self, wire, rev):
773 repo = self._factory.repo(wire)
778 repo = self._factory.repo(wire)
774 ctx = self._get_ctx(repo, rev)
779 ctx = self._get_ctx(repo, rev)
775 return ctx.rev()
780 return ctx.rev()
776
781
777 @reraise_safe_exceptions
782 @reraise_safe_exceptions
778 def rev_range(self, wire, commit_filter):
783 def rev_range(self, wire, commit_filter):
779 cache_on, context_uid, repo_id = self._cache_on(wire)
784 cache_on, context_uid, repo_id = self._cache_on(wire)
780 region = self._region(wire)
785 region = self._region(wire)
781
786
782 @region.conditional_cache_on_arguments(condition=cache_on)
787 @region.conditional_cache_on_arguments(condition=cache_on)
783 def _rev_range(_context_uid, _repo_id, _filter):
788 def _rev_range(_context_uid, _repo_id, _filter):
784 repo = self._factory.repo(wire)
789 repo = self._factory.repo(wire)
785 revisions = [
790 revisions = [
786 ascii_str(repo[rev].hex())
791 ascii_str(repo[rev].hex())
787 for rev in revrange(repo, list(map(ascii_bytes, commit_filter)))
792 for rev in revrange(repo, list(map(ascii_bytes, commit_filter)))
788 ]
793 ]
789 return revisions
794 return revisions
790
795
791 return _rev_range(context_uid, repo_id, sorted(commit_filter))
796 return _rev_range(context_uid, repo_id, sorted(commit_filter))
792
797
793 @reraise_safe_exceptions
798 @reraise_safe_exceptions
794 def rev_range_hash(self, wire, node):
799 def rev_range_hash(self, wire, node):
795 repo = self._factory.repo(wire)
800 repo = self._factory.repo(wire)
796
801
797 def get_revs(repo, rev_opt):
802 def get_revs(repo, rev_opt):
798 if rev_opt:
803 if rev_opt:
799 revs = revrange(repo, rev_opt)
804 revs = revrange(repo, rev_opt)
800 if len(revs) == 0:
805 if len(revs) == 0:
801 return (nullrev, nullrev)
806 return (nullrev, nullrev)
802 return max(revs), min(revs)
807 return max(revs), min(revs)
803 else:
808 else:
804 return len(repo) - 1, 0
809 return len(repo) - 1, 0
805
810
806 stop, start = get_revs(repo, [node + ':'])
811 stop, start = get_revs(repo, [node + ':'])
807 revs = [ascii_str(repo[r].hex()) for r in range(start, stop + 1)]
812 revs = [ascii_str(repo[r].hex()) for r in range(start, stop + 1)]
808 return revs
813 return revs
809
814
810 @reraise_safe_exceptions
815 @reraise_safe_exceptions
811 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
816 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
812 org_path = safe_bytes(wire["path"])
817 org_path = safe_bytes(wire["path"])
813 other_path = safe_bytes(kwargs.pop('other_path', ''))
818 other_path = safe_bytes(kwargs.pop('other_path', ''))
814
819
815 # case when we want to compare two independent repositories
820 # case when we want to compare two independent repositories
816 if other_path and other_path != wire["path"]:
821 if other_path and other_path != wire["path"]:
817 baseui = self._factory._create_config(wire["config"])
822 baseui = self._factory._create_config(wire["config"])
818 repo = unionrepo.makeunionrepository(baseui, other_path, org_path)
823 repo = unionrepo.makeunionrepository(baseui, other_path, org_path)
819 else:
824 else:
820 repo = self._factory.repo(wire)
825 repo = self._factory.repo(wire)
821 return list(repo.revs(rev_spec, *args))
826 return list(repo.revs(rev_spec, *args))
822
827
823 @reraise_safe_exceptions
828 @reraise_safe_exceptions
824 def verify(self, wire,):
829 def verify(self, wire,):
825 repo = self._factory.repo(wire)
830 repo = self._factory.repo(wire)
826 baseui = self._factory._create_config(wire['config'])
831 baseui = self._factory._create_config(wire['config'])
827
832
828 baseui, output = patch_ui_message_output(baseui)
833 baseui, output = patch_ui_message_output(baseui)
829
834
830 repo.ui = baseui
835 repo.ui = baseui
831 verify.verify(repo)
836 verify.verify(repo)
832 return output.getvalue()
837 return output.getvalue()
833
838
834 @reraise_safe_exceptions
839 @reraise_safe_exceptions
835 def hg_update_cache(self, wire,):
840 def hg_update_cache(self, wire,):
836 repo = self._factory.repo(wire)
841 repo = self._factory.repo(wire)
837 baseui = self._factory._create_config(wire['config'])
842 baseui = self._factory._create_config(wire['config'])
838 baseui, output = patch_ui_message_output(baseui)
843 baseui, output = patch_ui_message_output(baseui)
839
844
840 repo.ui = baseui
845 repo.ui = baseui
841 with repo.wlock(), repo.lock():
846 with repo.wlock(), repo.lock():
842 repo.updatecaches(full=True)
847 repo.updatecaches(full=True)
843
848
844 return output.getvalue()
849 return output.getvalue()
845
850
846 @reraise_safe_exceptions
851 @reraise_safe_exceptions
847 def hg_rebuild_fn_cache(self, wire,):
852 def hg_rebuild_fn_cache(self, wire,):
848 repo = self._factory.repo(wire)
853 repo = self._factory.repo(wire)
849 baseui = self._factory._create_config(wire['config'])
854 baseui = self._factory._create_config(wire['config'])
850 baseui, output = patch_ui_message_output(baseui)
855 baseui, output = patch_ui_message_output(baseui)
851
856
852 repo.ui = baseui
857 repo.ui = baseui
853
858
854 repair.rebuildfncache(baseui, repo)
859 repair.rebuildfncache(baseui, repo)
855
860
856 return output.getvalue()
861 return output.getvalue()
857
862
858 @reraise_safe_exceptions
863 @reraise_safe_exceptions
859 def tags(self, wire):
864 def tags(self, wire):
860 cache_on, context_uid, repo_id = self._cache_on(wire)
865 cache_on, context_uid, repo_id = self._cache_on(wire)
861 region = self._region(wire)
866 region = self._region(wire)
862
867
863 @region.conditional_cache_on_arguments(condition=cache_on)
868 @region.conditional_cache_on_arguments(condition=cache_on)
864 def _tags(_context_uid, _repo_id):
869 def _tags(_context_uid, _repo_id):
865 repo = self._factory.repo(wire)
870 repo = self._factory.repo(wire)
866 return {safe_str(name): ascii_str(hex(sha)) for name, sha in repo.tags().items()}
871 return {safe_str(name): ascii_str(hex(sha)) for name, sha in repo.tags().items()}
867
872
868 return _tags(context_uid, repo_id)
873 return _tags(context_uid, repo_id)
869
874
870 @reraise_safe_exceptions
875 @reraise_safe_exceptions
871 def update(self, wire, node='', clean=False):
876 def update(self, wire, node='', clean=False):
872 repo = self._factory.repo(wire)
877 repo = self._factory.repo(wire)
873 baseui = self._factory._create_config(wire['config'])
878 baseui = self._factory._create_config(wire['config'])
874 node = safe_bytes(node)
879 node = safe_bytes(node)
875
880
876 commands.update(baseui, repo, node=node, clean=clean)
881 commands.update(baseui, repo, node=node, clean=clean)
877
882
878 @reraise_safe_exceptions
883 @reraise_safe_exceptions
879 def identify(self, wire):
884 def identify(self, wire):
880 repo = self._factory.repo(wire)
885 repo = self._factory.repo(wire)
881 baseui = self._factory._create_config(wire['config'])
886 baseui = self._factory._create_config(wire['config'])
882 output = io.BytesIO()
887 output = io.BytesIO()
883 baseui.write = output.write
888 baseui.write = output.write
884 # This is required to get a full node id
889 # This is required to get a full node id
885 baseui.debugflag = True
890 baseui.debugflag = True
886 commands.identify(baseui, repo, id=True)
891 commands.identify(baseui, repo, id=True)
887
892
888 return output.getvalue()
893 return output.getvalue()
889
894
890 @reraise_safe_exceptions
895 @reraise_safe_exceptions
891 def heads(self, wire, branch=None):
896 def heads(self, wire, branch=None):
892 repo = self._factory.repo(wire)
897 repo = self._factory.repo(wire)
893 baseui = self._factory._create_config(wire['config'])
898 baseui = self._factory._create_config(wire['config'])
894 output = io.BytesIO()
899 output = io.BytesIO()
895
900
896 def write(data, **unused_kwargs):
901 def write(data, **unused_kwargs):
897 output.write(data)
902 output.write(data)
898
903
899 baseui.write = write
904 baseui.write = write
900 if branch:
905 if branch:
901 args = [safe_bytes(branch)]
906 args = [safe_bytes(branch)]
902 else:
907 else:
903 args = []
908 args = []
904 commands.heads(baseui, repo, template=b'{node} ', *args)
909 commands.heads(baseui, repo, template=b'{node} ', *args)
905
910
906 return output.getvalue()
911 return output.getvalue()
907
912
908 @reraise_safe_exceptions
913 @reraise_safe_exceptions
909 def ancestor(self, wire, revision1, revision2):
914 def ancestor(self, wire, revision1, revision2):
910 repo = self._factory.repo(wire)
915 repo = self._factory.repo(wire)
911 changelog = repo.changelog
916 changelog = repo.changelog
912 lookup = repo.lookup
917 lookup = repo.lookup
913 a = changelog.ancestor(lookup(safe_bytes(revision1)), lookup(safe_bytes(revision2)))
918 a = changelog.ancestor(lookup(safe_bytes(revision1)), lookup(safe_bytes(revision2)))
914 return hex(a)
919 return hex(a)
915
920
916 @reraise_safe_exceptions
921 @reraise_safe_exceptions
917 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
922 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
918 baseui = self._factory._create_config(wire["config"], hooks=hooks)
923 baseui = self._factory._create_config(wire["config"], hooks=hooks)
919 clone(baseui, safe_bytes(source), safe_bytes(dest), noupdate=not update_after_clone)
924 clone(baseui, safe_bytes(source), safe_bytes(dest), noupdate=not update_after_clone)
920
925
921 @reraise_safe_exceptions
926 @reraise_safe_exceptions
922 def commitctx(self, wire, message, parents, commit_time, commit_timezone, user, files, extra, removed, updated):
927 def commitctx(self, wire, message, parents, commit_time, commit_timezone, user, files, extra, removed, updated):
923
928
924 repo = self._factory.repo(wire)
929 repo = self._factory.repo(wire)
925 baseui = self._factory._create_config(wire['config'])
930 baseui = self._factory._create_config(wire['config'])
926 publishing = baseui.configbool(b'phases', b'publish')
931 publishing = baseui.configbool(b'phases', b'publish')
927
932
928 def _filectxfn(_repo, ctx, path: bytes):
933 def _filectxfn(_repo, ctx, path: bytes):
929 """
934 """
930 Marks given path as added/changed/removed in a given _repo. This is
935 Marks given path as added/changed/removed in a given _repo. This is
931 for internal mercurial commit function.
936 for internal mercurial commit function.
932 """
937 """
933
938
934 # check if this path is removed
939 # check if this path is removed
935 if safe_str(path) in removed:
940 if safe_str(path) in removed:
936 # returning None is a way to mark node for removal
941 # returning None is a way to mark node for removal
937 return None
942 return None
938
943
939 # check if this path is added
944 # check if this path is added
940 for node in updated:
945 for node in updated:
941 if safe_bytes(node['path']) == path:
946 if safe_bytes(node['path']) == path:
942 return memfilectx(
947 return memfilectx(
943 _repo,
948 _repo,
944 changectx=ctx,
949 changectx=ctx,
945 path=safe_bytes(node['path']),
950 path=safe_bytes(node['path']),
946 data=safe_bytes(node['content']),
951 data=safe_bytes(node['content']),
947 islink=False,
952 islink=False,
948 isexec=bool(node['mode'] & stat.S_IXUSR),
953 isexec=bool(node['mode'] & stat.S_IXUSR),
949 copysource=False)
954 copysource=False)
950 abort_exc = exceptions.AbortException()
955 abort_exc = exceptions.AbortException()
951 raise abort_exc(f"Given path haven't been marked as added, changed or removed ({path})")
956 raise abort_exc(f"Given path haven't been marked as added, changed or removed ({path})")
952
957
953 if publishing:
958 if publishing:
954 new_commit_phase = b'public'
959 new_commit_phase = b'public'
955 else:
960 else:
956 new_commit_phase = b'draft'
961 new_commit_phase = b'draft'
957 with repo.ui.configoverride({(b'phases', b'new-commit'): new_commit_phase}):
962 with repo.ui.configoverride({(b'phases', b'new-commit'): new_commit_phase}):
958 kwargs = {safe_bytes(k): safe_bytes(v) for k, v in extra.items()}
963 kwargs = {safe_bytes(k): safe_bytes(v) for k, v in extra.items()}
959 commit_ctx = memctx(
964 commit_ctx = memctx(
960 repo=repo,
965 repo=repo,
961 parents=parents,
966 parents=parents,
962 text=safe_bytes(message),
967 text=safe_bytes(message),
963 files=[safe_bytes(x) for x in files],
968 files=[safe_bytes(x) for x in files],
964 filectxfn=_filectxfn,
969 filectxfn=_filectxfn,
965 user=safe_bytes(user),
970 user=safe_bytes(user),
966 date=(commit_time, commit_timezone),
971 date=(commit_time, commit_timezone),
967 extra=kwargs)
972 extra=kwargs)
968
973
969 n = repo.commitctx(commit_ctx)
974 n = repo.commitctx(commit_ctx)
970 new_id = hex(n)
975 new_id = hex(n)
971
976
972 return new_id
977 return new_id
973
978
974 @reraise_safe_exceptions
979 @reraise_safe_exceptions
975 def pull(self, wire, url, commit_ids=None):
980 def pull(self, wire, url, commit_ids=None):
976 repo = self._factory.repo(wire)
981 repo = self._factory.repo(wire)
977 # Disable any prompts for this repo
982 # Disable any prompts for this repo
978 repo.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
983 repo.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
979
984
980 remote = peer(repo, {}, safe_bytes(url))
985 remote = peer(repo, {}, safe_bytes(url))
981 # Disable any prompts for this remote
986 # Disable any prompts for this remote
982 remote.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
987 remote.ui.setconfig(b'ui', b'interactive', b'off', b'-y')
983
988
984 if commit_ids:
989 if commit_ids:
985 commit_ids = [bin(commit_id) for commit_id in commit_ids]
990 commit_ids = [bin(commit_id) for commit_id in commit_ids]
986
991
987 return exchange.pull(
992 return exchange.pull(
988 repo, remote, heads=commit_ids, force=None).cgresult
993 repo, remote, heads=commit_ids, force=None).cgresult
989
994
990 @reraise_safe_exceptions
995 @reraise_safe_exceptions
991 def pull_cmd(self, wire, source, bookmark='', branch='', revision='', hooks=True):
996 def pull_cmd(self, wire, source, bookmark='', branch='', revision='', hooks=True):
992 repo = self._factory.repo(wire)
997 repo = self._factory.repo(wire)
993 baseui = self._factory._create_config(wire['config'], hooks=hooks)
998 baseui = self._factory._create_config(wire['config'], hooks=hooks)
994
999
995 source = safe_bytes(source)
1000 source = safe_bytes(source)
996
1001
997 # Mercurial internally has a lot of logic that checks ONLY if
1002 # Mercurial internally has a lot of logic that checks ONLY if
998 # option is defined, we just pass those if they are defined then
1003 # option is defined, we just pass those if they are defined then
999 opts = {}
1004 opts = {}
1000
1005
1001 if bookmark:
1006 if bookmark:
1002 opts['bookmark'] = [safe_bytes(x) for x in bookmark] \
1007 opts['bookmark'] = [safe_bytes(x) for x in bookmark] \
1003 if isinstance(bookmark, list) else safe_bytes(bookmark)
1008 if isinstance(bookmark, list) else safe_bytes(bookmark)
1004
1009
1005 if branch:
1010 if branch:
1006 opts['branch'] = [safe_bytes(x) for x in branch] \
1011 opts['branch'] = [safe_bytes(x) for x in branch] \
1007 if isinstance(branch, list) else safe_bytes(branch)
1012 if isinstance(branch, list) else safe_bytes(branch)
1008
1013
1009 if revision:
1014 if revision:
1010 opts['rev'] = [safe_bytes(x) for x in revision] \
1015 opts['rev'] = [safe_bytes(x) for x in revision] \
1011 if isinstance(revision, list) else safe_bytes(revision)
1016 if isinstance(revision, list) else safe_bytes(revision)
1012
1017
1013 commands.pull(baseui, repo, source, **opts)
1018 commands.pull(baseui, repo, source, **opts)
1014
1019
1015 @reraise_safe_exceptions
1020 @reraise_safe_exceptions
1016 def push(self, wire, revisions, dest_path, hooks: bool = True, push_branches: bool = False):
1021 def push(self, wire, revisions, dest_path, hooks: bool = True, push_branches: bool = False):
1017 repo = self._factory.repo(wire)
1022 repo = self._factory.repo(wire)
1018 baseui = self._factory._create_config(wire['config'], hooks=hooks)
1023 baseui = self._factory._create_config(wire['config'], hooks=hooks)
1019
1024
1020 revisions = [safe_bytes(x) for x in revisions] \
1025 revisions = [safe_bytes(x) for x in revisions] \
1021 if isinstance(revisions, list) else safe_bytes(revisions)
1026 if isinstance(revisions, list) else safe_bytes(revisions)
1022
1027
1023 commands.push(baseui, repo, safe_bytes(dest_path),
1028 commands.push(baseui, repo, safe_bytes(dest_path),
1024 rev=revisions,
1029 rev=revisions,
1025 new_branch=push_branches)
1030 new_branch=push_branches)
1026
1031
1027 @reraise_safe_exceptions
1032 @reraise_safe_exceptions
1028 def strip(self, wire, revision, update, backup):
1033 def strip(self, wire, revision, update, backup):
1029 repo = self._factory.repo(wire)
1034 repo = self._factory.repo(wire)
1030 ctx = self._get_ctx(repo, revision)
1035 ctx = self._get_ctx(repo, revision)
1031 hgext_strip.strip(
1036 hgext_strip.strip(
1032 repo.baseui, repo, ctx.node(), update=update, backup=backup)
1037 repo.baseui, repo, ctx.node(), update=update, backup=backup)
1033
1038
1034 @reraise_safe_exceptions
1039 @reraise_safe_exceptions
1035 def get_unresolved_files(self, wire):
1040 def get_unresolved_files(self, wire):
1036 repo = self._factory.repo(wire)
1041 repo = self._factory.repo(wire)
1037
1042
1038 log.debug('Calculating unresolved files for repo: %s', repo)
1043 log.debug('Calculating unresolved files for repo: %s', repo)
1039 output = io.BytesIO()
1044 output = io.BytesIO()
1040
1045
1041 def write(data, **unused_kwargs):
1046 def write(data, **unused_kwargs):
1042 output.write(data)
1047 output.write(data)
1043
1048
1044 baseui = self._factory._create_config(wire['config'])
1049 baseui = self._factory._create_config(wire['config'])
1045 baseui.write = write
1050 baseui.write = write
1046
1051
1047 commands.resolve(baseui, repo, list=True)
1052 commands.resolve(baseui, repo, list=True)
1048 unresolved = output.getvalue().splitlines(0)
1053 unresolved = output.getvalue().splitlines(0)
1049 return unresolved
1054 return unresolved
1050
1055
1051 @reraise_safe_exceptions
1056 @reraise_safe_exceptions
1052 def merge(self, wire, revision):
1057 def merge(self, wire, revision):
1053 repo = self._factory.repo(wire)
1058 repo = self._factory.repo(wire)
1054 baseui = self._factory._create_config(wire['config'])
1059 baseui = self._factory._create_config(wire['config'])
1055 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1060 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1056
1061
1057 # In case of sub repositories are used mercurial prompts the user in
1062 # In case of sub repositories are used mercurial prompts the user in
1058 # case of merge conflicts or different sub repository sources. By
1063 # case of merge conflicts or different sub repository sources. By
1059 # setting the interactive flag to `False` mercurial doesn't prompt the
1064 # setting the interactive flag to `False` mercurial doesn't prompt the
1060 # used but instead uses a default value.
1065 # used but instead uses a default value.
1061 repo.ui.setconfig(b'ui', b'interactive', False)
1066 repo.ui.setconfig(b'ui', b'interactive', False)
1062 commands.merge(baseui, repo, rev=safe_bytes(revision))
1067 commands.merge(baseui, repo, rev=safe_bytes(revision))
1063
1068
1064 @reraise_safe_exceptions
1069 @reraise_safe_exceptions
1065 def merge_state(self, wire):
1070 def merge_state(self, wire):
1066 repo = self._factory.repo(wire)
1071 repo = self._factory.repo(wire)
1067 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1072 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1068
1073
1069 # In case of sub repositories are used mercurial prompts the user in
1074 # In case of sub repositories are used mercurial prompts the user in
1070 # case of merge conflicts or different sub repository sources. By
1075 # case of merge conflicts or different sub repository sources. By
1071 # setting the interactive flag to `False` mercurial doesn't prompt the
1076 # setting the interactive flag to `False` mercurial doesn't prompt the
1072 # used but instead uses a default value.
1077 # used but instead uses a default value.
1073 repo.ui.setconfig(b'ui', b'interactive', False)
1078 repo.ui.setconfig(b'ui', b'interactive', False)
1074 ms = hg_merge.mergestate(repo)
1079 ms = hg_merge.mergestate(repo)
1075 return [x for x in ms.unresolved()]
1080 return [x for x in ms.unresolved()]
1076
1081
1077 @reraise_safe_exceptions
1082 @reraise_safe_exceptions
1078 def commit(self, wire, message, username, close_branch=False):
1083 def commit(self, wire, message, username, close_branch=False):
1079 repo = self._factory.repo(wire)
1084 repo = self._factory.repo(wire)
1080 baseui = self._factory._create_config(wire['config'])
1085 baseui = self._factory._create_config(wire['config'])
1081 repo.ui.setconfig(b'ui', b'username', safe_bytes(username))
1086 repo.ui.setconfig(b'ui', b'username', safe_bytes(username))
1082 commands.commit(baseui, repo, message=safe_bytes(message), close_branch=close_branch)
1087 commands.commit(baseui, repo, message=safe_bytes(message), close_branch=close_branch)
1083
1088
1084 @reraise_safe_exceptions
1089 @reraise_safe_exceptions
1085 def rebase(self, wire, source='', dest='', abort=False):
1090 def rebase(self, wire, source='', dest='', abort=False):
1086 repo = self._factory.repo(wire)
1091 repo = self._factory.repo(wire)
1087 baseui = self._factory._create_config(wire['config'])
1092 baseui = self._factory._create_config(wire['config'])
1088 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1093 repo.ui.setconfig(b'ui', b'merge', b'internal:dump')
1089 # In case of sub repositories are used mercurial prompts the user in
1094 # In case of sub repositories are used mercurial prompts the user in
1090 # case of merge conflicts or different sub repository sources. By
1095 # case of merge conflicts or different sub repository sources. By
1091 # setting the interactive flag to `False` mercurial doesn't prompt the
1096 # setting the interactive flag to `False` mercurial doesn't prompt the
1092 # used but instead uses a default value.
1097 # used but instead uses a default value.
1093 repo.ui.setconfig(b'ui', b'interactive', False)
1098 repo.ui.setconfig(b'ui', b'interactive', False)
1094
1099
1095 rebase.rebase(baseui, repo, base=safe_bytes(source or ''), dest=safe_bytes(dest or ''),
1100 rebase.rebase(baseui, repo, base=safe_bytes(source or ''), dest=safe_bytes(dest or ''),
1096 abort=abort, keep=not abort)
1101 abort=abort, keep=not abort)
1097
1102
1098 @reraise_safe_exceptions
1103 @reraise_safe_exceptions
1099 def tag(self, wire, name, revision, message, local, user, tag_time, tag_timezone):
1104 def tag(self, wire, name, revision, message, local, user, tag_time, tag_timezone):
1100 repo = self._factory.repo(wire)
1105 repo = self._factory.repo(wire)
1101 ctx = self._get_ctx(repo, revision)
1106 ctx = self._get_ctx(repo, revision)
1102 node = ctx.node()
1107 node = ctx.node()
1103
1108
1104 date = (tag_time, tag_timezone)
1109 date = (tag_time, tag_timezone)
1105 try:
1110 try:
1106 hg_tag.tag(repo, safe_bytes(name), node, safe_bytes(message), local, safe_bytes(user), date)
1111 hg_tag.tag(repo, safe_bytes(name), node, safe_bytes(message), local, safe_bytes(user), date)
1107 except Abort as e:
1112 except Abort as e:
1108 log.exception("Tag operation aborted")
1113 log.exception("Tag operation aborted")
1109 # Exception can contain unicode which we convert
1114 # Exception can contain unicode which we convert
1110 raise exceptions.AbortException(e)(repr(e))
1115 raise exceptions.AbortException(e)(repr(e))
1111
1116
1112 @reraise_safe_exceptions
1117 @reraise_safe_exceptions
1113 def bookmark(self, wire, bookmark, revision=''):
1118 def bookmark(self, wire, bookmark, revision=''):
1114 repo = self._factory.repo(wire)
1119 repo = self._factory.repo(wire)
1115 baseui = self._factory._create_config(wire['config'])
1120 baseui = self._factory._create_config(wire['config'])
1116 revision = revision or ''
1121 revision = revision or ''
1117 commands.bookmark(baseui, repo, safe_bytes(bookmark), rev=safe_bytes(revision), force=True)
1122 commands.bookmark(baseui, repo, safe_bytes(bookmark), rev=safe_bytes(revision), force=True)
1118
1123
1119 @reraise_safe_exceptions
1124 @reraise_safe_exceptions
1120 def install_hooks(self, wire, force=False):
1125 def install_hooks(self, wire, force=False):
1121 # we don't need any special hooks for Mercurial
1126 # we don't need any special hooks for Mercurial
1122 pass
1127 pass
1123
1128
1124 @reraise_safe_exceptions
1129 @reraise_safe_exceptions
1125 def get_hooks_info(self, wire):
1130 def get_hooks_info(self, wire):
1126 return {
1131 return {
1127 'pre_version': vcsserver.__version__,
1132 'pre_version': vcsserver.__version__,
1128 'post_version': vcsserver.__version__,
1133 'post_version': vcsserver.__version__,
1129 }
1134 }
1130
1135
1131 @reraise_safe_exceptions
1136 @reraise_safe_exceptions
1132 def set_head_ref(self, wire, head_name):
1137 def set_head_ref(self, wire, head_name):
1133 pass
1138 pass
1134
1139
1135 @reraise_safe_exceptions
1140 @reraise_safe_exceptions
1136 def archive_repo(self, wire, archive_name_key, kind, mtime, archive_at_path,
1141 def archive_repo(self, wire, archive_name_key, kind, mtime, archive_at_path,
1137 archive_dir_name, commit_id, cache_config):
1142 archive_dir_name, commit_id, cache_config):
1138
1143
1139 def file_walker(_commit_id, path):
1144 def file_walker(_commit_id, path):
1140 repo = self._factory.repo(wire)
1145 repo = self._factory.repo(wire)
1141 ctx = repo[_commit_id]
1146 ctx = repo[_commit_id]
1142 is_root = path in ['', '/']
1147 is_root = path in ['', '/']
1143 if is_root:
1148 if is_root:
1144 matcher = alwaysmatcher(badfn=None)
1149 matcher = alwaysmatcher(badfn=None)
1145 else:
1150 else:
1146 matcher = patternmatcher('', [(b'glob', safe_bytes(path)+b'/**', b'')], badfn=None)
1151 matcher = patternmatcher('', [(b'glob', safe_bytes(path)+b'/**', b'')], badfn=None)
1147 file_iter = ctx.manifest().walk(matcher)
1152 file_iter = ctx.manifest().walk(matcher)
1148
1153
1149 for fn in file_iter:
1154 for fn in file_iter:
1150 file_path = fn
1155 file_path = fn
1151 flags = ctx.flags(fn)
1156 flags = ctx.flags(fn)
1152 mode = b'x' in flags and 0o755 or 0o644
1157 mode = b'x' in flags and 0o755 or 0o644
1153 is_link = b'l' in flags
1158 is_link = b'l' in flags
1154
1159
1155 yield ArchiveNode(file_path, mode, is_link, ctx[fn].data)
1160 yield ArchiveNode(file_path, mode, is_link, ctx[fn].data)
1156
1161
1157 return store_archive_in_cache(
1162 return store_archive_in_cache(
1158 file_walker, archive_name_key, kind, mtime, archive_at_path, archive_dir_name, commit_id, cache_config=cache_config)
1163 file_walker, archive_name_key, kind, mtime, archive_at_path, archive_dir_name, commit_id, cache_config=cache_config)
1159
1164
General Comments 0
You need to be logged in to leave comments. Login now