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