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