github.com/whamcloud/lemur@v0.0.0-20190827193804-4655df8a52af/packaging/ci/lambda/GitPullS3/cffi/setuptools_ext.py (about) 1 import os 2 3 try: 4 basestring 5 except NameError: 6 # Python 3.x 7 basestring = str 8 9 def error(msg): 10 from distutils.errors import DistutilsSetupError 11 raise DistutilsSetupError(msg) 12 13 14 def execfile(filename, glob): 15 # We use execfile() (here rewritten for Python 3) instead of 16 # __import__() to load the build script. The problem with 17 # a normal import is that in some packages, the intermediate 18 # __init__.py files may already try to import the file that 19 # we are generating. 20 with open(filename) as f: 21 src = f.read() 22 src += '\n' # Python 2.6 compatibility 23 code = compile(src, filename, 'exec') 24 exec(code, glob, glob) 25 26 27 def add_cffi_module(dist, mod_spec): 28 from cffi.api import FFI 29 30 if not isinstance(mod_spec, basestring): 31 error("argument to 'cffi_modules=...' must be a str or a list of str," 32 " not %r" % (type(mod_spec).__name__,)) 33 mod_spec = str(mod_spec) 34 try: 35 build_file_name, ffi_var_name = mod_spec.split(':') 36 except ValueError: 37 error("%r must be of the form 'path/build.py:ffi_variable'" % 38 (mod_spec,)) 39 if not os.path.exists(build_file_name): 40 ext = '' 41 rewritten = build_file_name.replace('.', '/') + '.py' 42 if os.path.exists(rewritten): 43 ext = ' (rewrite cffi_modules to [%r])' % ( 44 rewritten + ':' + ffi_var_name,) 45 error("%r does not name an existing file%s" % (build_file_name, ext)) 46 47 mod_vars = {'__name__': '__cffi__', '__file__': build_file_name} 48 execfile(build_file_name, mod_vars) 49 50 try: 51 ffi = mod_vars[ffi_var_name] 52 except KeyError: 53 error("%r: object %r not found in module" % (mod_spec, 54 ffi_var_name)) 55 if not isinstance(ffi, FFI): 56 ffi = ffi() # maybe it's a function instead of directly an ffi 57 if not isinstance(ffi, FFI): 58 error("%r is not an FFI instance (got %r)" % (mod_spec, 59 type(ffi).__name__)) 60 if not hasattr(ffi, '_assigned_source'): 61 error("%r: the set_source() method was not called" % (mod_spec,)) 62 module_name, source, source_extension, kwds = ffi._assigned_source 63 if ffi._windows_unicode: 64 kwds = kwds.copy() 65 ffi._apply_windows_unicode(kwds) 66 67 if source is None: 68 _add_py_module(dist, ffi, module_name) 69 else: 70 _add_c_module(dist, ffi, module_name, source, source_extension, kwds) 71 72 73 def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): 74 from distutils.core import Extension 75 from distutils.command.build_ext import build_ext 76 from distutils.dir_util import mkpath 77 from distutils import log 78 from cffi import recompiler 79 80 allsources = ['$PLACEHOLDER'] 81 allsources.extend(kwds.pop('sources', [])) 82 ext = Extension(name=module_name, sources=allsources, **kwds) 83 84 def make_mod(tmpdir, pre_run=None): 85 c_file = os.path.join(tmpdir, module_name + source_extension) 86 log.info("generating cffi module %r" % c_file) 87 mkpath(tmpdir) 88 # a setuptools-only, API-only hook: called with the "ext" and "ffi" 89 # arguments just before we turn the ffi into C code. To use it, 90 # subclass the 'distutils.command.build_ext.build_ext' class and 91 # add a method 'def pre_run(self, ext, ffi)'. 92 if pre_run is not None: 93 pre_run(ext, ffi) 94 updated = recompiler.make_c_source(ffi, module_name, source, c_file) 95 if not updated: 96 log.info("already up-to-date") 97 return c_file 98 99 if dist.ext_modules is None: 100 dist.ext_modules = [] 101 dist.ext_modules.append(ext) 102 103 base_class = dist.cmdclass.get('build_ext', build_ext) 104 class build_ext_make_mod(base_class): 105 def run(self): 106 if ext.sources[0] == '$PLACEHOLDER': 107 pre_run = getattr(self, 'pre_run', None) 108 ext.sources[0] = make_mod(self.build_temp, pre_run) 109 base_class.run(self) 110 dist.cmdclass['build_ext'] = build_ext_make_mod 111 # NB. multiple runs here will create multiple 'build_ext_make_mod' 112 # classes. Even in this case the 'build_ext' command should be 113 # run once; but just in case, the logic above does nothing if 114 # called again. 115 116 117 def _add_py_module(dist, ffi, module_name): 118 from distutils.dir_util import mkpath 119 from distutils.command.build_py import build_py 120 from distutils.command.build_ext import build_ext 121 from distutils import log 122 from cffi import recompiler 123 124 def generate_mod(py_file): 125 log.info("generating cffi module %r" % py_file) 126 mkpath(os.path.dirname(py_file)) 127 updated = recompiler.make_py_source(ffi, module_name, py_file) 128 if not updated: 129 log.info("already up-to-date") 130 131 base_class = dist.cmdclass.get('build_py', build_py) 132 class build_py_make_mod(base_class): 133 def run(self): 134 base_class.run(self) 135 module_path = module_name.split('.') 136 module_path[-1] += '.py' 137 generate_mod(os.path.join(self.build_lib, *module_path)) 138 dist.cmdclass['build_py'] = build_py_make_mod 139 140 # the following is only for "build_ext -i" 141 base_class_2 = dist.cmdclass.get('build_ext', build_ext) 142 class build_ext_make_mod(base_class_2): 143 def run(self): 144 base_class_2.run(self) 145 if self.inplace: 146 # from get_ext_fullpath() in distutils/command/build_ext.py 147 module_path = module_name.split('.') 148 package = '.'.join(module_path[:-1]) 149 build_py = self.get_finalized_command('build_py') 150 package_dir = build_py.get_package_dir(package) 151 file_name = module_path[-1] + '.py' 152 generate_mod(os.path.join(package_dir, file_name)) 153 dist.cmdclass['build_ext'] = build_ext_make_mod 154 155 def cffi_modules(dist, attr, value): 156 assert attr == 'cffi_modules' 157 if isinstance(value, basestring): 158 value = [value] 159 160 for cffi_module in value: 161 add_cffi_module(dist, cffi_module)