# -*- coding: ascii -*- # # Copyright 2007, 2008, 2009, 2010, 2011 # Andr\xe9 Malo or his licensors, as applicable # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ =================== Command extenders =================== Command extenders. """ __author__ = "Andr\xe9 Malo" __docformat__ = "restructuredtext en" __test__ = False from distutils import fancy_getopt as _fancy_getopt from distutils import log from distutils.command import build as _build from distutils.command import build_ext as _build_ext from distutils.command import install as _install from distutils.command import install_data as _install_data from distutils.command import install_lib as _install_lib import os as _os _option_defaults = {} _option_inherits = {} _option_finalizers = {} _command_mapping = { 'install': 'Install', 'install_data': 'InstallData', 'install_lib': 'InstallLib', 'build': 'Build', 'build_ext': 'BuildExt', } def add_option(command, long_name, help_text, short_name=None, default=None, inherit=None): """ Add an option """ try: command_class = globals()[_command_mapping[command]] except KeyError: raise ValueError("Unknown command %r" % (command,)) for opt in command_class.user_options: if opt[0] == long_name: break else: opt = (long_name, short_name, help_text) command_class.user_options.append(opt) if not long_name.endswith('='): command_class.boolean_options.append(long_name) attr_name = _fancy_getopt.translate_longopt(long_name) else: attr_name = _fancy_getopt.translate_longopt(long_name[:-1]) if command not in _option_defaults: _option_defaults[command] = [] if inherit is not None: if isinstance(inherit, str): inherit = [inherit] for i_inherit in inherit: add_option( i_inherit, long_name, help_text, short_name, default ) default = None if command not in _option_inherits: _option_inherits[command] = [] for i_inherit in inherit: for i_command, opt_name in _option_inherits[command]: if i_command == i_inherit and opt_name == attr_name: break else: _option_inherits[command].append((i_inherit, attr_name)) _option_defaults[command].append((attr_name, default)) def add_finalizer(command, key, func): """ Add finalizer """ if command not in _option_finalizers: _option_finalizers[command] = {} if key not in _option_finalizers[command]: _option_finalizers[command][key] = func class Install(_install.install): """ Extended installer to reflect the additional data options """ user_options = _install.install.user_options + [ ('single-version-externally-managed', None, "Compat option. Does not a thing."), ] boolean_options = _install.install.boolean_options + [ 'single-version-externally-managed' ] def initialize_options(self): """ Prepare for new options """ _install.install.initialize_options(self) self.single_version_externally_managed = None if 'install' in _option_defaults: for opt_name, default in _option_defaults['install']: setattr(self, opt_name, default) def finalize_options(self): """ Finalize options """ _install.install.finalize_options(self) if 'install' in _option_inherits: for parent, opt_name in _option_inherits['install']: self.set_undefined_options(parent, (opt_name, opt_name)) if 'install' in _option_finalizers: for func in list(_option_finalizers['install'].values()): func(self) class InstallData(_install_data.install_data): """ Extended data installer """ user_options = _install_data.install_data.user_options + [] boolean_options = _install_data.install_data.boolean_options + [] def initialize_options(self): """ Prepare for new options """ _install_data.install_data.initialize_options(self) if 'install_data' in _option_defaults: for opt_name, default in _option_defaults['install_data']: setattr(self, opt_name, default) def finalize_options(self): """ Finalize options """ _install_data.install_data.finalize_options(self) if 'install_data' in _option_inherits: for parent, opt_name in _option_inherits['install_data']: self.set_undefined_options(parent, (opt_name, opt_name)) if 'install_data' in _option_finalizers: for func in list(_option_finalizers['install_data'].values()): func(self) class InstallLib(_install_lib.install_lib): """ Extended lib installer """ user_options = _install_lib.install_lib.user_options + [] boolean_options = _install_lib.install_lib.boolean_options + [] def initialize_options(self): """ Prepare for new options """ _install_lib.install_lib.initialize_options(self) if 'install_lib' in _option_defaults: for opt_name, default in _option_defaults['install_lib']: setattr(self, opt_name, default) def finalize_options(self): """ Finalize options """ _install_lib.install_lib.finalize_options(self) if 'install_lib' in _option_inherits: for parent, opt_name in _option_inherits['install_lib']: self.set_undefined_options(parent, (opt_name, opt_name)) if 'install_lib' in _option_finalizers: for func in list(_option_finalizers['install_lib'].values()): func(self) class BuildExt(_build_ext.build_ext): """ Extended extension builder class This class allows extensions to provide a ``check_prerequisites`` method which is called before actually building it. The method takes the `BuildExt` instance and returns whether the extension should be skipped or not. """ def initialize_options(self): """ Prepare for new options """ _build_ext.build_ext.initialize_options(self) if 'build_ext' in _option_defaults: for opt_name, default in _option_defaults['build_ext']: setattr(self, opt_name, default) def finalize_options(self): """ Finalize options """ _build_ext.build_ext.finalize_options(self) if 'build_ext' in _option_inherits: for parent, opt_name in _option_inherits['build_ext']: self.set_undefined_options(parent, (opt_name, opt_name)) if 'build_ext' in _option_finalizers: for func in list(_option_finalizers['build_ext'].values()): func(self) def build_extension(self, ext): """ Build C extension - with extended functionality The following features are added here: - ``ext.check_prerequisites`` is called before the extension is being built. See `Extension` for details. If the method does not exist, simply no check will be run. - The macros ``EXT_PACKAGE`` and ``EXT_MODULE`` will be filled (or unset) depending on the extensions name, but only if they are not already defined. :Parameters: `ext` : `Extension` The extension to build. If it's a pure ``distutils.core.Extension``, simply no prequisites check is applied. :Return: whatever ``distutils.command.build_ext.build_ext`` returns :Rtype: any """ # handle name macros macros = dict(ext.define_macros or ()) tup = ext.name.split('.') if len(tup) == 1: pkg, mod = None, tup[0] else: pkg, mod = '.'.join(tup[:-1]), tup[-1] if pkg is not None and 'EXT_PACKAGE' not in macros: ext.define_macros.append(('EXT_PACKAGE', pkg)) if 'EXT_MODULE' not in macros: ext.define_macros.append(('EXT_MODULE', mod)) if pkg is None: macros = dict(ext.undef_macros or ()) if 'EXT_PACKAGE' not in macros: ext.undef_macros.append('EXT_PACKAGE') # handle prereq checks try: checker = ext.check_prerequisites except AttributeError: pass else: if checker(self): log.info("Skipping %s extension" % ext.name) return return _build_ext.build_ext.build_extension(self, ext) class Build(_build.build): def initialize_options(self): """ Prepare for new options """ _build.build.initialize_options(self) if 'build' in _option_defaults: for opt_name, default in _option_defaults['build']: setattr(self, opt_name, default) def finalize_options(self): """ Finalize options """ _build.build.finalize_options(self) if 'build' in _option_inherits: for parent, opt_name in _option_inherits['build']: self.set_undefined_options(parent, (opt_name, opt_name)) if 'build' in _option_finalizers: for func in list(_option_finalizers['build'].values()): func(self)