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)