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