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