##// END OF EJS Templates
mercurial: use tags module as repo function is deprecated as of 4.2
marcink -
r274:6d90cc98 default
parent child Browse files
Show More
@@ -1,746 +1,746 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 patch, peer, revrange, ui, Abort, LookupError, RepoError, RepoLookupError,
37 InterventionRequired, RequirementError)
36 patch, peer, revrange, ui, hg_tag, Abort, LookupError, RepoError,
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 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 290 def ctx_phase(self, wire, revision):
291 291 repo = self._factory.repo(wire)
292 292 ctx = repo[revision]
293 293 # public=0, draft=1, secret=3
294 294 return ctx.phase()
295 295
296 296 @reraise_safe_exceptions
297 297 def ctx_obsolete(self, wire, revision):
298 298 repo = self._factory.repo(wire)
299 299 ctx = repo[revision]
300 300 return ctx.obsolete()
301 301
302 302 @reraise_safe_exceptions
303 303 def ctx_hidden(self, wire, revision):
304 304 repo = self._factory.repo(wire)
305 305 ctx = repo[revision]
306 306 return ctx.hidden()
307 307
308 308 @reraise_safe_exceptions
309 309 def ctx_substate(self, wire, revision):
310 310 repo = self._factory.repo(wire)
311 311 ctx = repo[revision]
312 312 return ctx.substate
313 313
314 314 @reraise_safe_exceptions
315 315 def ctx_status(self, wire, revision):
316 316 repo = self._factory.repo(wire)
317 317 ctx = repo[revision]
318 318 status = repo[ctx.p1().node()].status(other=ctx.node())
319 319 # object of status (odd, custom named tuple in mercurial) is not
320 320 # correctly serializable, we make it a list, as the underling
321 321 # API expects this to be a list
322 322 return list(status)
323 323
324 324 @reraise_safe_exceptions
325 325 def ctx_user(self, wire, revision):
326 326 repo = self._factory.repo(wire)
327 327 ctx = repo[revision]
328 328 return ctx.user()
329 329
330 330 @reraise_safe_exceptions
331 331 def check_url(self, url, config):
332 332 _proto = None
333 333 if '+' in url[:url.find('://')]:
334 334 _proto = url[0:url.find('+')]
335 335 url = url[url.find('+') + 1:]
336 336 handlers = []
337 337 url_obj = url_parser(url)
338 338 test_uri, authinfo = url_obj.authinfo()
339 339 url_obj.passwd = '*****' if url_obj.passwd else url_obj.passwd
340 340 url_obj.query = obfuscate_qs(url_obj.query)
341 341
342 342 cleaned_uri = str(url_obj)
343 343 log.info("Checking URL for remote cloning/import: %s", cleaned_uri)
344 344
345 345 if authinfo:
346 346 # create a password manager
347 347 passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
348 348 passmgr.add_password(*authinfo)
349 349
350 350 handlers.extend((httpbasicauthhandler(passmgr),
351 351 httpdigestauthhandler(passmgr)))
352 352
353 353 o = urllib2.build_opener(*handlers)
354 354 o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
355 355 ('Accept', 'application/mercurial-0.1')]
356 356
357 357 q = {"cmd": 'between'}
358 358 q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
359 359 qs = '?%s' % urllib.urlencode(q)
360 360 cu = "%s%s" % (test_uri, qs)
361 361 req = urllib2.Request(cu, None, {})
362 362
363 363 try:
364 364 log.debug("Trying to open URL %s", cleaned_uri)
365 365 resp = o.open(req)
366 366 if resp.code != 200:
367 367 raise exceptions.URLError('Return Code is not 200')
368 368 except Exception as e:
369 369 log.warning("URL cannot be opened: %s", cleaned_uri, exc_info=True)
370 370 # means it cannot be cloned
371 371 raise exceptions.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
372 372
373 373 # now check if it's a proper hg repo, but don't do it for svn
374 374 try:
375 375 if _proto == 'svn':
376 376 pass
377 377 else:
378 378 # check for pure hg repos
379 379 log.debug(
380 380 "Verifying if URL is a Mercurial repository: %s",
381 381 cleaned_uri)
382 382 httppeer(make_ui_from_config(config), url).lookup('tip')
383 383 except Exception as e:
384 384 log.warning("URL is not a valid Mercurial repository: %s",
385 385 cleaned_uri)
386 386 raise exceptions.URLError(
387 387 "url [%s] does not look like an hg repo org_exc: %s"
388 388 % (cleaned_uri, e))
389 389
390 390 log.info("URL is a valid Mercurial repository: %s", cleaned_uri)
391 391 return True
392 392
393 393 @reraise_safe_exceptions
394 394 def diff(
395 395 self, wire, rev1, rev2, file_filter, opt_git, opt_ignorews,
396 396 context):
397 397 repo = self._factory.repo(wire)
398 398
399 399 if file_filter:
400 400 match_filter = match(file_filter[0], '', [file_filter[1]])
401 401 else:
402 402 match_filter = file_filter
403 403 opts = diffopts(git=opt_git, ignorews=opt_ignorews, context=context)
404 404
405 405 try:
406 406 return "".join(patch.diff(
407 407 repo, node1=rev1, node2=rev2, match=match_filter, opts=opts))
408 408 except RepoLookupError:
409 409 raise exceptions.LookupException()
410 410
411 411 @reraise_safe_exceptions
412 412 def file_history(self, wire, revision, path, limit):
413 413 repo = self._factory.repo(wire)
414 414
415 415 ctx = repo[revision]
416 416 fctx = ctx.filectx(path)
417 417
418 418 def history_iter():
419 419 limit_rev = fctx.rev()
420 420 for obj in reversed(list(fctx.filelog())):
421 421 obj = fctx.filectx(obj)
422 422 if limit_rev >= obj.rev():
423 423 yield obj
424 424
425 425 history = []
426 426 for cnt, obj in enumerate(history_iter()):
427 427 if limit and cnt >= limit:
428 428 break
429 429 history.append(hex(obj.node()))
430 430
431 431 return [x for x in history]
432 432
433 433 @reraise_safe_exceptions
434 434 def file_history_untill(self, wire, revision, path, limit):
435 435 repo = self._factory.repo(wire)
436 436 ctx = repo[revision]
437 437 fctx = ctx.filectx(path)
438 438
439 439 file_log = list(fctx.filelog())
440 440 if limit:
441 441 # Limit to the last n items
442 442 file_log = file_log[-limit:]
443 443
444 444 return [hex(fctx.filectx(cs).node()) for cs in reversed(file_log)]
445 445
446 446 @reraise_safe_exceptions
447 447 def fctx_annotate(self, wire, revision, path):
448 448 repo = self._factory.repo(wire)
449 449 ctx = repo[revision]
450 450 fctx = ctx.filectx(path)
451 451
452 452 result = []
453 453 for i, annotate_data in enumerate(fctx.annotate()):
454 454 ln_no = i + 1
455 455 node_info, content = annotate_data
456 456 sha = hex(node_info[0].node())
457 457 result.append((ln_no, sha, content))
458 458 return result
459 459
460 460 @reraise_safe_exceptions
461 461 def fctx_data(self, wire, revision, path):
462 462 repo = self._factory.repo(wire)
463 463 ctx = repo[revision]
464 464 fctx = ctx.filectx(path)
465 465 return fctx.data()
466 466
467 467 @reraise_safe_exceptions
468 468 def fctx_flags(self, wire, revision, path):
469 469 repo = self._factory.repo(wire)
470 470 ctx = repo[revision]
471 471 fctx = ctx.filectx(path)
472 472 return fctx.flags()
473 473
474 474 @reraise_safe_exceptions
475 475 def fctx_size(self, wire, revision, path):
476 476 repo = self._factory.repo(wire)
477 477 ctx = repo[revision]
478 478 fctx = ctx.filectx(path)
479 479 return fctx.size()
480 480
481 481 @reraise_safe_exceptions
482 482 def get_all_commit_ids(self, wire, name):
483 483 repo = self._factory.repo(wire)
484 484 revs = repo.filtered(name).changelog.index
485 485 return map(lambda x: hex(x[7]), revs)[:-1]
486 486
487 487 @reraise_safe_exceptions
488 488 def get_config_value(self, wire, section, name, untrusted=False):
489 489 repo = self._factory.repo(wire)
490 490 return repo.ui.config(section, name, untrusted=untrusted)
491 491
492 492 @reraise_safe_exceptions
493 493 def get_config_bool(self, wire, section, name, untrusted=False):
494 494 repo = self._factory.repo(wire)
495 495 return repo.ui.configbool(section, name, untrusted=untrusted)
496 496
497 497 @reraise_safe_exceptions
498 498 def get_config_list(self, wire, section, name, untrusted=False):
499 499 repo = self._factory.repo(wire)
500 500 return repo.ui.configlist(section, name, untrusted=untrusted)
501 501
502 502 @reraise_safe_exceptions
503 503 def is_large_file(self, wire, path):
504 504 return largefiles.lfutil.isstandin(path)
505 505
506 506 @reraise_safe_exceptions
507 507 def in_largefiles_store(self, wire, sha):
508 508 repo = self._factory.repo(wire)
509 509 return largefiles.lfutil.instore(repo, sha)
510 510
511 511 @reraise_safe_exceptions
512 512 def in_user_cache(self, wire, sha):
513 513 repo = self._factory.repo(wire)
514 514 return largefiles.lfutil.inusercache(repo.ui, sha)
515 515
516 516 @reraise_safe_exceptions
517 517 def store_path(self, wire, sha):
518 518 repo = self._factory.repo(wire)
519 519 return largefiles.lfutil.storepath(repo, sha)
520 520
521 521 @reraise_safe_exceptions
522 522 def link(self, wire, sha, path):
523 523 repo = self._factory.repo(wire)
524 524 largefiles.lfutil.link(
525 525 largefiles.lfutil.usercachepath(repo.ui, sha), path)
526 526
527 527 @reraise_safe_exceptions
528 528 def localrepository(self, wire, create=False):
529 529 self._factory.repo(wire, create=create)
530 530
531 531 @reraise_safe_exceptions
532 532 def lookup(self, wire, revision, both):
533 533 # TODO Paris: Ugly hack to "deserialize" long for msgpack
534 534 if isinstance(revision, float):
535 535 revision = long(revision)
536 536 repo = self._factory.repo(wire)
537 537 try:
538 538 ctx = repo[revision]
539 539 except RepoLookupError:
540 540 raise exceptions.LookupException(revision)
541 541 except LookupError as e:
542 542 raise exceptions.LookupException(e.name)
543 543
544 544 if not both:
545 545 return ctx.hex()
546 546
547 547 ctx = repo[ctx.hex()]
548 548 return ctx.hex(), ctx.rev()
549 549
550 550 @reraise_safe_exceptions
551 551 def pull(self, wire, url, commit_ids=None):
552 552 repo = self._factory.repo(wire)
553 553 remote = peer(repo, {}, url)
554 554 if commit_ids:
555 555 commit_ids = [bin(commit_id) for commit_id in commit_ids]
556 556
557 557 return exchange.pull(
558 558 repo, remote, heads=commit_ids, force=None).cgresult
559 559
560 560 @reraise_safe_exceptions
561 561 def revision(self, wire, rev):
562 562 repo = self._factory.repo(wire)
563 563 ctx = repo[rev]
564 564 return ctx.rev()
565 565
566 566 @reraise_safe_exceptions
567 567 def rev_range(self, wire, filter):
568 568 repo = self._factory.repo(wire)
569 569 revisions = [rev for rev in revrange(repo, filter)]
570 570 return revisions
571 571
572 572 @reraise_safe_exceptions
573 573 def rev_range_hash(self, wire, node):
574 574 repo = self._factory.repo(wire)
575 575
576 576 def get_revs(repo, rev_opt):
577 577 if rev_opt:
578 578 revs = revrange(repo, rev_opt)
579 579 if len(revs) == 0:
580 580 return (nullrev, nullrev)
581 581 return max(revs), min(revs)
582 582 else:
583 583 return len(repo) - 1, 0
584 584
585 585 stop, start = get_revs(repo, [node + ':'])
586 586 revs = [hex(repo[r].node()) for r in xrange(start, stop + 1)]
587 587 return revs
588 588
589 589 @reraise_safe_exceptions
590 590 def revs_from_revspec(self, wire, rev_spec, *args, **kwargs):
591 591 other_path = kwargs.pop('other_path', None)
592 592
593 593 # case when we want to compare two independent repositories
594 594 if other_path and other_path != wire["path"]:
595 595 baseui = self._factory._create_config(wire["config"])
596 596 repo = unionrepo.unionrepository(baseui, other_path, wire["path"])
597 597 else:
598 598 repo = self._factory.repo(wire)
599 599 return list(repo.revs(rev_spec, *args))
600 600
601 601 @reraise_safe_exceptions
602 602 def strip(self, wire, revision, update, backup):
603 603 repo = self._factory.repo(wire)
604 604 ctx = repo[revision]
605 605 hgext_strip(
606 606 repo.baseui, repo, ctx.node(), update=update, backup=backup)
607 607
608 608 @reraise_safe_exceptions
609 609 def verify(self, wire,):
610 610 repo = self._factory.repo(wire)
611 611 baseui = self._factory._create_config(wire['config'])
612 612 baseui.setconfig('ui', 'quiet', 'false')
613 613 output = io.BytesIO()
614 614
615 615 def write(data, **unused_kwargs):
616 616 output.write(data)
617 617 baseui.write = write
618 618
619 619 repo.ui = baseui
620 620 verify.verify(repo)
621 621 return output.getvalue()
622 622
623 623 @reraise_safe_exceptions
624 624 def tag(self, wire, name, revision, message, local, user,
625 625 tag_time, tag_timezone):
626 626 repo = self._factory.repo(wire)
627 627 ctx = repo[revision]
628 628 node = ctx.node()
629 629
630 630 date = (tag_time, tag_timezone)
631 631 try:
632 repo.tag(name, node, message, local, user, date)
632 hg_tag.tag(repo, name, node, message, local, user, date)
633 633 except Abort as e:
634 634 log.exception("Tag operation aborted")
635 635 # Exception can contain unicode which we convert
636 636 raise exceptions.AbortException(repr(e))
637 637
638 638 @reraise_safe_exceptions
639 639 def tags(self, wire):
640 640 repo = self._factory.repo(wire)
641 641 return repo.tags()
642 642
643 643 @reraise_safe_exceptions
644 644 def update(self, wire, node=None, clean=False):
645 645 repo = self._factory.repo(wire)
646 646 baseui = self._factory._create_config(wire['config'])
647 647 commands.update(baseui, repo, node=node, clean=clean)
648 648
649 649 @reraise_safe_exceptions
650 650 def identify(self, wire):
651 651 repo = self._factory.repo(wire)
652 652 baseui = self._factory._create_config(wire['config'])
653 653 output = io.BytesIO()
654 654 baseui.write = output.write
655 655 # This is required to get a full node id
656 656 baseui.debugflag = True
657 657 commands.identify(baseui, repo, id=True)
658 658
659 659 return output.getvalue()
660 660
661 661 @reraise_safe_exceptions
662 662 def pull_cmd(self, wire, source, bookmark=None, branch=None, revision=None,
663 663 hooks=True):
664 664 repo = self._factory.repo(wire)
665 665 baseui = self._factory._create_config(wire['config'], hooks=hooks)
666 666
667 667 # Mercurial internally has a lot of logic that checks ONLY if
668 668 # option is defined, we just pass those if they are defined then
669 669 opts = {}
670 670 if bookmark:
671 671 opts['bookmark'] = bookmark
672 672 if branch:
673 673 opts['branch'] = branch
674 674 if revision:
675 675 opts['rev'] = revision
676 676
677 677 commands.pull(baseui, repo, source, **opts)
678 678
679 679 @reraise_safe_exceptions
680 680 def heads(self, wire, branch=None):
681 681 repo = self._factory.repo(wire)
682 682 baseui = self._factory._create_config(wire['config'])
683 683 output = io.BytesIO()
684 684
685 685 def write(data, **unused_kwargs):
686 686 output.write(data)
687 687
688 688 baseui.write = write
689 689 if branch:
690 690 args = [branch]
691 691 else:
692 692 args = []
693 693 commands.heads(baseui, repo, template='{node} ', *args)
694 694
695 695 return output.getvalue()
696 696
697 697 @reraise_safe_exceptions
698 698 def ancestor(self, wire, revision1, revision2):
699 699 repo = self._factory.repo(wire)
700 700 changelog = repo.changelog
701 701 lookup = repo.lookup
702 702 a = changelog.ancestor(lookup(revision1), lookup(revision2))
703 703 return hex(a)
704 704
705 705 @reraise_safe_exceptions
706 706 def push(self, wire, revisions, dest_path, hooks=True,
707 707 push_branches=False):
708 708 repo = self._factory.repo(wire)
709 709 baseui = self._factory._create_config(wire['config'], hooks=hooks)
710 710 commands.push(baseui, repo, dest=dest_path, rev=revisions,
711 711 new_branch=push_branches)
712 712
713 713 @reraise_safe_exceptions
714 714 def merge(self, wire, revision):
715 715 repo = self._factory.repo(wire)
716 716 baseui = self._factory._create_config(wire['config'])
717 717 repo.ui.setconfig('ui', 'merge', 'internal:dump')
718 718
719 719 # In case of sub repositories are used mercurial prompts the user in
720 720 # case of merge conflicts or different sub repository sources. By
721 721 # setting the interactive flag to `False` mercurial doesn't prompt the
722 722 # used but instead uses a default value.
723 723 repo.ui.setconfig('ui', 'interactive', False)
724 724
725 725 commands.merge(baseui, repo, rev=revision)
726 726
727 727 @reraise_safe_exceptions
728 728 def commit(self, wire, message, username, close_branch=False):
729 729 repo = self._factory.repo(wire)
730 730 baseui = self._factory._create_config(wire['config'])
731 731 repo.ui.setconfig('ui', 'username', username)
732 732 commands.commit(baseui, repo, message=message, close_branch=close_branch)
733 733
734 734 @reraise_safe_exceptions
735 735 def rebase(self, wire, source=None, dest=None, abort=False):
736 736 repo = self._factory.repo(wire)
737 737 baseui = self._factory._create_config(wire['config'])
738 738 repo.ui.setconfig('ui', 'merge', 'internal:dump')
739 739 rebase.rebase(
740 740 baseui, repo, base=source, dest=dest, abort=abort, keep=not abort)
741 741
742 742 @reraise_safe_exceptions
743 743 def bookmark(self, wire, bookmark, revision=None):
744 744 repo = self._factory.repo(wire)
745 745 baseui = self._factory._create_config(wire['config'])
746 746 commands.bookmark(baseui, repo, bookmark, rev=revision, force=True)
@@ -1,62 +1,63 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 """
19 19 Mercurial libs compatibility
20 20 """
21 21
22 22 import mercurial
23 23 import mercurial.demandimport
24 24 # patch demandimport, due to bug in mercurial when it always triggers
25 25 # demandimport.enable()
26 26 mercurial.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 from mercurial import tags as hg_tag
39 40
40 41 from mercurial.commands import clone, nullid, pull
41 42 from mercurial.context import memctx, memfilectx
42 43 from mercurial.error import (
43 44 LookupError, RepoError, RepoLookupError, Abort, InterventionRequired,
44 45 RequirementError)
45 46 from mercurial.hgweb import hgweb_mod
46 47 from mercurial.localrepo import localrepository
47 48 from mercurial.match import match
48 49 from mercurial.mdiff import diffopts
49 50 from mercurial.node import bin, hex
50 51 from mercurial.encoding import tolocal
51 52 from mercurial.discovery import findcommonoutgoing
52 53 from mercurial.hg import peer
53 54 from mercurial.httppeer import httppeer
54 55 from mercurial.util import url as hg_url
55 56 from mercurial.scmutil import revrange
56 57 from mercurial.node import nullrev
57 58 from mercurial import exchange
58 59 from hgext import largefiles
59 60
60 61 # those authnadlers are patched for python 2.6.5 bug an
61 62 # infinit looping when given invalid resources
62 63 from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
General Comments 0
You need to be logged in to leave comments. Login now