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