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