##// END OF EJS Templates
exchangev2: start to implement pull with wire protocol v2...
exchangev2: start to implement pull with wire protocol v2 Wire protocol version 2 will take a substantially different approach to exchange than version 1 (at least as far as pulling is concerned). This commit establishes a new exchangev2 module for holding code related to exchange using wire protocol v2. I could have added things to the existing exchange module. But it is already quite big. And doing things inline isn't in question because the existing code is already littered with conditional code for various states of support for the existing wire protocol as it evolved over 10+ years. A new module gives us a chance to make a clean break. This approach does mean we'll end up writing some duplicate code. And there's a significant chance we'll miss functionality as code is ported. The plan is to eventually add #testcase's to existing tests so the new wire protocol is tested side-by-side with the existing one. This will hopefully tease out any features that weren't ported properly. But before we get there, we need to build up support for the new exchange methods. Our journey towards implementing a new exchange begins with pulling. And pulling begins with discovery. The discovery code added to exchangev2 is heavily drawn from the following functions: * exchange._pulldiscoverychangegroup * discovery.findcommonincoming For now, we build on top of existing discovery mechanisms. The new wire protocol should be capable of doing things more efficiently. But I'd rather defer on this problem. To foster the transition, we invent a fake capability on the HTTPv2 peer and have the main pull code in exchange.py call into exchangev2 when the new wire protocol is being used. Differential Revision: https://phab.mercurial-scm.org/D4480

File last commit:

r39488:481db51c merge default
r39665:a86d21e7 default
Show More
policy.py
109 lines | 3.6 KiB | text/x-python | PythonLexer
# policy.py - module policy logic for Mercurial.
#
# Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
import os
import sys
# Rules for how modules can be loaded. Values are:
#
# c - require C extensions
# allow - allow pure Python implementation when C loading fails
# cffi - required cffi versions (implemented within pure module)
# cffi-allow - allow pure Python implementation if cffi version is missing
# py - only load pure Python modules
#
# By default, fall back to the pure modules so the in-place build can
# run without recompiling the C extensions. This will be overridden by
# __modulepolicy__ generated by setup.py.
policy = b'allow'
_packageprefs = {
# policy: (versioned package, pure package)
b'c': (r'cext', None),
b'allow': (r'cext', r'pure'),
b'cffi': (r'cffi', None),
b'cffi-allow': (r'cffi', r'pure'),
b'py': (None, r'pure'),
}
try:
from . import __modulepolicy__
policy = __modulepolicy__.modulepolicy
except ImportError:
pass
# PyPy doesn't load C extensions.
#
# The canonical way to do this is to test platform.python_implementation().
# But we don't import platform and don't bloat for it here.
if r'__pypy__' in sys.builtin_module_names:
policy = b'cffi'
# Environment variable can always force settings.
if sys.version_info[0] >= 3:
if r'HGMODULEPOLICY' in os.environ:
policy = os.environ[r'HGMODULEPOLICY'].encode(r'utf-8')
else:
policy = os.environ.get(r'HGMODULEPOLICY', policy)
def _importfrom(pkgname, modname):
# from .<pkgname> import <modname> (where . is looked through this module)
fakelocals = {}
pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1)
try:
fakelocals[modname] = mod = getattr(pkg, modname)
except AttributeError:
raise ImportError(r'cannot import name %s' % modname)
# force import; fakelocals[modname] may be replaced with the real module
getattr(mod, r'__doc__', None)
return fakelocals[modname]
# keep in sync with "version" in C modules
_cextversions = {
(r'cext', r'base85'): 1,
(r'cext', r'bdiff'): 3,
(r'cext', r'mpatch'): 1,
(r'cext', r'osutil'): 4,
(r'cext', r'parsers'): 11,
}
# map import request to other package or module
_modredirects = {
(r'cext', r'charencode'): (r'cext', r'parsers'),
(r'cffi', r'base85'): (r'pure', r'base85'),
(r'cffi', r'charencode'): (r'pure', r'charencode'),
(r'cffi', r'parsers'): (r'pure', r'parsers'),
}
def _checkmod(pkgname, modname, mod):
expected = _cextversions.get((pkgname, modname))
actual = getattr(mod, r'version', None)
if actual != expected:
raise ImportError(r'cannot import module %s.%s '
r'(expected version: %d, actual: %r)'
% (pkgname, modname, expected, actual))
def importmod(modname):
"""Import module according to policy and check API version"""
try:
verpkg, purepkg = _packageprefs[policy]
except KeyError:
raise ImportError(r'invalid HGMODULEPOLICY %r' % policy)
assert verpkg or purepkg
if verpkg:
pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
try:
mod = _importfrom(pn, mn)
if pn == verpkg:
_checkmod(pn, mn, mod)
return mod
except ImportError:
if not purepkg:
raise
pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
return _importfrom(pn, mn)