##// END OF EJS Templates
mercurial: disable paginate for all commands to prevent potential gunicorn issues....
marcink -
r349:9d03aa86 default
parent child Browse files
Show More
@@ -1,748 +1,749 b''
1 1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 2 # Copyright (C) 2014-2017 RodeCode 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
24 24 from hgext import largefiles, rebase
25 25 from hgext.strip import strip as hgext_strip
26 26 from mercurial import commands
27 27 from mercurial import unionrepo
28 28 from mercurial import verify
29 29
30 30 from vcsserver import exceptions
31 31 from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original
32 32 from vcsserver.hgcompat import (
33 33 archival, bin, clone, config as hgconfig, diffopts, hex,
34 34 hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler,
35 35 httppeer, localrepository, match, memctx, exchange, memfilectx, nullrev,
36 36 patch, peer, revrange, ui, hg_tag, Abort, LookupError, RepoError,
37 37 RepoLookupError, InterventionRequired, RequirementError)
38 38
39 39 log = logging.getLogger(__name__)
40 40
41 41
42 42 def make_ui_from_config(repo_config):
43 43 baseui = ui.ui()
44 44
45 45 # clean the baseui object
46 46 baseui._ocfg = hgconfig.config()
47 47 baseui._ucfg = hgconfig.config()
48 48 baseui._tcfg = hgconfig.config()
49 49
50 50 for section, option, value in repo_config:
51 51 baseui.setconfig(section, option, value)
52 52
53 53 # make our hgweb quiet so it doesn't print output
54 54 baseui.setconfig('ui', 'quiet', 'true')
55 55
56 baseui.setconfig('ui', 'paginate', 'never')
56 57 # force mercurial to only use 1 thread, otherwise it may try to set a
57 58 # signal in a non-main thread, thus generating a ValueError.
58 59 baseui.setconfig('worker', 'numcpus', 1)
59 60
60 61 # If there is no config for the largefiles extension, we explicitly disable
61 62 # it here. This overrides settings from repositories hgrc file. Recent
62 63 # mercurial versions enable largefiles in hgrc on clone from largefile
63 64 # repo.
64 65 if not baseui.hasconfig('extensions', 'largefiles'):
65 66 log.debug('Explicitly disable largefiles extension for repo.')
66 67 baseui.setconfig('extensions', 'largefiles', '!')
67 68
68 69 return baseui
69 70
70 71
71 72 def reraise_safe_exceptions(func):
72 73 """Decorator for converting mercurial exceptions to something neutral."""
73 74 def wrapper(*args, **kwargs):
74 75 try:
75 76 return func(*args, **kwargs)
76 77 except (Abort, InterventionRequired):
77 78 raise_from_original(exceptions.AbortException)
78 79 except RepoLookupError:
79 80 raise_from_original(exceptions.LookupException)
80 81 except RequirementError:
81 82 raise_from_original(exceptions.RequirementException)
82 83 except RepoError:
83 84 raise_from_original(exceptions.VcsException)
84 85 except LookupError:
85 86 raise_from_original(exceptions.LookupException)
86 87 except Exception as e:
87 88 if not hasattr(e, '_vcs_kind'):
88 89 log.exception("Unhandled exception in hg remote call")
89 90 raise_from_original(exceptions.UnhandledException)
90 91 raise
91 92 return wrapper
92 93
93 94
94 95 class MercurialFactory(RepoFactory):
95 96
96 97 def _create_config(self, config, hooks=True):
97 98 if not hooks:
98 99 hooks_to_clean = frozenset((
99 100 'changegroup.repo_size', 'preoutgoing.pre_pull',
100 101 'outgoing.pull_logger', 'prechangegroup.pre_push'))
101 102 new_config = []
102 103 for section, option, value in config:
103 104 if section == 'hooks' and option in hooks_to_clean:
104 105 continue
105 106 new_config.append((section, option, value))
106 107 config = new_config
107 108
108 109 baseui = make_ui_from_config(config)
109 110 return baseui
110 111
111 112 def _create_repo(self, wire, create):
112 113 baseui = self._create_config(wire["config"])
113 114 return localrepository(baseui, wire["path"], create)
114 115
115 116
116 117 class HgRemote(object):
117 118
118 119 def __init__(self, factory):
119 120 self._factory = factory
120 121
121 122 self._bulk_methods = {
122 123 "affected_files": self.ctx_files,
123 124 "author": self.ctx_user,
124 125 "branch": self.ctx_branch,
125 126 "children": self.ctx_children,
126 127 "date": self.ctx_date,
127 128 "message": self.ctx_description,
128 129 "parents": self.ctx_parents,
129 130 "status": self.ctx_status,
130 131 "obsolete": self.ctx_obsolete,
131 132 "phase": self.ctx_phase,
132 133 "hidden": self.ctx_hidden,
133 134 "_file_paths": self.ctx_list,
134 135 }
135 136
136 137 @reraise_safe_exceptions
137 138 def discover_hg_version(self):
138 139 from mercurial import util
139 140 return util.version()
140 141
141 142 @reraise_safe_exceptions
142 143 def archive_repo(self, archive_path, mtime, file_info, kind):
143 144 if kind == "tgz":
144 145 archiver = archival.tarit(archive_path, mtime, "gz")
145 146 elif kind == "tbz2":
146 147 archiver = archival.tarit(archive_path, mtime, "bz2")
147 148 elif kind == 'zip':
148 149 archiver = archival.zipit(archive_path, mtime)
149 150 else:
150 151 raise exceptions.ArchiveException(
151 152 'Remote does not support: "%s".' % kind)
152 153
153 154 for f_path, f_mode, f_is_link, f_content in file_info:
154 155 archiver.addfile(f_path, f_mode, f_is_link, f_content)
155 156 archiver.done()
156 157
157 158 @reraise_safe_exceptions
158 159 def bookmarks(self, wire):
159 160 repo = self._factory.repo(wire)
160 161 return dict(repo._bookmarks)
161 162
162 163 @reraise_safe_exceptions
163 164 def branches(self, wire, normal, closed):
164 165 repo = self._factory.repo(wire)
165 166 iter_branches = repo.branchmap().iterbranches()
166 167 bt = {}
167 168 for branch_name, _heads, tip, is_closed in iter_branches:
168 169 if normal and not is_closed:
169 170 bt[branch_name] = tip
170 171 if closed and is_closed:
171 172 bt[branch_name] = tip
172 173
173 174 return bt
174 175
175 176 @reraise_safe_exceptions
176 177 def bulk_request(self, wire, rev, pre_load):
177 178 result = {}
178 179 for attr in pre_load:
179 180 try:
180 181 method = self._bulk_methods[attr]
181 182 result[attr] = method(wire, rev)
182 183 except KeyError:
183 184 raise exceptions.VcsException(
184 185 'Unknown bulk attribute: "%s"' % attr)
185 186 return result
186 187
187 188 @reraise_safe_exceptions
188 189 def clone(self, wire, source, dest, update_after_clone=False, hooks=True):
189 190 baseui = self._factory._create_config(wire["config"], hooks=hooks)
190 191 clone(baseui, source, dest, noupdate=not update_after_clone)
191 192
192 193 @reraise_safe_exceptions
193 194 def commitctx(
194 195 self, wire, message, parents, commit_time, commit_timezone,
195 196 user, files, extra, removed, updated):
196 197
197 198 def _filectxfn(_repo, memctx, path):
198 199 """
199 200 Marks given path as added/changed/removed in a given _repo. This is
200 201 for internal mercurial commit function.
201 202 """
202 203
203 204 # check if this path is removed
204 205 if path in removed:
205 206 # returning None is a way to mark node for removal
206 207 return None
207 208
208 209 # check if this path is added
209 210 for node in updated:
210 211 if node['path'] == path:
211 212 return memfilectx(
212 213 _repo,
213 214 path=node['path'],
214 215 data=node['content'],
215 216 islink=False,
216 217 isexec=bool(node['mode'] & stat.S_IXUSR),
217 218 copied=False,
218 219 memctx=memctx)
219 220
220 221 raise exceptions.AbortException(
221 222 "Given path haven't been marked as added, "
222 223 "changed or removed (%s)" % path)
223 224
224 225 repo = self._factory.repo(wire)
225 226
226 227 commit_ctx = memctx(
227 228 repo=repo,
228 229 parents=parents,
229 230 text=message,
230 231 files=files,
231 232 filectxfn=_filectxfn,
232 233 user=user,
233 234 date=(commit_time, commit_timezone),
234 235 extra=extra)
235 236
236 237 n = repo.commitctx(commit_ctx)
237 238 new_id = hex(n)
238 239
239 240 return new_id
240 241
241 242 @reraise_safe_exceptions
242 243 def ctx_branch(self, wire, revision):
243 244 repo = self._factory.repo(wire)
244 245 ctx = repo[revision]
245 246 return ctx.branch()
246 247
247 248 @reraise_safe_exceptions
248 249 def ctx_children(self, wire, revision):
249 250 repo = self._factory.repo(wire)
250 251 ctx = repo[revision]
251 252 return [child.rev() for child in ctx.children()]
252 253
253 254 @reraise_safe_exceptions
254 255 def ctx_date(self, wire, revision):
255 256 repo = self._factory.repo(wire)
256 257 ctx = repo[revision]
257 258 return ctx.date()
258 259
259 260 @reraise_safe_exceptions
260 261 def ctx_description(self, wire, revision):
261 262 repo = self._factory.repo(wire)
262 263 ctx = repo[revision]
263 264 return ctx.description()
264 265
265 266 @reraise_safe_exceptions
266 267 def ctx_diff(
267 268 self, wire, revision, git=True, ignore_whitespace=True, context=3):
268 269 repo = self._factory.repo(wire)
269 270 ctx = repo[revision]
270 271 result = ctx.diff(
271 272 git=git, ignore_whitespace=ignore_whitespace, context=context)
272 273 return list(result)
273 274
274 275 @reraise_safe_exceptions
275 276 def ctx_files(self, wire, revision):
276 277 repo = self._factory.repo(wire)
277 278 ctx = repo[revision]
278 279 return ctx.files()
279 280
280 281 @reraise_safe_exceptions
281 282 def ctx_list(self, path, revision):
282 283 repo = self._factory.repo(path)
283 284 ctx = repo[revision]
284 285 return list(ctx)
285 286
286 287 @reraise_safe_exceptions
287 288 def ctx_parents(self, wire, revision):
288 289 repo = self._factory.repo(wire)
289 290 ctx = repo[revision]
290 291 return [parent.rev() for parent in ctx.parents()]
291 292
292 293 @reraise_safe_exceptions
293 294 def ctx_phase(self, wire, revision):
294 295 repo = self._factory.repo(wire)
295 296 ctx = repo[revision]
296 297 # public=0, draft=1, secret=3
297 298 return ctx.phase()
298 299
299 300 @reraise_safe_exceptions
300 301 def ctx_obsolete(self, wire, revision):
301 302 repo = self._factory.repo(wire)
302 303 ctx = repo[revision]
303 304 return ctx.obsolete()
304 305
305 306 @reraise_safe_exceptions
306 307 def ctx_hidden(self, wire, revision):
307 308 repo = self._factory.repo(wire)
308 309 ctx = repo[revision]
309 310 return ctx.hidden()
310 311
311 312 @reraise_safe_exceptions
312 313 def ctx_substate(self, wire, revision):
313 314 repo = self._factory.repo(wire)
314 315 ctx = repo[revision]
315 316 return ctx.substate
316 317
317 318 @reraise_safe_exceptions
318 319 def ctx_status(self, wire, revision):
319 320 repo = self._factory.repo(wire)
320 321 ctx = repo[revision]
321 322 status = repo[ctx.p1().node()].status(other=ctx.node())
322 323 # object of status (odd, custom named tuple in mercurial) is not
323 324 # correctly serializable, we make it a list, as the underling
324 325 # API expects this to be a list
325 326 return list(status)
326 327
327 328 @reraise_safe_exceptions
328 329 def ctx_user(self, wire, revision):
329 330 repo = self._factory.repo(wire)
330 331 ctx = repo[revision]
331 332 return ctx.user()
332 333
333 334 @reraise_safe_exceptions
334 335 def check_url(self, url, config):
335 336 _proto = None
336 337 if '+' in url[:url.find('://')]:
337 338 _proto = url[0:url.find('+')]
338 339 url = url[url.find('+') + 1:]
339 340 handlers = []
340 341 url_obj = url_parser(url)
341 342 test_uri, authinfo = url_obj.authinfo()
342 343 url_obj.passwd = '*****' if url_obj.passwd else url_obj.passwd
343 344 url_obj.query = obfuscate_qs(url_obj.query)
344 345
345 346 cleaned_uri = str(url_obj)
346 347 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
347 348
348 349 if authinfo:
349 350 # create a password manager
350 351 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
351 352 passmgr.add_password(*authinfo)
352 353
353 354 handlers.extend((httpbasicauthhandler(passmgr),
354 355 httpdigestauthhandler(passmgr)))
355 356
356 357 o = urllib2.build_opener(*handlers)
357 358 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
358 359 ('Accept', 'application/mercurial-0.1')]
359 360
360 361 q = {"cmd": 'between'}
361 362 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
362 363 qs = '?%s' % urllib.urlencode(q)
363 364 cu = "%s%s" % (test_uri, qs)
364 365 req = urllib2.Request(cu, None, {})
365 366
366 367 try:
367 368 log.debug("Trying to open URL %s", cleaned_uri)
368 369 resp = o.open(req)
369 370 if resp.code != 200:
370 371 raise exceptions.URLError('Return Code is not 200')
371 372 except Exception as e:
372 373 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
373 374 # means it cannot be cloned
374 375 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
375 376
376 377 # now check if it's a proper hg repo, but don't do it for svn
377 378 try:
378 379 if _proto == 'svn':
379 380 pass
380 381 else:
381 382 # check for pure hg repos
382 383 log.debug(
383 384 "Verifying if URL is a Mercurial repository: %s",
384 385 cleaned_uri)
385 386 httppeer(make_ui_from_config(config), url).lookup('tip')
386 387 except Exception as e:
387 388 log.warning("URL is not a valid Mercurial repository: %s",
388 389 cleaned_uri)
389 390 raise exceptions.URLError(
390 391 "url [%s] does not look like an hg repo org_exc: %s"
391 392 % (cleaned_uri, e))
392 393
393 394 log.info("URL is a valid Mercurial repository: %s", cleaned_uri)
394 395 return True
395 396
396 397 @reraise_safe_exceptions
397 398 def diff(
398 399 self, wire, rev1, rev2, file_filter, opt_git, opt_ignorews,
399 400 context):
400 401 repo = self._factory.repo(wire)
401 402
402 403 if file_filter:
403 404 match_filter = match(file_filter[0], '', [file_filter[1]])
404 405 else:
405 406 match_filter = file_filter
406 407 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
407 408
408 409 try:
409 410 return "".join(patch.diff(
410 411 repo, node1=rev1, node2=rev2, match=match_filter, opts=opts))
411 412 except RepoLookupError:
412 413 raise exceptions.LookupException()
413 414
414 415 @reraise_safe_exceptions
415 416 def file_history(self, wire, revision, path, limit):
416 417 repo = self._factory.repo(wire)
417 418
418 419 ctx = repo[revision]
419 420 fctx = ctx.filectx(path)
420 421
421 422 def history_iter():
422 423 limit_rev = fctx.rev()
423 424 for obj in reversed(list(fctx.filelog())):
424 425 obj = fctx.filectx(obj)
425 426 if limit_rev >= obj.rev():
426 427 yield obj
427 428
428 429 history = []
429 430 for cnt, obj in enumerate(history_iter()):
430 431 if limit and cnt >= limit:
431 432 break
432 433 history.append(hex(obj.node()))
433 434
434 435 return [x for x in history]
435 436
436 437 @reraise_safe_exceptions
437 438 def file_history_untill(self, wire, revision, path, limit):
438 439 repo = self._factory.repo(wire)
439 440 ctx = repo[revision]
440 441 fctx = ctx.filectx(path)
441 442
442 443 file_log = list(fctx.filelog())
443 444 if limit:
444 445 # Limit to the last n items
445 446 file_log = file_log[-limit:]
446 447
447 448 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
448 449
449 450 @reraise_safe_exceptions
450 451 def fctx_annotate(self, wire, revision, path):
451 452 repo = self._factory.repo(wire)
452 453 ctx = repo[revision]
453 454 fctx = ctx.filectx(path)
454 455
455 456 result = []
456 457 for i, (a_line, content) in enumerate(fctx.annotate()):
457 458 ln_no = i + 1
458 459 sha = hex(a_line.fctx.node())
459 460 result.append((ln_no, sha, content))
460 461 return result
461 462
462 463 @reraise_safe_exceptions
463 464 def fctx_data(self, wire, revision, path):
464 465 repo = self._factory.repo(wire)
465 466 ctx = repo[revision]
466 467 fctx = ctx.filectx(path)
467 468 return fctx.data()
468 469
469 470 @reraise_safe_exceptions
470 471 def fctx_flags(self, wire, revision, path):
471 472 repo = self._factory.repo(wire)
472 473 ctx = repo[revision]
473 474 fctx = ctx.filectx(path)
474 475 return fctx.flags()
475 476
476 477 @reraise_safe_exceptions
477 478 def fctx_size(self, wire, revision, path):
478 479 repo = self._factory.repo(wire)
479 480 ctx = repo[revision]
480 481 fctx = ctx.filectx(path)
481 482 return fctx.size()
482 483
483 484 @reraise_safe_exceptions
484 485 def get_all_commit_ids(self, wire, name):
485 486 repo = self._factory.repo(wire)
486 487 revs = repo.filtered(name).changelog.index
487 488 return map(lambda x: hex(x[7]), revs)[:-1]
488 489
489 490 @reraise_safe_exceptions
490 491 def get_config_value(self, wire, section, name, untrusted=False):
491 492 repo = self._factory.repo(wire)
492 493 return repo.ui.config(section, name, untrusted=untrusted)
493 494
494 495 @reraise_safe_exceptions
495 496 def get_config_bool(self, wire, section, name, untrusted=False):
496 497 repo = self._factory.repo(wire)
497 498 return repo.ui.configbool(section, name, untrusted=untrusted)
498 499
499 500 @reraise_safe_exceptions
500 501 def get_config_list(self, wire, section, name, untrusted=False):
501 502 repo = self._factory.repo(wire)
502 503 return repo.ui.configlist(section, name, untrusted=untrusted)
503 504
504 505 @reraise_safe_exceptions
505 506 def is_large_file(self, wire, path):
506 507 return largefiles.lfutil.isstandin(path)
507 508
508 509 @reraise_safe_exceptions
509 510 def in_largefiles_store(self, wire, sha):
510 511 repo = self._factory.repo(wire)
511 512 return largefiles.lfutil.instore(repo, sha)
512 513
513 514 @reraise_safe_exceptions
514 515 def in_user_cache(self, wire, sha):
515 516 repo = self._factory.repo(wire)
516 517 return largefiles.lfutil.inusercache(repo.ui, sha)
517 518
518 519 @reraise_safe_exceptions
519 520 def store_path(self, wire, sha):
520 521 repo = self._factory.repo(wire)
521 522 return largefiles.lfutil.storepath(repo, sha)
522 523
523 524 @reraise_safe_exceptions
524 525 def link(self, wire, sha, path):
525 526 repo = self._factory.repo(wire)
526 527 largefiles.lfutil.link(
527 528 largefiles.lfutil.usercachepath(repo.ui, sha), path)
528 529
529 530 @reraise_safe_exceptions
530 531 def localrepository(self, wire, create=False):
531 532 self._factory.repo(wire, create=create)
532 533
533 534 @reraise_safe_exceptions
534 535 def lookup(self, wire, revision, both):
535 536 # TODO Paris: Ugly hack to "deserialize" long for msgpack
536 537 if isinstance(revision, float):
537 538 revision = long(revision)
538 539 repo = self._factory.repo(wire)
539 540 try:
540 541 ctx = repo[revision]
541 542 except RepoLookupError:
542 543 raise exceptions.LookupException(revision)
543 544 except LookupError as e:
544 545 raise exceptions.LookupException(e.name)
545 546
546 547 if not both:
547 548 return ctx.hex()
548 549
549 550 ctx = repo[ctx.hex()]
550 551 return ctx.hex(), ctx.rev()
551 552
552 553 @reraise_safe_exceptions
553 554 def pull(self, wire, url, commit_ids=None):
554 555 repo = self._factory.repo(wire)
555 556 remote = peer(repo, {}, url)
556 557 if commit_ids:
557 558 commit_ids = [bin(commit_id) for commit_id in commit_ids]
558 559
559 560 return exchange.pull(
560 561 repo, remote, heads=commit_ids, force=None).cgresult
561 562
562 563 @reraise_safe_exceptions
563 564 def revision(self, wire, rev):
564 565 repo = self._factory.repo(wire)
565 566 ctx = repo[rev]
566 567 return ctx.rev()
567 568
568 569 @reraise_safe_exceptions
569 570 def rev_range(self, wire, filter):
570 571 repo = self._factory.repo(wire)
571 572 revisions = [rev for rev in revrange(repo, filter)]
572 573 return revisions
573 574
574 575 @reraise_safe_exceptions
575 576 def rev_range_hash(self, wire, node):
576 577 repo = self._factory.repo(wire)
577 578
578 579 def get_revs(repo, rev_opt):
579 580 if rev_opt:
580 581 revs = revrange(repo, rev_opt)
581 582 if len(revs) == 0:
582 583 return (nullrev, nullrev)
583 584 return max(revs), min(revs)
584 585 else:
585 586 return len(repo) - 1, 0
586 587
587 588 stop, start = get_revs(repo, [node + ':'])
588 589 revs = [hex(repo[r].node()) for r in xrange(start, stop + 1)]
589 590 return revs
590 591
591 592 @reraise_safe_exceptions
592 593 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
593 594 other_path = kwargs.pop('other_path', None)
594 595
595 596 # case when we want to compare two independent repositories
596 597 if other_path and other_path != wire["path"]:
597 598 baseui = self._factory._create_config(wire["config"])
598 599 repo = unionrepo.unionrepository(baseui, other_path, wire["path"])
599 600 else:
600 601 repo = self._factory.repo(wire)
601 602 return list(repo.revs(rev_spec, *args))
602 603
603 604 @reraise_safe_exceptions
604 605 def strip(self, wire, revision, update, backup):
605 606 repo = self._factory.repo(wire)
606 607 ctx = repo[revision]
607 608 hgext_strip(
608 609 repo.baseui, repo, ctx.node(), update=update, backup=backup)
609 610
610 611 @reraise_safe_exceptions
611 612 def verify(self, wire,):
612 613 repo = self._factory.repo(wire)
613 614 baseui = self._factory._create_config(wire['config'])
614 615 baseui.setconfig('ui', 'quiet', 'false')
615 616 output = io.BytesIO()
616 617
617 618 def write(data, **unused_kwargs):
618 619 output.write(data)
619 620 baseui.write = write
620 621
621 622 repo.ui = baseui
622 623 verify.verify(repo)
623 624 return output.getvalue()
624 625
625 626 @reraise_safe_exceptions
626 627 def tag(self, wire, name, revision, message, local, user,
627 628 tag_time, tag_timezone):
628 629 repo = self._factory.repo(wire)
629 630 ctx = repo[revision]
630 631 node = ctx.node()
631 632
632 633 date = (tag_time, tag_timezone)
633 634 try:
634 635 hg_tag.tag(repo, name, node, message, local, user, date)
635 636 except Abort as e:
636 637 log.exception("Tag operation aborted")
637 638 # Exception can contain unicode which we convert
638 639 raise exceptions.AbortException(repr(e))
639 640
640 641 @reraise_safe_exceptions
641 642 def tags(self, wire):
642 643 repo = self._factory.repo(wire)
643 644 return repo.tags()
644 645
645 646 @reraise_safe_exceptions
646 647 def update(self, wire, node=None, clean=False):
647 648 repo = self._factory.repo(wire)
648 649 baseui = self._factory._create_config(wire['config'])
649 650 commands.update(baseui, repo, node=node, clean=clean)
650 651
651 652 @reraise_safe_exceptions
652 653 def identify(self, wire):
653 654 repo = self._factory.repo(wire)
654 655 baseui = self._factory._create_config(wire['config'])
655 656 output = io.BytesIO()
656 657 baseui.write = output.write
657 658 # This is required to get a full node id
658 659 baseui.debugflag = True
659 660 commands.identify(baseui, repo, id=True)
660 661
661 662 return output.getvalue()
662 663
663 664 @reraise_safe_exceptions
664 665 def pull_cmd(self, wire, source, bookmark=None, branch=None, revision=None,
665 666 hooks=True):
666 667 repo = self._factory.repo(wire)
667 668 baseui = self._factory._create_config(wire['config'], hooks=hooks)
668 669
669 670 # Mercurial internally has a lot of logic that checks ONLY if
670 671 # option is defined, we just pass those if they are defined then
671 672 opts = {}
672 673 if bookmark:
673 674 opts['bookmark'] = bookmark
674 675 if branch:
675 676 opts['branch'] = branch
676 677 if revision:
677 678 opts['rev'] = revision
678 679
679 680 commands.pull(baseui, repo, source, **opts)
680 681
681 682 @reraise_safe_exceptions
682 683 def heads(self, wire, branch=None):
683 684 repo = self._factory.repo(wire)
684 685 baseui = self._factory._create_config(wire['config'])
685 686 output = io.BytesIO()
686 687
687 688 def write(data, **unused_kwargs):
688 689 output.write(data)
689 690
690 691 baseui.write = write
691 692 if branch:
692 693 args = [branch]
693 694 else:
694 695 args = []
695 696 commands.heads(baseui, repo, template='{node} ', *args)
696 697
697 698 return output.getvalue()
698 699
699 700 @reraise_safe_exceptions
700 701 def ancestor(self, wire, revision1, revision2):
701 702 repo = self._factory.repo(wire)
702 703 changelog = repo.changelog
703 704 lookup = repo.lookup
704 705 a = changelog.ancestor(lookup(revision1), lookup(revision2))
705 706 return hex(a)
706 707
707 708 @reraise_safe_exceptions
708 709 def push(self, wire, revisions, dest_path, hooks=True,
709 710 push_branches=False):
710 711 repo = self._factory.repo(wire)
711 712 baseui = self._factory._create_config(wire['config'], hooks=hooks)
712 713 commands.push(baseui, repo, dest=dest_path, rev=revisions,
713 714 new_branch=push_branches)
714 715
715 716 @reraise_safe_exceptions
716 717 def merge(self, wire, revision):
717 718 repo = self._factory.repo(wire)
718 719 baseui = self._factory._create_config(wire['config'])
719 720 repo.ui.setconfig('ui', 'merge', 'internal:dump')
720 721
721 722 # In case of sub repositories are used mercurial prompts the user in
722 723 # case of merge conflicts or different sub repository sources. By
723 724 # setting the interactive flag to `False` mercurial doesn't prompt the
724 725 # used but instead uses a default value.
725 726 repo.ui.setconfig('ui', 'interactive', False)
726 727
727 728 commands.merge(baseui, repo, rev=revision)
728 729
729 730 @reraise_safe_exceptions
730 731 def commit(self, wire, message, username, close_branch=False):
731 732 repo = self._factory.repo(wire)
732 733 baseui = self._factory._create_config(wire['config'])
733 734 repo.ui.setconfig('ui', 'username', username)
734 735 commands.commit(baseui, repo, message=message, close_branch=close_branch)
735 736
736 737 @reraise_safe_exceptions
737 738 def rebase(self, wire, source=None, dest=None, abort=False):
738 739 repo = self._factory.repo(wire)
739 740 baseui = self._factory._create_config(wire['config'])
740 741 repo.ui.setconfig('ui', 'merge', 'internal:dump')
741 742 rebase.rebase(
742 743 baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
743 744
744 745 @reraise_safe_exceptions
745 746 def bookmark(self, wire, bookmark, revision=None):
746 747 repo = self._factory.repo(wire)
747 748 baseui = self._factory._create_config(wire['config'])
748 749 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
General Comments 0
You need to be logged in to leave comments. Login now