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