267 lines
9.7 KiB
Python
267 lines
9.7 KiB
Python
# -*- 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)
|