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