initial import

This commit is contained in:
ndparker 2014-06-01 19:05:29 +02:00
commit 0cb7a56018
49 changed files with 6944 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
Makefile
*.py[cod]
*.so
dist
build
__pycache__
docs/_userdoc/_build/
docs/apidoc/
docs/userdoc/
_website/
*.ebuild
.sw?
.*.sw?
MANIFEST

201
LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

73
README.rst Normal file
View File

@ -0,0 +1,73 @@
-*- coding: utf-8 -*-
TABLE OF CONTENTS
=================
1. Introduction
2. Copyright and License
3. System Requirements
4. Installation
5. Documentation
6. Bugs
7. Author Information
INTRODUCTION
============
The setup tools are used to simplify the development and distribution of
python projects. The stuff found in this package has been collected over the
time and finally been separated into its own package. It's a neverending
task nevertheless...
COPYRIGHT AND LICENSE
=====================
Copyright 2005 - 2014
André Malo or his licensors, as applicable.
The whole package is distributed under the Apache License Version 2.0.
You'll find a copy in the root directory of the distribution or online
at: <http://www.apache.org/licenses/LICENSE-2.0>.
SYSTEM REQUIREMENTS
===================
You need python 2 (>= 2.2) or python 3.
INSTALLATION
============
Copy the _setup directory into your project.
DOCUMENTATION
=============
There's the code documentation, generated by epydoc
(<http://epydoc.sourceforge.net/>), which can be found in the
docs/apidoc/ subdirectory.
The latest documentation is also available online at
<http://opensource.perlig.de/setup/>.
BUGS
====
No bugs, of course. ;-)
But if you've found one or have an idea how to improve the setup tools, please
send a mail to <setup-bugs@perlig.de>.
AUTHOR INFORMATION
==================
André "nd" Malo <nd@perlig.de>
GPG: 0x8103A37E
If God intended people to be naked, they would be born that way.
-- Oscar Wilde

39
__init__.py Normal file
View File

@ -0,0 +1,39 @@
# -*- 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

10
docs/CLASSIFIERS Normal file
View File

@ -0,0 +1,10 @@
Development Status :: 4 - Beta
Intended Audience :: Developers
License :: OSI Approved
License :: OSI Approved :: Apache License, Version 2.0
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 2
Topic :: Software Development :: Libraries
Topic :: Software Development :: Libraries :: Python Modules
Topic :: Utilities

40
docs/DESCRIPTION Normal file
View File

@ -0,0 +1,40 @@
=============
Setup Tools
=============
The setup tools are used to simplify the development and distribution of
python projects. The stuff found in this package has been collected over the
time and finally been separated into its own package. It's a neverending
task nevertheless...
Copyright and License
~~~~~~~~~~~~~~~~~~~~~
Copyright 2005 - 2014
André Malo or his licensors, as applicable.
The whole package is distributed under the Apache License Version 2.0.
You'll find a copy in the root directory of the distribution or online
at: <http://www.apache.org/licenses/LICENSE-2.0>.
Bugs
~~~~
No bugs, of course. ;-)
But if you've found one or have an idea how to improve the setup tools, please
send a mail to <setup-bugs@perlig.de>.
Author Information
~~~~~~~~~~~~~~~~~~
André "nd" Malo <nd perlig.de>
GPG: 0x8103A37E
If God intended people to be naked, they would be born that way.
-- Oscar Wilde
.. vim:tw=72 syntax=rest

1
docs/PROVIDES Normal file
View File

@ -0,0 +1 @@
_setup (0.9)

1
docs/SUMMARY Normal file
View File

@ -0,0 +1 @@
Setup tools

244
include/cext.h Normal file
View File

@ -0,0 +1,244 @@
/*
* Copyright 2006 - 2014
* 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 */

73
package.cfg Normal file
View File

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
#
# Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011
# André 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]
name = setup
python.min = 2.2
#python.max = 2.7
version.number = 0.9.2
version.dev = false
version.revision = 3227
author.name = André Malo
author.email = nd@perlig.de
#maintainer.name =
#maintainer.email =
url.homepage = http://opensource.perlig.de/setup/
url.download = http://storage.perlig.de/setup/
[docs]
meta.classifiers = docs/CLASSIFIERS
meta.description = docs/DESCRIPTION
meta.summary = docs/SUMMARY
meta.provides = docs/PROVIDES
meta.license = LICENSE
meta.keywords =
setup
apidoc.dir = docs/apidoc
apidoc.strip = 1
#apidoc.ignore =
#userdoc.dir = docs/userdoc
#userdoc.strip = 1
#userdoc.ignore =
# .buildinfo
#examples.dir = docs/examples
#examples.strip = 1
#examples.ignore =
#man =
extra =
# docs/CHANGES
README
[manifest]
#packages.lib = .
packages.collect = _setup
#modules =
#scripts =
#dist =
# tests

