# HG changeset patch # User Marcin Kuzminski # Date 2018-05-10 09:12:10 # Node ID 92b33b734c8a62a3e0f1875ce2b0a16b5e38cfa7 # Parent 6faeb1fd407bb4a74f9a778e5201a29aa9ebc923 hg: fixed code after version upgrade to 4.6.0 release diff --git a/vcsserver/hg.py b/vcsserver/hg.py --- a/vcsserver/hg.py +++ b/vcsserver/hg.py @@ -211,12 +211,12 @@ class HgRemote(object): if node['path'] == path: return memfilectx( _repo, + changectx=memctx, path=node['path'], data=node['content'], islink=False, isexec=bool(node['mode'] & stat.S_IXUSR), - copied=False, - memctx=memctx) + copied=False) raise exceptions.AbortException( "Given path haven't been marked as added, " @@ -454,9 +454,10 @@ class HgRemote(object): fctx = ctx.filectx(path) result = [] - for i, (a_line, content) in enumerate(fctx.annotate()): - ln_no = i + 1 - sha = hex(a_line.fctx.node()) + for i, annotate_obj in enumerate(fctx.annotate(), 1): + ln_no = i + sha = hex(annotate_obj.fctx.node()) + content = annotate_obj.text result.append((ln_no, sha, content)) return result @@ -533,10 +534,22 @@ class HgRemote(object): @reraise_safe_exceptions def lookup(self, wire, revision, both): - # TODO Paris: Ugly hack to "deserialize" long for msgpack - if isinstance(revision, float): - revision = long(revision) + repo = self._factory.repo(wire) + + if isinstance(revision, int): + # NOTE(marcink): + # since Mercurial doesn't support indexes properly + # we need to shift accordingly by one to get proper index, e.g + # repo[-1] => repo[-2] + # repo[0] => repo[-1] + # repo[1] => repo[2] we also never call repo[0] because + # it's actually second commit + if revision <= 0: + revision = revision + -1 + else: + revision = revision + 1 + try: ctx = repo[revision] except RepoLookupError: diff --git a/vcsserver/hgpatches.py b/vcsserver/hgpatches.py --- a/vcsserver/hgpatches.py +++ b/vcsserver/hgpatches.py @@ -36,15 +36,15 @@ def patch_largefiles_capabilities(): lfproto = hgcompat.largefiles.proto wrapper = _dynamic_capabilities_wrapper( lfproto, hgcompat.extensions.extensions) - lfproto.capabilities = wrapper + lfproto._capabilities = wrapper def _dynamic_capabilities_wrapper(lfproto, extensions): - wrapped_capabilities = lfproto.capabilities + wrapped_capabilities = lfproto._capabilities logger = logging.getLogger('vcsserver.hg') - def _dynamic_capabilities(repo, proto): + def _dynamic_capabilities(orig, repo, proto): """ Adds dynamic behavior, so that the capability is only added if the extension is enabled in the current ui object. @@ -52,10 +52,10 @@ def _dynamic_capabilities_wrapper(lfprot if 'largefiles' in dict(extensions(repo.ui)): logger.debug('Extension largefiles enabled') calc_capabilities = wrapped_capabilities + return calc_capabilities(orig, repo, proto) else: logger.debug('Extension largefiles disabled') - calc_capabilities = lfproto.capabilitiesorig - return calc_capabilities(repo, proto) + return orig(repo, proto) return _dynamic_capabilities diff --git a/vcsserver/hooks.py b/vcsserver/hooks.py --- a/vcsserver/hooks.py +++ b/vcsserver/hooks.py @@ -164,7 +164,8 @@ def _extras_from_ui(ui): def _rev_range_hash(repo, node): commits = [] - for rev in xrange(repo[node], len(repo)): + start = repo[node].rev() + for rev in xrange(start, len(repo)): ctx = repo[rev] commit_id = mercurial.node.hex(ctx.node()) branch = ctx.branch() diff --git a/vcsserver/scm_app.py b/vcsserver/scm_app.py --- a/vcsserver/scm_app.py +++ b/vcsserver/scm_app.py @@ -21,9 +21,9 @@ import itertools import mercurial import mercurial.error +import mercurial.wireprotoserver import mercurial.hgweb.common import mercurial.hgweb.hgweb_mod -import mercurial.hgweb.protocol import webob.exc from vcsserver import pygrack, exceptions, settings, git_lfs @@ -73,14 +73,18 @@ class HgWeb(mercurial.hgweb.hgweb_mod.hg This may be called by multiple threads. """ - req = mercurial.hgweb.request.wsgirequest(environ, start_response) - gen = self.run_wsgi(req) + from mercurial.hgweb import request as requestmod + req = requestmod.parserequestfromenv(environ) + res = requestmod.wsgiresponse(req, start_response) + gen = self.run_wsgi(req, res) first_chunk = None try: data = gen.next() - def first_chunk(): yield data + + def first_chunk(): + yield data except StopIteration: pass @@ -88,17 +92,18 @@ class HgWeb(mercurial.hgweb.hgweb_mod.hg return itertools.chain(first_chunk(), gen) return gen - def _runwsgi(self, req, repo): - cmd = req.form.get('cmd', [''])[0] - if not mercurial.hgweb.protocol.iscmd(cmd): - req.respond( - mercurial.hgweb.common.ErrorResponse( - mercurial.hgweb.common.HTTP_BAD_REQUEST), - mercurial.hgweb.protocol.HGTYPE - ) - return [''] + def _runwsgi(self, req, res, repo): - return super(HgWeb, self)._runwsgi(req, repo) + cmd = req.qsparams.get('cmd', '') + if not mercurial.wireprotoserver.iscmd(cmd): + # NOTE(marcink): for unsupported commands, we return bad request + # internally from HG + from mercurial.hgweb.common import statusmessage + res.status = statusmessage(mercurial.hgweb.common.HTTP_BAD_REQUEST) + res.setbodybytes('') + return res.sendresponse() + + return super(HgWeb, self)._runwsgi(req, res, repo) def make_hg_ui_from_config(repo_config): diff --git a/vcsserver/tests/test_hgpatches.py b/vcsserver/tests/test_hgpatches.py --- a/vcsserver/tests/test_hgpatches.py +++ b/vcsserver/tests/test_hgpatches.py @@ -28,56 +28,45 @@ def test_patch_largefiles_capabilities_a patched_capabilities): lfproto = hgcompat.largefiles.proto hgpatches.patch_largefiles_capabilities() - assert lfproto.capabilities.func_name == '_dynamic_capabilities' + assert lfproto._capabilities.func_name == '_dynamic_capabilities' def test_dynamic_capabilities_uses_original_function_if_not_enabled( - stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities): + stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities, + orig_capabilities): dynamic_capabilities = hgpatches._dynamic_capabilities_wrapper( hgcompat.largefiles.proto, stub_extensions) - caps = dynamic_capabilities(stub_repo, stub_proto) + caps = dynamic_capabilities(orig_capabilities, stub_repo, stub_proto) stub_extensions.assert_called_once_with(stub_ui) assert LARGEFILES_CAPABILITY not in caps -def test_dynamic_capabilities_uses_updated_capabilitiesorig( - stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities): - dynamic_capabilities = hgpatches._dynamic_capabilities_wrapper( - hgcompat.largefiles.proto, stub_extensions) - - # This happens when the extension is loaded for the first time, important - # to ensure that an updated function is correctly picked up. - hgcompat.largefiles.proto.capabilitiesorig = mock.Mock( - return_value='REPLACED') - - caps = dynamic_capabilities(stub_repo, stub_proto) - assert 'REPLACED' == caps - - def test_dynamic_capabilities_ignores_updated_capabilities( - stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities): + stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities, + orig_capabilities): stub_extensions.return_value = [('largefiles', mock.Mock())] dynamic_capabilities = hgpatches._dynamic_capabilities_wrapper( hgcompat.largefiles.proto, stub_extensions) # This happens when the extension is loaded for the first time, important # to ensure that an updated function is correctly picked up. - hgcompat.largefiles.proto.capabilities = mock.Mock( + hgcompat.largefiles.proto._capabilities = mock.Mock( side_effect=Exception('Must not be called')) - dynamic_capabilities(stub_repo, stub_proto) + dynamic_capabilities(orig_capabilities, stub_repo, stub_proto) def test_dynamic_capabilities_uses_largefiles_if_enabled( - stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities): + stub_repo, stub_proto, stub_ui, stub_extensions, patched_capabilities, + orig_capabilities): stub_extensions.return_value = [('largefiles', mock.Mock())] dynamic_capabilities = hgpatches._dynamic_capabilities_wrapper( hgcompat.largefiles.proto, stub_extensions) - caps = dynamic_capabilities(stub_repo, stub_proto) + caps = dynamic_capabilities(orig_capabilities, stub_repo, stub_proto) stub_extensions.assert_called_once_with(stub_ui) assert LARGEFILES_CAPABILITY in caps @@ -94,15 +83,11 @@ def patched_capabilities(request): Patch in `capabilitiesorig` and restore both capability functions. """ lfproto = hgcompat.largefiles.proto - orig_capabilities = lfproto.capabilities - orig_capabilitiesorig = lfproto.capabilitiesorig - - lfproto.capabilitiesorig = mock.Mock(return_value='ORIG') + orig_capabilities = lfproto._capabilities @request.addfinalizer def restore(): - lfproto.capabilities = orig_capabilities - lfproto.capabilitiesorig = orig_capabilitiesorig + lfproto._capabilities = orig_capabilities @pytest.fixture @@ -120,6 +105,15 @@ def stub_proto(stub_ui): @pytest.fixture +def orig_capabilities(): + from mercurial.wireprotov1server import wireprotocaps + + def _capabilities(repo, proto): + return wireprotocaps + return _capabilities + + +@pytest.fixture def stub_ui(): return hgcompat.ui.ui()