remove _setup
This commit is contained in:
parent
1ce76d20dd
commit
5d86fbf444
@ -1,39 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
================
|
|
||||||
Package _setup
|
|
||||||
================
|
|
||||||
|
|
||||||
This package provides tools for main package setup.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
if _sys.version_info[0] == 2:
|
|
||||||
__path__ = [_os.path.join(__path__[0], 'py2')]
|
|
||||||
__author__ = __author__.decode('latin-1')
|
|
||||||
elif _sys.version_info[0] == 3:
|
|
||||||
__path__ = [_os.path.join(__path__[0], 'py3')]
|
|
||||||
else:
|
|
||||||
raise RuntimeError("Unsupported python version")
|
|
||||||
del _os, _sys
|
|
||||||
|
|
||||||
from _setup.setup import run # pylint: disable = W0611
|
|
@ -1,244 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006, 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* central naming stuff
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SETUP_CEXT_H
|
|
||||||
#define SETUP_CEXT_H
|
|
||||||
|
|
||||||
#ifndef EXT_MODULE
|
|
||||||
#error EXT_MODULE must be defined outside of this file (-DEXT_MODULE=...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* include core header files
|
|
||||||
*/
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
|
||||||
|
|
||||||
#include "Python.h"
|
|
||||||
#include "structmember.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* define our helper macros depending on the stuff above
|
|
||||||
*/
|
|
||||||
#define STRINGIFY(n) STRINGIFY_HELPER(n)
|
|
||||||
#define STRINGIFY_HELPER(n) #n
|
|
||||||
#define CONCATENATE(first, second) CONCATENATE_HELPER(first, second)
|
|
||||||
#define CONCATENATE_HELPER(first, second) first##second
|
|
||||||
|
|
||||||
#define EXT_MODULE_NAME STRINGIFY(EXT_MODULE)
|
|
||||||
#ifdef EXT_PACKAGE
|
|
||||||
#define EXT_PACKAGE_NAME STRINGIFY(EXT_PACKAGE)
|
|
||||||
#define EXT_MODULE_PATH EXT_PACKAGE_NAME "." EXT_MODULE_NAME
|
|
||||||
#else
|
|
||||||
#define EXT_PACKAGE_NAME ""
|
|
||||||
#define EXT_MODULE_PATH EXT_MODULE_NAME
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EXT_DOCS_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, __doc__))
|
|
||||||
#define EXT_METHODS_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, _methods))
|
|
||||||
#define EXT_METHODS static PyMethodDef EXT_METHODS_VAR[]
|
|
||||||
|
|
||||||
#define EXT_DEFINE_VAR CONCATENATE(var, CONCATENATE(EXT_MODULE, _module))
|
|
||||||
|
|
||||||
/* Py3K Support */
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
|
||||||
|
|
||||||
#define EXT3
|
|
||||||
|
|
||||||
#ifndef PyMODINIT_FUNC
|
|
||||||
#define EXT_INIT_FUNC PyObject *CONCATENATE(PyInit_, EXT_MODULE)(void)
|
|
||||||
#else
|
|
||||||
#define EXT_INIT_FUNC PyMODINIT_FUNC CONCATENATE(PyInit_, EXT_MODULE)(void)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EXT_DEFINE(name, methods, doc) \
|
|
||||||
static struct PyModuleDef EXT_DEFINE_VAR = { \
|
|
||||||
PyModuleDef_HEAD_INIT, \
|
|
||||||
name, \
|
|
||||||
doc, \
|
|
||||||
-1, \
|
|
||||||
methods, \
|
|
||||||
NULL, \
|
|
||||||
NULL, \
|
|
||||||
NULL, \
|
|
||||||
NULL \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define EXT_CREATE(def) (PyModule_Create(def))
|
|
||||||
#define EXT_INIT_ERROR(module) do {Py_XDECREF(module); return NULL;} while(0)
|
|
||||||
#define EXT_INIT_RETURN(module) return module
|
|
||||||
|
|
||||||
#else /* end py3k */
|
|
||||||
|
|
||||||
#define EXT2
|
|
||||||
|
|
||||||
#ifndef PyMODINIT_FUNC
|
|
||||||
#define EXT_INIT_FUNC void CONCATENATE(init, EXT_MODULE)(void)
|
|
||||||
#else
|
|
||||||
#define EXT_INIT_FUNC PyMODINIT_FUNC CONCATENATE(init, EXT_MODULE)(void)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EXT_DEFINE__STRUCT \
|
|
||||||
CONCATENATE(struct, CONCATENATE(EXT_MODULE, _module))
|
|
||||||
|
|
||||||
struct EXT_DEFINE__STRUCT {
|
|
||||||
char *m_name;
|
|
||||||
char *m_doc;
|
|
||||||
PyMethodDef *m_methods;
|
|
||||||
};
|
|
||||||
#define EXT_DEFINE(name, methods, doc) \
|
|
||||||
static struct EXT_DEFINE__STRUCT EXT_DEFINE_VAR = { \
|
|
||||||
name, \
|
|
||||||
doc, \
|
|
||||||
methods \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define EXT_CREATE(def) ((def)->m_doc \
|
|
||||||
? Py_InitModule3((def)->m_name, (def)->m_methods, (def)->m_doc) \
|
|
||||||
: Py_InitModule((def)->m_name, (def)->m_methods) \
|
|
||||||
)
|
|
||||||
#define EXT_INIT_ERROR(module) return
|
|
||||||
#define EXT_INIT_RETURN(module) return
|
|
||||||
|
|
||||||
#endif /* end py2K */
|
|
||||||
|
|
||||||
#define EXT_INIT_TYPE(module, type) do { \
|
|
||||||
if (PyType_Ready(type) < 0) \
|
|
||||||
EXT_INIT_ERROR(module); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define EXT_ADD_TYPE(module, name, type) do { \
|
|
||||||
Py_INCREF(type); \
|
|
||||||
if (PyModule_AddObject(module, name, (PyObject *)(type)) < 0) \
|
|
||||||
EXT_INIT_ERROR(module); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define EXT_ADD_UNICODE(module, name, string, encoding) do { \
|
|
||||||
if (PyModule_AddObject( \
|
|
||||||
module, \
|
|
||||||
name, \
|
|
||||||
PyUnicode_Decode( \
|
|
||||||
string, \
|
|
||||||
sizeof(string) - 1, \
|
|
||||||
encoding, \
|
|
||||||
"strict" \
|
|
||||||
)) < 0) \
|
|
||||||
EXT_INIT_ERROR(module); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define EXT_ADD_STRING(module, name, string) do { \
|
|
||||||
if (PyModule_AddStringConstant(module, name, string) < 0) \
|
|
||||||
EXT_INIT_ERROR(module); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define EXT_ADD_INT(module, name, number) do { \
|
|
||||||
if (PyModule_AddIntConstant(module, name, number) < 0) \
|
|
||||||
EXT_INIT_ERROR(module); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
|
||||||
/* PEP 353 support, implemented as of python 2.5 */
|
|
||||||
#if PY_VERSION_HEX < 0x02050000
|
|
||||||
typedef int Py_ssize_t;
|
|
||||||
#define PyInt_FromSsize_t(arg) PyInt_FromLong((long)arg)
|
|
||||||
#define PyInt_AsSsize_t(arg) (int)PyInt_AsLong(arg)
|
|
||||||
#define PY_SSIZE_T_MAX ((Py_ssize_t)INT_MAX)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* some helper macros (Python 2.4)
|
|
||||||
*/
|
|
||||||
#ifndef Py_VISIT
|
|
||||||
#define Py_VISIT(op) do { \
|
|
||||||
if (op) { \
|
|
||||||
int vret = visit((op), arg); \
|
|
||||||
if (vret) return vret; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef Py_CLEAR
|
|
||||||
#undef Py_CLEAR
|
|
||||||
#endif
|
|
||||||
#define Py_CLEAR(op) do { \
|
|
||||||
if (op) { \
|
|
||||||
PyObject *tmp__ = (PyObject *)(op); \
|
|
||||||
(op) = NULL; \
|
|
||||||
Py_DECREF(tmp__); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifndef Py_RETURN_NONE
|
|
||||||
#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef Py_RETURN_FALSE
|
|
||||||
#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef Py_RETURN_TRUE
|
|
||||||
#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Macros for inline documentation. (Python 2.3) */
|
|
||||||
#ifndef PyDoc_VAR
|
|
||||||
#define PyDoc_VAR(name) static char name[]
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PyDoc_STRVAR
|
|
||||||
#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PyDoc_STR
|
|
||||||
#ifdef WITH_DOC_STRINGS
|
|
||||||
#define PyDoc_STR(str) str
|
|
||||||
#else
|
|
||||||
#define PyDoc_STR(str) ""
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Basestring check (basestring introduced in Python 2.3) */
|
|
||||||
#if PY_VERSION_HEX < 0x02030000
|
|
||||||
#define BaseString_Check(type) ( \
|
|
||||||
PyObject_TypeCheck((type), &PyString_Type) \
|
|
||||||
|| PyObject_TypeCheck((type), &PyUnicode_Type) \
|
|
||||||
)
|
|
||||||
#else
|
|
||||||
#define BaseString_Check(type) PyObject_TypeCheck((type), &PyBaseString_Type)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define GENERIC_ALLOC(type) \
|
|
||||||
((void *)((PyTypeObject *)type)->tp_alloc(type, (Py_ssize_t)0))
|
|
||||||
|
|
||||||
/* PyPy doesn't define it */
|
|
||||||
#ifndef PyType_IS_GC
|
|
||||||
#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DEFINE_GENERIC_DEALLOC(prefix) \
|
|
||||||
static void prefix##_dealloc(void *self) \
|
|
||||||
{ \
|
|
||||||
if (PyType_IS_GC(((PyObject *)self)->ob_type)) \
|
|
||||||
PyObject_GC_UnTrack(self); \
|
|
||||||
(void)prefix##_clear(self); \
|
|
||||||
((PyObject *)self)->ob_type->tp_free((PyObject *)self); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SETUP_CEXT_H */
|
|
@ -1,27 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
================
|
|
||||||
Package _setup
|
|
||||||
================
|
|
||||||
|
|
||||||
This package provides tools for main package setup.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
from _setup.setup import run # pylint: disable = W0611
|
|
@ -1,267 +0,0 @@
|
|||||||
# -*- 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__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
__test__ = False
|
|
||||||
|
|
||||||
from distutils import fancy_getopt as _fancy_getopt
|
|
||||||
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
|
|
||||||
|
|
||||||
from _setup.util import log
|
|
||||||
|
|
||||||
_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 not _option_defaults.has_key(command):
|
|
||||||
_option_defaults[command] = []
|
|
||||||
if inherit is not None:
|
|
||||||
if isinstance(inherit, (str, unicode)):
|
|
||||||
inherit = [inherit]
|
|
||||||
for i_inherit in inherit:
|
|
||||||
add_option(
|
|
||||||
i_inherit, long_name, help_text, short_name, default
|
|
||||||
)
|
|
||||||
default = None
|
|
||||||
if not _option_inherits.has_key(command):
|
|
||||||
_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 not _option_finalizers.has_key(command):
|
|
||||||
_option_finalizers[command] = {}
|
|
||||||
if not _option_finalizers[command].has_key(key):
|
|
||||||
_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 _option_defaults.has_key('install'):
|
|
||||||
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 _option_inherits.has_key('install'):
|
|
||||||
for parent, opt_name in _option_inherits['install']:
|
|
||||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
|
||||||
if _option_finalizers.has_key('install'):
|
|
||||||
for func in _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 _option_defaults.has_key('install_data'):
|
|
||||||
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 _option_inherits.has_key('install_data'):
|
|
||||||
for parent, opt_name in _option_inherits['install_data']:
|
|
||||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
|
||||||
if _option_finalizers.has_key('install_data'):
|
|
||||||
for func in _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 _option_defaults.has_key('install_lib'):
|
|
||||||
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 _option_inherits.has_key('install_lib'):
|
|
||||||
for parent, opt_name in _option_inherits['install_lib']:
|
|
||||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
|
||||||
if _option_finalizers.has_key('install_lib'):
|
|
||||||
for func in _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 _option_defaults.has_key('build_ext'):
|
|
||||||
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 _option_inherits.has_key('build_ext'):
|
|
||||||
for parent, opt_name in _option_inherits['build_ext']:
|
|
||||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
|
||||||
if _option_finalizers.has_key('build_ext'):
|
|
||||||
for func in _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 _option_defaults.has_key('build'):
|
|
||||||
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 _option_inherits.has_key('build'):
|
|
||||||
for parent, opt_name in _option_inherits['build']:
|
|
||||||
self.set_undefined_options(parent, (opt_name, opt_name))
|
|
||||||
if _option_finalizers.has_key('build'):
|
|
||||||
for func in _option_finalizers['build'].values():
|
|
||||||
func(self)
|
|
@ -1,165 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
===================
|
|
||||||
Data distribution
|
|
||||||
===================
|
|
||||||
|
|
||||||
This module provides tools to simplify data distribution.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
from distutils import filelist as _filelist
|
|
||||||
import os as _os
|
|
||||||
import posixpath as _posixpath
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import commands as _commands
|
|
||||||
|
|
||||||
|
|
||||||
def splitpath(path):
|
|
||||||
""" Split a path """
|
|
||||||
drive, path = '', _os.path.normpath(path)
|
|
||||||
try:
|
|
||||||
splitunc = _os.path.splitunc
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
drive, path = splitunc(path)
|
|
||||||
if not drive:
|
|
||||||
drive, path = _os.path.splitdrive(path)
|
|
||||||
elems = []
|
|
||||||
try:
|
|
||||||
sep = _os.path.sep
|
|
||||||
except AttributeError:
|
|
||||||
sep = _os.path.join('1', '2')[1:-1]
|
|
||||||
while 1:
|
|
||||||
prefix, path = _os.path.split(path)
|
|
||||||
elems.append(path)
|
|
||||||
if prefix in ('', sep):
|
|
||||||
drive = _os.path.join(drive, prefix)
|
|
||||||
break
|
|
||||||
path = prefix
|
|
||||||
elems.reverse()
|
|
||||||
return drive, elems
|
|
||||||
|
|
||||||
|
|
||||||
def finalizer(installer):
|
|
||||||
""" Finalize install_data """
|
|
||||||
data_files = []
|
|
||||||
for item in installer.data_files:
|
|
||||||
if not isinstance(item, Data):
|
|
||||||
data_files.append(item)
|
|
||||||
continue
|
|
||||||
data_files.extend(item.flatten(installer))
|
|
||||||
installer.data_files = data_files
|
|
||||||
|
|
||||||
|
|
||||||
class Data(object):
|
|
||||||
""" File list container """
|
|
||||||
|
|
||||||
def __init__(self, files, target=None, preserve=0, strip=0,
|
|
||||||
prefix=None):
|
|
||||||
""" Initialization """
|
|
||||||
self._files = files
|
|
||||||
self._target = target
|
|
||||||
self._preserve = preserve
|
|
||||||
self._strip = strip
|
|
||||||
self._prefix = prefix
|
|
||||||
self.fixup_commands()
|
|
||||||
|
|
||||||
def fixup_commands(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def from_templates(cls, *templates, **kwargs):
|
|
||||||
""" Initialize from template """
|
|
||||||
files = _filelist.FileList()
|
|
||||||
for tpl in templates:
|
|
||||||
for line in tpl.split(';'):
|
|
||||||
files.process_template_line(line.strip())
|
|
||||||
files.sort()
|
|
||||||
files.remove_duplicates()
|
|
||||||
result = []
|
|
||||||
for filename in files.files:
|
|
||||||
_, elems = splitpath(filename)
|
|
||||||
if '.svn' in elems or '.git' in elems:
|
|
||||||
continue
|
|
||||||
result.append(filename)
|
|
||||||
return cls(result, **kwargs)
|
|
||||||
from_templates = classmethod(from_templates)
|
|
||||||
|
|
||||||
def flatten(self, installer):
|
|
||||||
""" Flatten the file list to (target, file) tuples """
|
|
||||||
# pylint: disable = W0613
|
|
||||||
if self._prefix:
|
|
||||||
_, prefix = splitpath(self._prefix)
|
|
||||||
telems = prefix
|
|
||||||
else:
|
|
||||||
telems = []
|
|
||||||
|
|
||||||
tmap = {}
|
|
||||||
for fname in self._files:
|
|
||||||
(_, name), target = splitpath(fname), telems
|
|
||||||
if self._preserve:
|
|
||||||
if self._strip:
|
|
||||||
name = name[max(0, min(self._strip, len(name) - 1)):]
|
|
||||||
if len(name) > 1:
|
|
||||||
target = telems + name[:-1]
|
|
||||||
tmap.setdefault(_posixpath.join(*target), []).append(fname)
|
|
||||||
return tmap.items()
|
|
||||||
|
|
||||||
|
|
||||||
class Documentation(Data):
|
|
||||||
""" Documentation container """
|
|
||||||
|
|
||||||
def fixup_commands(self):
|
|
||||||
_commands.add_option('install_data', 'without-docs',
|
|
||||||
help_text='Do not install documentation files',
|
|
||||||
inherit='install',
|
|
||||||
)
|
|
||||||
_commands.add_finalizer('install_data', 'documentation', finalizer)
|
|
||||||
|
|
||||||
def flatten(self, installer):
|
|
||||||
""" Check if docs should be installed at all """
|
|
||||||
if installer.without_docs:
|
|
||||||
return []
|
|
||||||
return Data.flatten(self, installer)
|
|
||||||
|
|
||||||
|
|
||||||
class Manpages(Documentation):
|
|
||||||
""" Manpages container """
|
|
||||||
|
|
||||||
def dispatch(cls, files):
|
|
||||||
""" Automatically dispatch manpages to their target directories """
|
|
||||||
mpmap = {}
|
|
||||||
for manpage in files:
|
|
||||||
normalized = _os.path.normpath(manpage)
|
|
||||||
_, ext = _os.path.splitext(normalized)
|
|
||||||
if ext.startswith(_os.path.extsep):
|
|
||||||
ext = ext[len(_os.path.extsep):]
|
|
||||||
mpmap.setdefault(ext, []).append(manpage)
|
|
||||||
return [cls(manpages, prefix=_posixpath.join(
|
|
||||||
'share', 'man', 'man%s' % section,
|
|
||||||
)) for section, manpages in mpmap.items()]
|
|
||||||
dispatch = classmethod(dispatch)
|
|
||||||
|
|
||||||
def flatten(self, installer):
|
|
||||||
""" Check if manpages are suitable """
|
|
||||||
if _sys.platform == 'win32':
|
|
||||||
return []
|
|
||||||
return Documentation.flatten(self, installer)
|
|
@ -1,25 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 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.
|
|
||||||
"""
|
|
||||||
====================
|
|
||||||
Package _setup.dev
|
|
||||||
====================
|
|
||||||
|
|
||||||
Development tools, not distributed.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
@ -1,258 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2006, 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.
|
|
||||||
"""
|
|
||||||
=================================
|
|
||||||
Support for code analysis tools
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Support for code analysis tools.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import re as _re
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import term as _term
|
|
||||||
from _setup import shell as _shell
|
|
||||||
|
|
||||||
|
|
||||||
class NotFinished(Exception):
|
|
||||||
""" Exception used for message passing in the stream filter """
|
|
||||||
|
|
||||||
class NotParseable(Exception):
|
|
||||||
""" Exception used for message passing in the stream filter """
|
|
||||||
|
|
||||||
class SpecialMessage(Exception):
|
|
||||||
""" Exception used for message passing in the stream filter """
|
|
||||||
|
|
||||||
|
|
||||||
class FilterStream(object):
|
|
||||||
""" Stream filter """
|
|
||||||
_LINERE = _re.compile(r'''
|
|
||||||
(?P<name>[^:]+)
|
|
||||||
:
|
|
||||||
(?P<lineno>\d+)
|
|
||||||
:\s+
|
|
||||||
\[(?P<mid>[^\],]+)(?:,\s+(?P<func>[^\]]+))?\]
|
|
||||||
\s+
|
|
||||||
(?P<desc>.*)
|
|
||||||
''', _re.X)
|
|
||||||
_SIMRE = _re.compile(r'in (?P<number>\d+) files')
|
|
||||||
_CYCRE = _re.compile(r'\((?P<cycle>[^)]+)\)')
|
|
||||||
|
|
||||||
def __init__(self, term, stream=_sys.stdout):
|
|
||||||
self.written = False
|
|
||||||
self._stream = stream
|
|
||||||
self._lastname = None
|
|
||||||
self._cycled = False
|
|
||||||
self._term = dict(term)
|
|
||||||
self._buffer = ''
|
|
||||||
|
|
||||||
def write(self, towrite):
|
|
||||||
""" Stream write function """
|
|
||||||
self._buffer += towrite
|
|
||||||
term = self._term
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
name, lineno, mid, func, desc = self._parse()
|
|
||||||
except NotFinished:
|
|
||||||
break
|
|
||||||
except SpecialMessage, e:
|
|
||||||
self._dospecial(e)
|
|
||||||
continue
|
|
||||||
except NotParseable, e:
|
|
||||||
self._print_literal(str(e.args[0]))
|
|
||||||
continue
|
|
||||||
|
|
||||||
if name != self._lastname:
|
|
||||||
if self._lastname is not None:
|
|
||||||
self._stream.write("\n")
|
|
||||||
term['path'] = name
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s>>> %(path)s%(NORMAL)s\n" % term
|
|
||||||
)
|
|
||||||
self._lastname = name
|
|
||||||
self.written = True
|
|
||||||
|
|
||||||
term['mid'] = mid
|
|
||||||
if mid.startswith('E') or mid.startswith('F'):
|
|
||||||
self._stream.write("%(BOLD)s%(RED)s%(mid)s%(NORMAL)s" % term)
|
|
||||||
elif mid == 'W0511':
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s%(GREEN)s%(mid)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
|
|
||||||
if int(lineno) != 0:
|
|
||||||
term['lineno'] = lineno
|
|
||||||
self._stream.write(" (%(lineno)s" % term)
|
|
||||||
if func:
|
|
||||||
term['func'] = func
|
|
||||||
self._stream.write(
|
|
||||||
", %(BOLD)s%(YELLOW)s%(func)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
self._stream.write(')')
|
|
||||||
|
|
||||||
self._stream.write(": %s\n" % desc)
|
|
||||||
self._stream.flush()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def _print_literal(self, line):
|
|
||||||
""" Print literal """
|
|
||||||
suppress = (
|
|
||||||
line.startswith('Unable to get imported names for ') or
|
|
||||||
line.startswith("Exception exceptions.RuntimeError: 'generator "
|
|
||||||
"ignored GeneratorExit' in <generator object at") or
|
|
||||||
line.startswith("Exception RuntimeError: 'generator "
|
|
||||||
"ignored GeneratorExit' in <generator object") or
|
|
||||||
not line.strip()
|
|
||||||
)
|
|
||||||
if not suppress:
|
|
||||||
self._stream.write("%s\n" % line)
|
|
||||||
self._stream.flush()
|
|
||||||
self.written = True
|
|
||||||
|
|
||||||
def _dospecial(self, e):
|
|
||||||
""" Deal with special messages """
|
|
||||||
if e.args[0] == 'R0401':
|
|
||||||
pos = self._buffer.find('\n')
|
|
||||||
line, self._buffer = (
|
|
||||||
self._buffer[:pos + 1], self._buffer[pos + 1:]
|
|
||||||
)
|
|
||||||
term = self._term
|
|
||||||
term['mid'] = e.args[0]
|
|
||||||
if not self._cycled:
|
|
||||||
self._cycled = True
|
|
||||||
self._stream.write('\n')
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
self._stream.write(": Cyclic imports\n")
|
|
||||||
match = self._CYCRE.search(e.args[1])
|
|
||||||
term['cycle'] = match.group('cycle')
|
|
||||||
self._stream.write("%(BOLD)s@@@ %(NORMAL)s%(cycle)s\n" % term)
|
|
||||||
self._stream.flush()
|
|
||||||
self.written = True
|
|
||||||
|
|
||||||
elif e.args[0] == 'R0801':
|
|
||||||
match = self._SIMRE.search(e.args[1])
|
|
||||||
if not match:
|
|
||||||
raise AssertionError(
|
|
||||||
'Could not determine number of similar files'
|
|
||||||
)
|
|
||||||
|
|
||||||
numfiles = int(match.group('number'))
|
|
||||||
pos = -1
|
|
||||||
for _ in range(numfiles + 1):
|
|
||||||
pos = self._buffer.find('\n', pos + 1)
|
|
||||||
if pos >= 0:
|
|
||||||
lines = self._buffer[:pos + 1]
|
|
||||||
self._buffer = self._buffer[pos + 1:]
|
|
||||||
term = self._term
|
|
||||||
|
|
||||||
self._stream.write("\n")
|
|
||||||
for name in lines.splitlines()[1:]:
|
|
||||||
name = name.rstrip()[2:]
|
|
||||||
term['path'] = name
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s=== %(path)s%(NORMAL)s\n" % term
|
|
||||||
)
|
|
||||||
self._lastname = name
|
|
||||||
|
|
||||||
term['mid'] = e.args[0]
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
self._stream.write(": %s\n" % e.args[1])
|
|
||||||
self._stream.flush()
|
|
||||||
self.written = True
|
|
||||||
|
|
||||||
def _parse(self):
|
|
||||||
""" Parse output """
|
|
||||||
if '\n' not in self._buffer:
|
|
||||||
raise NotFinished()
|
|
||||||
|
|
||||||
line = self._buffer[:self._buffer.find('\n') + 1]
|
|
||||||
self._buffer = self._buffer[len(line):]
|
|
||||||
line = line.rstrip()
|
|
||||||
match = self._LINERE.match(line)
|
|
||||||
if not match:
|
|
||||||
raise NotParseable(line)
|
|
||||||
|
|
||||||
mid = match.group('mid')
|
|
||||||
if mid in ('R0801', 'R0401'):
|
|
||||||
self._buffer = "%s\n%s" % (line, self._buffer)
|
|
||||||
raise SpecialMessage(mid, match.group('desc'))
|
|
||||||
|
|
||||||
return match.group('name', 'lineno', 'mid', 'func', 'desc')
|
|
||||||
|
|
||||||
|
|
||||||
def run(config, *args):
|
|
||||||
""" Run pylint """
|
|
||||||
try:
|
|
||||||
from pylint import lint
|
|
||||||
from pylint.reporters import text
|
|
||||||
except ImportError:
|
|
||||||
return 2
|
|
||||||
|
|
||||||
if config is None:
|
|
||||||
config = _shell.native('pylint.conf')
|
|
||||||
argv = ['--rcfile', config,
|
|
||||||
'--reports', 'no',
|
|
||||||
'--output-format', 'parseable',
|
|
||||||
'--include-ids', 'yes'
|
|
||||||
]
|
|
||||||
|
|
||||||
stream = FilterStream(_term.terminfo())
|
|
||||||
|
|
||||||
old_stderr = _sys.stderr
|
|
||||||
try:
|
|
||||||
# pylint: disable = E1101
|
|
||||||
_sys.stderr = stream
|
|
||||||
from pylint import __pkginfo__
|
|
||||||
if __pkginfo__.numversion < (0, 13):
|
|
||||||
# The lint tool is not very user friendly, so we need a hack here.
|
|
||||||
lint.REPORTER_OPT_MAP['parseable'] = \
|
|
||||||
lambda: text.TextReporter2(stream)
|
|
||||||
reporter = text.TextReporter2(stream)
|
|
||||||
else:
|
|
||||||
reporter = text.ParseableTextReporter(stream)
|
|
||||||
lint.REPORTER_OPT_MAP['parseable'] = lambda: reporter
|
|
||||||
|
|
||||||
for path in args:
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
lint.Run(argv + [path], reporter=reporter)
|
|
||||||
except SystemExit:
|
|
||||||
pass # don't accept the exit. strange errors happen...
|
|
||||||
|
|
||||||
if stream.written:
|
|
||||||
print
|
|
||||||
stream.written = False
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print
|
|
||||||
raise
|
|
||||||
finally:
|
|
||||||
_sys.stderr = old_stderr
|
|
||||||
|
|
||||||
return 0
|
|
@ -1,31 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2006, 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.
|
|
||||||
"""
|
|
||||||
=================================
|
|
||||||
Support for code analysis tools
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Support for code analysis tools.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
|
|
||||||
def pylint(config, *args):
|
|
||||||
""" Run pylint """
|
|
||||||
from _setup.dev import _pylint
|
|
||||||
return _pylint.run(config, *args)
|
|
@ -1,131 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
==================
|
|
||||||
API doc builders
|
|
||||||
==================
|
|
||||||
|
|
||||||
API doc builders.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
import re as _re
|
|
||||||
|
|
||||||
from _setup import shell as _shell
|
|
||||||
from _setup import term as _term
|
|
||||||
from _setup import util as _util
|
|
||||||
|
|
||||||
|
|
||||||
def _cleanup_epydoc(target):
|
|
||||||
"""
|
|
||||||
Cleanup epydoc generated files
|
|
||||||
|
|
||||||
This removes the epydoc-footer. It changes every release because of the
|
|
||||||
timestamp. That creates bad diffs (accidently it's also invalid html).
|
|
||||||
"""
|
|
||||||
search = _re.compile(r'<table[^<>]+width="100%%"').search
|
|
||||||
for filename in _shell.files(target, '*.html'):
|
|
||||||
fp = open(filename, 'r')
|
|
||||||
try:
|
|
||||||
html = fp.read()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
match = search(html)
|
|
||||||
if match:
|
|
||||||
start = match.start()
|
|
||||||
end = html.find('</table>', start)
|
|
||||||
if end >= 0:
|
|
||||||
end += len('</table>') + 1
|
|
||||||
html = html[:start] + html[end:]
|
|
||||||
fp = open(filename, 'w')
|
|
||||||
try:
|
|
||||||
fp.write(html)
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
|
|
||||||
_VERSION_SEARCH = _re.compile(
|
|
||||||
r'\bversion\s+(?P<major>\d+)\.(?P<minor>\d+)'
|
|
||||||
).search
|
|
||||||
def epydoc(**kwargs):
|
|
||||||
""" Run epydoc """
|
|
||||||
# pylint: disable = R0912
|
|
||||||
prog = kwargs.get('epydoc') or 'epydoc'
|
|
||||||
if not _os.path.dirname(_os.path.normpath(prog)):
|
|
||||||
prog = _shell.frompath(prog)
|
|
||||||
if not prog:
|
|
||||||
_term.red("%(epydoc)s not found",
|
|
||||||
epydoc=kwargs.get('epydoc') or 'epydoc',
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
||||||
version = _VERSION_SEARCH(_shell.spawn(prog, "--version", stdout=True))
|
|
||||||
if version is not None:
|
|
||||||
try:
|
|
||||||
version = tuple(map(int, version.group('major', 'minor')))
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
version = None
|
|
||||||
if version is None:
|
|
||||||
_term.red("%(prog)s version not recognized" % locals())
|
|
||||||
return False
|
|
||||||
|
|
||||||
if version < (3, 0):
|
|
||||||
_term.red("%(prog)s is too old %(version)r < (3, 0)" % locals())
|
|
||||||
return False
|
|
||||||
|
|
||||||
env = dict(_os.environ)
|
|
||||||
|
|
||||||
prepend = kwargs.get('prepend')
|
|
||||||
if prepend:
|
|
||||||
toprepend = _os.pathsep.join(map(str, prepend))
|
|
||||||
if 'PYTHONPATH' in env:
|
|
||||||
env['PYTHONPATH'] = _os.pathsep.join((
|
|
||||||
toprepend, env['PYTHONPATH']
|
|
||||||
))
|
|
||||||
else:
|
|
||||||
env['PYTHONPATH'] = toprepend
|
|
||||||
|
|
||||||
append = kwargs.get('append')
|
|
||||||
if append:
|
|
||||||
toappend = _os.pathsep.join(map(str, append))
|
|
||||||
if 'PYTHONPATH' in env:
|
|
||||||
env['PYTHONPATH'] = _os.pathsep.join((
|
|
||||||
env['PYTHONPATH'], toappend
|
|
||||||
))
|
|
||||||
else:
|
|
||||||
env['PYTHONPATH'] = toappend
|
|
||||||
|
|
||||||
moreenv = kwargs.get('env')
|
|
||||||
if moreenv:
|
|
||||||
env.update(moreenv)
|
|
||||||
|
|
||||||
config = kwargs.get('config') or _shell.native('docs/epydoc.conf')
|
|
||||||
|
|
||||||
argv = [prog, '--config', config]
|
|
||||||
res = not _shell.spawn(*argv, **{'env': env})
|
|
||||||
if res:
|
|
||||||
cfg = _util.SafeConfigParser()
|
|
||||||
cfg.read(config)
|
|
||||||
try:
|
|
||||||
target = dict(cfg.items('epydoc'))['target']
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
_cleanup_epydoc(target)
|
|
||||||
return res
|
|
@ -1,50 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 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.
|
|
||||||
"""
|
|
||||||
===================
|
|
||||||
User doc builders
|
|
||||||
===================
|
|
||||||
|
|
||||||
User doc builders.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
|
|
||||||
from _setup import shell as _shell
|
|
||||||
from _setup import term as _term
|
|
||||||
|
|
||||||
|
|
||||||
def sphinx(**kwargs):
|
|
||||||
""" Run sphinx """
|
|
||||||
prog = _shell.frompath('sphinx-build')
|
|
||||||
if prog is None:
|
|
||||||
_term.red("sphinx-build not found")
|
|
||||||
return False
|
|
||||||
|
|
||||||
env = dict(_os.environ)
|
|
||||||
|
|
||||||
argv = [
|
|
||||||
prog, '-a',
|
|
||||||
'-d', _os.path.join(kwargs['build'], 'doctrees'),
|
|
||||||
'-b', 'html',
|
|
||||||
kwargs['source'],
|
|
||||||
kwargs['target'],
|
|
||||||
]
|
|
||||||
|
|
||||||
return not _shell.spawn(*argv, **{'env': env})
|
|
@ -1,51 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
================
|
|
||||||
dist utilities
|
|
||||||
================
|
|
||||||
|
|
||||||
dist utilities.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import shell as _shell
|
|
||||||
|
|
||||||
|
|
||||||
def run_setup(*args, **kwargs):
|
|
||||||
""" Run setup """
|
|
||||||
if 'setup' in kwargs:
|
|
||||||
script = kwargs.get('setup') or 'setup.py'
|
|
||||||
del kwargs['setup']
|
|
||||||
else:
|
|
||||||
script = 'setup.py'
|
|
||||||
if 'fakeroot' in kwargs:
|
|
||||||
fakeroot = kwargs['fakeroot']
|
|
||||||
del kwargs['fakeroot']
|
|
||||||
else:
|
|
||||||
fakeroot = None
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError("Unrecognized keyword parameters")
|
|
||||||
|
|
||||||
script = _shell.native(script)
|
|
||||||
argv = [_sys.executable, script] + list(args)
|
|
||||||
if fakeroot:
|
|
||||||
argv.insert(0, fakeroot)
|
|
||||||
return not _shell.spawn(*argv)
|
|
@ -1,254 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
===================
|
|
||||||
C extension tools
|
|
||||||
===================
|
|
||||||
|
|
||||||
C extension tools.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
__test__ = False
|
|
||||||
|
|
||||||
from distutils import core as _core
|
|
||||||
from distutils import errors as _distutils_errors
|
|
||||||
import os as _os
|
|
||||||
import posixpath as _posixpath
|
|
||||||
import shutil as _shutil
|
|
||||||
import tempfile as _tempfile
|
|
||||||
|
|
||||||
from _setup import commands as _commands
|
|
||||||
from _setup.util import log
|
|
||||||
|
|
||||||
|
|
||||||
def _install_finalizer(installer):
|
|
||||||
if installer.without_c_extensions:
|
|
||||||
installer.distribution.ext_modules = []
|
|
||||||
|
|
||||||
def _build_finalizer(builder):
|
|
||||||
if builder.without_c_extensions:
|
|
||||||
builder.extensions = []
|
|
||||||
|
|
||||||
|
|
||||||
class Extension(_core.Extension):
|
|
||||||
"""
|
|
||||||
Extension with prerequisite check interface
|
|
||||||
|
|
||||||
If your check is cacheable (during the setup run), override
|
|
||||||
`cached_check_prerequisites`, `check_prerequisites` otherwise.
|
|
||||||
|
|
||||||
:IVariables:
|
|
||||||
`cached_check` : ``bool``
|
|
||||||
The cached check result
|
|
||||||
"""
|
|
||||||
cached_check = None
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
""" Initialization """
|
|
||||||
if kwargs.has_key('depends'):
|
|
||||||
self.depends = kwargs['depends'] or []
|
|
||||||
else:
|
|
||||||
self.depends = []
|
|
||||||
_core.Extension.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
# add include path
|
|
||||||
included = _posixpath.join('_setup', 'include')
|
|
||||||
if included not in self.include_dirs:
|
|
||||||
self.include_dirs.append(included)
|
|
||||||
|
|
||||||
# add cext.h to the dependencies
|
|
||||||
cext_h = _posixpath.join(included, 'cext.h')
|
|
||||||
if cext_h not in self.depends:
|
|
||||||
self.depends.append(cext_h)
|
|
||||||
|
|
||||||
_commands.add_option('install_lib', 'without-c-extensions',
|
|
||||||
help_text='Don\'t install C extensions',
|
|
||||||
inherit='install',
|
|
||||||
)
|
|
||||||
_commands.add_finalizer('install_lib', 'c-extensions',
|
|
||||||
_install_finalizer
|
|
||||||
)
|
|
||||||
_commands.add_option('build_ext', 'without-c-extensions',
|
|
||||||
help_text='Don\'t build C extensions',
|
|
||||||
inherit=('build', 'install_lib'),
|
|
||||||
)
|
|
||||||
_commands.add_finalizer('build_ext', 'c-extensions', _build_finalizer)
|
|
||||||
|
|
||||||
def check_prerequisites(self, build):
|
|
||||||
"""
|
|
||||||
Check prerequisites
|
|
||||||
|
|
||||||
The check should cover all dependencies needed for the extension to
|
|
||||||
be built and run. The method can do the following:
|
|
||||||
|
|
||||||
- return a false value: the extension will be built
|
|
||||||
- return a true value: the extension will be skipped. This is useful
|
|
||||||
for optional extensions
|
|
||||||
- raise an exception. This is useful for mandatory extensions
|
|
||||||
|
|
||||||
If the check result is cacheable (during the setup run), override
|
|
||||||
`cached_check_prerequisites` instead.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`build` : `BuildExt`
|
|
||||||
The extension builder
|
|
||||||
|
|
||||||
:Return: Skip the extension?
|
|
||||||
:Rtype: ``bool``
|
|
||||||
"""
|
|
||||||
if self.cached_check is None:
|
|
||||||
log.debug("PREREQ check for %s" % self.name)
|
|
||||||
self.cached_check = self.cached_check_prerequisites(build)
|
|
||||||
else:
|
|
||||||
log.debug("PREREQ check for %s (cached)" % self.name)
|
|
||||||
return self.cached_check
|
|
||||||
|
|
||||||
def cached_check_prerequisites(self, build):
|
|
||||||
"""
|
|
||||||
Check prerequisites
|
|
||||||
|
|
||||||
The check should cover all dependencies needed for the extension to
|
|
||||||
be built and run. The method can do the following:
|
|
||||||
|
|
||||||
- return a false value: the extension will be built
|
|
||||||
- return a true value: the extension will be skipped. This is useful
|
|
||||||
for optional extensions
|
|
||||||
- raise an exception. This is useful for mandatory extensions
|
|
||||||
|
|
||||||
If the check result is *not* cacheable (during the setup run),
|
|
||||||
override `check_prerequisites` instead.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`build` : `BuildExt`
|
|
||||||
The extension builder
|
|
||||||
|
|
||||||
:Return: Skip the extension?
|
|
||||||
:Rtype: ``bool``
|
|
||||||
"""
|
|
||||||
# pylint: disable = W0613
|
|
||||||
log.debug("Nothing to check for %s!" % self.name)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class ConfTest(object):
|
|
||||||
"""
|
|
||||||
Single conftest abstraction
|
|
||||||
|
|
||||||
:IVariables:
|
|
||||||
`_tempdir` : ``str``
|
|
||||||
The tempdir created for this test
|
|
||||||
|
|
||||||
`src` : ``str``
|
|
||||||
Name of the source file
|
|
||||||
|
|
||||||
`target` : ``str``
|
|
||||||
Target filename
|
|
||||||
|
|
||||||
`compiler` : ``CCompiler``
|
|
||||||
compiler instance
|
|
||||||
|
|
||||||
`obj` : ``list``
|
|
||||||
List of object filenames (``[str, ...]``)
|
|
||||||
"""
|
|
||||||
_tempdir = None
|
|
||||||
|
|
||||||
def __init__(self, build, source):
|
|
||||||
"""
|
|
||||||
Initialization
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`build` : ``distuils.command.build_ext.build_ext``
|
|
||||||
builder instance
|
|
||||||
|
|
||||||
`source` : ``str``
|
|
||||||
Source of the file to compile
|
|
||||||
"""
|
|
||||||
self._tempdir = tempdir = _tempfile.mkdtemp()
|
|
||||||
src = _os.path.join(tempdir, 'conftest.c')
|
|
||||||
fp = open(src, 'w')
|
|
||||||
try:
|
|
||||||
fp.write(source)
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
self.src = src
|
|
||||||
self.compiler = compiler = build.compiler
|
|
||||||
self.target = _os.path.join(tempdir, 'conftest')
|
|
||||||
self.obj = compiler.object_filenames([src], output_dir=tempdir)
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
""" Destruction """
|
|
||||||
self.destroy()
|
|
||||||
|
|
||||||
def destroy(self):
|
|
||||||
""" Destroy the conftest leftovers on disk """
|
|
||||||
tempdir, self._tempdir = self._tempdir, None
|
|
||||||
if tempdir is not None:
|
|
||||||
_shutil.rmtree(tempdir)
|
|
||||||
|
|
||||||
def compile(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Compile the conftest
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`kwargs` : ``dict``
|
|
||||||
Optional keyword parameters for the compiler call
|
|
||||||
|
|
||||||
:Return: Was the compilation successful?
|
|
||||||
:Rtype: ``bool``
|
|
||||||
"""
|
|
||||||
kwargs['output_dir'] = self._tempdir
|
|
||||||
try:
|
|
||||||
self.compiler.compile([self.src], **kwargs)
|
|
||||||
except _distutils_errors.CompileError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def link(self, **kwargs):
|
|
||||||
r"""
|
|
||||||
Link the conftest
|
|
||||||
|
|
||||||
Before you can link the conftest objects they need to be `compile`\d.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`kwargs` : ``dict``
|
|
||||||
Optional keyword parameters for the linker call
|
|
||||||
|
|
||||||
:Return: Was the linking successful?
|
|
||||||
:Rtype: ``bool``
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
self.compiler.link_executable(self.obj, self.target, **kwargs)
|
|
||||||
except _distutils_errors.LinkError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def pipe(self, mode="r"):
|
|
||||||
r"""
|
|
||||||
Execute the conftest binary and connect to it using a pipe
|
|
||||||
|
|
||||||
Before you can pipe to or from the conftest binary it needs to
|
|
||||||
be `link`\ed.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`mode` : ``str``
|
|
||||||
Pipe mode - r/w
|
|
||||||
|
|
||||||
:Return: The open pipe
|
|
||||||
:Rtype: ``file``
|
|
||||||
"""
|
|
||||||
return _os.popen(self.compiler.executable_filename(self.target), mode)
|
|
@ -1,28 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 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.
|
|
||||||
"""
|
|
||||||
=====================
|
|
||||||
Package _setup.make
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Make tools, not distributed.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
# pylint: disable = W0611
|
|
||||||
from _setup.make._make import main, fail, warn, fatal, Target
|
|
@ -1,338 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
==================
|
|
||||||
Simple make base
|
|
||||||
==================
|
|
||||||
|
|
||||||
Simple make base.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import term as _term
|
|
||||||
|
|
||||||
|
|
||||||
class Failure(SystemExit):
|
|
||||||
""" Failure exception """
|
|
||||||
|
|
||||||
|
|
||||||
def fail(reason):
|
|
||||||
""" Fail for a reason """
|
|
||||||
raise Failure(reason)
|
|
||||||
|
|
||||||
|
|
||||||
def warn(message, name=None):
|
|
||||||
""" Warn """
|
|
||||||
_term.red("%(NAME)sWarning: %(msg)s",
|
|
||||||
NAME=name and "%s:" % name or '', msg=message
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def fatal(reason):
|
|
||||||
""" Fatal error, immediate stop """
|
|
||||||
print >> _sys.stderr, reason
|
|
||||||
_sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
class Target(object):
|
|
||||||
""" Target base class """
|
|
||||||
NAME = None
|
|
||||||
DEPS = None
|
|
||||||
HIDDEN = False
|
|
||||||
|
|
||||||
ERROR = None
|
|
||||||
|
|
||||||
def __init__(self, runner):
|
|
||||||
""" Base __init__ """
|
|
||||||
self.runner = runner
|
|
||||||
self.init()
|
|
||||||
|
|
||||||
def init(self):
|
|
||||||
""" Default init hook """
|
|
||||||
pass
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
""" Default run hook """
|
|
||||||
pass
|
|
||||||
|
|
||||||
def clean(self, scm=True, dist=False):
|
|
||||||
""" Default clean hook """
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class _Runner(object):
|
|
||||||
""" Runner """
|
|
||||||
|
|
||||||
def __init__(self, *targetscollection):
|
|
||||||
""" Initialization """
|
|
||||||
tdict = {}
|
|
||||||
if not targetscollection:
|
|
||||||
import __main__
|
|
||||||
targetscollection = [__main__]
|
|
||||||
|
|
||||||
from _setup.make import default_targets
|
|
||||||
if default_targets not in targetscollection:
|
|
||||||
targetscollection.append(default_targets)
|
|
||||||
|
|
||||||
for targets in targetscollection:
|
|
||||||
for value in vars(targets).values():
|
|
||||||
if isinstance(value, type) and issubclass(value, Target) and \
|
|
||||||
value.NAME is not None:
|
|
||||||
if value.NAME in tdict:
|
|
||||||
if issubclass(value, tdict[value.NAME]):
|
|
||||||
pass # override base target
|
|
||||||
elif issubclass(tdict[value.NAME], value):
|
|
||||||
continue # found base later. ignore
|
|
||||||
else:
|
|
||||||
warn('Ambiguous target name', value.NAME)
|
|
||||||
continue
|
|
||||||
tdict[value.NAME] = value
|
|
||||||
self._tdict = tdict
|
|
||||||
self._itdict = {}
|
|
||||||
|
|
||||||
def print_help(self):
|
|
||||||
""" Print make help """
|
|
||||||
import textwrap as _textwrap
|
|
||||||
|
|
||||||
targets = self.targetinfo()
|
|
||||||
keys = []
|
|
||||||
for key, info in targets.items():
|
|
||||||
if not info['hide']:
|
|
||||||
keys.append(key)
|
|
||||||
keys.sort()
|
|
||||||
length = max(map(len, keys))
|
|
||||||
info = []
|
|
||||||
for key in keys:
|
|
||||||
info.append("%s%s" % (
|
|
||||||
(key + " " * length)[:length + 2],
|
|
||||||
_textwrap.fill(
|
|
||||||
targets[key]['desc'].strip(),
|
|
||||||
subsequent_indent=" " * (length + 2)
|
|
||||||
),
|
|
||||||
))
|
|
||||||
print "Available targets:\n\n" + "\n".join(info)
|
|
||||||
|
|
||||||
def targetinfo(self):
|
|
||||||
""" Extract target information """
|
|
||||||
result = {}
|
|
||||||
for name, cls in self._tdict.items():
|
|
||||||
result[name] = {
|
|
||||||
'desc': cls.__doc__ or "no description",
|
|
||||||
'hide': cls.HIDDEN,
|
|
||||||
'deps': cls.DEPS or (),
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _topleveltargets(self):
|
|
||||||
""" Find all top level targets """
|
|
||||||
rev = {} # key is a dep of [values]
|
|
||||||
all_ = self.targetinfo()
|
|
||||||
for target, info in all_.items():
|
|
||||||
for dep in info['deps']:
|
|
||||||
if dep not in all_:
|
|
||||||
fatal("Unknown target '%s' (dep of %s) -> exit" % (
|
|
||||||
dep, target
|
|
||||||
))
|
|
||||||
rev.setdefault(dep, []).append(target)
|
|
||||||
return [target for target, info in rev.items() if not info]
|
|
||||||
|
|
||||||
def _run(self, target, seen=None):
|
|
||||||
""" Run a target """
|
|
||||||
if target.DEPS:
|
|
||||||
self(*target.DEPS, **{'seen': seen})
|
|
||||||
|
|
||||||
if not target.HIDDEN:
|
|
||||||
_term.yellow(">>> %(name)s", name=target.NAME)
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = target.run()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
result, target.ERROR = False, "^C -> exit"
|
|
||||||
except Failure, e:
|
|
||||||
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
|
|
||||||
except (SystemExit, MemoryError):
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
import traceback
|
|
||||||
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
|
|
||||||
traceback.format_exception(*_sys.exc_info())
|
|
||||||
))
|
|
||||||
result = False
|
|
||||||
else:
|
|
||||||
if result is None:
|
|
||||||
result = True
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _clean(self, target, scm, dist, seen=None):
|
|
||||||
""" Run a target """
|
|
||||||
if target.DEPS:
|
|
||||||
self.run_clean(
|
|
||||||
*target.DEPS, **{'scm': scm, 'dist': dist, 'seen': seen}
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = target.clean(scm, dist)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
result, target.ERROR = False, "^C -> exit"
|
|
||||||
except Failure, e:
|
|
||||||
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
|
|
||||||
except (SystemExit, MemoryError):
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
import traceback
|
|
||||||
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
|
|
||||||
traceback.format_exception(*_sys.exc_info())
|
|
||||||
))
|
|
||||||
result = False
|
|
||||||
else:
|
|
||||||
if result is None:
|
|
||||||
result = True
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _make_init(self, seen):
|
|
||||||
""" Make init mapper """
|
|
||||||
def init(target):
|
|
||||||
""" Return initialized target """
|
|
||||||
if target not in seen:
|
|
||||||
try:
|
|
||||||
seen[target] = self._tdict[target](self)
|
|
||||||
except KeyError:
|
|
||||||
fatal("Unknown target '%s' -> exit" % target)
|
|
||||||
else:
|
|
||||||
seen[target] = None
|
|
||||||
return seen[target]
|
|
||||||
return init
|
|
||||||
|
|
||||||
def run_clean(self, *targets, **kwargs):
|
|
||||||
""" Run targets """
|
|
||||||
def pop(name, default=None):
|
|
||||||
""" Pop """
|
|
||||||
if name in kwargs:
|
|
||||||
value = kwargs[name]
|
|
||||||
del kwargs[name]
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
return value
|
|
||||||
else:
|
|
||||||
return default
|
|
||||||
seen = pop('seen', {})
|
|
||||||
scm = pop('scm', True)
|
|
||||||
dist = pop('dist', False)
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError('Unknown keyword parameters')
|
|
||||||
|
|
||||||
if not targets:
|
|
||||||
top_targets = self._topleveltargets()
|
|
||||||
targets = self.targetinfo()
|
|
||||||
for item in top_targets:
|
|
||||||
del targets[item]
|
|
||||||
targets = targets.keys()
|
|
||||||
targets.sort()
|
|
||||||
top_targets.sort()
|
|
||||||
targets = top_targets + targets
|
|
||||||
|
|
||||||
init = self._make_init(seen)
|
|
||||||
for name in targets:
|
|
||||||
target = init(name)
|
|
||||||
if target is not None:
|
|
||||||
if not self._clean(target, scm=scm, dist=dist, seen=seen):
|
|
||||||
msg = target.ERROR
|
|
||||||
if msg is None:
|
|
||||||
msg = "Clean target %s returned error -> exit" % name
|
|
||||||
fatal(msg)
|
|
||||||
|
|
||||||
def __call__(self, *targets, **kwargs):
|
|
||||||
""" Run targets """
|
|
||||||
if 'seen' in kwargs:
|
|
||||||
seen = kwargs['seen']
|
|
||||||
del kwargs['seen']
|
|
||||||
else:
|
|
||||||
seen = None
|
|
||||||
if seen is None:
|
|
||||||
seen = self._itdict
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError('Unknown keyword parameters')
|
|
||||||
|
|
||||||
init = self._make_init(seen)
|
|
||||||
for name in targets:
|
|
||||||
target = init(name)
|
|
||||||
if target is not None:
|
|
||||||
if not self._run(target, seen):
|
|
||||||
msg = target.ERROR
|
|
||||||
if msg is None:
|
|
||||||
msg = "Target %s returned error -> exit" % name
|
|
||||||
fatal(msg)
|
|
||||||
|
|
||||||
|
|
||||||
def main(*args, **kwargs):
|
|
||||||
"""
|
|
||||||
main(argv=None, *args, name=None)
|
|
||||||
|
|
||||||
Main start point. This function parses the command line and executes the
|
|
||||||
targets given through `argv`. If there are no targets given, a help output
|
|
||||||
is generated.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`argv` : sequence
|
|
||||||
Command line arguments. If omitted or ``None``, they are picked from
|
|
||||||
``sys.argv``.
|
|
||||||
|
|
||||||
`args` : ``tuple``
|
|
||||||
The list of modules with targets. If omitted, ``__main__``
|
|
||||||
is imported and treated as target module. Additionally the mechanism
|
|
||||||
always adds the `_setup.make` module (this one) to the list in order
|
|
||||||
to grab some default targets.
|
|
||||||
|
|
||||||
`name` : ``str``
|
|
||||||
Name of the executing module. If omitted or ``None``, ``'__main__'``
|
|
||||||
is assumed. If the final name is not ``'__main__'``, the function
|
|
||||||
returns immediately.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
name = kwargs['name']
|
|
||||||
except KeyError:
|
|
||||||
name = '__main__'
|
|
||||||
else:
|
|
||||||
del kwargs['name']
|
|
||||||
if name is None:
|
|
||||||
name = '__main__'
|
|
||||||
|
|
||||||
try:
|
|
||||||
argv = kwargs['argv']
|
|
||||||
except KeyError:
|
|
||||||
if not args:
|
|
||||||
args = (None,)
|
|
||||||
else:
|
|
||||||
del kwargs['argv']
|
|
||||||
args = (argv,) + args
|
|
||||||
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError("Unrecognized keyword arguments for main()")
|
|
||||||
|
|
||||||
if name == '__main__':
|
|
||||||
argv, args = args[0], args[1:]
|
|
||||||
if argv is None:
|
|
||||||
argv = _sys.argv[1:]
|
|
||||||
|
|
||||||
runner = _Runner(*args)
|
|
||||||
if argv:
|
|
||||||
runner(*argv)
|
|
||||||
else:
|
|
||||||
runner.print_help()
|
|
@ -1,110 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
==================
|
|
||||||
Simple make base
|
|
||||||
==================
|
|
||||||
|
|
||||||
Simple make base.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import make as _make
|
|
||||||
from _setup import shell as _shell
|
|
||||||
|
|
||||||
|
|
||||||
class MakefileTarget(_make.Target):
|
|
||||||
""" Create a make file """
|
|
||||||
NAME = 'makefile'
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
def escape(value):
|
|
||||||
""" Escape for make and shell """
|
|
||||||
return '"%s"' % value.replace(
|
|
||||||
'\\', '\\\\').replace(
|
|
||||||
'"', '\\"').replace(
|
|
||||||
'$', '\\$$')
|
|
||||||
def decorate(line, prefix='# ', width=78, char='~', padding=' '):
|
|
||||||
""" Decorate a line """
|
|
||||||
line = line.center(width - len(prefix))
|
|
||||||
return '%s%s%s%s%s%s' % (
|
|
||||||
prefix,
|
|
||||||
char * (len(line) - len(line.lstrip()) - len(padding)),
|
|
||||||
padding,
|
|
||||||
line.strip(),
|
|
||||||
padding,
|
|
||||||
char * (len(line) - len(line.rstrip()) - len(padding)),
|
|
||||||
)
|
|
||||||
|
|
||||||
python = escape(_sys.executable)
|
|
||||||
script = escape(_sys.argv[0])
|
|
||||||
targets = self.runner.targetinfo()
|
|
||||||
names = []
|
|
||||||
for name, info in targets.items():
|
|
||||||
if not info['hide']:
|
|
||||||
names.append(name)
|
|
||||||
names.sort()
|
|
||||||
|
|
||||||
fp = open(_shell.native('Makefile'), 'w')
|
|
||||||
print >> fp, decorate("Generated Makefile, DO NOT EDIT")
|
|
||||||
print >> fp, decorate("python %s %s" % (
|
|
||||||
_os.path.basename(script), self.NAME
|
|
||||||
))
|
|
||||||
print >> fp
|
|
||||||
print >> fp, "_default_:"
|
|
||||||
print >> fp, "\t@%s %s" % (python, script)
|
|
||||||
for name in names:
|
|
||||||
print >> fp, "\n"
|
|
||||||
print >> fp, "# %s" % \
|
|
||||||
targets[name]['desc'].splitlines()[0].strip()
|
|
||||||
print >> fp, "%s:" % name
|
|
||||||
print >> fp, "\t@%s %s %s" % (python, script, escape(name))
|
|
||||||
print >> fp
|
|
||||||
extension = self.extend(names)
|
|
||||||
if extension is not None:
|
|
||||||
print >> fp, extension
|
|
||||||
print >> fp
|
|
||||||
print >> fp, ".PHONY: _default_ %s\n\n" % ' '.join(names)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
def extend(self, names):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CleanTarget(_make.Target):
|
|
||||||
""" Clean the mess """
|
|
||||||
NAME = 'clean'
|
|
||||||
_scm, _dist = True, False
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.runner.run_clean(scm=self._scm, dist=self._dist)
|
|
||||||
|
|
||||||
|
|
||||||
class DistCleanTarget(CleanTarget):
|
|
||||||
""" Clean as freshly unpacked dist package """
|
|
||||||
NAME = 'distclean'
|
|
||||||
_scm, _dist = False, True
|
|
||||||
|
|
||||||
|
|
||||||
class ExtraCleanTarget(CleanTarget):
|
|
||||||
""" Clean everything """
|
|
||||||
NAME = 'extraclean'
|
|
||||||
_scm, _dist = True, True
|
|
@ -1,324 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2007 - 2013
|
|
||||||
# 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.
|
|
||||||
"""
|
|
||||||
==================
|
|
||||||
Standard targets
|
|
||||||
==================
|
|
||||||
|
|
||||||
Standard targets.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import dist as _dist
|
|
||||||
from _setup import make as _make
|
|
||||||
from _setup import shell as _shell
|
|
||||||
from _setup import term as _term
|
|
||||||
|
|
||||||
|
|
||||||
class Distribution(_make.Target):
|
|
||||||
""" Build a distribution """
|
|
||||||
NAME = "dist"
|
|
||||||
DEPS = ["MANIFEST"]
|
|
||||||
|
|
||||||
_dist, _ebuilds, _changes = None, None, None
|
|
||||||
|
|
||||||
def init(self):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
exts = self.dist_pkg()
|
|
||||||
digests = self.digest_files(exts)
|
|
||||||
self.sign_digests(digests)
|
|
||||||
self.copy_ebuilds()
|
|
||||||
self.copy_changes()
|
|
||||||
|
|
||||||
def dist_pkg(self):
|
|
||||||
_term.green("Building package...")
|
|
||||||
_dist.run_setup("sdist", "--formats", "tar,zip",
|
|
||||||
fakeroot=_shell.frompath('fakeroot')
|
|
||||||
)
|
|
||||||
exts = ['.zip']
|
|
||||||
for name in _shell.files(self._dist, '*.tar', False):
|
|
||||||
exts.extend(self.compress(name))
|
|
||||||
_shell.rm(name)
|
|
||||||
return exts
|
|
||||||
|
|
||||||
def compress(self, filename):
|
|
||||||
""" Compress file """
|
|
||||||
ext = _os.path.splitext(filename)[1]
|
|
||||||
exts = []
|
|
||||||
exts.append('.'.join((ext, self.compress_gzip(filename))))
|
|
||||||
exts.append('.'.join((ext, self.compress_bzip2(filename))))
|
|
||||||
exts.append('.'.join((ext, self.compress_xz(filename))))
|
|
||||||
return exts
|
|
||||||
|
|
||||||
def compress_xz(self, filename):
|
|
||||||
outfilename = filename + '.xz'
|
|
||||||
self.compress_external(filename, outfilename, 'xz', '-c9')
|
|
||||||
return 'xz'
|
|
||||||
|
|
||||||
def compress_bzip2(self, filename):
|
|
||||||
outfilename = filename + '.bz2'
|
|
||||||
try:
|
|
||||||
import bz2 as _bz2
|
|
||||||
except ImportError:
|
|
||||||
self.compress_external(filename, outfilename, 'bzip2', '-c9')
|
|
||||||
else:
|
|
||||||
outfile = _bz2.BZ2File(outfilename, 'w')
|
|
||||||
self.compress_internal(filename, outfile, outfilename)
|
|
||||||
return 'bz2'
|
|
||||||
|
|
||||||
def compress_gzip(self, filename):
|
|
||||||
outfilename = filename + '.gz'
|
|
||||||
try:
|
|
||||||
import gzip as _gzip
|
|
||||||
except ImportError:
|
|
||||||
self.compress_external(filename, outfilename, 'gzip', '-c9')
|
|
||||||
else:
|
|
||||||
outfile = _gzip.GzipFile(filename, 'wb',
|
|
||||||
fileobj=open(outfilename, 'wb')
|
|
||||||
)
|
|
||||||
self.compress_internal(filename, outfile, outfilename)
|
|
||||||
return 'gz'
|
|
||||||
|
|
||||||
def compress_external(self, infile, outfile, *argv):
|
|
||||||
argv = list(argv)
|
|
||||||
argv[0] = _shell.frompath(argv[0])
|
|
||||||
if argv[0] is not None:
|
|
||||||
return not _shell.spawn(*argv, **{
|
|
||||||
'filepipe': True, 'stdin': infile, 'stdout': outfile,
|
|
||||||
})
|
|
||||||
return None
|
|
||||||
|
|
||||||
def compress_internal(self, filename, outfile, outfilename):
|
|
||||||
infile = open(filename, 'rb')
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
while 1:
|
|
||||||
chunk = infile.read(8192)
|
|
||||||
if not chunk:
|
|
||||||
break
|
|
||||||
outfile.write(chunk)
|
|
||||||
outfile.close()
|
|
||||||
except:
|
|
||||||
e = _sys.exc_info()
|
|
||||||
try:
|
|
||||||
_shell.rm(outfilename)
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
raise e[0], e[1], e[2]
|
|
||||||
finally:
|
|
||||||
del e
|
|
||||||
finally:
|
|
||||||
infile.close()
|
|
||||||
|
|
||||||
def digest_files(self, exts):
|
|
||||||
""" digest files """
|
|
||||||
digests = {}
|
|
||||||
digestnames = {}
|
|
||||||
for ext in exts:
|
|
||||||
for name in _shell.files(self._dist, '*' + ext, False):
|
|
||||||
basename = _os.path.basename(name)
|
|
||||||
if basename not in digests:
|
|
||||||
digests[basename] = []
|
|
||||||
digests[basename].extend(self.digest(name))
|
|
||||||
digestname = basename[:-len(ext)]
|
|
||||||
if digestname not in digestnames:
|
|
||||||
digestnames[digestname] = []
|
|
||||||
digestnames[digestname].append(basename)
|
|
||||||
|
|
||||||
result = []
|
|
||||||
for name, basenames in digestnames.items():
|
|
||||||
result.append(_os.path.join(self._dist, name + '.digests'))
|
|
||||||
fp = open(result[-1], 'wb')
|
|
||||||
try:
|
|
||||||
fp.write(
|
|
||||||
'\n# The file may contain MD5, SHA1 and SHA256 digests\n'
|
|
||||||
)
|
|
||||||
fp.write('# Check archive integrity with, e.g. md5sum -c\n')
|
|
||||||
fp.write('# Check digest file integrity with PGP\n\n')
|
|
||||||
basenames.sort()
|
|
||||||
for basename in basenames:
|
|
||||||
for digest in digests[basename]:
|
|
||||||
fp.write("%s *%s\n" % (digest, basename))
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
def digest(self, filename):
|
|
||||||
result = []
|
|
||||||
for method in (self.md5, self.sha1, self.sha256):
|
|
||||||
digest = method(filename)
|
|
||||||
if digest is not None:
|
|
||||||
result.append(digest)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def do_digest(self, hashfunc, name, filename):
|
|
||||||
filename = _shell.native(filename)
|
|
||||||
_term.green("%(digest)s-digesting %(name)s...",
|
|
||||||
digest=name, name=_os.path.basename(filename))
|
|
||||||
fp = open(filename, 'rb')
|
|
||||||
sig = hashfunc()
|
|
||||||
block = fp.read(8192)
|
|
||||||
while block:
|
|
||||||
sig.update(block)
|
|
||||||
block = fp.read(8192)
|
|
||||||
fp.close()
|
|
||||||
return sig.hexdigest()
|
|
||||||
|
|
||||||
param = {'sig': sig.hexdigest(), 'file': _os.path.basename(filename)}
|
|
||||||
fp = open("%s.%s" % (filename, name), "w")
|
|
||||||
fp.write("%(sig)s *%(file)s\n" % param)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def md5(self, filename):
|
|
||||||
try:
|
|
||||||
from hashlib import md5
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from md5 import new as md5
|
|
||||||
except ImportError:
|
|
||||||
_make.warn("md5 not found -> skip md5 digests", self.NAME)
|
|
||||||
return None
|
|
||||||
return self.do_digest(md5, "md5", filename)
|
|
||||||
|
|
||||||
def sha1(self, filename):
|
|
||||||
try:
|
|
||||||
from hashlib import sha1
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from sha import new as sha1
|
|
||||||
except ImportError:
|
|
||||||
_make.warn("sha1 not found -> skip sha1 digests", self.NAME)
|
|
||||||
return None
|
|
||||||
return self.do_digest(sha1, "sha1", filename)
|
|
||||||
|
|
||||||
def sha256(self, filename):
|
|
||||||
try:
|
|
||||||
from hashlib import sha256
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from Crypto.Hash.SHA256 import new as sha256
|
|
||||||
except ImportError:
|
|
||||||
_make.warn(
|
|
||||||
"sha256 not found -> skip sha256 digests", self.NAME
|
|
||||||
)
|
|
||||||
return None
|
|
||||||
return self.do_digest(sha256, "sha256", filename)
|
|
||||||
|
|
||||||
def copy_ebuilds(self):
|
|
||||||
if self._ebuilds is not None:
|
|
||||||
for src in _shell.files(self._ebuilds, '*.ebuild'):
|
|
||||||
_shell.cp(src, self._dist)
|
|
||||||
|
|
||||||
def copy_changes(self):
|
|
||||||
if self._changes is not None:
|
|
||||||
_shell.cp(self._changes, self._dist)
|
|
||||||
|
|
||||||
def sign_digests(self, digests):
|
|
||||||
for digest in digests:
|
|
||||||
self.sign(digest, detach=False)
|
|
||||||
|
|
||||||
def sign(self, filename, detach=True):
|
|
||||||
filename = _shell.native(filename)
|
|
||||||
try:
|
|
||||||
from pyme import core, errors
|
|
||||||
from pyme.constants.sig import mode
|
|
||||||
except ImportError:
|
|
||||||
return self.sign_external(filename, detach=detach)
|
|
||||||
|
|
||||||
_term.green("signing %(name)s...", name=_os.path.basename(filename))
|
|
||||||
sigmode = [mode.CLEAR, mode.DETACH][bool(detach)]
|
|
||||||
fp = core.Data(file=filename)
|
|
||||||
sig = core.Data()
|
|
||||||
try:
|
|
||||||
c = core.Context()
|
|
||||||
except errors.GPGMEError:
|
|
||||||
return self.sign_external(filename, detach=detach)
|
|
||||||
c.set_armor(1)
|
|
||||||
try:
|
|
||||||
c.op_sign(fp, sig, sigmode)
|
|
||||||
except errors.GPGMEError, e:
|
|
||||||
_make.fail(str(e))
|
|
||||||
|
|
||||||
sig.seek(0, 0)
|
|
||||||
if detach:
|
|
||||||
open("%s.asc" % filename, "w").write(sig.read())
|
|
||||||
else:
|
|
||||||
open(filename, "w").write(sig.read())
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def sign_external(self, filename, detach=True):
|
|
||||||
""" Sign calling gpg """
|
|
||||||
gpg = _shell.frompath('gpg')
|
|
||||||
if gpg is None:
|
|
||||||
_make.warn('GPG not found -> cannot sign')
|
|
||||||
return False
|
|
||||||
if detach:
|
|
||||||
_shell.spawn(gpg,
|
|
||||||
'--armor',
|
|
||||||
'--output', filename + '.asc',
|
|
||||||
'--detach-sign',
|
|
||||||
'--',
|
|
||||||
filename,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_shell.spawn(gpg,
|
|
||||||
'--output', filename + '.signed',
|
|
||||||
'--clearsign',
|
|
||||||
'--',
|
|
||||||
filename,
|
|
||||||
)
|
|
||||||
_os.rename(filename + '.signed', filename)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def clean(self, scm, dist):
|
|
||||||
_term.green("Removing dist files...")
|
|
||||||
_shell.rm_rf(self._dist)
|
|
||||||
|
|
||||||
|
|
||||||
class Manifest(_make.Target):
|
|
||||||
""" Create manifest """
|
|
||||||
NAME = "MANIFEST"
|
|
||||||
HIDDEN = True
|
|
||||||
DEPS = ["doc"]
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
_term.green("Creating %(name)s...", name=self.NAME)
|
|
||||||
dest = _shell.native(self.NAME)
|
|
||||||
dest = open(dest, 'w')
|
|
||||||
for name in self.manifest_names():
|
|
||||||
dest.write("%s\n" % name)
|
|
||||||
dest.close()
|
|
||||||
|
|
||||||
def manifest_names(self):
|
|
||||||
import setup
|
|
||||||
for item in setup.manifest():
|
|
||||||
yield item
|
|
||||||
|
|
||||||
def clean(self, scm, dist):
|
|
||||||
""" Clean manifest """
|
|
||||||
if scm:
|
|
||||||
_term.green("Removing MANIFEST")
|
|
||||||
_shell.rm(self.NAME)
|
|
@ -1,419 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2007 - 2013
|
|
||||||
# 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.
|
|
||||||
"""
|
|
||||||
===================
|
|
||||||
Main setup runner
|
|
||||||
===================
|
|
||||||
|
|
||||||
This module provides a wrapper around the distutils core setup.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import ConfigParser as _config_parser
|
|
||||||
from distutils import core as _core
|
|
||||||
import os as _os
|
|
||||||
import posixpath as _posixpath
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import commands as _commands
|
|
||||||
from _setup import data as _data
|
|
||||||
from _setup import ext as _ext
|
|
||||||
from _setup import util as _util
|
|
||||||
from _setup import shell as _shell
|
|
||||||
|
|
||||||
|
|
||||||
def check_python_version(impl, version_min, version_max):
|
|
||||||
""" Check python version """
|
|
||||||
if impl == 'python':
|
|
||||||
version_info = _sys.version_info
|
|
||||||
elif impl == 'pypy':
|
|
||||||
version_info = getattr(_sys, 'pypy_version_info', None)
|
|
||||||
if not version_info:
|
|
||||||
return
|
|
||||||
elif impl == 'jython':
|
|
||||||
if not 'java' in _sys.platform.lower():
|
|
||||||
return
|
|
||||||
version_info = _sys.version_info
|
|
||||||
else:
|
|
||||||
raise AssertionError("impl not in ('python', 'pypy', 'jython')")
|
|
||||||
|
|
||||||
pyversion = map(int, version_info[:3])
|
|
||||||
if version_min:
|
|
||||||
min_required = \
|
|
||||||
map(int, '.'.join((version_min, '0.0.0')).split('.')[:3])
|
|
||||||
if pyversion < min_required:
|
|
||||||
raise EnvironmentError("Need at least %s %s (vs. %s)" % (
|
|
||||||
impl, version_min, '.'.join(map(str, pyversion))
|
|
||||||
))
|
|
||||||
if version_max:
|
|
||||||
max_required = map(int, version_max.split('.'))
|
|
||||||
max_required[-1] += 1
|
|
||||||
if pyversion >= max_required:
|
|
||||||
raise EnvironmentError("Need at max %s %s (vs. %s)" % (
|
|
||||||
impl,
|
|
||||||
version_max,
|
|
||||||
'.'.join(map(str, pyversion))
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
def find_description(docs):
|
|
||||||
"""
|
|
||||||
Determine the package description from DESCRIPTION
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`docs` : ``dict``
|
|
||||||
Docs config section
|
|
||||||
|
|
||||||
:Return: Tuple of summary, description and license
|
|
||||||
(``('summary', 'description', 'license')``)
|
|
||||||
(all may be ``None``)
|
|
||||||
:Rtype: ``tuple``
|
|
||||||
"""
|
|
||||||
summary = None
|
|
||||||
filename = docs.get('meta.summary', 'SUMMARY').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
summary = fp.read().strip().splitlines()[0].rstrip()
|
|
||||||
except IndexError:
|
|
||||||
summary = ''
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
description = None
|
|
||||||
filename = docs.get('meta.description', 'DESCRIPTION').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
description = fp.read().rstrip()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
if summary is None and description:
|
|
||||||
from docutils import core
|
|
||||||
summary = core.publish_parts(
|
|
||||||
source=description,
|
|
||||||
source_path=filename,
|
|
||||||
writer_name='html',
|
|
||||||
)['title'].encode('utf-8')
|
|
||||||
|
|
||||||
return summary, description
|
|
||||||
|
|
||||||
|
|
||||||
def find_classifiers(docs):
|
|
||||||
"""
|
|
||||||
Determine classifiers from CLASSIFIERS
|
|
||||||
|
|
||||||
:return: List of classifiers (``['classifier', ...]``)
|
|
||||||
:rtype: ``list``
|
|
||||||
"""
|
|
||||||
filename = docs.get('meta.classifiers', 'CLASSIFIERS').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
content = fp.read()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
content = [item.strip() for item in content.splitlines()]
|
|
||||||
return [item for item in content if item and not item.startswith('#')]
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def find_provides(docs):
|
|
||||||
"""
|
|
||||||
Determine provides from PROVIDES
|
|
||||||
|
|
||||||
:return: List of provides (``['provides', ...]``)
|
|
||||||
:rtype: ``list``
|
|
||||||
"""
|
|
||||||
filename = docs.get('meta.provides', 'PROVIDES').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
content = fp.read()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
content = [item.strip() for item in content.splitlines()]
|
|
||||||
return [item for item in content if item and not item.startswith('#')]
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def find_license(docs):
|
|
||||||
"""
|
|
||||||
Determine license from LICENSE
|
|
||||||
|
|
||||||
:return: License text
|
|
||||||
:rtype: ``str``
|
|
||||||
"""
|
|
||||||
filename = docs.get('meta.license', 'LICENSE').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
return fp.read().rstrip()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def find_packages(manifest):
|
|
||||||
""" Determine packages and subpackages """
|
|
||||||
packages = {}
|
|
||||||
collect = manifest.get('packages.collect', '').split()
|
|
||||||
lib = manifest.get('packages.lib', '.')
|
|
||||||
try:
|
|
||||||
sep = _os.path.sep
|
|
||||||
except AttributeError:
|
|
||||||
sep = _os.path.join('1', '2')[1:-1]
|
|
||||||
for root in collect:
|
|
||||||
for dirpath, _, filenames in _shell.walk(_os.path.join(lib, root)):
|
|
||||||
if dirpath.find('.svn') >= 0 or dirpath.find('.git') >= 0:
|
|
||||||
continue
|
|
||||||
if '__init__.py' in filenames:
|
|
||||||
packages[
|
|
||||||
_os.path.normpath(dirpath).replace(sep, '.')
|
|
||||||
] = None
|
|
||||||
packages = packages.keys()
|
|
||||||
packages.sort()
|
|
||||||
return packages
|
|
||||||
|
|
||||||
|
|
||||||
def find_data(name, docs):
|
|
||||||
""" Determine data files """
|
|
||||||
result = []
|
|
||||||
if docs.get('extra', '').strip():
|
|
||||||
result.append(_data.Documentation(docs['extra'].split(),
|
|
||||||
prefix='share/doc/%s' % name,
|
|
||||||
))
|
|
||||||
if docs.get('examples.dir', '').strip():
|
|
||||||
tpl = ['recursive-include %s *' % docs['examples.dir']]
|
|
||||||
if docs.get('examples.ignore', '').strip():
|
|
||||||
tpl.extend(["global-exclude %s" % item
|
|
||||||
for item in docs['examples.ignore'].split()
|
|
||||||
])
|
|
||||||
strip = int(docs.get('examples.strip', '') or 0)
|
|
||||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
|
||||||
'strip': strip,
|
|
||||||
'prefix': 'share/doc/%s' % name,
|
|
||||||
'preserve': 1,
|
|
||||||
}))
|
|
||||||
if docs.get('userdoc.dir', '').strip():
|
|
||||||
tpl = ['recursive-include %s *' % docs['userdoc.dir']]
|
|
||||||
if docs.get('userdoc.ignore', '').strip():
|
|
||||||
tpl.extend(["global-exclude %s" % item
|
|
||||||
for item in docs['userdoc.ignore'].split()
|
|
||||||
])
|
|
||||||
strip = int(docs.get('userdoc.strip', '') or 0)
|
|
||||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
|
||||||
'strip': strip,
|
|
||||||
'prefix': 'share/doc/%s' % name,
|
|
||||||
'preserve': 1,
|
|
||||||
}))
|
|
||||||
if docs.get('apidoc.dir', '').strip():
|
|
||||||
tpl = ['recursive-include %s *' % docs['apidoc.dir']]
|
|
||||||
if docs.get('apidoc.ignore', '').strip():
|
|
||||||
tpl.extend(["global-exclude %s" % item
|
|
||||||
for item in docs['apidoc.ignore'].split()
|
|
||||||
])
|
|
||||||
strip = int(docs.get('apidoc.strip', '') or 0)
|
|
||||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
|
||||||
'strip': strip,
|
|
||||||
'prefix': 'share/doc/%s' % name,
|
|
||||||
'preserve': 1,
|
|
||||||
}))
|
|
||||||
if docs.get('man', '').strip():
|
|
||||||
result.extend(_data.Manpages.dispatch(docs['man'].split()))
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def make_manifest(manifest, config, docs, kwargs):
|
|
||||||
""" Create file list to pack up """
|
|
||||||
# pylint: disable = R0912
|
|
||||||
kwargs = kwargs.copy()
|
|
||||||
kwargs['script_args'] = ['install']
|
|
||||||
kwargs['packages'] = list(kwargs.get('packages') or ()) + [
|
|
||||||
'_setup', '_setup.py2', '_setup.py3',
|
|
||||||
] + list(manifest.get('packages.extra', '').split() or ())
|
|
||||||
_core._setup_stop_after = "commandline"
|
|
||||||
try:
|
|
||||||
dist = _core.setup(**kwargs)
|
|
||||||
finally:
|
|
||||||
_core._setup_stop_after = None
|
|
||||||
|
|
||||||
result = ['MANIFEST', 'PKG-INFO', 'setup.py'] + list(config)
|
|
||||||
# TODO: work with default values:
|
|
||||||
for key in ('classifiers', 'description', 'summary', 'provides',
|
|
||||||
'license'):
|
|
||||||
filename = docs.get('meta.' + key, '').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
result.append(filename)
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("build_py")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
#from pprint import pprint; pprint(("build_py", cmd.get_source_files()))
|
|
||||||
for item in cmd.get_source_files():
|
|
||||||
result.append(_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
))
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("build_ext")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
#from pprint import pprint; pprint(("build_ext", cmd.get_source_files()))
|
|
||||||
for item in cmd.get_source_files():
|
|
||||||
result.append(_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
))
|
|
||||||
for ext in cmd.extensions:
|
|
||||||
if ext.depends:
|
|
||||||
result.extend([_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
) for item in ext.depends])
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("build_clib")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
if cmd.libraries:
|
|
||||||
#import pprint; pprint.pprint(("build_clib", cmd.get_source_files()))
|
|
||||||
for item in cmd.get_source_files():
|
|
||||||
result.append(_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
))
|
|
||||||
for lib in cmd.libraries:
|
|
||||||
if lib[1].get('depends'):
|
|
||||||
result.extend([_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
) for item in lib[1]['depends']])
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("build_scripts")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
#import pprint; pprint.pprint(("build_scripts", cmd.get_source_files()))
|
|
||||||
if cmd.get_source_files():
|
|
||||||
for item in cmd.get_source_files():
|
|
||||||
result.append(_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
))
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("install_data")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
#from pprint import pprint; pprint(("install_data", cmd.get_inputs()))
|
|
||||||
try:
|
|
||||||
strings = basestring
|
|
||||||
except NameError:
|
|
||||||
strings = (str, unicode)
|
|
||||||
|
|
||||||
for item in cmd.get_inputs():
|
|
||||||
if isinstance(item, strings):
|
|
||||||
result.append(item)
|
|
||||||
else:
|
|
||||||
result.extend(item[1])
|
|
||||||
|
|
||||||
for item in manifest.get('dist', '').split():
|
|
||||||
result.append(item)
|
|
||||||
if _os.path.isdir(item):
|
|
||||||
for filename in _shell.files(item):
|
|
||||||
result.append(filename)
|
|
||||||
|
|
||||||
result = dict([(item, None) for item in result]).keys()
|
|
||||||
result.sort()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def run(config=('package.cfg',), ext=None, script_args=None, manifest_only=0):
|
|
||||||
""" Main runner """
|
|
||||||
if ext is None:
|
|
||||||
ext = []
|
|
||||||
|
|
||||||
cfg = _util.SafeConfigParser()
|
|
||||||
cfg.read(config)
|
|
||||||
pkg = dict(cfg.items('package'))
|
|
||||||
python_min = pkg.get('python.min') or None
|
|
||||||
python_max = pkg.get('python.max') or None
|
|
||||||
check_python_version('python', python_min, python_max)
|
|
||||||
pypy_min = pkg.get('pypy.min') or None
|
|
||||||
pypy_max = pkg.get('pypy.max') or None
|
|
||||||
check_python_version('pypy', pypy_min, pypy_max)
|
|
||||||
jython_min = pkg.get('jython.min') or None
|
|
||||||
jython_max = pkg.get('jython.max') or None
|
|
||||||
check_python_version('jython', jython_min, jython_max)
|
|
||||||
|
|
||||||
manifest = dict(cfg.items('manifest'))
|
|
||||||
try:
|
|
||||||
docs = dict(cfg.items('docs'))
|
|
||||||
except _config_parser.NoSectionError:
|
|
||||||
docs = {}
|
|
||||||
|
|
||||||
summary, description = find_description(docs)
|
|
||||||
scripts = manifest.get('scripts', '').strip() or None
|
|
||||||
if scripts:
|
|
||||||
scripts = scripts.split()
|
|
||||||
modules = manifest.get('modules', '').strip() or None
|
|
||||||
if modules:
|
|
||||||
modules = modules.split()
|
|
||||||
keywords = docs.get('meta.keywords', '').strip() or None
|
|
||||||
if keywords:
|
|
||||||
keywords = keywords.split()
|
|
||||||
revision = pkg.get('version.revision', '').strip()
|
|
||||||
if revision:
|
|
||||||
revision = "-r%s" % (revision,)
|
|
||||||
|
|
||||||
kwargs = {
|
|
||||||
'name': pkg['name'],
|
|
||||||
'version': "%s%s" % (
|
|
||||||
pkg['version.number'],
|
|
||||||
["", "-dev%s" % (revision,)][_util.humanbool(
|
|
||||||
'version.dev', pkg.get('version.dev', 'false')
|
|
||||||
)],
|
|
||||||
),
|
|
||||||
'provides': find_provides(docs),
|
|
||||||
'description': summary,
|
|
||||||
'long_description': description,
|
|
||||||
'classifiers': find_classifiers(docs),
|
|
||||||
'keywords': keywords,
|
|
||||||
'author': pkg['author.name'],
|
|
||||||
'author_email': pkg['author.email'],
|
|
||||||
'maintainer': pkg.get('maintainer.name'),
|
|
||||||
'maintainer_email': pkg.get('maintainer.email'),
|
|
||||||
'url': pkg.get('url.homepage'),
|
|
||||||
'download_url': pkg.get('url.download'),
|
|
||||||
'license': find_license(docs),
|
|
||||||
'package_dir': {'': manifest.get('packages.lib', '.')},
|
|
||||||
'packages': find_packages(manifest),
|
|
||||||
'py_modules': modules,
|
|
||||||
'ext_modules': ext,
|
|
||||||
'scripts': scripts,
|
|
||||||
'script_args': script_args,
|
|
||||||
'data_files': find_data(pkg['name'], docs),
|
|
||||||
'cmdclass': {
|
|
||||||
'build' : _commands.Build,
|
|
||||||
'build_ext' : _commands.BuildExt,
|
|
||||||
'install' : _commands.Install,
|
|
||||||
'install_data': _commands.InstallData,
|
|
||||||
'install_lib' : _commands.InstallLib,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for key in ('provides',):
|
|
||||||
if key not in _core.setup_keywords:
|
|
||||||
del kwargs[key]
|
|
||||||
|
|
||||||
if manifest_only:
|
|
||||||
return make_manifest(manifest, config, docs, kwargs)
|
|
||||||
|
|
||||||
# monkey-patch crappy manifest writer away.
|
|
||||||
from distutils.command import sdist
|
|
||||||
sdist.sdist.get_file_list = sdist.sdist.read_manifest
|
|
||||||
|
|
||||||
return _core.setup(**kwargs)
|
|
@ -1,478 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2007 - 2013
|
|
||||||
# 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.
|
|
||||||
"""
|
|
||||||
=================
|
|
||||||
Shell utilities
|
|
||||||
=================
|
|
||||||
|
|
||||||
Shell utilities.
|
|
||||||
"""
|
|
||||||
from __future__ import generators
|
|
||||||
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import errno as _errno
|
|
||||||
import fnmatch as _fnmatch
|
|
||||||
import os as _os
|
|
||||||
import shutil as _shutil
|
|
||||||
import sys as _sys
|
|
||||||
import tempfile as _tempfile
|
|
||||||
|
|
||||||
cwd = _os.path.dirname(_os.path.abspath(_sys.argv[0]))
|
|
||||||
|
|
||||||
class ExitError(RuntimeError):
|
|
||||||
""" Exit error """
|
|
||||||
def __init__(self, code):
|
|
||||||
RuntimeError.__init__(self, code)
|
|
||||||
self.code = code
|
|
||||||
self.signal = None
|
|
||||||
|
|
||||||
|
|
||||||
class SignalError(ExitError):
|
|
||||||
""" Signal error """
|
|
||||||
def __init__(self, code, signal):
|
|
||||||
ExitError.__init__(self, code)
|
|
||||||
import signal as _signal
|
|
||||||
self.signal = signal
|
|
||||||
for key, val in vars(_signal).iteritems():
|
|
||||||
if key.startswith('SIG') and not key.startswith('SIG_'):
|
|
||||||
if val == signal:
|
|
||||||
self.signalstr = key[3:]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
self.signalstr = '%04d' % signal
|
|
||||||
|
|
||||||
|
|
||||||
def native(path):
|
|
||||||
""" Convert slash path to native """
|
|
||||||
path = _os.path.sep.join(path.split('/'))
|
|
||||||
return _os.path.normpath(_os.path.join(cwd, path))
|
|
||||||
|
|
||||||
|
|
||||||
def cp(src, dest):
|
|
||||||
""" Copy src to dest """
|
|
||||||
_shutil.copy2(native(src), native(dest))
|
|
||||||
|
|
||||||
|
|
||||||
def cp_r(src, dest):
|
|
||||||
""" Copy -r src to dest """
|
|
||||||
_shutil.copytree(native(src), native(dest))
|
|
||||||
|
|
||||||
|
|
||||||
def rm(dest):
|
|
||||||
""" Remove a file """
|
|
||||||
try:
|
|
||||||
_os.unlink(native(dest))
|
|
||||||
except OSError, e:
|
|
||||||
if _errno.ENOENT != e.errno:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def rm_rf(dest):
|
|
||||||
""" Remove a tree """
|
|
||||||
dest = native(dest)
|
|
||||||
if _os.path.exists(dest):
|
|
||||||
for path in files(dest, '*'):
|
|
||||||
_os.chmod(native(path), 0644)
|
|
||||||
_shutil.rmtree(dest)
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
mkstemp = _tempfile.mkstemp
|
|
||||||
except AttributeError:
|
|
||||||
# helpers stolen from 2.4 tempfile module
|
|
||||||
try:
|
|
||||||
import fcntl as _fcntl
|
|
||||||
except ImportError:
|
|
||||||
def _set_cloexec(fd):
|
|
||||||
""" Set close-on-exec (not implemented, but not an error) """
|
|
||||||
# pylint: disable = W0613
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
def _set_cloexec(fd):
|
|
||||||
""" Set close-on-exec """
|
|
||||||
try:
|
|
||||||
flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)
|
|
||||||
except IOError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
# flags read successfully, modify
|
|
||||||
flags |= _fcntl.FD_CLOEXEC
|
|
||||||
_fcntl.fcntl(fd, _fcntl.F_SETFD, flags)
|
|
||||||
|
|
||||||
_text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL
|
|
||||||
_text_openflags |= getattr(_os, 'O_NOINHERIT', 0)
|
|
||||||
_text_openflags |= getattr(_os, 'O_NOFOLLOW', 0)
|
|
||||||
|
|
||||||
_bin_openflags = _text_openflags
|
|
||||||
_bin_openflags |= getattr(_os, 'O_BINARY', 0)
|
|
||||||
|
|
||||||
def mkstemp(suffix="", prefix=_tempfile.gettempprefix(), dir=None,
|
|
||||||
text=False):
|
|
||||||
""" Create secure temp file """
|
|
||||||
# pylint: disable = W0622
|
|
||||||
if dir is None:
|
|
||||||
dir = _tempfile.gettempdir()
|
|
||||||
if text:
|
|
||||||
flags = _text_openflags
|
|
||||||
else:
|
|
||||||
flags = _bin_openflags
|
|
||||||
count = 100
|
|
||||||
while count > 0:
|
|
||||||
j = _tempfile._counter.get_next() # pylint: disable = E1101, W0212
|
|
||||||
fname = _os.path.join(dir, prefix + str(j) + suffix)
|
|
||||||
try:
|
|
||||||
fd = _os.open(fname, flags, 0600)
|
|
||||||
except OSError, e:
|
|
||||||
if e.errno == _errno.EEXIST:
|
|
||||||
count -= 1
|
|
||||||
continue
|
|
||||||
raise
|
|
||||||
_set_cloexec(fd)
|
|
||||||
return fd, _os.path.abspath(fname)
|
|
||||||
raise IOError, (_errno.EEXIST, "No usable temporary file name found")
|
|
||||||
|
|
||||||
|
|
||||||
def _pipespawn(argv, env):
|
|
||||||
""" Pipe spawn """
|
|
||||||
# pylint: disable = R0912
|
|
||||||
import pickle as _pickle
|
|
||||||
fd, name = mkstemp('.py')
|
|
||||||
try:
|
|
||||||
_os.write(fd, (r"""
|
|
||||||
import os
|
|
||||||
import pickle
|
|
||||||
try:
|
|
||||||
import subprocess
|
|
||||||
except ImportError:
|
|
||||||
subprocess = None
|
|
||||||
import sys
|
|
||||||
|
|
||||||
argv = pickle.loads(%(argv)s)
|
|
||||||
env = pickle.loads(%(env)s)
|
|
||||||
if 'X_JYTHON_WA_PATH' in env:
|
|
||||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
|
||||||
|
|
||||||
if subprocess is None:
|
|
||||||
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
|
|
||||||
result = os.waitpid(pid, 0)[1]
|
|
||||||
else:
|
|
||||||
p = subprocess.Popen(argv, env=env)
|
|
||||||
result = p.wait()
|
|
||||||
if result < 0:
|
|
||||||
print "\n%%d 1" %% (-result)
|
|
||||||
sys.exit(2)
|
|
||||||
|
|
||||||
if result == 0:
|
|
||||||
sys.exit(0)
|
|
||||||
signalled = getattr(os, 'WIFSIGNALED', None)
|
|
||||||
if signalled is not None:
|
|
||||||
if signalled(result):
|
|
||||||
print "\n%%d %%d" %% (os.WTERMSIG(result), result & 7)
|
|
||||||
sys.exit(2)
|
|
||||||
print "\n%%d" %% (result & 7,)
|
|
||||||
sys.exit(3)
|
|
||||||
""".strip() + "\n") % {
|
|
||||||
'argv': repr(_pickle.dumps(argv)),
|
|
||||||
'env': repr(_pickle.dumps(env)),
|
|
||||||
})
|
|
||||||
fd, _ = None, _os.close(fd)
|
|
||||||
if _sys.platform == 'win32':
|
|
||||||
argv = []
|
|
||||||
for arg in [_sys.executable, name]:
|
|
||||||
if ' ' in arg or arg.startswith('"'):
|
|
||||||
arg = '"%s"' % arg.replace('"', '\\"')
|
|
||||||
argv.append(arg)
|
|
||||||
argv = ' '.join(argv)
|
|
||||||
shell = True
|
|
||||||
close_fds = False
|
|
||||||
else:
|
|
||||||
argv = [_sys.executable, name]
|
|
||||||
shell = False
|
|
||||||
close_fds = True
|
|
||||||
|
|
||||||
res = 0
|
|
||||||
try:
|
|
||||||
import subprocess
|
|
||||||
except ImportError:
|
|
||||||
import popen2 as _popen2
|
|
||||||
proc = _popen2.Popen3(argv, False)
|
|
||||||
try:
|
|
||||||
proc.tochild.close()
|
|
||||||
result = proc.fromchild.read()
|
|
||||||
finally:
|
|
||||||
res = proc.wait()
|
|
||||||
else:
|
|
||||||
if 'X_JYTHON_WA_PATH' in env:
|
|
||||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
|
||||||
|
|
||||||
proc = subprocess.Popen(argv,
|
|
||||||
shell=shell,
|
|
||||||
stdin=subprocess.PIPE,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
close_fds=close_fds,
|
|
||||||
env=env,
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
proc.stdin.close()
|
|
||||||
result = proc.stdout.read()
|
|
||||||
finally:
|
|
||||||
res = proc.wait()
|
|
||||||
if res != 0:
|
|
||||||
if res == 2:
|
|
||||||
signal, code = map(int, result.splitlines()[-1].split())
|
|
||||||
raise SignalError(code, signal)
|
|
||||||
elif res == 3:
|
|
||||||
code = int(result.splitlines()[-1].strip())
|
|
||||||
raise ExitError(code)
|
|
||||||
raise ExitError(res)
|
|
||||||
|
|
||||||
return result
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
if fd is not None:
|
|
||||||
_os.close(fd)
|
|
||||||
finally:
|
|
||||||
_os.unlink(name)
|
|
||||||
|
|
||||||
|
|
||||||
def _filepipespawn(infile, outfile, argv, env):
|
|
||||||
""" File Pipe spawn """
|
|
||||||
try:
|
|
||||||
import subprocess
|
|
||||||
except ImportError:
|
|
||||||
subprocess = None
|
|
||||||
import pickle as _pickle
|
|
||||||
fd, name = mkstemp('.py')
|
|
||||||
try:
|
|
||||||
_os.write(fd, ("""
|
|
||||||
import os
|
|
||||||
import pickle
|
|
||||||
import sys
|
|
||||||
|
|
||||||
infile = pickle.loads(%(infile)s)
|
|
||||||
outfile = pickle.loads(%(outfile)s)
|
|
||||||
argv = pickle.loads(%(argv)s)
|
|
||||||
env = pickle.loads(%(env)s)
|
|
||||||
|
|
||||||
if infile is not None:
|
|
||||||
infile = open(infile, 'rb')
|
|
||||||
os.dup2(infile.fileno(), 0)
|
|
||||||
infile.close()
|
|
||||||
if outfile is not None:
|
|
||||||
outfile = open(outfile, 'wb')
|
|
||||||
os.dup2(outfile.fileno(), 1)
|
|
||||||
outfile.close()
|
|
||||||
|
|
||||||
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
|
|
||||||
result = os.waitpid(pid, 0)[1]
|
|
||||||
sys.exit(result & 7)
|
|
||||||
""".strip() + "\n") % {
|
|
||||||
'infile': repr(_pickle.dumps(_os.path.abspath(infile))),
|
|
||||||
'outfile': repr(_pickle.dumps(_os.path.abspath(outfile))),
|
|
||||||
'argv': repr(_pickle.dumps(argv)),
|
|
||||||
'env': repr(_pickle.dumps(env)),
|
|
||||||
})
|
|
||||||
fd, _ = None, _os.close(fd)
|
|
||||||
if _sys.platform == 'win32':
|
|
||||||
argv = []
|
|
||||||
for arg in [_sys.executable, name]:
|
|
||||||
if ' ' in arg or arg.startswith('"'):
|
|
||||||
arg = '"%s"' % arg.replace('"', '\\"')
|
|
||||||
argv.append(arg)
|
|
||||||
argv = ' '.join(argv)
|
|
||||||
close_fds = False
|
|
||||||
shell = True
|
|
||||||
else:
|
|
||||||
argv = [_sys.executable, name]
|
|
||||||
close_fds = True
|
|
||||||
shell = False
|
|
||||||
|
|
||||||
if subprocess is None:
|
|
||||||
pid = _os.spawnve(_os.P_NOWAIT, argv[0], argv, env)
|
|
||||||
return _os.waitpid(pid, 0)[1]
|
|
||||||
else:
|
|
||||||
p = subprocess.Popen(
|
|
||||||
argv, env=env, shell=shell, close_fds=close_fds
|
|
||||||
)
|
|
||||||
return p.wait()
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
if fd is not None:
|
|
||||||
_os.close(fd)
|
|
||||||
finally:
|
|
||||||
_os.unlink(name)
|
|
||||||
|
|
||||||
|
|
||||||
def spawn(*argv, **kwargs):
|
|
||||||
""" Spawn a process """
|
|
||||||
try:
|
|
||||||
import subprocess
|
|
||||||
except ImportError:
|
|
||||||
subprocess = None
|
|
||||||
|
|
||||||
if _sys.platform == 'win32':
|
|
||||||
newargv = []
|
|
||||||
for arg in argv:
|
|
||||||
if not arg or ' ' in arg or arg.startswith('"'):
|
|
||||||
arg = '"%s"' % arg.replace('"', '\\"')
|
|
||||||
newargv.append(arg)
|
|
||||||
argv = newargv
|
|
||||||
close_fds = False
|
|
||||||
shell = True
|
|
||||||
else:
|
|
||||||
close_fds = True
|
|
||||||
shell = False
|
|
||||||
|
|
||||||
env = kwargs.get('env')
|
|
||||||
if env is None:
|
|
||||||
env = dict(_os.environ)
|
|
||||||
if 'X_JYTHON_WA_PATH' in env:
|
|
||||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
|
||||||
|
|
||||||
echo = kwargs.get('echo')
|
|
||||||
if echo:
|
|
||||||
print ' '.join(argv)
|
|
||||||
filepipe = kwargs.get('filepipe')
|
|
||||||
if filepipe:
|
|
||||||
return _filepipespawn(
|
|
||||||
kwargs.get('stdin'), kwargs.get('stdout'), argv, env
|
|
||||||
)
|
|
||||||
pipe = kwargs.get('stdout')
|
|
||||||
if pipe:
|
|
||||||
return _pipespawn(argv, env)
|
|
||||||
|
|
||||||
if subprocess is None:
|
|
||||||
pid = _os.spawnve(_os.P_NOWAIT, argv[0], argv, env)
|
|
||||||
return _os.waitpid(pid, 0)[1]
|
|
||||||
else:
|
|
||||||
p = subprocess.Popen(argv, env=env, shell=shell, close_fds=close_fds)
|
|
||||||
return p.wait()
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
walk = _os.walk
|
|
||||||
except AttributeError:
|
|
||||||
# copy from python 2.4 sources (modulo docs and comments)
|
|
||||||
def walk(top, topdown=True, onerror=None):
|
|
||||||
""" directory tree walker """
|
|
||||||
# pylint: disable = C0103
|
|
||||||
join, isdir, islink = _os.path.join, _os.path.isdir, _os.path.islink
|
|
||||||
listdir, error = _os.listdir, _os.error
|
|
||||||
|
|
||||||
try:
|
|
||||||
names = listdir(top)
|
|
||||||
except error, err:
|
|
||||||
if onerror is not None:
|
|
||||||
onerror(err)
|
|
||||||
return
|
|
||||||
|
|
||||||
dirs, nondirs = [], []
|
|
||||||
for name in names:
|
|
||||||
if isdir(join(top, name)):
|
|
||||||
dirs.append(name)
|
|
||||||
else:
|
|
||||||
nondirs.append(name)
|
|
||||||
|
|
||||||
if topdown:
|
|
||||||
yield top, dirs, nondirs
|
|
||||||
for name in dirs:
|
|
||||||
path = join(top, name)
|
|
||||||
if not islink(path):
|
|
||||||
for x in walk(path, topdown, onerror):
|
|
||||||
yield x
|
|
||||||
if not topdown:
|
|
||||||
yield top, dirs, nondirs
|
|
||||||
|
|
||||||
|
|
||||||
def files(base, wildcard='[!.]*', recursive=1, prune=('.git', '.svn', 'CVS')):
|
|
||||||
""" Determine a filelist """
|
|
||||||
for dirpath, dirnames, filenames in walk(native(base)):
|
|
||||||
for item in prune:
|
|
||||||
if item in dirnames:
|
|
||||||
dirnames.remove(item)
|
|
||||||
|
|
||||||
filenames.sort()
|
|
||||||
for name in _fnmatch.filter(filenames, wildcard):
|
|
||||||
dest = _os.path.join(dirpath, name)
|
|
||||||
if dest.startswith(cwd):
|
|
||||||
dest = dest.replace(cwd, '', 1)
|
|
||||||
aslist = []
|
|
||||||
head, tail = _os.path.split(dest)
|
|
||||||
while tail:
|
|
||||||
aslist.append(tail)
|
|
||||||
head, tail = _os.path.split(head)
|
|
||||||
aslist.reverse()
|
|
||||||
dest = '/'.join(aslist)
|
|
||||||
yield dest
|
|
||||||
|
|
||||||
if not recursive:
|
|
||||||
break
|
|
||||||
dirnames.sort()
|
|
||||||
|
|
||||||
|
|
||||||
def dirs(base, wildcard='[!.]*', recursive=1, prune=('.git', '.svn', 'CVS')):
|
|
||||||
""" Determine a filelist """
|
|
||||||
for dirpath, dirnames, filenames in walk(native(base)):
|
|
||||||
for item in prune:
|
|
||||||
if item in dirnames:
|
|
||||||
dirnames.remove(item)
|
|
||||||
|
|
||||||
dirnames.sort()
|
|
||||||
for name in _fnmatch.filter(dirnames, wildcard):
|
|
||||||
dest = _os.path.join(dirpath, name)
|
|
||||||
if dest.startswith(cwd):
|
|
||||||
dest = dest.replace(cwd, '', 1)
|
|
||||||
aslist = []
|
|
||||||
head, tail = _os.path.split(dest)
|
|
||||||
while tail:
|
|
||||||
aslist.append(tail)
|
|
||||||
head, tail = _os.path.split(head)
|
|
||||||
aslist.reverse()
|
|
||||||
dest = '/'.join(aslist)
|
|
||||||
yield dest
|
|
||||||
|
|
||||||
if not recursive:
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def frompath(executable):
|
|
||||||
""" Find executable in PATH """
|
|
||||||
# Based on distutils.spawn.find_executable.
|
|
||||||
path = _os.environ.get('PATH', '')
|
|
||||||
paths = [
|
|
||||||
_os.path.expanduser(item)
|
|
||||||
for item in path.split(_os.pathsep)
|
|
||||||
]
|
|
||||||
ext = _os.path.splitext(executable)[1]
|
|
||||||
exts = ['']
|
|
||||||
if _sys.platform == 'win32' or _os.name == 'os2':
|
|
||||||
eext = ['.exe', '.bat', '.py']
|
|
||||||
if ext not in eext:
|
|
||||||
exts.extend(eext)
|
|
||||||
|
|
||||||
for ext in exts:
|
|
||||||
if not _os.path.isfile(executable + ext):
|
|
||||||
for path in paths:
|
|
||||||
fname = _os.path.join(path, executable + ext)
|
|
||||||
if _os.path.isfile(fname):
|
|
||||||
# the file exists, we have a shot at spawn working
|
|
||||||
return fname
|
|
||||||
else:
|
|
||||||
return executable + ext
|
|
||||||
|
|
||||||
return None
|
|
@ -1,28 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 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.
|
|
||||||
"""
|
|
||||||
=====================
|
|
||||||
Package _setup.term
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Terminal tools, not distributed.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
# pylint: disable = W0611
|
|
||||||
from _setup.term._term import terminfo, write, green, red, yellow, announce
|
|
@ -1,115 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
=================
|
|
||||||
Terminal writer
|
|
||||||
=================
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
|
|
||||||
class _INFO(dict):
|
|
||||||
""" Terminal info dict """
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initialization """
|
|
||||||
dict.__init__(self, {
|
|
||||||
'NORMAL': '',
|
|
||||||
'BOLD': '',
|
|
||||||
'ERASE': '\n',
|
|
||||||
'RED': '',
|
|
||||||
'YELLOW': '',
|
|
||||||
'GREEN': '',
|
|
||||||
})
|
|
||||||
try:
|
|
||||||
import curses as _curses
|
|
||||||
except ImportError:
|
|
||||||
# fixup if a submodule of curses failed.
|
|
||||||
if 'curses' in _sys.modules:
|
|
||||||
del _sys.modules['curses']
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
_curses.setupterm()
|
|
||||||
except (TypeError, _curses.error):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
def make_color(color):
|
|
||||||
""" Make color control string """
|
|
||||||
seq = _curses.tigetstr('setaf')
|
|
||||||
if seq is not None:
|
|
||||||
# XXX may fail - need better logic
|
|
||||||
seq = seq.replace("%p1", "") % color
|
|
||||||
return seq
|
|
||||||
|
|
||||||
self['NORMAL'] = _curses.tigetstr('sgr0')
|
|
||||||
self['BOLD'] = _curses.tigetstr('bold')
|
|
||||||
|
|
||||||
erase = _curses.tigetstr('el1')
|
|
||||||
if erase is not None:
|
|
||||||
self['ERASE'] = erase + _curses.tigetstr('cr')
|
|
||||||
|
|
||||||
self['RED'] = make_color(_curses.COLOR_RED)
|
|
||||||
self['YELLOW'] = make_color(_curses.COLOR_YELLOW)
|
|
||||||
self['GREEN'] = make_color(_curses.COLOR_GREEN)
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
""" Deliver always """
|
|
||||||
dict.get(self, key) or ""
|
|
||||||
|
|
||||||
|
|
||||||
def terminfo():
|
|
||||||
""" Get info singleton """
|
|
||||||
# pylint: disable = E1101, W0612
|
|
||||||
if terminfo.info is None:
|
|
||||||
terminfo.info = _INFO()
|
|
||||||
return terminfo.info
|
|
||||||
terminfo.info = None
|
|
||||||
|
|
||||||
|
|
||||||
def write(fmt, **kwargs):
|
|
||||||
""" Write stuff on the terminal """
|
|
||||||
parm = dict(terminfo())
|
|
||||||
parm.update(kwargs)
|
|
||||||
_sys.stdout.write(fmt % parm)
|
|
||||||
_sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def green(bmt, **kwargs):
|
|
||||||
""" Write something in green on screen """
|
|
||||||
announce("%%(GREEN)s%s%%(NORMAL)s" % bmt, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def red(bmt, **kwargs):
|
|
||||||
""" Write something in red on the screen """
|
|
||||||
announce("%%(BOLD)s%%(RED)s%s%%(NORMAL)s" % bmt, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def yellow(fmt, **kwargs):
|
|
||||||
""" Write something in yellow on the screen """
|
|
||||||
announce("%%(BOLD)s%%(YELLOW)s%s%%(NORMAL)s" % fmt, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def announce(fmt, **kwargs):
|
|
||||||
""" Announce something """
|
|
||||||
write(fmt, **kwargs)
|
|
||||||
_sys.stdout.write("\n")
|
|
||||||
_sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
=================
|
|
||||||
Setup utilities
|
|
||||||
=================
|
|
||||||
|
|
||||||
Setup utilities.
|
|
||||||
"""
|
|
||||||
__author__ = u"Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
try:
|
|
||||||
from distutils import log
|
|
||||||
except ImportError:
|
|
||||||
class log(object):
|
|
||||||
def info(self, value):
|
|
||||||
print value
|
|
||||||
def debug(self, value):
|
|
||||||
pass
|
|
||||||
log = log()
|
|
||||||
|
|
||||||
from distutils import util as _util
|
|
||||||
try:
|
|
||||||
from ConfigParser import SafeConfigParser
|
|
||||||
except ImportError:
|
|
||||||
import ConfigParser as _config_parser
|
|
||||||
class SafeConfigParser(_config_parser.ConfigParser):
|
|
||||||
""" Safe config parser """
|
|
||||||
def _interpolate(self, section, option, rawval, vars):
|
|
||||||
return rawval
|
|
||||||
|
|
||||||
def items(self, section):
|
|
||||||
return [(key, self.get(section, key))
|
|
||||||
for key in self.options(section)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def humanbool(name, value):
|
|
||||||
"""
|
|
||||||
Determine human boolean value
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`name` : ``str``
|
|
||||||
The config key (used for error message)
|
|
||||||
|
|
||||||
`value` : ``str``
|
|
||||||
The config value
|
|
||||||
|
|
||||||
:Return: The boolean value
|
|
||||||
:Rtype: ``bool``
|
|
||||||
|
|
||||||
:Exceptions:
|
|
||||||
- `ValueError` : The value could not be recognized
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return _util.strtobool(str(value).strip().lower() or 'no')
|
|
||||||
except ValueError:
|
|
||||||
raise ValueError("Unrecognized config value: %s = %s" % (name, value))
|
|
@ -1,27 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
================
|
|
||||||
Package _setup
|
|
||||||
================
|
|
||||||
|
|
||||||
This package provides tools for main package setup.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
from _setup.setup import run # pylint: disable = W0611
|
|
@ -1,266 +0,0 @@
|
|||||||
# -*- 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)
|
|
@ -1,165 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
===================
|
|
||||||
Data distribution
|
|
||||||
===================
|
|
||||||
|
|
||||||
This module provides tools to simplify data distribution.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
from distutils import filelist as _filelist
|
|
||||||
import os as _os
|
|
||||||
import posixpath as _posixpath
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import commands as _commands
|
|
||||||
|
|
||||||
|
|
||||||
def splitpath(path):
|
|
||||||
""" Split a path """
|
|
||||||
drive, path = '', _os.path.normpath(path)
|
|
||||||
try:
|
|
||||||
splitunc = _os.path.splitunc
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
drive, path = splitunc(path)
|
|
||||||
if not drive:
|
|
||||||
drive, path = _os.path.splitdrive(path)
|
|
||||||
elems = []
|
|
||||||
try:
|
|
||||||
sep = _os.path.sep
|
|
||||||
except AttributeError:
|
|
||||||
sep = _os.path.join('1', '2')[1:-1]
|
|
||||||
while 1:
|
|
||||||
prefix, path = _os.path.split(path)
|
|
||||||
elems.append(path)
|
|
||||||
if prefix in ('', sep):
|
|
||||||
drive = _os.path.join(drive, prefix)
|
|
||||||
break
|
|
||||||
path = prefix
|
|
||||||
elems.reverse()
|
|
||||||
return drive, elems
|
|
||||||
|
|
||||||
|
|
||||||
def finalizer(installer):
|
|
||||||
""" Finalize install_data """
|
|
||||||
data_files = []
|
|
||||||
for item in installer.data_files:
|
|
||||||
if not isinstance(item, Data):
|
|
||||||
data_files.append(item)
|
|
||||||
continue
|
|
||||||
data_files.extend(item.flatten(installer))
|
|
||||||
installer.data_files = data_files
|
|
||||||
|
|
||||||
|
|
||||||
class Data(object):
|
|
||||||
""" File list container """
|
|
||||||
|
|
||||||
def __init__(self, files, target=None, preserve=0, strip=0,
|
|
||||||
prefix=None):
|
|
||||||
""" Initialization """
|
|
||||||
self._files = files
|
|
||||||
self._target = target
|
|
||||||
self._preserve = preserve
|
|
||||||
self._strip = strip
|
|
||||||
self._prefix = prefix
|
|
||||||
self.fixup_commands()
|
|
||||||
|
|
||||||
def fixup_commands(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def from_templates(cls, *templates, **kwargs):
|
|
||||||
""" Initialize from template """
|
|
||||||
files = _filelist.FileList()
|
|
||||||
for tpl in templates:
|
|
||||||
for line in tpl.split(';'):
|
|
||||||
files.process_template_line(line.strip())
|
|
||||||
files.sort()
|
|
||||||
files.remove_duplicates()
|
|
||||||
result = []
|
|
||||||
for filename in files.files:
|
|
||||||
_, elems = splitpath(filename)
|
|
||||||
if '.svn' in elems or '.git' in elems:
|
|
||||||
continue
|
|
||||||
result.append(filename)
|
|
||||||
return cls(result, **kwargs)
|
|
||||||
from_templates = classmethod(from_templates)
|
|
||||||
|
|
||||||
def flatten(self, installer):
|
|
||||||
""" Flatten the file list to (target, file) tuples """
|
|
||||||
# pylint: disable = W0613
|
|
||||||
if self._prefix:
|
|
||||||
_, prefix = splitpath(self._prefix)
|
|
||||||
telems = prefix
|
|
||||||
else:
|
|
||||||
telems = []
|
|
||||||
|
|
||||||
tmap = {}
|
|
||||||
for fname in self._files:
|
|
||||||
(_, name), target = splitpath(fname), telems
|
|
||||||
if self._preserve:
|
|
||||||
if self._strip:
|
|
||||||
name = name[max(0, min(self._strip, len(name) - 1)):]
|
|
||||||
if len(name) > 1:
|
|
||||||
target = telems + name[:-1]
|
|
||||||
tmap.setdefault(_posixpath.join(*target), []).append(fname)
|
|
||||||
return list(tmap.items())
|
|
||||||
|
|
||||||
|
|
||||||
class Documentation(Data):
|
|
||||||
""" Documentation container """
|
|
||||||
|
|
||||||
def fixup_commands(self):
|
|
||||||
_commands.add_option('install_data', 'without-docs',
|
|
||||||
help_text='Do not install documentation files',
|
|
||||||
inherit='install',
|
|
||||||
)
|
|
||||||
_commands.add_finalizer('install_data', 'documentation', finalizer)
|
|
||||||
|
|
||||||
def flatten(self, installer):
|
|
||||||
""" Check if docs should be installed at all """
|
|
||||||
if installer.without_docs:
|
|
||||||
return []
|
|
||||||
return Data.flatten(self, installer)
|
|
||||||
|
|
||||||
|
|
||||||
class Manpages(Documentation):
|
|
||||||
""" Manpages container """
|
|
||||||
|
|
||||||
def dispatch(cls, files):
|
|
||||||
""" Automatically dispatch manpages to their target directories """
|
|
||||||
mpmap = {}
|
|
||||||
for manpage in files:
|
|
||||||
normalized = _os.path.normpath(manpage)
|
|
||||||
_, ext = _os.path.splitext(normalized)
|
|
||||||
if ext.startswith(_os.path.extsep):
|
|
||||||
ext = ext[len(_os.path.extsep):]
|
|
||||||
mpmap.setdefault(ext, []).append(manpage)
|
|
||||||
return [cls(manpages, prefix=_posixpath.join(
|
|
||||||
'share', 'man', 'man%s' % section,
|
|
||||||
)) for section, manpages in list(mpmap.items())]
|
|
||||||
dispatch = classmethod(dispatch)
|
|
||||||
|
|
||||||
def flatten(self, installer):
|
|
||||||
""" Check if manpages are suitable """
|
|
||||||
if _sys.platform == 'win32':
|
|
||||||
return []
|
|
||||||
return Documentation.flatten(self, installer)
|
|
@ -1,25 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 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.
|
|
||||||
"""
|
|
||||||
====================
|
|
||||||
Package _setup.dev
|
|
||||||
====================
|
|
||||||
|
|
||||||
Development tools, not distributed.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
@ -1,258 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2006, 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.
|
|
||||||
"""
|
|
||||||
=================================
|
|
||||||
Support for code analysis tools
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Support for code analysis tools.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import re as _re
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import term as _term
|
|
||||||
from _setup import shell as _shell
|
|
||||||
|
|
||||||
|
|
||||||
class NotFinished(Exception):
|
|
||||||
""" Exception used for message passing in the stream filter """
|
|
||||||
|
|
||||||
class NotParseable(Exception):
|
|
||||||
""" Exception used for message passing in the stream filter """
|
|
||||||
|
|
||||||
class SpecialMessage(Exception):
|
|
||||||
""" Exception used for message passing in the stream filter """
|
|
||||||
|
|
||||||
|
|
||||||
class FilterStream(object):
|
|
||||||
""" Stream filter """
|
|
||||||
_LINERE = _re.compile(r'''
|
|
||||||
(?P<name>[^:]+)
|
|
||||||
:
|
|
||||||
(?P<lineno>\d+)
|
|
||||||
:\s+
|
|
||||||
\[(?P<mid>[^\],]+)(?:,\s+(?P<func>[^\]]+))?\]
|
|
||||||
\s+
|
|
||||||
(?P<desc>.*)
|
|
||||||
''', _re.X)
|
|
||||||
_SIMRE = _re.compile(r'in (?P<number>\d+) files')
|
|
||||||
_CYCRE = _re.compile(r'\((?P<cycle>[^)]+)\)')
|
|
||||||
|
|
||||||
def __init__(self, term, stream=_sys.stdout):
|
|
||||||
self.written = False
|
|
||||||
self._stream = stream
|
|
||||||
self._lastname = None
|
|
||||||
self._cycled = False
|
|
||||||
self._term = dict(term)
|
|
||||||
self._buffer = ''
|
|
||||||
|
|
||||||
def write(self, towrite):
|
|
||||||
""" Stream write function """
|
|
||||||
self._buffer += towrite
|
|
||||||
term = self._term
|
|
||||||
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
name, lineno, mid, func, desc = self._parse()
|
|
||||||
except NotFinished:
|
|
||||||
break
|
|
||||||
except SpecialMessage as e:
|
|
||||||
self._dospecial(e)
|
|
||||||
continue
|
|
||||||
except NotParseable as e:
|
|
||||||
self._print_literal(str(e.args[0]))
|
|
||||||
continue
|
|
||||||
|
|
||||||
if name != self._lastname:
|
|
||||||
if self._lastname is not None:
|
|
||||||
self._stream.write("\n")
|
|
||||||
term['path'] = name
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s>>> %(path)s%(NORMAL)s\n" % term
|
|
||||||
)
|
|
||||||
self._lastname = name
|
|
||||||
self.written = True
|
|
||||||
|
|
||||||
term['mid'] = mid
|
|
||||||
if mid.startswith('E') or mid.startswith('F'):
|
|
||||||
self._stream.write("%(BOLD)s%(RED)s%(mid)s%(NORMAL)s" % term)
|
|
||||||
elif mid == 'W0511':
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s%(GREEN)s%(mid)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
|
|
||||||
if int(lineno) != 0:
|
|
||||||
term['lineno'] = lineno
|
|
||||||
self._stream.write(" (%(lineno)s" % term)
|
|
||||||
if func:
|
|
||||||
term['func'] = func
|
|
||||||
self._stream.write(
|
|
||||||
", %(BOLD)s%(YELLOW)s%(func)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
self._stream.write(')')
|
|
||||||
|
|
||||||
self._stream.write(": %s\n" % desc)
|
|
||||||
self._stream.flush()
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
def _print_literal(self, line):
|
|
||||||
""" Print literal """
|
|
||||||
suppress = (
|
|
||||||
line.startswith('Unable to get imported names for ') or
|
|
||||||
line.startswith("Exception exceptions.RuntimeError: 'generator "
|
|
||||||
"ignored GeneratorExit' in <generator object at") or
|
|
||||||
line.startswith("Exception RuntimeError: 'generator "
|
|
||||||
"ignored GeneratorExit' in <generator object") or
|
|
||||||
not line.strip()
|
|
||||||
)
|
|
||||||
if not suppress:
|
|
||||||
self._stream.write("%s\n" % line)
|
|
||||||
self._stream.flush()
|
|
||||||
self.written = True
|
|
||||||
|
|
||||||
def _dospecial(self, e):
|
|
||||||
""" Deal with special messages """
|
|
||||||
if e.args[0] == 'R0401':
|
|
||||||
pos = self._buffer.find('\n')
|
|
||||||
line, self._buffer = (
|
|
||||||
self._buffer[:pos + 1], self._buffer[pos + 1:]
|
|
||||||
)
|
|
||||||
term = self._term
|
|
||||||
term['mid'] = e.args[0]
|
|
||||||
if not self._cycled:
|
|
||||||
self._cycled = True
|
|
||||||
self._stream.write('\n')
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
self._stream.write(": Cyclic imports\n")
|
|
||||||
match = self._CYCRE.search(e.args[1])
|
|
||||||
term['cycle'] = match.group('cycle')
|
|
||||||
self._stream.write("%(BOLD)s@@@ %(NORMAL)s%(cycle)s\n" % term)
|
|
||||||
self._stream.flush()
|
|
||||||
self.written = True
|
|
||||||
|
|
||||||
elif e.args[0] == 'R0801':
|
|
||||||
match = self._SIMRE.search(e.args[1])
|
|
||||||
if not match:
|
|
||||||
raise AssertionError(
|
|
||||||
'Could not determine number of similar files'
|
|
||||||
)
|
|
||||||
|
|
||||||
numfiles = int(match.group('number'))
|
|
||||||
pos = -1
|
|
||||||
for _ in range(numfiles + 1):
|
|
||||||
pos = self._buffer.find('\n', pos + 1)
|
|
||||||
if pos >= 0:
|
|
||||||
lines = self._buffer[:pos + 1]
|
|
||||||
self._buffer = self._buffer[pos + 1:]
|
|
||||||
term = self._term
|
|
||||||
|
|
||||||
self._stream.write("\n")
|
|
||||||
for name in lines.splitlines()[1:]:
|
|
||||||
name = name.rstrip()[2:]
|
|
||||||
term['path'] = name
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s=== %(path)s%(NORMAL)s\n" % term
|
|
||||||
)
|
|
||||||
self._lastname = name
|
|
||||||
|
|
||||||
term['mid'] = e.args[0]
|
|
||||||
self._stream.write(
|
|
||||||
"%(BOLD)s%(YELLOW)s%(mid)s%(NORMAL)s" % term
|
|
||||||
)
|
|
||||||
self._stream.write(": %s\n" % e.args[1])
|
|
||||||
self._stream.flush()
|
|
||||||
self.written = True
|
|
||||||
|
|
||||||
def _parse(self):
|
|
||||||
""" Parse output """
|
|
||||||
if '\n' not in self._buffer:
|
|
||||||
raise NotFinished()
|
|
||||||
|
|
||||||
line = self._buffer[:self._buffer.find('\n') + 1]
|
|
||||||
self._buffer = self._buffer[len(line):]
|
|
||||||
line = line.rstrip()
|
|
||||||
match = self._LINERE.match(line)
|
|
||||||
if not match:
|
|
||||||
raise NotParseable(line)
|
|
||||||
|
|
||||||
mid = match.group('mid')
|
|
||||||
if mid in ('R0801', 'R0401'):
|
|
||||||
self._buffer = "%s\n%s" % (line, self._buffer)
|
|
||||||
raise SpecialMessage(mid, match.group('desc'))
|
|
||||||
|
|
||||||
return match.group('name', 'lineno', 'mid', 'func', 'desc')
|
|
||||||
|
|
||||||
|
|
||||||
def run(config, *args):
|
|
||||||
""" Run pylint """
|
|
||||||
try:
|
|
||||||
from pylint import lint
|
|
||||||
from pylint.reporters import text
|
|
||||||
except ImportError:
|
|
||||||
return 2
|
|
||||||
|
|
||||||
if config is None:
|
|
||||||
config = _shell.native('pylint.conf')
|
|
||||||
argv = ['--rcfile', config,
|
|
||||||
'--reports', 'no',
|
|
||||||
'--output-format', 'parseable',
|
|
||||||
'--include-ids', 'yes'
|
|
||||||
]
|
|
||||||
|
|
||||||
stream = FilterStream(_term.terminfo())
|
|
||||||
|
|
||||||
old_stderr = _sys.stderr
|
|
||||||
try:
|
|
||||||
# pylint: disable = E1101
|
|
||||||
_sys.stderr = stream
|
|
||||||
from pylint import __pkginfo__
|
|
||||||
if __pkginfo__.numversion < (0, 13):
|
|
||||||
# The lint tool is not very user friendly, so we need a hack here.
|
|
||||||
lint.REPORTER_OPT_MAP['parseable'] = \
|
|
||||||
lambda: text.TextReporter2(stream)
|
|
||||||
reporter = text.TextReporter2(stream)
|
|
||||||
else:
|
|
||||||
reporter = text.ParseableTextReporter(stream)
|
|
||||||
lint.REPORTER_OPT_MAP['parseable'] = lambda: reporter
|
|
||||||
|
|
||||||
for path in args:
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
lint.Run(argv + [path], reporter=reporter)
|
|
||||||
except SystemExit:
|
|
||||||
pass # don't accept the exit. strange errors happen...
|
|
||||||
|
|
||||||
if stream.written:
|
|
||||||
print()
|
|
||||||
stream.written = False
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print()
|
|
||||||
raise
|
|
||||||
finally:
|
|
||||||
_sys.stderr = old_stderr
|
|
||||||
|
|
||||||
return 0
|
|
@ -1,31 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2006, 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.
|
|
||||||
"""
|
|
||||||
=================================
|
|
||||||
Support for code analysis tools
|
|
||||||
=================================
|
|
||||||
|
|
||||||
Support for code analysis tools.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
|
|
||||||
def pylint(config, *args):
|
|
||||||
""" Run pylint """
|
|
||||||
from _setup.dev import _pylint
|
|
||||||
return _pylint.run(config, *args)
|
|
@ -1,131 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
==================
|
|
||||||
API doc builders
|
|
||||||
==================
|
|
||||||
|
|
||||||
API doc builders.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
import re as _re
|
|
||||||
|
|
||||||
from _setup import shell as _shell
|
|
||||||
from _setup import term as _term
|
|
||||||
from _setup import util as _util
|
|
||||||
|
|
||||||
|
|
||||||
def _cleanup_epydoc(target):
|
|
||||||
"""
|
|
||||||
Cleanup epydoc generated files
|
|
||||||
|
|
||||||
This removes the epydoc-footer. It changes every release because of the
|
|
||||||
timestamp. That creates bad diffs (accidently it's also invalid html).
|
|
||||||
"""
|
|
||||||
search = _re.compile(r'<table[^<>]+width="100%%"').search
|
|
||||||
for filename in _shell.files(target, '*.html'):
|
|
||||||
fp = open(filename, 'r')
|
|
||||||
try:
|
|
||||||
html = fp.read()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
match = search(html)
|
|
||||||
if match:
|
|
||||||
start = match.start()
|
|
||||||
end = html.find('</table>', start)
|
|
||||||
if end >= 0:
|
|
||||||
end += len('</table>') + 1
|
|
||||||
html = html[:start] + html[end:]
|
|
||||||
fp = open(filename, 'w')
|
|
||||||
try:
|
|
||||||
fp.write(html)
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
|
|
||||||
_VERSION_SEARCH = _re.compile(
|
|
||||||
r'\bversion\s+(?P<major>\d+)\.(?P<minor>\d+)'
|
|
||||||
).search
|
|
||||||
def epydoc(**kwargs):
|
|
||||||
""" Run epydoc """
|
|
||||||
# pylint: disable = R0912
|
|
||||||
prog = kwargs.get('epydoc') or 'epydoc'
|
|
||||||
if not _os.path.dirname(_os.path.normpath(prog)):
|
|
||||||
prog = _shell.frompath(prog)
|
|
||||||
if not prog:
|
|
||||||
_term.red("%(epydoc)s not found",
|
|
||||||
epydoc=kwargs.get('epydoc') or 'epydoc',
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
|
|
||||||
version = _VERSION_SEARCH(_shell.spawn(prog, "--version", stdout=True))
|
|
||||||
if version is not None:
|
|
||||||
try:
|
|
||||||
version = tuple(map(int, version.group('major', 'minor')))
|
|
||||||
except (TypeError, ValueError):
|
|
||||||
version = None
|
|
||||||
if version is None:
|
|
||||||
_term.red("%(prog)s version not recognized" % locals())
|
|
||||||
return False
|
|
||||||
|
|
||||||
if version < (3, 0):
|
|
||||||
_term.red("%(prog)s is too old %(version)r < (3, 0)" % locals())
|
|
||||||
return False
|
|
||||||
|
|
||||||
env = dict(_os.environ)
|
|
||||||
|
|
||||||
prepend = kwargs.get('prepend')
|
|
||||||
if prepend:
|
|
||||||
toprepend = _os.pathsep.join(map(str, prepend))
|
|
||||||
if 'PYTHONPATH' in env:
|
|
||||||
env['PYTHONPATH'] = _os.pathsep.join((
|
|
||||||
toprepend, env['PYTHONPATH']
|
|
||||||
))
|
|
||||||
else:
|
|
||||||
env['PYTHONPATH'] = toprepend
|
|
||||||
|
|
||||||
append = kwargs.get('append')
|
|
||||||
if append:
|
|
||||||
toappend = _os.pathsep.join(map(str, append))
|
|
||||||
if 'PYTHONPATH' in env:
|
|
||||||
env['PYTHONPATH'] = _os.pathsep.join((
|
|
||||||
env['PYTHONPATH'], toappend
|
|
||||||
))
|
|
||||||
else:
|
|
||||||
env['PYTHONPATH'] = toappend
|
|
||||||
|
|
||||||
moreenv = kwargs.get('env')
|
|
||||||
if moreenv:
|
|
||||||
env.update(moreenv)
|
|
||||||
|
|
||||||
config = kwargs.get('config') or _shell.native('docs/epydoc.conf')
|
|
||||||
|
|
||||||
argv = [prog, '--config', config]
|
|
||||||
res = not _shell.spawn(*argv, **{'env': env})
|
|
||||||
if res:
|
|
||||||
cfg = _util.SafeConfigParser()
|
|
||||||
cfg.read(config)
|
|
||||||
try:
|
|
||||||
target = dict(cfg.items('epydoc'))['target']
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
_cleanup_epydoc(target)
|
|
||||||
return res
|
|
@ -1,50 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 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.
|
|
||||||
"""
|
|
||||||
===================
|
|
||||||
User doc builders
|
|
||||||
===================
|
|
||||||
|
|
||||||
User doc builders.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
|
|
||||||
from _setup import shell as _shell
|
|
||||||
from _setup import term as _term
|
|
||||||
|
|
||||||
|
|
||||||
def sphinx(**kwargs):
|
|
||||||
""" Run sphinx """
|
|
||||||
prog = _shell.frompath('sphinx-build')
|
|
||||||
if prog is None:
|
|
||||||
_term.red("sphinx-build not found")
|
|
||||||
return False
|
|
||||||
|
|
||||||
env = dict(_os.environ)
|
|
||||||
|
|
||||||
argv = [
|
|
||||||
prog, '-a',
|
|
||||||
'-d', _os.path.join(kwargs['build'], 'doctrees'),
|
|
||||||
'-b', 'html',
|
|
||||||
kwargs['source'],
|
|
||||||
kwargs['target'],
|
|
||||||
]
|
|
||||||
|
|
||||||
return not _shell.spawn(*argv, **{'env': env})
|
|
@ -1,51 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
================
|
|
||||||
dist utilities
|
|
||||||
================
|
|
||||||
|
|
||||||
dist utilities.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import shell as _shell
|
|
||||||
|
|
||||||
|
|
||||||
def run_setup(*args, **kwargs):
|
|
||||||
""" Run setup """
|
|
||||||
if 'setup' in kwargs:
|
|
||||||
script = kwargs.get('setup') or 'setup.py'
|
|
||||||
del kwargs['setup']
|
|
||||||
else:
|
|
||||||
script = 'setup.py'
|
|
||||||
if 'fakeroot' in kwargs:
|
|
||||||
fakeroot = kwargs['fakeroot']
|
|
||||||
del kwargs['fakeroot']
|
|
||||||
else:
|
|
||||||
fakeroot = None
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError("Unrecognized keyword parameters")
|
|
||||||
|
|
||||||
script = _shell.native(script)
|
|
||||||
argv = [_sys.executable, script] + list(args)
|
|
||||||
if fakeroot:
|
|
||||||
argv.insert(0, fakeroot)
|
|
||||||
return not _shell.spawn(*argv)
|
|
@ -1,253 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
===================
|
|
||||||
C extension tools
|
|
||||||
===================
|
|
||||||
|
|
||||||
C extension tools.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
__test__ = False
|
|
||||||
|
|
||||||
from distutils import core as _core
|
|
||||||
from distutils import errors as _distutils_errors
|
|
||||||
from distutils import log
|
|
||||||
import os as _os
|
|
||||||
import posixpath as _posixpath
|
|
||||||
import shutil as _shutil
|
|
||||||
import tempfile as _tempfile
|
|
||||||
|
|
||||||
from _setup import commands as _commands
|
|
||||||
|
|
||||||
def _install_finalizer(installer):
|
|
||||||
if installer.without_c_extensions:
|
|
||||||
installer.distribution.ext_modules = []
|
|
||||||
|
|
||||||
def _build_finalizer(builder):
|
|
||||||
if builder.without_c_extensions:
|
|
||||||
builder.extensions = []
|
|
||||||
|
|
||||||
|
|
||||||
class Extension(_core.Extension):
|
|
||||||
"""
|
|
||||||
Extension with prerequisite check interface
|
|
||||||
|
|
||||||
If your check is cacheable (during the setup run), override
|
|
||||||
`cached_check_prerequisites`, `check_prerequisites` otherwise.
|
|
||||||
|
|
||||||
:IVariables:
|
|
||||||
`cached_check` : ``bool``
|
|
||||||
The cached check result
|
|
||||||
"""
|
|
||||||
cached_check = None
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
""" Initialization """
|
|
||||||
if 'depends' in kwargs:
|
|
||||||
self.depends = kwargs['depends'] or []
|
|
||||||
else:
|
|
||||||
self.depends = []
|
|
||||||
_core.Extension.__init__(self, *args, **kwargs)
|
|
||||||
|
|
||||||
# add include path
|
|
||||||
included = _posixpath.join('_setup', 'include')
|
|
||||||
if included not in self.include_dirs:
|
|
||||||
self.include_dirs.append(included)
|
|
||||||
|
|
||||||
# add cext.h to the dependencies
|
|
||||||
cext_h = _posixpath.join(included, 'cext.h')
|
|
||||||
if cext_h not in self.depends:
|
|
||||||
self.depends.append(cext_h)
|
|
||||||
|
|
||||||
_commands.add_option('install_lib', 'without-c-extensions',
|
|
||||||
help_text='Don\'t install C extensions',
|
|
||||||
inherit='install',
|
|
||||||
)
|
|
||||||
_commands.add_finalizer('install_lib', 'c-extensions',
|
|
||||||
_install_finalizer
|
|
||||||
)
|
|
||||||
_commands.add_option('build_ext', 'without-c-extensions',
|
|
||||||
help_text='Don\'t build C extensions',
|
|
||||||
inherit=('build', 'install_lib'),
|
|
||||||
)
|
|
||||||
_commands.add_finalizer('build_ext', 'c-extensions', _build_finalizer)
|
|
||||||
|
|
||||||
def check_prerequisites(self, build):
|
|
||||||
"""
|
|
||||||
Check prerequisites
|
|
||||||
|
|
||||||
The check should cover all dependencies needed for the extension to
|
|
||||||
be built and run. The method can do the following:
|
|
||||||
|
|
||||||
- return a false value: the extension will be built
|
|
||||||
- return a true value: the extension will be skipped. This is useful
|
|
||||||
for optional extensions
|
|
||||||
- raise an exception. This is useful for mandatory extensions
|
|
||||||
|
|
||||||
If the check result is cacheable (during the setup run), override
|
|
||||||
`cached_check_prerequisites` instead.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`build` : `BuildExt`
|
|
||||||
The extension builder
|
|
||||||
|
|
||||||
:Return: Skip the extension?
|
|
||||||
:Rtype: ``bool``
|
|
||||||
"""
|
|
||||||
if self.cached_check is None:
|
|
||||||
log.debug("PREREQ check for %s" % self.name)
|
|
||||||
self.cached_check = self.cached_check_prerequisites(build)
|
|
||||||
else:
|
|
||||||
log.debug("PREREQ check for %s (cached)" % self.name)
|
|
||||||
return self.cached_check
|
|
||||||
|
|
||||||
def cached_check_prerequisites(self, build):
|
|
||||||
"""
|
|
||||||
Check prerequisites
|
|
||||||
|
|
||||||
The check should cover all dependencies needed for the extension to
|
|
||||||
be built and run. The method can do the following:
|
|
||||||
|
|
||||||
- return a false value: the extension will be built
|
|
||||||
- return a true value: the extension will be skipped. This is useful
|
|
||||||
for optional extensions
|
|
||||||
- raise an exception. This is useful for mandatory extensions
|
|
||||||
|
|
||||||
If the check result is *not* cacheable (during the setup run),
|
|
||||||
override `check_prerequisites` instead.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`build` : `BuildExt`
|
|
||||||
The extension builder
|
|
||||||
|
|
||||||
:Return: Skip the extension?
|
|
||||||
:Rtype: ``bool``
|
|
||||||
"""
|
|
||||||
# pylint: disable = W0613
|
|
||||||
log.debug("Nothing to check for %s!" % self.name)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class ConfTest(object):
|
|
||||||
"""
|
|
||||||
Single conftest abstraction
|
|
||||||
|
|
||||||
:IVariables:
|
|
||||||
`_tempdir` : ``str``
|
|
||||||
The tempdir created for this test
|
|
||||||
|
|
||||||
`src` : ``str``
|
|
||||||
Name of the source file
|
|
||||||
|
|
||||||
`target` : ``str``
|
|
||||||
Target filename
|
|
||||||
|
|
||||||
`compiler` : ``CCompiler``
|
|
||||||
compiler instance
|
|
||||||
|
|
||||||
`obj` : ``list``
|
|
||||||
List of object filenames (``[str, ...]``)
|
|
||||||
"""
|
|
||||||
_tempdir = None
|
|
||||||
|
|
||||||
def __init__(self, build, source):
|
|
||||||
"""
|
|
||||||
Initialization
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`build` : ``distuils.command.build_ext.build_ext``
|
|
||||||
builder instance
|
|
||||||
|
|
||||||
`source` : ``str``
|
|
||||||
Source of the file to compile
|
|
||||||
"""
|
|
||||||
self._tempdir = tempdir = _tempfile.mkdtemp()
|
|
||||||
src = _os.path.join(tempdir, 'conftest.c')
|
|
||||||
fp = open(src, 'w')
|
|
||||||
try:
|
|
||||||
fp.write(source)
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
self.src = src
|
|
||||||
self.compiler = compiler = build.compiler
|
|
||||||
self.target = _os.path.join(tempdir, 'conftest')
|
|
||||||
self.obj = compiler.object_filenames([src], output_dir=tempdir)
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
""" Destruction """
|
|
||||||
self.destroy()
|
|
||||||
|
|
||||||
def destroy(self):
|
|
||||||
""" Destroy the conftest leftovers on disk """
|
|
||||||
tempdir, self._tempdir = self._tempdir, None
|
|
||||||
if tempdir is not None:
|
|
||||||
_shutil.rmtree(tempdir)
|
|
||||||
|
|
||||||
def compile(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Compile the conftest
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`kwargs` : ``dict``
|
|
||||||
Optional keyword parameters for the compiler call
|
|
||||||
|
|
||||||
:Return: Was the compilation successful?
|
|
||||||
:Rtype: ``bool``
|
|
||||||
"""
|
|
||||||
kwargs['output_dir'] = self._tempdir
|
|
||||||
try:
|
|
||||||
self.compiler.compile([self.src], **kwargs)
|
|
||||||
except _distutils_errors.CompileError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def link(self, **kwargs):
|
|
||||||
r"""
|
|
||||||
Link the conftest
|
|
||||||
|
|
||||||
Before you can link the conftest objects they need to be `compile`\d.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`kwargs` : ``dict``
|
|
||||||
Optional keyword parameters for the linker call
|
|
||||||
|
|
||||||
:Return: Was the linking successful?
|
|
||||||
:Rtype: ``bool``
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
self.compiler.link_executable(self.obj, self.target, **kwargs)
|
|
||||||
except _distutils_errors.LinkError:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def pipe(self, mode="r"):
|
|
||||||
r"""
|
|
||||||
Execute the conftest binary and connect to it using a pipe
|
|
||||||
|
|
||||||
Before you can pipe to or from the conftest binary it needs to
|
|
||||||
be `link`\ed.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`mode` : ``str``
|
|
||||||
Pipe mode - r/w
|
|
||||||
|
|
||||||
:Return: The open pipe
|
|
||||||
:Rtype: ``file``
|
|
||||||
"""
|
|
||||||
return _os.popen(self.compiler.executable_filename(self.target), mode)
|
|
@ -1,28 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 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.
|
|
||||||
"""
|
|
||||||
=====================
|
|
||||||
Package _setup.make
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Make tools, not distributed.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
# pylint: disable = W0611
|
|
||||||
from _setup.make._make import main, fail, warn, fatal, Target
|
|
@ -1,338 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
==================
|
|
||||||
Simple make base
|
|
||||||
==================
|
|
||||||
|
|
||||||
Simple make base.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import term as _term
|
|
||||||
|
|
||||||
|
|
||||||
class Failure(SystemExit):
|
|
||||||
""" Failure exception """
|
|
||||||
|
|
||||||
|
|
||||||
def fail(reason):
|
|
||||||
""" Fail for a reason """
|
|
||||||
raise Failure(reason)
|
|
||||||
|
|
||||||
|
|
||||||
def warn(message, name=None):
|
|
||||||
""" Warn """
|
|
||||||
_term.red("%(NAME)sWarning: %(msg)s",
|
|
||||||
NAME=name and "%s:" % name or '', msg=message
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def fatal(reason):
|
|
||||||
""" Fatal error, immediate stop """
|
|
||||||
print(reason, file=_sys.stderr)
|
|
||||||
_sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
class Target(object):
|
|
||||||
""" Target base class """
|
|
||||||
NAME = None
|
|
||||||
DEPS = None
|
|
||||||
HIDDEN = False
|
|
||||||
|
|
||||||
ERROR = None
|
|
||||||
|
|
||||||
def __init__(self, runner):
|
|
||||||
""" Base __init__ """
|
|
||||||
self.runner = runner
|
|
||||||
self.init()
|
|
||||||
|
|
||||||
def init(self):
|
|
||||||
""" Default init hook """
|
|
||||||
pass
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
""" Default run hook """
|
|
||||||
pass
|
|
||||||
|
|
||||||
def clean(self, scm=True, dist=False):
|
|
||||||
""" Default clean hook """
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class _Runner(object):
|
|
||||||
""" Runner """
|
|
||||||
|
|
||||||
def __init__(self, *targetscollection):
|
|
||||||
""" Initialization """
|
|
||||||
tdict = {}
|
|
||||||
if not targetscollection:
|
|
||||||
import __main__
|
|
||||||
targetscollection = [__main__]
|
|
||||||
|
|
||||||
from _setup.make import default_targets
|
|
||||||
if default_targets not in targetscollection:
|
|
||||||
targetscollection.append(default_targets)
|
|
||||||
|
|
||||||
for targets in targetscollection:
|
|
||||||
for value in list(vars(targets).values()):
|
|
||||||
if isinstance(value, type) and issubclass(value, Target) and \
|
|
||||||
value.NAME is not None:
|
|
||||||
if value.NAME in tdict:
|
|
||||||
if issubclass(value, tdict[value.NAME]):
|
|
||||||
pass # override base target
|
|
||||||
elif issubclass(tdict[value.NAME], value):
|
|
||||||
continue # found base later. ignore
|
|
||||||
else:
|
|
||||||
warn('Ambiguous target name', value.NAME)
|
|
||||||
continue
|
|
||||||
tdict[value.NAME] = value
|
|
||||||
self._tdict = tdict
|
|
||||||
self._itdict = {}
|
|
||||||
|
|
||||||
def print_help(self):
|
|
||||||
""" Print make help """
|
|
||||||
import textwrap as _textwrap
|
|
||||||
|
|
||||||
targets = self.targetinfo()
|
|
||||||
keys = []
|
|
||||||
for key, info in list(targets.items()):
|
|
||||||
if not info['hide']:
|
|
||||||
keys.append(key)
|
|
||||||
keys.sort()
|
|
||||||
length = max(list(map(len, keys)))
|
|
||||||
info = []
|
|
||||||
for key in keys:
|
|
||||||
info.append("%s%s" % (
|
|
||||||
(key + " " * length)[:length + 2],
|
|
||||||
_textwrap.fill(
|
|
||||||
targets[key]['desc'].strip(),
|
|
||||||
subsequent_indent=" " * (length + 2)
|
|
||||||
),
|
|
||||||
))
|
|
||||||
print("Available targets:\n\n" + "\n".join(info))
|
|
||||||
|
|
||||||
def targetinfo(self):
|
|
||||||
""" Extract target information """
|
|
||||||
result = {}
|
|
||||||
for name, cls in list(self._tdict.items()):
|
|
||||||
result[name] = {
|
|
||||||
'desc': cls.__doc__ or "no description",
|
|
||||||
'hide': cls.HIDDEN,
|
|
||||||
'deps': cls.DEPS or (),
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _topleveltargets(self):
|
|
||||||
""" Find all top level targets """
|
|
||||||
rev = {} # key is a dep of [values]
|
|
||||||
all_ = self.targetinfo()
|
|
||||||
for target, info in list(all_.items()):
|
|
||||||
for dep in info['deps']:
|
|
||||||
if dep not in all_:
|
|
||||||
fatal("Unknown target '%s' (dep of %s) -> exit" % (
|
|
||||||
dep, target
|
|
||||||
))
|
|
||||||
rev.setdefault(dep, []).append(target)
|
|
||||||
return [target for target, info in list(rev.items()) if not info]
|
|
||||||
|
|
||||||
def _run(self, target, seen=None):
|
|
||||||
""" Run a target """
|
|
||||||
if target.DEPS:
|
|
||||||
self(*target.DEPS, **{'seen': seen})
|
|
||||||
|
|
||||||
if not target.HIDDEN:
|
|
||||||
_term.yellow(">>> %(name)s", name=target.NAME)
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = target.run()
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
result, target.ERROR = False, "^C -> exit"
|
|
||||||
except Failure as e:
|
|
||||||
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
|
|
||||||
except (SystemExit, MemoryError):
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
import traceback
|
|
||||||
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
|
|
||||||
traceback.format_exception(*_sys.exc_info())
|
|
||||||
))
|
|
||||||
result = False
|
|
||||||
else:
|
|
||||||
if result is None:
|
|
||||||
result = True
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _clean(self, target, scm, dist, seen=None):
|
|
||||||
""" Run a target """
|
|
||||||
if target.DEPS:
|
|
||||||
self.run_clean(
|
|
||||||
*target.DEPS, **{'scm': scm, 'dist': dist, 'seen': seen}
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
|
||||||
result = target.clean(scm, dist)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
result, target.ERROR = False, "^C -> exit"
|
|
||||||
except Failure as e:
|
|
||||||
result, target.ERROR = False, "%s: %s" % (target.NAME, e)
|
|
||||||
except (SystemExit, MemoryError):
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
import traceback
|
|
||||||
target.ERROR = "%s errored:\n%s" % (target.NAME, ''.join(
|
|
||||||
traceback.format_exception(*_sys.exc_info())
|
|
||||||
))
|
|
||||||
result = False
|
|
||||||
else:
|
|
||||||
if result is None:
|
|
||||||
result = True
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _make_init(self, seen):
|
|
||||||
""" Make init mapper """
|
|
||||||
def init(target):
|
|
||||||
""" Return initialized target """
|
|
||||||
if target not in seen:
|
|
||||||
try:
|
|
||||||
seen[target] = self._tdict[target](self)
|
|
||||||
except KeyError:
|
|
||||||
fatal("Unknown target '%s' -> exit" % target)
|
|
||||||
else:
|
|
||||||
seen[target] = None
|
|
||||||
return seen[target]
|
|
||||||
return init
|
|
||||||
|
|
||||||
def run_clean(self, *targets, **kwargs):
|
|
||||||
""" Run targets """
|
|
||||||
def pop(name, default=None):
|
|
||||||
""" Pop """
|
|
||||||
if name in kwargs:
|
|
||||||
value = kwargs[name]
|
|
||||||
del kwargs[name]
|
|
||||||
if value is None:
|
|
||||||
return default
|
|
||||||
return value
|
|
||||||
else:
|
|
||||||
return default
|
|
||||||
seen = pop('seen', {})
|
|
||||||
scm = pop('scm', True)
|
|
||||||
dist = pop('dist', False)
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError('Unknown keyword parameters')
|
|
||||||
|
|
||||||
if not targets:
|
|
||||||
top_targets = self._topleveltargets()
|
|
||||||
targets = self.targetinfo()
|
|
||||||
for item in top_targets:
|
|
||||||
del targets[item]
|
|
||||||
targets = list(targets.keys())
|
|
||||||
targets.sort()
|
|
||||||
top_targets.sort()
|
|
||||||
targets = top_targets + targets
|
|
||||||
|
|
||||||
init = self._make_init(seen)
|
|
||||||
for name in targets:
|
|
||||||
target = init(name)
|
|
||||||
if target is not None:
|
|
||||||
if not self._clean(target, scm=scm, dist=dist, seen=seen):
|
|
||||||
msg = target.ERROR
|
|
||||||
if msg is None:
|
|
||||||
msg = "Clean target %s returned error -> exit" % name
|
|
||||||
fatal(msg)
|
|
||||||
|
|
||||||
def __call__(self, *targets, **kwargs):
|
|
||||||
""" Run targets """
|
|
||||||
if 'seen' in kwargs:
|
|
||||||
seen = kwargs['seen']
|
|
||||||
del kwargs['seen']
|
|
||||||
else:
|
|
||||||
seen = None
|
|
||||||
if seen is None:
|
|
||||||
seen = self._itdict
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError('Unknown keyword parameters')
|
|
||||||
|
|
||||||
init = self._make_init(seen)
|
|
||||||
for name in targets:
|
|
||||||
target = init(name)
|
|
||||||
if target is not None:
|
|
||||||
if not self._run(target, seen):
|
|
||||||
msg = target.ERROR
|
|
||||||
if msg is None:
|
|
||||||
msg = "Target %s returned error -> exit" % name
|
|
||||||
fatal(msg)
|
|
||||||
|
|
||||||
|
|
||||||
def main(*args, **kwargs):
|
|
||||||
"""
|
|
||||||
main(argv=None, *args, name=None)
|
|
||||||
|
|
||||||
Main start point. This function parses the command line and executes the
|
|
||||||
targets given through `argv`. If there are no targets given, a help output
|
|
||||||
is generated.
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`argv` : sequence
|
|
||||||
Command line arguments. If omitted or ``None``, they are picked from
|
|
||||||
``sys.argv``.
|
|
||||||
|
|
||||||
`args` : ``tuple``
|
|
||||||
The list of modules with targets. If omitted, ``__main__``
|
|
||||||
is imported and treated as target module. Additionally the mechanism
|
|
||||||
always adds the `_setup.make` module (this one) to the list in order
|
|
||||||
to grab some default targets.
|
|
||||||
|
|
||||||
`name` : ``str``
|
|
||||||
Name of the executing module. If omitted or ``None``, ``'__main__'``
|
|
||||||
is assumed. If the final name is not ``'__main__'``, the function
|
|
||||||
returns immediately.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
name = kwargs['name']
|
|
||||||
except KeyError:
|
|
||||||
name = '__main__'
|
|
||||||
else:
|
|
||||||
del kwargs['name']
|
|
||||||
if name is None:
|
|
||||||
name = '__main__'
|
|
||||||
|
|
||||||
try:
|
|
||||||
argv = kwargs['argv']
|
|
||||||
except KeyError:
|
|
||||||
if not args:
|
|
||||||
args = (None,)
|
|
||||||
else:
|
|
||||||
del kwargs['argv']
|
|
||||||
args = (argv,) + args
|
|
||||||
|
|
||||||
if kwargs:
|
|
||||||
raise TypeError("Unrecognized keyword arguments for main()")
|
|
||||||
|
|
||||||
if name == '__main__':
|
|
||||||
argv, args = args[0], args[1:]
|
|
||||||
if argv is None:
|
|
||||||
argv = _sys.argv[1:]
|
|
||||||
|
|
||||||
runner = _Runner(*args)
|
|
||||||
if argv:
|
|
||||||
runner(*argv)
|
|
||||||
else:
|
|
||||||
runner.print_help()
|
|
@ -1,110 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
==================
|
|
||||||
Simple make base
|
|
||||||
==================
|
|
||||||
|
|
||||||
Simple make base.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import make as _make
|
|
||||||
from _setup import shell as _shell
|
|
||||||
|
|
||||||
|
|
||||||
class MakefileTarget(_make.Target):
|
|
||||||
""" Create a make file """
|
|
||||||
NAME = 'makefile'
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
def escape(value):
|
|
||||||
""" Escape for make and shell """
|
|
||||||
return '"%s"' % value.replace(
|
|
||||||
'\\', '\\\\').replace(
|
|
||||||
'"', '\\"').replace(
|
|
||||||
'$', '\\$$')
|
|
||||||
def decorate(line, prefix='# ', width=78, char='~', padding=' '):
|
|
||||||
""" Decorate a line """
|
|
||||||
line = line.center(width - len(prefix))
|
|
||||||
return '%s%s%s%s%s%s' % (
|
|
||||||
prefix,
|
|
||||||
char * (len(line) - len(line.lstrip()) - len(padding)),
|
|
||||||
padding,
|
|
||||||
line.strip(),
|
|
||||||
padding,
|
|
||||||
char * (len(line) - len(line.rstrip()) - len(padding)),
|
|
||||||
)
|
|
||||||
|
|
||||||
python = escape(_sys.executable)
|
|
||||||
script = escape(_sys.argv[0])
|
|
||||||
targets = self.runner.targetinfo()
|
|
||||||
names = []
|
|
||||||
for name, info in list(targets.items()):
|
|
||||||
if not info['hide']:
|
|
||||||
names.append(name)
|
|
||||||
names.sort()
|
|
||||||
|
|
||||||
fp = open(_shell.native('Makefile'), 'w')
|
|
||||||
print(decorate("Generated Makefile, DO NOT EDIT"), file=fp)
|
|
||||||
print(decorate("python %s %s" % (
|
|
||||||
_os.path.basename(script), self.NAME
|
|
||||||
)), file=fp)
|
|
||||||
print(file=fp)
|
|
||||||
print("_default_:", file=fp)
|
|
||||||
print("\t@%s %s" % (python, script), file=fp)
|
|
||||||
for name in names:
|
|
||||||
print("\n", file=fp)
|
|
||||||
print("# %s" % \
|
|
||||||
targets[name]['desc'].splitlines()[0].strip(), file=fp)
|
|
||||||
print("%s:" % name, file=fp)
|
|
||||||
print("\t@%s %s %s" % (python, script, escape(name)), file=fp)
|
|
||||||
print(file=fp)
|
|
||||||
extension = self.extend(names)
|
|
||||||
if extension is not None:
|
|
||||||
print(extension, file=fp)
|
|
||||||
print(file=fp)
|
|
||||||
print(".PHONY: _default_ %s\n\n" % ' '.join(names), file=fp)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
def extend(self, names):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CleanTarget(_make.Target):
|
|
||||||
""" Clean the mess """
|
|
||||||
NAME = 'clean'
|
|
||||||
_scm, _dist = True, False
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
self.runner.run_clean(scm=self._scm, dist=self._dist)
|
|
||||||
|
|
||||||
|
|
||||||
class DistCleanTarget(CleanTarget):
|
|
||||||
""" Clean as freshly unpacked dist package """
|
|
||||||
NAME = 'distclean'
|
|
||||||
_scm, _dist = False, True
|
|
||||||
|
|
||||||
|
|
||||||
class ExtraCleanTarget(CleanTarget):
|
|
||||||
""" Clean everything """
|
|
||||||
NAME = 'extraclean'
|
|
||||||
_scm, _dist = True, True
|
|
@ -1,326 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2007 - 2013
|
|
||||||
# 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.
|
|
||||||
"""
|
|
||||||
==================
|
|
||||||
Standard targets
|
|
||||||
==================
|
|
||||||
|
|
||||||
Standard targets.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import os as _os
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import dist as _dist
|
|
||||||
from _setup import make as _make
|
|
||||||
from _setup import shell as _shell
|
|
||||||
from _setup import term as _term
|
|
||||||
|
|
||||||
|
|
||||||
class Distribution(_make.Target):
|
|
||||||
""" Build a distribution """
|
|
||||||
NAME = "dist"
|
|
||||||
DEPS = ["MANIFEST"]
|
|
||||||
|
|
||||||
_dist, _ebuilds, _changes = None, None, None
|
|
||||||
|
|
||||||
def init(self):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
exts = self.dist_pkg()
|
|
||||||
digests = self.digest_files(exts)
|
|
||||||
self.sign_digests(digests)
|
|
||||||
self.copy_ebuilds()
|
|
||||||
self.copy_changes()
|
|
||||||
|
|
||||||
def dist_pkg(self):
|
|
||||||
_term.green("Building package...")
|
|
||||||
_dist.run_setup("sdist", "--formats", "tar,zip",
|
|
||||||
fakeroot=_shell.frompath('fakeroot')
|
|
||||||
)
|
|
||||||
exts = ['.zip']
|
|
||||||
for name in _shell.files(self._dist, '*.tar', False):
|
|
||||||
exts.extend(self.compress(name))
|
|
||||||
_shell.rm(name)
|
|
||||||
return exts
|
|
||||||
|
|
||||||
def compress(self, filename):
|
|
||||||
""" Compress file """
|
|
||||||
ext = _os.path.splitext(filename)[1]
|
|
||||||
exts = []
|
|
||||||
exts.append('.'.join((ext, self.compress_gzip(filename))))
|
|
||||||
exts.append('.'.join((ext, self.compress_bzip2(filename))))
|
|
||||||
exts.append('.'.join((ext, self.compress_xz(filename))))
|
|
||||||
return exts
|
|
||||||
|
|
||||||
def compress_xz(self, filename):
|
|
||||||
outfilename = filename + '.xz'
|
|
||||||
self.compress_external(filename, outfilename, 'xz', '-c9')
|
|
||||||
return 'xz'
|
|
||||||
|
|
||||||
def compress_bzip2(self, filename):
|
|
||||||
outfilename = filename + '.bz2'
|
|
||||||
try:
|
|
||||||
import bz2 as _bz2
|
|
||||||
except ImportError:
|
|
||||||
self.compress_external(filename, outfilename, 'bzip2', '-c9')
|
|
||||||
else:
|
|
||||||
outfile = _bz2.BZ2File(outfilename, 'w')
|
|
||||||
self.compress_internal(filename, outfile, outfilename)
|
|
||||||
return 'bz2'
|
|
||||||
|
|
||||||
def compress_gzip(self, filename):
|
|
||||||
outfilename = filename + '.gz'
|
|
||||||
try:
|
|
||||||
import gzip as _gzip
|
|
||||||
except ImportError:
|
|
||||||
self.compress_external(filename, outfilename, 'gzip', '-c9')
|
|
||||||
else:
|
|
||||||
outfile = _gzip.GzipFile(filename, 'wb',
|
|
||||||
fileobj=open(outfilename, 'wb')
|
|
||||||
)
|
|
||||||
self.compress_internal(filename, outfile, outfilename)
|
|
||||||
return 'gz'
|
|
||||||
|
|
||||||
def compress_external(self, infile, outfile, *argv):
|
|
||||||
argv = list(argv)
|
|
||||||
argv[0] = _shell.frompath(argv[0])
|
|
||||||
if argv[0] is not None:
|
|
||||||
return not _shell.spawn(*argv, **{
|
|
||||||
'filepipe': True, 'stdin': infile, 'stdout': outfile,
|
|
||||||
})
|
|
||||||
return None
|
|
||||||
|
|
||||||
def compress_internal(self, filename, outfile, outfilename):
|
|
||||||
infile = open(filename, 'rb')
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
while 1:
|
|
||||||
chunk = infile.read(8192)
|
|
||||||
if not chunk:
|
|
||||||
break
|
|
||||||
outfile.write(chunk)
|
|
||||||
outfile.close()
|
|
||||||
except:
|
|
||||||
e = _sys.exc_info()
|
|
||||||
try:
|
|
||||||
_shell.rm(outfilename)
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
raise e[0](e[1]).with_traceback(e[2])
|
|
||||||
finally:
|
|
||||||
del e
|
|
||||||
finally:
|
|
||||||
infile.close()
|
|
||||||
|
|
||||||
def digest_files(self, exts):
|
|
||||||
""" digest files """
|
|
||||||
digests = {}
|
|
||||||
digestnames = {}
|
|
||||||
for ext in exts:
|
|
||||||
for name in _shell.files(self._dist, '*' + ext, False):
|
|
||||||
basename = _os.path.basename(name)
|
|
||||||
if basename not in digests:
|
|
||||||
digests[basename] = []
|
|
||||||
digests[basename].extend(self.digest(name))
|
|
||||||
digestname = basename[:-len(ext)]
|
|
||||||
if digestname not in digestnames:
|
|
||||||
digestnames[digestname] = []
|
|
||||||
digestnames[digestname].append(basename)
|
|
||||||
|
|
||||||
result = []
|
|
||||||
for name, basenames in digestnames.items():
|
|
||||||
result.append(_os.path.join(self._dist, name + '.digests'))
|
|
||||||
fp = open(result[-1], 'wb')
|
|
||||||
try:
|
|
||||||
fp.write(
|
|
||||||
b'\n# The file may contain MD5, SHA1 and SHA256 digests\n'
|
|
||||||
)
|
|
||||||
fp.write(b'# Check archive integrity with, e.g. md5sum -c\n')
|
|
||||||
fp.write(b'# Check digest file integrity with PGP\n\n')
|
|
||||||
basenames.sort()
|
|
||||||
for basename in basenames:
|
|
||||||
for digest in digests[basename]:
|
|
||||||
fp.write((
|
|
||||||
"%s *%s\n" % (digest, basename)).encode('utf-8')
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
def digest(self, filename):
|
|
||||||
result = []
|
|
||||||
for method in (self.md5, self.sha1, self.sha256):
|
|
||||||
digest = method(filename)
|
|
||||||
if digest is not None:
|
|
||||||
result.append(digest)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def do_digest(self, hashfunc, name, filename):
|
|
||||||
filename = _shell.native(filename)
|
|
||||||
_term.green("%(digest)s-digesting %(name)s...",
|
|
||||||
digest=name, name=_os.path.basename(filename))
|
|
||||||
fp = open(filename, 'rb')
|
|
||||||
sig = hashfunc()
|
|
||||||
block = fp.read(8192)
|
|
||||||
while block:
|
|
||||||
sig.update(block)
|
|
||||||
block = fp.read(8192)
|
|
||||||
fp.close()
|
|
||||||
return sig.hexdigest()
|
|
||||||
|
|
||||||
param = {'sig': sig.hexdigest(), 'file': _os.path.basename(filename)}
|
|
||||||
fp = open("%s.%s" % (filename, name), "w")
|
|
||||||
fp.write("%(sig)s *%(file)s\n" % param)
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def md5(self, filename):
|
|
||||||
try:
|
|
||||||
from hashlib import md5
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from md5 import new as md5
|
|
||||||
except ImportError:
|
|
||||||
_make.warn("md5 not found -> skip md5 digests", self.NAME)
|
|
||||||
return None
|
|
||||||
return self.do_digest(md5, "md5", filename)
|
|
||||||
|
|
||||||
def sha1(self, filename):
|
|
||||||
try:
|
|
||||||
from hashlib import sha1
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from sha import new as sha1
|
|
||||||
except ImportError:
|
|
||||||
_make.warn("sha1 not found -> skip sha1 digests", self.NAME)
|
|
||||||
return None
|
|
||||||
return self.do_digest(sha1, "sha1", filename)
|
|
||||||
|
|
||||||
def sha256(self, filename):
|
|
||||||
try:
|
|
||||||
from hashlib import sha256
|
|
||||||
except ImportError:
|
|
||||||
try:
|
|
||||||
from Crypto.Hash.SHA256 import new as sha256
|
|
||||||
except ImportError:
|
|
||||||
_make.warn(
|
|
||||||
"sha256 not found -> skip sha256 digests", self.NAME
|
|
||||||
)
|
|
||||||
return None
|
|
||||||
return self.do_digest(sha256, "sha256", filename)
|
|
||||||
|
|
||||||
def copy_ebuilds(self):
|
|
||||||
if self._ebuilds is not None:
|
|
||||||
for src in _shell.files(self._ebuilds, '*.ebuild'):
|
|
||||||
_shell.cp(src, self._dist)
|
|
||||||
|
|
||||||
def copy_changes(self):
|
|
||||||
if self._changes is not None:
|
|
||||||
_shell.cp(self._changes, self._dist)
|
|
||||||
|
|
||||||
def sign_digests(self, digests):
|
|
||||||
for digest in digests:
|
|
||||||
self.sign(digest, detach=False)
|
|
||||||
|
|
||||||
def sign(self, filename, detach=True):
|
|
||||||
filename = _shell.native(filename)
|
|
||||||
try:
|
|
||||||
from pyme import core, errors
|
|
||||||
from pyme.constants.sig import mode
|
|
||||||
except ImportError:
|
|
||||||
return self.sign_external(filename, detach=detach)
|
|
||||||
|
|
||||||
_term.green("signing %(name)s...", name=_os.path.basename(filename))
|
|
||||||
sigmode = [mode.CLEAR, mode.DETACH][bool(detach)]
|
|
||||||
fp = core.Data(file=filename)
|
|
||||||
sig = core.Data()
|
|
||||||
try:
|
|
||||||
c = core.Context()
|
|
||||||
except errors.GPGMEError:
|
|
||||||
return self.sign_external(filename, detach=detach)
|
|
||||||
c.set_armor(1)
|
|
||||||
try:
|
|
||||||
c.op_sign(fp, sig, sigmode)
|
|
||||||
except errors.GPGMEError as e:
|
|
||||||
_make.fail(str(e))
|
|
||||||
|
|
||||||
sig.seek(0, 0)
|
|
||||||
if detach:
|
|
||||||
open("%s.asc" % filename, "w").write(sig.read())
|
|
||||||
else:
|
|
||||||
open(filename, "w").write(sig.read())
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def sign_external(self, filename, detach=True):
|
|
||||||
""" Sign calling gpg """
|
|
||||||
gpg = _shell.frompath('gpg')
|
|
||||||
if gpg is None:
|
|
||||||
_make.warn('GPG not found -> cannot sign')
|
|
||||||
return False
|
|
||||||
if detach:
|
|
||||||
_shell.spawn(gpg,
|
|
||||||
'--armor',
|
|
||||||
'--output', filename + '.asc',
|
|
||||||
'--detach-sign',
|
|
||||||
'--',
|
|
||||||
filename,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
_shell.spawn(gpg,
|
|
||||||
'--output', filename + '.signed',
|
|
||||||
'--clearsign',
|
|
||||||
'--',
|
|
||||||
filename,
|
|
||||||
)
|
|
||||||
_os.rename(filename + '.signed', filename)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def clean(self, scm, dist):
|
|
||||||
_term.green("Removing dist files...")
|
|
||||||
_shell.rm_rf(self._dist)
|
|
||||||
|
|
||||||
|
|
||||||
class Manifest(_make.Target):
|
|
||||||
""" Create manifest """
|
|
||||||
NAME = "MANIFEST"
|
|
||||||
HIDDEN = True
|
|
||||||
DEPS = ["doc"]
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
_term.green("Creating %(name)s...", name=self.NAME)
|
|
||||||
dest = _shell.native(self.NAME)
|
|
||||||
dest = open(dest, 'w')
|
|
||||||
for name in self.manifest_names():
|
|
||||||
dest.write("%s\n" % name)
|
|
||||||
dest.close()
|
|
||||||
|
|
||||||
def manifest_names(self):
|
|
||||||
import setup
|
|
||||||
for item in setup.manifest():
|
|
||||||
yield item
|
|
||||||
|
|
||||||
def clean(self, scm, dist):
|
|
||||||
""" Clean manifest """
|
|
||||||
if scm:
|
|
||||||
_term.green("Removing MANIFEST")
|
|
||||||
_shell.rm(self.NAME)
|
|
@ -1,420 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2007 - 2013
|
|
||||||
# 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.
|
|
||||||
"""
|
|
||||||
===================
|
|
||||||
Main setup runner
|
|
||||||
===================
|
|
||||||
|
|
||||||
This module provides a wrapper around the distutils core setup.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import configparser as _config_parser
|
|
||||||
from distutils import core as _core
|
|
||||||
import os as _os
|
|
||||||
import posixpath as _posixpath
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
from _setup import commands as _commands
|
|
||||||
from _setup import data as _data
|
|
||||||
from _setup import ext as _ext
|
|
||||||
from _setup import util as _util
|
|
||||||
from _setup import shell as _shell
|
|
||||||
|
|
||||||
|
|
||||||
def check_python_version(impl, version_min, version_max):
|
|
||||||
""" Check python version """
|
|
||||||
if impl == 'python':
|
|
||||||
version_info = _sys.version_info
|
|
||||||
elif impl == 'pypy':
|
|
||||||
version_info = getattr(_sys, 'pypy_version_info', None)
|
|
||||||
if not version_info:
|
|
||||||
return
|
|
||||||
elif impl == 'jython':
|
|
||||||
if not 'java' in _sys.platform.lower():
|
|
||||||
return
|
|
||||||
version_info = _sys.version_info
|
|
||||||
else:
|
|
||||||
raise AssertionError("impl not in ('python', 'pypy', 'jython')")
|
|
||||||
|
|
||||||
pyversion = list(map(int, version_info[:3]))
|
|
||||||
if version_min:
|
|
||||||
min_required = list(
|
|
||||||
map(int, '.'.join((version_min, '0.0.0')).split('.')[:3])
|
|
||||||
)
|
|
||||||
if pyversion < min_required:
|
|
||||||
raise EnvironmentError("Need at least %s %s (vs. %s)" % (
|
|
||||||
impl, version_min, '.'.join(map(str, pyversion))
|
|
||||||
))
|
|
||||||
if version_max:
|
|
||||||
max_required = list(map(int, version_max.split('.')))
|
|
||||||
max_required[-1] += 1
|
|
||||||
if pyversion >= max_required:
|
|
||||||
raise EnvironmentError("Need at max %s %s (vs. %s)" % (
|
|
||||||
impl,
|
|
||||||
version_max,
|
|
||||||
'.'.join(map(str, pyversion))
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
def find_description(docs):
|
|
||||||
"""
|
|
||||||
Determine the package description from DESCRIPTION
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`docs` : ``dict``
|
|
||||||
Docs config section
|
|
||||||
|
|
||||||
:Return: Tuple of summary, description and license
|
|
||||||
(``('summary', 'description', 'license')``)
|
|
||||||
(all may be ``None``)
|
|
||||||
:Rtype: ``tuple``
|
|
||||||
"""
|
|
||||||
summary = None
|
|
||||||
filename = docs.get('meta.summary', 'SUMMARY').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
summary = fp.read().strip().splitlines()[0].rstrip()
|
|
||||||
except IndexError:
|
|
||||||
summary = ''
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
description = None
|
|
||||||
filename = docs.get('meta.description', 'DESCRIPTION').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
description = fp.read().rstrip()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
|
|
||||||
if summary is None and description:
|
|
||||||
from docutils import core
|
|
||||||
summary = core.publish_parts(
|
|
||||||
source=description,
|
|
||||||
source_path=filename,
|
|
||||||
writer_name='html',
|
|
||||||
)['title'].encode('utf-8')
|
|
||||||
|
|
||||||
return summary, description
|
|
||||||
|
|
||||||
|
|
||||||
def find_classifiers(docs):
|
|
||||||
"""
|
|
||||||
Determine classifiers from CLASSIFIERS
|
|
||||||
|
|
||||||
:return: List of classifiers (``['classifier', ...]``)
|
|
||||||
:rtype: ``list``
|
|
||||||
"""
|
|
||||||
filename = docs.get('meta.classifiers', 'CLASSIFIERS').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
content = fp.read()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
content = [item.strip() for item in content.splitlines()]
|
|
||||||
return [item for item in content if item and not item.startswith('#')]
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def find_provides(docs):
|
|
||||||
"""
|
|
||||||
Determine provides from PROVIDES
|
|
||||||
|
|
||||||
:return: List of provides (``['provides', ...]``)
|
|
||||||
:rtype: ``list``
|
|
||||||
"""
|
|
||||||
filename = docs.get('meta.provides', 'PROVIDES').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
content = fp.read()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
content = [item.strip() for item in content.splitlines()]
|
|
||||||
return [item for item in content if item and not item.startswith('#')]
|
|
||||||
return []
|
|
||||||
|
|
||||||
|
|
||||||
def find_license(docs):
|
|
||||||
"""
|
|
||||||
Determine license from LICENSE
|
|
||||||
|
|
||||||
:return: License text
|
|
||||||
:rtype: ``str``
|
|
||||||
"""
|
|
||||||
filename = docs.get('meta.license', 'LICENSE').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
fp = open(filename)
|
|
||||||
try:
|
|
||||||
return fp.read().rstrip()
|
|
||||||
finally:
|
|
||||||
fp.close()
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def find_packages(manifest):
|
|
||||||
""" Determine packages and subpackages """
|
|
||||||
packages = {}
|
|
||||||
collect = manifest.get('packages.collect', '').split()
|
|
||||||
lib = manifest.get('packages.lib', '.')
|
|
||||||
try:
|
|
||||||
sep = _os.path.sep
|
|
||||||
except AttributeError:
|
|
||||||
sep = _os.path.join('1', '2')[1:-1]
|
|
||||||
for root in collect:
|
|
||||||
for dirpath, _, filenames in _shell.walk(_os.path.join(lib, root)):
|
|
||||||
if dirpath.find('.svn') >= 0 or dirpath.find('.git') >= 0:
|
|
||||||
continue
|
|
||||||
if '__init__.py' in filenames:
|
|
||||||
packages[
|
|
||||||
_os.path.normpath(dirpath).replace(sep, '.')
|
|
||||||
] = None
|
|
||||||
packages = list(packages.keys())
|
|
||||||
packages.sort()
|
|
||||||
return packages
|
|
||||||
|
|
||||||
|
|
||||||
def find_data(name, docs):
|
|
||||||
""" Determine data files """
|
|
||||||
result = []
|
|
||||||
if docs.get('extra', '').strip():
|
|
||||||
result.append(_data.Documentation(docs['extra'].split(),
|
|
||||||
prefix='share/doc/%s' % name,
|
|
||||||
))
|
|
||||||
if docs.get('examples.dir', '').strip():
|
|
||||||
tpl = ['recursive-include %s *' % docs['examples.dir']]
|
|
||||||
if docs.get('examples.ignore', '').strip():
|
|
||||||
tpl.extend(["global-exclude %s" % item
|
|
||||||
for item in docs['examples.ignore'].split()
|
|
||||||
])
|
|
||||||
strip = int(docs.get('examples.strip', '') or 0)
|
|
||||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
|
||||||
'strip': strip,
|
|
||||||
'prefix': 'share/doc/%s' % name,
|
|
||||||
'preserve': 1,
|
|
||||||
}))
|
|
||||||
if docs.get('userdoc.dir', '').strip():
|
|
||||||
tpl = ['recursive-include %s *' % docs['userdoc.dir']]
|
|
||||||
if docs.get('userdoc.ignore', '').strip():
|
|
||||||
tpl.extend(["global-exclude %s" % item
|
|
||||||
for item in docs['userdoc.ignore'].split()
|
|
||||||
])
|
|
||||||
strip = int(docs.get('userdoc.strip', '') or 0)
|
|
||||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
|
||||||
'strip': strip,
|
|
||||||
'prefix': 'share/doc/%s' % name,
|
|
||||||
'preserve': 1,
|
|
||||||
}))
|
|
||||||
if docs.get('apidoc.dir', '').strip():
|
|
||||||
tpl = ['recursive-include %s *' % docs['apidoc.dir']]
|
|
||||||
if docs.get('apidoc.ignore', '').strip():
|
|
||||||
tpl.extend(["global-exclude %s" % item
|
|
||||||
for item in docs['apidoc.ignore'].split()
|
|
||||||
])
|
|
||||||
strip = int(docs.get('apidoc.strip', '') or 0)
|
|
||||||
result.append(_data.Documentation.from_templates(*tpl, **{
|
|
||||||
'strip': strip,
|
|
||||||
'prefix': 'share/doc/%s' % name,
|
|
||||||
'preserve': 1,
|
|
||||||
}))
|
|
||||||
if docs.get('man', '').strip():
|
|
||||||
result.extend(_data.Manpages.dispatch(docs['man'].split()))
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def make_manifest(manifest, config, docs, kwargs):
|
|
||||||
""" Create file list to pack up """
|
|
||||||
# pylint: disable = R0912
|
|
||||||
kwargs = kwargs.copy()
|
|
||||||
kwargs['script_args'] = ['install']
|
|
||||||
kwargs['packages'] = list(kwargs.get('packages') or ()) + [
|
|
||||||
'_setup', '_setup.py2', '_setup.py3',
|
|
||||||
] + list(manifest.get('packages.extra', '').split() or ())
|
|
||||||
_core._setup_stop_after = "commandline"
|
|
||||||
try:
|
|
||||||
dist = _core.setup(**kwargs)
|
|
||||||
finally:
|
|
||||||
_core._setup_stop_after = None
|
|
||||||
|
|
||||||
result = ['MANIFEST', 'PKG-INFO', 'setup.py'] + list(config)
|
|
||||||
# TODO: work with default values:
|
|
||||||
for key in ('classifiers', 'description', 'summary', 'provides',
|
|
||||||
'license'):
|
|
||||||
filename = docs.get('meta.' + key, '').strip()
|
|
||||||
if filename and _os.path.isfile(filename):
|
|
||||||
result.append(filename)
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("build_py")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
#from pprint import pprint; pprint(("build_py", cmd.get_source_files()))
|
|
||||||
for item in cmd.get_source_files():
|
|
||||||
result.append(_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
))
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("build_ext")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
#from pprint import pprint; pprint(("build_ext", cmd.get_source_files()))
|
|
||||||
for item in cmd.get_source_files():
|
|
||||||
result.append(_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
))
|
|
||||||
for ext in cmd.extensions:
|
|
||||||
if ext.depends:
|
|
||||||
result.extend([_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
) for item in ext.depends])
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("build_clib")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
if cmd.libraries:
|
|
||||||
#import pprint; pprint.pprint(("build_clib", cmd.get_source_files()))
|
|
||||||
for item in cmd.get_source_files():
|
|
||||||
result.append(_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
))
|
|
||||||
for lib in cmd.libraries:
|
|
||||||
if lib[1].get('depends'):
|
|
||||||
result.extend([_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
) for item in lib[1]['depends']])
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("build_scripts")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
#import pprint; pprint.pprint(("build_scripts", cmd.get_source_files()))
|
|
||||||
if cmd.get_source_files():
|
|
||||||
for item in cmd.get_source_files():
|
|
||||||
result.append(_posixpath.sep.join(
|
|
||||||
_os.path.normpath(item).split(_os.path.sep)
|
|
||||||
))
|
|
||||||
|
|
||||||
cmd = dist.get_command_obj("install_data")
|
|
||||||
cmd.ensure_finalized()
|
|
||||||
#from pprint import pprint; pprint(("install_data", cmd.get_inputs()))
|
|
||||||
try:
|
|
||||||
strings = str
|
|
||||||
except NameError:
|
|
||||||
strings = (str, str)
|
|
||||||
|
|
||||||
for item in cmd.get_inputs():
|
|
||||||
if isinstance(item, strings):
|
|
||||||
result.append(item)
|
|
||||||
else:
|
|
||||||
result.extend(item[1])
|
|
||||||
|
|
||||||
for item in manifest.get('dist', '').split():
|
|
||||||
result.append(item)
|
|
||||||
if _os.path.isdir(item):
|
|
||||||
for filename in _shell.files(item):
|
|
||||||
result.append(filename)
|
|
||||||
|
|
||||||
result = list(dict([(item, None) for item in result]).keys())
|
|
||||||
result.sort()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def run(config=('package.cfg',), ext=None, script_args=None, manifest_only=0):
|
|
||||||
""" Main runner """
|
|
||||||
if ext is None:
|
|
||||||
ext = []
|
|
||||||
|
|
||||||
cfg = _util.SafeConfigParser()
|
|
||||||
cfg.read(config)
|
|
||||||
pkg = dict(cfg.items('package'))
|
|
||||||
python_min = pkg.get('python.min') or None
|
|
||||||
python_max = pkg.get('python.max') or None
|
|
||||||
check_python_version('python', python_min, python_max)
|
|
||||||
pypy_min = pkg.get('pypy.min') or None
|
|
||||||
pypy_max = pkg.get('pypy.max') or None
|
|
||||||
check_python_version('pypy', pypy_min, pypy_max)
|
|
||||||
jython_min = pkg.get('jython.min') or None
|
|
||||||
jython_max = pkg.get('jython.max') or None
|
|
||||||
check_python_version('jython', jython_min, jython_max)
|
|
||||||
|
|
||||||
manifest = dict(cfg.items('manifest'))
|
|
||||||
try:
|
|
||||||
docs = dict(cfg.items('docs'))
|
|
||||||
except _config_parser.NoSectionError:
|
|
||||||
docs = {}
|
|
||||||
|
|
||||||
summary, description = find_description(docs)
|
|
||||||
scripts = manifest.get('scripts', '').strip() or None
|
|
||||||
if scripts:
|
|
||||||
scripts = scripts.split()
|
|
||||||
modules = manifest.get('modules', '').strip() or None
|
|
||||||
if modules:
|
|
||||||
modules = modules.split()
|
|
||||||
keywords = docs.get('meta.keywords', '').strip() or None
|
|
||||||
if keywords:
|
|
||||||
keywords = keywords.split()
|
|
||||||
revision = pkg.get('version.revision', '').strip()
|
|
||||||
if revision:
|
|
||||||
revision = "-r%s" % (revision,)
|
|
||||||
|
|
||||||
kwargs = {
|
|
||||||
'name': pkg['name'],
|
|
||||||
'version': "%s%s" % (
|
|
||||||
pkg['version.number'],
|
|
||||||
["", "-dev%s" % (revision,)][_util.humanbool(
|
|
||||||
'version.dev', pkg.get('version.dev', 'false')
|
|
||||||
)],
|
|
||||||
),
|
|
||||||
'provides': find_provides(docs),
|
|
||||||
'description': summary,
|
|
||||||
'long_description': description,
|
|
||||||
'classifiers': find_classifiers(docs),
|
|
||||||
'keywords': keywords,
|
|
||||||
'author': pkg['author.name'],
|
|
||||||
'author_email': pkg['author.email'],
|
|
||||||
'maintainer': pkg.get('maintainer.name'),
|
|
||||||
'maintainer_email': pkg.get('maintainer.email'),
|
|
||||||
'url': pkg.get('url.homepage'),
|
|
||||||
'download_url': pkg.get('url.download'),
|
|
||||||
'license': find_license(docs),
|
|
||||||
'package_dir': {'': manifest.get('packages.lib', '.')},
|
|
||||||
'packages': find_packages(manifest),
|
|
||||||
'py_modules': modules,
|
|
||||||
'ext_modules': ext,
|
|
||||||
'scripts': scripts,
|
|
||||||
'script_args': script_args,
|
|
||||||
'data_files': find_data(pkg['name'], docs),
|
|
||||||
'cmdclass': {
|
|
||||||
'build' : _commands.Build,
|
|
||||||
'build_ext' : _commands.BuildExt,
|
|
||||||
'install' : _commands.Install,
|
|
||||||
'install_data': _commands.InstallData,
|
|
||||||
'install_lib' : _commands.InstallLib,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for key in ('provides',):
|
|
||||||
if key not in _core.setup_keywords:
|
|
||||||
del kwargs[key]
|
|
||||||
|
|
||||||
if manifest_only:
|
|
||||||
return make_manifest(manifest, config, docs, kwargs)
|
|
||||||
|
|
||||||
# monkey-patch crappy manifest writer away.
|
|
||||||
from distutils.command import sdist
|
|
||||||
sdist.sdist.get_file_list = sdist.sdist.read_manifest
|
|
||||||
|
|
||||||
return _core.setup(**kwargs)
|
|
@ -1,351 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 2007 - 2013
|
|
||||||
# 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.
|
|
||||||
"""
|
|
||||||
=================
|
|
||||||
Shell utilities
|
|
||||||
=================
|
|
||||||
|
|
||||||
Shell utilities.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import errno as _errno
|
|
||||||
import fnmatch as _fnmatch
|
|
||||||
import os as _os
|
|
||||||
import shutil as _shutil
|
|
||||||
import subprocess as _subprocess
|
|
||||||
import sys as _sys
|
|
||||||
import tempfile as _tempfile
|
|
||||||
|
|
||||||
cwd = _os.path.dirname(_os.path.abspath(_sys.argv[0]))
|
|
||||||
|
|
||||||
class ExitError(RuntimeError):
|
|
||||||
""" Exit error """
|
|
||||||
def __init__(self, code):
|
|
||||||
RuntimeError.__init__(self, code)
|
|
||||||
self.code = code
|
|
||||||
self.signal = None
|
|
||||||
|
|
||||||
|
|
||||||
class SignalError(ExitError):
|
|
||||||
""" Signal error """
|
|
||||||
def __init__(self, code, signal):
|
|
||||||
ExitError.__init__(self, code)
|
|
||||||
import signal as _signal
|
|
||||||
self.signal = signal
|
|
||||||
for key, val in vars(_signal).items():
|
|
||||||
if key.startswith('SIG') and not key.startswith('SIG_'):
|
|
||||||
if val == signal:
|
|
||||||
self.signalstr = key[3:]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
self.signalstr = '%04d' % signal
|
|
||||||
|
|
||||||
|
|
||||||
def native(path):
|
|
||||||
""" Convert slash path to native """
|
|
||||||
path = _os.path.sep.join(path.split('/'))
|
|
||||||
return _os.path.normpath(_os.path.join(cwd, path))
|
|
||||||
|
|
||||||
|
|
||||||
def cp(src, dest):
|
|
||||||
""" Copy src to dest """
|
|
||||||
_shutil.copy2(native(src), native(dest))
|
|
||||||
|
|
||||||
|
|
||||||
def cp_r(src, dest):
|
|
||||||
""" Copy -r src to dest """
|
|
||||||
_shutil.copytree(native(src), native(dest))
|
|
||||||
|
|
||||||
|
|
||||||
def rm(dest):
|
|
||||||
""" Remove a file """
|
|
||||||
try:
|
|
||||||
_os.unlink(native(dest))
|
|
||||||
except OSError as e:
|
|
||||||
if _errno.ENOENT != e.errno:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def rm_rf(dest):
|
|
||||||
""" Remove a tree """
|
|
||||||
dest = native(dest)
|
|
||||||
if _os.path.exists(dest):
|
|
||||||
for path in files(dest, '*'):
|
|
||||||
_os.chmod(native(path), 0o644)
|
|
||||||
_shutil.rmtree(dest)
|
|
||||||
|
|
||||||
|
|
||||||
mkstemp = _tempfile.mkstemp
|
|
||||||
|
|
||||||
|
|
||||||
def _pipespawn(argv, env):
|
|
||||||
""" Pipe spawn """
|
|
||||||
# pylint: disable = R0912
|
|
||||||
import pickle as _pickle
|
|
||||||
fd, name = mkstemp('.py')
|
|
||||||
try:
|
|
||||||
_os.write(fd, ((r"""
|
|
||||||
import os
|
|
||||||
import pickle
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
argv = pickle.loads(%(argv)s)
|
|
||||||
env = pickle.loads(%(env)s)
|
|
||||||
if 'X_JYTHON_WA_PATH' in env:
|
|
||||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
|
||||||
|
|
||||||
p = subprocess.Popen(argv, env=env)
|
|
||||||
result = p.wait()
|
|
||||||
if result < 0:
|
|
||||||
print("\n%%d 1" %% (-result))
|
|
||||||
sys.exit(2)
|
|
||||||
if result == 0:
|
|
||||||
sys.exit(0)
|
|
||||||
print("\n%%d" %% (result & 7,))
|
|
||||||
sys.exit(3)
|
|
||||||
""".strip() + "\n") % {
|
|
||||||
'argv': repr(_pickle.dumps(argv)),
|
|
||||||
'env': repr(_pickle.dumps(dict(env))),
|
|
||||||
}).encode('utf-8'))
|
|
||||||
fd, _ = None, _os.close(fd)
|
|
||||||
if _sys.platform == 'win32':
|
|
||||||
argv = []
|
|
||||||
for arg in [_sys.executable, name]:
|
|
||||||
if ' ' in arg or arg.startswith('"'):
|
|
||||||
arg = '"%s"' % arg.replace('"', '\\"')
|
|
||||||
argv.append(arg)
|
|
||||||
argv = ' '.join(argv)
|
|
||||||
shell = True
|
|
||||||
close_fds = False
|
|
||||||
else:
|
|
||||||
argv = [_sys.executable, name]
|
|
||||||
shell = False
|
|
||||||
close_fds = True
|
|
||||||
|
|
||||||
res = 0
|
|
||||||
if 'X_JYTHON_WA_PATH' in env:
|
|
||||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
|
||||||
|
|
||||||
proc = _subprocess.Popen(argv,
|
|
||||||
shell=shell,
|
|
||||||
stdin=_subprocess.PIPE,
|
|
||||||
stdout=_subprocess.PIPE,
|
|
||||||
close_fds=close_fds,
|
|
||||||
env=env,
|
|
||||||
)
|
|
||||||
try:
|
|
||||||
proc.stdin.close()
|
|
||||||
result = proc.stdout.read()
|
|
||||||
finally:
|
|
||||||
res = proc.wait()
|
|
||||||
if res != 0:
|
|
||||||
if res == 2:
|
|
||||||
signal, code = list(map(int, result.splitlines()[-1].split()))
|
|
||||||
raise SignalError(code, signal)
|
|
||||||
elif res == 3:
|
|
||||||
code = int(result.splitlines()[-1].strip())
|
|
||||||
raise ExitError(code)
|
|
||||||
raise ExitError(res)
|
|
||||||
|
|
||||||
return result.decode('latin-1')
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
if fd is not None:
|
|
||||||
_os.close(fd)
|
|
||||||
finally:
|
|
||||||
_os.unlink(name)
|
|
||||||
|
|
||||||
|
|
||||||
def _filepipespawn(infile, outfile, argv, env):
|
|
||||||
""" File Pipe spawn """
|
|
||||||
import pickle as _pickle
|
|
||||||
fd, name = mkstemp('.py')
|
|
||||||
try:
|
|
||||||
_os.write(fd, (("""
|
|
||||||
import os
|
|
||||||
import pickle
|
|
||||||
import sys
|
|
||||||
|
|
||||||
infile = pickle.loads(%(infile)s)
|
|
||||||
outfile = pickle.loads(%(outfile)s)
|
|
||||||
argv = pickle.loads(%(argv)s)
|
|
||||||
env = pickle.loads(%(env)s)
|
|
||||||
|
|
||||||
if infile is not None:
|
|
||||||
infile = open(infile, 'rb')
|
|
||||||
os.dup2(infile.fileno(), 0)
|
|
||||||
infile.close()
|
|
||||||
if outfile is not None:
|
|
||||||
outfile = open(outfile, 'wb')
|
|
||||||
os.dup2(outfile.fileno(), 1)
|
|
||||||
outfile.close()
|
|
||||||
|
|
||||||
pid = os.spawnve(os.P_NOWAIT, argv[0], argv, env)
|
|
||||||
result = os.waitpid(pid, 0)[1]
|
|
||||||
sys.exit(result & 7)
|
|
||||||
""".strip() + "\n") % {
|
|
||||||
'infile': repr(_pickle.dumps(_os.path.abspath(infile))),
|
|
||||||
'outfile': repr(_pickle.dumps(_os.path.abspath(outfile))),
|
|
||||||
'argv': repr(_pickle.dumps(argv)),
|
|
||||||
'env': repr(_pickle.dumps(env)),
|
|
||||||
}))
|
|
||||||
fd, _ = None, _os.close(fd)
|
|
||||||
if _sys.platform == 'win32':
|
|
||||||
argv = []
|
|
||||||
for arg in [_sys.executable, name]:
|
|
||||||
if ' ' in arg or arg.startswith('"'):
|
|
||||||
arg = '"%s"' % arg.replace('"', '\\"')
|
|
||||||
argv.append(arg)
|
|
||||||
argv = ' '.join(argv)
|
|
||||||
close_fds = False
|
|
||||||
shell = True
|
|
||||||
else:
|
|
||||||
argv = [_sys.executable, name]
|
|
||||||
close_fds = True
|
|
||||||
shell = False
|
|
||||||
|
|
||||||
p = _subprocess.Popen(
|
|
||||||
argv, env=env, shell=shell, close_fds=close_fds
|
|
||||||
)
|
|
||||||
return p.wait()
|
|
||||||
finally:
|
|
||||||
try:
|
|
||||||
if fd is not None:
|
|
||||||
_os.close(fd)
|
|
||||||
finally:
|
|
||||||
_os.unlink(name)
|
|
||||||
|
|
||||||
|
|
||||||
def spawn(*argv, **kwargs):
|
|
||||||
""" Spawn a process """
|
|
||||||
if _sys.platform == 'win32':
|
|
||||||
newargv = []
|
|
||||||
for arg in argv:
|
|
||||||
if not arg or ' ' in arg or arg.startswith('"'):
|
|
||||||
arg = '"%s"' % arg.replace('"', '\\"')
|
|
||||||
newargv.append(arg)
|
|
||||||
argv = newargv
|
|
||||||
close_fds = False
|
|
||||||
shell = True
|
|
||||||
else:
|
|
||||||
close_fds = True
|
|
||||||
shell = False
|
|
||||||
|
|
||||||
env = kwargs.get('env')
|
|
||||||
if env is None:
|
|
||||||
env = dict(_os.environ)
|
|
||||||
if 'X_JYTHON_WA_PATH' in env:
|
|
||||||
env['PATH'] = env['X_JYTHON_WA_PATH']
|
|
||||||
|
|
||||||
echo = kwargs.get('echo')
|
|
||||||
if echo:
|
|
||||||
print(' '.join(argv))
|
|
||||||
filepipe = kwargs.get('filepipe')
|
|
||||||
if filepipe:
|
|
||||||
return _filepipespawn(
|
|
||||||
kwargs.get('stdin'), kwargs.get('stdout'), argv, env
|
|
||||||
)
|
|
||||||
pipe = kwargs.get('stdout')
|
|
||||||
if pipe:
|
|
||||||
return _pipespawn(argv, env)
|
|
||||||
|
|
||||||
p = _subprocess.Popen(argv, env=env, shell=shell, close_fds=close_fds)
|
|
||||||
return p.wait()
|
|
||||||
|
|
||||||
|
|
||||||
walk = _os.walk
|
|
||||||
|
|
||||||
|
|
||||||
def files(base, wildcard='[!.]*', recursive=1, prune=('.git', '.svn', 'CVS')):
|
|
||||||
""" Determine a filelist """
|
|
||||||
for dirpath, dirnames, filenames in walk(native(base)):
|
|
||||||
for item in prune:
|
|
||||||
if item in dirnames:
|
|
||||||
dirnames.remove(item)
|
|
||||||
|
|
||||||
filenames.sort()
|
|
||||||
for name in _fnmatch.filter(filenames, wildcard):
|
|
||||||
dest = _os.path.join(dirpath, name)
|
|
||||||
if dest.startswith(cwd):
|
|
||||||
dest = dest.replace(cwd, '', 1)
|
|
||||||
aslist = []
|
|
||||||
head, tail = _os.path.split(dest)
|
|
||||||
while tail:
|
|
||||||
aslist.append(tail)
|
|
||||||
head, tail = _os.path.split(head)
|
|
||||||
aslist.reverse()
|
|
||||||
dest = '/'.join(aslist)
|
|
||||||
yield dest
|
|
||||||
|
|
||||||
if not recursive:
|
|
||||||
break
|
|
||||||
dirnames.sort()
|
|
||||||
|
|
||||||
|
|
||||||
def dirs(base, wildcard='[!.]*', recursive=1, prune=('.git', '.svn', 'CVS')):
|
|
||||||
""" Determine a filelist """
|
|
||||||
for dirpath, dirnames, filenames in walk(native(base)):
|
|
||||||
for item in prune:
|
|
||||||
if item in dirnames:
|
|
||||||
dirnames.remove(item)
|
|
||||||
|
|
||||||
dirnames.sort()
|
|
||||||
for name in _fnmatch.filter(dirnames, wildcard):
|
|
||||||
dest = _os.path.join(dirpath, name)
|
|
||||||
if dest.startswith(cwd):
|
|
||||||
dest = dest.replace(cwd, '', 1)
|
|
||||||
aslist = []
|
|
||||||
head, tail = _os.path.split(dest)
|
|
||||||
while tail:
|
|
||||||
aslist.append(tail)
|
|
||||||
head, tail = _os.path.split(head)
|
|
||||||
aslist.reverse()
|
|
||||||
dest = '/'.join(aslist)
|
|
||||||
yield dest
|
|
||||||
|
|
||||||
if not recursive:
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
def frompath(executable):
|
|
||||||
""" Find executable in PATH """
|
|
||||||
# Based on distutils.spawn.find_executable.
|
|
||||||
path = _os.environ.get('PATH', '')
|
|
||||||
paths = [
|
|
||||||
_os.path.expanduser(item)
|
|
||||||
for item in path.split(_os.pathsep)
|
|
||||||
]
|
|
||||||
ext = _os.path.splitext(executable)[1]
|
|
||||||
exts = ['']
|
|
||||||
if _sys.platform == 'win32' or _os.name == 'os2':
|
|
||||||
eext = ['.exe', '.bat', '.py']
|
|
||||||
if ext not in eext:
|
|
||||||
exts.extend(eext)
|
|
||||||
|
|
||||||
for ext in exts:
|
|
||||||
if not _os.path.isfile(executable + ext):
|
|
||||||
for path in paths:
|
|
||||||
fname = _os.path.join(path, executable + ext)
|
|
||||||
if _os.path.isfile(fname):
|
|
||||||
# the file exists, we have a shot at spawn working
|
|
||||||
return fname
|
|
||||||
else:
|
|
||||||
return executable + ext
|
|
||||||
|
|
||||||
return None
|
|
@ -1,28 +0,0 @@
|
|||||||
# -*- coding: ascii -*-
|
|
||||||
#
|
|
||||||
# Copyright 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.
|
|
||||||
"""
|
|
||||||
=====================
|
|
||||||
Package _setup.term
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Terminal tools, not distributed.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
# pylint: disable = W0611
|
|
||||||
from _setup.term._term import terminfo, write, green, red, yellow, announce
|
|
@ -1,116 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
=================
|
|
||||||
Terminal writer
|
|
||||||
=================
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
import sys as _sys
|
|
||||||
|
|
||||||
|
|
||||||
class _INFO(dict):
|
|
||||||
""" Terminal info dict """
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
""" Initialization """
|
|
||||||
dict.__init__(self, {
|
|
||||||
'NORMAL': '',
|
|
||||||
'BOLD': '',
|
|
||||||
'ERASE': '\n',
|
|
||||||
'RED': '',
|
|
||||||
'YELLOW': '',
|
|
||||||
'GREEN': '',
|
|
||||||
})
|
|
||||||
try:
|
|
||||||
import curses as _curses
|
|
||||||
except ImportError:
|
|
||||||
# fixup if a submodule of curses failed.
|
|
||||||
if 'curses' in _sys.modules:
|
|
||||||
del _sys.modules['curses']
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
_curses.setupterm()
|
|
||||||
except (TypeError, _curses.error):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
def make_color(color):
|
|
||||||
""" Make color control string """
|
|
||||||
seq = _curses.tigetstr('setaf').decode('ascii')
|
|
||||||
if seq is not None:
|
|
||||||
# XXX may fail - need better logic
|
|
||||||
seq = seq.replace("%p1", "") % color
|
|
||||||
return seq
|
|
||||||
|
|
||||||
self['NORMAL'] = _curses.tigetstr('sgr0').decode('ascii')
|
|
||||||
self['BOLD'] = _curses.tigetstr('bold').decode('ascii')
|
|
||||||
|
|
||||||
erase = _curses.tigetstr('el1').decode('ascii')
|
|
||||||
if erase is not None:
|
|
||||||
self['ERASE'] = erase + \
|
|
||||||
_curses.tigetstr('cr').decode('ascii')
|
|
||||||
|
|
||||||
self['RED'] = make_color(_curses.COLOR_RED)
|
|
||||||
self['YELLOW'] = make_color(_curses.COLOR_YELLOW)
|
|
||||||
self['GREEN'] = make_color(_curses.COLOR_GREEN)
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
""" Deliver always """
|
|
||||||
dict.get(self, key) or ""
|
|
||||||
|
|
||||||
|
|
||||||
def terminfo():
|
|
||||||
""" Get info singleton """
|
|
||||||
# pylint: disable = E1101, W0612
|
|
||||||
if terminfo.info is None:
|
|
||||||
terminfo.info = _INFO()
|
|
||||||
return terminfo.info
|
|
||||||
terminfo.info = None
|
|
||||||
|
|
||||||
|
|
||||||
def write(fmt, **kwargs):
|
|
||||||
""" Write stuff on the terminal """
|
|
||||||
parm = dict(terminfo())
|
|
||||||
parm.update(kwargs)
|
|
||||||
_sys.stdout.write(fmt % parm)
|
|
||||||
_sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def green(bmt, **kwargs):
|
|
||||||
""" Write something in green on screen """
|
|
||||||
announce("%%(GREEN)s%s%%(NORMAL)s" % bmt, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def red(bmt, **kwargs):
|
|
||||||
""" Write something in red on the screen """
|
|
||||||
announce("%%(BOLD)s%%(RED)s%s%%(NORMAL)s" % bmt, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def yellow(fmt, **kwargs):
|
|
||||||
""" Write something in yellow on the screen """
|
|
||||||
announce("%%(BOLD)s%%(YELLOW)s%s%%(NORMAL)s" % fmt, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def announce(fmt, **kwargs):
|
|
||||||
""" Announce something """
|
|
||||||
write(fmt, **kwargs)
|
|
||||||
_sys.stdout.write("\n")
|
|
||||||
_sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
|||||||
# -*- 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.
|
|
||||||
"""
|
|
||||||
=================
|
|
||||||
Setup utilities
|
|
||||||
=================
|
|
||||||
|
|
||||||
Setup utilities.
|
|
||||||
"""
|
|
||||||
__author__ = "Andr\xe9 Malo"
|
|
||||||
__docformat__ = "restructuredtext en"
|
|
||||||
|
|
||||||
from distutils import util as _util
|
|
||||||
try:
|
|
||||||
from configparser import SafeConfigParser
|
|
||||||
except ImportError:
|
|
||||||
import configparser as _config_parser
|
|
||||||
class SafeConfigParser(_config_parser.ConfigParser):
|
|
||||||
""" Safe config parser """
|
|
||||||
def _interpolate(self, section, option, rawval, vars):
|
|
||||||
return rawval
|
|
||||||
|
|
||||||
def items(self, section):
|
|
||||||
return [(key, self.get(section, key))
|
|
||||||
for key in self.options(section)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def humanbool(name, value):
|
|
||||||
"""
|
|
||||||
Determine human boolean value
|
|
||||||
|
|
||||||
:Parameters:
|
|
||||||
`name` : ``str``
|
|
||||||
The config key (used for error message)
|
|
||||||
|
|
||||||
`value` : ``str``
|
|
||||||
The config value
|
|
||||||
|
|
||||||
:Return: The boolean value
|
|
||||||
:Rtype: ``bool``
|
|
||||||
|
|
||||||
:Exceptions:
|
|
||||||
- `ValueError` : The value could not be recognized
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
return _util.strtobool(str(value).strip().lower() or 'no')
|
|
||||||
except ValueError:
|
|
||||||
raise ValueError("Unrecognized config value: %s = %s" % (name, value))
|
|
Loading…
x
Reference in New Issue
Block a user