Changeset - 1c4007ec86e8
[Not reviewed]
default
0 2 0
Mads Kiilerich - 7 years ago 2018-12-23 21:16:06
mads@kiilerich.com
hg: fix URL cloning with Mercurial 4.6 and later

In 03dfcbe52906, I didn't notice that the API also changed ... and it was not
sufficiently tested.

Now, instead of using the peer classes directly, use the instance wrapper.

There is no automated testing of this, but it was tested manually to also work
in the oldest supported Mercurial version.
2 files changed with 4 insertions and 7 deletions:
0 comments (0 inline, 0 general)
kallithea/lib/vcs/backends/hg/repository.py
Show inline comments
 
@@ -271,91 +271,91 @@ class MercurialRepository(BaseRepository
 
        return ''.join(patch.diff(self._repo, rev1, rev2, match=file_filter,
 
                          opts=diffopts(git=True,
 
                                        showfunc=True,
 
                                        ignorews=ignore_whitespace,
 
                                        context=context)))
 

	
 
    @classmethod
 
    def _check_url(cls, url, repoui=None):
 
        """
 
        Function will check given url and try to verify if it's a valid
 
        link. Sometimes it may happened that mercurial will issue basic
 
        auth request that can cause whole API to hang when used from python
 
        or other external calls.
 

	
 
        On failures it'll raise urllib2.HTTPError, exception is also thrown
 
        when the return code is non 200
 
        """
 
        # check first if it's not an local url
 
        if os.path.isdir(url) or url.startswith('file:'):
 
            return True
 

	
 
        if url.startswith('ssh:'):
 
            # in case of invalid uri or authentication issues, sshpeer will
 
            # throw an exception.
 
            sshpeer(repoui or ui.ui(), url).lookup('tip')
 
            sshpeer.instance(repoui or ui.ui(), url, False).lookup('tip')
 
            return True
 

	
 
        url_prefix = None
 
        if '+' in url[:url.find('://')]:
 
            url_prefix, url = url.split('+', 1)
 

	
 
        handlers = []
 
        url_obj = hg_url(url)
 
        test_uri, authinfo = url_obj.authinfo()
 
        url_obj.passwd = '*****'
 
        cleaned_uri = str(url_obj)
 

	
 
        if authinfo:
 
            # create a password manager
 
            passmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
 
            passmgr.add_password(*authinfo)
 

	
 
            handlers.extend((httpbasicauthhandler(passmgr),
 
                             httpdigestauthhandler(passmgr)))
 

	
 
        o = urllib2.build_opener(*handlers)
 
        o.addheaders = [('Content-Type', 'application/mercurial-0.1'),
 
                        ('Accept', 'application/mercurial-0.1')]
 

	
 
        q = {"cmd": 'between'}
 
        q.update({'pairs': "%s-%s" % ('0' * 40, '0' * 40)})
 
        qs = '?%s' % urllib.urlencode(q)
 
        cu = "%s%s" % (test_uri, qs)
 
        req = urllib2.Request(cu, None, {})
 

	
 
        try:
 
            resp = o.open(req)
 
            if resp.code != 200:
 
                raise Exception('Return Code is not 200')
 
        except Exception as e:
 
            # means it cannot be cloned
 
            raise urllib2.URLError("[%s] org_exc: %s" % (cleaned_uri, e))
 

	
 
        if not url_prefix: # skip svn+http://... (and git+... too)
 
            # now check if it's a proper hg repo
 
            try:
 
                httppeer(repoui or ui.ui(), url).lookup('tip')
 
                httppeer.instance(repoui or ui.ui(), url, False).lookup('tip')
 
            except Exception as e:
 
                raise urllib2.URLError(
 
                    "url [%s] does not look like an hg repo org_exc: %s"
 
                    % (cleaned_uri, e))
 

	
 
        return True
 

	
 
    def _get_repo(self, create, src_url=None, update_after_clone=False):
 
        """
 
        Function will check for mercurial repository in given path and return
 
        a localrepo object. If there is no repository in that path it will
 
        raise an exception unless ``create`` parameter is set to True - in
 
        that case repository would be created and returned.
 
        If ``src_url`` is given, would try to clone repository from the
 
        location at given clone_point. Additionally it'll make update to
 
        working copy accordingly to ``update_after_clone`` flag
 
        """
 

	
 
        try:
 
            if src_url:
 
                url = safe_str(self._get_url(src_url))
 
                opts = {}
 
                if not update_after_clone:
 
                    opts.update({'noupdate': True})
kallithea/lib/vcs/utils/hgcompat.py
Show inline comments
 
"""
 
Mercurial libs compatibility
 
"""
 

	
 
import mercurial
 
from mercurial import demandimport
 
# patch demandimport, due to bug in mercurial when it always triggers demandimport.enable()
 
demandimport.enable = lambda *args, **kwargs: 1
 
from mercurial import archival, merge as hg_merge, patch, ui
 
from mercurial import discovery
 
from mercurial import localrepo
 
from mercurial import unionrepo
 
from mercurial import scmutil
 
from mercurial import config
 
from mercurial import tags as tagsmod
 
from mercurial import httppeer
 
from mercurial import sshpeer
 
from mercurial.commands import clone, nullid, pull
 
from mercurial.context import memctx, memfilectx
 
from mercurial.error import RepoError, RepoLookupError, Abort
 
from mercurial.hgweb import hgweb_mod
 
from mercurial.hgweb.common import get_contact
 
from mercurial.match import match
 
from mercurial.mdiff import diffopts
 
from mercurial.node import hex
 
from mercurial.encoding import tolocal
 
from mercurial.discovery import findcommonoutgoing
 
from mercurial.hg import peer
 
from mercurial.httppeer import httppeer
 
try: # sshpeer was renamed in Mercurial 4.6 (625038cb4b1d), but v1 is still good enough
 
    from mercurial.sshpeer import sshv1peer as sshpeer
 
except ImportError:
 
    from mercurial.sshpeer import sshpeer
 
from mercurial.util import url as hg_url
 
from mercurial.scmutil import revrange
 
from mercurial.node import nullrev
 
from mercurial.url import httpbasicauthhandler, httpdigestauthhandler
 

	
 

	
 
# Mercurial 4.5 8a0cac20a1ad introduced an extra memctx changectx argument
 
# - introduce an optional wrapper factory that doesn't pass it on
 
import inspect
 
if inspect.getargspec(memfilectx.__init__).args[2] != 'changectx':
 
    __org_memfilectx = memfilectx
 
    memfilectx = lambda repo, changectx, *args, **kwargs: __org_memfilectx(repo, *args, **kwargs)
 

	
 

	
 
# workaround for 3.3 94ac64bcf6fe and not calling largefiles reposetup correctly
 
localrepo.localrepository._lfstatuswriters = [lambda *msg, **opts: None]
 
# 3.5 7699d3212994 added the invariant that repo.lfstatus must exist before hitting overridearchive
 
localrepo.localrepository.lfstatus = False
 

	
 
# Mercurial 4.2 moved tag from localrepo to the tags module
 
def tag(repo, *args):
 
    try:
 
        tag_f  = tagsmod.tag
 
    except AttributeError:
0 comments (0 inline, 0 general)