##// END OF EJS Templates
mercurial: implement import hook for handling C/Python modules...
Gregory Szorc -
r27220:4374d819 default
parent child Browse files
Show More
@@ -0,0 +1,109 b''
1 # __init__.py - Startup and module loading logic for Mercurial.
2 #
3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
4 #
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
7
8 from __future__ import absolute_import
9
10 import imp
11 import os
12 import sys
13
14 __all__ = []
15
16 # Rules for how modules can be loaded. Values are:
17 #
18 # c - require C extensions
19 # allow - allow pure Python implementation when C loading fails
20 # py - only load pure Python modules
21 modulepolicy = '@MODULELOADPOLICY@'
22
23 # By default, require the C extensions for performance reasons.
24 if modulepolicy == '@' 'MODULELOADPOLICY' '@':
25 # TODO change to 'c' once installer is changed.
26 modulepolicy = 'allow'
27
28 # Environment variable can always force settings.
29 modulepolicy = os.environ.get('HGMODULEPOLICY', modulepolicy)
30
31 # Modules that have both Python and C implementations. See also the
32 # set of .py files under mercurial/pure/.
33 _dualmodules = set([
34 'mercurial.base85',
35 'mercurial.bdiff',
36 'mercurial.diffhelpers',
37 'mercurial.mpatch',
38 'mercurial.osutil',
39 'mercurial.parsers',
40 ])
41
42 class hgimporter(object):
43 """Object that conforms to import hook interface defined in PEP-302."""
44 def find_module(self, name, path=None):
45 # We only care about modules that have both C and pure implementations.
46 if name in _dualmodules:
47 return self
48 return None
49
50 def load_module(self, name):
51 mod = sys.modules.get(name, None)
52 if mod:
53 return mod
54
55 mercurial = sys.modules['mercurial']
56
57 # Unlike the default importer which searches special locations and
58 # sys.path, we only look in the directory where "mercurial" was
59 # imported from.
60
61 # imp.find_module doesn't support submodules (modules with ".").
62 # Instead you have to pass the parent package's __path__ attribute
63 # as the path argument.
64 stem = name.split('.')[-1]
65
66 try:
67 if modulepolicy == 'py':
68 raise ImportError()
69
70 modinfo = imp.find_module(stem, mercurial.__path__)
71
72 # The Mercurial installer used to copy files from
73 # mercurial/pure/*.py to mercurial/*.py. Therefore, it's possible
74 # for some installations to have .py files under mercurial/*.
75 # Loading Python modules when we expected C versions could result
76 # in a) poor performance b) loading a version from a previous
77 # Mercurial version, potentially leading to incompatibility. Either
78 # scenario is bad. So we verify that modules loaded from
79 # mercurial/* are C extensions. If the current policy allows the
80 # loading of .py modules, the module will be re-imported from
81 # mercurial/pure/* below.
82 # TODO uncomment once setup.py is updated to actually install
83 # into mercurial/pure.
84 #if modinfo[2][2] != imp.C_EXTENSION:
85 # raise ImportError('.py version of %s found where C '
86 # 'version should exist' % name)
87
88 except ImportError:
89 if modulepolicy == 'c':
90 raise
91
92 # Could not load the C extension and pure Python is allowed. So
93 # try to load them.
94 from . import pure
95 modinfo = imp.find_module(stem, pure.__path__)
96 if not modinfo:
97 raise ImportError('could not find mercurial module %s' %
98 name)
99
100 mod = imp.load_module(name, *modinfo)
101 sys.modules[name] = mod
102 return mod
103
104 # We automagically register our custom importer as a side-effect of loading.
105 # This is necessary to ensure that any entry points are able to import
106 # mercurial.* modules without having to perform this registration themselves.
107 if not any(isinstance(x, hgimporter) for x in sys.meta_path):
108 # meta_path is used before any implicit finders and before sys.path.
109 sys.meta_path.insert(0, hgimporter())
@@ -177,11 +177,9 b' def runhg(cmd, env):'
177
177
178 version = ''
178 version = ''
179
179
180 # Execute hg out of this directory with a custom environment which
180 # Execute hg out of this directory with a custom environment which takes care
181 # includes the pure Python modules in mercurial/pure. We also take
181 # to not use any hgrc files and do no localization.
182 # care to not use any hgrc files and do no localization.
182 env = {'HGMODULEPOLICY': 'py',
183 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
184 env = {'PYTHONPATH': os.pathsep.join(pypath),
185 'HGRCPATH': '',
183 'HGRCPATH': '',
186 'LANGUAGE': 'C'}
184 'LANGUAGE': 'C'}
187 if 'LD_LIBRARY_PATH' in os.environ:
185 if 'LD_LIBRARY_PATH' in os.environ:
General Comments 0
You need to be logged in to leave comments. Login now