27
py2/__init__.py Normal file
View File

@ -0,0 +1,27 @@
# -*- 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

267
py2/commands.py Normal file
View File

@ -0,0 +1,267 @@
# -*- 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)

165
py2/data.py Normal file
View File

@ -0,0 +1,165 @@
# -*- 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)

25
py2/dev/__init__.py Normal file
View File

@ -0,0 +1,25 @@
# -*- 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"

258
py2/dev/_pylint.py Normal file
View File

@ -0,0 +1,258 @@
# -*- 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

31
py2/dev/analysis.py Normal file
View File

@ -0,0 +1,31 @@
# -*- 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)

131
py2/dev/apidoc.py Normal file
View File

@ -0,0 +1,131 @@
# -*- 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

50
py2/dev/userdoc.py Normal file
View File

@ -0,0 +1,50 @@
# -*- 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})

51
py2/dist.py Normal file
View File

@ -0,0 +1,51 @@
# -*- 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)

254
py2/ext.py Normal file
View File

@ -0,0 +1,254 @@
# -*- 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)

28
py2/make/__init__.py Normal file
View File

@ -0,0 +1,28 @@
# -*- 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

338
py2/make/_make.py Normal file
View File

@ -0,0 +1,338 @@
# -*- 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()

110
py2/make/default_targets.py Normal file
View File

@ -0,0 +1,110 @@
# -*- 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

324
py2/make/targets.py Normal file
View File

@ -0,0 +1,324 @@
# -*- 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)

419
py2/setup.py Normal file
View File

@ -0,0 +1,419 @@
# -*- 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)

478
py2/shell.py Normal file
View File

@ -0,0 +1,478 @@
# -*- 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

28
py2/term/__init__.py Normal file
View File

@ -0,0 +1,28 @@
# -*- 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

115
py2/term/_term.py Normal file
View File

@ -0,0 +1,115 @@
# -*- 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()

73
py2/util.py Normal file
View File

@ -0,0 +1,73 @@
# -*- 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))

27
py3/__init__.py Normal file
View File

@ -0,0 +1,27 @@
# -*- 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

266
py3/commands.py Normal file
View File

@ -0,0 +1,266 @@
# -*- 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)

165
py3/data.py Normal file
View File

@ -0,0 +1,165 @@
# -*- 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)

25
py3/dev/__init__.py Normal file
View File

@ -0,0 +1,25 @@
# -*- 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"

258
py3/dev/_pylint.py Normal file
View File

@ -0,0 +1,258 @@
# -*- 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

31
py3/dev/analysis.py Normal file
View File

@ -0,0 +1,31 @@
# -*- 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)

131
py3/dev/apidoc.py Normal file
View File

@ -0,0 +1,131 @@
# -*- 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

50
py3/dev/userdoc.py Normal file
View File

@ -0,0 +1,50 @@
# -*- 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})

51
py3/dist.py Normal file
View File

@ -0,0 +1,51 @@
# -*- 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)

253
py3/ext.py Normal file
View File

@ -0,0 +1,253 @@
# -*- 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)

28
py3/make/__init__.py Normal file
View File

@ -0,0 +1,28 @@
# -*- 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

338
py3/make/_make.py Normal file
View File

@ -0,0 +1,338 @@
# -*- 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()

110
py3/make/default_targets.py Normal file
View File

@ -0,0 +1,110 @@
# -*- 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

326
py3/make/targets.py Normal file
View File

@ -0,0 +1,326 @@
# -*- 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)

420
py3/setup.py Normal file
View File

@ -0,0 +1,420 @@
# -*- 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)

351
py3/shell.py Normal file
View File

@ -0,0 +1,351 @@
# -*- 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

28
py3/term/__init__.py Normal file
View File

@ -0,0 +1,28 @@
# -*- 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

116
py3/term/_term.py Normal file
View File

@ -0,0 +1,116 @@
# -*- 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()

63
py3/util.py Normal file
View File

@ -0,0 +1,63 @@
# -*- 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))

39
setup.py.example Normal file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env python
# -*- coding: ascii -*-
#
# Copyright 2005 - 2014
# 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.
from _setup import run
def setup(args=None, _manifest=0):
""" Main setup function """
# Use this for extensions:
#from _setup.ext import Extension
return run(
script_args=args,
manifest_only=_manifest,
)
def manifest():
""" Create List of packaged files """
return setup((), _manifest=1)
if __name__ == '__main__':
setup()