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