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