diff options
| author | Tarek Ziade <tarek@ziade.org> | 2010-09-19 10:15:10 +0200 |
|---|---|---|
| committer | Tarek Ziade <tarek@ziade.org> | 2010-09-19 10:15:10 +0200 |
| commit | 5afe5844d0b204e55801b6a02fab6b2e18254448 (patch) | |
| tree | a65ade5921380d541e2cc30ad307a30917b54d27 /src | |
| parent | addfd74a36216143ed49f25da1cd6030902dad91 (diff) | |
| download | disutils2-5afe5844d0b204e55801b6a02fab6b2e18254448.tar.gz | |
moved everything in the same dir - we want to include docs/ in the release
Diffstat (limited to 'src')
212 files changed, 0 insertions, 37540 deletions
diff --git a/src/CHANGES.txt b/src/CHANGES.txt deleted file mode 100644 index 8bc3e6e..0000000 --- a/src/CHANGES.txt +++ /dev/null @@ -1,38 +0,0 @@ -======= -CHANGES -======= - -1.0a2 - ? ---------- - -- Add a converter for distutils/setuptools-based setup scripts [tarek] -- Factor out MANIFEST[.in] support into disutils2.manifest [tarek] -- Implement pkgutil APIs described in PEP 376 [josip] -- Add PEP 376 .dist-info support in Distribute [josip] -- Add distutils2.depgraph, a dependency graph builder [josip] -- Add a mock server to test network-using code [alexis, konrad] -- Add distutils2.index, a comprehensive subpackage to query PyPI [alexis] -- Add 2to3 support to the build command [zubin] -- Enhance the check command (sanity tests) [konrad] -- Make sdist include source files used by other commands [jeremy] -- Change install_egg_info to install_distinfo (PEP 376) [josip] -- Import the upload_docs command from distribute [konrad] -- Add a test command [konrad] -- Add post and pre-hooks for build and install [konrad] -- Remove PyPIRCCommand, move its helper code into util [tarek] -- Remove Mac OS 9 support [éric] -- Start adding docstrings to interface methods [jeremy] -- Move documentation from the stdlib [ali, éric] -- Lots of bug fixes, cleanups, tests [everyone] - - -1.0a1 - 2010-05-06 ------------------- - -- Initial import from the stdlib [tarek] -- Add support for PEP 386 in distutils2.version [tarek] -- Add support for PEP 345 in distutils2.metadata [tarek] -- Add mkpkg, a helper script to create a setup.py [sean] -- Remove bdist_rpm command [tarek] -- Add some PEP 376 functions to pkgutil [michael] -- Add distutils2.util.find_packages [tarek] diff --git a/src/CONTRIBUTORS.txt b/src/CONTRIBUTORS.txt deleted file mode 100644 index f501efc..0000000 --- a/src/CONTRIBUTORS.txt +++ /dev/null @@ -1,33 +0,0 @@ -============ -Contributors -============ - -Distutils2 is a project that was started and that is maintained by -Tarek Ziadé, and many people are contributing to the project. - -If you did, please add your name below in alphabetical order! - -Thanks to: - -- Ali Afshar -- Éric Araujo -- Pior Bastida -- Anthony Baxter -- Titus Brown -- Nicolas Cadou -- Konrad Delong -- Josip Djolonga -- Yannick Gingras -- Jeremy Kloth -- Martin von Löwis -- Carl Meyer -- Alexis Métaireau -- Zubin Mithra -- Michael Mulich -- George Peristerakis -- Sean Reifschneider -- Antoine Reversat -- Luis Rojas -- Erik Rose -- Brian Rosner -- Alexandre Vassalotti diff --git a/src/DEVNOTES.txt b/src/DEVNOTES.txt deleted file mode 100644 index e0753df..0000000 --- a/src/DEVNOTES.txt +++ /dev/null @@ -1,14 +0,0 @@ -Notes for developers -==================== - -- Distutils2 runs on Python from 2.4 to 3.2 (3.x not implemented yet), - so make sure you don't use a syntax that doesn't work under - one of these Python versions. - -- Always run tests.sh before you push a change. This implies - that you have all Python versions installed from 2.4 to 2.7. - -- With Python 2.4, if you want to run tests with runtests.py, or run - just one test directly, be sure to run python2.4 setup.py build_ext - first, else tests won't find _hashlib or _md5. When using tests.sh, - build_ext is automatically done. diff --git a/src/README.txt b/src/README.txt deleted file mode 100644 index 32f8a7e..0000000 --- a/src/README.txt +++ /dev/null @@ -1,15 +0,0 @@ -========== -Distutils2 -========== - -Welcome to Distutils2! - -Distutils2 is the new version of Distutils. It's not backward compatible with -Distutils but provides more features, and implement most new packaging -standards. - -See the documentation at http://packages.python.org/Distutils2 for more info. - -**Beware that Distutils2 is in its early stage and should not be used in -production. Its API is subject to changes** - diff --git a/src/check.sh b/src/check.sh deleted file mode 100755 index bc77bf9..0000000 --- a/src/check.sh +++ /dev/null @@ -1,2 +0,0 @@ -pep8 distutils2 -pyflakes distutils2 diff --git a/src/distutils2/README b/src/distutils2/README deleted file mode 100644 index 4afd700..0000000 --- a/src/distutils2/README +++ /dev/null @@ -1,13 +0,0 @@ -This directory contains the Distutils2 package. - -There's a full documentation available at: - - http://docs.python.org/distutils/ - -The Distutils-SIG web page is also a good starting point: - - http://www.python.org/sigs/distutils-sig/ - -WARNING: Distutils2 must remain compatible with Python 2.4 - -$Id: README 70017 2009-02-27 12:53:34Z tarek.ziade $ diff --git a/src/distutils2/__init__.py b/src/distutils2/__init__.py deleted file mode 100644 index 4d330b3..0000000 --- a/src/distutils2/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -"""distutils - -The main package for the Python Distribution Utilities 2. Setup -scripts should import the setup function from distutils2.core: - - from distutils2.core import setup - - setup(name=..., version=..., ...) - -Third-party tools can use parts of Distutils2 as building blocks -without causing the other modules to be imported: - - import distutils2.version - import distutils2.pypi.simple - import distutils2.tests.pypi_server -""" -__all__ = ['__version__'] - -__revision__ = "$Id: __init__.py 78020 2010-02-06 16:37:32Z benjamin.peterson $" -__version__ = "1.0a2" - - -# when set to True, converts doctests by default too -run_2to3_on_doctests = True -# Standard package names for fixer packages -lib2to3_fixer_packages = ['lib2to3.fixes'] diff --git a/src/distutils2/_backport/__init__.py b/src/distutils2/_backport/__init__.py deleted file mode 100644 index bfbf6ec..0000000 --- a/src/distutils2/_backport/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -"""Things that will land in the Python 3.3 std lib but which we must drag along -with us for now to support 2.x.""" - -def any(seq): - for elem in seq: - if elem: - return True - return False diff --git a/src/distutils2/_backport/_hashopenssl.c b/src/distutils2/_backport/_hashopenssl.c deleted file mode 100644 index fdcae5d..0000000 --- a/src/distutils2/_backport/_hashopenssl.c +++ /dev/null @@ -1,524 +0,0 @@ -/* Module that wraps all OpenSSL hash algorithms */ - -/* - * Copyright (C) 2005 Gregory P. Smith (greg@krypto.org) - * Licensed to PSF under a Contributor Agreement. - * - * Derived from a skeleton of shamodule.c containing work performed by: - * - * Andrew Kuchling (amk@amk.ca) - * Greg Stein (gstein@lyra.org) - * - */ - -#define PY_SSIZE_T_CLEAN - -#include "Python.h" -#include "structmember.h" - -#if (PY_VERSION_HEX < 0x02050000) -#define Py_ssize_t int -#endif - -/* EVP is the preferred interface to hashing in OpenSSL */ -#include <openssl/evp.h> - -#define MUNCH_SIZE INT_MAX - - -#ifndef HASH_OBJ_CONSTRUCTOR -#define HASH_OBJ_CONSTRUCTOR 0 -#endif - -typedef struct { - PyObject_HEAD - PyObject *name; /* name of this hash algorithm */ - EVP_MD_CTX ctx; /* OpenSSL message digest context */ -} EVPobject; - - -static PyTypeObject EVPtype; - - -#define DEFINE_CONSTS_FOR_NEW(Name) \ - static PyObject *CONST_ ## Name ## _name_obj; \ - static EVP_MD_CTX CONST_new_ ## Name ## _ctx; \ - static EVP_MD_CTX *CONST_new_ ## Name ## _ctx_p = NULL; - -DEFINE_CONSTS_FOR_NEW(md5) -DEFINE_CONSTS_FOR_NEW(sha1) -DEFINE_CONSTS_FOR_NEW(sha224) -DEFINE_CONSTS_FOR_NEW(sha256) -DEFINE_CONSTS_FOR_NEW(sha384) -DEFINE_CONSTS_FOR_NEW(sha512) - - -static EVPobject * -newEVPobject(PyObject *name) -{ - EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype); - - /* save the name for .name to return */ - if (retval != NULL) { - Py_INCREF(name); - retval->name = name; - } - - return retval; -} - -/* Internal methods for a hash object */ - -static void -EVP_dealloc(PyObject *ptr) -{ - EVP_MD_CTX_cleanup(&((EVPobject *)ptr)->ctx); - Py_XDECREF(((EVPobject *)ptr)->name); - PyObject_Del(ptr); -} - - -/* External methods for a hash object */ - -PyDoc_STRVAR(EVP_copy__doc__, "Return a copy of the hash object."); - -static PyObject * -EVP_copy(EVPobject *self, PyObject *unused) -{ - EVPobject *newobj; - - if ( (newobj = newEVPobject(self->name))==NULL) - return NULL; - - EVP_MD_CTX_copy(&newobj->ctx, &self->ctx); - return (PyObject *)newobj; -} - -PyDoc_STRVAR(EVP_digest__doc__, -"Return the digest value as a string of binary data."); - -static PyObject * -EVP_digest(EVPobject *self, PyObject *unused) -{ - unsigned char digest[EVP_MAX_MD_SIZE]; - EVP_MD_CTX temp_ctx; - PyObject *retval; - unsigned int digest_size; - - EVP_MD_CTX_copy(&temp_ctx, &self->ctx); - digest_size = EVP_MD_CTX_size(&temp_ctx); - EVP_DigestFinal(&temp_ctx, digest, NULL); - - retval = PyString_FromStringAndSize((const char *)digest, digest_size); - EVP_MD_CTX_cleanup(&temp_ctx); - return retval; -} - -PyDoc_STRVAR(EVP_hexdigest__doc__, -"Return the digest value as a string of hexadecimal digits."); - -static PyObject * -EVP_hexdigest(EVPobject *self, PyObject *unused) -{ - unsigned char digest[EVP_MAX_MD_SIZE]; - EVP_MD_CTX temp_ctx; - PyObject *retval; - char *hex_digest; - unsigned int i, j, digest_size; - - /* Get the raw (binary) digest value */ - EVP_MD_CTX_copy(&temp_ctx, &self->ctx); - digest_size = EVP_MD_CTX_size(&temp_ctx); - EVP_DigestFinal(&temp_ctx, digest, NULL); - - EVP_MD_CTX_cleanup(&temp_ctx); - - /* Create a new string */ - /* NOTE: not thread safe! modifying an already created string object */ - /* (not a problem because we hold the GIL by default) */ - retval = PyString_FromStringAndSize(NULL, digest_size * 2); - if (!retval) - return NULL; - hex_digest = PyString_AsString(retval); - if (!hex_digest) { - Py_DECREF(retval); - return NULL; - } - - /* Make hex version of the digest */ - for(i=j=0; i<digest_size; i++) { - char c; - c = (digest[i] >> 4) & 0xf; - c = (c>9) ? c+'a'-10 : c + '0'; - hex_digest[j++] = c; - c = (digest[i] & 0xf); - c = (c>9) ? c+'a'-10 : c + '0'; - hex_digest[j++] = c; - } - return retval; -} - -PyDoc_STRVAR(EVP_update__doc__, -"Update this hash object's state with the provided string."); - -static PyObject * -EVP_update(EVPobject *self, PyObject *args) -{ - unsigned char *cp; - Py_ssize_t len; - - if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) - return NULL; - - if (len > 0 && len <= MUNCH_SIZE) { - EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, - unsigned int)); - } else { - Py_ssize_t offset = 0; - while (len) { - unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len; - EVP_DigestUpdate(&self->ctx, cp + offset, process); - len -= process; - offset += process; - } - } - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef EVP_methods[] = { - {"update", (PyCFunction)EVP_update, METH_VARARGS, EVP_update__doc__}, - {"digest", (PyCFunction)EVP_digest, METH_NOARGS, EVP_digest__doc__}, - {"hexdigest", (PyCFunction)EVP_hexdigest, METH_NOARGS, EVP_hexdigest__doc__}, - {"copy", (PyCFunction)EVP_copy, METH_NOARGS, EVP_copy__doc__}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject * -EVP_get_block_size(EVPobject *self, void *closure) -{ - return PyInt_FromLong(EVP_MD_CTX_block_size(&((EVPobject *)self)->ctx)); -} - -static PyObject * -EVP_get_digest_size(EVPobject *self, void *closure) -{ - return PyInt_FromLong(EVP_MD_CTX_size(&((EVPobject *)self)->ctx)); -} - -static PyMemberDef EVP_members[] = { - {"name", T_OBJECT, offsetof(EVPobject, name), READONLY, PyDoc_STR("algorithm name.")}, - {NULL} /* Sentinel */ -}; - -static PyGetSetDef EVP_getseters[] = { - {"digest_size", - (getter)EVP_get_digest_size, NULL, - NULL, - NULL}, - {"block_size", - (getter)EVP_get_block_size, NULL, - NULL, - NULL}, - /* the old md5 and sha modules support 'digest_size' as in PEP 247. - * the old sha module also supported 'digestsize'. ugh. */ - {"digestsize", - (getter)EVP_get_digest_size, NULL, - NULL, - NULL}, - {NULL} /* Sentinel */ -}; - - -static PyObject * -EVP_repr(PyObject *self) -{ - char buf[100]; - PyOS_snprintf(buf, sizeof(buf), "<%s HASH object @ %p>", - PyString_AsString(((EVPobject *)self)->name), self); - return PyString_FromString(buf); -} - -#if HASH_OBJ_CONSTRUCTOR -static int -EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"name", "string", NULL}; - PyObject *name_obj = NULL; - char *nameStr; - unsigned char *cp = NULL; - Py_ssize_t len = 0; - const EVP_MD *digest; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s#:HASH", kwlist, - &name_obj, &cp, &len)) { - return -1; - } - - if (!PyArg_Parse(name_obj, "s", &nameStr)) { - PyErr_SetString(PyExc_TypeError, "name must be a string"); - return -1; - } - - digest = EVP_get_digestbyname(nameStr); - if (!digest) { - PyErr_SetString(PyExc_ValueError, "unknown hash function"); - return -1; - } - EVP_DigestInit(&self->ctx, digest); - - self->name = name_obj; - Py_INCREF(self->name); - - if (cp && len) { - if (len > 0 && len <= MUNCH_SIZE) { - EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, - unsigned int)); - } else { - Py_ssize_t offset = 0; - while (len) { - unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len; - EVP_DigestUpdate(&self->ctx, cp + offset, process); - len -= process; - offset += process; - } - } - } - - return 0; -} -#endif - - -PyDoc_STRVAR(hashtype_doc, -"A hash represents the object used to calculate a checksum of a\n\ -string of information.\n\ -\n\ -Methods:\n\ -\n\ -update() -- updates the current digest with an additional string\n\ -digest() -- return the current digest value\n\ -hexdigest() -- return the current digest as a string of hexadecimal digits\n\ -copy() -- return a copy of the current hash object\n\ -\n\ -Attributes:\n\ -\n\ -name -- the hash algorithm being used by this object\n\ -digest_size -- number of bytes in this hashes output\n"); - -static PyTypeObject EVPtype = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "_hashlib.HASH", /*tp_name*/ - sizeof(EVPobject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - EVP_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - EVP_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - hashtype_doc, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - EVP_methods, /* tp_methods */ - EVP_members, /* tp_members */ - EVP_getseters, /* tp_getset */ -#if 1 - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ -#endif -#if HASH_OBJ_CONSTRUCTOR - (initproc)EVP_tp_init, /* tp_init */ -#endif -}; - -static PyObject * -EVPnew(PyObject *name_obj, - const EVP_MD *digest, const EVP_MD_CTX *initial_ctx, - const unsigned char *cp, Py_ssize_t len) -{ - EVPobject *self; - - if (!digest && !initial_ctx) { - PyErr_SetString(PyExc_ValueError, "unsupported hash type"); - return NULL; - } - - if ((self = newEVPobject(name_obj)) == NULL) - return NULL; - - if (initial_ctx) { - EVP_MD_CTX_copy(&self->ctx, initial_ctx); - } else { - EVP_DigestInit(&self->ctx, digest); - } - - if (cp && len) { - if (len > 0 && len <= MUNCH_SIZE) { - EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, - unsigned int)); - } else { - Py_ssize_t offset = 0; - while (len) { - unsigned int process = len > MUNCH_SIZE ? MUNCH_SIZE : len; - EVP_DigestUpdate(&self->ctx, cp + offset, process); - len -= process; - offset += process; - } - } - } - - return (PyObject *)self; -} - - -/* The module-level function: new() */ - -PyDoc_STRVAR(EVP_new__doc__, -"Return a new hash object using the named algorithm.\n\ -An optional string argument may be provided and will be\n\ -automatically hashed.\n\ -\n\ -The MD5 and SHA1 algorithms are always supported.\n"); - -static PyObject * -EVP_new(PyObject *self, PyObject *args, PyObject *kwdict) -{ - static char *kwlist[] = {"name", "string", NULL}; - PyObject *name_obj = NULL; - char *name; - const EVP_MD *digest; - unsigned char *cp = NULL; - Py_ssize_t len = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s#:new", kwlist, - &name_obj, &cp, &len)) { - return NULL; - } - - if (!PyArg_Parse(name_obj, "s", &name)) { - PyErr_SetString(PyExc_TypeError, "name must be a string"); - return NULL; - } - - digest = EVP_get_digestbyname(name); - - return EVPnew(name_obj, digest, NULL, cp, len); -} - -/* - * This macro generates constructor function definitions for specific - * hash algorithms. These constructors are much faster than calling - * the generic one passing it a python string and are noticably - * faster than calling a python new() wrapper. Thats important for - * code that wants to make hashes of a bunch of small strings. - */ -#define GEN_CONSTRUCTOR(NAME) \ - static PyObject * \ - EVP_new_ ## NAME (PyObject *self, PyObject *args) \ - { \ - unsigned char *cp = NULL; \ - Py_ssize_t len = 0; \ - \ - if (!PyArg_ParseTuple(args, "|s#:" #NAME , &cp, &len)) { \ - return NULL; \ - } \ - \ - return EVPnew( \ - CONST_ ## NAME ## _name_obj, \ - NULL, \ - CONST_new_ ## NAME ## _ctx_p, \ - cp, len); \ - } - -/* a PyMethodDef structure for the constructor */ -#define CONSTRUCTOR_METH_DEF(NAME) \ - {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \ - PyDoc_STR("Returns a " #NAME \ - " hash object; optionally initialized with a string") \ - } - -/* used in the init function to setup a constructor */ -#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ - CONST_ ## NAME ## _name_obj = PyString_FromString(#NAME); \ - if (EVP_get_digestbyname(#NAME)) { \ - CONST_new_ ## NAME ## _ctx_p = &CONST_new_ ## NAME ## _ctx; \ - EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \ - } \ -} while (0); - -GEN_CONSTRUCTOR(md5) -GEN_CONSTRUCTOR(sha1) -GEN_CONSTRUCTOR(sha224) -GEN_CONSTRUCTOR(sha256) -GEN_CONSTRUCTOR(sha384) -GEN_CONSTRUCTOR(sha512) - -/* List of functions exported by this module */ - -static struct PyMethodDef EVP_functions[] = { - {"new", (PyCFunction)EVP_new, METH_VARARGS|METH_KEYWORDS, EVP_new__doc__}, - CONSTRUCTOR_METH_DEF(md5), - CONSTRUCTOR_METH_DEF(sha1), - CONSTRUCTOR_METH_DEF(sha224), - CONSTRUCTOR_METH_DEF(sha256), - CONSTRUCTOR_METH_DEF(sha384), - CONSTRUCTOR_METH_DEF(sha512), - {NULL, NULL} /* Sentinel */ -}; - - -/* Initialize this module. */ - -PyMODINIT_FUNC -init_hashlib(void) -{ - PyObject *m; - - OpenSSL_add_all_digests(); - - /* TODO build EVP_functions openssl_* entries dynamically based - * on what hashes are supported rather than listing many - * but having some be unsupported. Only init appropriate - * constants. */ - - EVPtype.ob_type = &PyType_Type; - if (PyType_Ready(&EVPtype) < 0) - return; - - m = Py_InitModule("_hashlib", EVP_functions); - if (m == NULL) - return; - -#if HASH_OBJ_CONSTRUCTOR - Py_INCREF(&EVPtype); - PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype); -#endif - - /* these constants are used by the convenience constructors */ - INIT_CONSTRUCTOR_CONSTANTS(md5); - INIT_CONSTRUCTOR_CONSTANTS(sha1); - INIT_CONSTRUCTOR_CONSTANTS(sha224); - INIT_CONSTRUCTOR_CONSTANTS(sha256); - INIT_CONSTRUCTOR_CONSTANTS(sha384); - INIT_CONSTRUCTOR_CONSTANTS(sha512); -} diff --git a/src/distutils2/_backport/hashlib.py b/src/distutils2/_backport/hashlib.py deleted file mode 100644 index dd2b02a..0000000 --- a/src/distutils2/_backport/hashlib.py +++ /dev/null @@ -1,143 +0,0 @@ -# $Id$ -# -# Copyright (C) 2005 Gregory P. Smith (greg@krypto.org) -# Licensed to PSF under a Contributor Agreement. -# - -__doc__ = """hashlib module - A common interface to many hash functions. - -new(name, string='') - returns a new hash object implementing the - given hash function; initializing the hash - using the given string data. - -Named constructor functions are also available, these are much faster -than using new(): - -md5(), sha1(), sha224(), sha256(), sha384(), and sha512() - -More algorithms may be available on your platform but the above are -guaranteed to exist. - -NOTE: If you want the adler32 or crc32 hash functions they are available in -the zlib module. - -Choose your hash function wisely. Some have known collision weaknesses. -sha384 and sha512 will be slow on 32 bit platforms. - -Hash objects have these methods: - - update(arg): Update the hash object with the string arg. Repeated calls - are equivalent to a single call with the concatenation of all - the arguments. - - digest(): Return the digest of the strings passed to the update() method - so far. This may contain non-ASCII characters, including - NUL bytes. - - hexdigest(): Like digest() except the digest is returned as a string of - double length, containing only hexadecimal digits. - - copy(): Return a copy (clone) of the hash object. This can be used to - efficiently compute the digests of strings that share a common - initial substring. - -For example, to obtain the digest of the string 'Nobody inspects the -spammish repetition': - - >>> import hashlib - >>> m = hashlib.md5() - >>> m.update("Nobody inspects") - >>> m.update(" the spammish repetition") - >>> m.digest() - '\\xbbd\\x9c\\x83\\xdd\\x1e\\xa5\\xc9\\xd9\\xde\\xc9\\xa1\\x8d\\xf0\\xff\\xe9' - -More condensed: - - >>> hashlib.sha224("Nobody inspects the spammish repetition").hexdigest() - 'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2' - -""" - -# This tuple and __get_builtin_constructor() must be modified if a new -# always available algorithm is added. -__always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512') - -algorithms = __always_supported - -__all__ = __always_supported + ('new', 'algorithms') - - -def __get_builtin_constructor(name): - if name in ('SHA1', 'sha1'): - from distutils2._backport import _sha - return _sha.new - elif name in ('MD5', 'md5'): - from distutils2._backport import _md5 - return _md5.new - elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): - from distutils2._backport import _sha256 - bs = name[3:] - if bs == '256': - return _sha256.sha256 - elif bs == '224': - return _sha256.sha224 - elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): - from distutils2._backport import _sha512 - bs = name[3:] - if bs == '512': - return _sha512.sha512 - elif bs == '384': - return _sha512.sha384 - - raise ValueError('unsupported hash type %s' % name) - - -def __get_openssl_constructor(name): - try: - f = getattr(_hashlib, 'openssl_' + name) - # Allow the C module to raise ValueError. The function will be - # defined but the hash not actually available thanks to OpenSSL. - f() - # Use the C function directly (very fast) - return f - except (AttributeError, ValueError): - return __get_builtin_constructor(name) - - -def __py_new(name, string=''): - """new(name, string='') - Return a new hashing object using the named algorithm; - optionally initialized with a string. - """ - return __get_builtin_constructor(name)(string) - - -def __hash_new(name, string=''): - """new(name, string='') - Return a new hashing object using the named algorithm; - optionally initialized with a string. - """ - try: - return _hashlib.new(name, string) - except ValueError: - # If the _hashlib module (OpenSSL) doesn't support the named - # hash, try using our builtin implementations. - # This allows for SHA224/256 and SHA384/512 support even though - # the OpenSSL library prior to 0.9.8 doesn't provide them. - return __get_builtin_constructor(name)(string) - - -try: - from distutils2._backport import _hashlib - new = __hash_new - __get_hash = __get_openssl_constructor -except ImportError: - new = __py_new - __get_hash = __get_builtin_constructor - -for __func_name in __always_supported: - # try them all, some may not work due to the OpenSSL - # version not supporting that algorithm. - try: - globals()[__func_name] = __get_hash(__func_name) - except ValueError: - import logging - logging.exception('code for hash %s was not found.', __func_name) - -# Cleanup locals() -del __always_supported, __func_name, __get_hash -del __py_new, __hash_new, __get_openssl_constructor diff --git a/src/distutils2/_backport/md5.c b/src/distutils2/_backport/md5.c deleted file mode 100644 index c35d96c..0000000 --- a/src/distutils2/_backport/md5.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - <ghost@aladdin.com>. Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include <string.h> - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include <stdio.h> in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "md5.h" -#include <string.h> - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#ifdef ARCH_IS_BIG_ENDIAN -# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) -#else -# define BYTE_ORDER 0 -#endif - -#define T_MASK ((md5_word_t)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - md5_word_t xbuf[16]; - const md5_word_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const md5_byte_t *xp = data; - int i; - -# if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -# else -# define xbuf X /* (static only) */ -# endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} diff --git a/src/distutils2/_backport/md5.h b/src/distutils2/_backport/md5.h deleted file mode 100644 index 1718401..0000000 --- a/src/distutils2/_backport/md5.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.h 43594 2006-04-03 16:27:50Z matthias.klose $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - <ghost@aladdin.com>. Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke <purschke@bnl.gov>. - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -/* - * This package supports both compile-time and run-time determination of CPU - * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be - * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is - * defined as non-zero, the code will be compiled to run only on big-endian - * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to - * run on either big- or little-endian CPUs, but will run slightly less - * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ diff --git a/src/distutils2/_backport/md5module.c b/src/distutils2/_backport/md5module.c deleted file mode 100644 index 5e4f116..0000000 --- a/src/distutils2/_backport/md5module.c +++ /dev/null @@ -1,312 +0,0 @@ - -/* MD5 module */ - -/* This module provides an interface to the RSA Data Security, - Inc. MD5 Message-Digest Algorithm, described in RFC 1321. - It requires the files md5c.c and md5.h (which are slightly changed - from the versions in the RFC to avoid the "global.h" file.) */ - - -/* MD5 objects */ - -#include "Python.h" -#include "structmember.h" -#include "md5.h" - -typedef struct { - PyObject_HEAD - md5_state_t md5; /* the context holder */ -} md5object; - -static PyTypeObject MD5type; - -#define is_md5object(v) ((v)->ob_type == &MD5type) - -static md5object * -newmd5object(void) -{ - md5object *md5p; - - md5p = PyObject_New(md5object, &MD5type); - if (md5p == NULL) - return NULL; - - md5_init(&md5p->md5); /* actual initialisation */ - return md5p; -} - - -/* MD5 methods */ - -static void -md5_dealloc(md5object *md5p) -{ - PyObject_Del(md5p); -} - - -/* MD5 methods-as-attributes */ - -static PyObject * -md5_update(md5object *self, PyObject *args) -{ - unsigned char *cp; - int len; - - if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) - return NULL; - - md5_append(&self->md5, cp, len); - - Py_INCREF(Py_None); - return Py_None; -} - -PyDoc_STRVAR(update_doc, -"update (arg)\n\ -\n\ -Update the md5 object with the string arg. Repeated calls are\n\ -equivalent to a single call with the concatenation of all the\n\ -arguments."); - - -static PyObject * -md5_digest(md5object *self) -{ - md5_state_t mdContext; - unsigned char aDigest[16]; - - /* make a temporary copy, and perform the final */ - mdContext = self->md5; - md5_finish(&mdContext, aDigest); - - return PyString_FromStringAndSize((char *)aDigest, 16); -} - -PyDoc_STRVAR(digest_doc, -"digest() -> string\n\ -\n\ -Return the digest of the strings passed to the update() method so\n\ -far. This is a 16-byte string which may contain non-ASCII characters,\n\ -including null bytes."); - - -static PyObject * -md5_hexdigest(md5object *self) -{ - md5_state_t mdContext; - unsigned char digest[16]; - unsigned char hexdigest[32]; - int i, j; - - /* make a temporary copy, and perform the final */ - mdContext = self->md5; - md5_finish(&mdContext, digest); - - /* Make hex version of the digest */ - for(i=j=0; i<16; i++) { - char c; - c = (digest[i] >> 4) & 0xf; - c = (c>9) ? c+'a'-10 : c + '0'; - hexdigest[j++] = c; - c = (digest[i] & 0xf); - c = (c>9) ? c+'a'-10 : c + '0'; - hexdigest[j++] = c; - } - return PyString_FromStringAndSize((char*)hexdigest, 32); -} - - -PyDoc_STRVAR(hexdigest_doc, -"hexdigest() -> string\n\ -\n\ -Like digest(), but returns the digest as a string of hexadecimal digits."); - - -static PyObject * -md5_copy(md5object *self) -{ - md5object *md5p; - - if ((md5p = newmd5object()) == NULL) - return NULL; - - md5p->md5 = self->md5; - - return (PyObject *)md5p; -} - -PyDoc_STRVAR(copy_doc, -"copy() -> md5 object\n\ -\n\ -Return a copy (``clone'') of the md5 object."); - - -static PyMethodDef md5_methods[] = { - {"update", (PyCFunction)md5_update, METH_VARARGS, update_doc}, - {"digest", (PyCFunction)md5_digest, METH_NOARGS, digest_doc}, - {"hexdigest", (PyCFunction)md5_hexdigest, METH_NOARGS, hexdigest_doc}, - {"copy", (PyCFunction)md5_copy, METH_NOARGS, copy_doc}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject * -md5_get_block_size(PyObject *self, void *closure) -{ - return PyInt_FromLong(64); -} - -static PyObject * -md5_get_digest_size(PyObject *self, void *closure) -{ - return PyInt_FromLong(16); -} - -static PyObject * -md5_get_name(PyObject *self, void *closure) -{ - return PyString_FromStringAndSize("MD5", 3); -} - -static PyGetSetDef md5_getseters[] = { - {"digest_size", - (getter)md5_get_digest_size, NULL, - NULL, - NULL}, - {"block_size", - (getter)md5_get_block_size, NULL, - NULL, - NULL}, - {"name", - (getter)md5_get_name, NULL, - NULL, - NULL}, - /* the old md5 and sha modules support 'digest_size' as in PEP 247. - * the old sha module also supported 'digestsize'. ugh. */ - {"digestsize", - (getter)md5_get_digest_size, NULL, - NULL, - NULL}, - {NULL} /* Sentinel */ -}; - - -PyDoc_STRVAR(module_doc, -"This module implements the interface to RSA's MD5 message digest\n\ -algorithm (see also Internet RFC 1321). Its use is quite\n\ -straightforward: use the new() to create an md5 object. You can now\n\ -feed this object with arbitrary strings using the update() method, and\n\ -at any point you can ask it for the digest (a strong kind of 128-bit\n\ -checksum, a.k.a. ``fingerprint'') of the concatenation of the strings\n\ -fed to it so far using the digest() method.\n\ -\n\ -Functions:\n\ -\n\ -new([arg]) -- return a new md5 object, initialized with arg if provided\n\ -md5([arg]) -- DEPRECATED, same as new, but for compatibility\n\ -\n\ -Special Objects:\n\ -\n\ -MD5Type -- type object for md5 objects"); - -PyDoc_STRVAR(md5type_doc, -"An md5 represents the object used to calculate the MD5 checksum of a\n\ -string of information.\n\ -\n\ -Methods:\n\ -\n\ -update() -- updates the current digest with an additional string\n\ -digest() -- return the current digest value\n\ -hexdigest() -- return the current digest as a string of hexadecimal digits\n\ -copy() -- return a copy of the current md5 object"); - -static PyTypeObject MD5type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "_md5.md5", /*tp_name*/ - sizeof(md5object), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)md5_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - md5type_doc, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - md5_methods, /*tp_methods*/ - 0, /*tp_members*/ - md5_getseters, /*tp_getset*/ -}; - - -/* MD5 functions */ - -static PyObject * -MD5_new(PyObject *self, PyObject *args) -{ - md5object *md5p; - unsigned char *cp = NULL; - int len = 0; - - if (!PyArg_ParseTuple(args, "|s#:new", &cp, &len)) - return NULL; - - if ((md5p = newmd5object()) == NULL) - return NULL; - - if (cp) - md5_append(&md5p->md5, cp, len); - - return (PyObject *)md5p; -} - -PyDoc_STRVAR(new_doc, -"new([arg]) -> md5 object\n\ -\n\ -Return a new md5 object. If arg is present, the method call update(arg)\n\ -is made."); - - -/* List of functions exported by this module */ - -static PyMethodDef md5_functions[] = { - {"new", (PyCFunction)MD5_new, METH_VARARGS, new_doc}, - {NULL, NULL} /* Sentinel */ -}; - - -/* Initialize this module. */ - -PyMODINIT_FUNC -init_md5(void) -{ - PyObject *m, *d; - - MD5type.ob_type = &PyType_Type; - if (PyType_Ready(&MD5type) < 0) - return; - m = Py_InitModule3("_md5", md5_functions, module_doc); - if (m == NULL) - return; - d = PyModule_GetDict(m); - PyDict_SetItemString(d, "MD5Type", (PyObject *)&MD5type); - PyModule_AddIntConstant(m, "digest_size", 16); - /* No need to check the error here, the caller will do that */ -} diff --git a/src/distutils2/_backport/pkgutil.py b/src/distutils2/_backport/pkgutil.py deleted file mode 100644 index c53bd22..0000000 --- a/src/distutils2/_backport/pkgutil.py +++ /dev/null @@ -1,1155 +0,0 @@ -"""Utilities to support packages.""" - -# NOTE: This module must remain compatible with Python 2.3, as it is shared -# by setuptools for distribution with Python 2.3 and up. - -import os -import sys -import imp -import os.path -from csv import reader as csv_reader -from types import ModuleType -from distutils2.errors import DistutilsError -from distutils2.metadata import DistributionMetadata -from distutils2.version import suggest_normalized_version, VersionPredicate -import zipimport -try: - import cStringIO as StringIO -except ImportError: - import StringIO -import re -import warnings - - -__all__ = [ - 'get_importer', 'iter_importers', 'get_loader', 'find_loader', - 'walk_packages', 'iter_modules', 'get_data', - 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path', - 'Distribution', 'EggInfoDistribution', 'distinfo_dirname', - 'get_distributions', 'get_distribution', 'get_file_users', - 'provides_distribution', 'obsoletes_distribution', - 'enable_cache', 'disable_cache', 'clear_cache' -] - - -def read_code(stream): - # This helper is needed in order for the :pep:`302` emulation to - # correctly handle compiled files - import marshal - - magic = stream.read(4) - if magic != imp.get_magic(): - return None - - stream.read(4) # Skip timestamp - return marshal.load(stream) - - -def simplegeneric(func): - """Make a trivial single-dispatch generic function""" - registry = {} - - def wrapper(*args, **kw): - ob = args[0] - try: - cls = ob.__class__ - except AttributeError: - cls = type(ob) - try: - mro = cls.__mro__ - except AttributeError: - try: - - class cls(cls, object): - pass - mro = cls.__mro__[1:] - except TypeError: - mro = object, # must be an ExtensionClass or some such :( - for t in mro: - if t in registry: - return registry[t](*args, **kw) - else: - return func(*args, **kw) - try: - wrapper.__name__ = func.__name__ - except (TypeError, AttributeError): - pass # Python 2.3 doesn't allow functions to be renamed - - def register(typ, func=None): - if func is None: - return lambda f: register(typ, f) - registry[typ] = func - return func - - wrapper.__dict__ = func.__dict__ - wrapper.__doc__ = func.__doc__ - wrapper.register = register - return wrapper - - -def walk_packages(path=None, prefix='', onerror=None): - """Yields ``(module_loader, name, ispkg)`` for all modules recursively - on *path*, or, if *path* is ``None``, all accessible modules. - - :parameter path: should be either ``None`` or a list of paths to look for - modules in. - :parameter prefix: is a string to output on the front of every module name - on output. - - Note that this function must import all packages (NOT all - modules!) on the given path, in order to access the ``__path__`` - attribute to find submodules. - - *onerror* is a function which gets called with one argument (the - name of the package which was being imported) if any exception - occurs while trying to import a package. If no onerror function is - supplied, ``ImportErrors`` are caught and ignored, while all other - exceptions are propagated, terminating the search. - - Examples: - - * list all modules python can access:: - - walk_packages() - - * list all submodules of ctypes:: - - walk_packages(ctypes.__path__, ctypes.__name__+'.') - - """ - - def seen(p, m={}): - if p in m: - return True - m[p] = True - - for importer, name, ispkg in iter_modules(path, prefix): - yield importer, name, ispkg - - if ispkg: - try: - __import__(name) - except ImportError: - if onerror is not None: - onerror(name) - except Exception: - if onerror is not None: - onerror(name) - else: - raise - else: - path = getattr(sys.modules[name], '__path__', None) or [] - - # don't traverse path items we've seen before - path = [p for p in path if not seen(p)] - - for item in walk_packages(path, name + '.', onerror): - yield item - - -def iter_modules(path=None, prefix=''): - """Yields ``(module_loader, name, ispkg)`` for all submodules on path, - or, if *path* is ``None``, all top-level modules on ``sys.path``. - - :parameter path: should be either None or a list of paths to look for - modules in. - :parameter prefix: is a string to output on the front of every module name - on output. - - """ - - if path is None: - importers = iter_importers() - else: - importers = map(get_importer, path) - - yielded = {} - for i in importers: - for name, ispkg in iter_importer_modules(i, prefix): - if name not in yielded: - yielded[name] = 1 - yield i, name, ispkg - - -#@simplegeneric -def iter_importer_modules(importer, prefix=''): - "" - if not hasattr(importer, 'iter_modules'): - return [] - return importer.iter_modules(prefix) - -iter_importer_modules = simplegeneric(iter_importer_modules) - - -class ImpImporter(object): - """:pep:`302` Importer that wraps Python's "classic" import algorithm - - ``ImpImporter(dirname)`` produces a :pep:`302` importer that searches that - directory. ``ImpImporter(None)`` produces a :pep:`302` importer that - searches the current ``sys.path``, plus any modules that are frozen - or built-in. - - Note that :class:`ImpImporter` does not currently support being used by - placement on ``sys.meta_path``. - """ - - def __init__(self, path=None): - self.path = path - - def find_module(self, fullname, path=None): - # Note: we ignore 'path' argument since it is only used via meta_path - subname = fullname.split(".")[-1] - if subname != fullname and self.path is None: - return None - if self.path is None: - path = None - else: - path = [os.path.realpath(self.path)] - try: - file, filename, etc = imp.find_module(subname, path) - except ImportError: - return None - return ImpLoader(fullname, file, filename, etc) - - def iter_modules(self, prefix=''): - if self.path is None or not os.path.isdir(self.path): - return - - yielded = {} - import inspect - - filenames = os.listdir(self.path) - filenames.sort() # handle packages before same-named modules - - for fn in filenames: - modname = inspect.getmodulename(fn) - if modname == '__init__' or modname in yielded: - continue - - path = os.path.join(self.path, fn) - ispkg = False - - if not modname and os.path.isdir(path) and '.' not in fn: - modname = fn - for fn in os.listdir(path): - subname = inspect.getmodulename(fn) - if subname == '__init__': - ispkg = True - break - else: - continue # not a package - - if modname and '.' not in modname: - yielded[modname] = 1 - yield prefix + modname, ispkg - - -class ImpLoader(object): - """:pep:`302` Loader that wraps Python's "classic" import algorithm """ - - code = source = None - - def __init__(self, fullname, file, filename, etc): - self.file = file - self.filename = filename - self.fullname = fullname - self.etc = etc - - def load_module(self, fullname): - self._reopen() - try: - mod = imp.load_module(fullname, self.file, self.filename, self.etc) - finally: - if self.file: - self.file.close() - # Note: we don't set __loader__ because we want the module to look - # normal; i.e. this is just a wrapper for standard import machinery - return mod - - def get_data(self, pathname): - return open(pathname, "rb").read() - - def _reopen(self): - if self.file and self.file.closed: - mod_type = self.etc[2] - if mod_type == imp.PY_SOURCE: - self.file = open(self.filename, 'rU') - elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION): - self.file = open(self.filename, 'rb') - - def _fix_name(self, fullname): - if fullname is None: - fullname = self.fullname - elif fullname != self.fullname: - raise ImportError("Loader for module %s cannot handle " - "module %s" % (self.fullname, fullname)) - return fullname - - def is_package(self, fullname): - fullname = self._fix_name(fullname) - return self.etc[2] == imp.PKG_DIRECTORY - - def get_code(self, fullname=None): - fullname = self._fix_name(fullname) - if self.code is None: - mod_type = self.etc[2] - if mod_type == imp.PY_SOURCE: - source = self.get_source(fullname) - self.code = compile(source, self.filename, 'exec') - elif mod_type == imp.PY_COMPILED: - self._reopen() - try: - self.code = read_code(self.file) - finally: - self.file.close() - elif mod_type == imp.PKG_DIRECTORY: - self.code = self._get_delegate().get_code() - return self.code - - def get_source(self, fullname=None): - fullname = self._fix_name(fullname) - if self.source is None: - mod_type = self.etc[2] - if mod_type == imp.PY_SOURCE: - self._reopen() - try: - self.source = self.file.read() - finally: - self.file.close() - elif mod_type == imp.PY_COMPILED: - if os.path.exists(self.filename[:-1]): - f = open(self.filename[:-1], 'rU') - self.source = f.read() - f.close() - elif mod_type == imp.PKG_DIRECTORY: - self.source = self._get_delegate().get_source() - return self.source - - def _get_delegate(self): - return ImpImporter(self.filename).find_module('__init__') - - def get_filename(self, fullname=None): - fullname = self._fix_name(fullname) - mod_type = self.etc[2] - if self.etc[2] == imp.PKG_DIRECTORY: - return self._get_delegate().get_filename() - elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): - return self.filename - return None - - -try: - import zipimport - from zipimport import zipimporter - - def iter_zipimport_modules(importer, prefix=''): - dirlist = zipimport._zip_directory_cache[importer.archive].keys() - dirlist.sort() - _prefix = importer.prefix - plen = len(_prefix) - yielded = {} - import inspect - for fn in dirlist: - if not fn.startswith(_prefix): - continue - - fn = fn[plen:].split(os.sep) - - if len(fn) == 2 and fn[1].startswith('__init__.py'): - if fn[0] not in yielded: - yielded[fn[0]] = 1 - yield fn[0], True - - if len(fn) != 1: - continue - - modname = inspect.getmodulename(fn[0]) - if modname == '__init__': - continue - - if modname and '.' not in modname and modname not in yielded: - yielded[modname] = 1 - yield prefix + modname, False - - iter_importer_modules.register(zipimporter, iter_zipimport_modules) - -except ImportError: - pass - - -def get_importer(path_item): - """Retrieve a :pep:`302` importer for the given path item - - The returned importer is cached in ``sys.path_importer_cache`` - if it was newly created by a path hook. - - If there is no importer, a wrapper around the basic import - machinery is returned. This wrapper is never inserted into - the importer cache (``None`` is inserted instead). - - The cache (or part of it) can be cleared manually if a - rescan of ``sys.path_hooks`` is necessary. - """ - try: - importer = sys.path_importer_cache[path_item] - except KeyError: - for path_hook in sys.path_hooks: - try: - importer = path_hook(path_item) - break - except ImportError: - pass - else: - importer = None - sys.path_importer_cache.setdefault(path_item, importer) - - if importer is None: - try: - importer = ImpImporter(path_item) - except ImportError: - importer = None - return importer - - -def iter_importers(fullname=""): - """Yield :pep:`302` importers for the given module name - - If fullname contains a '.', the importers will be for the package - containing fullname, otherwise they will be importers for sys.meta_path, - sys.path, and Python's "classic" import machinery, in that order. If - the named module is in a package, that package is imported as a side - effect of invoking this function. - - Non :pep:`302` mechanisms (e.g. the Windows registry) used by the - standard import machinery to find files in alternative locations - are partially supported, but are searched AFTER ``sys.path``. Normally, - these locations are searched BEFORE sys.path, preventing ``sys.path`` - entries from shadowing them. - - For this to cause a visible difference in behaviour, there must - be a module or package name that is accessible via both sys.path - and one of the non :pep:`302` file system mechanisms. In this case, - the emulation will find the former version, while the builtin - import mechanism will find the latter. - - Items of the following types can be affected by this discrepancy: - ``imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY`` - """ - if fullname.startswith('.'): - raise ImportError("Relative module names not supported") - if '.' in fullname: - # Get the containing package's __path__ - pkg = '.'.join(fullname.split('.')[:-1]) - if pkg not in sys.modules: - __import__(pkg) - path = getattr(sys.modules[pkg], '__path__', None) or [] - else: - for importer in sys.meta_path: - yield importer - path = sys.path - for item in path: - yield get_importer(item) - if '.' not in fullname: - yield ImpImporter() - - -def get_loader(module_or_name): - """Get a :pep:`302` "loader" object for module_or_name - - If the module or package is accessible via the normal import - mechanism, a wrapper around the relevant part of that machinery - is returned. Returns None if the module cannot be found or imported. - If the named module is not already imported, its containing package - (if any) is imported, in order to establish the package ``__path__``. - - This function uses :func:`iter_importers`, and is thus subject to the same - limitations regarding platform-specific special import locations such - as the Windows registry. - """ - if module_or_name in sys.modules: - module_or_name = sys.modules[module_or_name] - if isinstance(module_or_name, ModuleType): - module = module_or_name - loader = getattr(module, '__loader__', None) - if loader is not None: - return loader - fullname = module.__name__ - else: - fullname = module_or_name - return find_loader(fullname) - - -def find_loader(fullname): - """Find a :pep:`302` "loader" object for fullname - - If fullname contains dots, path must be the containing package's - ``__path__``. Returns ``None`` if the module cannot be found or imported. - This function uses :func:`iter_importers`, and is thus subject to the same - limitations regarding platform-specific special import locations such as - the Windows registry. - """ - for importer in iter_importers(fullname): - loader = importer.find_module(fullname) - if loader is not None: - return loader - - return None - - -def extend_path(path, name): - """Extend a package's path. - - Intended use is to place the following code in a package's - ``__init__.py``:: - - from pkgutil import extend_path - __path__ = extend_path(__path__, __name__) - - This will add to the package's ``__path__`` all subdirectories of - directories on ``sys.path`` named after the package. This is useful - if one wants to distribute different parts of a single logical - package as multiple directories. - - It also looks for ``*.pkg`` files beginning where ``*`` matches the name - argument. This feature is similar to ``*.pth`` files (see ``site.py``), - except that it doesn't special-case lines starting with ``import``. - A ``*.pkg`` file is trusted at face value: apart from checking for - duplicates, all entries found in a ``*.pkg`` file are added to the - path, regardless of whether they are exist the filesystem. (This - is a feature.) - - If the input path is not a list (as is the case for frozen - packages) it is returned unchanged. The input path is not - modified; an extended copy is returned. Items are only appended - to the copy at the end. - - It is assumed that sys.path is a sequence. Items of sys.path that - are not (unicode or 8-bit) strings referring to existing - directories are ignored. Unicode items of sys.path that cause - errors when used as filenames may cause this function to raise an - exception (in line with ``os.path.isdir()`` behavior). - """ - - if not isinstance(path, list): - # This could happen e.g. when this is called from inside a - # frozen package. Return the path unchanged in that case. - return path - - pname = os.path.join(*name.split('.')) # Reconstitute as relative path - # Just in case os.extsep != '.' - sname = os.extsep.join(name.split('.')) - sname_pkg = sname + os.extsep + "pkg" - init_py = "__init__" + os.extsep + "py" - - path = path[:] # Start with a copy of the existing path - - for dir in sys.path: - if not isinstance(dir, basestring) or not os.path.isdir(dir): - continue - subdir = os.path.join(dir, pname) - # XXX This may still add duplicate entries to path on - # case-insensitive filesystems - initfile = os.path.join(subdir, init_py) - if subdir not in path and os.path.isfile(initfile): - path.append(subdir) - # XXX Is this the right thing for subpackages like zope.app? - # It looks for a file named "zope.app.pkg" - pkgfile = os.path.join(dir, sname_pkg) - if os.path.isfile(pkgfile): - try: - f = open(pkgfile) - except IOError, msg: - sys.stderr.write("Can't open %s: %s\n" % - (pkgfile, msg)) - else: - for line in f: - line = line.rstrip('\n') - if not line or line.startswith('#'): - continue - path.append(line) # Don't check for existence! - f.close() - - return path - - -def get_data(package, resource): - """Get a resource from a package. - - This is a wrapper round the :pep:`302` loader get_data API. The package - argument should be the name of a package, in standard module format - (``foo.bar``). The resource argument should be in the form of a relative - filename, using ``'/'`` as the path separator. The parent directory name - ``'..'`` is not allowed, and nor is a rooted name (starting with a - ``'/'``). - - The function returns a binary string, which is the contents of the - specified resource. - - For packages located in the filesystem, which have already been imported, - this is the rough equivalent of:: - - d = os.path.dirname(sys.modules[package].__file__) - data = open(os.path.join(d, resource), 'rb').read() - - If the package cannot be located or loaded, or it uses a :pep:`302` loader - which does not support :func:`get_data`, then ``None`` is returned. - """ - - loader = get_loader(package) - if loader is None or not hasattr(loader, 'get_data'): - return None - mod = sys.modules.get(package) or loader.load_module(package) - if mod is None or not hasattr(mod, '__file__'): - return None - - # Modify the resource name to be compatible with the loader.get_data - # signature - an os.path format "filename" starting with the dirname of - # the package's __file__ - parts = resource.split('/') - parts.insert(0, os.path.dirname(mod.__file__)) - resource_name = os.path.join(*parts) - return loader.get_data(resource_name) - -########################## -# PEP 376 Implementation # -########################## - -DIST_FILES = ('INSTALLER', 'METADATA', 'RECORD', 'REQUESTED',) - -# Cache -_cache_name = {} # maps names to Distribution instances -_cache_name_egg = {} # maps names to EggInfoDistribution instances -_cache_path = {} # maps paths to Distribution instances -_cache_path_egg = {} # maps paths to EggInfoDistribution instances -_cache_generated = False # indicates if .dist-info distributions are cached -_cache_generated_egg = False # indicates if .dist-info and .egg are cached -_cache_enabled = True - - -def enable_cache(): - """ - Enables the internal cache. - - Note that this function will not clear the cache in any case, for that - functionality see :func:`clear_cache`. - """ - global _cache_enabled - - _cache_enabled = True - -def disable_cache(): - """ - Disables the internal cache. - - Note that this function will not clear the cache in any case, for that - functionality see :func:`clear_cache`. - """ - global _cache_enabled - - _cache_enabled = False - -def clear_cache(): - """ Clears the internal cache. """ - global _cache_name, _cache_name_egg, cache_path, _cache_path_egg, \ - _cache_generated, _cache_generated_egg - - _cache_name = {} - _cache_name_egg = {} - _cache_path = {} - _cache_path_egg = {} - _cache_generated = False - _cache_generated_egg = False - - -def _yield_distributions(include_dist, include_egg): - """ - Yield .dist-info and .egg(-info) distributions, based on the arguments - - :parameter include_dist: yield .dist-info distributions - :parameter include_egg: yield .egg(-info) distributions - """ - for path in sys.path: - realpath = os.path.realpath(path) - if not os.path.isdir(realpath): - continue - for dir in os.listdir(realpath): - dist_path = os.path.join(realpath, dir) - if include_dist and dir.endswith('.dist-info'): - yield Distribution(dist_path) - elif include_egg and (dir.endswith('.egg-info') or - dir.endswith('.egg')): - yield EggInfoDistribution(dist_path) - - -def _generate_cache(use_egg_info=False): - global _cache_generated, _cache_generated_egg - - if _cache_generated_egg or (_cache_generated and not use_egg_info): - return - else: - gen_dist = not _cache_generated - gen_egg = use_egg_info - - for dist in _yield_distributions(gen_dist, gen_egg): - if isinstance(dist, Distribution): - _cache_path[dist.path] = dist - if not dist.name in _cache_name: - _cache_name[dist.name] = [] - _cache_name[dist.name].append(dist) - else: - _cache_path_egg[dist.path] = dist - if not dist.name in _cache_name_egg: - _cache_name_egg[dist.name] = [] - _cache_name_egg[dist.name].append(dist) - - if gen_dist: - _cache_generated = True - if gen_egg: - _cache_generated_egg = True - - -class Distribution(object): - """Created with the *path* of the ``.dist-info`` directory provided to the - constructor. It reads the metadata contained in ``METADATA`` when it is - instantiated.""" - - # Attribute documenting for Sphinx style documentation, see for more info: - # http://sphinx.pocoo.org/ext/autodoc.html#dir-autoattribute - name = '' - """The name of the distribution.""" - metadata = None - """A :class:`distutils2.metadata.DistributionMetadata` instance loaded with - the distribution's ``METADATA`` file.""" - requested = False - """A boolean that indicates whether the ``REQUESTED`` metadata file is - present (in other words, whether the package was installed by user - request or it was installed as a dependency).""" - - def __init__(self, path): - if _cache_enabled and path in _cache_path: - self.metadata = _cache_path[path].metadata - else: - metadata_path = os.path.join(path, 'METADATA') - self.metadata = DistributionMetadata(path=metadata_path) - - self.path = path - self.name = self.metadata['name'] - - if _cache_enabled and not path in _cache_path: - _cache_path[path] = self - - def _get_records(self, local=False): - RECORD = os.path.join(self.path, 'RECORD') - record_reader = csv_reader(open(RECORD, 'rb'), delimiter=',') - for row in record_reader: - path, md5, size = row[:] + [None for i in xrange(len(row), 3)] - if local: - path = path.replace('/', os.sep) - path = os.path.join(sys.prefix, path) - yield path, md5, size - - def get_installed_files(self, local=False): - """ - Iterates over the ``RECORD`` entries and returns a tuple - ``(path, md5, size)`` for each line. If *local* is ``True``, - the returned path is transformed into a local absolute path. - Otherwise the raw value from RECORD is returned. - - A local absolute path is an absolute path in which occurrences of - ``'/'`` have been replaced by the system separator given by ``os.sep``. - - :parameter local: flag to say if the path should be returned a local - absolute path - - :type local: boolean - :returns: iterator of (path, md5, size) - """ - return self._get_records(local) - - def uses(self, path): - """ - Returns ``True`` if path is listed in ``RECORD``. *path* can be a local - absolute path or a relative ``'/'``-separated path. - - :rtype: boolean - """ - for p, md5, size in self._get_records(): - local_absolute = os.path.join(sys.prefix, p) - if path == p or path == local_absolute: - return True - return False - - def get_distinfo_file(self, path, binary=False): - """ - Returns a file located under the ``.dist-info`` directory. Returns a - ``file`` instance for the file pointed by *path*. - - :parameter path: a ``'/'``-separated path relative to the - ``.dist-info`` directory or an absolute path; - If *path* is an absolute path and doesn't start - with the ``.dist-info`` directory path, - a :class:`DistutilsError` is raised - :type path: string - :parameter binary: If *binary* is ``True``, opens the file in read-only - binary mode (``rb``), otherwise opens it in - read-only mode (``r``). - :rtype: file object - """ - open_flags = 'r' - if binary: - open_flags += 'b' - - # Check if it is an absolute path - if path.find(os.sep) >= 0: - # it's an absolute path? - distinfo_dirname, path = path.split(os.sep)[-2:] - if distinfo_dirname != self.path.split(os.sep)[-1]: - raise DistutilsError("Requested dist-info file does not " - "belong to the %s distribution. '%s' was requested." \ - % (self.name, os.sep.join([distinfo_dirname, path]))) - - # The file must be relative - if path not in DIST_FILES: - raise DistutilsError("Requested an invalid dist-info file: " - "%s" % path) - - # Convert the relative path back to absolute - path = os.path.join(self.path, path) - return open(path, open_flags) - - def get_distinfo_files(self, local=False): - """ - Iterates over the ``RECORD`` entries and returns paths for each line if - the path is pointing to a file located in the ``.dist-info`` directory - or one of its subdirectories. - - :parameter local: If *local* is ``True``, each returned path is - transformed into a local absolute path. Otherwise the - raw value from ``RECORD`` is returned. - :type local: boolean - :returns: iterator of paths - """ - for path, md5, size in self._get_records(local): - yield path - - def __eq__(self, other): - return isinstance(other, Distribution) and self.path == other.path - - # See http://docs.python.org/reference/datamodel#object.__hash__ - __hash__ = object.__hash__ - - -class EggInfoDistribution(object): - """Created with the *path* of the ``.egg-info`` directory or file provided - to the constructor. It reads the metadata contained in the file itself, or - if the given path happens to be a directory, the metadata is read from the - file ``PKG-INFO`` under that directory.""" - - name = '' - """The name of the distribution.""" - metadata = None - """A :class:`distutils2.metadata.DistributionMetadata` instance loaded with - the distribution's ``METADATA`` file.""" - _REQUIREMENT = re.compile( \ - r'(?P<name>[-A-Za-z0-9_.]+)\s*' \ - r'(?P<first>(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)?\s*' \ - r'(?P<rest>(?:\s*,\s*(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)*)\s*' \ - r'(?P<extras>\[.*\])?') - - def __init__(self, path): - self.path = path - - if _cache_enabled and path in _cache_path_egg: - self.metadata = _cache_path_egg[path].metadata - self.name = self.metadata['Name'] - return - - # reused from Distribute's pkg_resources - def yield_lines(strs): - """Yield non-empty/non-comment lines of a ``basestring`` - or sequence""" - if isinstance(strs, basestring): - for s in strs.splitlines(): - s = s.strip() - if s and not s.startswith('#'): # skip blank lines/comments - yield s - else: - for ss in strs: - for s in yield_lines(ss): - yield s - - requires = None - if path.endswith('.egg'): - if os.path.isdir(path): - meta_path = os.path.join(path, 'EGG-INFO', 'PKG-INFO') - self.metadata = DistributionMetadata(path=meta_path) - try: - req_path = os.path.join(path, 'EGG-INFO', 'requires.txt') - requires = open(req_path, 'r').read() - except IOError: - requires = None - else: - zipf = zipimport.zipimporter(path) - fileobj = StringIO.StringIO(zipf.get_data('EGG-INFO/PKG-INFO')) - self.metadata = DistributionMetadata(fileobj=fileobj) - try: - requires = zipf.get_data('EGG-INFO/requires.txt') - except IOError: - requires = None - self.name = self.metadata['Name'] - elif path.endswith('.egg-info'): - if os.path.isdir(path): - path = os.path.join(path, 'PKG-INFO') - try: - req_f = open(os.path.join(path, 'requires.txt'), 'r') - requires = req_f.read() - except IOError: - requires = None - self.metadata = DistributionMetadata(path=path) - self.name = self.metadata['name'] - else: - raise ValueError('The path must end with .egg-info or .egg') - - provides = "%s (%s)" % (self.metadata['name'], - self.metadata['version']) - if self.metadata['Metadata-Version'] == '1.2': - self.metadata['Provides-Dist'] += (provides,) - else: - self.metadata['Provides'] += (provides,) - reqs = [] - if requires is not None: - for line in yield_lines(requires): - if line[0] == '[': - warnings.warn('distutils2 does not support extensions ' - 'in requires.txt') - break - else: - match = self._REQUIREMENT.match(line.strip()) - if not match: - raise ValueError('Distribution %s has ill formed ' - 'requires.txt file (%s)' % - (self.name, line)) - else: - if match.group('extras'): - s = (('Distribution %s uses extra requirements ' - 'which are not supported in distutils') \ - % (self.name)) - warnings.warn(s) - name = match.group('name') - version = None - if match.group('first'): - version = match.group('first') - if match.group('rest'): - version += match.group('rest') - version = version.replace(' ', '') # trim spaces - if version is None: - reqs.append(name) - else: - reqs.append('%s (%s)' % (name, version)) - if self.metadata['Metadata-Version'] == '1.2': - self.metadata['Requires-Dist'] += reqs - else: - self.metadata['Requires'] += reqs - - if _cache_enabled: - _cache_path_egg[self.path] = self - - def get_installed_files(self, local=False): - return [] - - def uses(self, path): - return False - - def __eq__(self, other): - return isinstance(other, EggInfoDistribution) and \ - self.path == other.path - - # See http://docs.python.org/reference/datamodel#object.__hash__ - __hash__ = object.__hash__ - - -def _normalize_dist_name(name): - """Returns a normalized name from the given *name*. - :rtype: string""" - return name.replace('-', '_') - - -def distinfo_dirname(name, version): - """ - The *name* and *version* parameters are converted into their - filename-escaped form, i.e. any ``'-'`` characters are replaced - with ``'_'`` other than the one in ``'dist-info'`` and the one - separating the name from the version number. - - :parameter name: is converted to a standard distribution name by replacing - any runs of non- alphanumeric characters with a single - ``'-'``. - :type name: string - :parameter version: is converted to a standard version string. Spaces - become dots, and all other non-alphanumeric characters - (except dots) become dashes, with runs of multiple - dashes condensed to a single dash. - :type version: string - :returns: directory name - :rtype: string""" - file_extension = '.dist-info' - name = _normalize_dist_name(name) - normalized_version = suggest_normalized_version(version) - # Because this is a lookup procedure, something will be returned even if - # it is a version that cannot be normalized - if normalized_version is None: - # Unable to achieve normality? - normalized_version = version - return '-'.join([name, normalized_version]) + file_extension - - -def get_distributions(use_egg_info=False): - """ - Provides an iterator that looks for ``.dist-info`` directories in - ``sys.path`` and returns :class:`Distribution` instances for each one of - them. If the parameters *use_egg_info* is ``True``, then the ``.egg-info`` - files and directores are iterated as well. - - :rtype: iterator of :class:`Distribution` and :class:`EggInfoDistribution` - instances - """ - if not _cache_enabled: - for dist in _yield_distributions(True, use_egg_info): - yield dist - else: - _generate_cache(use_egg_info) - - for dist in _cache_path.itervalues(): - yield dist - - if use_egg_info: - for dist in _cache_path_egg.itervalues(): - yield dist - - -def get_distribution(name, use_egg_info=False): - """ - Scans all elements in ``sys.path`` and looks for all directories - ending with ``.dist-info``. Returns a :class:`Distribution` - corresponding to the ``.dist-info`` directory that contains the - ``METADATA`` that matches *name* for the *name* metadata field. - If no distribution exists with the given *name* and the parameter - *use_egg_info* is set to ``True``, then all files and directories ending - with ``.egg-info`` are scanned. A :class:`EggInfoDistribution` instance is - returned if one is found that has metadata that matches *name* for the - *name* metadata field. - - This function only returns the first result found, as no more than one - value is expected. If the directory is not found, ``None`` is returned. - - :rtype: :class:`Distribution` or :class:`EggInfoDistribution` or None - """ - if not _cache_enabled: - for dist in _yield_distributions(True, use_egg_info): - if dist.name == name: - return dist - else: - _generate_cache(use_egg_info) - - if name in _cache_name: - return _cache_name[name][0] - elif use_egg_info and name in _cache_name_egg: - return _cache_name_egg[name][0] - else: - return None - - -def obsoletes_distribution(name, version=None, use_egg_info=False): - """ - Iterates over all distributions to find which distributions obsolete - *name*. - - If a *version* is provided, it will be used to filter the results. - If the argument *use_egg_info* is set to ``True``, then ``.egg-info`` - distributions will be considered as well. - - :type name: string - :type version: string - :parameter name: - """ - for dist in get_distributions(use_egg_info): - obsoleted = (dist.metadata['Obsoletes-Dist'] + - dist.metadata['Obsoletes']) - for obs in obsoleted: - o_components = obs.split(' ', 1) - if len(o_components) == 1 or version is None: - if name == o_components[0]: - yield dist - break - else: - try: - predicate = VersionPredicate(obs) - except ValueError: - raise DistutilsError(('Distribution %s has ill formed' + - ' obsoletes field') % (dist.name,)) - if name == o_components[0] and predicate.match(version): - yield dist - break - - -def provides_distribution(name, version=None, use_egg_info=False): - """ - Iterates over all distributions to find which distributions provide *name*. - If a *version* is provided, it will be used to filter the results. Scans - all elements in ``sys.path`` and looks for all directories ending with - ``.dist-info``. Returns a :class:`Distribution` corresponding to the - ``.dist-info`` directory that contains a ``METADATA`` that matches *name* - for the name metadata. If the argument *use_egg_info* is set to ``True``, - then all files and directories ending with ``.egg-info`` are considered - as well and returns an :class:`EggInfoDistribution` instance. - - This function only returns the first result found, since no more than - one values are expected. If the directory is not found, returns ``None``. - - :parameter version: a version specifier that indicates the version - required, conforming to the format in ``PEP-345`` - - :type name: string - :type version: string - """ - predicate = None - if not version is None: - try: - predicate = VersionPredicate(name + ' (' + version + ')') - except ValueError: - raise DistutilsError('Invalid name or version') - - for dist in get_distributions(use_egg_info): - provided = dist.metadata['Provides-Dist'] + dist.metadata['Provides'] - - for p in provided: - p_components = p.rsplit(' ', 1) - if len(p_components) == 1 or predicate is None: - if name == p_components[0]: - yield dist - break - else: - p_name, p_ver = p_components - if len(p_ver) < 2 or p_ver[0] != '(' or p_ver[-1] != ')': - raise DistutilsError(('Distribution %s has invalid ' + - 'provides field: %s') \ - % (dist.name, p)) - p_ver = p_ver[1:-1] # trim off the parenthesis - if p_name == name and predicate.match(p_ver): - yield dist - break - - -def get_file_users(path): - """ - Iterates over all distributions to find out which distributions uses - *path*. - - :parameter path: can be a local absolute path or a relative - ``'/'``-separated path. - :type path: string - :rtype: iterator of :class:`Distribution` instances - """ - for dist in get_distributions(): - if dist.uses(path): - yield dist diff --git a/src/distutils2/_backport/sha256module.c b/src/distutils2/_backport/sha256module.c deleted file mode 100644 index 96cbd10..0000000 --- a/src/distutils2/_backport/sha256module.c +++ /dev/null @@ -1,701 +0,0 @@ -/* SHA256 module */ - -/* This module provides an interface to NIST's SHA-256 and SHA-224 Algorithms */ - -/* See below for information about the original code this module was - based upon. Additional work performed by: - - Andrew Kuchling (amk@amk.ca) - Greg Stein (gstein@lyra.org) - Trevor Perrin (trevp@trevp.net) - - Copyright (C) 2005 Gregory P. Smith (greg@krypto.org) - Licensed to PSF under a Contributor Agreement. - -*/ - -/* SHA objects */ - -#include "Python.h" -#include "structmember.h" - - -/* Endianness testing and definitions */ -#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ - if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} - -#define PCT_LITTLE_ENDIAN 1 -#define PCT_BIG_ENDIAN 0 - -/* Some useful types */ - -typedef unsigned char SHA_BYTE; - -#if SIZEOF_INT == 4 -typedef unsigned int SHA_INT32; /* 32-bit integer */ -#else -/* not defined. compilation will die. */ -#endif - -/* The SHA block size and message digest sizes, in bytes */ - -#define SHA_BLOCKSIZE 64 -#define SHA_DIGESTSIZE 32 - -/* The structure for storing SHA info */ - -typedef struct { - PyObject_HEAD - SHA_INT32 digest[8]; /* Message digest */ - SHA_INT32 count_lo, count_hi; /* 64-bit bit count */ - SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ - int Endianness; - int local; /* unprocessed amount in data */ - int digestsize; -} SHAobject; - -/* When run on a little-endian CPU we need to perform byte reversal on an - array of longwords. */ - -static void longReverse(SHA_INT32 *buffer, int byteCount, int Endianness) -{ - SHA_INT32 value; - - if ( Endianness == PCT_BIG_ENDIAN ) - return; - - byteCount /= sizeof(*buffer); - while (byteCount--) { - value = *buffer; - value = ( ( value & 0xFF00FF00L ) >> 8 ) | \ - ( ( value & 0x00FF00FFL ) << 8 ); - *buffer++ = ( value << 16 ) | ( value >> 16 ); - } -} - -static void SHAcopy(SHAobject *src, SHAobject *dest) -{ - dest->Endianness = src->Endianness; - dest->local = src->local; - dest->digestsize = src->digestsize; - dest->count_lo = src->count_lo; - dest->count_hi = src->count_hi; - memcpy(dest->digest, src->digest, sizeof(src->digest)); - memcpy(dest->data, src->data, sizeof(src->data)); -} - - -/* ------------------------------------------------------------------------ - * - * This code for the SHA-256 algorithm was noted as public domain. The - * original headers are pasted below. - * - * Several changes have been made to make it more compatible with the - * Python environment and desired interface. - * - */ - -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * gurantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org - */ - - -/* SHA256 by Tom St Denis */ - -/* Various logical functions */ -#define ROR(x, y)\ -( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | \ -((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) ROR((x),(n)) -#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) - - -static void -sha_transform(SHAobject *sha_info) -{ - int i; - SHA_INT32 S[8], W[64], t0, t1; - - memcpy(W, sha_info->data, sizeof(sha_info->data)); - longReverse(W, (int)sizeof(sha_info->data), sha_info->Endianness); - - for (i = 16; i < 64; ++i) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } - for (i = 0; i < 8; ++i) { - S[i] = sha_info->digest[i]; - } - - /* Compress */ -#define RND(a,b,c,d,e,f,g,h,i,ki) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; - - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); - -#undef RND - - /* feedback */ - for (i = 0; i < 8; i++) { - sha_info->digest[i] = sha_info->digest[i] + S[i]; - } - -} - - - -/* initialize the SHA digest */ - -static void -sha_init(SHAobject *sha_info) -{ - TestEndianness(sha_info->Endianness) - sha_info->digest[0] = 0x6A09E667L; - sha_info->digest[1] = 0xBB67AE85L; - sha_info->digest[2] = 0x3C6EF372L; - sha_info->digest[3] = 0xA54FF53AL; - sha_info->digest[4] = 0x510E527FL; - sha_info->digest[5] = 0x9B05688CL; - sha_info->digest[6] = 0x1F83D9ABL; - sha_info->digest[7] = 0x5BE0CD19L; - sha_info->count_lo = 0L; - sha_info->count_hi = 0L; - sha_info->local = 0; - sha_info->digestsize = 32; -} - -static void -sha224_init(SHAobject *sha_info) -{ - TestEndianness(sha_info->Endianness) - sha_info->digest[0] = 0xc1059ed8L; - sha_info->digest[1] = 0x367cd507L; - sha_info->digest[2] = 0x3070dd17L; - sha_info->digest[3] = 0xf70e5939L; - sha_info->digest[4] = 0xffc00b31L; - sha_info->digest[5] = 0x68581511L; - sha_info->digest[6] = 0x64f98fa7L; - sha_info->digest[7] = 0xbefa4fa4L; - sha_info->count_lo = 0L; - sha_info->count_hi = 0L; - sha_info->local = 0; - sha_info->digestsize = 28; -} - - -/* update the SHA digest */ - -static void -sha_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) -{ - int i; - SHA_INT32 clo; - - clo = sha_info->count_lo + ((SHA_INT32) count << 3); - if (clo < sha_info->count_lo) { - ++sha_info->count_hi; - } - sha_info->count_lo = clo; - sha_info->count_hi += (SHA_INT32) count >> 29; - if (sha_info->local) { - i = SHA_BLOCKSIZE - sha_info->local; - if (i > count) { - i = count; - } - memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); - count -= i; - buffer += i; - sha_info->local += i; - if (sha_info->local == SHA_BLOCKSIZE) { - sha_transform(sha_info); - } - else { - return; - } - } - while (count >= SHA_BLOCKSIZE) { - memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); - buffer += SHA_BLOCKSIZE; - count -= SHA_BLOCKSIZE; - sha_transform(sha_info); - } - memcpy(sha_info->data, buffer, count); - sha_info->local = count; -} - -/* finish computing the SHA digest */ - -static void -sha_final(unsigned char digest[SHA_DIGESTSIZE], SHAobject *sha_info) -{ - int count; - SHA_INT32 lo_bit_count, hi_bit_count; - - lo_bit_count = sha_info->count_lo; - hi_bit_count = sha_info->count_hi; - count = (int) ((lo_bit_count >> 3) & 0x3f); - ((SHA_BYTE *) sha_info->data)[count++] = 0x80; - if (count > SHA_BLOCKSIZE - 8) { - memset(((SHA_BYTE *) sha_info->data) + count, 0, - SHA_BLOCKSIZE - count); - sha_transform(sha_info); - memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8); - } - else { - memset(((SHA_BYTE *) sha_info->data) + count, 0, - SHA_BLOCKSIZE - 8 - count); - } - - /* GJS: note that we add the hi/lo in big-endian. sha_transform will - swap these values into host-order. */ - sha_info->data[56] = (hi_bit_count >> 24) & 0xff; - sha_info->data[57] = (hi_bit_count >> 16) & 0xff; - sha_info->data[58] = (hi_bit_count >> 8) & 0xff; - sha_info->data[59] = (hi_bit_count >> 0) & 0xff; - sha_info->data[60] = (lo_bit_count >> 24) & 0xff; - sha_info->data[61] = (lo_bit_count >> 16) & 0xff; - sha_info->data[62] = (lo_bit_count >> 8) & 0xff; - sha_info->data[63] = (lo_bit_count >> 0) & 0xff; - sha_transform(sha_info); - digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); - digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); - digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); - digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff); - digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); - digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); - digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); - digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff); - digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); - digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); - digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); - digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff); - digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); - digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); - digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); - digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff); - digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); - digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); - digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); - digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff); - digest[20] = (unsigned char) ((sha_info->digest[5] >> 24) & 0xff); - digest[21] = (unsigned char) ((sha_info->digest[5] >> 16) & 0xff); - digest[22] = (unsigned char) ((sha_info->digest[5] >> 8) & 0xff); - digest[23] = (unsigned char) ((sha_info->digest[5] ) & 0xff); - digest[24] = (unsigned char) ((sha_info->digest[6] >> 24) & 0xff); - digest[25] = (unsigned char) ((sha_info->digest[6] >> 16) & 0xff); - digest[26] = (unsigned char) ((sha_info->digest[6] >> 8) & 0xff); - digest[27] = (unsigned char) ((sha_info->digest[6] ) & 0xff); - digest[28] = (unsigned char) ((sha_info->digest[7] >> 24) & 0xff); - digest[29] = (unsigned char) ((sha_info->digest[7] >> 16) & 0xff); - digest[30] = (unsigned char) ((sha_info->digest[7] >> 8) & 0xff); - digest[31] = (unsigned char) ((sha_info->digest[7] ) & 0xff); -} - -/* - * End of copied SHA code. - * - * ------------------------------------------------------------------------ - */ - -static PyTypeObject SHA224type; -static PyTypeObject SHA256type; - - -static SHAobject * -newSHA224object(void) -{ - return (SHAobject *)PyObject_New(SHAobject, &SHA224type); -} - -static SHAobject * -newSHA256object(void) -{ - return (SHAobject *)PyObject_New(SHAobject, &SHA256type); -} - -/* Internal methods for a hash object */ - -static void -SHA_dealloc(PyObject *ptr) -{ - PyObject_Del(ptr); -} - - -/* External methods for a hash object */ - -PyDoc_STRVAR(SHA256_copy__doc__, "Return a copy of the hash object."); - -static PyObject * -SHA256_copy(SHAobject *self, PyObject *unused) -{ - SHAobject *newobj; - - if (((PyObject*)self)->ob_type == &SHA256type) { - if ( (newobj = newSHA256object())==NULL) - return NULL; - } else { - if ( (newobj = newSHA224object())==NULL) - return NULL; - } - - SHAcopy(self, newobj); - return (PyObject *)newobj; -} - -PyDoc_STRVAR(SHA256_digest__doc__, -"Return the digest value as a string of binary data."); - -static PyObject * -SHA256_digest(SHAobject *self, PyObject *unused) -{ - unsigned char digest[SHA_DIGESTSIZE]; - SHAobject temp; - - SHAcopy(self, &temp); - sha_final(digest, &temp); - return PyString_FromStringAndSize((const char *)digest, self->digestsize); -} - -PyDoc_STRVAR(SHA256_hexdigest__doc__, -"Return the digest value as a string of hexadecimal digits."); - -static PyObject * -SHA256_hexdigest(SHAobject *self, PyObject *unused) -{ - unsigned char digest[SHA_DIGESTSIZE]; - SHAobject temp; - PyObject *retval; - char *hex_digest; - int i, j; - - /* Get the raw (binary) digest value */ - SHAcopy(self, &temp); - sha_final(digest, &temp); - - /* Create a new string */ - retval = PyString_FromStringAndSize(NULL, self->digestsize * 2); - if (!retval) - return NULL; - hex_digest = PyString_AsString(retval); - if (!hex_digest) { - Py_DECREF(retval); - return NULL; - } - - /* Make hex version of the digest */ - for(i=j=0; i<self->digestsize; i++) { - char c; - c = (digest[i] >> 4) & 0xf; - c = (c>9) ? c+'a'-10 : c + '0'; - hex_digest[j++] = c; - c = (digest[i] & 0xf); - c = (c>9) ? c+'a'-10 : c + '0'; - hex_digest[j++] = c; - } - return retval; -} - -PyDoc_STRVAR(SHA256_update__doc__, -"Update this hash object's state with the provided string."); - -static PyObject * -SHA256_update(SHAobject *self, PyObject *args) -{ - unsigned char *cp; - int len; - - if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) - return NULL; - - sha_update(self, cp, len); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef SHA_methods[] = { - {"copy", (PyCFunction)SHA256_copy, METH_NOARGS, SHA256_copy__doc__}, - {"digest", (PyCFunction)SHA256_digest, METH_NOARGS, SHA256_digest__doc__}, - {"hexdigest", (PyCFunction)SHA256_hexdigest, METH_NOARGS, SHA256_hexdigest__doc__}, - {"update", (PyCFunction)SHA256_update, METH_VARARGS, SHA256_update__doc__}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject * -SHA256_get_block_size(PyObject *self, void *closure) -{ - return PyInt_FromLong(SHA_BLOCKSIZE); -} - -static PyObject * -SHA256_get_name(PyObject *self, void *closure) -{ - if (((SHAobject *)self)->digestsize == 32) - return PyString_FromStringAndSize("SHA256", 6); - else - return PyString_FromStringAndSize("SHA224", 6); -} - -static PyGetSetDef SHA_getseters[] = { - {"block_size", - (getter)SHA256_get_block_size, NULL, - NULL, - NULL}, - {"name", - (getter)SHA256_get_name, NULL, - NULL, - NULL}, - {NULL} /* Sentinel */ -}; - -static PyMemberDef SHA_members[] = { - {"digest_size", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, - /* the old md5 and sha modules support 'digest_size' as in PEP 247. - * the old sha module also supported 'digestsize'. ugh. */ - {"digestsize", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, - {NULL} /* Sentinel */ -}; - -static PyTypeObject SHA224type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "_sha256.sha224", /*tp_name*/ - sizeof(SHAobject), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - SHA_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - SHA_methods, /* tp_methods */ - SHA_members, /* tp_members */ - SHA_getseters, /* tp_getset */ -}; - -static PyTypeObject SHA256type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "_sha256.sha256", /*tp_name*/ - sizeof(SHAobject), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - SHA_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - SHA_methods, /* tp_methods */ - SHA_members, /* tp_members */ - SHA_getseters, /* tp_getset */ -}; - - -/* The single module-level function: new() */ - -PyDoc_STRVAR(SHA256_new__doc__, -"Return a new SHA-256 hash object; optionally initialized with a string."); - -static PyObject * -SHA256_new(PyObject *self, PyObject *args, PyObject *kwdict) -{ - static char *kwlist[] = {"string", NULL}; - SHAobject *new; - unsigned char *cp = NULL; - int len; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { - return NULL; - } - - if ((new = newSHA256object()) == NULL) - return NULL; - - sha_init(new); - - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; - } - if (cp) - sha_update(new, cp, len); - - return (PyObject *)new; -} - -PyDoc_STRVAR(SHA224_new__doc__, -"Return a new SHA-224 hash object; optionally initialized with a string."); - -static PyObject * -SHA224_new(PyObject *self, PyObject *args, PyObject *kwdict) -{ - static char *kwlist[] = {"string", NULL}; - SHAobject *new; - unsigned char *cp = NULL; - int len; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { - return NULL; - } - - if ((new = newSHA224object()) == NULL) - return NULL; - - sha224_init(new); - - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; - } - if (cp) - sha_update(new, cp, len); - - return (PyObject *)new; -} - - -/* List of functions exported by this module */ - -static struct PyMethodDef SHA_functions[] = { - {"sha256", (PyCFunction)SHA256_new, METH_VARARGS|METH_KEYWORDS, SHA256_new__doc__}, - {"sha224", (PyCFunction)SHA224_new, METH_VARARGS|METH_KEYWORDS, SHA224_new__doc__}, - {NULL, NULL} /* Sentinel */ -}; - - -/* Initialize this module. */ - -#define insint(n,v) { PyModule_AddIntConstant(m,n,v); } - -PyMODINIT_FUNC -init_sha256(void) -{ - PyObject *m; - - SHA224type.ob_type = &PyType_Type; - if (PyType_Ready(&SHA224type) < 0) - return; - SHA256type.ob_type = &PyType_Type; - if (PyType_Ready(&SHA256type) < 0) - return; - m = Py_InitModule("_sha256", SHA_functions); - if (m == NULL) - return; -} diff --git a/src/distutils2/_backport/sha512module.c b/src/distutils2/_backport/sha512module.c deleted file mode 100644 index dbaec17..0000000 --- a/src/distutils2/_backport/sha512module.c +++ /dev/null @@ -1,769 +0,0 @@ -/* SHA512 module */ - -/* This module provides an interface to NIST's SHA-512 and SHA-384 Algorithms */ - -/* See below for information about the original code this module was - based upon. Additional work performed by: - - Andrew Kuchling (amk@amk.ca) - Greg Stein (gstein@lyra.org) - Trevor Perrin (trevp@trevp.net) - - Copyright (C) 2005 Gregory P. Smith (greg@krypto.org) - Licensed to PSF under a Contributor Agreement. - -*/ - -/* SHA objects */ - -#include "Python.h" -#include "structmember.h" - -#ifdef PY_LONG_LONG /* If no PY_LONG_LONG, don't compile anything! */ - -/* Endianness testing and definitions */ -#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ - if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} - -#define PCT_LITTLE_ENDIAN 1 -#define PCT_BIG_ENDIAN 0 - -/* Some useful types */ - -typedef unsigned char SHA_BYTE; - -#if SIZEOF_INT == 4 -typedef unsigned int SHA_INT32; /* 32-bit integer */ -typedef unsigned PY_LONG_LONG SHA_INT64; /* 64-bit integer */ -#else -/* not defined. compilation will die. */ -#endif - -/* The SHA block size and message digest sizes, in bytes */ - -#define SHA_BLOCKSIZE 128 -#define SHA_DIGESTSIZE 64 - -/* The structure for storing SHA info */ - -typedef struct { - PyObject_HEAD - SHA_INT64 digest[8]; /* Message digest */ - SHA_INT32 count_lo, count_hi; /* 64-bit bit count */ - SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ - int Endianness; - int local; /* unprocessed amount in data */ - int digestsize; -} SHAobject; - -/* When run on a little-endian CPU we need to perform byte reversal on an - array of longwords. */ - -static void longReverse(SHA_INT64 *buffer, int byteCount, int Endianness) -{ - SHA_INT64 value; - - if ( Endianness == PCT_BIG_ENDIAN ) - return; - - byteCount /= sizeof(*buffer); - while (byteCount--) { - value = *buffer; - - ((unsigned char*)buffer)[0] = (unsigned char)(value >> 56) & 0xff; - ((unsigned char*)buffer)[1] = (unsigned char)(value >> 48) & 0xff; - ((unsigned char*)buffer)[2] = (unsigned char)(value >> 40) & 0xff; - ((unsigned char*)buffer)[3] = (unsigned char)(value >> 32) & 0xff; - ((unsigned char*)buffer)[4] = (unsigned char)(value >> 24) & 0xff; - ((unsigned char*)buffer)[5] = (unsigned char)(value >> 16) & 0xff; - ((unsigned char*)buffer)[6] = (unsigned char)(value >> 8) & 0xff; - ((unsigned char*)buffer)[7] = (unsigned char)(value ) & 0xff; - - buffer++; - } -} - -static void SHAcopy(SHAobject *src, SHAobject *dest) -{ - dest->Endianness = src->Endianness; - dest->local = src->local; - dest->digestsize = src->digestsize; - dest->count_lo = src->count_lo; - dest->count_hi = src->count_hi; - memcpy(dest->digest, src->digest, sizeof(src->digest)); - memcpy(dest->data, src->data, sizeof(src->data)); -} - - -/* ------------------------------------------------------------------------ - * - * This code for the SHA-512 algorithm was noted as public domain. The - * original headers are pasted below. - * - * Several changes have been made to make it more compatible with the - * Python environment and desired interface. - * - */ - -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * gurantee it works. - * - * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org - */ - - -/* SHA512 by Tom St Denis */ - -/* Various logical functions */ -#define ROR64(x, y) \ - ( ((((x) & 0xFFFFFFFFFFFFFFFFULL)>>((unsigned PY_LONG_LONG)(y) & 63)) | \ - ((x)<<((unsigned PY_LONG_LONG)(64-((y) & 63))))) & 0xFFFFFFFFFFFFFFFFULL) -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) ROR64((x),(n)) -#define R(x, n) (((x) & 0xFFFFFFFFFFFFFFFFULL) >> ((unsigned PY_LONG_LONG)n)) -#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) -#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) -#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) -#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) - - -static void -sha512_transform(SHAobject *sha_info) -{ - int i; - SHA_INT64 S[8], W[80], t0, t1; - - memcpy(W, sha_info->data, sizeof(sha_info->data)); - longReverse(W, (int)sizeof(sha_info->data), sha_info->Endianness); - - for (i = 16; i < 80; ++i) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } - for (i = 0; i < 8; ++i) { - S[i] = sha_info->digest[i]; - } - - /* Compress */ -#define RND(a,b,c,d,e,f,g,h,i,ki) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; - - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98d728ae22ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x7137449123ef65cdULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcfec4d3b2fULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba58189dbbcULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25bf348b538ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1b605d019ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4af194f9bULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5da6d8118ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98a3030242ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b0145706fbeULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be4ee4b28cULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3d5ffb4e2ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74f27b896fULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe3b1696b1ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a725c71235ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174cf692694ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c19ef14ad2ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786384f25e3ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc68b8cd5b5ULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc77ac9c65ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f592b0275ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa6ea6e483ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dcbd41fbd4ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da831153b5ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152ee66dfabULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d2db43210ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c898fb213fULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7beef0ee4ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf33da88fc2ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147930aa725ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351e003826fULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x142929670a0e6e70ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a8546d22ffcULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b21385c26c926ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc5ac42aedULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d139d95b3dfULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a73548baf63deULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb3c77b2a8ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e47edaee6ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c851482353bULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a14cf10364ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664bbc423001ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70d0f89791ULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a30654be30ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819d6ef5218ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd69906245565a910ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e35855771202aULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa07032bbd1b8ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116b8d2d0c8ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c085141ab53ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774cdf8eeb99ULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5e19b48a8ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3c5c95a63ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4ae3418acbULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f7763e373ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3d6b2b8a3ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee5defb2fcULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f43172f60ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814a1f0ab72ULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc702081a6439ecULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa23631e28ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506cebde82bde9ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7b2c67915ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2e372532bULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],64,0xca273eceea26619cULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],65,0xd186b8c721c0c207ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],66,0xeada7dd6cde0eb1eULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],67,0xf57d4f7fee6ed178ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],68,0x06f067aa72176fbaULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],69,0x0a637dc5a2c898a6ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],70,0x113f9804bef90daeULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],71,0x1b710b35131c471bULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],72,0x28db77f523047d84ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],73,0x32caab7b40c72493ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],74,0x3c9ebe0a15c9bebcULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],75,0x431d67c49c100d4cULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],76,0x4cc5d4becb3e42b6ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],77,0x597f299cfc657e2aULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],78,0x5fcb6fab3ad6faecULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],79,0x6c44198c4a475817ULL); - -#undef RND - - /* feedback */ - for (i = 0; i < 8; i++) { - sha_info->digest[i] = sha_info->digest[i] + S[i]; - } - -} - - - -/* initialize the SHA digest */ - -static void -sha512_init(SHAobject *sha_info) -{ - TestEndianness(sha_info->Endianness) - sha_info->digest[0] = 0x6a09e667f3bcc908ULL; - sha_info->digest[1] = 0xbb67ae8584caa73bULL; - sha_info->digest[2] = 0x3c6ef372fe94f82bULL; - sha_info->digest[3] = 0xa54ff53a5f1d36f1ULL; - sha_info->digest[4] = 0x510e527fade682d1ULL; - sha_info->digest[5] = 0x9b05688c2b3e6c1fULL; - sha_info->digest[6] = 0x1f83d9abfb41bd6bULL; - sha_info->digest[7] = 0x5be0cd19137e2179ULL; - sha_info->count_lo = 0L; - sha_info->count_hi = 0L; - sha_info->local = 0; - sha_info->digestsize = 64; -} - -static void -sha384_init(SHAobject *sha_info) -{ - TestEndianness(sha_info->Endianness) - sha_info->digest[0] = 0xcbbb9d5dc1059ed8ULL; - sha_info->digest[1] = 0x629a292a367cd507ULL; - sha_info->digest[2] = 0x9159015a3070dd17ULL; - sha_info->digest[3] = 0x152fecd8f70e5939ULL; - sha_info->digest[4] = 0x67332667ffc00b31ULL; - sha_info->digest[5] = 0x8eb44a8768581511ULL; - sha_info->digest[6] = 0xdb0c2e0d64f98fa7ULL; - sha_info->digest[7] = 0x47b5481dbefa4fa4ULL; - sha_info->count_lo = 0L; - sha_info->count_hi = 0L; - sha_info->local = 0; - sha_info->digestsize = 48; -} - - -/* update the SHA digest */ - -static void -sha512_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) -{ - int i; - SHA_INT32 clo; - - clo = sha_info->count_lo + ((SHA_INT32) count << 3); - if (clo < sha_info->count_lo) { - ++sha_info->count_hi; - } - sha_info->count_lo = clo; - sha_info->count_hi += (SHA_INT32) count >> 29; - if (sha_info->local) { - i = SHA_BLOCKSIZE - sha_info->local; - if (i > count) { - i = count; - } - memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); - count -= i; - buffer += i; - sha_info->local += i; - if (sha_info->local == SHA_BLOCKSIZE) { - sha512_transform(sha_info); - } - else { - return; - } - } - while (count >= SHA_BLOCKSIZE) { - memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); - buffer += SHA_BLOCKSIZE; - count -= SHA_BLOCKSIZE; - sha512_transform(sha_info); - } - memcpy(sha_info->data, buffer, count); - sha_info->local = count; -} - -/* finish computing the SHA digest */ - -static void -sha512_final(unsigned char digest[SHA_DIGESTSIZE], SHAobject *sha_info) -{ - int count; - SHA_INT32 lo_bit_count, hi_bit_count; - - lo_bit_count = sha_info->count_lo; - hi_bit_count = sha_info->count_hi; - count = (int) ((lo_bit_count >> 3) & 0x7f); - ((SHA_BYTE *) sha_info->data)[count++] = 0x80; - if (count > SHA_BLOCKSIZE - 16) { - memset(((SHA_BYTE *) sha_info->data) + count, 0, - SHA_BLOCKSIZE - count); - sha512_transform(sha_info); - memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 16); - } - else { - memset(((SHA_BYTE *) sha_info->data) + count, 0, - SHA_BLOCKSIZE - 16 - count); - } - - /* GJS: note that we add the hi/lo in big-endian. sha512_transform will - swap these values into host-order. */ - sha_info->data[112] = 0; - sha_info->data[113] = 0; - sha_info->data[114] = 0; - sha_info->data[115] = 0; - sha_info->data[116] = 0; - sha_info->data[117] = 0; - sha_info->data[118] = 0; - sha_info->data[119] = 0; - sha_info->data[120] = (hi_bit_count >> 24) & 0xff; - sha_info->data[121] = (hi_bit_count >> 16) & 0xff; - sha_info->data[122] = (hi_bit_count >> 8) & 0xff; - sha_info->data[123] = (hi_bit_count >> 0) & 0xff; - sha_info->data[124] = (lo_bit_count >> 24) & 0xff; - sha_info->data[125] = (lo_bit_count >> 16) & 0xff; - sha_info->data[126] = (lo_bit_count >> 8) & 0xff; - sha_info->data[127] = (lo_bit_count >> 0) & 0xff; - sha512_transform(sha_info); - digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 56) & 0xff); - digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 48) & 0xff); - digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 40) & 0xff); - digest[ 3] = (unsigned char) ((sha_info->digest[0] >> 32) & 0xff); - digest[ 4] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); - digest[ 5] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); - digest[ 6] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); - digest[ 7] = (unsigned char) ((sha_info->digest[0] ) & 0xff); - digest[ 8] = (unsigned char) ((sha_info->digest[1] >> 56) & 0xff); - digest[ 9] = (unsigned char) ((sha_info->digest[1] >> 48) & 0xff); - digest[10] = (unsigned char) ((sha_info->digest[1] >> 40) & 0xff); - digest[11] = (unsigned char) ((sha_info->digest[1] >> 32) & 0xff); - digest[12] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); - digest[13] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); - digest[14] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); - digest[15] = (unsigned char) ((sha_info->digest[1] ) & 0xff); - digest[16] = (unsigned char) ((sha_info->digest[2] >> 56) & 0xff); - digest[17] = (unsigned char) ((sha_info->digest[2] >> 48) & 0xff); - digest[18] = (unsigned char) ((sha_info->digest[2] >> 40) & 0xff); - digest[19] = (unsigned char) ((sha_info->digest[2] >> 32) & 0xff); - digest[20] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); - digest[21] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); - digest[22] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); - digest[23] = (unsigned char) ((sha_info->digest[2] ) & 0xff); - digest[24] = (unsigned char) ((sha_info->digest[3] >> 56) & 0xff); - digest[25] = (unsigned char) ((sha_info->digest[3] >> 48) & 0xff); - digest[26] = (unsigned char) ((sha_info->digest[3] >> 40) & 0xff); - digest[27] = (unsigned char) ((sha_info->digest[3] >> 32) & 0xff); - digest[28] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); - digest[29] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); - digest[30] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); - digest[31] = (unsigned char) ((sha_info->digest[3] ) & 0xff); - digest[32] = (unsigned char) ((sha_info->digest[4] >> 56) & 0xff); - digest[33] = (unsigned char) ((sha_info->digest[4] >> 48) & 0xff); - digest[34] = (unsigned char) ((sha_info->digest[4] >> 40) & 0xff); - digest[35] = (unsigned char) ((sha_info->digest[4] >> 32) & 0xff); - digest[36] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); - digest[37] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); - digest[38] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); - digest[39] = (unsigned char) ((sha_info->digest[4] ) & 0xff); - digest[40] = (unsigned char) ((sha_info->digest[5] >> 56) & 0xff); - digest[41] = (unsigned char) ((sha_info->digest[5] >> 48) & 0xff); - digest[42] = (unsigned char) ((sha_info->digest[5] >> 40) & 0xff); - digest[43] = (unsigned char) ((sha_info->digest[5] >> 32) & 0xff); - digest[44] = (unsigned char) ((sha_info->digest[5] >> 24) & 0xff); - digest[45] = (unsigned char) ((sha_info->digest[5] >> 16) & 0xff); - digest[46] = (unsigned char) ((sha_info->digest[5] >> 8) & 0xff); - digest[47] = (unsigned char) ((sha_info->digest[5] ) & 0xff); - digest[48] = (unsigned char) ((sha_info->digest[6] >> 56) & 0xff); - digest[49] = (unsigned char) ((sha_info->digest[6] >> 48) & 0xff); - digest[50] = (unsigned char) ((sha_info->digest[6] >> 40) & 0xff); - digest[51] = (unsigned char) ((sha_info->digest[6] >> 32) & 0xff); - digest[52] = (unsigned char) ((sha_info->digest[6] >> 24) & 0xff); - digest[53] = (unsigned char) ((sha_info->digest[6] >> 16) & 0xff); - digest[54] = (unsigned char) ((sha_info->digest[6] >> 8) & 0xff); - digest[55] = (unsigned char) ((sha_info->digest[6] ) & 0xff); - digest[56] = (unsigned char) ((sha_info->digest[7] >> 56) & 0xff); - digest[57] = (unsigned char) ((sha_info->digest[7] >> 48) & 0xff); - digest[58] = (unsigned char) ((sha_info->digest[7] >> 40) & 0xff); - digest[59] = (unsigned char) ((sha_info->digest[7] >> 32) & 0xff); - digest[60] = (unsigned char) ((sha_info->digest[7] >> 24) & 0xff); - digest[61] = (unsigned char) ((sha_info->digest[7] >> 16) & 0xff); - digest[62] = (unsigned char) ((sha_info->digest[7] >> 8) & 0xff); - digest[63] = (unsigned char) ((sha_info->digest[7] ) & 0xff); -} - -/* - * End of copied SHA code. - * - * ------------------------------------------------------------------------ - */ - -static PyTypeObject SHA384type; -static PyTypeObject SHA512type; - - -static SHAobject * -newSHA384object(void) -{ - return (SHAobject *)PyObject_New(SHAobject, &SHA384type); -} - -static SHAobject * -newSHA512object(void) -{ - return (SHAobject *)PyObject_New(SHAobject, &SHA512type); -} - -/* Internal methods for a hash object */ - -static void -SHA512_dealloc(PyObject *ptr) -{ - PyObject_Del(ptr); -} - - -/* External methods for a hash object */ - -PyDoc_STRVAR(SHA512_copy__doc__, "Return a copy of the hash object."); - -static PyObject * -SHA512_copy(SHAobject *self, PyObject *unused) -{ - SHAobject *newobj; - - if (((PyObject*)self)->ob_type == &SHA512type) { - if ( (newobj = newSHA512object())==NULL) - return NULL; - } else { - if ( (newobj = newSHA384object())==NULL) - return NULL; - } - - SHAcopy(self, newobj); - return (PyObject *)newobj; -} - -PyDoc_STRVAR(SHA512_digest__doc__, -"Return the digest value as a string of binary data."); - -static PyObject * -SHA512_digest(SHAobject *self, PyObject *unused) -{ - unsigned char digest[SHA_DIGESTSIZE]; - SHAobject temp; - - SHAcopy(self, &temp); - sha512_final(digest, &temp); - return PyString_FromStringAndSize((const char *)digest, self->digestsize); -} - -PyDoc_STRVAR(SHA512_hexdigest__doc__, -"Return the digest value as a string of hexadecimal digits."); - -static PyObject * -SHA512_hexdigest(SHAobject *self, PyObject *unused) -{ - unsigned char digest[SHA_DIGESTSIZE]; - SHAobject temp; - PyObject *retval; - char *hex_digest; - int i, j; - - /* Get the raw (binary) digest value */ - SHAcopy(self, &temp); - sha512_final(digest, &temp); - - /* Create a new string */ - retval = PyString_FromStringAndSize(NULL, self->digestsize * 2); - if (!retval) - return NULL; - hex_digest = PyString_AsString(retval); - if (!hex_digest) { - Py_DECREF(retval); - return NULL; - } - - /* Make hex version of the digest */ - for (i=j=0; i<self->digestsize; i++) { - char c; - c = (digest[i] >> 4) & 0xf; - c = (c>9) ? c+'a'-10 : c + '0'; - hex_digest[j++] = c; - c = (digest[i] & 0xf); - c = (c>9) ? c+'a'-10 : c + '0'; - hex_digest[j++] = c; - } - return retval; -} - -PyDoc_STRVAR(SHA512_update__doc__, -"Update this hash object's state with the provided string."); - -static PyObject * -SHA512_update(SHAobject *self, PyObject *args) -{ - unsigned char *cp; - int len; - - if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) - return NULL; - - sha512_update(self, cp, len); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef SHA_methods[] = { - {"copy", (PyCFunction)SHA512_copy, METH_NOARGS, SHA512_copy__doc__}, - {"digest", (PyCFunction)SHA512_digest, METH_NOARGS, SHA512_digest__doc__}, - {"hexdigest", (PyCFunction)SHA512_hexdigest, METH_NOARGS, SHA512_hexdigest__doc__}, - {"update", (PyCFunction)SHA512_update, METH_VARARGS, SHA512_update__doc__}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject * -SHA512_get_block_size(PyObject *self, void *closure) -{ - return PyInt_FromLong(SHA_BLOCKSIZE); -} - -static PyObject * -SHA512_get_name(PyObject *self, void *closure) -{ - if (((SHAobject *)self)->digestsize == 64) - return PyString_FromStringAndSize("SHA512", 6); - else - return PyString_FromStringAndSize("SHA384", 6); -} - -static PyGetSetDef SHA_getseters[] = { - {"block_size", - (getter)SHA512_get_block_size, NULL, - NULL, - NULL}, - {"name", - (getter)SHA512_get_name, NULL, - NULL, - NULL}, - {NULL} /* Sentinel */ -}; - -static PyMemberDef SHA_members[] = { - {"digest_size", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, - /* the old md5 and sha modules support 'digest_size' as in PEP 247. - * the old sha module also supported 'digestsize'. ugh. */ - {"digestsize", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, - {NULL} /* Sentinel */ -}; - -static PyTypeObject SHA384type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "_sha512.sha384", /*tp_name*/ - sizeof(SHAobject), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - SHA512_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - SHA_methods, /* tp_methods */ - SHA_members, /* tp_members */ - SHA_getseters, /* tp_getset */ -}; - -static PyTypeObject SHA512type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "_sha512.sha512", /*tp_name*/ - sizeof(SHAobject), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - SHA512_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - SHA_methods, /* tp_methods */ - SHA_members, /* tp_members */ - SHA_getseters, /* tp_getset */ -}; - - -/* The single module-level function: new() */ - -PyDoc_STRVAR(SHA512_new__doc__, -"Return a new SHA-512 hash object; optionally initialized with a string."); - -static PyObject * -SHA512_new(PyObject *self, PyObject *args, PyObject *kwdict) -{ - static char *kwlist[] = {"string", NULL}; - SHAobject *new; - unsigned char *cp = NULL; - int len; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { - return NULL; - } - - if ((new = newSHA512object()) == NULL) - return NULL; - - sha512_init(new); - - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; - } - if (cp) - sha512_update(new, cp, len); - - return (PyObject *)new; -} - -PyDoc_STRVAR(SHA384_new__doc__, -"Return a new SHA-384 hash object; optionally initialized with a string."); - -static PyObject * -SHA384_new(PyObject *self, PyObject *args, PyObject *kwdict) -{ - static char *kwlist[] = {"string", NULL}; - SHAobject *new; - unsigned char *cp = NULL; - int len; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { - return NULL; - } - - if ((new = newSHA384object()) == NULL) - return NULL; - - sha384_init(new); - - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; - } - if (cp) - sha512_update(new, cp, len); - - return (PyObject *)new; -} - - -/* List of functions exported by this module */ - -static struct PyMethodDef SHA_functions[] = { - {"sha512", (PyCFunction)SHA512_new, METH_VARARGS|METH_KEYWORDS, SHA512_new__doc__}, - {"sha384", (PyCFunction)SHA384_new, METH_VARARGS|METH_KEYWORDS, SHA384_new__doc__}, - {NULL, NULL} /* Sentinel */ -}; - - -/* Initialize this module. */ - -#define insint(n,v) { PyModule_AddIntConstant(m,n,v); } - -PyMODINIT_FUNC -init_sha512(void) -{ - PyObject *m; - - SHA384type.ob_type = &PyType_Type; - if (PyType_Ready(&SHA384type) < 0) - return; - SHA512type.ob_type = &PyType_Type; - if (PyType_Ready(&SHA512type) < 0) - return; - m = Py_InitModule("_sha512", SHA_functions); - if (m == NULL) - return; -} - -#endif diff --git a/src/distutils2/_backport/shamodule.c b/src/distutils2/_backport/shamodule.c deleted file mode 100644 index 171dfa1..0000000 --- a/src/distutils2/_backport/shamodule.c +++ /dev/null @@ -1,593 +0,0 @@ -/* SHA module */ - -/* This module provides an interface to NIST's Secure Hash Algorithm */ - -/* See below for information about the original code this module was - based upon. Additional work performed by: - - Andrew Kuchling (amk@amk.ca) - Greg Stein (gstein@lyra.org) - - Copyright (C) 2005 Gregory P. Smith (greg@krypto.org) - Licensed to PSF under a Contributor Agreement. - -*/ - -/* SHA objects */ - -#include "Python.h" -#include "structmember.h" - - -/* Endianness testing and definitions */ -#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ - if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} - -#define PCT_LITTLE_ENDIAN 1 -#define PCT_BIG_ENDIAN 0 - -/* Some useful types */ - -typedef unsigned char SHA_BYTE; - -#if SIZEOF_INT == 4 -typedef unsigned int SHA_INT32; /* 32-bit integer */ -#else -/* not defined. compilation will die. */ -#endif - -/* The SHA block size and message digest sizes, in bytes */ - -#define SHA_BLOCKSIZE 64 -#define SHA_DIGESTSIZE 20 - -/* The structure for storing SHS info */ - -typedef struct { - PyObject_HEAD - SHA_INT32 digest[5]; /* Message digest */ - SHA_INT32 count_lo, count_hi; /* 64-bit bit count */ - SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ - int Endianness; - int local; /* unprocessed amount in data */ -} SHAobject; - -/* When run on a little-endian CPU we need to perform byte reversal on an - array of longwords. */ - -static void longReverse(SHA_INT32 *buffer, int byteCount, int Endianness) -{ - SHA_INT32 value; - - if ( Endianness == PCT_BIG_ENDIAN ) - return; - - byteCount /= sizeof(*buffer); - while (byteCount--) { - value = *buffer; - value = ( ( value & 0xFF00FF00L ) >> 8 ) | \ - ( ( value & 0x00FF00FFL ) << 8 ); - *buffer++ = ( value << 16 ) | ( value >> 16 ); - } -} - -static void SHAcopy(SHAobject *src, SHAobject *dest) -{ - dest->Endianness = src->Endianness; - dest->local = src->local; - dest->count_lo = src->count_lo; - dest->count_hi = src->count_hi; - memcpy(dest->digest, src->digest, sizeof(src->digest)); - memcpy(dest->data, src->data, sizeof(src->data)); -} - - -/* ------------------------------------------------------------------------ - * - * This code for the SHA algorithm was noted as public domain. The original - * headers are pasted below. - * - * Several changes have been made to make it more compatible with the - * Python environment and desired interface. - * - */ - -/* NIST Secure Hash Algorithm */ -/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */ -/* from Peter C. Gutmann's implementation as found in */ -/* Applied Cryptography by Bruce Schneier */ -/* Further modifications to include the "UNRAVEL" stuff, below */ - -/* This code is in the public domain */ - -/* UNRAVEL should be fastest & biggest */ -/* UNROLL_LOOPS should be just as big, but slightly slower */ -/* both undefined should be smallest and slowest */ - -#define UNRAVEL -/* #define UNROLL_LOOPS */ - -/* The SHA f()-functions. The f1 and f3 functions can be optimized to - save one boolean operation each - thanks to Rich Schroeppel, - rcs@cs.arizona.edu for discovering this */ - -/*#define f1(x,y,z) ((x & y) | (~x & z)) // Rounds 0-19 */ -#define f1(x,y,z) (z ^ (x & (y ^ z))) /* Rounds 0-19 */ -#define f2(x,y,z) (x ^ y ^ z) /* Rounds 20-39 */ -/*#define f3(x,y,z) ((x & y) | (x & z) | (y & z)) // Rounds 40-59 */ -#define f3(x,y,z) ((x & y) | (z & (x | y))) /* Rounds 40-59 */ -#define f4(x,y,z) (x ^ y ^ z) /* Rounds 60-79 */ - -/* SHA constants */ - -#define CONST1 0x5a827999L /* Rounds 0-19 */ -#define CONST2 0x6ed9eba1L /* Rounds 20-39 */ -#define CONST3 0x8f1bbcdcL /* Rounds 40-59 */ -#define CONST4 0xca62c1d6L /* Rounds 60-79 */ - -/* 32-bit rotate */ - -#define R32(x,n) ((x << n) | (x >> (32 - n))) - -/* the generic case, for when the overall rotation is not unraveled */ - -#define FG(n) \ - T = R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n; \ - E = D; D = C; C = R32(B,30); B = A; A = T - -/* specific cases, for when the overall rotation is unraveled */ - -#define FA(n) \ - T = R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n; B = R32(B,30) - -#define FB(n) \ - E = R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n; A = R32(A,30) - -#define FC(n) \ - D = R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n; T = R32(T,30) - -#define FD(n) \ - C = R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n; E = R32(E,30) - -#define FE(n) \ - B = R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n; D = R32(D,30) - -#define FT(n) \ - A = R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n; C = R32(C,30) - -/* do SHA transformation */ - -static void -sha_transform(SHAobject *sha_info) -{ - int i; - SHA_INT32 T, A, B, C, D, E, W[80], *WP; - - memcpy(W, sha_info->data, sizeof(sha_info->data)); - longReverse(W, (int)sizeof(sha_info->data), sha_info->Endianness); - - for (i = 16; i < 80; ++i) { - W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; - - /* extra rotation fix */ - W[i] = R32(W[i], 1); - } - A = sha_info->digest[0]; - B = sha_info->digest[1]; - C = sha_info->digest[2]; - D = sha_info->digest[3]; - E = sha_info->digest[4]; - WP = W; -#ifdef UNRAVEL - FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); - FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); - FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); - FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); - FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); - FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); - FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); - FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); - sha_info->digest[0] += E; - sha_info->digest[1] += T; - sha_info->digest[2] += A; - sha_info->digest[3] += B; - sha_info->digest[4] += C; -#else /* !UNRAVEL */ -#ifdef UNROLL_LOOPS - FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); - FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); - FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); - FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); - FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); - FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); - FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); - FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); -#else /* !UNROLL_LOOPS */ - for (i = 0; i < 20; ++i) { FG(1); } - for (i = 20; i < 40; ++i) { FG(2); } - for (i = 40; i < 60; ++i) { FG(3); } - for (i = 60; i < 80; ++i) { FG(4); } -#endif /* !UNROLL_LOOPS */ - sha_info->digest[0] += A; - sha_info->digest[1] += B; - sha_info->digest[2] += C; - sha_info->digest[3] += D; - sha_info->digest[4] += E; -#endif /* !UNRAVEL */ -} - -/* initialize the SHA digest */ - -static void -sha_init(SHAobject *sha_info) -{ - TestEndianness(sha_info->Endianness) - - sha_info->digest[0] = 0x67452301L; - sha_info->digest[1] = 0xefcdab89L; - sha_info->digest[2] = 0x98badcfeL; - sha_info->digest[3] = 0x10325476L; - sha_info->digest[4] = 0xc3d2e1f0L; - sha_info->count_lo = 0L; - sha_info->count_hi = 0L; - sha_info->local = 0; -} - -/* update the SHA digest */ - -static void -sha_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) -{ - int i; - SHA_INT32 clo; - - clo = sha_info->count_lo + ((SHA_INT32) count << 3); - if (clo < sha_info->count_lo) { - ++sha_info->count_hi; - } - sha_info->count_lo = clo; - sha_info->count_hi += (SHA_INT32) count >> 29; - if (sha_info->local) { - i = SHA_BLOCKSIZE - sha_info->local; - if (i > count) { - i = count; - } - memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); - count -= i; - buffer += i; - sha_info->local += i; - if (sha_info->local == SHA_BLOCKSIZE) { - sha_transform(sha_info); - } - else { - return; - } - } - while (count >= SHA_BLOCKSIZE) { - memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); - buffer += SHA_BLOCKSIZE; - count -= SHA_BLOCKSIZE; - sha_transform(sha_info); - } - memcpy(sha_info->data, buffer, count); - sha_info->local = count; -} - -/* finish computing the SHA digest */ - -static void -sha_final(unsigned char digest[20], SHAobject *sha_info) -{ - int count; - SHA_INT32 lo_bit_count, hi_bit_count; - - lo_bit_count = sha_info->count_lo; - hi_bit_count = sha_info->count_hi; - count = (int) ((lo_bit_count >> 3) & 0x3f); - ((SHA_BYTE *) sha_info->data)[count++] = 0x80; - if (count > SHA_BLOCKSIZE - 8) { - memset(((SHA_BYTE *) sha_info->data) + count, 0, - SHA_BLOCKSIZE - count); - sha_transform(sha_info); - memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8); - } - else { - memset(((SHA_BYTE *) sha_info->data) + count, 0, - SHA_BLOCKSIZE - 8 - count); - } - - /* GJS: note that we add the hi/lo in big-endian. sha_transform will - swap these values into host-order. */ - sha_info->data[56] = (hi_bit_count >> 24) & 0xff; - sha_info->data[57] = (hi_bit_count >> 16) & 0xff; - sha_info->data[58] = (hi_bit_count >> 8) & 0xff; - sha_info->data[59] = (hi_bit_count >> 0) & 0xff; - sha_info->data[60] = (lo_bit_count >> 24) & 0xff; - sha_info->data[61] = (lo_bit_count >> 16) & 0xff; - sha_info->data[62] = (lo_bit_count >> 8) & 0xff; - sha_info->data[63] = (lo_bit_count >> 0) & 0xff; - sha_transform(sha_info); - digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); - digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); - digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); - digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff); - digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); - digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); - digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); - digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff); - digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); - digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); - digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); - digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff); - digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); - digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); - digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); - digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff); - digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); - digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); - digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); - digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff); -} - -/* - * End of copied SHA code. - * - * ------------------------------------------------------------------------ - */ - -static PyTypeObject SHAtype; - - -static SHAobject * -newSHAobject(void) -{ - return (SHAobject *)PyObject_New(SHAobject, &SHAtype); -} - -/* Internal methods for a hashing object */ - -static void -SHA_dealloc(PyObject *ptr) -{ - PyObject_Del(ptr); -} - - -/* External methods for a hashing object */ - -PyDoc_STRVAR(SHA_copy__doc__, "Return a copy of the hashing object."); - -static PyObject * -SHA_copy(SHAobject *self, PyObject *unused) -{ - SHAobject *newobj; - - if ( (newobj = newSHAobject())==NULL) - return NULL; - - SHAcopy(self, newobj); - return (PyObject *)newobj; -} - -PyDoc_STRVAR(SHA_digest__doc__, -"Return the digest value as a string of binary data."); - -static PyObject * -SHA_digest(SHAobject *self, PyObject *unused) -{ - unsigned char digest[SHA_DIGESTSIZE]; - SHAobject temp; - - SHAcopy(self, &temp); - sha_final(digest, &temp); - return PyString_FromStringAndSize((const char *)digest, sizeof(digest)); -} - -PyDoc_STRVAR(SHA_hexdigest__doc__, -"Return the digest value as a string of hexadecimal digits."); - -static PyObject * -SHA_hexdigest(SHAobject *self, PyObject *unused) -{ - unsigned char digest[SHA_DIGESTSIZE]; - SHAobject temp; - PyObject *retval; - char *hex_digest; - int i, j; - - /* Get the raw (binary) digest value */ - SHAcopy(self, &temp); - sha_final(digest, &temp); - - /* Create a new string */ - retval = PyString_FromStringAndSize(NULL, sizeof(digest) * 2); - if (!retval) - return NULL; - hex_digest = PyString_AsString(retval); - if (!hex_digest) { - Py_DECREF(retval); - return NULL; - } - - /* Make hex version of the digest */ - for(i=j=0; i<sizeof(digest); i++) { - char c; - c = (digest[i] >> 4) & 0xf; - c = (c>9) ? c+'a'-10 : c + '0'; - hex_digest[j++] = c; - c = (digest[i] & 0xf); - c = (c>9) ? c+'a'-10 : c + '0'; - hex_digest[j++] = c; - } - return retval; -} - -PyDoc_STRVAR(SHA_update__doc__, -"Update this hashing object's state with the provided string."); - -static PyObject * -SHA_update(SHAobject *self, PyObject *args) -{ - unsigned char *cp; - int len; - - if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) - return NULL; - - sha_update(self, cp, len); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef SHA_methods[] = { - {"copy", (PyCFunction)SHA_copy, METH_NOARGS, SHA_copy__doc__}, - {"digest", (PyCFunction)SHA_digest, METH_NOARGS, SHA_digest__doc__}, - {"hexdigest", (PyCFunction)SHA_hexdigest, METH_NOARGS, SHA_hexdigest__doc__}, - {"update", (PyCFunction)SHA_update, METH_VARARGS, SHA_update__doc__}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject * -SHA_get_block_size(PyObject *self, void *closure) -{ - return PyInt_FromLong(SHA_BLOCKSIZE); -} - -static PyObject * -SHA_get_digest_size(PyObject *self, void *closure) -{ - return PyInt_FromLong(SHA_DIGESTSIZE); -} - -static PyObject * -SHA_get_name(PyObject *self, void *closure) -{ - return PyString_FromStringAndSize("SHA1", 4); -} - -static PyGetSetDef SHA_getseters[] = { - {"digest_size", - (getter)SHA_get_digest_size, NULL, - NULL, - NULL}, - {"block_size", - (getter)SHA_get_block_size, NULL, - NULL, - NULL}, - {"name", - (getter)SHA_get_name, NULL, - NULL, - NULL}, - /* the old md5 and sha modules support 'digest_size' as in PEP 247. - * the old sha module also supported 'digestsize'. ugh. */ - {"digestsize", - (getter)SHA_get_digest_size, NULL, - NULL, - NULL}, - {NULL} /* Sentinel */ -}; - -static PyTypeObject SHAtype = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "_sha.sha", /*tp_name*/ - sizeof(SHAobject), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - SHA_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - SHA_methods, /* tp_methods */ - 0, /* tp_members */ - SHA_getseters, /* tp_getset */ -}; - - -/* The single module-level function: new() */ - -PyDoc_STRVAR(SHA_new__doc__, -"Return a new SHA hashing object. An optional string argument\n\ -may be provided; if present, this string will be automatically\n\ -hashed."); - -static PyObject * -SHA_new(PyObject *self, PyObject *args, PyObject *kwdict) -{ - static char *kwlist[] = {"string", NULL}; - SHAobject *new; - unsigned char *cp = NULL; - int len; - - if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, - &cp, &len)) { - return NULL; - } - - if ((new = newSHAobject()) == NULL) - return NULL; - - sha_init(new); - - if (PyErr_Occurred()) { - Py_DECREF(new); - return NULL; - } - if (cp) - sha_update(new, cp, len); - - return (PyObject *)new; -} - - -/* List of functions exported by this module */ - -static struct PyMethodDef SHA_functions[] = { - {"new", (PyCFunction)SHA_new, METH_VARARGS|METH_KEYWORDS, SHA_new__doc__}, - {NULL, NULL} /* Sentinel */ -}; - - -/* Initialize this module. */ - -#define insint(n,v) { PyModule_AddIntConstant(m,n,v); } - -PyMODINIT_FUNC -init_sha(void) -{ - PyObject *m; - - SHAtype.ob_type = &PyType_Type; - if (PyType_Ready(&SHAtype) < 0) - return; - m = Py_InitModule("_sha", SHA_functions); - if (m == NULL) - return; - - /* Add some symbolic constants to the module */ - insint("blocksize", 1); /* For future use, in case some hash - functions require an integral number of - blocks */ - insint("digestsize", 20); - insint("digest_size", 20); -} diff --git a/src/distutils2/_backport/shutil.py b/src/distutils2/_backport/shutil.py deleted file mode 100644 index b9e6a77..0000000 --- a/src/distutils2/_backport/shutil.py +++ /dev/null @@ -1,570 +0,0 @@ -"""Utility functions for copying files and directory trees. - -XXX The functions here don't copy the resource fork or other metadata on Mac. - -""" - -import os -import sys -import stat -from os.path import abspath -import fnmatch -from warnings import warn - -try: - from pwd import getpwnam -except ImportError: - getpwnam = None - -try: - from grp import getgrnam -except ImportError: - getgrnam = None - -__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2", - "copytree","move","rmtree","Error", "SpecialFileError", - "ExecError","make_archive"] - -class Error(EnvironmentError): - pass - -class SpecialFileError(EnvironmentError): - """Raised when trying to do a kind of operation (e.g. copying) which is - not supported on a special file (e.g. a named pipe)""" - -class ExecError(EnvironmentError): - """Raised when a command could not be executed""" - -try: - WindowsError -except NameError: - WindowsError = None - -def copyfileobj(fsrc, fdst, length=16*1024): - """copy data from file-like object fsrc to file-like object fdst""" - while 1: - buf = fsrc.read(length) - if not buf: - break - fdst.write(buf) - -def _samefile(src, dst): - # Macintosh, Unix. - if hasattr(os.path,'samefile'): - try: - return os.path.samefile(src, dst) - except OSError: - return False - - # All other platforms: check for same pathname. - return (os.path.normcase(os.path.abspath(src)) == - os.path.normcase(os.path.abspath(dst))) - -def copyfile(src, dst): - """Copy data from src to dst""" - if _samefile(src, dst): - raise Error, "`%s` and `%s` are the same file" % (src, dst) - - fsrc = None - fdst = None - for fn in [src, dst]: - try: - st = os.stat(fn) - except OSError: - # File most likely does not exist - pass - else: - # XXX What about other special files? (sockets, devices...) - if stat.S_ISFIFO(st.st_mode): - raise SpecialFileError("`%s` is a named pipe" % fn) - try: - fsrc = open(src, 'rb') - fdst = open(dst, 'wb') - copyfileobj(fsrc, fdst) - finally: - if fdst: - fdst.close() - if fsrc: - fsrc.close() - -def copymode(src, dst): - """Copy mode bits from src to dst""" - if hasattr(os, 'chmod'): - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - os.chmod(dst, mode) - -def copystat(src, dst): - """Copy all stat info (mode bits, atime, mtime, flags) from src to dst""" - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - if hasattr(os, 'utime'): - os.utime(dst, (st.st_atime, st.st_mtime)) - if hasattr(os, 'chmod'): - os.chmod(dst, mode) - if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - os.chflags(dst, st.st_flags) - - -def copy(src, dst): - """Copy data and mode bits ("cp src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copymode(src, dst) - -def copy2(src, dst): - """Copy data and all stat info ("cp -p src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copystat(src, dst) - -def ignore_patterns(*patterns): - """Function that can be used as copytree() ignore parameter. - - Patterns is a sequence of glob-style patterns - that are used to exclude files""" - def _ignore_patterns(path, names): - ignored_names = [] - for pattern in patterns: - ignored_names.extend(fnmatch.filter(names, pattern)) - return set(ignored_names) - return _ignore_patterns - -def copytree(src, dst, symlinks=False, ignore=None): - """Recursively copy a directory tree using copy2(). - - The destination directory must not already exist. - If exception(s) occur, an Error is raised with a list of reasons. - - If the optional symlinks flag is true, symbolic links in the - source tree result in symbolic links in the destination tree; if - it is false, the contents of the files pointed to by symbolic - links are copied. - - The optional ignore argument is a callable. If given, it - is called with the `src` parameter, which is the directory - being visited by copytree(), and `names` which is the list of - `src` contents, as returned by os.listdir(): - - callable(src, names) -> ignored_names - - Since copytree() is called recursively, the callable will be - called once for each directory that is copied. It returns a - list of names relative to the `src` directory that should - not be copied. - - XXX Consider this example code rather than the ultimate tool. - - """ - names = os.listdir(src) - if ignore is not None: - ignored_names = ignore(src, names) - else: - ignored_names = set() - - if not os.path.exists(dst): - os.makedirs(dst) - - errors = [] - for name in names: - if name in ignored_names: - continue - srcname = os.path.join(src, name) - dstname = os.path.join(dst, name) - try: - if symlinks and os.path.islink(srcname): - linkto = os.readlink(srcname) - os.symlink(linkto, dstname) - elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore) - else: - # Will raise a SpecialFileError for unsupported file types - copy2(srcname, dstname) - # catch the Error from the recursive copytree so that we can - # continue with other files - except Error, err: - errors.extend(err.args[0]) - except EnvironmentError, why: - errors.append((srcname, dstname, str(why))) - try: - copystat(src, dst) - except OSError, why: - if WindowsError is not None and isinstance(why, WindowsError): - # Copying file access times may fail on Windows - pass - else: - errors.extend((src, dst, str(why))) - if errors: - raise Error, errors - -def rmtree(path, ignore_errors=False, onerror=None): - """Recursively delete a directory tree. - - If ignore_errors is set, errors are ignored; otherwise, if onerror - is set, it is called to handle the error with arguments (func, - path, exc_info) where func is os.listdir, os.remove, or os.rmdir; - path is the argument to that function that caused it to fail; and - exc_info is a tuple returned by sys.exc_info(). If ignore_errors - is false and onerror is None, an exception is raised. - - """ - if ignore_errors: - def onerror(*args): - pass - elif onerror is None: - def onerror(*args): - raise - try: - if os.path.islink(path): - # symlinks to directories are forbidden, see bug #1669 - raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) - # can't continue even if onerror hook returns - return - names = [] - try: - names = os.listdir(path) - except os.error, err: - onerror(os.listdir, path, sys.exc_info()) - for name in names: - fullname = os.path.join(path, name) - try: - mode = os.lstat(fullname).st_mode - except os.error: - mode = 0 - if stat.S_ISDIR(mode): - rmtree(fullname, ignore_errors, onerror) - else: - try: - os.remove(fullname) - except os.error, err: - onerror(os.remove, fullname, sys.exc_info()) - try: - os.rmdir(path) - except os.error: - onerror(os.rmdir, path, sys.exc_info()) - - -def _basename(path): - # A basename() variant which first strips the trailing slash, if present. - # Thus we always get the last component of the path, even for directories. - return os.path.basename(path.rstrip(os.path.sep)) - -def move(src, dst): - """Recursively move a file or directory to another location. This is - similar to the Unix "mv" command. - - If the destination is a directory or a symlink to a directory, the source - is moved inside the directory. The destination path must not already - exist. - - If the destination already exists but is not a directory, it may be - overwritten depending on os.rename() semantics. - - If the destination is on our current filesystem, then rename() is used. - Otherwise, src is copied to the destination and then removed. - A lot more could be done here... A look at a mv.c shows a lot of - the issues this implementation glosses over. - - """ - real_dst = dst - if os.path.isdir(dst): - real_dst = os.path.join(dst, _basename(src)) - if os.path.exists(real_dst): - raise Error, "Destination path '%s' already exists" % real_dst - try: - os.rename(src, real_dst) - except OSError: - if os.path.isdir(src): - if _destinsrc(src, dst): - raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst) - copytree(src, real_dst, symlinks=True) - rmtree(src) - else: - copy2(src, real_dst) - os.unlink(src) - -def _destinsrc(src, dst): - src = abspath(src) - dst = abspath(dst) - if not src.endswith(os.path.sep): - src += os.path.sep - if not dst.endswith(os.path.sep): - dst += os.path.sep - return dst.startswith(src) - -def _get_gid(name): - """Returns a gid, given a group name.""" - if getgrnam is None or name is None: - return None - try: - result = getgrnam(name) - except KeyError: - result = None - if result is not None: - return result[2] - return None - -def _get_uid(name): - """Returns an uid, given a user name.""" - if getpwnam is None or name is None: - return None - try: - result = getpwnam(name) - except KeyError: - result = None - if result is not None: - return result[2] - return None - -def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, - owner=None, group=None, logger=None): - """Create a (possibly compressed) tar file from all the files under - 'base_dir'. - - 'compress' must be "gzip" (the default), "compress", "bzip2", or None. - (compress will be deprecated in Python 3.2) - - 'owner' and 'group' can be used to define an owner and a group for the - archive that is being built. If not provided, the current owner and group - will be used. - - The output tar file will be named 'base_dir' + ".tar", possibly plus - the appropriate compression extension (".gz", ".bz2" or ".Z"). - - Returns the output filename. - """ - tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', None: '', 'compress': ''} - compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'compress': '.Z'} - - # flags for compression program, each element of list will be an argument - if compress is not None and compress not in compress_ext.keys(): - raise ValueError, \ - ("bad value for 'compress': must be None, 'gzip', 'bzip2' " - "or 'compress'") - - archive_name = base_name + '.tar' - if compress != 'compress': - archive_name += compress_ext.get(compress, '') - - archive_dir = os.path.dirname(archive_name) - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s" % archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - - # creating the tarball - from distutils2._backport import tarfile - - if logger is not None: - logger.info('Creating tar archive') - - uid = _get_uid(owner) - gid = _get_gid(group) - - def _set_uid_gid(tarinfo): - if gid is not None: - tarinfo.gid = gid - tarinfo.gname = group - if uid is not None: - tarinfo.uid = uid - tarinfo.uname = owner - return tarinfo - - if not dry_run: - tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) - try: - tar.add(base_dir, filter=_set_uid_gid) - finally: - tar.close() - - # compression using `compress` - # XXX this block will be removed in Python 3.2 - if compress == 'compress': - warn("'compress' will be deprecated.", PendingDeprecationWarning) - # the option varies depending on the platform - compressed_name = archive_name + compress_ext[compress] - if sys.platform == 'win32': - cmd = [compress, archive_name, compressed_name] - else: - cmd = [compress, '-f', archive_name] - from distutils2.spawn import spawn - spawn(cmd, dry_run=dry_run) - return compressed_name - - return archive_name - -def _call_external_zip(directory, verbose=False): - # XXX see if we want to keep an external call here - if verbose: - zipoptions = "-r" - else: - zipoptions = "-rq" - from distutils2.errors import DistutilsExecError - from distutils2.spawn import spawn - try: - spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) - except DistutilsExecError: - # XXX really should distinguish between "couldn't find - # external 'zip' command" and "zip failed". - raise ExecError, \ - ("unable to create zip file '%s': " - "could neither import the 'zipfile' module nor " - "find a standalone zip utility") % zip_filename - -def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): - """Create a zip file from all the files under 'base_dir'. - - The output zip file will be named 'base_dir' + ".zip". Uses either the - "zipfile" Python module (if available) or the InfoZIP "zip" utility - (if installed and found on the default search path). If neither tool is - available, raises ExecError. Returns the name of the output zip - file. - """ - zip_filename = base_name + ".zip" - archive_dir = os.path.dirname(base_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # If zipfile module is not available, try spawning an external 'zip' - # command. - try: - import zipfile - except ImportError: - zipfile = None - - if zipfile is None: - _call_external_zip(base_dir, verbose) - else: - if logger is not None: - logger.info("creating '%s' and adding '%s' to it", - zip_filename, base_dir) - - if not dry_run: - zip = zipfile.ZipFile(zip_filename, "w", - compression=zipfile.ZIP_DEFLATED) - - for dirpath, dirnames, filenames in os.walk(base_dir): - for name in filenames: - path = os.path.normpath(os.path.join(dirpath, name)) - if os.path.isfile(path): - zip.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) - zip.close() - - return zip_filename - -_ARCHIVE_FORMATS = { - 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), - 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), - 'ztar': (_make_tarball, [('compress', 'compress')], - "compressed tar file"), - 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (_make_zipfile, [],"ZIP file") - } - -def get_archive_formats(): - """Returns a list of supported formats for archiving and unarchiving. - - Each element of the returned sequence is a tuple (name, description) - """ - formats = [(name, registry[2]) for name, registry in - _ARCHIVE_FORMATS.items()] - formats.sort() - return formats - -def register_archive_format(name, function, extra_args=None, description=''): - """Registers an archive format. - - name is the name of the format. function is the callable that will be - used to create archives. If provided, extra_args is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_archive_formats() function. - """ - if extra_args is None: - extra_args = [] - if not callable(function): - raise TypeError('The %s object is not callable' % function) - if not isinstance(extra_args, (tuple, list)): - raise TypeError('extra_args needs to be a sequence') - for element in extra_args: - if not isinstance(element, (tuple, list)) or len(element) !=2 : - raise TypeError('extra_args elements are : (arg_name, value)') - - _ARCHIVE_FORMATS[name] = (function, extra_args, description) - -def unregister_archive_format(name): - del _ARCHIVE_FORMATS[name] - -def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, - dry_run=0, owner=None, group=None, logger=None): - """Create an archive file (eg. zip or tar). - - 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "ztar", - or "gztar". - - 'root_dir' is a directory that will be the root directory of the - archive; ie. we typically chdir into 'root_dir' before creating the - archive. 'base_dir' is the directory where we start archiving from; - ie. 'base_dir' will be the common prefix of all files and - directories in the archive. 'root_dir' and 'base_dir' both default - to the current directory. Returns the name of the archive file. - - 'owner' and 'group' are used when creating a tar archive. By default, - uses the current owner and group. - """ - save_cwd = os.getcwd() - if root_dir is not None: - if logger is not None: - logger.debug("changing into '%s'", root_dir) - base_name = os.path.abspath(base_name) - if not dry_run: - os.chdir(root_dir) - - if base_dir is None: - base_dir = os.curdir - - kwargs = {'dry_run': dry_run, 'logger': logger} - - try: - format_info = _ARCHIVE_FORMATS[format] - except KeyError: - raise ValueError, "unknown archive format '%s'" % format - - func = format_info[0] - for arg, val in format_info[1]: - kwargs[arg] = val - - if format != 'zip': - kwargs['owner'] = owner - kwargs['group'] = group - - try: - filename = func(base_name, base_dir, **kwargs) - finally: - if root_dir is not None: - if logger is not None: - logger.debug("changing back to '%s'", save_cwd) - os.chdir(save_cwd) - - return filename diff --git a/src/distutils2/_backport/sysconfig.cfg b/src/distutils2/_backport/sysconfig.cfg deleted file mode 100644 index a5d3c94..0000000 --- a/src/distutils2/_backport/sysconfig.cfg +++ /dev/null @@ -1,111 +0,0 @@ -[globals] -# These are the useful categories that are sometimes referenced at runtime, -# using pkgutil.open(): -# Configuration files -config = {confdir}/{distribution.name} -# Non-writable data that is independent of architecture (images, many xml/text files) -appdata = {datadir}/{distribution.name} -# Non-writable data that is architecture-dependent (some binary data formats) -appdata.arch = {libdir}/{distribution.name} -# Data, written by the package, that must be preserved (databases) -appdata.persistent = {statedir}/lib/{distribution.name} -# Data, written by the package, that can be safely discarded (cache) -appdata.disposable = {statedir}/cache/{distribution.name} -# Help or documentation files referenced at runtime -help = {datadir}/{distribution.name} -icon = {datadir}/pixmaps -scripts = {base}/bin - -# Non-runtime files. These are valid categories for marking files for -# install, but they should not be referenced by the app at runtime: -# Help or documentation files not referenced by the package at runtime -doc = {datadir}/doc/{distribution.name} -# GNU info documentation files -info = {datadir}/info -# man pages -man = {datadir}/man - -[posix_prefix] -# Configuration directories. Some of these come straight out of the -# configure script. They are for implementing the other variables, not to -# be used directly in [resource_locations]. -confdir = /etc -datadir = /usr/share -libdir = /usr/lib ; or /usr/lib64 on a multilib system -statedir = /var -# User resource directory -local = ~/.local/{distribution.name} - -stdlib = {base}/lib/python{py_version_short} -platstdlib = {platbase}/lib/python{py_version_short} -purelib = {base}/lib/python{py_version_short}/site-packages -platlib = {platbase}/lib/python{py_version_short}/site-packages -include = {base}/include/python{py_version_short} -platinclude = {platbase}/include/python{py_version_short} -data = {base} - -[posix_home] -stdlib = {base}/lib/python -platstdlib = {base}/lib/python -purelib = {base}/lib/python -platlib = {base}/lib/python -include = {base}/include/python -platinclude = {base}/include/python -scripts = {base}/bin -data = {base} - -[nt] -stdlib = {base}/Lib -platstdlib = {base}/Lib -purelib = {base}/Lib/site-packages -platlib = {base}/Lib/site-packages -include = {base}/Include -platinclude = {base}/Include -scripts = {base}/Scripts -data = {base} - -[os2] -stdlib = {base}/Lib -platstdlib = {base}/Lib -purelib = {base}/Lib/site-packages -platlib = {base}/Lib/site-packages -include = {base}/Include -platinclude = {base}/Include -scripts = {base}/Scripts -data = {base} - -[os2_home] -stdlib = {userbase}/lib/python{py_version_short} -platstdlib = {userbase}/lib/python{py_version_short} -purelib = {userbase}/lib/python{py_version_short}/site-packages -platlib = {userbase}/lib/python{py_version_short}/site-packages -include = {userbase}/include/python{py_version_short} -scripts = {userbase}/bin -data = {userbase} - -[nt_user] -stdlib = {userbase}/Python{py_version_nodot} -platstdlib = {userbase}/Python{py_version_nodot} -purelib = {userbase}/Python{py_version_nodot}/site-packages -platlib = {userbase}/Python{py_version_nodot}/site-packages -include = {userbase}/Python{py_version_nodot}/Include -scripts = {userbase}/Scripts -data = {userbase} - -[posix_user] -stdlib = {userbase}/lib/python{py_version_short} -platstdlib = {userbase}/lib/python{py_version_short} -purelib = {userbase}/lib/python{py_version_short}/site-packages -platlib = {userbase}/lib/python{py_version_short}/site-packages -include = {userbase}/include/python{py_version_short} -scripts = {userbase}/bin -data = {userbase} - -[osx_framework_user] -stdlib = {userbase}/lib/python -platstdlib = {userbase}/lib/python -purelib = {userbase}/lib/python/site-packages -platlib = {userbase}/lib/python/site-packages -include = {userbase}/include -scripts = {userbase}/bin -data = {userbase} diff --git a/src/distutils2/_backport/sysconfig.py b/src/distutils2/_backport/sysconfig.py deleted file mode 100644 index a5661df..0000000 --- a/src/distutils2/_backport/sysconfig.py +++ /dev/null @@ -1,718 +0,0 @@ -"""Provide access to Python's configuration information. - -""" -import sys -import os -import re -from os.path import pardir, realpath -from ConfigParser import RawConfigParser - -_PREFIX = os.path.normpath(sys.prefix) -_EXEC_PREFIX = os.path.normpath(sys.exec_prefix) - -# let's read the configuration file -# XXX _CONFIG_DIR will be set by the Makefile later -_CONFIG_DIR = os.path.normpath(os.path.dirname(__file__)) -_CONFIG_FILE = os.path.join(_CONFIG_DIR, 'sysconfig.cfg') -_SCHEMES = RawConfigParser() -_SCHEMES.read(_CONFIG_FILE) -_VAR_REPL = re.compile(r'\{([^{]*?)\}') - -def _expand_globals(config): - if config.has_section('globals'): - globals = config.items('globals') - else: - globals = tuple() - - sections = config.sections() - for section in sections: - if section == 'globals': - continue - for option, value in globals: - if config.has_option(section, option): - continue - config.set(section, option, value) - config.remove_section('globals') - - # now expanding local variables defined in the cfg file - # - for section in config.sections(): - variables = dict(config.items(section)) - def _replacer(matchobj): - name = matchobj.group(1) - if name in variables: - return variables[name] - return matchobj.group(0) - for option, value in config.items(section): - config.set(section, option, _VAR_REPL.sub(_replacer, value)) - -_expand_globals(_SCHEMES) - -_PY_VERSION = sys.version.split()[0] -_PY_VERSION_SHORT = sys.version[:3] -_PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2] -_CONFIG_VARS = None -_USER_BASE = None -if sys.executable: - _PROJECT_BASE = os.path.dirname(realpath(sys.executable)) -else: - # sys.executable can be empty if argv[0] has been changed and Python is - # unable to retrieve the real program name - _PROJECT_BASE = realpath(os.getcwd()) - -if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower(): - _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir)) -# PC/VS7.1 -if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower(): - _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) -# PC/AMD64 -if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower(): - _PROJECT_BASE = realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) - -def is_python_build(): - for fn in ("Setup.dist", "Setup.local"): - if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): - return True - return False - -_PYTHON_BUILD = is_python_build() - -if _PYTHON_BUILD: - for scheme in ('posix_prefix', 'posix_home'): - _SCHEMES.set(scheme, 'include', '{srcdir}/Include') - _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.') - - -def _subst_vars(path, local_vars): - """In the string `path`, replace tokens like {some.thing} with the corresponding value from the map `local_vars`. - - If there is no corresponding value, leave the token unchanged. - - """ - def _replacer(matchobj): - name = matchobj.group(1) - if name in local_vars: - return local_vars[name] - elif name in os.environ: - return os.environ[name] - return matchobj.group(0) - return _VAR_REPL.sub(_replacer, path) - -def _extend_dict(target_dict, other_dict): - target_keys = target_dict.keys() - for key, value in other_dict.items(): - if key in target_keys: - continue - target_dict[key] = value - -def _expand_vars(scheme, vars): - res = {} - if vars is None: - vars = {} - _extend_dict(vars, get_config_vars()) - - for key, value in _SCHEMES.items(scheme): - if os.name in ('posix', 'nt'): - value = os.path.expanduser(value) - res[key] = os.path.normpath(_subst_vars(value, vars)) - return res - -def _get_default_scheme(): - if os.name == 'posix': - # the default scheme for posix is posix_prefix - return 'posix_prefix' - return os.name - -def _getuserbase(): - env_base = os.environ.get("PYTHONUSERBASE", None) - def joinuser(*args): - return os.path.expanduser(os.path.join(*args)) - - # what about 'os2emx', 'riscos' ? - if os.name == "nt": - base = os.environ.get("APPDATA") or "~" - if env_base: - return env_base - else: - return joinuser(base, "Python") - - if sys.platform == "darwin": - framework = get_config_var("PYTHONFRAMEWORK") - if framework: - if env_base: - return env_base - else: - return joinuser("~", "Library", framework, "%d.%d" % - sys.version_info[:2]) - - if env_base: - return env_base - else: - return joinuser("~", ".local") - - -def _parse_makefile(filename, vars=None): - """Parse a Makefile-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - import re - # Regexes needed for parsing Makefile (and similar syntaxes, - # like old-style Setup files). - _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") - _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") - _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") - - if vars is None: - vars = {} - done = {} - notdone = {} - - f = open(filename) - try: - lines = f.readlines() - finally: - f.close() - - for line in lines: - if line.startswith('#') or line.strip() == '': - continue - m = _variable_rx.match(line) - if m: - n, v = m.group(1, 2) - v = v.strip() - # `$$' is a literal `$' in make - tmpv = v.replace('$$', '') - - if "$" in tmpv: - notdone[n] = v - else: - try: - v = int(v) - except ValueError: - # insert literal `$' - done[n] = v.replace('$$', '$') - else: - done[n] = v - - # do variable interpolation here - variables = notdone.keys() - - # Variables with a 'PY_' prefix in the makefile. These need to - # be made available without that prefix through sysconfig. - # Special care is needed to ensure that variable expansion works, even - # if the expansion uses the name without a prefix. - renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') - - while len(variables) > 0: - for name in tuple(variables): - value = notdone[name] - m = _findvar1_rx.search(value) or _findvar2_rx.search(value) - if m is not None: - n = m.group(1) - found = True - if n in done: - item = str(done[n]) - elif n in notdone: - # get it on a subsequent round - found = False - elif n in os.environ: - # do it like make: fall back to environment - item = os.environ[n] - - elif n in renamed_variables: - if name.startswith('PY_') and name[3:] in renamed_variables: - item = "" - - elif 'PY_' + n in notdone: - found = False - - else: - item = str(done['PY_' + n]) - - else: - done[n] = item = "" - - if found: - after = value[m.end():] - value = value[:m.start()] + item + after - if "$" in after: - notdone[name] = value - else: - try: - value = int(value) - except ValueError: - done[name] = value.strip() - else: - done[name] = value - variables.remove(name) - - if name.startswith('PY_') \ - and name[3:] in renamed_variables: - - name = name[3:] - if name not in done: - done[name] = value - - - else: - # bogus variable reference; just drop it since we can't deal - variables.remove(name) - - # save the results in the global dictionary - vars.update(done) - return vars - - -def _get_makefile_filename(): - if _PYTHON_BUILD: - return os.path.join(_PROJECT_BASE, "Makefile") - return os.path.join(get_path('stdlib'), "config", "Makefile") - - -def _init_posix(vars): - """Initialize the module as appropriate for POSIX systems.""" - # load the installed Makefile: - makefile = _get_makefile_filename() - try: - _parse_makefile(makefile, vars) - except IOError, e: - msg = "invalid Python installation: unable to open %s" % makefile - if hasattr(e, "strerror"): - msg = msg + " (%s)" % e.strerror - raise IOError(msg) - - # load the installed pyconfig.h: - config_h = get_config_h_filename() - try: - parse_config_h(open(config_h), vars) - except IOError, e: - msg = "invalid Python installation: unable to open %s" % config_h - if hasattr(e, "strerror"): - msg = msg + " (%s)" % e.strerror - raise IOError(msg) - - # On MacOSX we need to check the setting of the environment variable - # MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so - # it needs to be compatible. - # If it isn't set we set it to the configure-time value - if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in vars: - cfg_target = vars['MACOSX_DEPLOYMENT_TARGET'] - cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '') - if cur_target == '': - cur_target = cfg_target - os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target) - elif map(int, cfg_target.split('.')) > map(int, cur_target.split('.')): - msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" ' - 'during configure' % (cur_target, cfg_target)) - raise IOError(msg) - - # On AIX, there are wrong paths to the linker scripts in the Makefile - # -- these paths are relative to the Python source, but when installed - # the scripts are in another directory. - if _PYTHON_BUILD: - vars['LDSHARED'] = vars['BLDSHARED'] - -def _init_non_posix(vars): - """Initialize the module as appropriate for NT""" - # set basic install directories - vars['LIBDEST'] = get_path('stdlib') - vars['BINLIBDEST'] = get_path('platstdlib') - vars['INCLUDEPY'] = get_path('include') - vars['SO'] = '.pyd' - vars['EXE'] = '.exe' - vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT - vars['BINDIR'] = os.path.dirname(realpath(sys.executable)) - -# -# public APIs -# - - -def parse_config_h(fp, vars=None): - """Parse a config.h-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - import re - if vars is None: - vars = {} - define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") - undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") - - while True: - line = fp.readline() - if not line: - break - m = define_rx.match(line) - if m: - n, v = m.group(1, 2) - try: v = int(v) - except ValueError: pass - vars[n] = v - else: - m = undef_rx.match(line) - if m: - vars[m.group(1)] = 0 - return vars - -def get_config_h_filename(): - """Returns the path of pyconfig.h.""" - if _PYTHON_BUILD: - if os.name == "nt": - inc_dir = os.path.join(_PROJECT_BASE, "PC") - else: - inc_dir = _PROJECT_BASE - else: - inc_dir = get_path('platinclude') - return os.path.join(inc_dir, 'pyconfig.h') - -def get_scheme_names(): - """Returns a tuple containing the schemes names.""" - return tuple(sorted(_SCHEMES.sections())) - -def get_path_names(): - """Returns a tuple containing the paths names.""" - # xxx see if we want a static list - return _SCHEMES.options('posix_prefix') - -def get_paths(scheme=_get_default_scheme(), vars=None, expand=True): - """Returns a mapping containing an install scheme. - - ``scheme`` is the install scheme name. If not provided, it will - return the default scheme for the current platform. - """ - if expand: - return _expand_vars(scheme, vars) - else: - return dict(_SCHEMES.items(scheme)) - -def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True): - """Returns a path corresponding to the scheme. - - ``scheme`` is the install scheme name. - """ - return get_paths(scheme, vars, expand)[name] - -def get_config_vars(*args): - """With no arguments, return a dictionary of all configuration - variables relevant for the current platform. - - On Unix, this means every variable defined in Python's installed Makefile; - On Windows and Mac OS it's a much smaller set. - - With arguments, return a list of values that result from looking up - each argument in the configuration variable dictionary. - """ - import re - global _CONFIG_VARS - if _CONFIG_VARS is None: - _CONFIG_VARS = {} - # Normalized versions of prefix and exec_prefix are handy to have; - # in fact, these are the standard versions used most places in the - # Distutils. - _CONFIG_VARS['prefix'] = _PREFIX - _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX - _CONFIG_VARS['py_version'] = _PY_VERSION - _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT - _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2] - _CONFIG_VARS['base'] = _PREFIX - _CONFIG_VARS['platbase'] = _EXEC_PREFIX - _CONFIG_VARS['projectbase'] = _PROJECT_BASE - - if os.name in ('nt', 'os2'): - _init_non_posix(_CONFIG_VARS) - if os.name == 'posix': - _init_posix(_CONFIG_VARS) - - # Setting 'userbase' is done below the call to the - # init function to enable using 'get_config_var' in - # the init-function. - if sys.version >= '2.6': - _CONFIG_VARS['userbase'] = _getuserbase() - - if 'srcdir' not in _CONFIG_VARS: - _CONFIG_VARS['srcdir'] = _PROJECT_BASE - else: - _CONFIG_VARS['srcdir'] = realpath(_CONFIG_VARS['srcdir']) - - - # Convert srcdir into an absolute path if it appears necessary. - # Normally it is relative to the build directory. However, during - # testing, for example, we might be running a non-installed python - # from a different directory. - if _PYTHON_BUILD and os.name == "posix": - base = _PROJECT_BASE - if (not os.path.isabs(_CONFIG_VARS['srcdir']) and - base != os.getcwd()): - # srcdir is relative and we are not in the same directory - # as the executable. Assume executable is in the build - # directory and make srcdir absolute. - srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) - _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) - - if sys.platform == 'darwin': - kernel_version = os.uname()[2] # Kernel version (8.4.3) - major_version = int(kernel_version.split('.')[0]) - - if major_version < 8: - # On Mac OS X before 10.4, check if -arch and -isysroot - # are in CFLAGS or LDFLAGS and remove them if they are. - # This is needed when building extensions on a 10.3 system - # using a universal build of python. - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - flags = _CONFIG_VARS[key] - flags = re.sub('-arch\s+\w+\s', ' ', flags) - flags = re.sub('-isysroot [^ \t]*', ' ', flags) - _CONFIG_VARS[key] = flags - else: - # Allow the user to override the architecture flags using - # an environment variable. - # NOTE: This name was introduced by Apple in OSX 10.5 and - # is used by several scripting languages distributed with - # that OS release. - if 'ARCHFLAGS' in os.environ: - arch = os.environ['ARCHFLAGS'] - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub('-arch\s+\w+\s', ' ', flags) - flags = flags + ' ' + arch - _CONFIG_VARS[key] = flags - - # If we're on OSX 10.5 or later and the user tries to - # compiles an extension using an SDK that is not present - # on the current machine it is better to not use an SDK - # than to fail. - # - # The major usecase for this is users using a Python.org - # binary installer on OSX 10.6: that installer uses - # the 10.4u SDK, but that SDK is not installed by default - # when you install Xcode. - # - CFLAGS = _CONFIG_VARS.get('CFLAGS', '') - m = re.search('-isysroot\s+(\S+)', CFLAGS) - if m is not None: - sdk = m.group(1) - if not os.path.exists(sdk): - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags) - _CONFIG_VARS[key] = flags - - if args: - vals = [] - for name in args: - vals.append(_CONFIG_VARS.get(name)) - return vals - else: - return _CONFIG_VARS - -def get_config_var(name): - """Return the value of a single variable using the dictionary returned by - 'get_config_vars()'. - - Equivalent to get_config_vars().get(name) - """ - return get_config_vars().get(name) - -def get_platform(): - """Return a string that identifies the current platform. - - This is used mainly to distinguish platform-specific build directories and - platform-specific built distributions. Typically includes the OS name - and version and the architecture (as supplied by 'os.uname()'), - although the exact information included depends on the OS; eg. for IRIX - the architecture isn't particularly important (IRIX only runs on SGI - hardware), but for Linux the kernel version isn't particularly - important. - - Examples of returned values: - linux-i586 - linux-alpha (?) - solaris-2.6-sun4u - irix-5.3 - irix64-6.2 - - Windows will return one of: - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) - win-ia64 (64bit Windows on Itanium) - win32 (all others - specifically, sys.platform is returned) - - For other non-POSIX platforms, currently just returns 'sys.platform'. - """ - import re - if os.name == 'nt': - # sniff sys.version for architecture. - prefix = " bit (" - i = sys.version.find(prefix) - if i == -1: - return sys.platform - j = sys.version.find(")", i) - look = sys.version[i+len(prefix):j].lower() - if look == 'amd64': - return 'win-amd64' - if look == 'itanium': - return 'win-ia64' - return sys.platform - - if os.name != "posix" or not hasattr(os, 'uname'): - # XXX what about the architecture? NT is Intel or Alpha, - # Mac OS is M68k or PPC, etc. - return sys.platform - - # Try to distinguish various flavours of Unix - osname, host, release, version, machine = os.uname() - - # Convert the OS name to lowercase, remove '/' characters - # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh") - osname = osname.lower().replace('/', '') - machine = machine.replace(' ', '_') - machine = machine.replace('/', '-') - - if osname[:5] == "linux": - # At least on Linux/Intel, 'machine' is the processor -- - # i386, etc. - # XXX what about Alpha, SPARC, etc? - return "%s-%s" % (osname, machine) - elif osname[:5] == "sunos": - if release[0] >= "5": # SunOS 5 == Solaris 2 - osname = "solaris" - release = "%d.%s" % (int(release[0]) - 3, release[2:]) - # fall through to standard osname-release-machine representation - elif osname[:4] == "irix": # could be "irix64"! - return "%s-%s" % (osname, release) - elif osname[:3] == "aix": - return "%s-%s.%s" % (osname, version, release) - elif osname[:6] == "cygwin": - osname = "cygwin" - rel_re = re.compile (r'[\d.]+') - m = rel_re.match(release) - if m: - release = m.group() - elif osname[:6] == "darwin": - # - # For our purposes, we'll assume that the system version from - # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set - # to. This makes the compatibility story a bit more sane because the - # machine is going to compile and link as if it were - # MACOSX_DEPLOYMENT_TARGET. - cfgvars = get_config_vars() - macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET') - if not macver: - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') - - if 1: - # Always calculate the release of the running machine, - # needed to determine if we can build fat binaries or not. - - macrelease = macver - # Get the system version. Reading this plist is a documented - # way to get the system version (see the documentation for - # the Gestalt Manager) - try: - f = open('/System/Library/CoreServices/SystemVersion.plist') - except IOError: - # We're on a plain darwin box, fall back to the default - # behaviour. - pass - else: - try: - m = re.search(r'<key>ProductUserVisibleVersion</key>\s*' - r'<string>(.*?)</string>', f.read()) - finally: - f.close() - if m is not None: - macrelease = '.'.join(m.group(1).split('.')[:2]) - # else: fall back to the default behaviour - - if not macver: - macver = macrelease - - if macver: - release = macver - osname = "macosx" - - if (macrelease + '.') >= '10.4.' and \ - '-arch' in get_config_vars().get('CFLAGS', '').strip(): - # The universal build will build fat binaries, but not on - # systems before 10.4 - # - # Try to detect 4-way universal builds, those have machine-type - # 'universal' instead of 'fat'. - - machine = 'fat' - cflags = get_config_vars().get('CFLAGS') - - archs = re.findall('-arch\s+(\S+)', cflags) - archs = tuple(sorted(set(archs))) - - if len(archs) == 1: - machine = archs[0] - elif archs == ('i386', 'ppc'): - machine = 'fat' - elif archs == ('i386', 'x86_64'): - machine = 'intel' - elif archs == ('i386', 'ppc', 'x86_64'): - machine = 'fat3' - elif archs == ('ppc64', 'x86_64'): - machine = 'fat64' - elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): - machine = 'universal' - else: - raise ValueError( - "Don't know machine value for archs=%r"%(archs,)) - - elif machine == 'i386': - # On OSX the machine type returned by uname is always the - # 32-bit variant, even if the executable architecture is - # the 64-bit variant - if sys.maxint >= 2**32: - machine = 'x86_64' - - elif machine in ('PowerPC', 'Power_Macintosh'): - # Pick a sane name for the PPC architecture. - # See 'i386' case - if sys.maxint >= 2**32: - machine = 'ppc64' - else: - machine = 'ppc' - - return "%s-%s-%s" % (osname, release, machine) - - -def get_python_version(): - return _PY_VERSION_SHORT - -def _print_dict(title, data): - for index, (key, value) in enumerate(sorted(data.items())): - if index == 0: - print '%s: ' % (title) - print '\t%s = "%s"' % (key, value) - -def _main(): - """Display all information sysconfig detains.""" - print 'Platform: "%s"' % get_platform() - print 'Python version: "%s"' % get_python_version() - print 'Current installation scheme: "%s"' % _get_default_scheme() - print '' - _print_dict('Paths', get_paths()) - print - _print_dict('Variables', get_config_vars()) - -if __name__ == '__main__': - _main() diff --git a/src/distutils2/_backport/tarfile.py b/src/distutils2/_backport/tarfile.py deleted file mode 100644 index 3c95868..0000000 --- a/src/distutils2/_backport/tarfile.py +++ /dev/null @@ -1,2573 +0,0 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 -*- -#------------------------------------------------------------------- -# tarfile.py -#------------------------------------------------------------------- -# Copyright (C) 2002 Lars Gustäbel <lars@gustaebel.de> -# All rights reserved. -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation -# files (the "Software"), to deal in the Software without -# restriction, including without limitation the rights to use, -# copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following -# conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -"""Read from and write to tar format archives. -""" - -__version__ = "$Revision: 76780 $" -# $Source$ - -version = "0.9.0" -__author__ = "Lars Gustäbel (lars@gustaebel.de)" -__date__ = "$Date: 2009-12-13 12:32:27 +0100 (Dim 13 déc 2009) $" -__cvsid__ = "$Id: tarfile.py 76780 2009-12-13 11:32:27Z lars.gustaebel $" -__credits__ = "Gustavo Niemeyer, Niels Gustäbel, Richard Townsend." - -#--------- -# Imports -#--------- -import sys -import os -import shutil -import stat -import errno -import time -import struct -import copy -import re -import operator - -if not hasattr(os, 'SEEK_SET'): - os.SEEK_SET = 0 - -try: - import grp, pwd -except ImportError: - grp = pwd = None - -# from tarfile import * -__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"] - -#--------------------------------------------------------- -# tar constants -#--------------------------------------------------------- -NUL = "\0" # the null character -BLOCKSIZE = 512 # length of processing blocks -RECORDSIZE = BLOCKSIZE * 20 # length of records -GNU_MAGIC = "ustar \0" # magic gnu tar string -POSIX_MAGIC = "ustar\x0000" # magic posix tar string - -LENGTH_NAME = 100 # maximum length of a filename -LENGTH_LINK = 100 # maximum length of a linkname -LENGTH_PREFIX = 155 # maximum length of the prefix field - -REGTYPE = "0" # regular file -AREGTYPE = "\0" # regular file -LNKTYPE = "1" # link (inside tarfile) -SYMTYPE = "2" # symbolic link -CHRTYPE = "3" # character special device -BLKTYPE = "4" # block special device -DIRTYPE = "5" # directory -FIFOTYPE = "6" # fifo special device -CONTTYPE = "7" # contiguous file - -GNUTYPE_LONGNAME = "L" # GNU tar longname -GNUTYPE_LONGLINK = "K" # GNU tar longlink -GNUTYPE_SPARSE = "S" # GNU tar sparse file - -XHDTYPE = "x" # POSIX.1-2001 extended header -XGLTYPE = "g" # POSIX.1-2001 global header -SOLARIS_XHDTYPE = "X" # Solaris extended header - -USTAR_FORMAT = 0 # POSIX.1-1988 (ustar) format -GNU_FORMAT = 1 # GNU tar format -PAX_FORMAT = 2 # POSIX.1-2001 (pax) format -DEFAULT_FORMAT = GNU_FORMAT - -#--------------------------------------------------------- -# tarfile constants -#--------------------------------------------------------- -# File types that tarfile supports: -SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, - SYMTYPE, DIRTYPE, FIFOTYPE, - CONTTYPE, CHRTYPE, BLKTYPE, - GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, - GNUTYPE_SPARSE) - -# File types that will be treated as a regular file. -REGULAR_TYPES = (REGTYPE, AREGTYPE, - CONTTYPE, GNUTYPE_SPARSE) - -# File types that are part of the GNU tar format. -GNU_TYPES = (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, - GNUTYPE_SPARSE) - -# Fields from a pax header that override a TarInfo attribute. -PAX_FIELDS = ("path", "linkpath", "size", "mtime", - "uid", "gid", "uname", "gname") - -# Fields in a pax header that are numbers, all other fields -# are treated as strings. -PAX_NUMBER_FIELDS = { - "atime": float, - "ctime": float, - "mtime": float, - "uid": int, - "gid": int, - "size": int -} - -#--------------------------------------------------------- -# Bits used in the mode field, values in octal. -#--------------------------------------------------------- -S_IFLNK = 0120000 # symbolic link -S_IFREG = 0100000 # regular file -S_IFBLK = 0060000 # block device -S_IFDIR = 0040000 # directory -S_IFCHR = 0020000 # character device -S_IFIFO = 0010000 # fifo - -TSUID = 04000 # set UID on execution -TSGID = 02000 # set GID on execution -TSVTX = 01000 # reserved - -TUREAD = 0400 # read by owner -TUWRITE = 0200 # write by owner -TUEXEC = 0100 # execute/search by owner -TGREAD = 0040 # read by group -TGWRITE = 0020 # write by group -TGEXEC = 0010 # execute/search by group -TOREAD = 0004 # read by other -TOWRITE = 0002 # write by other -TOEXEC = 0001 # execute/search by other - -#--------------------------------------------------------- -# initialization -#--------------------------------------------------------- -ENCODING = sys.getfilesystemencoding() -if ENCODING is None: - ENCODING = sys.getdefaultencoding() - -#--------------------------------------------------------- -# Some useful functions -#--------------------------------------------------------- - -def stn(s, length): - """Convert a python string to a null-terminated string buffer. - """ - return s[:length] + (length - len(s)) * NUL - -def nts(s): - """Convert a null-terminated string field to a python string. - """ - # Use the string up to the first null char. - p = s.find("\0") - if p == -1: - return s - return s[:p] - -def nti(s): - """Convert a number field to a python number. - """ - # There are two possible encodings for a number field, see - # itn() below. - if s[0] != chr(0200): - try: - n = int(nts(s) or "0", 8) - except ValueError: - raise InvalidHeaderError("invalid header") - else: - n = 0L - for i in xrange(len(s) - 1): - n <<= 8 - n += ord(s[i + 1]) - return n - -def itn(n, digits=8, format=DEFAULT_FORMAT): - """Convert a python number to a number field. - """ - # POSIX 1003.1-1988 requires numbers to be encoded as a string of - # octal digits followed by a null-byte, this allows values up to - # (8**(digits-1))-1. GNU tar allows storing numbers greater than - # that if necessary. A leading 0200 byte indicates this particular - # encoding, the following digits-1 bytes are a big-endian - # representation. This allows values up to (256**(digits-1))-1. - if 0 <= n < 8 ** (digits - 1): - s = "%0*o" % (digits - 1, n) + NUL - else: - if format != GNU_FORMAT or n >= 256 ** (digits - 1): - raise ValueError("overflow in number field") - - if n < 0: - # XXX We mimic GNU tar's behaviour with negative numbers, - # this could raise OverflowError. - n = struct.unpack("L", struct.pack("l", n))[0] - - s = "" - for i in xrange(digits - 1): - s = chr(n & 0377) + s - n >>= 8 - s = chr(0200) + s - return s - -def uts(s, encoding, errors): - """Convert a unicode object to a string. - """ - if errors == "utf-8": - # An extra error handler similar to the -o invalid=UTF-8 option - # in POSIX.1-2001. Replace untranslatable characters with their - # UTF-8 representation. - try: - return s.encode(encoding, "strict") - except UnicodeEncodeError: - x = [] - for c in s: - try: - x.append(c.encode(encoding, "strict")) - except UnicodeEncodeError: - x.append(c.encode("utf8")) - return "".join(x) - else: - return s.encode(encoding, errors) - -def calc_chksums(buf): - """Calculate the checksum for a member's header by summing up all - characters except for the chksum field which is treated as if - it was filled with spaces. According to the GNU tar sources, - some tars (Sun and NeXT) calculate chksum with signed char, - which will be different if there are chars in the buffer with - the high bit set. So we calculate two checksums, unsigned and - signed. - """ - unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512])) - signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512])) - return unsigned_chksum, signed_chksum - -def copyfileobj(src, dst, length=None): - """Copy length bytes from fileobj src to fileobj dst. - If length is None, copy the entire content. - """ - if length == 0: - return - if length is None: - shutil.copyfileobj(src, dst) - return - - BUFSIZE = 16 * 1024 - blocks, remainder = divmod(length, BUFSIZE) - for b in xrange(blocks): - buf = src.read(BUFSIZE) - if len(buf) < BUFSIZE: - raise IOError("end of file reached") - dst.write(buf) - - if remainder != 0: - buf = src.read(remainder) - if len(buf) < remainder: - raise IOError("end of file reached") - dst.write(buf) - return - -filemode_table = ( - ((S_IFLNK, "l"), - (S_IFREG, "-"), - (S_IFBLK, "b"), - (S_IFDIR, "d"), - (S_IFCHR, "c"), - (S_IFIFO, "p")), - - ((TUREAD, "r"),), - ((TUWRITE, "w"),), - ((TUEXEC|TSUID, "s"), - (TSUID, "S"), - (TUEXEC, "x")), - - ((TGREAD, "r"),), - ((TGWRITE, "w"),), - ((TGEXEC|TSGID, "s"), - (TSGID, "S"), - (TGEXEC, "x")), - - ((TOREAD, "r"),), - ((TOWRITE, "w"),), - ((TOEXEC|TSVTX, "t"), - (TSVTX, "T"), - (TOEXEC, "x")) -) - -def filemode(mode): - """Convert a file's mode to a string of the form - -rwxrwxrwx. - Used by TarFile.list() - """ - perm = [] - for table in filemode_table: - for bit, char in table: - if mode & bit == bit: - perm.append(char) - break - else: - perm.append("-") - return "".join(perm) - -class TarError(Exception): - """Base exception.""" - pass -class ExtractError(TarError): - """General exception for extract errors.""" - pass -class ReadError(TarError): - """Exception for unreadble tar archives.""" - pass -class CompressionError(TarError): - """Exception for unavailable compression methods.""" - pass -class StreamError(TarError): - """Exception for unsupported operations on stream-like TarFiles.""" - pass -class HeaderError(TarError): - """Base exception for header errors.""" - pass -class EmptyHeaderError(HeaderError): - """Exception for empty headers.""" - pass -class TruncatedHeaderError(HeaderError): - """Exception for truncated headers.""" - pass -class EOFHeaderError(HeaderError): - """Exception for end of file headers.""" - pass -class InvalidHeaderError(HeaderError): - """Exception for invalid headers.""" - pass -class SubsequentHeaderError(HeaderError): - """Exception for missing and invalid extended headers.""" - pass - -#--------------------------- -# internal stream interface -#--------------------------- -class _LowLevelFile(object): - """Low-level file object. Supports reading and writing. - It is used instead of a regular file object for streaming - access. - """ - - def __init__(self, name, mode): - mode = { - "r": os.O_RDONLY, - "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC, - }[mode] - if hasattr(os, "O_BINARY"): - mode |= os.O_BINARY - self.fd = os.open(name, mode) - - def close(self): - os.close(self.fd) - - def read(self, size): - return os.read(self.fd, size) - - def write(self, s): - os.write(self.fd, s) - -class _Stream(object): - """Class that serves as an adapter between TarFile and - a stream-like object. The stream-like object only - needs to have a read() or write() method and is accessed - blockwise. Use of gzip or bzip2 compression is possible. - A stream-like object could be for example: sys.stdin, - sys.stdout, a socket, a tape device etc. - - _Stream is intended to be used only internally. - """ - - def __init__(self, name, mode, comptype, fileobj, bufsize): - """Construct a _Stream object. - """ - self._extfileobj = True - if fileobj is None: - fileobj = _LowLevelFile(name, mode) - self._extfileobj = False - - if comptype == '*': - # Enable transparent compression detection for the - # stream interface - fileobj = _StreamProxy(fileobj) - comptype = fileobj.getcomptype() - - self.name = name or "" - self.mode = mode - self.comptype = comptype - self.fileobj = fileobj - self.bufsize = bufsize - self.buf = "" - self.pos = 0L - self.closed = False - - if comptype == "gz": - try: - import zlib - except ImportError: - raise CompressionError("zlib module is not available") - self.zlib = zlib - self.crc = zlib.crc32("") & 0xffffffffL - if mode == "r": - self._init_read_gz() - else: - self._init_write_gz() - - if comptype == "bz2": - try: - import bz2 - except ImportError: - raise CompressionError("bz2 module is not available") - if mode == "r": - self.dbuf = "" - self.cmp = bz2.BZ2Decompressor() - else: - self.cmp = bz2.BZ2Compressor() - - def __del__(self): - if hasattr(self, "closed") and not self.closed: - self.close() - - def _init_write_gz(self): - """Initialize for writing with gzip compression. - """ - self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, - -self.zlib.MAX_WBITS, - self.zlib.DEF_MEM_LEVEL, - 0) - timestamp = struct.pack("<L", long(time.time())) - self.__write("\037\213\010\010%s\002\377" % timestamp) - if self.name.endswith(".gz"): - self.name = self.name[:-3] - self.__write(self.name + NUL) - - def write(self, s): - """Write string s to the stream. - """ - if self.comptype == "gz": - self.crc = self.zlib.crc32(s, self.crc) & 0xffffffffL - self.pos += len(s) - if self.comptype != "tar": - s = self.cmp.compress(s) - self.__write(s) - - def __write(self, s): - """Write string s to the stream if a whole new block - is ready to be written. - """ - self.buf += s - while len(self.buf) > self.bufsize: - self.fileobj.write(self.buf[:self.bufsize]) - self.buf = self.buf[self.bufsize:] - - def close(self): - """Close the _Stream object. No operation should be - done on it afterwards. - """ - if self.closed: - return - - if self.mode == "w" and self.comptype != "tar": - self.buf += self.cmp.flush() - - if self.mode == "w" and self.buf: - self.fileobj.write(self.buf) - self.buf = "" - if self.comptype == "gz": - # The native zlib crc is an unsigned 32-bit integer, but - # the Python wrapper implicitly casts that to a signed C - # long. So, on a 32-bit box self.crc may "look negative", - # while the same crc on a 64-bit box may "look positive". - # To avoid irksome warnings from the `struct` module, force - # it to look positive on all boxes. - self.fileobj.write(struct.pack("<L", self.crc & 0xffffffffL)) - self.fileobj.write(struct.pack("<L", self.pos & 0xffffFFFFL)) - - if not self._extfileobj: - self.fileobj.close() - - self.closed = True - - def _init_read_gz(self): - """Initialize for reading a gzip compressed fileobj. - """ - self.cmp = self.zlib.decompressobj(-self.zlib.MAX_WBITS) - self.dbuf = "" - - # taken from gzip.GzipFile with some alterations - if self.__read(2) != "\037\213": - raise ReadError("not a gzip file") - if self.__read(1) != "\010": - raise CompressionError("unsupported compression method") - - flag = ord(self.__read(1)) - self.__read(6) - - if flag & 4: - xlen = ord(self.__read(1)) + 256 * ord(self.__read(1)) - self.read(xlen) - if flag & 8: - while True: - s = self.__read(1) - if not s or s == NUL: - break - if flag & 16: - while True: - s = self.__read(1) - if not s or s == NUL: - break - if flag & 2: - self.__read(2) - - def tell(self): - """Return the stream's file pointer position. - """ - return self.pos - - def seek(self, pos=0): - """Set the stream's file pointer to pos. Negative seeking - is forbidden. - """ - if pos - self.pos >= 0: - blocks, remainder = divmod(pos - self.pos, self.bufsize) - for i in xrange(blocks): - self.read(self.bufsize) - self.read(remainder) - else: - raise StreamError("seeking backwards is not allowed") - return self.pos - - def read(self, size=None): - """Return the next size number of bytes from the stream. - If size is not defined, return all bytes of the stream - up to EOF. - """ - if size is None: - t = [] - while True: - buf = self._read(self.bufsize) - if not buf: - break - t.append(buf) - buf = "".join(t) - else: - buf = self._read(size) - self.pos += len(buf) - return buf - - def _read(self, size): - """Return size bytes from the stream. - """ - if self.comptype == "tar": - return self.__read(size) - - c = len(self.dbuf) - t = [self.dbuf] - while c < size: - buf = self.__read(self.bufsize) - if not buf: - break - try: - buf = self.cmp.decompress(buf) - except IOError: - raise ReadError("invalid compressed data") - t.append(buf) - c += len(buf) - t = "".join(t) - self.dbuf = t[size:] - return t[:size] - - def __read(self, size): - """Return size bytes from stream. If internal buffer is empty, - read another block from the stream. - """ - c = len(self.buf) - t = [self.buf] - while c < size: - buf = self.fileobj.read(self.bufsize) - if not buf: - break - t.append(buf) - c += len(buf) - t = "".join(t) - self.buf = t[size:] - return t[:size] -# class _Stream - -class _StreamProxy(object): - """Small proxy class that enables transparent compression - detection for the Stream interface (mode 'r|*'). - """ - - def __init__(self, fileobj): - self.fileobj = fileobj - self.buf = self.fileobj.read(BLOCKSIZE) - - def read(self, size): - self.read = self.fileobj.read - return self.buf - - def getcomptype(self): - if self.buf.startswith("\037\213\010"): - return "gz" - if self.buf.startswith("BZh91"): - return "bz2" - return "tar" - - def close(self): - self.fileobj.close() -# class StreamProxy - -class _BZ2Proxy(object): - """Small proxy class that enables external file object - support for "r:bz2" and "w:bz2" modes. This is actually - a workaround for a limitation in bz2 module's BZ2File - class which (unlike gzip.GzipFile) has no support for - a file object argument. - """ - - blocksize = 16 * 1024 - - def __init__(self, fileobj, mode): - self.fileobj = fileobj - self.mode = mode - self.name = getattr(self.fileobj, "name", None) - self.init() - - def init(self): - import bz2 - self.pos = 0 - if self.mode == "r": - self.bz2obj = bz2.BZ2Decompressor() - self.fileobj.seek(0) - self.buf = "" - else: - self.bz2obj = bz2.BZ2Compressor() - - def read(self, size): - b = [self.buf] - x = len(self.buf) - while x < size: - raw = self.fileobj.read(self.blocksize) - if not raw: - break - data = self.bz2obj.decompress(raw) - b.append(data) - x += len(data) - self.buf = "".join(b) - - buf = self.buf[:size] - self.buf = self.buf[size:] - self.pos += len(buf) - return buf - - def seek(self, pos): - if pos < self.pos: - self.init() - self.read(pos - self.pos) - - def tell(self): - return self.pos - - def write(self, data): - self.pos += len(data) - raw = self.bz2obj.compress(data) - self.fileobj.write(raw) - - def close(self): - if self.mode == "w": - raw = self.bz2obj.flush() - self.fileobj.write(raw) -# class _BZ2Proxy - -#------------------------ -# Extraction file object -#------------------------ -class _FileInFile(object): - """A thin wrapper around an existing file object that - provides a part of its data as an individual file - object. - """ - - def __init__(self, fileobj, offset, size, sparse=None): - self.fileobj = fileobj - self.offset = offset - self.size = size - self.sparse = sparse - self.position = 0 - - def tell(self): - """Return the current file position. - """ - return self.position - - def seek(self, position): - """Seek to a position in the file. - """ - self.position = position - - def read(self, size=None): - """Read data from the file. - """ - if size is None: - size = self.size - self.position - else: - size = min(size, self.size - self.position) - - if self.sparse is None: - return self.readnormal(size) - else: - return self.readsparse(size) - - def readnormal(self, size): - """Read operation for regular files. - """ - self.fileobj.seek(self.offset + self.position) - self.position += size - return self.fileobj.read(size) - - def readsparse(self, size): - """Read operation for sparse files. - """ - data = [] - while size > 0: - buf = self.readsparsesection(size) - if not buf: - break - size -= len(buf) - data.append(buf) - return "".join(data) - - def readsparsesection(self, size): - """Read a single section of a sparse file. - """ - section = self.sparse.find(self.position) - - if section is None: - return "" - - size = min(size, section.offset + section.size - self.position) - - if isinstance(section, _data): - realpos = section.realpos + self.position - section.offset - self.fileobj.seek(self.offset + realpos) - self.position += size - return self.fileobj.read(size) - else: - self.position += size - return NUL * size -#class _FileInFile - - -class ExFileObject(object): - """File-like object for reading an archive member. - Is returned by TarFile.extractfile(). - """ - blocksize = 1024 - - def __init__(self, tarfile, tarinfo): - self.fileobj = _FileInFile(tarfile.fileobj, - tarinfo.offset_data, - tarinfo.size, - getattr(tarinfo, "sparse", None)) - self.name = tarinfo.name - self.mode = "r" - self.closed = False - self.size = tarinfo.size - - self.position = 0 - self.buffer = "" - - def read(self, size=None): - """Read at most size bytes from the file. If size is not - present or None, read all data until EOF is reached. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - buf = "" - if self.buffer: - if size is None: - buf = self.buffer - self.buffer = "" - else: - buf = self.buffer[:size] - self.buffer = self.buffer[size:] - - if size is None: - buf += self.fileobj.read() - else: - buf += self.fileobj.read(size - len(buf)) - - self.position += len(buf) - return buf - - def readline(self, size=-1): - """Read one entire line from the file. If size is present - and non-negative, return a string with at most that - size, which may be an incomplete line. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - if "\n" in self.buffer: - pos = self.buffer.find("\n") + 1 - else: - buffers = [self.buffer] - while True: - buf = self.fileobj.read(self.blocksize) - buffers.append(buf) - if not buf or "\n" in buf: - self.buffer = "".join(buffers) - pos = self.buffer.find("\n") + 1 - if pos == 0: - # no newline found. - pos = len(self.buffer) - break - - if size != -1: - pos = min(size, pos) - - buf = self.buffer[:pos] - self.buffer = self.buffer[pos:] - self.position += len(buf) - return buf - - def readlines(self): - """Return a list with all remaining lines. - """ - result = [] - while True: - line = self.readline() - if not line: break - result.append(line) - return result - - def tell(self): - """Return the current file position. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - return self.position - - def seek(self, pos, whence=os.SEEK_SET): - """Seek to a position in the file. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - if whence == os.SEEK_SET: - self.position = min(max(pos, 0), self.size) - elif whence == os.SEEK_CUR: - if pos < 0: - self.position = max(self.position + pos, 0) - else: - self.position = min(self.position + pos, self.size) - elif whence == os.SEEK_END: - self.position = max(min(self.size + pos, self.size), 0) - else: - raise ValueError("Invalid argument") - - self.buffer = "" - self.fileobj.seek(self.position) - - def close(self): - """Close the file object. - """ - self.closed = True - - def __iter__(self): - """Get an iterator over the file's lines. - """ - while True: - line = self.readline() - if not line: - break - yield line -#class ExFileObject - -#------------------ -# Exported Classes -#------------------ -class TarInfo(object): - """Informational class which holds the details about an - archive member given by a tar header block. - TarInfo objects are returned by TarFile.getmember(), - TarFile.getmembers() and TarFile.gettarinfo() and are - usually created internally. - """ - - def __init__(self, name=""): - """Construct a TarInfo object. name is the optional name - of the member. - """ - self.name = name # member name - self.mode = 0644 # file permissions - self.uid = 0 # user id - self.gid = 0 # group id - self.size = 0 # file size - self.mtime = 0 # modification time - self.chksum = 0 # header checksum - self.type = REGTYPE # member type - self.linkname = "" # link name - self.uname = "root" # user name - self.gname = "root" # group name - self.devmajor = 0 # device major number - self.devminor = 0 # device minor number - - self.offset = 0 # the tar header starts here - self.offset_data = 0 # the file's data starts here - - self.pax_headers = {} # pax header information - - # In pax headers the "name" and "linkname" field are called - # "path" and "linkpath". - def _getpath(self): - return self.name - def _setpath(self, name): - self.name = name - path = property(_getpath, _setpath) - - def _getlinkpath(self): - return self.linkname - def _setlinkpath(self, linkname): - self.linkname = linkname - linkpath = property(_getlinkpath, _setlinkpath) - - def __repr__(self): - return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) - - def get_info(self, encoding, errors): - """Return the TarInfo's attributes as a dictionary. - """ - info = { - "name": self.name, - "mode": self.mode & 07777, - "uid": self.uid, - "gid": self.gid, - "size": self.size, - "mtime": self.mtime, - "chksum": self.chksum, - "type": self.type, - "linkname": self.linkname, - "uname": self.uname, - "gname": self.gname, - "devmajor": self.devmajor, - "devminor": self.devminor - } - - if info["type"] == DIRTYPE and not info["name"].endswith("/"): - info["name"] += "/" - - for key in ("name", "linkname", "uname", "gname"): - if type(info[key]) is unicode: - info[key] = info[key].encode(encoding, errors) - - return info - - def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="strict"): - """Return a tar header as a string of 512 byte blocks. - """ - info = self.get_info(encoding, errors) - - if format == USTAR_FORMAT: - return self.create_ustar_header(info) - elif format == GNU_FORMAT: - return self.create_gnu_header(info) - elif format == PAX_FORMAT: - return self.create_pax_header(info, encoding, errors) - else: - raise ValueError("invalid format") - - def create_ustar_header(self, info): - """Return the object as a ustar header block. - """ - info["magic"] = POSIX_MAGIC - - if len(info["linkname"]) > LENGTH_LINK: - raise ValueError("linkname is too long") - - if len(info["name"]) > LENGTH_NAME: - info["prefix"], info["name"] = self._posix_split_name(info["name"]) - - return self._create_header(info, USTAR_FORMAT) - - def create_gnu_header(self, info): - """Return the object as a GNU header block sequence. - """ - info["magic"] = GNU_MAGIC - - buf = "" - if len(info["linkname"]) > LENGTH_LINK: - buf += self._create_gnu_long_header(info["linkname"], GNUTYPE_LONGLINK) - - if len(info["name"]) > LENGTH_NAME: - buf += self._create_gnu_long_header(info["name"], GNUTYPE_LONGNAME) - - return buf + self._create_header(info, GNU_FORMAT) - - def create_pax_header(self, info, encoding, errors): - """Return the object as a ustar header block. If it cannot be - represented this way, prepend a pax extended header sequence - with supplement information. - """ - info["magic"] = POSIX_MAGIC - pax_headers = self.pax_headers.copy() - - # Test string fields for values that exceed the field length or cannot - # be represented in ASCII encoding. - for name, hname, length in ( - ("name", "path", LENGTH_NAME), ("linkname", "linkpath", LENGTH_LINK), - ("uname", "uname", 32), ("gname", "gname", 32)): - - if hname in pax_headers: - # The pax header has priority. - continue - - val = info[name].decode(encoding, errors) - - # Try to encode the string as ASCII. - try: - val.encode("ascii") - except UnicodeEncodeError: - pax_headers[hname] = val - continue - - if len(info[name]) > length: - pax_headers[hname] = val - - # Test number fields for values that exceed the field limit or values - # that like to be stored as float. - for name, digits in (("uid", 8), ("gid", 8), ("size", 12), ("mtime", 12)): - if name in pax_headers: - # The pax header has priority. Avoid overflow. - info[name] = 0 - continue - - val = info[name] - if not 0 <= val < 8 ** (digits - 1) or isinstance(val, float): - pax_headers[name] = unicode(val) - info[name] = 0 - - # Create a pax extended header if necessary. - if pax_headers: - buf = self._create_pax_generic_header(pax_headers) - else: - buf = "" - - return buf + self._create_header(info, USTAR_FORMAT) - - @classmethod - def create_pax_global_header(cls, pax_headers): - """Return the object as a pax global header block sequence. - """ - return cls._create_pax_generic_header(pax_headers, type=XGLTYPE) - - def _posix_split_name(self, name): - """Split a name longer than 100 chars into a prefix - and a name part. - """ - prefix = name[:LENGTH_PREFIX + 1] - while prefix and prefix[-1] != "/": - prefix = prefix[:-1] - - name = name[len(prefix):] - prefix = prefix[:-1] - - if not prefix or len(name) > LENGTH_NAME: - raise ValueError("name is too long") - return prefix, name - - @staticmethod - def _create_header(info, format): - """Return a header block. info is a dictionary with file - information, format must be one of the *_FORMAT constants. - """ - parts = [ - stn(info.get("name", ""), 100), - itn(info.get("mode", 0) & 07777, 8, format), - itn(info.get("uid", 0), 8, format), - itn(info.get("gid", 0), 8, format), - itn(info.get("size", 0), 12, format), - itn(info.get("mtime", 0), 12, format), - " ", # checksum field - info.get("type", REGTYPE), - stn(info.get("linkname", ""), 100), - stn(info.get("magic", POSIX_MAGIC), 8), - stn(info.get("uname", "root"), 32), - stn(info.get("gname", "root"), 32), - itn(info.get("devmajor", 0), 8, format), - itn(info.get("devminor", 0), 8, format), - stn(info.get("prefix", ""), 155) - ] - - buf = struct.pack("%ds" % BLOCKSIZE, "".join(parts)) - chksum = calc_chksums(buf[-BLOCKSIZE:])[0] - buf = buf[:-364] + "%06o\0" % chksum + buf[-357:] - return buf - - @staticmethod - def _create_payload(payload): - """Return the string payload filled with zero bytes - up to the next 512 byte border. - """ - blocks, remainder = divmod(len(payload), BLOCKSIZE) - if remainder > 0: - payload += (BLOCKSIZE - remainder) * NUL - return payload - - @classmethod - def _create_gnu_long_header(cls, name, type): - """Return a GNUTYPE_LONGNAME or GNUTYPE_LONGLINK sequence - for name. - """ - name += NUL - - info = {} - info["name"] = "././@LongLink" - info["type"] = type - info["size"] = len(name) - info["magic"] = GNU_MAGIC - - # create extended header + name blocks. - return cls._create_header(info, USTAR_FORMAT) + \ - cls._create_payload(name) - - @classmethod - def _create_pax_generic_header(cls, pax_headers, type=XHDTYPE): - """Return a POSIX.1-2001 extended or global header sequence - that contains a list of keyword, value pairs. The values - must be unicode objects. - """ - records = [] - for keyword, value in pax_headers.iteritems(): - keyword = keyword.encode("utf8") - value = value.encode("utf8") - l = len(keyword) + len(value) + 3 # ' ' + '=' + '\n' - n = p = 0 - while True: - n = l + len(str(p)) - if n == p: - break - p = n - records.append("%d %s=%s\n" % (p, keyword, value)) - records = "".join(records) - - # We use a hardcoded "././@PaxHeader" name like star does - # instead of the one that POSIX recommends. - info = {} - info["name"] = "././@PaxHeader" - info["type"] = type - info["size"] = len(records) - info["magic"] = POSIX_MAGIC - - # Create pax header + record blocks. - return cls._create_header(info, USTAR_FORMAT) + \ - cls._create_payload(records) - - @classmethod - def frombuf(cls, buf): - """Construct a TarInfo object from a 512 byte string buffer. - """ - if len(buf) == 0: - raise EmptyHeaderError("empty header") - if len(buf) != BLOCKSIZE: - raise TruncatedHeaderError("truncated header") - if buf.count(NUL) == BLOCKSIZE: - raise EOFHeaderError("end of file header") - - chksum = nti(buf[148:156]) - if chksum not in calc_chksums(buf): - raise InvalidHeaderError("bad checksum") - - obj = cls() - obj.buf = buf - obj.name = nts(buf[0:100]) - obj.mode = nti(buf[100:108]) - obj.uid = nti(buf[108:116]) - obj.gid = nti(buf[116:124]) - obj.size = nti(buf[124:136]) - obj.mtime = nti(buf[136:148]) - obj.chksum = chksum - obj.type = buf[156:157] - obj.linkname = nts(buf[157:257]) - obj.uname = nts(buf[265:297]) - obj.gname = nts(buf[297:329]) - obj.devmajor = nti(buf[329:337]) - obj.devminor = nti(buf[337:345]) - prefix = nts(buf[345:500]) - - # Old V7 tar format represents a directory as a regular - # file with a trailing slash. - if obj.type == AREGTYPE and obj.name.endswith("/"): - obj.type = DIRTYPE - - # Remove redundant slashes from directories. - if obj.isdir(): - obj.name = obj.name.rstrip("/") - - # Reconstruct a ustar longname. - if prefix and obj.type not in GNU_TYPES: - obj.name = prefix + "/" + obj.name - return obj - - @classmethod - def fromtarfile(cls, tarfile): - """Return the next TarInfo object from TarFile object - tarfile. - """ - buf = tarfile.fileobj.read(BLOCKSIZE) - obj = cls.frombuf(buf) - obj.offset = tarfile.fileobj.tell() - BLOCKSIZE - return obj._proc_member(tarfile) - - #-------------------------------------------------------------------------- - # The following are methods that are called depending on the type of a - # member. The entry point is _proc_member() which can be overridden in a - # subclass to add custom _proc_*() methods. A _proc_*() method MUST - # implement the following - # operations: - # 1. Set self.offset_data to the position where the data blocks begin, - # if there is data that follows. - # 2. Set tarfile.offset to the position where the next member's header will - # begin. - # 3. Return self or another valid TarInfo object. - def _proc_member(self, tarfile): - """Choose the right processing method depending on - the type and call it. - """ - if self.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK): - return self._proc_gnulong(tarfile) - elif self.type == GNUTYPE_SPARSE: - return self._proc_sparse(tarfile) - elif self.type in (XHDTYPE, XGLTYPE, SOLARIS_XHDTYPE): - return self._proc_pax(tarfile) - else: - return self._proc_builtin(tarfile) - - def _proc_builtin(self, tarfile): - """Process a builtin type or an unknown type which - will be treated as a regular file. - """ - self.offset_data = tarfile.fileobj.tell() - offset = self.offset_data - if self.isreg() or self.type not in SUPPORTED_TYPES: - # Skip the following data blocks. - offset += self._block(self.size) - tarfile.offset = offset - - # Patch the TarInfo object with saved global - # header information. - self._apply_pax_info(tarfile.pax_headers, tarfile.encoding, tarfile.errors) - - return self - - def _proc_gnulong(self, tarfile): - """Process the blocks that hold a GNU longname - or longlink member. - """ - buf = tarfile.fileobj.read(self._block(self.size)) - - # Fetch the next header and process it. - try: - next = self.fromtarfile(tarfile) - except HeaderError: - raise SubsequentHeaderError("missing or bad subsequent header") - - # Patch the TarInfo object from the next header with - # the longname information. - next.offset = self.offset - if self.type == GNUTYPE_LONGNAME: - next.name = nts(buf) - elif self.type == GNUTYPE_LONGLINK: - next.linkname = nts(buf) - - return next - - def _proc_sparse(self, tarfile): - """Process a GNU sparse header plus extra headers. - """ - buf = self.buf - sp = _ringbuffer() - pos = 386 - lastpos = 0L - realpos = 0L - # There are 4 possible sparse structs in the - # first header. - for i in xrange(4): - try: - offset = nti(buf[pos:pos + 12]) - numbytes = nti(buf[pos + 12:pos + 24]) - except ValueError: - break - if offset > lastpos: - sp.append(_hole(lastpos, offset - lastpos)) - sp.append(_data(offset, numbytes, realpos)) - realpos += numbytes - lastpos = offset + numbytes - pos += 24 - - isextended = ord(buf[482]) - origsize = nti(buf[483:495]) - - # If the isextended flag is given, - # there are extra headers to process. - while isextended == 1: - buf = tarfile.fileobj.read(BLOCKSIZE) - pos = 0 - for i in xrange(21): - try: - offset = nti(buf[pos:pos + 12]) - numbytes = nti(buf[pos + 12:pos + 24]) - except ValueError: - break - if offset > lastpos: - sp.append(_hole(lastpos, offset - lastpos)) - sp.append(_data(offset, numbytes, realpos)) - realpos += numbytes - lastpos = offset + numbytes - pos += 24 - isextended = ord(buf[504]) - - if lastpos < origsize: - sp.append(_hole(lastpos, origsize - lastpos)) - - self.sparse = sp - - self.offset_data = tarfile.fileobj.tell() - tarfile.offset = self.offset_data + self._block(self.size) - self.size = origsize - - return self - - def _proc_pax(self, tarfile): - """Process an extended or global header as described in - POSIX.1-2001. - """ - # Read the header information. - buf = tarfile.fileobj.read(self._block(self.size)) - - # A pax header stores supplemental information for either - # the following file (extended) or all following files - # (global). - if self.type == XGLTYPE: - pax_headers = tarfile.pax_headers - else: - pax_headers = tarfile.pax_headers.copy() - - # Parse pax header information. A record looks like that: - # "%d %s=%s\n" % (length, keyword, value). length is the size - # of the complete record including the length field itself and - # the newline. keyword and value are both UTF-8 encoded strings. - regex = re.compile(r"(\d+) ([^=]+)=", re.U) - pos = 0 - while True: - match = regex.match(buf, pos) - if not match: - break - - length, keyword = match.groups() - length = int(length) - value = buf[match.end(2) + 1:match.start(1) + length - 1] - - keyword = keyword.decode("utf8") - value = value.decode("utf8") - - pax_headers[keyword] = value - pos += length - - # Fetch the next header. - try: - next = self.fromtarfile(tarfile) - except HeaderError: - raise SubsequentHeaderError("missing or bad subsequent header") - - if self.type in (XHDTYPE, SOLARIS_XHDTYPE): - # Patch the TarInfo object with the extended header info. - next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors) - next.offset = self.offset - - if "size" in pax_headers: - # If the extended header replaces the size field, - # we need to recalculate the offset where the next - # header starts. - offset = next.offset_data - if next.isreg() or next.type not in SUPPORTED_TYPES: - offset += next._block(next.size) - tarfile.offset = offset - - return next - - def _apply_pax_info(self, pax_headers, encoding, errors): - """Replace fields with supplemental information from a previous - pax extended or global header. - """ - for keyword, value in pax_headers.iteritems(): - if keyword not in PAX_FIELDS: - continue - - if keyword == "path": - value = value.rstrip("/") - - if keyword in PAX_NUMBER_FIELDS: - try: - value = PAX_NUMBER_FIELDS[keyword](value) - except ValueError: - value = 0 - else: - value = uts(value, encoding, errors) - - setattr(self, keyword, value) - - self.pax_headers = pax_headers.copy() - - def _block(self, count): - """Round up a byte count by BLOCKSIZE and return it, - e.g. _block(834) => 1024. - """ - blocks, remainder = divmod(count, BLOCKSIZE) - if remainder: - blocks += 1 - return blocks * BLOCKSIZE - - def isreg(self): - return self.type in REGULAR_TYPES - def isfile(self): - return self.isreg() - def isdir(self): - return self.type == DIRTYPE - def issym(self): - return self.type == SYMTYPE - def islnk(self): - return self.type == LNKTYPE - def ischr(self): - return self.type == CHRTYPE - def isblk(self): - return self.type == BLKTYPE - def isfifo(self): - return self.type == FIFOTYPE - def issparse(self): - return self.type == GNUTYPE_SPARSE - def isdev(self): - return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE) -# class TarInfo - -class TarFile(object): - """The TarFile Class provides an interface to tar archives. - """ - - debug = 0 # May be set from 0 (no msgs) to 3 (all msgs) - - dereference = False # If true, add content of linked file to the - # tar file, else the link. - - ignore_zeros = False # If true, skips empty or invalid blocks and - # continues processing. - - errorlevel = 1 # If 0, fatal errors only appear in debug - # messages (if debug >= 0). If > 0, errors - # are passed to the caller as exceptions. - - format = DEFAULT_FORMAT # The format to use when creating an archive. - - encoding = ENCODING # Encoding for 8-bit character strings. - - errors = None # Error handler for unicode conversion. - - tarinfo = TarInfo # The default TarInfo class to use. - - fileobject = ExFileObject # The default ExFileObject class to use. - - def __init__(self, name=None, mode="r", fileobj=None, format=None, - tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, - errors=None, pax_headers=None, debug=None, errorlevel=None): - """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to - read from an existing archive, 'a' to append data to an existing - file or 'w' to create a new file overwriting an existing one. `mode' - defaults to 'r'. - If `fileobj' is given, it is used for reading or writing data. If it - can be determined, `mode' is overridden by `fileobj's mode. - `fileobj' is not closed, when TarFile is closed. - """ - if len(mode) > 1 or mode not in "raw": - raise ValueError("mode must be 'r', 'a' or 'w'") - self.mode = mode - self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] - - if not fileobj: - if self.mode == "a" and not os.path.exists(name): - # Create nonexistent files in append mode. - self.mode = "w" - self._mode = "wb" - fileobj = bltn_open(name, self._mode) - self._extfileobj = False - else: - if name is None and hasattr(fileobj, "name"): - name = fileobj.name - if hasattr(fileobj, "mode"): - self._mode = fileobj.mode - self._extfileobj = True - if name: - self.name = os.path.abspath(name) - else: - self.name = None - self.fileobj = fileobj - - # Init attributes. - if format is not None: - self.format = format - if tarinfo is not None: - self.tarinfo = tarinfo - if dereference is not None: - self.dereference = dereference - if ignore_zeros is not None: - self.ignore_zeros = ignore_zeros - if encoding is not None: - self.encoding = encoding - - if errors is not None: - self.errors = errors - elif mode == "r": - self.errors = "utf-8" - else: - self.errors = "strict" - - if pax_headers is not None and self.format == PAX_FORMAT: - self.pax_headers = pax_headers - else: - self.pax_headers = {} - - if debug is not None: - self.debug = debug - if errorlevel is not None: - self.errorlevel = errorlevel - - # Init datastructures. - self.closed = False - self.members = [] # list of members as TarInfo objects - self._loaded = False # flag if all members have been read - self.offset = self.fileobj.tell() - # current position in the archive file - self.inodes = {} # dictionary caching the inodes of - # archive members already added - - try: - if self.mode == "r": - self.firstmember = None - self.firstmember = self.next() - - if self.mode == "a": - # Move to the end of the archive, - # before the first empty block. - while True: - self.fileobj.seek(self.offset) - try: - tarinfo = self.tarinfo.fromtarfile(self) - self.members.append(tarinfo) - except EOFHeaderError: - self.fileobj.seek(self.offset) - break - except HeaderError, e: - raise ReadError(str(e)) - - if self.mode in "aw": - self._loaded = True - - if self.pax_headers: - buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) - self.fileobj.write(buf) - self.offset += len(buf) - except: - if not self._extfileobj: - self.fileobj.close() - self.closed = True - raise - - def _getposix(self): - return self.format == USTAR_FORMAT - def _setposix(self, value): - import warnings - warnings.warn("use the format attribute instead", DeprecationWarning, - 2) - if value: - self.format = USTAR_FORMAT - else: - self.format = GNU_FORMAT - posix = property(_getposix, _setposix) - - #-------------------------------------------------------------------------- - # Below are the classmethods which act as alternate constructors to the - # TarFile class. The open() method is the only one that is needed for - # public use; it is the "super"-constructor and is able to select an - # adequate "sub"-constructor for a particular compression using the mapping - # from OPEN_METH. - # - # This concept allows one to subclass TarFile without losing the comfort of - # the super-constructor. A sub-constructor is registered and made available - # by adding it to the mapping in OPEN_METH. - - @classmethod - def open(cls, name=None, mode="r", fileobj=None, bufsize=RECORDSIZE, **kwargs): - """Open a tar archive for reading, writing or appending. Return - an appropriate TarFile class. - - mode: - 'r' or 'r:*' open for reading with transparent compression - 'r:' open for reading exclusively uncompressed - 'r:gz' open for reading with gzip compression - 'r:bz2' open for reading with bzip2 compression - 'a' or 'a:' open for appending, creating the file if necessary - 'w' or 'w:' open for writing without compression - 'w:gz' open for writing with gzip compression - 'w:bz2' open for writing with bzip2 compression - - 'r|*' open a stream of tar blocks with transparent compression - 'r|' open an uncompressed stream of tar blocks for reading - 'r|gz' open a gzip compressed stream of tar blocks - 'r|bz2' open a bzip2 compressed stream of tar blocks - 'w|' open an uncompressed stream for writing - 'w|gz' open a gzip compressed stream for writing - 'w|bz2' open a bzip2 compressed stream for writing - """ - - if not name and not fileobj: - raise ValueError("nothing to open") - - if mode in ("r", "r:*"): - # Find out which *open() is appropriate for opening the file. - for comptype in cls.OPEN_METH: - func = getattr(cls, cls.OPEN_METH[comptype]) - if fileobj is not None: - saved_pos = fileobj.tell() - try: - return func(name, "r", fileobj, **kwargs) - except (ReadError, CompressionError), e: - if fileobj is not None: - fileobj.seek(saved_pos) - continue - raise ReadError("file could not be opened successfully") - - elif ":" in mode: - filemode, comptype = mode.split(":", 1) - filemode = filemode or "r" - comptype = comptype or "tar" - - # Select the *open() function according to - # given compression. - if comptype in cls.OPEN_METH: - func = getattr(cls, cls.OPEN_METH[comptype]) - else: - raise CompressionError("unknown compression type %r" % comptype) - return func(name, filemode, fileobj, **kwargs) - - elif "|" in mode: - filemode, comptype = mode.split("|", 1) - filemode = filemode or "r" - comptype = comptype or "tar" - - if filemode not in "rw": - raise ValueError("mode must be 'r' or 'w'") - - t = cls(name, filemode, - _Stream(name, filemode, comptype, fileobj, bufsize), - **kwargs) - t._extfileobj = False - return t - - elif mode in "aw": - return cls.taropen(name, mode, fileobj, **kwargs) - - raise ValueError("undiscernible mode") - - @classmethod - def taropen(cls, name, mode="r", fileobj=None, **kwargs): - """Open uncompressed tar archive name for reading or writing. - """ - if len(mode) > 1 or mode not in "raw": - raise ValueError("mode must be 'r', 'a' or 'w'") - return cls(name, mode, fileobj, **kwargs) - - @classmethod - def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): - """Open gzip compressed tar archive name for reading or writing. - Appending is not allowed. - """ - if len(mode) > 1 or mode not in "rw": - raise ValueError("mode must be 'r' or 'w'") - - try: - import gzip - gzip.GzipFile - except (ImportError, AttributeError): - raise CompressionError("gzip module is not available") - - if fileobj is None: - fileobj = bltn_open(name, mode + "b") - - try: - t = cls.taropen(name, mode, - gzip.GzipFile(name, mode, compresslevel, fileobj), - **kwargs) - except IOError: - raise ReadError("not a gzip file") - t._extfileobj = False - return t - - @classmethod - def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): - """Open bzip2 compressed tar archive name for reading or writing. - Appending is not allowed. - """ - if len(mode) > 1 or mode not in "rw": - raise ValueError("mode must be 'r' or 'w'.") - - try: - import bz2 - except ImportError: - raise CompressionError("bz2 module is not available") - - if fileobj is not None: - fileobj = _BZ2Proxy(fileobj, mode) - else: - fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel) - - try: - t = cls.taropen(name, mode, fileobj, **kwargs) - except (IOError, EOFError): - raise ReadError("not a bzip2 file") - t._extfileobj = False - return t - - # All *open() methods are registered here. - OPEN_METH = { - "tar": "taropen", # uncompressed tar - "gz": "gzopen", # gzip compressed tar - "bz2": "bz2open" # bzip2 compressed tar - } - - #-------------------------------------------------------------------------- - # The public methods which TarFile provides: - - def close(self): - """Close the TarFile. In write-mode, two finishing zero blocks are - appended to the archive. - """ - if self.closed: - return - - if self.mode in "aw": - self.fileobj.write(NUL * (BLOCKSIZE * 2)) - self.offset += (BLOCKSIZE * 2) - # fill up the end with zero-blocks - # (like option -b20 for tar does) - blocks, remainder = divmod(self.offset, RECORDSIZE) - if remainder > 0: - self.fileobj.write(NUL * (RECORDSIZE - remainder)) - - if not self._extfileobj: - self.fileobj.close() - self.closed = True - - def getmember(self, name): - """Return a TarInfo object for member `name'. If `name' can not be - found in the archive, KeyError is raised. If a member occurs more - than once in the archive, its last occurrence is assumed to be the - most up-to-date version. - """ - tarinfo = self._getmember(name) - if tarinfo is None: - raise KeyError("filename %r not found" % name) - return tarinfo - - def getmembers(self): - """Return the members of the archive as a list of TarInfo objects. The - list has the same order as the members in the archive. - """ - self._check() - if not self._loaded: # if we want to obtain a list of - self._load() # all members, we first have to - # scan the whole archive. - return self.members - - def getnames(self): - """Return the members of the archive as a list of their names. It has - the same order as the list returned by getmembers(). - """ - return [tarinfo.name for tarinfo in self.getmembers()] - - def gettarinfo(self, name=None, arcname=None, fileobj=None): - """Create a TarInfo object for either the file `name' or the file - object `fileobj' (using os.fstat on its file descriptor). You can - modify some of the TarInfo's attributes before you add it using - addfile(). If given, `arcname' specifies an alternative name for the - file in the archive. - """ - self._check("aw") - - # When fileobj is given, replace name by - # fileobj's real name. - if fileobj is not None: - name = fileobj.name - - # Building the name of the member in the archive. - # Backward slashes are converted to forward slashes, - # Absolute paths are turned to relative paths. - if arcname is None: - arcname = name - drv, arcname = os.path.splitdrive(arcname) - arcname = arcname.replace(os.sep, "/") - arcname = arcname.lstrip("/") - - # Now, fill the TarInfo object with - # information specific for the file. - tarinfo = self.tarinfo() - tarinfo.tarfile = self - - # Use os.stat or os.lstat, depending on platform - # and if symlinks shall be resolved. - if fileobj is None: - if hasattr(os, "lstat") and not self.dereference: - statres = os.lstat(name) - else: - statres = os.stat(name) - else: - statres = os.fstat(fileobj.fileno()) - linkname = "" - - stmd = statres.st_mode - if stat.S_ISREG(stmd): - inode = (statres.st_ino, statres.st_dev) - if not self.dereference and statres.st_nlink > 1 and \ - inode in self.inodes and arcname != self.inodes[inode]: - # Is it a hardlink to an already - # archived file? - type = LNKTYPE - linkname = self.inodes[inode] - else: - # The inode is added only if its valid. - # For win32 it is always 0. - type = REGTYPE - if inode[0]: - self.inodes[inode] = arcname - elif stat.S_ISDIR(stmd): - type = DIRTYPE - elif stat.S_ISFIFO(stmd): - type = FIFOTYPE - elif stat.S_ISLNK(stmd): - type = SYMTYPE - linkname = os.readlink(name) - elif stat.S_ISCHR(stmd): - type = CHRTYPE - elif stat.S_ISBLK(stmd): - type = BLKTYPE - else: - return None - - # Fill the TarInfo object with all - # information we can get. - tarinfo.name = arcname - tarinfo.mode = stmd - tarinfo.uid = statres.st_uid - tarinfo.gid = statres.st_gid - if stat.S_ISREG(stmd): - tarinfo.size = statres.st_size - else: - tarinfo.size = 0L - tarinfo.mtime = statres.st_mtime - tarinfo.type = type - tarinfo.linkname = linkname - if pwd: - try: - tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0] - except KeyError: - pass - if grp: - try: - tarinfo.gname = grp.getgrgid(tarinfo.gid)[0] - except KeyError: - pass - - if type in (CHRTYPE, BLKTYPE): - if hasattr(os, "major") and hasattr(os, "minor"): - tarinfo.devmajor = os.major(statres.st_rdev) - tarinfo.devminor = os.minor(statres.st_rdev) - return tarinfo - - def list(self, verbose=True): - """Print a table of contents to sys.stdout. If `verbose' is False, only - the names of the members are printed. If it is True, an `ls -l'-like - output is produced. - """ - self._check() - - for tarinfo in self: - if verbose: - print filemode(tarinfo.mode), - print "%s/%s" % (tarinfo.uname or tarinfo.uid, - tarinfo.gname or tarinfo.gid), - if tarinfo.ischr() or tarinfo.isblk(): - print "%10s" % ("%d,%d" \ - % (tarinfo.devmajor, tarinfo.devminor)), - else: - print "%10d" % tarinfo.size, - print "%d-%02d-%02d %02d:%02d:%02d" \ - % time.localtime(tarinfo.mtime)[:6], - - if tarinfo.isdir(): - sep = "/" - else: - sep = "" - print tarinfo.name + (sep), - - if verbose: - if tarinfo.issym(): - print "->", tarinfo.linkname, - if tarinfo.islnk(): - print "link to", tarinfo.linkname, - print - - def add(self, name, arcname=None, recursive=True, exclude=None, filter=None): - """Add the file `name' to the archive. `name' may be any type of file - (directory, fifo, symbolic link, etc.). If given, `arcname' - specifies an alternative name for the file in the archive. - Directories are added recursively by default. This can be avoided by - setting `recursive' to False. `exclude' is a function that should - return True for each filename to be excluded. `filter' is a function - that expects a TarInfo object argument and returns the changed - TarInfo object, if it returns None the TarInfo object will be - excluded from the archive. - """ - self._check("aw") - - if arcname is None: - arcname = name - - # Exclude pathnames. - if exclude is not None: - import warnings - warnings.warn("use the filter argument instead", - DeprecationWarning, 2) - if exclude(name): - self._dbg(2, "tarfile: Excluded %r" % name) - return - - # Skip if somebody tries to archive the archive... - if self.name is not None and os.path.abspath(name) == self.name: - self._dbg(2, "tarfile: Skipped %r" % name) - return - - self._dbg(1, name) - - # Create a TarInfo object from the file. - tarinfo = self.gettarinfo(name, arcname) - - if tarinfo is None: - self._dbg(1, "tarfile: Unsupported type %r" % name) - return - - # Change or exclude the TarInfo object. - if filter is not None: - tarinfo = filter(tarinfo) - if tarinfo is None: - self._dbg(2, "tarfile: Excluded %r" % name) - return - - # Append the tar header and data to the archive. - if tarinfo.isreg(): - f = bltn_open(name, "rb") - try: - self.addfile(tarinfo, f) - finally: - f.close() - - elif tarinfo.isdir(): - self.addfile(tarinfo) - if recursive: - for f in os.listdir(name): - self.add(os.path.join(name, f), os.path.join(arcname, f), - recursive, exclude, filter) - - else: - self.addfile(tarinfo) - - def addfile(self, tarinfo, fileobj=None): - """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is - given, tarinfo.size bytes are read from it and added to the archive. - You can create TarInfo objects using gettarinfo(). - On Windows platforms, `fileobj' should always be opened with mode - 'rb' to avoid irritation about the file size. - """ - self._check("aw") - - tarinfo = copy.copy(tarinfo) - - buf = tarinfo.tobuf(self.format, self.encoding, self.errors) - self.fileobj.write(buf) - self.offset += len(buf) - - # If there's data to follow, append it. - if fileobj is not None: - copyfileobj(fileobj, self.fileobj, tarinfo.size) - blocks, remainder = divmod(tarinfo.size, BLOCKSIZE) - if remainder > 0: - self.fileobj.write(NUL * (BLOCKSIZE - remainder)) - blocks += 1 - self.offset += blocks * BLOCKSIZE - - self.members.append(tarinfo) - - def extractall(self, path=".", members=None): - """Extract all members from the archive to the current working - directory and set owner, modification time and permissions on - directories afterwards. `path' specifies a different directory - to extract to. `members' is optional and must be a subset of the - list returned by getmembers(). - """ - directories = [] - - if members is None: - members = self - - for tarinfo in members: - if tarinfo.isdir(): - # Extract directories with a safe mode. - directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 0700 - self.extract(tarinfo, path) - - # Reverse sort directories. - directories.sort(key=operator.attrgetter('name')) - directories.reverse() - - # Set correct owner, mtime and filemode on directories. - for tarinfo in directories: - dirpath = os.path.join(path, tarinfo.name) - try: - self.chown(tarinfo, dirpath) - self.utime(tarinfo, dirpath) - self.chmod(tarinfo, dirpath) - except ExtractError, e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - def extract(self, member, path=""): - """Extract a member from the archive to the current working directory, - using its full name. Its file information is extracted as accurately - as possible. `member' may be a filename or a TarInfo object. You can - specify a different directory using `path'. - """ - self._check("r") - - if isinstance(member, basestring): - tarinfo = self.getmember(member) - else: - tarinfo = member - - # Prepare the link target for makelink(). - if tarinfo.islnk(): - tarinfo._link_target = os.path.join(path, tarinfo.linkname) - - try: - self._extract_member(tarinfo, os.path.join(path, tarinfo.name)) - except EnvironmentError, e: - if self.errorlevel > 0: - raise - else: - if e.filename is None: - self._dbg(1, "tarfile: %s" % e.strerror) - else: - self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) - except ExtractError, e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - def extractfile(self, member): - """Extract a member from the archive as a file object. `member' may be - a filename or a TarInfo object. If `member' is a regular file, a - file-like object is returned. If `member' is a link, a file-like - object is constructed from the link's target. If `member' is none of - the above, None is returned. - The file-like object is read-only and provides the following - methods: read(), readline(), readlines(), seek() and tell() - """ - self._check("r") - - if isinstance(member, basestring): - tarinfo = self.getmember(member) - else: - tarinfo = member - - if tarinfo.isreg(): - return self.fileobject(self, tarinfo) - - elif tarinfo.type not in SUPPORTED_TYPES: - # If a member's type is unknown, it is treated as a - # regular file. - return self.fileobject(self, tarinfo) - - elif tarinfo.islnk() or tarinfo.issym(): - if isinstance(self.fileobj, _Stream): - # A small but ugly workaround for the case that someone tries - # to extract a (sym)link as a file-object from a non-seekable - # stream of tar blocks. - raise StreamError("cannot extract (sym)link as file object") - else: - # A (sym)link's file object is its target's file object. - return self.extractfile(self._getmember(tarinfo.linkname, - tarinfo)) - else: - # If there's no data associated with the member (directory, chrdev, - # blkdev, etc.), return None instead of a file object. - return None - - def _extract_member(self, tarinfo, targetpath): - """Extract the TarInfo object tarinfo to a physical - file called targetpath. - """ - # Fetch the TarInfo object for the given name - # and build the destination pathname, replacing - # forward slashes to platform specific separators. - targetpath = targetpath.rstrip("/") - targetpath = targetpath.replace("/", os.sep) - - # Create all upper directories. - upperdirs = os.path.dirname(targetpath) - if upperdirs and not os.path.exists(upperdirs): - # Create directories that are not part of the archive with - # default permissions. - os.makedirs(upperdirs) - - if tarinfo.islnk() or tarinfo.issym(): - self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) - else: - self._dbg(1, tarinfo.name) - - if tarinfo.isreg(): - self.makefile(tarinfo, targetpath) - elif tarinfo.isdir(): - self.makedir(tarinfo, targetpath) - elif tarinfo.isfifo(): - self.makefifo(tarinfo, targetpath) - elif tarinfo.ischr() or tarinfo.isblk(): - self.makedev(tarinfo, targetpath) - elif tarinfo.islnk() or tarinfo.issym(): - self.makelink(tarinfo, targetpath) - elif tarinfo.type not in SUPPORTED_TYPES: - self.makeunknown(tarinfo, targetpath) - else: - self.makefile(tarinfo, targetpath) - - self.chown(tarinfo, targetpath) - if not tarinfo.issym(): - self.chmod(tarinfo, targetpath) - self.utime(tarinfo, targetpath) - - #-------------------------------------------------------------------------- - # Below are the different file methods. They are called via - # _extract_member() when extract() is called. They can be replaced in a - # subclass to implement other functionality. - - def makedir(self, tarinfo, targetpath): - """Make a directory called targetpath. - """ - try: - # Use a safe mode for the directory, the real mode is set - # later in _extract_member(). - os.mkdir(targetpath, 0700) - except EnvironmentError, e: - if e.errno != errno.EEXIST: - raise - - def makefile(self, tarinfo, targetpath): - """Make a file called targetpath. - """ - source = self.extractfile(tarinfo) - target = bltn_open(targetpath, "wb") - try: - copyfileobj(source, target) - finally: - source.close() - target.close() - - def makeunknown(self, tarinfo, targetpath): - """Make a file from a TarInfo object with an unknown type - at targetpath. - """ - self.makefile(tarinfo, targetpath) - self._dbg(1, "tarfile: Unknown file type %r, " \ - "extracted as regular file." % tarinfo.type) - - def makefifo(self, tarinfo, targetpath): - """Make a fifo called targetpath. - """ - if hasattr(os, "mkfifo"): - os.mkfifo(targetpath) - else: - raise ExtractError("fifo not supported by system") - - def makedev(self, tarinfo, targetpath): - """Make a character or block device called targetpath. - """ - if not hasattr(os, "mknod") or not hasattr(os, "makedev"): - raise ExtractError("special devices not supported by system") - - mode = tarinfo.mode - if tarinfo.isblk(): - mode |= stat.S_IFBLK - else: - mode |= stat.S_IFCHR - - os.mknod(targetpath, mode, - os.makedev(tarinfo.devmajor, tarinfo.devminor)) - - def makelink(self, tarinfo, targetpath): - """Make a (symbolic) link called targetpath. If it cannot be created - (platform limitation), we try to make a copy of the referenced file - instead of a link. - """ - try: - if tarinfo.issym(): - os.symlink(tarinfo.linkname, targetpath) - else: - # See extract(). - os.link(tarinfo._link_target, targetpath) - except AttributeError: - if tarinfo.issym(): - linkpath = os.path.dirname(tarinfo.name) + "/" + \ - tarinfo.linkname - else: - linkpath = tarinfo.linkname - - try: - self._extract_member(self.getmember(linkpath), targetpath) - except (EnvironmentError, KeyError), e: - linkpath = linkpath.replace("/", os.sep) - try: - shutil.copy2(linkpath, targetpath) - except EnvironmentError, e: - raise IOError("link could not be created") - - def chown(self, tarinfo, targetpath): - """Set owner of targetpath according to tarinfo. - """ - if pwd and hasattr(os, "geteuid") and os.geteuid() == 0: - # We have to be root to do so. - try: - g = grp.getgrnam(tarinfo.gname)[2] - except KeyError: - try: - g = grp.getgrgid(tarinfo.gid)[2] - except KeyError: - g = os.getgid() - try: - u = pwd.getpwnam(tarinfo.uname)[2] - except KeyError: - try: - u = pwd.getpwuid(tarinfo.uid)[2] - except KeyError: - u = os.getuid() - try: - if tarinfo.issym() and hasattr(os, "lchown"): - os.lchown(targetpath, u, g) - else: - if sys.platform != "os2emx": - os.chown(targetpath, u, g) - except EnvironmentError, e: - raise ExtractError("could not change owner") - - def chmod(self, tarinfo, targetpath): - """Set file permissions of targetpath according to tarinfo. - """ - if hasattr(os, 'chmod'): - try: - os.chmod(targetpath, tarinfo.mode) - except EnvironmentError, e: - raise ExtractError("could not change mode") - - def utime(self, tarinfo, targetpath): - """Set modification time of targetpath according to tarinfo. - """ - if not hasattr(os, 'utime'): - return - try: - os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) - except EnvironmentError, e: - raise ExtractError("could not change modification time") - - #-------------------------------------------------------------------------- - def next(self): - """Return the next member of the archive as a TarInfo object, when - TarFile is opened for reading. Return None if there is no more - available. - """ - self._check("ra") - if self.firstmember is not None: - m = self.firstmember - self.firstmember = None - return m - - # Read the next block. - self.fileobj.seek(self.offset) - tarinfo = None - while True: - try: - tarinfo = self.tarinfo.fromtarfile(self) - except EOFHeaderError, e: - if self.ignore_zeros: - self._dbg(2, "0x%X: %s" % (self.offset, e)) - self.offset += BLOCKSIZE - continue - except InvalidHeaderError, e: - if self.ignore_zeros: - self._dbg(2, "0x%X: %s" % (self.offset, e)) - self.offset += BLOCKSIZE - continue - elif self.offset == 0: - raise ReadError(str(e)) - except EmptyHeaderError: - if self.offset == 0: - raise ReadError("empty file") - except TruncatedHeaderError, e: - if self.offset == 0: - raise ReadError(str(e)) - except SubsequentHeaderError, e: - raise ReadError(str(e)) - break - - if tarinfo is not None: - self.members.append(tarinfo) - else: - self._loaded = True - - return tarinfo - - #-------------------------------------------------------------------------- - # Little helper methods: - - def _getmember(self, name, tarinfo=None): - """Find an archive member by name from bottom to top. - If tarinfo is given, it is used as the starting point. - """ - # Ensure that all members have been loaded. - members = self.getmembers() - - if tarinfo is None: - end = len(members) - else: - end = members.index(tarinfo) - - for i in xrange(end - 1, -1, -1): - if name == members[i].name: - return members[i] - - def _load(self): - """Read through the entire archive file and look for readable - members. - """ - while True: - tarinfo = self.next() - if tarinfo is None: - break - self._loaded = True - - def _check(self, mode=None): - """Check if TarFile is still open, and if the operation's mode - corresponds to TarFile's mode. - """ - if self.closed: - raise IOError("%s is closed" % self.__class__.__name__) - if mode is not None and self.mode not in mode: - raise IOError("bad operation for mode %r" % self.mode) - - def __iter__(self): - """Provide an iterator object. - """ - if self._loaded: - return iter(self.members) - else: - return TarIter(self) - - def _dbg(self, level, msg): - """Write debugging output to sys.stderr. - """ - if level <= self.debug: - print >> sys.stderr, msg -# class TarFile - -class TarIter(object): - """Iterator Class. - - for tarinfo in TarFile(...): - suite... - """ - - def __init__(self, tarfile): - """Construct a TarIter object. - """ - self.tarfile = tarfile - self.index = 0 - def __iter__(self): - """Return iterator object. - """ - return self - def next(self): - """Return the next item using TarFile's next() method. - When all members have been read, set TarFile as _loaded. - """ - # Fix for SF #1100429: Under rare circumstances it can - # happen that getmembers() is called during iteration, - # which will cause TarIter to stop prematurely. - if not self.tarfile._loaded: - tarinfo = self.tarfile.next() - if not tarinfo: - self.tarfile._loaded = True - raise StopIteration - else: - try: - tarinfo = self.tarfile.members[self.index] - except IndexError: - raise StopIteration - self.index += 1 - return tarinfo - -# Helper classes for sparse file support -class _section(object): - """Base class for _data and _hole. - """ - def __init__(self, offset, size): - self.offset = offset - self.size = size - def __contains__(self, offset): - return self.offset <= offset < self.offset + self.size - -class _data(_section): - """Represent a data section in a sparse file. - """ - def __init__(self, offset, size, realpos): - _section.__init__(self, offset, size) - self.realpos = realpos - -class _hole(_section): - """Represent a hole section in a sparse file. - """ - pass - -class _ringbuffer(list): - """Ringbuffer class which increases performance - over a regular list. - """ - def __init__(self): - self.idx = 0 - def find(self, offset): - idx = self.idx - while True: - item = self[idx] - if offset in item: - break - idx += 1 - if idx == len(self): - idx = 0 - if idx == self.idx: - # End of File - return None - self.idx = idx - return item - -#--------------------------------------------- -# zipfile compatible TarFile class -#--------------------------------------------- -TAR_PLAIN = 0 # zipfile.ZIP_STORED -TAR_GZIPPED = 8 # zipfile.ZIP_DEFLATED -class TarFileCompat(object): - """TarFile class compatible with standard module zipfile's - ZipFile class. - """ - def __init__(self, file, mode="r", compression=TAR_PLAIN): - from warnings import warnpy3k - warnpy3k("the TarFileCompat class has been removed in Python 3.0", - stacklevel=2) - if compression == TAR_PLAIN: - self.tarfile = TarFile.taropen(file, mode) - elif compression == TAR_GZIPPED: - self.tarfile = TarFile.gzopen(file, mode) - else: - raise ValueError("unknown compression constant") - if mode[0:1] == "r": - members = self.tarfile.getmembers() - for m in members: - m.filename = m.name - m.file_size = m.size - m.date_time = time.gmtime(m.mtime)[:6] - def namelist(self): - return map(lambda m: m.name, self.infolist()) - def infolist(self): - return filter(lambda m: m.type in REGULAR_TYPES, - self.tarfile.getmembers()) - def printdir(self): - self.tarfile.list() - def testzip(self): - return - def getinfo(self, name): - return self.tarfile.getmember(name) - def read(self, name): - return self.tarfile.extractfile(self.tarfile.getmember(name)).read() - def write(self, filename, arcname=None, compress_type=None): - self.tarfile.add(filename, arcname) - def writestr(self, zinfo, bytes): - try: - from cStringIO import StringIO - except ImportError: - from StringIO import StringIO - import calendar - tinfo = TarInfo(zinfo.filename) - tinfo.size = len(bytes) - tinfo.mtime = calendar.timegm(zinfo.date_time) - self.tarfile.addfile(tinfo, StringIO(bytes)) - def close(self): - self.tarfile.close() -#class TarFileCompat - -#-------------------- -# exported functions -#-------------------- -def is_tarfile(name): - """Return True if name points to a tar archive that we - are able to handle, else return False. - """ - try: - try: - t = open(name) - finally: - t.close() - return True - except TarError: - return False - -bltn_open = open -open = TarFile.open diff --git a/src/distutils2/_backport/tests/__init__.py b/src/distutils2/_backport/tests/__init__.py deleted file mode 100644 index 78c8142..0000000 --- a/src/distutils2/_backport/tests/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -import os -import sys - -from distutils2.tests.support import unittest - - -here = os.path.dirname(__file__) or os.curdir - -def test_suite(): - suite = unittest.TestSuite() - for fn in os.listdir(here): - if fn.startswith("test") and fn.endswith(".py"): - modname = "distutils2._backport.tests." + fn[:-3] - __import__(modname) - module = sys.modules[modname] - suite.addTest(module.test_suite()) - return suite - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/src/distutils2/_backport/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO b/src/distutils2/_backport/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO deleted file mode 100644 index a176dfd..0000000 --- a/src/distutils2/_backport/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO +++ /dev/null @@ -1,6 +0,0 @@ -Metadata-Version: 1.2 -Name: bacon -Version: 0.1 -Provides-Dist: truffles (2.0) -Provides-Dist: bacon (0.1) -Obsoletes-Dist: truffles (>=0.9,<=1.5) diff --git a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/PKG-INFO b/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/PKG-INFO deleted file mode 100644 index a7e118a..0000000 --- a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/PKG-INFO +++ /dev/null @@ -1,18 +0,0 @@ -Metadata-Version: 1.0 -Name: banana -Version: 0.4 -Summary: A yellow fruit -Home-page: http://en.wikipedia.org/wiki/Banana -Author: Josip Djolonga -Author-email: foo@nbar.com -License: BSD -Description: A fruit -Keywords: foo bar -Platform: UNKNOWN -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: Science/Research -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Scientific/Engineering :: GIS diff --git a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/SOURCES.txt b/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/SOURCES.txt deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/SOURCES.txt +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/dependency_links.txt b/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/entry_points.txt b/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/entry_points.txt deleted file mode 100644 index 5d3e5f6..0000000 --- a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ - - # -*- Entry points: -*- -
\ No newline at end of file diff --git a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/not-zip-safe b/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/not-zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/not-zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/requires.txt b/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/requires.txt deleted file mode 100644 index 4354305..0000000 --- a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/requires.txt +++ /dev/null @@ -1,6 +0,0 @@ -# this should be ignored - -strawberry >=0.5 - -[section ignored] -foo ==0.5 diff --git a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/top_level.txt b/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/top_level.txt deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/banana-0.4.egg/EGG-INFO/top_level.txt +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/cheese-2.0.2.egg-info b/src/distutils2/_backport/tests/fake_dists/cheese-2.0.2.egg-info deleted file mode 100644 index 27cbe30..0000000 --- a/src/distutils2/_backport/tests/fake_dists/cheese-2.0.2.egg-info +++ /dev/null @@ -1,5 +0,0 @@ -Metadata-Version: 1.2 -Name: cheese -Version: 2.0.2 -Provides-Dist: truffles (1.0.2) -Obsoletes-Dist: truffles (!=1.2,<=2.0) diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/INSTALLER +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA deleted file mode 100644 index 00c3674..0000000 --- a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/METADATA +++ /dev/null @@ -1,8 +0,0 @@ -Metadata-Version: 1.2 -Name: choxie -Version: 2.0.0.9 -Summary: Chocolate with a kick! -Requires-Dist: towel-stuff (0.1) -Provides-Dist: truffles (1.0) -Obsoletes-Dist: truffles (<=0.8,>=0.5) -Obsoletes-Dist: truffles (<=0.9,>=0.6) diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/RECORD +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9.dist-info/REQUESTED +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py deleted file mode 100644 index 633f866..0000000 --- a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- - diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py deleted file mode 100644 index c4027f3..0000000 --- a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/choxie/chocolate.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- -from towel_stuff import Towel - -class Chocolate(object): - """A piece of chocolate.""" - - def wrap_with_towel(self): - towel = Towel() - towel.wrap(self) - return towel diff --git a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/truffles.py b/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/truffles.py deleted file mode 100644 index 342b8ea..0000000 --- a/src/distutils2/_backport/tests/fake_dists/choxie-2.0.0.9/truffles.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -from choxie.chocolate import Chocolate - -class Truffle(Chocolate): - """A truffle.""" diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/INSTALLER b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/INSTALLER deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/INSTALLER +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/METADATA b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/METADATA deleted file mode 100644 index 0b99f52..0000000 --- a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/METADATA +++ /dev/null @@ -1,5 +0,0 @@ -Metadata-Version: 1.2 -Name: grammar -Version: 1.0a4 -Requires-Dist: truffles (>=1.2) -Author: Sherlock Holmes diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/RECORD b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/RECORD deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/RECORD +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/REQUESTED b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4.dist-info/REQUESTED +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/__init__.py b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/__init__.py deleted file mode 100644 index 633f866..0000000 --- a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- - diff --git a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/utils.py b/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/utils.py deleted file mode 100644 index 66ba796..0000000 --- a/src/distutils2/_backport/tests/fake_dists/grammar-1.0a4/grammar/utils.py +++ /dev/null @@ -1,8 +0,0 @@ -# -*- coding: utf-8 -*- -from random import randint - -def is_valid_grammar(sentence): - if randint(0, 10) < 2: - return False - else: - return True diff --git a/src/distutils2/_backport/tests/fake_dists/strawberry-0.6.egg b/src/distutils2/_backport/tests/fake_dists/strawberry-0.6.egg Binary files differdeleted file mode 100644 index 6d160e8..0000000 --- a/src/distutils2/_backport/tests/fake_dists/strawberry-0.6.egg +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/INSTALLER b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/INSTALLER deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/INSTALLER +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA deleted file mode 100644 index ca46d0a..0000000 --- a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA +++ /dev/null @@ -1,7 +0,0 @@ -Metadata-Version: 1.2 -Name: towel-stuff -Version: 0.1 -Provides-Dist: truffles (1.1.2) -Provides-Dist: towel-stuff (0.1) -Obsoletes-Dist: truffles (!=0.8,<1.0) -Requires-Dist: bacon (<=0.2) diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/RECORD b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/RECORD deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/RECORD +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/REQUESTED b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/REQUESTED deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/REQUESTED +++ /dev/null diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1/towel_stuff/__init__.py b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1/towel_stuff/__init__.py deleted file mode 100644 index 191f895..0000000 --- a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1/towel_stuff/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- - -class Towel(object): - """A towel, that one should never be without.""" - - def __init__(self, color='tie-dye'): - self.color = color - self.wrapped_obj = None - - def wrap(self, obj): - """Wrap an object up in our towel.""" - self.wrapped_obj = obj - - def unwrap(self): - """Unwrap whatever is in our towel and return whatever it is.""" - obj = self.wrapped_obj - self.wrapped_obj = None - return obj diff --git a/src/distutils2/_backport/tests/fake_dists/truffles-5.0.egg-info b/src/distutils2/_backport/tests/fake_dists/truffles-5.0.egg-info deleted file mode 100644 index 45f0cf8..0000000 --- a/src/distutils2/_backport/tests/fake_dists/truffles-5.0.egg-info +++ /dev/null @@ -1,3 +0,0 @@ -Metadata-Version: 1.2 -Name: truffles -Version: 5.0 diff --git a/src/distutils2/_backport/tests/test_pkgutil.py b/src/distutils2/_backport/tests/test_pkgutil.py deleted file mode 100644 index c052b4d..0000000 --- a/src/distutils2/_backport/tests/test_pkgutil.py +++ /dev/null @@ -1,610 +0,0 @@ -# -*- coding: utf-8 -*- -"""Tests for PEP 376 pkgutil functionality""" -import sys -import os -import csv -import imp -import tempfile -import shutil -import zipfile -try: - from hashlib import md5 -except ImportError: - from distutils2._backport.hashlib import md5 - -from test.test_support import run_unittest, TESTFN -from distutils2.tests.support import unittest - -from distutils2._backport import pkgutil - -try: - from os.path import relpath -except ImportError: - try: - from unittest.compatibility import relpath - except ImportError: - from unittest2.compatibility import relpath - -# Adapted from Python 2.7's trunk - -# TODO Add a test for getting a distribution that is provided by another -# distribution. - -# TODO Add a test for absolute pathed RECORD items (e.g. /etc/myapp/config.ini) - - -class TestPkgUtilData(unittest.TestCase): - - def setUp(self): - super(TestPkgUtilData, self).setUp() - self.dirname = tempfile.mkdtemp() - sys.path.insert(0, self.dirname) - - def tearDown(self): - super(TestPkgUtilData, self).tearDown() - del sys.path[0] - shutil.rmtree(self.dirname) - - def test_getdata_filesys(self): - pkg = 'test_getdata_filesys' - - # Include a LF and a CRLF, to test that binary data is read back - RESOURCE_DATA = 'Hello, world!\nSecond line\r\nThird line' - - # Make a package with some resources - package_dir = os.path.join(self.dirname, pkg) - os.mkdir(package_dir) - # Empty init.py - f = open(os.path.join(package_dir, '__init__.py'), "wb") - try: - pass - finally: - f.close() - # Resource files, res.txt, sub/res.txt - f = open(os.path.join(package_dir, 'res.txt'), "wb") - try: - f.write(RESOURCE_DATA) - finally: - f.close() - os.mkdir(os.path.join(package_dir, 'sub')) - f = open(os.path.join(package_dir, 'sub', 'res.txt'), "wb") - try: - f.write(RESOURCE_DATA) - finally: - f.close() - - # Check we can read the resources - res1 = pkgutil.get_data(pkg, 'res.txt') - self.assertEqual(res1, RESOURCE_DATA) - res2 = pkgutil.get_data(pkg, 'sub/res.txt') - self.assertEqual(res2, RESOURCE_DATA) - - del sys.modules[pkg] - - def test_getdata_zipfile(self): - zip = 'test_getdata_zipfile.zip' - pkg = 'test_getdata_zipfile' - - # Include a LF and a CRLF, to test that binary data is read back - RESOURCE_DATA = 'Hello, world!\nSecond line\r\nThird line' - - # Make a package with some resources - zip_file = os.path.join(self.dirname, zip) - z = zipfile.ZipFile(zip_file, 'w') - try: - # Empty init.py - z.writestr(pkg + '/__init__.py', "") - # Resource files, res.txt, sub/res.txt - z.writestr(pkg + '/res.txt', RESOURCE_DATA) - z.writestr(pkg + '/sub/res.txt', RESOURCE_DATA) - finally: - z.close() - - # Check we can read the resources - sys.path.insert(0, zip_file) - res1 = pkgutil.get_data(pkg, 'res.txt') - self.assertEqual(res1, RESOURCE_DATA) - res2 = pkgutil.get_data(pkg, 'sub/res.txt') - self.assertEqual(res2, RESOURCE_DATA) - del sys.path[0] - - del sys.modules[pkg] - - -# Adapted from Python 2.7's trunk - - -class TestPkgUtilPEP302(unittest.TestCase): - - class MyTestLoader(object): - - def load_module(self, fullname): - # Create an empty module - mod = sys.modules.setdefault(fullname, imp.new_module(fullname)) - mod.__file__ = "<%s>" % self.__class__.__name__ - mod.__loader__ = self - # Make it a package - mod.__path__ = [] - # Count how many times the module is reloaded - mod.__dict__['loads'] = mod.__dict__.get('loads', 0) + 1 - return mod - - def get_data(self, path): - return "Hello, world!" - - class MyTestImporter(object): - - def find_module(self, fullname, path=None): - return TestPkgUtilPEP302.MyTestLoader() - - def setUp(self): - super(TestPkgUtilPEP302, self).setUp() - sys.meta_path.insert(0, self.MyTestImporter()) - - def tearDown(self): - del sys.meta_path[0] - super(TestPkgUtilPEP302, self).tearDown() - - def test_getdata_pep302(self): - # Use a dummy importer/loader - self.assertEqual(pkgutil.get_data('foo', 'dummy'), "Hello, world!") - del sys.modules['foo'] - - def test_alreadyloaded(self): - # Ensure that get_data works without reloading - the "loads" module - # variable in the example loader should count how many times a reload - # occurs. - import foo - self.assertEqual(foo.loads, 1) - self.assertEqual(pkgutil.get_data('foo', 'dummy'), "Hello, world!") - self.assertEqual(foo.loads, 1) - del sys.modules['foo'] - - -class TestPkgUtilDistribution(unittest.TestCase): - # Tests the pkgutil.Distribution class - - def setUp(self): - super(TestPkgUtilDistribution, self).setUp() - self.fake_dists_path = os.path.abspath( - os.path.join(os.path.dirname(__file__), 'fake_dists')) - - self.distinfo_dirs = [os.path.join(self.fake_dists_path, dir) - for dir in os.listdir(self.fake_dists_path) - if dir.endswith('.dist-info')] - - def get_hexdigest(file): - md5_hash = md5() - md5_hash.update(open(file).read()) - return md5_hash.hexdigest() - - def record_pieces(file): - path = relpath(file, sys.prefix) - digest = get_hexdigest(file) - size = os.path.getsize(file) - return [path, digest, size] - - self.records = {} - for distinfo_dir in self.distinfo_dirs: - # Setup the RECORD file for this dist - record_file = os.path.join(distinfo_dir, 'RECORD') - record_writer = csv.writer(open(record_file, 'w'), delimiter=',', - quoting=csv.QUOTE_NONE) - dist_location = distinfo_dir.replace('.dist-info', '') - - for path, dirs, files in os.walk(dist_location): - for f in files: - record_writer.writerow(record_pieces( - os.path.join(path, f))) - for file in ['INSTALLER', 'METADATA', 'REQUESTED']: - record_writer.writerow(record_pieces( - os.path.join(distinfo_dir, file))) - record_writer.writerow([relpath(record_file, sys.prefix)]) - del record_writer # causes the RECORD file to close - record_reader = csv.reader(open(record_file, 'rb')) - record_data = [] - for row in record_reader: - path, md5_, size = row[:] + \ - [None for i in xrange(len(row), 3)] - record_data.append([path, (md5_, size,)]) - self.records[distinfo_dir] = dict(record_data) - - def tearDown(self): - self.records = None - for distinfo_dir in self.distinfo_dirs: - record_file = os.path.join(distinfo_dir, 'RECORD') - open(record_file, 'w').close() - super(TestPkgUtilDistribution, self).tearDown() - - def test_instantiation(self): - # Test the Distribution class's instantiation provides us with usable - # attributes. - # Import the Distribution class - from distutils2._backport.pkgutil import distinfo_dirname, Distribution - - here = os.path.abspath(os.path.dirname(__file__)) - name = 'choxie' - version = '2.0.0.9' - dist_path = os.path.join(here, 'fake_dists', - distinfo_dirname(name, version)) - dist = Distribution(dist_path) - - self.assertEqual(dist.name, name) - from distutils2.metadata import DistributionMetadata - self.assertTrue(isinstance(dist.metadata, DistributionMetadata)) - self.assertEqual(dist.metadata['version'], version) - self.assertTrue(isinstance(dist.requested, type(bool()))) - - def test_installed_files(self): - # Test the iteration of installed files. - # Test the distribution's installed files - from distutils2._backport.pkgutil import Distribution - for distinfo_dir in self.distinfo_dirs: - dist = Distribution(distinfo_dir) - for path, md5_, size in dist.get_installed_files(): - record_data = self.records[dist.path] - self.assertTrue(path in record_data.keys()) - self.assertEqual(md5_, record_data[path][0]) - self.assertEqual(size, record_data[path][1]) - - def test_uses(self): - # Test to determine if a distribution uses a specified file. - # Criteria to test against - distinfo_name = 'grammar-1.0a4' - distinfo_dir = os.path.join(self.fake_dists_path, - distinfo_name + '.dist-info') - true_path = [self.fake_dists_path, distinfo_name, \ - 'grammar', 'utils.py'] - true_path = relpath(os.path.join(*true_path), sys.prefix) - false_path = [self.fake_dists_path, 'towel_stuff-0.1', 'towel_stuff', - '__init__.py'] - false_path = relpath(os.path.join(*false_path), sys.prefix) - - # Test if the distribution uses the file in question - from distutils2._backport.pkgutil import Distribution - dist = Distribution(distinfo_dir) - self.assertTrue(dist.uses(true_path)) - self.assertFalse(dist.uses(false_path)) - - def test_get_distinfo_file(self): - # Test the retrieval of dist-info file objects. - from distutils2._backport.pkgutil import Distribution - distinfo_name = 'choxie-2.0.0.9' - other_distinfo_name = 'grammar-1.0a4' - distinfo_dir = os.path.join(self.fake_dists_path, - distinfo_name + '.dist-info') - dist = Distribution(distinfo_dir) - # Test for known good file matches - distinfo_files = [ - # Relative paths - 'INSTALLER', 'METADATA', - # Absolute paths - os.path.join(distinfo_dir, 'RECORD'), - os.path.join(distinfo_dir, 'REQUESTED'), - ] - - for distfile in distinfo_files: - value = dist.get_distinfo_file(distfile) - self.assertTrue(isinstance(value, file)) - # Is it the correct file? - self.assertEqual(value.name, os.path.join(distinfo_dir, distfile)) - - from distutils2.errors import DistutilsError - # Test an absolute path that is part of another distributions dist-info - other_distinfo_file = os.path.join(self.fake_dists_path, - other_distinfo_name + '.dist-info', 'REQUESTED') - self.assertRaises(DistutilsError, dist.get_distinfo_file, - other_distinfo_file) - # Test for a file that does not exist and should not exist - self.assertRaises(DistutilsError, dist.get_distinfo_file, \ - 'ENTRYPOINTS') - - def test_get_distinfo_files(self): - # Test for the iteration of RECORD path entries. - from distutils2._backport.pkgutil import Distribution - distinfo_name = 'towel_stuff-0.1' - distinfo_dir = os.path.join(self.fake_dists_path, - distinfo_name + '.dist-info') - dist = Distribution(distinfo_dir) - # Test for the iteration of the raw path - distinfo_record_paths = self.records[distinfo_dir].keys() - found = [path for path in dist.get_distinfo_files()] - self.assertEqual(sorted(found), sorted(distinfo_record_paths)) - # Test for the iteration of local absolute paths - distinfo_record_paths = [os.path.join(sys.prefix, path) - for path in self.records[distinfo_dir].keys()] - found = [path for path in dist.get_distinfo_files(local=True)] - self.assertEqual(sorted(found), sorted(distinfo_record_paths)) - - -class TestPkgUtilPEP376(unittest.TestCase): - # Tests for the new functionality added in PEP 376. - - def setUp(self): - super(TestPkgUtilPEP376, self).setUp() - # Setup the path environment with our fake distributions - current_path = os.path.abspath(os.path.dirname(__file__)) - self.sys_path = sys.path[:] - self.fake_dists_path = os.path.join(current_path, 'fake_dists') - sys.path.insert(0, self.fake_dists_path) - - def tearDown(self): - sys.path[:] = self.sys_path - super(TestPkgUtilPEP376, self).tearDown() - - def test_distinfo_dirname(self): - # Given a name and a version, we expect the distinfo_dirname function - # to return a standard distribution information directory name. - - items = [# (name, version, standard_dirname) - # Test for a very simple single word name and decimal - # version number - ('docutils', '0.5', 'docutils-0.5.dist-info'), - # Test for another except this time with a '-' in the name, which - # needs to be transformed during the name lookup - ('python-ldap', '2.5', 'python_ldap-2.5.dist-info'), - # Test for both '-' in the name and a funky version number - ('python-ldap', '2.5 a---5', 'python_ldap-2.5 a---5.dist-info'), - ] - - # Import the function in question - from distutils2._backport.pkgutil import distinfo_dirname - - # Loop through the items to validate the results - for name, version, standard_dirname in items: - dirname = distinfo_dirname(name, version) - self.assertEqual(dirname, standard_dirname) - - def test_get_distributions(self): - # Lookup all distributions found in the ``sys.path``. - # This test could potentially pick up other installed distributions - fake_dists = [('grammar', '1.0a4'), ('choxie', '2.0.0.9'), - ('towel-stuff', '0.1')] - found_dists = [] - - # Import the function in question - from distutils2._backport.pkgutil import get_distributions, \ - Distribution, \ - EggInfoDistribution - - # Verify the fake dists have been found. - dists = [dist for dist in get_distributions()] - for dist in dists: - if not isinstance(dist, Distribution): - self.fail("item received was not a Distribution instance: " - "%s" % type(dist)) - if dist.name in dict(fake_dists).keys() and \ - dist.path.startswith(self.fake_dists_path): - found_dists.append((dist.name, dist.metadata['version'],)) - else: - # check that it doesn't find anything more than this - self.assertFalse(dist.path.startswith(self.fake_dists_path)) - # otherwise we don't care what other distributions are found - - # Finally, test that we found all that we were looking for - self.assertListEqual(sorted(found_dists), sorted(fake_dists)) - - # Now, test if the egg-info distributions are found correctly as well - fake_dists += [('bacon', '0.1'), ('cheese', '2.0.2'), - ('banana', '0.4'), ('strawberry', '0.6'), - ('truffles', '5.0')] - found_dists = [] - - dists = [dist for dist in get_distributions(use_egg_info=True)] - for dist in dists: - if not (isinstance(dist, Distribution) or \ - isinstance(dist, EggInfoDistribution)): - self.fail("item received was not a Distribution or " - "EggInfoDistribution instance: %s" % type(dist)) - if dist.name in dict(fake_dists).keys() and \ - dist.path.startswith(self.fake_dists_path): - found_dists.append((dist.name, dist.metadata['version'])) - else: - self.assertFalse(dist.path.startswith(self.fake_dists_path)) - - self.assertListEqual(sorted(fake_dists), sorted(found_dists)) - - def test_get_distribution(self): - # Test for looking up a distribution by name. - # Test the lookup of the towel-stuff distribution - name = 'towel-stuff' # Note: This is different from the directory name - - # Import the function in question - from distutils2._backport.pkgutil import get_distribution, \ - Distribution, \ - EggInfoDistribution - - # Lookup the distribution - dist = get_distribution(name) - self.assertTrue(isinstance(dist, Distribution)) - self.assertEqual(dist.name, name) - - # Verify that an unknown distribution returns None - self.assertEqual(None, get_distribution('bogus')) - - # Verify partial name matching doesn't work - self.assertEqual(None, get_distribution('towel')) - - # Verify that it does not find egg-info distributions, when not - # instructed to - self.assertEqual(None, get_distribution('bacon')) - self.assertEqual(None, get_distribution('cheese')) - self.assertEqual(None, get_distribution('strawberry')) - self.assertEqual(None, get_distribution('banana')) - - # Now check that it works well in both situations, when egg-info - # is a file and directory respectively. - dist = get_distribution('cheese', use_egg_info=True) - self.assertTrue(isinstance(dist, EggInfoDistribution)) - self.assertEqual(dist.name, 'cheese') - - dist = get_distribution('bacon', use_egg_info=True) - self.assertTrue(isinstance(dist, EggInfoDistribution)) - self.assertEqual(dist.name, 'bacon') - - dist = get_distribution('banana', use_egg_info=True) - self.assertTrue(isinstance(dist, EggInfoDistribution)) - self.assertEqual(dist.name, 'banana') - - dist = get_distribution('strawberry', use_egg_info=True) - self.assertTrue(isinstance(dist, EggInfoDistribution)) - self.assertEqual(dist.name, 'strawberry') - - def test_get_file_users(self): - # Test the iteration of distributions that use a file. - from distutils2._backport.pkgutil import get_file_users, Distribution - name = 'towel_stuff-0.1' - path = os.path.join(self.fake_dists_path, name, - 'towel_stuff', '__init__.py') - for dist in get_file_users(path): - self.assertTrue(isinstance(dist, Distribution)) - self.assertEqual(dist.name, name) - - def test_provides(self): - # Test for looking up distributions by what they provide - from distutils2._backport.pkgutil import provides_distribution - from distutils2.errors import DistutilsError - - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) - - l = [dist.name for dist in provides_distribution('truffles')] - checkLists(l, ['choxie', 'towel-stuff']) - - l = [dist.name for dist in provides_distribution('truffles', '1.0')] - checkLists(l, ['choxie']) - - l = [dist.name for dist in provides_distribution('truffles', '1.0', - use_egg_info=True)] - checkLists(l, ['choxie', 'cheese']) - - l = [dist.name for dist in provides_distribution('truffles', '1.1.2')] - checkLists(l, ['towel-stuff']) - - l = [dist.name for dist in provides_distribution('truffles', '1.1')] - checkLists(l, ['towel-stuff']) - - l = [dist.name for dist in provides_distribution('truffles', \ - '!=1.1,<=2.0')] - checkLists(l, ['choxie']) - - l = [dist.name for dist in provides_distribution('truffles', \ - '!=1.1,<=2.0', - use_egg_info=True)] - checkLists(l, ['choxie', 'bacon', 'cheese']) - - l = [dist.name for dist in provides_distribution('truffles', '>1.0')] - checkLists(l, ['towel-stuff']) - - l = [dist.name for dist in provides_distribution('truffles', '>1.5')] - checkLists(l, []) - - l = [dist.name for dist in provides_distribution('truffles', '>1.5', - use_egg_info=True)] - checkLists(l, ['bacon', 'truffles']) - - l = [dist.name for dist in provides_distribution('truffles', '>=1.0')] - checkLists(l, ['choxie', 'towel-stuff']) - - l = [dist.name for dist in provides_distribution('strawberry', '0.6', - use_egg_info=True)] - checkLists(l, ['strawberry']) - - l = [dist.name for dist in provides_distribution('strawberry', '>=0.5', - use_egg_info=True)] - checkLists(l, ['strawberry']) - - - l = [dist.name for dist in provides_distribution('strawberry', '>0.6', - use_egg_info=True)] - checkLists(l, []) - - - l = [dist.name for dist in provides_distribution('banana', '0.4', - use_egg_info=True)] - checkLists(l, ['banana']) - - l = [dist.name for dist in provides_distribution('banana', '>=0.3', - use_egg_info=True)] - checkLists(l, ['banana']) - - - l = [dist.name for dist in provides_distribution('banana', '!=0.4', - use_egg_info=True)] - checkLists(l, []) - - def test_obsoletes(self): - # Test looking for distributions based on what they obsolete - from distutils2._backport.pkgutil import obsoletes_distribution - from distutils2.errors import DistutilsError - - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) - - l = [dist.name for dist in obsoletes_distribution('truffles', '1.0')] - checkLists(l, []) - - l = [dist.name for dist in obsoletes_distribution('truffles', '1.0', - use_egg_info=True)] - checkLists(l, ['cheese', 'bacon']) - - - l = [dist.name for dist in obsoletes_distribution('truffles', '0.8')] - checkLists(l, ['choxie']) - - l = [dist.name for dist in obsoletes_distribution('truffles', '0.8', - use_egg_info=True)] - checkLists(l, ['choxie', 'cheese']) - - l = [dist.name for dist in obsoletes_distribution('truffles', '0.9.6')] - checkLists(l, ['choxie', 'towel-stuff']) - - l = [dist.name for dist in obsoletes_distribution('truffles', \ - '0.5.2.3')] - checkLists(l, ['choxie', 'towel-stuff']) - - l = [dist.name for dist in obsoletes_distribution('truffles', '0.2')] - checkLists(l, ['towel-stuff']) - - def test_yield_distribution(self): - # tests the internal function _yield_distributions - from distutils2._backport.pkgutil import _yield_distributions - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) - - eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), - ('truffles', '5.0'), ('cheese', '2.0.2')] - dists = [('choxie', '2.0.0.9'), ('grammar', '1.0a4'), - ('towel-stuff', '0.1')] - - checkLists([], _yield_distributions(False, False)) - - found = [(dist.name, dist.metadata['Version']) - for dist in _yield_distributions(False, True) - if dist.path.startswith(self.fake_dists_path)] - checkLists(eggs, found) - - found = [(dist.name, dist.metadata['Version']) - for dist in _yield_distributions(True, False) - if dist.path.startswith(self.fake_dists_path)] - checkLists(dists, found) - - found = [(dist.name, dist.metadata['Version']) - for dist in _yield_distributions(True, True) - if dist.path.startswith(self.fake_dists_path)] - checkLists(dists + eggs, found) - - -def test_suite(): - suite = unittest.TestSuite() - load = unittest.defaultTestLoader.loadTestsFromTestCase - suite.addTest(load(TestPkgUtilData)) - suite.addTest(load(TestPkgUtilDistribution)) - suite.addTest(load(TestPkgUtilPEP302)) - suite.addTest(load(TestPkgUtilPEP376)) - return suite - - -def test_main(): - run_unittest(test_suite()) - - -if __name__ == "__main__": - test_main() diff --git a/src/distutils2/_backport/tests/test_sysconfig.py b/src/distutils2/_backport/tests/test_sysconfig.py deleted file mode 100644 index 3b51098..0000000 --- a/src/distutils2/_backport/tests/test_sysconfig.py +++ /dev/null @@ -1,305 +0,0 @@ -"""Tests for sysconfig.""" - -import os -import sys -import subprocess -import shutil -from copy import copy, deepcopy -from ConfigParser import RawConfigParser -from StringIO import StringIO - -from distutils2._backport import sysconfig -from distutils2._backport.sysconfig import ( - _expand_globals, _expand_vars, _get_default_scheme, _subst_vars, - get_config_var, get_config_vars, get_path, get_paths, get_platform, - get_scheme_names, _main, _SCHEMES) - -from distutils2.tests.support import unittest, EnvironGuard -from test.test_support import TESTFN, unlink -try: - from test.test_support import skip_unless_symlink -except ImportError: - skip_unless_symlink = unittest.skip( - 'requires test.test_support.skip_unless_symlink') - -class TestSysConfig(EnvironGuard, unittest.TestCase): - - def setUp(self): - super(TestSysConfig, self).setUp() - self.sys_path = sys.path[:] - self.makefile = None - # patching os.uname - if hasattr(os, 'uname'): - self.uname = os.uname - self._uname = os.uname() - else: - self.uname = None - self._uname = None - os.uname = self._get_uname - # saving the environment - self.name = os.name - self.platform = sys.platform - self.version = sys.version - self.maxint = sys.maxint - self.sep = os.sep - self.join = os.path.join - self.isabs = os.path.isabs - self.splitdrive = os.path.splitdrive - self._config_vars = copy(sysconfig._CONFIG_VARS) - - def tearDown(self): - sys.path[:] = self.sys_path - if self.makefile is not None: - os.unlink(self.makefile) - self._cleanup_testfn() - if self.uname is not None: - os.uname = self.uname - else: - del os.uname - os.name = self.name - sys.platform = self.platform - sys.version = self.version - sys.maxint = self.maxint - os.sep = self.sep - os.path.join = self.join - os.path.isabs = self.isabs - os.path.splitdrive = self.splitdrive - sysconfig._CONFIG_VARS = copy(self._config_vars) - super(TestSysConfig, self).tearDown() - - def _set_uname(self, uname): - self._uname = uname - - def _get_uname(self): - return self._uname - - def _cleanup_testfn(self): - path = TESTFN - if os.path.isfile(path): - os.remove(path) - elif os.path.isdir(path): - shutil.rmtree(path) - - # TODO use a static list or remove the test - #def test_get_path_names(self): - # self.assertEqual(get_path_names(), sysconfig._SCHEME_KEYS) - - def test_nested_var_substitution(self): - # Assert that the {curly brace token} expansion pattern will replace - # only the inner {something} on nested expressions like {py{something}} on - # the first pass. - - # We have no plans to make use of this, but it keeps the option open for - # the future, at the cost only of disallowing { itself as a piece of a - # substitution key (which would be weird). - self.assertEqual(_subst_vars('{py{version}}', {'version': '31'}), '{py31}') - - def test_get_paths(self): - scheme = get_paths() - default_scheme = _get_default_scheme() - wanted = _expand_vars(default_scheme, None) - wanted = sorted(wanted.items()) - scheme = sorted(scheme.items()) - self.assertEqual(scheme, wanted) - - def test_get_path(self): - # xxx make real tests here - for scheme in _SCHEMES.sections(): - for name, _ in _SCHEMES.items(scheme): - get_path(name, scheme) - - def test_get_config_vars(self): - cvars = get_config_vars() - self.assertIsInstance(cvars, dict) - self.assertTrue(cvars) - - def test_get_platform(self): - # windows XP, 32bits - os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Intel)]') - sys.platform = 'win32' - self.assertEqual(get_platform(), 'win32') - - # windows XP, amd64 - os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Amd64)]') - sys.platform = 'win32' - self.assertEqual(get_platform(), 'win-amd64') - - # windows XP, itanium - os.name = 'nt' - sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) ' - '[MSC v.1310 32 bit (Itanium)]') - sys.platform = 'win32' - self.assertEqual(get_platform(), 'win-ia64') - - # macbook - os.name = 'posix' - sys.version = ('2.5 (r25:51918, Sep 19 2006, 08:49:13) ' - '\n[GCC 4.0.1 (Apple Computer, Inc. build 5341)]') - sys.platform = 'darwin' - self._set_uname(('Darwin', 'macziade', '8.11.1', - ('Darwin Kernel Version 8.11.1: ' - 'Wed Oct 10 18:23:28 PDT 2007; ' - 'root:xnu-792.25.20~1/RELEASE_I386'), 'PowerPC')) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - - get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' - '-fwrapv -O3 -Wall -Wstrict-prototypes') - - sys.maxint = 2147483647 - self.assertEqual(get_platform(), 'macosx-10.3-ppc') - sys.maxint = 9223372036854775807 - self.assertEqual(get_platform(), 'macosx-10.3-ppc64') - - - self._set_uname(('Darwin', 'macziade', '8.11.1', - ('Darwin Kernel Version 8.11.1: ' - 'Wed Oct 10 18:23:28 PDT 2007; ' - 'root:xnu-792.25.20~1/RELEASE_I386'), 'i386')) - get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' - - get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g ' - '-fwrapv -O3 -Wall -Wstrict-prototypes') - - sys.maxint = 2147483647 - self.assertEqual(get_platform(), 'macosx-10.3-i386') - sys.maxint = 9223372036854775807 - self.assertEqual(get_platform(), 'macosx-10.3-x86_64') - - # macbook with fat binaries (fat, universal or fat64) - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.4' - get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - - self.assertEqual(get_platform(), 'macosx-10.4-fat') - - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - - self.assertEqual(get_platform(), 'macosx-10.4-intel') - - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - self.assertEqual(get_platform(), 'macosx-10.4-fat3') - - get_config_vars()['CFLAGS'] = ('-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - self.assertEqual(get_platform(), 'macosx-10.4-universal') - - get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc64 -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3') - - self.assertEqual(get_platform(), 'macosx-10.4-fat64') - - for arch in ('ppc', 'i386', 'x86_64', 'ppc64'): - get_config_vars()['CFLAGS'] = ('-arch %s -isysroot ' - '/Developer/SDKs/MacOSX10.4u.sdk ' - '-fno-strict-aliasing -fno-common ' - '-dynamic -DNDEBUG -g -O3'%(arch,)) - - self.assertEqual(get_platform(), 'macosx-10.4-%s'%(arch,)) - - # linux debian sarge - os.name = 'posix' - sys.version = ('2.3.5 (#1, Jul 4 2007, 17:28:59) ' - '\n[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)]') - sys.platform = 'linux2' - self._set_uname(('Linux', 'aglae', '2.6.21.1dedibox-r7', - '#1 Mon Apr 30 17:25:38 CEST 2007', 'i686')) - - self.assertEqual(get_platform(), 'linux-i686') - - # XXX more platforms to tests here - - def test_get_config_h_filename(self): - config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) - - def test_get_scheme_names(self): - wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user', - 'posix_home', 'posix_prefix', 'posix_user') - self.assertEqual(get_scheme_names(), wanted) - - @skip_unless_symlink - def test_symlink(self): - # On Windows, the EXE needs to know where pythonXY.dll is at so we have - # to add the directory to the path. - if sys.platform == 'win32': - os.environ['Path'] = ';'.join(( - os.path.dirname(sys.executable), os.environ['Path'])) - - # Issue 7880 - def get(python): - cmd = [python, '-c', - 'import sysconfig; print(sysconfig.get_platform())'] - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=os.environ) - return p.communicate() - real = os.path.realpath(sys.executable) - link = os.path.abspath(TESTFN) - os.symlink(real, link) - try: - self.assertEqual(get(real), get(link)) - finally: - unlink(link) - - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_user_similar(self): - # Issue 8759 : make sure the posix scheme for the users - # is similar to the global posix_prefix one - base = get_config_var('base') - user = get_config_var('userbase') - for name in ('stdlib', 'platstdlib', 'purelib', 'platlib'): - global_path = get_path(name, 'posix_prefix') - user_path = get_path(name, 'posix_user') - self.assertEqual(user_path, global_path.replace(base, user)) - - def test_main(self): - # just making sure _main() runs and returns things in the stdout - self.addCleanup(setattr, sys, 'stdout', sys.stdout) - sys.stdout = StringIO() - _main() - self.assertGreater(len(sys.stdout.getvalue().split('\n')), 0) - - @unittest.skipIf(sys.platform == 'win32', 'does not apply to Windows') - def test_ldshared_value(self): - ldflags = sysconfig.get_config_var('LDFLAGS') - ldshared = sysconfig.get_config_var('LDSHARED') - - self.assertIn(ldflags, ldshared) - - def test_expand_globals(self): - config = RawConfigParser() - config.add_section('globals') - config.set('globals', 'foo', 'ok') - config.add_section('posix') - config.set('posix', 'config', '/etc') - config.set('posix', 'more', '{config}/ok') - - _expand_globals(config) - - self.assertEqual(config.get('posix', 'foo'), 'ok') - self.assertEqual(config.get('posix', 'more'), '/etc/ok') - - # we might not have globals after all - # extending again (==no more globals section) - _expand_globals(config) - -def test_suite(): - return unittest.makeSuite(TestSysConfig) - -if __name__ == '__main__': - unittest.main(defaultTest='test_suite') diff --git a/src/distutils2/_trove.py b/src/distutils2/_trove.py deleted file mode 100644 index a215e9d..0000000 --- a/src/distutils2/_trove.py +++ /dev/null @@ -1,552 +0,0 @@ -# Temporary helper for mkpkg. - -# XXX get the list from PyPI and cache it instead of hardcoding - -# XXX see if it would be more useful to store it as another structure -# than a list of strings - -all_classifiers = [ - 'Development Status :: 1 - Planning', - 'Development Status :: 2 - Pre-Alpha', - 'Development Status :: 3 - Alpha', - 'Development Status :: 4 - Beta', - 'Development Status :: 5 - Production/Stable', - 'Development Status :: 6 - Mature', - 'Development Status :: 7 - Inactive', - 'Environment :: Console', - 'Environment :: Console :: Curses', - 'Environment :: Console :: Framebuffer', - 'Environment :: Console :: Newt', - 'Environment :: Console :: svgalib', - "Environment :: Handhelds/PDA's", - 'Environment :: MacOS X', - 'Environment :: MacOS X :: Aqua', - 'Environment :: MacOS X :: Carbon', - 'Environment :: MacOS X :: Cocoa', - 'Environment :: No Input/Output (Daemon)', - 'Environment :: Other Environment', - 'Environment :: Plugins', - 'Environment :: Web Environment', - 'Environment :: Web Environment :: Buffet', - 'Environment :: Web Environment :: Mozilla', - 'Environment :: Web Environment :: ToscaWidgets', - 'Environment :: Win32 (MS Windows)', - 'Environment :: X11 Applications', - 'Environment :: X11 Applications :: Gnome', - 'Environment :: X11 Applications :: GTK', - 'Environment :: X11 Applications :: KDE', - 'Environment :: X11 Applications :: Qt', - 'Framework :: BFG', - 'Framework :: Buildout', - 'Framework :: Chandler', - 'Framework :: CubicWeb', - 'Framework :: Django', - 'Framework :: IDLE', - 'Framework :: Paste', - 'Framework :: Plone', - 'Framework :: Pylons', - 'Framework :: Setuptools Plugin', - 'Framework :: Trac', - 'Framework :: TurboGears', - 'Framework :: TurboGears :: Applications', - 'Framework :: TurboGears :: Widgets', - 'Framework :: Twisted', - 'Framework :: ZODB', - 'Framework :: Zope2', - 'Framework :: Zope3', - 'Intended Audience :: Customer Service', - 'Intended Audience :: Developers', - 'Intended Audience :: Education', - 'Intended Audience :: End Users/Desktop', - 'Intended Audience :: Financial and Insurance Industry', - 'Intended Audience :: Healthcare Industry', - 'Intended Audience :: Information Technology', - 'Intended Audience :: Legal Industry', - 'Intended Audience :: Manufacturing', - 'Intended Audience :: Other Audience', - 'Intended Audience :: Religion', - 'Intended Audience :: Science/Research', - 'Intended Audience :: System Administrators', - 'Intended Audience :: Telecommunications Industry', - 'License :: Aladdin Free Public License (AFPL)', - 'License :: DFSG approved', - 'License :: Eiffel Forum License (EFL)', - 'License :: Free For Educational Use', - 'License :: Free For Home Use', - 'License :: Free for non-commercial use', - 'License :: Freely Distributable', - 'License :: Free To Use But Restricted', - 'License :: Freeware', - 'License :: Netscape Public License (NPL)', - 'License :: Nokia Open Source License (NOKOS)', - 'License :: OSI Approved', - 'License :: OSI Approved :: Academic Free License (AFL)', - 'License :: OSI Approved :: Apache Software License', - 'License :: OSI Approved :: Apple Public Source License', - 'License :: OSI Approved :: Artistic License', - 'License :: OSI Approved :: Attribution Assurance License', - 'License :: OSI Approved :: BSD License', - 'License :: OSI Approved :: Common Public License', - 'License :: OSI Approved :: Eiffel Forum License', - 'License :: OSI Approved :: European Union Public Licence 1.0 (EUPL 1.0)', - 'License :: OSI Approved :: European Union Public Licence 1.1 (EUPL 1.1)', - 'License :: OSI Approved :: GNU Affero General Public License v3', - 'License :: OSI Approved :: GNU Free Documentation License (FDL)', - 'License :: OSI Approved :: GNU General Public License (GPL)', - 'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)', - 'License :: OSI Approved :: IBM Public License', - 'License :: OSI Approved :: Intel Open Source License', - 'License :: OSI Approved :: ISC License (ISCL)', - 'License :: OSI Approved :: Jabber Open Source License', - 'License :: OSI Approved :: MIT License', - 'License :: OSI Approved :: MITRE Collaborative Virtual Workspace License (CVW)', - 'License :: OSI Approved :: Motosoto License', - 'License :: OSI Approved :: Mozilla Public License 1.0 (MPL)', - 'License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1)', - 'License :: OSI Approved :: Nethack General Public License', - 'License :: OSI Approved :: Nokia Open Source License', - 'License :: OSI Approved :: Open Group Test Suite License', - 'License :: OSI Approved :: Python License (CNRI Python License)', - 'License :: OSI Approved :: Python Software Foundation License', - 'License :: OSI Approved :: Qt Public License (QPL)', - 'License :: OSI Approved :: Ricoh Source Code Public License', - 'License :: OSI Approved :: Sleepycat License', - 'License :: OSI Approved :: Sun Industry Standards Source License (SISSL)', - 'License :: OSI Approved :: Sun Public License', - 'License :: OSI Approved :: University of Illinois/NCSA Open Source License', - 'License :: OSI Approved :: Vovida Software License 1.0', - 'License :: OSI Approved :: W3C License', - 'License :: OSI Approved :: X.Net License', - 'License :: OSI Approved :: zlib/libpng License', - 'License :: OSI Approved :: Zope Public License', - 'License :: Other/Proprietary License', - 'License :: Public Domain', - 'License :: Repoze Public License', - 'Natural Language :: Afrikaans', - 'Natural Language :: Arabic', - 'Natural Language :: Bengali', - 'Natural Language :: Bosnian', - 'Natural Language :: Bulgarian', - 'Natural Language :: Catalan', - 'Natural Language :: Chinese (Simplified)', - 'Natural Language :: Chinese (Traditional)', - 'Natural Language :: Croatian', - 'Natural Language :: Czech', - 'Natural Language :: Danish', - 'Natural Language :: Dutch', - 'Natural Language :: English', - 'Natural Language :: Esperanto', - 'Natural Language :: Finnish', - 'Natural Language :: French', - 'Natural Language :: German', - 'Natural Language :: Greek', - 'Natural Language :: Hebrew', - 'Natural Language :: Hindi', - 'Natural Language :: Hungarian', - 'Natural Language :: Icelandic', - 'Natural Language :: Indonesian', - 'Natural Language :: Italian', - 'Natural Language :: Japanese', - 'Natural Language :: Javanese', - 'Natural Language :: Korean', - 'Natural Language :: Latin', - 'Natural Language :: Latvian', - 'Natural Language :: Macedonian', - 'Natural Language :: Malay', - 'Natural Language :: Marathi', - 'Natural Language :: Norwegian', - 'Natural Language :: Panjabi', - 'Natural Language :: Persian', - 'Natural Language :: Polish', - 'Natural Language :: Portuguese', - 'Natural Language :: Portuguese (Brazilian)', - 'Natural Language :: Romanian', - 'Natural Language :: Russian', - 'Natural Language :: Serbian', - 'Natural Language :: Slovak', - 'Natural Language :: Slovenian', - 'Natural Language :: Spanish', - 'Natural Language :: Swedish', - 'Natural Language :: Tamil', - 'Natural Language :: Telugu', - 'Natural Language :: Thai', - 'Natural Language :: Turkish', - 'Natural Language :: Ukranian', - 'Natural Language :: Urdu', - 'Natural Language :: Vietnamese', - 'Operating System :: BeOS', - 'Operating System :: MacOS', - 'Operating System :: MacOS :: MacOS 9', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: Microsoft', - 'Operating System :: Microsoft :: MS-DOS', - 'Operating System :: Microsoft :: Windows', - 'Operating System :: Microsoft :: Windows :: Windows 3.1 or Earlier', - 'Operating System :: Microsoft :: Windows :: Windows 95/98/2000', - 'Operating System :: Microsoft :: Windows :: Windows CE', - 'Operating System :: Microsoft :: Windows :: Windows NT/2000', - 'Operating System :: OS/2', - 'Operating System :: OS Independent', - 'Operating System :: Other OS', - 'Operating System :: PalmOS', - 'Operating System :: PDA Systems', - 'Operating System :: POSIX', - 'Operating System :: POSIX :: AIX', - 'Operating System :: POSIX :: BSD', - 'Operating System :: POSIX :: BSD :: BSD/OS', - 'Operating System :: POSIX :: BSD :: FreeBSD', - 'Operating System :: POSIX :: BSD :: NetBSD', - 'Operating System :: POSIX :: BSD :: OpenBSD', - 'Operating System :: POSIX :: GNU Hurd', - 'Operating System :: POSIX :: HP-UX', - 'Operating System :: POSIX :: IRIX', - 'Operating System :: POSIX :: Linux', - 'Operating System :: POSIX :: Other', - 'Operating System :: POSIX :: SCO', - 'Operating System :: POSIX :: SunOS/Solaris', - 'Operating System :: Unix', - 'Programming Language :: Ada', - 'Programming Language :: APL', - 'Programming Language :: ASP', - 'Programming Language :: Assembly', - 'Programming Language :: Awk', - 'Programming Language :: Basic', - 'Programming Language :: C', - 'Programming Language :: C#', - 'Programming Language :: C++', - 'Programming Language :: Cold Fusion', - 'Programming Language :: Cython', - 'Programming Language :: Delphi/Kylix', - 'Programming Language :: Dylan', - 'Programming Language :: Eiffel', - 'Programming Language :: Emacs-Lisp', - 'Programming Language :: Erlang', - 'Programming Language :: Euler', - 'Programming Language :: Euphoria', - 'Programming Language :: Forth', - 'Programming Language :: Fortran', - 'Programming Language :: Haskell', - 'Programming Language :: Java', - 'Programming Language :: JavaScript', - 'Programming Language :: Lisp', - 'Programming Language :: Logo', - 'Programming Language :: ML', - 'Programming Language :: Modula', - 'Programming Language :: Objective C', - 'Programming Language :: Object Pascal', - 'Programming Language :: OCaml', - 'Programming Language :: Other', - 'Programming Language :: Other Scripting Engines', - 'Programming Language :: Pascal', - 'Programming Language :: Perl', - 'Programming Language :: PHP', - 'Programming Language :: Pike', - 'Programming Language :: Pliant', - 'Programming Language :: PL/SQL', - 'Programming Language :: PROGRESS', - 'Programming Language :: Prolog', - 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.3', - 'Programming Language :: Python :: 2.4', - 'Programming Language :: Python :: 2.5', - 'Programming Language :: Python :: 2.6', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.0', - 'Programming Language :: Python :: 3.1', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: REBOL', - 'Programming Language :: Rexx', - 'Programming Language :: Ruby', - 'Programming Language :: Scheme', - 'Programming Language :: Simula', - 'Programming Language :: Smalltalk', - 'Programming Language :: SQL', - 'Programming Language :: Tcl', - 'Programming Language :: Unix Shell', - 'Programming Language :: Visual Basic', - 'Programming Language :: XBasic', - 'Programming Language :: YACC', - 'Programming Language :: Zope', - 'Topic :: Adaptive Technologies', - 'Topic :: Artistic Software', - 'Topic :: Communications', - 'Topic :: Communications :: BBS', - 'Topic :: Communications :: Chat', - 'Topic :: Communications :: Chat :: AOL Instant Messenger', - 'Topic :: Communications :: Chat :: ICQ', - 'Topic :: Communications :: Chat :: Internet Relay Chat', - 'Topic :: Communications :: Chat :: Unix Talk', - 'Topic :: Communications :: Conferencing', - 'Topic :: Communications :: Email', - 'Topic :: Communications :: Email :: Address Book', - 'Topic :: Communications :: Email :: Email Clients (MUA)', - 'Topic :: Communications :: Email :: Filters', - 'Topic :: Communications :: Email :: Mailing List Servers', - 'Topic :: Communications :: Email :: Mail Transport Agents', - 'Topic :: Communications :: Email :: Post-Office', - 'Topic :: Communications :: Email :: Post-Office :: IMAP', - 'Topic :: Communications :: Email :: Post-Office :: POP3', - 'Topic :: Communications :: Fax', - 'Topic :: Communications :: FIDO', - 'Topic :: Communications :: File Sharing', - 'Topic :: Communications :: File Sharing :: Gnutella', - 'Topic :: Communications :: File Sharing :: Napster', - 'Topic :: Communications :: Ham Radio', - 'Topic :: Communications :: Internet Phone', - 'Topic :: Communications :: Telephony', - 'Topic :: Communications :: Usenet News', - 'Topic :: Database', - 'Topic :: Database :: Database Engines/Servers', - 'Topic :: Database :: Front-Ends', - 'Topic :: Desktop Environment', - 'Topic :: Desktop Environment :: File Managers', - 'Topic :: Desktop Environment :: Gnome', - 'Topic :: Desktop Environment :: GNUstep', - 'Topic :: Desktop Environment :: K Desktop Environment (KDE)', - 'Topic :: Desktop Environment :: K Desktop Environment (KDE) :: Themes', - 'Topic :: Desktop Environment :: PicoGUI', - 'Topic :: Desktop Environment :: PicoGUI :: Applications', - 'Topic :: Desktop Environment :: PicoGUI :: Themes', - 'Topic :: Desktop Environment :: Screen Savers', - 'Topic :: Desktop Environment :: Window Managers', - 'Topic :: Desktop Environment :: Window Managers :: Afterstep', - 'Topic :: Desktop Environment :: Window Managers :: Afterstep :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: Applets', - 'Topic :: Desktop Environment :: Window Managers :: Blackbox', - 'Topic :: Desktop Environment :: Window Managers :: Blackbox :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: CTWM', - 'Topic :: Desktop Environment :: Window Managers :: CTWM :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: Enlightenment', - 'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Epplets', - 'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR15', - 'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR16', - 'Topic :: Desktop Environment :: Window Managers :: Enlightenment :: Themes DR17', - 'Topic :: Desktop Environment :: Window Managers :: Fluxbox', - 'Topic :: Desktop Environment :: Window Managers :: Fluxbox :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: FVWM', - 'Topic :: Desktop Environment :: Window Managers :: FVWM :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: IceWM', - 'Topic :: Desktop Environment :: Window Managers :: IceWM :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: MetaCity', - 'Topic :: Desktop Environment :: Window Managers :: MetaCity :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: Oroborus', - 'Topic :: Desktop Environment :: Window Managers :: Oroborus :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: Sawfish', - 'Topic :: Desktop Environment :: Window Managers :: Sawfish :: Themes 0.30', - 'Topic :: Desktop Environment :: Window Managers :: Sawfish :: Themes pre-0.30', - 'Topic :: Desktop Environment :: Window Managers :: Waimea', - 'Topic :: Desktop Environment :: Window Managers :: Waimea :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: Window Maker', - 'Topic :: Desktop Environment :: Window Managers :: Window Maker :: Applets', - 'Topic :: Desktop Environment :: Window Managers :: Window Maker :: Themes', - 'Topic :: Desktop Environment :: Window Managers :: XFCE', - 'Topic :: Desktop Environment :: Window Managers :: XFCE :: Themes', - 'Topic :: Documentation', - 'Topic :: Education', - 'Topic :: Education :: Computer Aided Instruction (CAI)', - 'Topic :: Education :: Testing', - 'Topic :: Games/Entertainment', - 'Topic :: Games/Entertainment :: Arcade', - 'Topic :: Games/Entertainment :: Board Games', - 'Topic :: Games/Entertainment :: First Person Shooters', - 'Topic :: Games/Entertainment :: Fortune Cookies', - 'Topic :: Games/Entertainment :: Multi-User Dungeons (MUD)', - 'Topic :: Games/Entertainment :: Puzzle Games', - 'Topic :: Games/Entertainment :: Real Time Strategy', - 'Topic :: Games/Entertainment :: Role-Playing', - 'Topic :: Games/Entertainment :: Side-Scrolling/Arcade Games', - 'Topic :: Games/Entertainment :: Simulation', - 'Topic :: Games/Entertainment :: Turn Based Strategy', - 'Topic :: Home Automation', - 'Topic :: Internet', - 'Topic :: Internet :: File Transfer Protocol (FTP)', - 'Topic :: Internet :: Finger', - 'Topic :: Internet :: Log Analysis', - 'Topic :: Internet :: Name Service (DNS)', - 'Topic :: Internet :: Proxy Servers', - 'Topic :: Internet :: WAP', - 'Topic :: Internet :: WWW/HTTP', - 'Topic :: Internet :: WWW/HTTP :: Browsers', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Message Boards', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: News/Diary', - 'Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Page Counters', - 'Topic :: Internet :: WWW/HTTP :: HTTP Servers', - 'Topic :: Internet :: WWW/HTTP :: Indexing/Search', - 'Topic :: Internet :: WWW/HTTP :: Site Management', - 'Topic :: Internet :: WWW/HTTP :: Site Management :: Link Checking', - 'Topic :: Internet :: WWW/HTTP :: WSGI', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware', - 'Topic :: Internet :: WWW/HTTP :: WSGI :: Server', - 'Topic :: Internet :: Z39.50', - 'Topic :: Multimedia', - 'Topic :: Multimedia :: Graphics', - 'Topic :: Multimedia :: Graphics :: 3D Modeling', - 'Topic :: Multimedia :: Graphics :: 3D Rendering', - 'Topic :: Multimedia :: Graphics :: Capture', - 'Topic :: Multimedia :: Graphics :: Capture :: Digital Camera', - 'Topic :: Multimedia :: Graphics :: Capture :: Scanners', - 'Topic :: Multimedia :: Graphics :: Capture :: Screen Capture', - 'Topic :: Multimedia :: Graphics :: Editors', - 'Topic :: Multimedia :: Graphics :: Editors :: Raster-Based', - 'Topic :: Multimedia :: Graphics :: Editors :: Vector-Based', - 'Topic :: Multimedia :: Graphics :: Graphics Conversion', - 'Topic :: Multimedia :: Graphics :: Presentation', - 'Topic :: Multimedia :: Graphics :: Viewers', - 'Topic :: Multimedia :: Sound/Audio', - 'Topic :: Multimedia :: Sound/Audio :: Analysis', - 'Topic :: Multimedia :: Sound/Audio :: Capture/Recording', - 'Topic :: Multimedia :: Sound/Audio :: CD Audio', - 'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Playing', - 'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Ripping', - 'Topic :: Multimedia :: Sound/Audio :: CD Audio :: CD Writing', - 'Topic :: Multimedia :: Sound/Audio :: Conversion', - 'Topic :: Multimedia :: Sound/Audio :: Editors', - 'Topic :: Multimedia :: Sound/Audio :: MIDI', - 'Topic :: Multimedia :: Sound/Audio :: Mixers', - 'Topic :: Multimedia :: Sound/Audio :: Players', - 'Topic :: Multimedia :: Sound/Audio :: Players :: MP3', - 'Topic :: Multimedia :: Sound/Audio :: Sound Synthesis', - 'Topic :: Multimedia :: Sound/Audio :: Speech', - 'Topic :: Multimedia :: Video', - 'Topic :: Multimedia :: Video :: Capture', - 'Topic :: Multimedia :: Video :: Conversion', - 'Topic :: Multimedia :: Video :: Display', - 'Topic :: Multimedia :: Video :: Non-Linear Editor', - 'Topic :: Office/Business', - 'Topic :: Office/Business :: Financial', - 'Topic :: Office/Business :: Financial :: Accounting', - 'Topic :: Office/Business :: Financial :: Investment', - 'Topic :: Office/Business :: Financial :: Point-Of-Sale', - 'Topic :: Office/Business :: Financial :: Spreadsheet', - 'Topic :: Office/Business :: Groupware', - 'Topic :: Office/Business :: News/Diary', - 'Topic :: Office/Business :: Office Suites', - 'Topic :: Office/Business :: Scheduling', - 'Topic :: Other/Nonlisted Topic', - 'Topic :: Printing', - 'Topic :: Religion', - 'Topic :: Scientific/Engineering', - 'Topic :: Scientific/Engineering :: Artificial Intelligence', - 'Topic :: Scientific/Engineering :: Astronomy', - 'Topic :: Scientific/Engineering :: Atmospheric Science', - 'Topic :: Scientific/Engineering :: Bio-Informatics', - 'Topic :: Scientific/Engineering :: Chemistry', - 'Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)', - 'Topic :: Scientific/Engineering :: GIS', - 'Topic :: Scientific/Engineering :: Human Machine Interfaces', - 'Topic :: Scientific/Engineering :: Image Recognition', - 'Topic :: Scientific/Engineering :: Information Analysis', - 'Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator', - 'Topic :: Scientific/Engineering :: Mathematics', - 'Topic :: Scientific/Engineering :: Medical Science Apps.', - 'Topic :: Scientific/Engineering :: Physics', - 'Topic :: Scientific/Engineering :: Visualization', - 'Topic :: Security', - 'Topic :: Security :: Cryptography', - 'Topic :: Sociology', - 'Topic :: Sociology :: Genealogy', - 'Topic :: Sociology :: History', - 'Topic :: Software Development', - 'Topic :: Software Development :: Assemblers', - 'Topic :: Software Development :: Bug Tracking', - 'Topic :: Software Development :: Build Tools', - 'Topic :: Software Development :: Code Generators', - 'Topic :: Software Development :: Compilers', - 'Topic :: Software Development :: Debuggers', - 'Topic :: Software Development :: Disassemblers', - 'Topic :: Software Development :: Documentation', - 'Topic :: Software Development :: Embedded Systems', - 'Topic :: Software Development :: Internationalization', - 'Topic :: Software Development :: Interpreters', - 'Topic :: Software Development :: Libraries', - 'Topic :: Software Development :: Libraries :: Application Frameworks', - 'Topic :: Software Development :: Libraries :: Java Libraries', - 'Topic :: Software Development :: Libraries :: Perl Modules', - 'Topic :: Software Development :: Libraries :: PHP Classes', - 'Topic :: Software Development :: Libraries :: Pike Modules', - 'Topic :: Software Development :: Libraries :: pygame', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: Software Development :: Libraries :: Ruby Modules', - 'Topic :: Software Development :: Libraries :: Tcl Extensions', - 'Topic :: Software Development :: Localization', - 'Topic :: Software Development :: Object Brokering', - 'Topic :: Software Development :: Object Brokering :: CORBA', - 'Topic :: Software Development :: Pre-processors', - 'Topic :: Software Development :: Quality Assurance', - 'Topic :: Software Development :: Testing', - 'Topic :: Software Development :: Testing :: Traffic Generation', - 'Topic :: Software Development :: User Interfaces', - 'Topic :: Software Development :: Version Control', - 'Topic :: Software Development :: Version Control :: CVS', - 'Topic :: Software Development :: Version Control :: RCS', - 'Topic :: Software Development :: Version Control :: SCCS', - 'Topic :: Software Development :: Widget Sets', - 'Topic :: System', - 'Topic :: System :: Archiving', - 'Topic :: System :: Archiving :: Backup', - 'Topic :: System :: Archiving :: Compression', - 'Topic :: System :: Archiving :: Mirroring', - 'Topic :: System :: Archiving :: Packaging', - 'Topic :: System :: Benchmark', - 'Topic :: System :: Boot', - 'Topic :: System :: Boot :: Init', - 'Topic :: System :: Clustering', - 'Topic :: System :: Console Fonts', - 'Topic :: System :: Distributed Computing', - 'Topic :: System :: Emulators', - 'Topic :: System :: Filesystems', - 'Topic :: System :: Hardware', - 'Topic :: System :: Hardware :: Hardware Drivers', - 'Topic :: System :: Hardware :: Mainframes', - 'Topic :: System :: Hardware :: Symmetric Multi-processing', - 'Topic :: System :: Installation/Setup', - 'Topic :: System :: Logging', - 'Topic :: System :: Monitoring', - 'Topic :: System :: Networking', - 'Topic :: System :: Networking :: Firewalls', - 'Topic :: System :: Networking :: Monitoring', - 'Topic :: System :: Networking :: Monitoring :: Hardware Watchdog', - 'Topic :: System :: Networking :: Time Synchronization', - 'Topic :: System :: Operating System', - 'Topic :: System :: Operating System Kernels', - 'Topic :: System :: Operating System Kernels :: BSD', - 'Topic :: System :: Operating System Kernels :: GNU Hurd', - 'Topic :: System :: Operating System Kernels :: Linux', - 'Topic :: System :: Power (UPS)', - 'Topic :: System :: Recovery Tools', - 'Topic :: System :: Shells', - 'Topic :: System :: Software Distribution', - 'Topic :: System :: Systems Administration', - 'Topic :: System :: Systems Administration :: Authentication/Directory', - 'Topic :: System :: Systems Administration :: Authentication/Directory :: LDAP', - 'Topic :: System :: Systems Administration :: Authentication/Directory :: NIS', - 'Topic :: System :: System Shells', - 'Topic :: Terminals', - 'Topic :: Terminals :: Serial', - 'Topic :: Terminals :: Telnet', - 'Topic :: Terminals :: Terminal Emulators/X Terminals', - 'Topic :: Text Editors', - 'Topic :: Text Editors :: Documentation', - 'Topic :: Text Editors :: Emacs', - 'Topic :: Text Editors :: Integrated Development Environments (IDE)', - 'Topic :: Text Editors :: Text Processing', - 'Topic :: Text Editors :: Word Processors', - 'Topic :: Text Processing', - 'Topic :: Text Processing :: Filters', - 'Topic :: Text Processing :: Fonts', - 'Topic :: Text Processing :: General', - 'Topic :: Text Processing :: Indexing', - 'Topic :: Text Processing :: Linguistic', - 'Topic :: Text Processing :: Markup', - 'Topic :: Text Processing :: Markup :: HTML', - 'Topic :: Text Processing :: Markup :: LaTeX', - 'Topic :: Text Processing :: Markup :: SGML', - 'Topic :: Text Processing :: Markup :: VRML', - 'Topic :: Text Processing :: Markup :: XML', - 'Topic :: Utilities', -] diff --git a/src/distutils2/command/__init__.py b/src/distutils2/command/__init__.py deleted file mode 100644 index 4ae17ae..0000000 --- a/src/distutils2/command/__init__.py +++ /dev/null @@ -1,28 +0,0 @@ -"""distutils.command - -Package containing implementation of all the standard Distutils -commands.""" - -__revision__ = "$Id: __init__.py 71473 2009-04-11 14:55:07Z tarek.ziade $" - -__all__ = ['check', - 'test', - 'build', - 'build_py', - 'build_ext', - 'build_clib', - 'build_scripts', - 'clean', - 'install', - 'install_lib', - 'install_headers', - 'install_scripts', - 'install_data', - 'install_distinfo', - 'sdist', - 'bdist', - 'bdist_dumb', - 'bdist_wininst', - 'register', - 'upload', - ] diff --git a/src/distutils2/command/bdist.py b/src/distutils2/command/bdist.py deleted file mode 100644 index 147a31e..0000000 --- a/src/distutils2/command/bdist.py +++ /dev/null @@ -1,140 +0,0 @@ -"""distutils.command.bdist - -Implements the Distutils 'bdist' command (create a built [binary] -distribution).""" - -__revision__ = "$Id: bdist.py 77761 2010-01-26 22:46:15Z tarek.ziade $" - -import os - -from distutils2.util import get_platform -from distutils2.core import Command -from distutils2.errors import DistutilsPlatformError, DistutilsOptionError - - -def show_formats(): - """Print list of available formats (arguments to "--format" option). - """ - from distutils2.fancy_getopt import FancyGetopt - formats = [] - for format in bdist.format_commands: - formats.append(("formats=" + format, None, - bdist.format_command[format][1])) - pretty_printer = FancyGetopt(formats) - pretty_printer.print_help("List of available distribution formats:") - - -class bdist(Command): - - description = "create a built (binary) distribution" - - user_options = [('bdist-base=', 'b', - "temporary directory for creating built distributions"), - ('plat-name=', 'p', - "platform name to embed in generated filenames " - "(default: %s)" % get_platform()), - ('formats=', None, - "formats for distribution (comma-separated list)"), - ('dist-dir=', 'd', - "directory to put final built distributions in " - "[default: dist]"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ('owner=', 'u', - "Owner name used when creating a tar file" - " [default: current user]"), - ('group=', 'g', - "Group name used when creating a tar file" - " [default: current group]"), - ] - - boolean_options = ['skip-build'] - - help_options = [ - ('help-formats', None, - "lists available distribution formats", show_formats), - ] - - # This won't do in reality: will need to distinguish RPM-ish Linux, - # Debian-ish Linux, Solaris, FreeBSD, ..., Windows, Mac OS. - default_format = {'posix': 'gztar', - 'nt': 'zip', - 'os2': 'zip'} - - # Establish the preferred order (for the --help-formats option). - format_commands = ['gztar', 'bztar', 'ztar', 'tar', - 'wininst', 'zip', 'msi'] - - # And the real information. - format_command = {'gztar': ('bdist_dumb', "gzip'ed tar file"), - 'bztar': ('bdist_dumb', "bzip2'ed tar file"), - 'ztar': ('bdist_dumb', "compressed tar file"), - 'tar': ('bdist_dumb', "tar file"), - 'wininst': ('bdist_wininst', - "Windows executable installer"), - 'zip': ('bdist_dumb', "ZIP file"), - 'msi': ('bdist_msi', "Microsoft Installer") - } - - - def initialize_options(self): - self.bdist_base = None - self.plat_name = None - self.formats = None - self.dist_dir = None - self.skip_build = 0 - self.group = None - self.owner = None - - def finalize_options(self): - # have to finalize 'plat_name' before 'bdist_base' - if self.plat_name is None: - if self.skip_build: - self.plat_name = get_platform() - else: - self.plat_name = self.get_finalized_command('build').plat_name - - # 'bdist_base' -- parent of per-built-distribution-format - # temporary directories (eg. we'll probably have - # "build/bdist.<plat>/dumb", etc.) - if self.bdist_base is None: - build_base = self.get_finalized_command('build').build_base - self.bdist_base = os.path.join(build_base, - 'bdist.' + self.plat_name) - - self.ensure_string_list('formats') - if self.formats is None: - try: - self.formats = [self.default_format[os.name]] - except KeyError: - raise DistutilsPlatformError, \ - "don't know how to create built distributions " + \ - "on platform %s" % os.name - - if self.dist_dir is None: - self.dist_dir = "dist" - - def run(self): - # Figure out which sub-commands we need to run. - commands = [] - for format in self.formats: - try: - commands.append(self.format_command[format][0]) - except KeyError: - raise DistutilsOptionError, "invalid format '%s'" % format - - # Reinitialize and run each command. - for i in range(len(self.formats)): - cmd_name = commands[i] - sub_cmd = self.get_reinitialized_command(cmd_name) - - # passing the owner and group names for tar archiving - if cmd_name == 'bdist_dumb': - sub_cmd.owner = self.owner - sub_cmd.group = self.group - - # If we're going to need to run this command again, tell it to - # keep its temporary files around so subsequent runs go faster. - if cmd_name in commands[i+1:]: - sub_cmd.keep_temp = 1 - self.run_command(cmd_name) diff --git a/src/distutils2/command/bdist_dumb.py b/src/distutils2/command/bdist_dumb.py deleted file mode 100644 index 4113a1e..0000000 --- a/src/distutils2/command/bdist_dumb.py +++ /dev/null @@ -1,142 +0,0 @@ -"""distutils.command.bdist_dumb - -Implements the Distutils 'bdist_dumb' command (create a "dumb" built -distribution -- i.e., just an archive to be unpacked under $prefix or -$exec_prefix).""" - -__revision__ = "$Id: bdist_dumb.py 77761 2010-01-26 22:46:15Z tarek.ziade $" - -import os -from shutil import rmtree -try: - from sysconfig import get_python_version -except ImportError: - from distutils2._backport.sysconfig import get_python_version -from distutils2.util import get_platform -from distutils2.core import Command -from distutils2.errors import DistutilsPlatformError -from distutils2 import log - -class bdist_dumb (Command): - - description = 'create a "dumb" built distribution' - - user_options = [('bdist-dir=', 'd', - "temporary directory for creating the distribution"), - ('plat-name=', 'p', - "platform name to embed in generated filenames " - "(default: %s)" % get_platform()), - ('format=', 'f', - "archive format to create (tar, ztar, gztar, zip)"), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ('relative', None, - "build the archive using relative paths" - "(default: false)"), - ('owner=', 'u', - "Owner name used when creating a tar file" - " [default: current user]"), - ('group=', 'g', - "Group name used when creating a tar file" - " [default: current group]"), - ] - - boolean_options = ['keep-temp', 'skip-build', 'relative'] - - default_format = { 'posix': 'gztar', - 'nt': 'zip', - 'os2': 'zip' } - - - def initialize_options (self): - self.bdist_dir = None - self.plat_name = None - self.format = None - self.keep_temp = 0 - self.dist_dir = None - self.skip_build = 0 - self.relative = 0 - self.owner = None - self.group = None - - def finalize_options(self): - if self.bdist_dir is None: - bdist_base = self.get_finalized_command('bdist').bdist_base - self.bdist_dir = os.path.join(bdist_base, 'dumb') - - if self.format is None: - try: - self.format = self.default_format[os.name] - except KeyError: - raise DistutilsPlatformError, \ - ("don't know how to create dumb built distributions " + - "on platform %s") % os.name - - self.set_undefined_options('bdist', 'dist_dir', 'plat_name') - - def run(self): - if not self.skip_build: - self.run_command('build') - - install = self.get_reinitialized_command('install', reinit_subcommands=1) - install.root = self.bdist_dir - install.skip_build = self.skip_build - install.warn_dir = 0 - - log.info("installing to %s" % self.bdist_dir) - self.run_command('install') - - # And make an archive relative to the root of the - # pseudo-installation tree. - archive_basename = "%s.%s" % (self.distribution.get_fullname(), - self.plat_name) - - # OS/2 objects to any ":" characters in a filename (such as when - # a timestamp is used in a version) so change them to hyphens. - if os.name == "os2": - archive_basename = archive_basename.replace(":", "-") - - pseudoinstall_root = os.path.join(self.dist_dir, archive_basename) - if not self.relative: - archive_root = self.bdist_dir - else: - if (self.distribution.has_ext_modules() and - (install.install_base != install.install_platbase)): - raise DistutilsPlatformError, \ - ("can't make a dumb built distribution where " - "base and platbase are different (%s, %s)" - % (repr(install.install_base), - repr(install.install_platbase))) - else: - archive_root = os.path.join( - self.bdist_dir, - self._ensure_relative(install.install_base)) - - # Make the archive - filename = self.make_archive(pseudoinstall_root, - self.format, root_dir=archive_root, - owner=self.owner, group=self.group) - if self.distribution.has_ext_modules(): - pyversion = get_python_version() - else: - pyversion = 'any' - self.distribution.dist_files.append(('bdist_dumb', pyversion, - filename)) - - if not self.keep_temp: - if self.dry_run: - log.info('Removing %s' % self.bdist_dir) - else: - rmtree(self.bdist_dir) - - def _ensure_relative(self, path): - # copied from dir_util, deleted - drive, path = os.path.splitdrive(path) - if path[0:1] == os.sep: - path = drive + path[1:] - return path diff --git a/src/distutils2/command/bdist_msi.py b/src/distutils2/command/bdist_msi.py deleted file mode 100644 index 61968ad..0000000 --- a/src/distutils2/command/bdist_msi.py +++ /dev/null @@ -1,735 +0,0 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2005, 2006 Martin von Löwis -# Licensed to PSF under a Contributor Agreement. -# The bdist_wininst command proper -# based on bdist_wininst -""" -Implements the bdist_msi command. -""" -import sys, os -from sysconfig import get_python_version - -from distutils2.core import Command -from distutils2.dir_util import remove_tree -from distutils2.version import StrictVersion -from distutils2.errors import DistutilsOptionError -from distutils2 import log -from distutils2.util import get_platform - -import msilib -from msilib import schema, sequence, text -from msilib import Directory, Feature, Dialog, add_data - -class PyDialog(Dialog): - """Dialog class with a fixed layout: controls at the top, then a ruler, - then a list of buttons: back, next, cancel. Optionally a bitmap at the - left.""" - def __init__(self, *args, **kw): - """Dialog(database, name, x, y, w, h, attributes, title, first, - default, cancel, bitmap=true)""" - Dialog.__init__(self, *args) - ruler = self.h - 36 - #if kw.get("bitmap", True): - # self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin") - self.line("BottomLine", 0, ruler, self.w, 0) - - def title(self, title): - "Set the title text of the dialog at the top." - # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix, - # text, in VerdanaBold10 - self.text("Title", 15, 10, 320, 60, 0x30003, - r"{\VerdanaBold10}%s" % title) - - def back(self, title, next, name = "Back", active = 1): - """Add a back button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next) - - def cancel(self, title, next, name = "Cancel", active = 1): - """Add a cancel button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next) - - def next(self, title, next, name = "Next", active = 1): - """Add a Next button with a given title, the tab-next button, - its name in the Control table, possibly initially disabled. - - Return the button, so that events can be associated""" - if active: - flags = 3 # Visible|Enabled - else: - flags = 1 # Visible - return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next) - - def xbutton(self, name, title, next, xpos): - """Add a button with a given title, the tab-next button, - its name in the Control table, giving its x position; the - y-position is aligned with the other buttons. - - Return the button, so that events can be associated""" - return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next) - -class bdist_msi (Command): - - description = "create a Microsoft Installer (.msi) binary distribution" - - user_options = [('bdist-dir=', None, - "temporary directory for creating the distribution"), - ('plat-name=', 'p', - "platform name to embed in generated filenames " - "(default: %s)" % get_platform()), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('target-version=', None, - "require a specific python version" + - " on the target system"), - ('no-target-compile', 'c', - "do not compile .py to .pyc on the target system"), - ('no-target-optimize', 'o', - "do not compile .py to .pyo (optimized)" - "on the target system"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ('install-script=', None, - "basename of installation script to be run after" - "installation or before deinstallation"), - ('pre-install-script=', None, - "Fully qualified filename of a script to be run before " - "any files are installed. This script need not be in the " - "distribution"), - ] - - boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', - 'skip-build'] - - all_versions = ['2.0', '2.1', '2.2', '2.3', '2.4', - '2.5', '2.6', '2.7', '2.8', '2.9', - '3.0', '3.1', '3.2', '3.3', '3.4', - '3.5', '3.6', '3.7', '3.8', '3.9'] - other_version = 'X' - - def initialize_options (self): - self.bdist_dir = None - self.plat_name = None - self.keep_temp = 0 - self.no_target_compile = 0 - self.no_target_optimize = 0 - self.target_version = None - self.dist_dir = None - self.skip_build = 0 - self.install_script = None - self.pre_install_script = None - self.versions = None - - def finalize_options (self): - if self.bdist_dir is None: - bdist_base = self.get_finalized_command('bdist').bdist_base - self.bdist_dir = os.path.join(bdist_base, 'msi') - short_version = get_python_version() - if (not self.target_version) and self.distribution.has_ext_modules(): - self.target_version = short_version - if self.target_version: - self.versions = [self.target_version] - if not self.skip_build and self.distribution.has_ext_modules()\ - and self.target_version != short_version: - raise DistutilsOptionError, \ - "target version can only be %s, or the '--skip-build'" \ - " option must be specified" % (short_version,) - else: - self.versions = list(self.all_versions) - - self.set_undefined_options('bdist', 'dist_dir', 'plat_name') - - if self.pre_install_script: - raise DistutilsOptionError, "the pre-install-script feature is not yet implemented" - - if self.install_script: - for script in self.distribution.scripts: - if self.install_script == os.path.basename(script): - break - else: - raise DistutilsOptionError, \ - "install_script '%s' not found in scripts" % \ - self.install_script - self.install_script_key = None - # finalize_options() - - - def run (self): - if not self.skip_build: - self.run_command('build') - - install = self.get_reinitialized_command('install', reinit_subcommands=1) - install.prefix = self.bdist_dir - install.skip_build = self.skip_build - install.warn_dir = 0 - - install_lib = self.get_reinitialized_command('install_lib') - # we do not want to include pyc or pyo files - install_lib.compile = 0 - install_lib.optimize = 0 - - if self.distribution.has_ext_modules(): - # If we are building an installer for a Python version other - # than the one we are currently running, then we need to ensure - # our build_lib reflects the other Python version rather than ours. - # Note that for target_version!=sys.version, we must have skipped the - # build step, so there is no issue with enforcing the build of this - # version. - target_version = self.target_version - if not target_version: - assert self.skip_build, "Should have already checked this" - target_version = sys.version[0:3] - plat_specifier = ".%s-%s" % (self.plat_name, target_version) - build = self.get_finalized_command('build') - build.build_lib = os.path.join(build.build_base, - 'lib' + plat_specifier) - - log.info("installing to %s", self.bdist_dir) - install.ensure_finalized() - - # avoid warning of 'install_lib' about installing - # into a directory not in sys.path - sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) - - install.run() - - del sys.path[0] - - self.mkpath(self.dist_dir) - fullname = self.distribution.get_fullname() - installer_name = self.get_installer_filename(fullname) - installer_name = os.path.abspath(installer_name) - if os.path.exists(installer_name): os.unlink(installer_name) - - metadata = self.distribution.metadata - author = metadata.author - if not author: - author = metadata.maintainer - if not author: - author = "UNKNOWN" - version = metadata.get_version() - # ProductVersion must be strictly numeric - # XXX need to deal with prerelease versions - sversion = "%d.%d.%d" % StrictVersion(version).version - # Prefix ProductName with Python x.y, so that - # it sorts together with the other Python packages - # in Add-Remove-Programs (APR) - fullname = self.distribution.get_fullname() - if self.target_version: - product_name = "Python %s %s" % (self.target_version, fullname) - else: - product_name = "Python %s" % (fullname) - self.db = msilib.init_database(installer_name, schema, - product_name, msilib.gen_uuid(), - sversion, author) - msilib.add_tables(self.db, sequence) - props = [('DistVersion', version)] - email = metadata.author_email or metadata.maintainer_email - if email: - props.append(("ARPCONTACT", email)) - if metadata.url: - props.append(("ARPURLINFOABOUT", metadata.url)) - if props: - add_data(self.db, 'Property', props) - - self.add_find_python() - self.add_files() - self.add_scripts() - self.add_ui() - self.db.Commit() - - if hasattr(self.distribution, 'dist_files'): - tup = 'bdist_msi', self.target_version or 'any', fullname - self.distribution.dist_files.append(tup) - - if not self.keep_temp: - remove_tree(self.bdist_dir, dry_run=self.dry_run) - - def add_files(self): - db = self.db - cab = msilib.CAB("distfiles") - rootdir = os.path.abspath(self.bdist_dir) - - root = Directory(db, cab, None, rootdir, "TARGETDIR", "SourceDir") - f = Feature(db, "Python", "Python", "Everything", - 0, 1, directory="TARGETDIR") - - items = [(f, root, '')] - for version in self.versions + [self.other_version]: - target = "TARGETDIR" + version - name = default = "Python" + version - desc = "Everything" - if version is self.other_version: - title = "Python from another location" - level = 2 - else: - title = "Python %s from registry" % version - level = 1 - f = Feature(db, name, title, desc, 1, level, directory=target) - dir = Directory(db, cab, root, rootdir, target, default) - items.append((f, dir, version)) - db.Commit() - - seen = {} - for feature, dir, version in items: - todo = [dir] - while todo: - dir = todo.pop() - for file in os.listdir(dir.absolute): - afile = os.path.join(dir.absolute, file) - if os.path.isdir(afile): - short = "%s|%s" % (dir.make_short(file), file) - default = file + version - newdir = Directory(db, cab, dir, file, default, short) - todo.append(newdir) - else: - if not dir.component: - dir.start_component(dir.logical, feature, 0) - if afile not in seen: - key = seen[afile] = dir.add_file(file) - if file==self.install_script: - if self.install_script_key: - raise DistutilsOptionError( - "Multiple files with name %s" % file) - self.install_script_key = '[#%s]' % key - else: - key = seen[afile] - add_data(self.db, "DuplicateFile", - [(key + version, dir.component, key, None, dir.logical)]) - db.Commit() - cab.commit(db) - - def add_find_python(self): - """Adds code to the installer to compute the location of Python. - - Properties PYTHON.MACHINE.X.Y and PYTHON.USER.X.Y will be set from the - registry for each version of Python. - - Properties TARGETDIRX.Y will be set from PYTHON.USER.X.Y if defined, - else from PYTHON.MACHINE.X.Y. - - Properties PYTHONX.Y will be set to TARGETDIRX.Y\\python.exe""" - - start = 402 - for ver in self.versions: - install_path = r"SOFTWARE\Python\PythonCore\%s\InstallPath" % ver - machine_reg = "python.machine." + ver - user_reg = "python.user." + ver - machine_prop = "PYTHON.MACHINE." + ver - user_prop = "PYTHON.USER." + ver - machine_action = "PythonFromMachine" + ver - user_action = "PythonFromUser" + ver - exe_action = "PythonExe" + ver - target_dir_prop = "TARGETDIR" + ver - exe_prop = "PYTHON" + ver - if msilib.Win64: - # type: msidbLocatorTypeRawValue + msidbLocatorType64bit - Type = 2+16 - else: - Type = 2 - add_data(self.db, "RegLocator", - [(machine_reg, 2, install_path, None, Type), - (user_reg, 1, install_path, None, Type)]) - add_data(self.db, "AppSearch", - [(machine_prop, machine_reg), - (user_prop, user_reg)]) - add_data(self.db, "CustomAction", - [(machine_action, 51+256, target_dir_prop, "[" + machine_prop + "]"), - (user_action, 51+256, target_dir_prop, "[" + user_prop + "]"), - (exe_action, 51+256, exe_prop, "[" + target_dir_prop + "]\\python.exe"), - ]) - add_data(self.db, "InstallExecuteSequence", - [(machine_action, machine_prop, start), - (user_action, user_prop, start + 1), - (exe_action, None, start + 2), - ]) - add_data(self.db, "InstallUISequence", - [(machine_action, machine_prop, start), - (user_action, user_prop, start + 1), - (exe_action, None, start + 2), - ]) - add_data(self.db, "Condition", - [("Python" + ver, 0, "NOT TARGETDIR" + ver)]) - start += 4 - assert start < 500 - - def add_scripts(self): - if self.install_script: - start = 6800 - for ver in self.versions + [self.other_version]: - install_action = "install_script." + ver - exe_prop = "PYTHON" + ver - add_data(self.db, "CustomAction", - [(install_action, 50, exe_prop, self.install_script_key)]) - add_data(self.db, "InstallExecuteSequence", - [(install_action, "&Python%s=3" % ver, start)]) - start += 1 - # XXX pre-install scripts are currently refused in finalize_options() - # but if this feature is completed, it will also need to add - # entries for each version as the above code does - if self.pre_install_script: - scriptfn = os.path.join(self.bdist_dir, "preinstall.bat") - f = open(scriptfn, "w") - # The batch file will be executed with [PYTHON], so that %1 - # is the path to the Python interpreter; %0 will be the path - # of the batch file. - # rem =""" - # %1 %0 - # exit - # """ - # <actual script> - f.write('rem ="""\n%1 %0\nexit\n"""\n') - f.write(open(self.pre_install_script).read()) - f.close() - add_data(self.db, "Binary", - [("PreInstall", msilib.Binary(scriptfn)) - ]) - add_data(self.db, "CustomAction", - [("PreInstall", 2, "PreInstall", None) - ]) - add_data(self.db, "InstallExecuteSequence", - [("PreInstall", "NOT Installed", 450)]) - - - def add_ui(self): - db = self.db - x = y = 50 - w = 370 - h = 300 - title = "[ProductName] Setup" - - # see "Dialog Style Bits" - modal = 3 # visible | modal - modeless = 1 # visible - - # UI customization properties - add_data(db, "Property", - # See "DefaultUIFont Property" - [("DefaultUIFont", "DlgFont8"), - # See "ErrorDialog Style Bit" - ("ErrorDialog", "ErrorDlg"), - ("Progress1", "Install"), # modified in maintenance type dlg - ("Progress2", "installs"), - ("MaintenanceForm_Action", "Repair"), - # possible values: ALL, JUSTME - ("WhichUsers", "ALL") - ]) - - # Fonts, see "TextStyle Table" - add_data(db, "TextStyle", - [("DlgFont8", "Tahoma", 9, None, 0), - ("DlgFontBold8", "Tahoma", 8, None, 1), #bold - ("VerdanaBold10", "Verdana", 10, None, 1), - ("VerdanaRed9", "Verdana", 9, 255, 0), - ]) - - # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" - # Numbers indicate sequence; see sequence.py for how these action integrate - add_data(db, "InstallUISequence", - [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), - ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141), - # In the user interface, assume all-users installation if privileged. - ("SelectFeaturesDlg", "Not Installed", 1230), - # XXX no support for resume installations yet - #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), - ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250), - ("ProgressDlg", None, 1280)]) - - add_data(db, 'ActionText', text.ActionText) - add_data(db, 'UIText', text.UIText) - ##################################################################### - # Standard dialogs: FatalError, UserExit, ExitDialog - fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - fatal.title("[ProductName] Installer ended prematurely") - fatal.back("< Back", "Finish", active = 0) - fatal.cancel("Cancel", "Back", active = 0) - fatal.text("Description1", 15, 70, 320, 80, 0x30003, - "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.") - fatal.text("Description2", 15, 155, 320, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c=fatal.next("Finish", "Cancel", name="Finish") - c.event("EndDialog", "Exit") - - user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - user_exit.title("[ProductName] Installer was interrupted") - user_exit.back("< Back", "Finish", active = 0) - user_exit.cancel("Cancel", "Back", active = 0) - user_exit.text("Description1", 15, 70, 320, 80, 0x30003, - "[ProductName] setup was interrupted. Your system has not been modified. " - "To install this program at a later time, please run the installation again.") - user_exit.text("Description2", 15, 155, 320, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c = user_exit.next("Finish", "Cancel", name="Finish") - c.event("EndDialog", "Exit") - - exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title, - "Finish", "Finish", "Finish") - exit_dialog.title("Completing the [ProductName] Installer") - exit_dialog.back("< Back", "Finish", active = 0) - exit_dialog.cancel("Cancel", "Back", active = 0) - exit_dialog.text("Description", 15, 235, 320, 20, 0x30003, - "Click the Finish button to exit the Installer.") - c = exit_dialog.next("Finish", "Cancel", name="Finish") - c.event("EndDialog", "Return") - - ##################################################################### - # Required dialog: FilesInUse, ErrorDlg - inuse = PyDialog(db, "FilesInUse", - x, y, w, h, - 19, # KeepModeless|Modal|Visible - title, - "Retry", "Retry", "Retry", bitmap=False) - inuse.text("Title", 15, 6, 200, 15, 0x30003, - r"{\DlgFontBold8}Files in Use") - inuse.text("Description", 20, 23, 280, 20, 0x30003, - "Some files that need to be updated are currently in use.") - inuse.text("Text", 20, 55, 330, 50, 3, - "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.") - inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess", - None, None, None) - c=inuse.back("Exit", "Ignore", name="Exit") - c.event("EndDialog", "Exit") - c=inuse.next("Ignore", "Retry", name="Ignore") - c.event("EndDialog", "Ignore") - c=inuse.cancel("Retry", "Exit", name="Retry") - c.event("EndDialog","Retry") - - # See "Error Dialog". See "ICE20" for the required names of the controls. - error = Dialog(db, "ErrorDlg", - 50, 10, 330, 101, - 65543, # Error|Minimize|Modal|Visible - title, - "ErrorText", None, None) - error.text("ErrorText", 50,9,280,48,3, "") - #error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) - error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo") - error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes") - error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort") - error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel") - error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore") - error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk") - error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry") - - ##################################################################### - # Global "Query Cancel" dialog - cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, - "No", "No", "No") - cancel.text("Text", 48, 15, 194, 30, 3, - "Are you sure you want to cancel [ProductName] installation?") - #cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, - # "py.ico", None, None) - c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") - c.event("EndDialog", "Exit") - - c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") - c.event("EndDialog", "Return") - - ##################################################################### - # Global "Wait for costing" dialog - costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title, - "Return", "Return", "Return") - costing.text("Text", 48, 15, 194, 30, 3, - "Please wait while the installer finishes determining your disk space requirements.") - c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None) - c.event("EndDialog", "Exit") - - ##################################################################### - # Preparation dialog: no user input except cancellation - prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title, - "Cancel", "Cancel", "Cancel") - prep.text("Description", 15, 70, 320, 40, 0x30003, - "Please wait while the Installer prepares to guide you through the installation.") - prep.title("Welcome to the [ProductName] Installer") - c=prep.text("ActionText", 15, 110, 320, 20, 0x30003, "Pondering...") - c.mapping("ActionText", "Text") - c=prep.text("ActionData", 15, 135, 320, 30, 0x30003, None) - c.mapping("ActionData", "Text") - prep.back("Back", None, active=0) - prep.next("Next", None, active=0) - c=prep.cancel("Cancel", None) - c.event("SpawnDialog", "CancelDlg") - - ##################################################################### - # Feature (Python directory) selection - seldlg = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal, title, - "Next", "Next", "Cancel") - seldlg.title("Select Python Installations") - - seldlg.text("Hint", 15, 30, 300, 20, 3, - "Select the Python locations where %s should be installed." - % self.distribution.get_fullname()) - - seldlg.back("< Back", None, active=0) - c = seldlg.next("Next >", "Cancel") - order = 1 - c.event("[TARGETDIR]", "[SourceDir]", ordering=order) - for version in self.versions + [self.other_version]: - order += 1 - c.event("[TARGETDIR]", "[TARGETDIR%s]" % version, - "FEATURE_SELECTED AND &Python%s=3" % version, - ordering=order) - c.event("SpawnWaitDialog", "WaitForCostingDlg", ordering=order + 1) - c.event("EndDialog", "Return", ordering=order + 2) - c = seldlg.cancel("Cancel", "Features") - c.event("SpawnDialog", "CancelDlg") - - c = seldlg.control("Features", "SelectionTree", 15, 60, 300, 120, 3, - "FEATURE", None, "PathEdit", None) - c.event("[FEATURE_SELECTED]", "1") - ver = self.other_version - install_other_cond = "FEATURE_SELECTED AND &Python%s=3" % ver - dont_install_other_cond = "FEATURE_SELECTED AND &Python%s<>3" % ver - - c = seldlg.text("Other", 15, 200, 300, 15, 3, - "Provide an alternate Python location") - c.condition("Enable", install_other_cond) - c.condition("Show", install_other_cond) - c.condition("Disable", dont_install_other_cond) - c.condition("Hide", dont_install_other_cond) - - c = seldlg.control("PathEdit", "PathEdit", 15, 215, 300, 16, 1, - "TARGETDIR" + ver, None, "Next", None) - c.condition("Enable", install_other_cond) - c.condition("Show", install_other_cond) - c.condition("Disable", dont_install_other_cond) - c.condition("Hide", dont_install_other_cond) - - ##################################################################### - # Disk cost - cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, - "OK", "OK", "OK", bitmap=False) - cost.text("Title", 15, 6, 200, 15, 0x30003, - "{\DlgFontBold8}Disk Space Requirements") - cost.text("Description", 20, 20, 280, 20, 0x30003, - "The disk space required for the installation of the selected features.") - cost.text("Text", 20, 53, 330, 60, 3, - "The highlighted volumes (if any) do not have enough disk space " - "available for the currently selected features. You can either " - "remove some files from the highlighted volumes, or choose to " - "install less features onto local drive(s), or select different " - "destination drive(s).") - cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223, - None, "{120}{70}{70}{70}{70}", None, None) - cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return") - - ##################################################################### - # WhichUsers Dialog. Only available on NT, and for privileged users. - # This must be run before FindRelatedProducts, because that will - # take into account whether the previous installation was per-user - # or per-machine. We currently don't support going back to this - # dialog after "Next" was selected; to support this, we would need to - # find how to reset the ALLUSERS property, and how to re-run - # FindRelatedProducts. - # On Windows9x, the ALLUSERS property is ignored on the command line - # and in the Property table, but installer fails according to the documentation - # if a dialog attempts to set ALLUSERS. - whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title, - "AdminInstall", "Next", "Cancel") - whichusers.title("Select whether to install [ProductName] for all users of this computer.") - # A radio group with two options: allusers, justme - g = whichusers.radiogroup("AdminInstall", 15, 60, 260, 50, 3, - "WhichUsers", "", "Next") - g.add("ALL", 0, 5, 150, 20, "Install for all users") - g.add("JUSTME", 0, 25, 150, 20, "Install just for me") - - whichusers.back("Back", None, active=0) - - c = whichusers.next("Next >", "Cancel") - c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1) - c.event("EndDialog", "Return", ordering = 2) - - c = whichusers.cancel("Cancel", "AdminInstall") - c.event("SpawnDialog", "CancelDlg") - - ##################################################################### - # Installation Progress dialog (modeless) - progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, - "Cancel", "Cancel", "Cancel", bitmap=False) - progress.text("Title", 20, 15, 200, 15, 0x30003, - "{\DlgFontBold8}[Progress1] [ProductName]") - progress.text("Text", 35, 65, 300, 30, 3, - "Please wait while the Installer [Progress2] [ProductName]. " - "This may take several minutes.") - progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:") - - c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...") - c.mapping("ActionText", "Text") - - #c=progress.text("ActionData", 35, 140, 300, 20, 3, None) - #c.mapping("ActionData", "Text") - - c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537, - None, "Progress done", None, None) - c.mapping("SetProgress", "Progress") - - progress.back("< Back", "Next", active=False) - progress.next("Next >", "Cancel", active=False) - progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg") - - ################################################################### - # Maintenance type: repair/uninstall - maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title, - "Next", "Next", "Cancel") - maint.title("Welcome to the [ProductName] Setup Wizard") - maint.text("BodyText", 15, 63, 330, 42, 3, - "Select whether you want to repair or remove [ProductName].") - g=maint.radiogroup("RepairRadioGroup", 15, 108, 330, 60, 3, - "MaintenanceForm_Action", "", "Next") - #g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") - g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]") - g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]") - - maint.back("< Back", None, active=False) - c=maint.next("Finish", "Cancel") - # Change installation: Change progress dialog to "Change", then ask - # for feature selection - #c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) - #c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) - - # Reinstall: Change progress dialog to "Repair", then invoke reinstall - # Also set list of reinstalled features to "ALL" - c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5) - c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6) - c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7) - c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8) - - # Uninstall: Change progress to "Remove", then invoke uninstall - # Also set list of removed features to "ALL" - c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11) - c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12) - c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13) - c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14) - - # Close dialog when maintenance action scheduled - c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20) - #c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) - - maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg") - - def get_installer_filename(self, fullname): - # Factored out to allow overriding in subclasses - if self.target_version: - base_name = "%s.%s-py%s.msi" % (fullname, self.plat_name, - self.target_version) - else: - base_name = "%s.%s.msi" % (fullname, self.plat_name) - installer_name = os.path.join(self.dist_dir, base_name) - return installer_name diff --git a/src/distutils2/command/bdist_wininst.py b/src/distutils2/command/bdist_wininst.py deleted file mode 100644 index 562c4ed..0000000 --- a/src/distutils2/command/bdist_wininst.py +++ /dev/null @@ -1,359 +0,0 @@ -"""distutils.command.bdist_wininst - -Implements the Distutils 'bdist_wininst' command: create a windows installer -exe-program.""" - -__revision__ = "$Id: bdist_wininst.py 77761 2010-01-26 22:46:15Z tarek.ziade $" - -import sys -import os -import string -from shutil import rmtree -try: - from sysconfig import get_python_version -except ImportError: - from distutils2._backport.sysconfig import get_python_version -from distutils2.core import Command -from distutils2.errors import DistutilsOptionError, DistutilsPlatformError -from distutils2 import log -from distutils2.util import get_platform - -class bdist_wininst (Command): - - description = "create an executable installer for MS Windows" - - user_options = [('bdist-dir=', None, - "temporary directory for creating the distribution"), - ('plat-name=', 'p', - "platform name to embed in generated filenames " - "(default: %s)" % get_platform()), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('target-version=', None, - "require a specific python version" + - " on the target system"), - ('no-target-compile', 'c', - "do not compile .py to .pyc on the target system"), - ('no-target-optimize', 'o', - "do not compile .py to .pyo (optimized)" - "on the target system"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('bitmap=', 'b', - "bitmap to use for the installer instead of python-powered logo"), - ('title=', 't', - "title to display on the installer background instead of default"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ('install-script=', None, - "basename of installation script to be run after" - "installation or before deinstallation"), - ('pre-install-script=', None, - "Fully qualified filename of a script to be run before " - "any files are installed. This script need not be in the " - "distribution"), - ('user-access-control=', None, - "specify Vista's UAC handling - 'none'/default=no " - "handling, 'auto'=use UAC if target Python installed for " - "all users, 'force'=always use UAC"), - ] - - boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', - 'skip-build'] - - def initialize_options (self): - self.bdist_dir = None - self.plat_name = None - self.keep_temp = 0 - self.no_target_compile = 0 - self.no_target_optimize = 0 - self.target_version = None - self.dist_dir = None - self.bitmap = None - self.title = None - self.skip_build = 0 - self.install_script = None - self.pre_install_script = None - self.user_access_control = None - - # initialize_options() - - - def finalize_options (self): - if self.bdist_dir is None: - if self.skip_build and self.plat_name: - # If build is skipped and plat_name is overridden, bdist will - # not see the correct 'plat_name' - so set that up manually. - bdist = self.distribution.get_command_obj('bdist') - bdist.plat_name = self.plat_name - # next the command will be initialized using that name - bdist_base = self.get_finalized_command('bdist').bdist_base - self.bdist_dir = os.path.join(bdist_base, 'wininst') - if not self.target_version: - self.target_version = "" - if not self.skip_build and self.distribution.has_ext_modules(): - short_version = get_python_version() - if self.target_version and self.target_version != short_version: - raise DistutilsOptionError, \ - "target version can only be %s, or the '--skip-build'" \ - " option must be specified" % (short_version,) - self.target_version = short_version - - self.set_undefined_options('bdist', 'dist_dir', 'plat_name') - - if self.install_script: - for script in self.distribution.scripts: - if self.install_script == os.path.basename(script): - break - else: - raise DistutilsOptionError, \ - "install_script '%s' not found in scripts" % \ - self.install_script - # finalize_options() - - - def run (self): - if (sys.platform != "win32" and - (self.distribution.has_ext_modules() or - self.distribution.has_c_libraries())): - raise DistutilsPlatformError \ - ("distribution contains extensions and/or C libraries; " - "must be compiled on a Windows 32 platform") - - if not self.skip_build: - self.run_command('build') - - install = self.get_reinitialized_command('install', reinit_subcommands=1) - install.root = self.bdist_dir - install.skip_build = self.skip_build - install.warn_dir = 0 - install.plat_name = self.plat_name - - install_lib = self.get_reinitialized_command('install_lib') - # we do not want to include pyc or pyo files - install_lib.compile = 0 - install_lib.optimize = 0 - - if self.distribution.has_ext_modules(): - # If we are building an installer for a Python version other - # than the one we are currently running, then we need to ensure - # our build_lib reflects the other Python version rather than ours. - # Note that for target_version!=sys.version, we must have skipped the - # build step, so there is no issue with enforcing the build of this - # version. - target_version = self.target_version - if not target_version: - assert self.skip_build, "Should have already checked this" - target_version = sys.version[0:3] - plat_specifier = ".%s-%s" % (self.plat_name, target_version) - build = self.get_finalized_command('build') - build.build_lib = os.path.join(build.build_base, - 'lib' + plat_specifier) - - # Use a custom scheme for the zip-file, because we have to decide - # at installation time which scheme to use. - for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'): - value = string.upper(key) - if key == 'headers': - value = value + '/Include/$dist_name' - setattr(install, - 'install_' + key, - value) - - log.info("installing to %s", self.bdist_dir) - install.ensure_finalized() - - # avoid warning of 'install_lib' about installing - # into a directory not in sys.path - sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB')) - - install.run() - - del sys.path[0] - - # And make an archive relative to the root of the - # pseudo-installation tree. - from tempfile import NamedTemporaryFile - archive_basename = NamedTemporaryFile().name - fullname = self.distribution.get_fullname() - arcname = self.make_archive(archive_basename, "zip", - root_dir=self.bdist_dir) - # create an exe containing the zip-file - self.create_exe(arcname, fullname, self.bitmap) - if self.distribution.has_ext_modules(): - pyversion = get_python_version() - else: - pyversion = 'any' - self.distribution.dist_files.append(('bdist_wininst', pyversion, - self.get_installer_filename(fullname))) - # remove the zip-file again - log.debug("removing temporary file '%s'", arcname) - os.remove(arcname) - - if not self.keep_temp: - if self.dry_run: - log.info('Removing %s' % self.bdist_dir) - else: - rmtree(self.bdist_dir) - - def get_inidata (self): - # Return data describing the installation. - - lines = [] - metadata = self.distribution.metadata - - # Write the [metadata] section. - lines.append("[metadata]") - - # 'info' will be displayed in the installer's dialog box, - # describing the items to be installed. - info = (metadata.long_description or '') + '\n' - - # Escape newline characters - def escape(s): - return string.replace(s, "\n", "\\n") - - for name in ["author", "author_email", "description", "maintainer", - "maintainer_email", "name", "url", "version"]: - data = getattr(metadata, name, "") - if data: - info = info + ("\n %s: %s" % \ - (string.capitalize(name), escape(data))) - lines.append("%s=%s" % (name, escape(data))) - - # The [setup] section contains entries controlling - # the installer runtime. - lines.append("\n[Setup]") - if self.install_script: - lines.append("install_script=%s" % self.install_script) - lines.append("info=%s" % escape(info)) - lines.append("target_compile=%d" % (not self.no_target_compile)) - lines.append("target_optimize=%d" % (not self.no_target_optimize)) - if self.target_version: - lines.append("target_version=%s" % self.target_version) - if self.user_access_control: - lines.append("user_access_control=%s" % self.user_access_control) - - title = self.title or self.distribution.get_fullname() - lines.append("title=%s" % escape(title)) - import time - import distutils2 - build_info = "Built %s with distutils2-%s" % \ - (time.ctime(time.time()), distutils2.__version__) - lines.append("build_info=%s" % build_info) - return string.join(lines, "\n") - - # get_inidata() - - def create_exe (self, arcname, fullname, bitmap=None): - import struct - - self.mkpath(self.dist_dir) - - cfgdata = self.get_inidata() - - installer_name = self.get_installer_filename(fullname) - self.announce("creating %s" % installer_name) - - if bitmap: - bitmapdata = open(bitmap, "rb").read() - bitmaplen = len(bitmapdata) - else: - bitmaplen = 0 - - file = open(installer_name, "wb") - file.write(self.get_exe_bytes()) - if bitmap: - file.write(bitmapdata) - - # Convert cfgdata from unicode to ascii, mbcs encoded - try: - unicode - except NameError: - pass - else: - if isinstance(cfgdata, unicode): - cfgdata = cfgdata.encode("mbcs") - - # Append the pre-install script - cfgdata = cfgdata + "\0" - if self.pre_install_script: - script_data = open(self.pre_install_script, "r").read() - cfgdata = cfgdata + script_data + "\n\0" - else: - # empty pre-install script - cfgdata = cfgdata + "\0" - file.write(cfgdata) - - # The 'magic number' 0x1234567B is used to make sure that the - # binary layout of 'cfgdata' is what the wininst.exe binary - # expects. If the layout changes, increment that number, make - # the corresponding changes to the wininst.exe sources, and - # recompile them. - header = struct.pack("<iii", - 0x1234567B, # tag - len(cfgdata), # length - bitmaplen, # number of bytes in bitmap - ) - file.write(header) - file.write(open(arcname, "rb").read()) - - # create_exe() - - def get_installer_filename(self, fullname): - # Factored out to allow overriding in subclasses - if self.target_version: - # if we create an installer for a specific python version, - # it's better to include this in the name - installer_name = os.path.join(self.dist_dir, - "%s.%s-py%s.exe" % - (fullname, self.plat_name, self.target_version)) - else: - installer_name = os.path.join(self.dist_dir, - "%s.%s.exe" % (fullname, self.plat_name)) - return installer_name - # get_installer_filename() - - def get_exe_bytes (self): - from distutils2.compiler.msvccompiler import get_build_version - # If a target-version other than the current version has been - # specified, then using the MSVC version from *this* build is no good. - # Without actually finding and executing the target version and parsing - # its sys.version, we just hard-code our knowledge of old versions. - # NOTE: Possible alternative is to allow "--target-version" to - # specify a Python executable rather than a simple version string. - # We can then execute this program to obtain any info we need, such - # as the real sys.version string for the build. - cur_version = get_python_version() - if self.target_version and self.target_version != cur_version: - # If the target version is *later* than us, then we assume they - # use what we use - # string compares seem wrong, but are what sysconfig.py itself uses - if self.target_version > cur_version: - bv = get_build_version() - else: - if self.target_version < "2.4": - bv = 6.0 - else: - bv = 7.1 - else: - # for current version - use authoritative check. - bv = get_build_version() - - # wininst-x.y.exe is in the same directory as this file - directory = os.path.dirname(__file__) - # we must use a wininst-x.y.exe built with the same C compiler - # used for python. XXX What about mingw, borland, and so on? - - # if plat_name starts with "win" but is not "win32" - # we want to strip "win" and leave the rest (e.g. -amd64) - # for all other cases, we don't want any suffix - if self.plat_name != 'win32' and self.plat_name[:3] == 'win': - sfix = self.plat_name[3:] - else: - sfix = '' - - filename = os.path.join(directory, "wininst-%.1f%s.exe" % (bv, sfix)) - return open(filename, "rb").read() -# class bdist_wininst diff --git a/src/distutils2/command/build.py b/src/distutils2/command/build.py deleted file mode 100644 index 3f7aad7..0000000 --- a/src/distutils2/command/build.py +++ /dev/null @@ -1,156 +0,0 @@ -"""distutils.command.build - -Implements the Distutils 'build' command.""" - -__revision__ = "$Id: build.py 77761 2010-01-26 22:46:15Z tarek.ziade $" - -import sys, os - -from distutils2.util import get_platform -from distutils2.core import Command -from distutils2.errors import DistutilsOptionError - -def show_compilers(): - from distutils2.compiler.ccompiler import show_compilers - show_compilers() - -class build(Command): - - description = "build everything needed to install" - - user_options = [ - ('build-base=', 'b', - "base directory for build library"), - ('build-purelib=', None, - "build directory for platform-neutral distributions"), - ('build-platlib=', None, - "build directory for platform-specific distributions"), - ('build-lib=', None, - "build directory for all distribution (defaults to either " + - "build-purelib or build-platlib"), - ('build-scripts=', None, - "build directory for scripts"), - ('build-temp=', 't', - "temporary build directory"), - ('plat-name=', 'p', - "platform name to build for, if supported " - "(default: %s)" % get_platform()), - ('compiler=', 'c', - "specify the compiler type"), - ('debug', 'g', - "compile extensions and libraries with debugging information"), - ('force', 'f', - "forcibly build everything (ignore file timestamps)"), - ('executable=', 'e', - "specify final destination interpreter path (build.py)"), - ('use-2to3', None, - "use 2to3 to make source python 3.x compatible"), - ('convert-2to3-doctests', None, - "use 2to3 to convert doctests in seperate text files"), - ('use-2to3-fixers', None, - "list additional fixers opted for during 2to3 conversion"), - ] - - boolean_options = ['debug', 'force'] - - help_options = [ - ('help-compiler', None, - "list available compilers", show_compilers), - ] - - def initialize_options(self): - self.build_base = 'build' - # these are decided only after 'build_base' has its final value - # (unless overridden by the user or client) - self.build_purelib = None - self.build_platlib = None - self.build_lib = None - self.build_temp = None - self.build_scripts = None - self.compiler = None - self.plat_name = None - self.debug = None - self.force = 0 - self.executable = None - self.use_2to3 = False - self.convert_2to3_doctests = None - self.use_2to3_fixers = None - - def finalize_options(self): - if self.plat_name is None: - self.plat_name = get_platform() - else: - # plat-name only supported for windows (other platforms are - # supported via ./configure flags, if at all). Avoid misleading - # other platforms. - if os.name != 'nt': - raise DistutilsOptionError( - "--plat-name only supported on Windows (try " - "using './configure --help' on your platform)") - - plat_specifier = ".%s-%s" % (self.plat_name, sys.version[0:3]) - - # Make it so Python 2.x and Python 2.x with --with-pydebug don't - # share the same build directories. Doing so confuses the build - # process for C modules - if hasattr(sys, 'gettotalrefcount'): - plat_specifier += '-pydebug' - - # 'build_purelib' and 'build_platlib' just default to 'lib' and - # 'lib.<plat>' under the base build directory. We only use one of - # them for a given distribution, though -- - if self.build_purelib is None: - self.build_purelib = os.path.join(self.build_base, 'lib') - if self.build_platlib is None: - self.build_platlib = os.path.join(self.build_base, - 'lib' + plat_specifier) - - # 'build_lib' is the actual directory that we will use for this - # particular module distribution -- if user didn't supply it, pick - # one of 'build_purelib' or 'build_platlib'. - if self.build_lib is None: - if self.distribution.ext_modules: - self.build_lib = self.build_platlib - else: - self.build_lib = self.build_purelib - - # 'build_temp' -- temporary directory for compiler turds, - # "build/temp.<plat>" - if self.build_temp is None: - self.build_temp = os.path.join(self.build_base, - 'temp' + plat_specifier) - if self.build_scripts is None: - self.build_scripts = os.path.join(self.build_base, - 'scripts-' + sys.version[0:3]) - - if self.executable is None: - self.executable = os.path.normpath(sys.executable) - - def run(self): - # Run all relevant sub-commands. This will be some subset of: - # - build_py - pure Python modules - # - build_clib - standalone C libraries - # - build_ext - Python extensions - # - build_scripts - (Python) scripts - for cmd_name in self.get_sub_commands(): - self.run_command(cmd_name) - - # -- Predicates for the sub-command list --------------------------- - - def has_pure_modules (self): - return self.distribution.has_pure_modules() - - def has_c_libraries (self): - return self.distribution.has_c_libraries() - - def has_ext_modules (self): - return self.distribution.has_ext_modules() - - def has_scripts (self): - return self.distribution.has_scripts() - - sub_commands = [('build_py', has_pure_modules), - ('build_clib', has_c_libraries), - ('build_ext', has_ext_modules), - ('build_scripts', has_scripts), - ] diff --git a/src/distutils2/command/build_clib.py b/src/distutils2/command/build_clib.py deleted file mode 100644 index e470b7e..0000000 --- a/src/distutils2/command/build_clib.py +++ /dev/null @@ -1,207 +0,0 @@ -"""distutils.command.build_clib - -Implements the Distutils 'build_clib' command, to build a C/C++ library -that is included in the module distribution and needed by an extension -module.""" - -__revision__ = "$Id: build_clib.py 77704 2010-01-23 09:23:15Z tarek.ziade $" - - -# XXX this module has *lots* of code ripped-off quite transparently from -# build_ext.py -- not surprisingly really, as the work required to build -# a static library from a collection of C source files is not really all -# that different from what's required to build a shared object file from -# a collection of C source files. Nevertheless, I haven't done the -# necessary refactoring to account for the overlap in code between the -# two modules, mainly because a number of subtle details changed in the -# cut 'n paste. Sigh. - -import os -from distutils2.core import Command -from distutils2.errors import DistutilsSetupError -from distutils2.compiler.ccompiler import customize_compiler -from distutils2 import log - -def show_compilers(): - from distutils2.compiler.ccompiler import show_compilers - show_compilers() - - -class build_clib(Command): - - description = "build C/C++ libraries used by Python extensions" - - user_options = [ - ('build-clib=', 'b', - "directory to build C/C++ libraries to"), - ('build-temp=', 't', - "directory to put temporary build by-products"), - ('debug', 'g', - "compile with debugging information"), - ('force', 'f', - "forcibly build everything (ignore file timestamps)"), - ('compiler=', 'c', - "specify the compiler type"), - ] - - boolean_options = ['debug', 'force'] - - help_options = [ - ('help-compiler', None, - "list available compilers", show_compilers), - ] - - def initialize_options(self): - self.build_clib = None - self.build_temp = None - - # List of libraries to build - self.libraries = None - - # Compilation options for all libraries - self.include_dirs = None - self.define = None - self.undef = None - self.debug = None - self.force = 0 - self.compiler = None - - - def finalize_options(self): - # This might be confusing: both build-clib and build-temp default - # to build-temp as defined by the "build" command. This is because - # I think that C libraries are really just temporary build - # by-products, at least from the point of view of building Python - # extensions -- but I want to keep my options open. - self.set_undefined_options('build', - ('build_temp', 'build_clib'), - ('build_temp', 'build_temp'), - 'compiler', 'debug', 'force') - - self.libraries = self.distribution.libraries - if self.libraries: - self.check_library_list(self.libraries) - - if self.include_dirs is None: - self.include_dirs = self.distribution.include_dirs or [] - if isinstance(self.include_dirs, str): - self.include_dirs = self.include_dirs.split(os.pathsep) - - # XXX same as for build_ext -- what about 'self.define' and - # 'self.undef' ? - - def run(self): - if not self.libraries: - return - - # Yech -- this is cut 'n pasted from build_ext.py! - from distutils2.compiler.ccompiler import new_compiler - self.compiler = new_compiler(compiler=self.compiler, - dry_run=self.dry_run, - force=self.force) - customize_compiler(self.compiler) - - if self.include_dirs is not None: - self.compiler.set_include_dirs(self.include_dirs) - if self.define is not None: - # 'define' option is a list of (name,value) tuples - for (name,value) in self.define: - self.compiler.define_macro(name, value) - if self.undef is not None: - for macro in self.undef: - self.compiler.undefine_macro(macro) - - self.build_libraries(self.libraries) - - - def check_library_list(self, libraries): - """Ensure that the list of libraries is valid. - - `library` is presumably provided as a command option 'libraries'. - This method checks that it is a list of 2-tuples, where the tuples - are (library_name, build_info_dict). - - Raise DistutilsSetupError if the structure is invalid anywhere; - just returns otherwise. - """ - if not isinstance(libraries, list): - raise DistutilsSetupError, \ - "'libraries' option must be a list of tuples" - - for lib in libraries: - if not isinstance(lib, tuple) and len(lib) != 2: - raise DistutilsSetupError, \ - "each element of 'libraries' must a 2-tuple" - - name, build_info = lib - - if not isinstance(name, str): - raise DistutilsSetupError, \ - "first element of each tuple in 'libraries' " + \ - "must be a string (the library name)" - if '/' in name or (os.sep != '/' and os.sep in name): - raise DistutilsSetupError, \ - ("bad library name '%s': " + - "may not contain directory separators") % \ - lib[0] - - if not isinstance(build_info, dict): - raise DistutilsSetupError, \ - "second element of each tuple in 'libraries' " + \ - "must be a dictionary (build info)" - - def get_library_names(self): - # Assume the library list is valid -- 'check_library_list()' is - # called from 'finalize_options()', so it should be! - if not self.libraries: - return None - - lib_names = [] - for (lib_name, build_info) in self.libraries: - lib_names.append(lib_name) - return lib_names - - - def get_source_files(self): - self.check_library_list(self.libraries) - filenames = [] - for (lib_name, build_info) in self.libraries: - sources = build_info.get('sources') - if sources is None or not isinstance(sources, (list, tuple)): - raise DistutilsSetupError, \ - ("in 'libraries' option (library '%s'), " - "'sources' must be present and must be " - "a list of source filenames") % lib_name - - filenames.extend(sources) - return filenames - - def build_libraries(self, libraries): - for (lib_name, build_info) in libraries: - sources = build_info.get('sources') - if sources is None or not isinstance(sources, (list, tuple)): - raise DistutilsSetupError, \ - ("in 'libraries' option (library '%s'), " + - "'sources' must be present and must be " + - "a list of source filenames") % lib_name - sources = list(sources) - - log.info("building '%s' library", lib_name) - - # First, compile the source code to object files in the library - # directory. (This should probably change to putting object - # files in a temporary build directory.) - macros = build_info.get('macros') - include_dirs = build_info.get('include_dirs') - objects = self.compiler.compile(sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=include_dirs, - debug=self.debug) - - # Now "link" the object files together into a static library. - # (On Unix at least, this isn't really linking -- it just - # builds an archive. Whatever.) - self.compiler.create_static_lib(objects, lib_name, - output_dir=self.build_clib, - debug=self.debug) diff --git a/src/distutils2/command/build_ext.py b/src/distutils2/command/build_ext.py deleted file mode 100644 index 405c594..0000000 --- a/src/distutils2/command/build_ext.py +++ /dev/null @@ -1,740 +0,0 @@ -"""distutils.command.build_ext - -Implements the Distutils 'build_ext' command, for building extension -modules (currently limited to C extensions, should accommodate C++ -extensions ASAP).""" - -__revision__ = "$Id: build_ext.py 77761 2010-01-26 22:46:15Z tarek.ziade $" - -import sys, os, re -from warnings import warn - -from distutils2.util import get_platform -from distutils2.core import Command -from distutils2.errors import (CCompilerError, CompileError, DistutilsError, - DistutilsPlatformError, DistutilsSetupError) -from distutils2.compiler.ccompiler import customize_compiler -from distutils2.util import newer_group -from distutils2.extension import Extension -from distutils2 import log -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig - -# this keeps compatibility from 2.3 to 2.5 -if sys.version < "2.6": - USER_BASE = None - HAS_USER_SITE = False -else: - from site import USER_BASE - HAS_USER_SITE = True - -if os.name == 'nt': - from distutils2.msvccompiler import get_build_version - MSVC_VERSION = int(get_build_version()) - -# An extension name is just a dot-separated list of Python NAMEs (ie. -# the same as a fully-qualified module name). -extension_name_re = re.compile \ - (r'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$') - - -def show_compilers (): - from distutils2.compiler.ccompiler import show_compilers - show_compilers() - - -class build_ext(Command): - - description = "build C/C++ extensions (compile/link to build directory)" - - # XXX thoughts on how to deal with complex command-line options like - # these, i.e. how to make it so fancy_getopt can suck them off the - # command line and make it look like setup.py defined the appropriate - # lists of tuples of what-have-you. - # - each command needs a callback to process its command-line options - # - Command.__init__() needs access to its share of the whole - # command line (must ultimately come from - # Distribution.parse_command_line()) - # - it then calls the current command class' option-parsing - # callback to deal with weird options like -D, which have to - # parse the option text and churn out some custom data - # structure - # - that data structure (in this case, a list of 2-tuples) - # will then be present in the command object by the time - # we get to finalize_options() (i.e. the constructor - # takes care of both command-line and client options - # in between initialize_options() and finalize_options()) - - sep_by = " (separated by '%s')" % os.pathsep - user_options = [ - ('build-lib=', 'b', - "directory for compiled extension modules"), - ('build-temp=', 't', - "directory for temporary files (build by-products)"), - ('plat-name=', 'p', - "platform name to cross-compile for, if supported " - "(default: %s)" % get_platform()), - ('inplace', 'i', - "ignore build-lib and put compiled extensions into the source " + - "directory alongside your pure Python modules"), - ('include-dirs=', 'I', - "list of directories to search for header files" + sep_by), - ('define=', 'D', - "C preprocessor macros to define"), - ('undef=', 'U', - "C preprocessor macros to undefine"), - ('libraries=', 'l', - "external C libraries to link with"), - ('library-dirs=', 'L', - "directories to search for external C libraries" + sep_by), - ('rpath=', 'R', - "directories to search for shared C libraries at runtime"), - ('link-objects=', 'O', - "extra explicit link objects to include in the link"), - ('debug', 'g', - "compile/link with debugging information"), - ('force', 'f', - "forcibly build everything (ignore file timestamps)"), - ('compiler=', 'c', - "specify the compiler type"), - ('swig-cpp', None, - "make SWIG create C++ files (default is C)"), - ('swig-opts=', None, - "list of SWIG command-line options"), - ('swig=', None, - "path to the SWIG executable"), - ] - - boolean_options = ['inplace', 'debug', 'force', 'swig-cpp'] - - if HAS_USER_SITE: - user_options.append(('user', None, - "add user include, library and rpath")) - boolean_options.append('user') - - help_options = [ - ('help-compiler', None, - "list available compilers", show_compilers), - ] - - - # making 'compiler' a property to deprecate - # its usage as something else than a compiler type - # e.g. like a compiler instance - def __init__(self, dist): - self._compiler = None - Command.__init__(self, dist) - - def __setattr__(self, name, value): - # need this to make sure setattr() (used in distutils) - # doesn't kill our property - if name == 'compiler': - self._set_compiler(value) - else: - self.__dict__[name] = value - - def _set_compiler(self, compiler): - if not isinstance(compiler, str) and compiler is not None: - # we don't want to allow that anymore in the future - warn("'compiler' specifies the compiler type in build_ext. " - "If you want to get the compiler object itself, " - "use 'compiler_obj'", DeprecationWarning) - self._compiler = compiler - - def _get_compiler(self): - if not isinstance(self._compiler, str) and self._compiler is not None: - # we don't want to allow that anymore in the future - warn("'compiler' specifies the compiler type in build_ext. " - "If you want to get the compiler object itself, " - "use 'compiler_obj'", DeprecationWarning) - return self._compiler - - compiler = property(_get_compiler, _set_compiler) - - def initialize_options(self): - self.extensions = None - self.build_lib = None - self.plat_name = None - self.build_temp = None - self.inplace = 0 - self.package = None - - self.include_dirs = None - self.define = None - self.undef = None - self.libraries = None - self.library_dirs = None - self.rpath = None - self.link_objects = None - self.debug = None - self.force = None - self.compiler = None - self.swig = None - self.swig_cpp = None - self.swig_opts = None - if HAS_USER_SITE: - self.user = None - - def finalize_options(self): - self.set_undefined_options('build', - 'build_lib', 'build_temp', 'compiler', - 'debug', 'force', 'plat_name') - - if self.package is None: - self.package = self.distribution.ext_package - - # Ensure that the list of extensions is valid, i.e. it is a list of - # Extension objects. - self.extensions = self.distribution.ext_modules - if self.extensions: - if not isinstance(self.extensions, (list, tuple)): - type_name = (self.extensions is None and 'None' - or type(self.extensions).__name__) - raise DistutilsSetupError( - "'ext_modules' must be a sequence of Extension instances," - " not %s" % (type_name,)) - for i, ext in enumerate(self.extensions): - if isinstance(ext, Extension): - continue # OK! (assume type-checking done - # by Extension constructor) - type_name = (ext is None and 'None' or type(ext).__name__) - raise DistutilsSetupError( - "'ext_modules' item %d must be an Extension instance," - " not %s" % (i, type_name)) - - # Make sure Python's include directories (for Python.h, pyconfig.h, - # etc.) are in the include search path. - py_include = sysconfig.get_path('include') - plat_py_include = sysconfig.get_path('platinclude') - if self.include_dirs is None: - self.include_dirs = self.distribution.include_dirs or [] - if isinstance(self.include_dirs, str): - self.include_dirs = self.include_dirs.split(os.pathsep) - - # Put the Python "system" include dir at the end, so that - # any local include dirs take precedence. - self.include_dirs.append(py_include) - if plat_py_include != py_include: - self.include_dirs.append(plat_py_include) - - if isinstance(self.libraries, str): - self.libraries = [self.libraries] - - # Life is easier if we're not forever checking for None, so - # simplify these options to empty lists if unset - if self.libraries is None: - self.libraries = [] - if self.library_dirs is None: - self.library_dirs = [] - elif isinstance(self.library_dirs, str): - self.library_dirs = self.library_dirs.split(os.pathsep) - - if self.rpath is None: - self.rpath = [] - elif isinstance(self.rpath, str): - self.rpath = self.rpath.split(os.pathsep) - - # for extensions under windows use different directories - # for Release and Debug builds. - # also Python's library directory must be appended to library_dirs - if os.name == 'nt': - # the 'libs' directory is for binary installs - we assume that - # must be the *native* platform. But we don't really support - # cross-compiling via a binary install anyway, so we let it go. - self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs')) - if self.debug: - self.build_temp = os.path.join(self.build_temp, "Debug") - else: - self.build_temp = os.path.join(self.build_temp, "Release") - - # Append the source distribution include and library directories, - # this allows distutils on windows to work in the source tree - self.include_dirs.append(os.path.join(sys.exec_prefix, 'PC')) - if MSVC_VERSION == 9: - # Use the .lib files for the correct architecture - if self.plat_name == 'win32': - suffix = '' - else: - # win-amd64 or win-ia64 - suffix = self.plat_name[4:] - new_lib = os.path.join(sys.exec_prefix, 'PCbuild') - if suffix: - new_lib = os.path.join(new_lib, suffix) - self.library_dirs.append(new_lib) - - elif MSVC_VERSION == 8: - self.library_dirs.append(os.path.join(sys.exec_prefix, - 'PC', 'VS8.0', 'win32release')) - elif MSVC_VERSION == 7: - self.library_dirs.append(os.path.join(sys.exec_prefix, - 'PC', 'VS7.1')) - else: - self.library_dirs.append(os.path.join(sys.exec_prefix, - 'PC', 'VC6')) - - # OS/2 (EMX) doesn't support Debug vs Release builds, but has the - # import libraries in its "Config" subdirectory - if os.name == 'os2': - self.library_dirs.append(os.path.join(sys.exec_prefix, 'Config')) - - # for extensions under Cygwin and AtheOS Python's library directory must be - # appended to library_dirs - if sys.platform[:6] == 'cygwin' or sys.platform[:6] == 'atheos': - if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")): - # building third party extensions - self.library_dirs.append(os.path.join(sys.prefix, "lib", - "python" + sysconfig.get_python_version(), - "config")) - else: - # building python standard extensions - self.library_dirs.append(os.curdir) - - # for extensions under Linux or Solaris with a shared Python library, - # Python's library directory must be appended to library_dirs - sysconfig.get_config_var('Py_ENABLE_SHARED') - if ((sys.platform.startswith('linux') or sys.platform.startswith('gnu') - or sys.platform.startswith('sunos')) - and sysconfig.get_config_var('Py_ENABLE_SHARED')): - if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")): - # building third party extensions - self.library_dirs.append(sysconfig.get_config_var('LIBDIR')) - else: - # building python standard extensions - self.library_dirs.append(os.curdir) - - # The argument parsing will result in self.define being a string, but - # it has to be a list of 2-tuples. All the preprocessor symbols - # specified by the 'define' option will be set to '1'. Multiple - # symbols can be separated with commas. - - if self.define: - defines = self.define.split(',') - self.define = [(symbol, '1') for symbol in defines] - - # The option for macros to undefine is also a string from the - # option parsing, but has to be a list. Multiple symbols can also - # be separated with commas here. - if self.undef: - self.undef = self.undef.split(',') - - if self.swig_opts is None: - self.swig_opts = [] - else: - self.swig_opts = self.swig_opts.split(' ') - - # Finally add the user include and library directories if requested - if HAS_USER_SITE and self.user: - user_include = os.path.join(USER_BASE, "include") - user_lib = os.path.join(USER_BASE, "lib") - if os.path.isdir(user_include): - self.include_dirs.append(user_include) - if os.path.isdir(user_lib): - self.library_dirs.append(user_lib) - self.rpath.append(user_lib) - - def run(self): - from distutils2.compiler.ccompiler import new_compiler - - # 'self.extensions', as supplied by setup.py, is a list of - # Extension instances. See the documentation for Extension (in - # distutils.extension) for details. - # - # For backwards compatibility with Distutils 0.8.2 and earlier, we - # also allow the 'extensions' list to be a list of tuples: - # (ext_name, build_info) - # where build_info is a dictionary containing everything that - # Extension instances do except the name, with a few things being - # differently named. We convert these 2-tuples to Extension - # instances as needed. - - if not self.extensions: - return - - # If we were asked to build any C/C++ libraries, make sure that the - # directory where we put them is in the library search path for - # linking extensions. - if self.distribution.has_c_libraries(): - build_clib = self.get_finalized_command('build_clib') - self.libraries.extend(build_clib.get_library_names() or []) - self.library_dirs.append(build_clib.build_clib) - - # Setup the CCompiler object that we'll use to do all the - # compiling and linking - - # used to prevent the usage of an existing compiler for the - # compiler option when calling new_compiler() - # this will be removed in 3.3 and 2.8 - if not isinstance(self._compiler, str): - self._compiler = None - - self.compiler_obj = new_compiler(compiler=self._compiler, - verbose=self.verbose, - dry_run=self.dry_run, - force=self.force) - - # used to keep the compiler object reachable with - # "self.compiler". this will be removed in 3.3 and 2.8 - self._compiler = self.compiler_obj - - customize_compiler(self.compiler_obj) - # If we are cross-compiling, init the compiler now (if we are not - # cross-compiling, init would not hurt, but people may rely on - # late initialization of compiler even if they shouldn't...) - if os.name == 'nt' and self.plat_name != get_platform(): - self.compiler_obj.initialize(self.plat_name) - - # And make sure that any compile/link-related options (which might - # come from the command line or from the setup script) are set in - # that CCompiler object -- that way, they automatically apply to - # all compiling and linking done here. - if self.include_dirs is not None: - self.compiler_obj.set_include_dirs(self.include_dirs) - if self.define is not None: - # 'define' option is a list of (name,value) tuples - for (name, value) in self.define: - self.compiler_obj.define_macro(name, value) - if self.undef is not None: - for macro in self.undef: - self.compiler_obj.undefine_macro(macro) - if self.libraries is not None: - self.compiler_obj.set_libraries(self.libraries) - if self.library_dirs is not None: - self.compiler_obj.set_library_dirs(self.library_dirs) - if self.rpath is not None: - self.compiler_obj.set_runtime_library_dirs(self.rpath) - if self.link_objects is not None: - self.compiler_obj.set_link_objects(self.link_objects) - - # Now actually compile and link everything. - self.build_extensions() - - def get_source_files(self): - filenames = [] - - # Wouldn't it be neat if we knew the names of header files too... - for ext in self.extensions: - filenames.extend(ext.sources) - - return filenames - - def get_outputs(self): - # And build the list of output (built) filenames. Note that this - # ignores the 'inplace' flag, and assumes everything goes in the - # "build" tree. - outputs = [] - for ext in self.extensions: - outputs.append(self.get_ext_fullpath(ext.name)) - return outputs - - def build_extensions(self): - for ext in self.extensions: - try: - self.build_extension(ext) - except (CCompilerError, DistutilsError, CompileError), e: - if not ext.optional: - raise - self.warn('building extension "%s" failed: %s' % - (ext.name, e)) - - def build_extension(self, ext): - sources = ext.sources - if sources is None or not isinstance(sources, (list, tuple)): - raise DistutilsSetupError, \ - ("in 'ext_modules' option (extension '%s'), " + - "'sources' must be present and must be " + - "a list of source filenames") % ext.name - sources = list(sources) - - ext_path = self.get_ext_fullpath(ext.name) - depends = sources + ext.depends - if not (self.force or newer_group(depends, ext_path, 'newer')): - log.debug("skipping '%s' extension (up-to-date)", ext.name) - return - else: - log.info("building '%s' extension", ext.name) - - # First, scan the sources for SWIG definition files (.i), run - # SWIG on 'em to create .c files, and modify the sources list - # accordingly. - sources = self.swig_sources(sources, ext) - - # Next, compile the source code to object files. - - # XXX not honouring 'define_macros' or 'undef_macros' -- the - # CCompiler API needs to change to accommodate this, and I - # want to do one thing at a time! - - # Two possible sources for extra compiler arguments: - # - 'extra_compile_args' in Extension object - # - CFLAGS environment variable (not particularly - # elegant, but people seem to expect it and I - # guess it's useful) - # The environment variable should take precedence, and - # any sensible compiler will give precedence to later - # command-line args. Hence we combine them in order: - extra_args = ext.extra_compile_args or [] - - macros = ext.define_macros[:] - for undef in ext.undef_macros: - macros.append((undef,)) - - objects = self.compiler_obj.compile(sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=ext.include_dirs, - debug=self.debug, - extra_postargs=extra_args, - depends=ext.depends) - - # XXX -- this is a Vile HACK! - # - # The setup.py script for Python on Unix needs to be able to - # get this list so it can perform all the clean up needed to - # avoid keeping object files around when cleaning out a failed - # build of an extension module. Since Distutils does not - # track dependencies, we have to get rid of intermediates to - # ensure all the intermediates will be properly re-built. - # - self._built_objects = objects[:] - - # Now link the object files together into a "shared object" -- - # of course, first we have to figure out all the other things - # that go into the mix. - if ext.extra_objects: - objects.extend(ext.extra_objects) - extra_args = ext.extra_link_args or [] - - # Detect target language, if not provided - language = ext.language or self.compiler_obj.detect_language(sources) - - self.compiler_obj.link_shared_object( - objects, ext_path, - libraries=self.get_libraries(ext), - library_dirs=ext.library_dirs, - runtime_library_dirs=ext.runtime_library_dirs, - extra_postargs=extra_args, - export_symbols=self.get_export_symbols(ext), - debug=self.debug, - build_temp=self.build_temp, - target_lang=language) - - - def swig_sources(self, sources, extension): - """Walk the list of source files in 'sources', looking for SWIG - interface (.i) files. Run SWIG on all that are found, and - return a modified 'sources' list with SWIG source files replaced - by the generated C (or C++) files. - """ - new_sources = [] - swig_sources = [] - swig_targets = {} - - # XXX this drops generated C/C++ files into the source tree, which - # is fine for developers who want to distribute the generated - # source -- but there should be an option to put SWIG output in - # the temp dir. - - if self.swig_cpp: - log.warn("--swig-cpp is deprecated - use --swig-opts=-c++") - - if self.swig_cpp or ('-c++' in self.swig_opts) or \ - ('-c++' in extension.swig_opts): - target_ext = '.cpp' - else: - target_ext = '.c' - - for source in sources: - (base, ext) = os.path.splitext(source) - if ext == ".i": # SWIG interface file - new_sources.append(base + '_wrap' + target_ext) - swig_sources.append(source) - swig_targets[source] = new_sources[-1] - else: - new_sources.append(source) - - if not swig_sources: - return new_sources - - swig = self.swig or self.find_swig() - swig_cmd = [swig, "-python"] - swig_cmd.extend(self.swig_opts) - if self.swig_cpp: - swig_cmd.append("-c++") - - # Do not override commandline arguments - if not self.swig_opts: - for o in extension.swig_opts: - swig_cmd.append(o) - - for source in swig_sources: - target = swig_targets[source] - log.info("swigging %s to %s", source, target) - self.spawn(swig_cmd + ["-o", target, source]) - - return new_sources - - def find_swig(self): - """Return the name of the SWIG executable. On Unix, this is - just "swig" -- it should be in the PATH. Tries a bit harder on - Windows. - """ - - if os.name == "posix": - return "swig" - elif os.name == "nt": - - # Look for SWIG in its standard installation directory on - # Windows (or so I presume!). If we find it there, great; - # if not, act like Unix and assume it's in the PATH. - for vers in ("1.3", "1.2", "1.1"): - fn = os.path.join("c:\\swig%s" % vers, "swig.exe") - if os.path.isfile(fn): - return fn - else: - return "swig.exe" - - elif os.name == "os2": - # assume swig available in the PATH. - return "swig.exe" - - else: - raise DistutilsPlatformError, \ - ("I don't know how to find (much less run) SWIG " - "on platform '%s'") % os.name - - # -- Name generators ----------------------------------------------- - # (extension names, filenames, whatever) - def get_ext_fullpath(self, ext_name): - """Returns the path of the filename for a given extension. - - The file is located in `build_lib` or directly in the package - (inplace option). - """ - fullname = self.get_ext_fullname(ext_name) - modpath = fullname.split('.') - filename = self.get_ext_filename(modpath[-1]) - - if not self.inplace: - # no further work needed - # returning : - # build_dir/package/path/filename - filename = os.path.join(*modpath[:-1]+[filename]) - return os.path.join(self.build_lib, filename) - - # the inplace option requires to find the package directory - # using the build_py command for that - package = '.'.join(modpath[0:-1]) - build_py = self.get_finalized_command('build_py') - package_dir = os.path.abspath(build_py.get_package_dir(package)) - - # returning - # package_dir/filename - return os.path.join(package_dir, filename) - - def get_ext_fullname(self, ext_name): - """Returns the fullname of a given extension name. - - Adds the `package.` prefix""" - if self.package is None: - return ext_name - else: - return self.package + '.' + ext_name - - def get_ext_filename(self, ext_name): - r"""Convert the name of an extension (eg. "foo.bar") into the name - of the file from which it will be loaded (eg. "foo/bar.so", or - "foo\bar.pyd"). - """ - ext_path = ext_name.split('.') - # OS/2 has an 8 character module (extension) limit :-( - if os.name == "os2": - ext_path[len(ext_path) - 1] = ext_path[len(ext_path) - 1][:8] - # extensions in debug_mode are named 'module_d.pyd' under windows - so_ext = sysconfig.get_config_var('SO') - if os.name == 'nt' and self.debug: - return os.path.join(*ext_path) + '_d' + so_ext - return os.path.join(*ext_path) + so_ext - - def get_export_symbols(self, ext): - """Return the list of symbols that a shared extension has to - export. This either uses 'ext.export_symbols' or, if it's not - provided, "init" + module_name. Only relevant on Windows, where - the .pyd file (DLL) must export the module "init" function. - """ - initfunc_name = "init" + ext.name.split('.')[-1] - if initfunc_name not in ext.export_symbols: - ext.export_symbols.append(initfunc_name) - return ext.export_symbols - - def get_libraries(self, ext): - """Return the list of libraries to link against when building a - shared extension. On most platforms, this is just 'ext.libraries'; - on Windows and OS/2, we add the Python library (eg. python20.dll). - """ - # The python library is always needed on Windows. For MSVC, this - # is redundant, since the library is mentioned in a pragma in - # pyconfig.h that MSVC groks. The other Windows compilers all seem - # to need it mentioned explicitly, though, so that's what we do. - # Append '_d' to the python import library on debug builds. - if sys.platform == "win32": - from distutils2.msvccompiler import MSVCCompiler - if not isinstance(self.compiler_obj, MSVCCompiler): - template = "python%d%d" - if self.debug: - template = template + '_d' - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) - # don't extend ext.libraries, it may be shared with other - # extensions, it is a reference to the original list - return ext.libraries + [pythonlib] - else: - return ext.libraries - elif sys.platform == "os2emx": - # EMX/GCC requires the python library explicitly, and I - # believe VACPP does as well (though not confirmed) - AIM Apr01 - template = "python%d%d" - # debug versions of the main DLL aren't supported, at least - # not at this time - AIM Apr01 - #if self.debug: - # template = template + '_d' - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) - # don't extend ext.libraries, it may be shared with other - # extensions, it is a reference to the original list - return ext.libraries + [pythonlib] - elif sys.platform[:6] == "cygwin": - template = "python%d.%d" - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) - # don't extend ext.libraries, it may be shared with other - # extensions, it is a reference to the original list - return ext.libraries + [pythonlib] - elif sys.platform[:6] == "atheos": - template = "python%d.%d" - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) - # Get SHLIBS from Makefile - extra = [] - for lib in sysconfig.get_config_var('SHLIBS').split(): - if lib.startswith('-l'): - extra.append(lib[2:]) - else: - extra.append(lib) - # don't extend ext.libraries, it may be shared with other - # extensions, it is a reference to the original list - return ext.libraries + [pythonlib, "m"] + extra - - elif sys.platform == 'darwin': - # Don't use the default code below - return ext.libraries - - else: - if sysconfig.get_config_var('Py_ENABLE_SHARED'): - template = "python%d.%d" - pythonlib = (template % - (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) - return ext.libraries + [pythonlib] - else: - return ext.libraries diff --git a/src/distutils2/command/build_py.py b/src/distutils2/command/build_py.py deleted file mode 100644 index 98b1619..0000000 --- a/src/distutils2/command/build_py.py +++ /dev/null @@ -1,436 +0,0 @@ -"""distutils.command.build_py - -Implements the Distutils 'build_py' command.""" - -__revision__ = "$Id: build_py.py 76956 2009-12-21 01:22:46Z tarek.ziade $" - -import os -import sys -import logging -from glob import glob - -import distutils2 -from distutils2.core import Command -from distutils2.errors import DistutilsOptionError, DistutilsFileError -from distutils2.util import convert_path -from distutils2.compat import Mixin2to3 - -# marking public APIs -__all__ = ['build_py'] - -class build_py(Command, Mixin2to3): - - description = "\"build\" pure Python modules (copy to build directory)" - - user_options = [ - ('build-lib=', 'd', "directory to \"build\" (copy) to"), - ('compile', 'c', "compile .py to .pyc"), - ('no-compile', None, "don't compile .py files [default]"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), - ('force', 'f', "forcibly build everything (ignore file timestamps)"), - ('use-2to3', None, - "use 2to3 to make source python 3.x compatible"), - ('convert-2to3-doctests', None, - "use 2to3 to convert doctests in seperate text files"), - ('use-2to3-fixers', None, - "list additional fixers opted for during 2to3 conversion"), - ] - - boolean_options = ['compile', 'force'] - negative_opt = {'no-compile' : 'compile'} - - def initialize_options(self): - self.build_lib = None - self.py_modules = None - self.package = None - self.package_data = None - self.package_dir = None - self.compile = 0 - self.optimize = 0 - self.force = None - self._updated_files = [] - self._doctests_2to3 = [] - self.use_2to3 = False - self.convert_2to3_doctests = None - self.use_2to3_fixers = None - - def finalize_options(self): - self.set_undefined_options('build', - 'use_2to3', 'use_2to3_fixers', - 'convert_2to3_doctests', 'build_lib', - 'force') - - # Get the distribution options that are aliases for build_py - # options -- list of packages and list of modules. - self.packages = self.distribution.packages - self.py_modules = self.distribution.py_modules - self.package_data = self.distribution.package_data - self.package_dir = {} - if self.distribution.package_dir: - for name, path in self.distribution.package_dir.items(): - self.package_dir[name] = convert_path(path) - self.data_files = self.get_data_files() - - # Ick, copied straight from install_lib.py (fancy_getopt needs a - # type system! Hell, *everything* needs a type system!!!) - if not isinstance(self.optimize, int): - try: - self.optimize = int(self.optimize) - assert 0 <= self.optimize <= 2 - except (ValueError, AssertionError): - raise DistutilsOptionError("optimize must be 0, 1, or 2") - - def run(self): - # XXX copy_file by default preserves atime and mtime. IMHO this is - # the right thing to do, but perhaps it should be an option -- in - # particular, a site administrator might want installed files to - # reflect the time of installation rather than the last - # modification time before the installed release. - - # XXX copy_file by default preserves mode, which appears to be the - # wrong thing to do: if a file is read-only in the working - # directory, we want it to be installed read/write so that the next - # installation of the same module distribution can overwrite it - # without problems. (This might be a Unix-specific issue.) Thus - # we turn off 'preserve_mode' when copying to the build directory, - # since the build directory is supposed to be exactly what the - # installation will look like (ie. we preserve mode when - # installing). - - # Two options control which modules will be installed: 'packages' - # and 'py_modules'. The former lets us work with whole packages, not - # specifying individual modules at all; the latter is for - # specifying modules one-at-a-time. - - if self.py_modules: - self.build_modules() - if self.packages: - self.build_packages() - self.build_package_data() - - if self.use_2to3 and self._updated_files: - self.run_2to3(self._updated_files, self._doctests_2to3, - self.use_2to3_fixers) - - self.byte_compile(self.get_outputs(include_bytecode=0)) - - # -- Top-level worker functions ------------------------------------ - - def get_data_files(self): - """Generate list of '(package,src_dir,build_dir,filenames)' tuples. - - Helper function for `finalize_options()`. - """ - data = [] - if not self.packages: - return data - for package in self.packages: - # Locate package source directory - src_dir = self.get_package_dir(package) - - # Compute package build directory - build_dir = os.path.join(*([self.build_lib] + package.split('.'))) - - # Length of path to strip from found files - plen = 0 - if src_dir: - plen = len(src_dir)+1 - - # Strip directory from globbed filenames - filenames = [ - file[plen:] for file in self.find_data_files(package, src_dir) - ] - data.append((package, src_dir, build_dir, filenames)) - return data - - def find_data_files(self, package, src_dir): - """Return filenames for package's data files in 'src_dir'. - - Helper function for `get_data_files()`. - """ - globs = (self.package_data.get('', []) - + self.package_data.get(package, [])) - files = [] - for pattern in globs: - # Each pattern has to be converted to a platform-specific path - filelist = glob(os.path.join(src_dir, convert_path(pattern))) - # Files that match more than one pattern are only added once - files.extend([fn for fn in filelist if fn not in files]) - return files - - def build_package_data(self): - """Copy data files into build directory. - - Helper function for `run()`. - """ - for package, src_dir, build_dir, filenames in self.data_files: - for filename in filenames: - target = os.path.join(build_dir, filename) - self.mkpath(os.path.dirname(target)) - outf, copied = self.copy_file(os.path.join(src_dir, filename), - target, preserve_mode=False) - if copied and srcfile in self.distribution.convert_2to3.doctests: - self._doctests_2to3.append(outf) - - # XXX - this should be moved to the Distribution class as it is not - # only needed for build_py. It also has no dependencies on this class. - def get_package_dir(self, package): - """Return the directory, relative to the top of the source - distribution, where package 'package' should be found - (at least according to the 'package_dir' option, if any).""" - - path = package.split('.') - - if not self.package_dir: - if path: - return os.path.join(*path) - else: - return '' - else: - tail = [] - while path: - try: - pdir = self.package_dir['.'.join(path)] - except KeyError: - tail.insert(0, path[-1]) - del path[-1] - else: - tail.insert(0, pdir) - return os.path.join(*tail) - else: - # Oops, got all the way through 'path' without finding a - # match in package_dir. If package_dir defines a directory - # for the root (nameless) package, then fallback on it; - # otherwise, we might as well have not consulted - # package_dir at all, as we just use the directory implied - # by 'tail' (which should be the same as the original value - # of 'path' at this point). - pdir = self.package_dir.get('') - if pdir is not None: - tail.insert(0, pdir) - - if tail: - return os.path.join(*tail) - else: - return '' - - def check_package(self, package, package_dir): - """Helper function for `find_package_modules()` and `find_modules()'. - """ - # Empty dir name means current directory, which we can probably - # assume exists. Also, os.path.exists and isdir don't know about - # my "empty string means current dir" convention, so we have to - # circumvent them. - if package_dir != "": - if not os.path.exists(package_dir): - raise DistutilsFileError( - "package directory '%s' does not exist" % package_dir) - if not os.path.isdir(package_dir): - raise DistutilsFileError( - "supposed package directory '%s' exists, " - "but is not a directory" % package_dir) - - # Require __init__.py for all but the "root package" - if package: - init_py = os.path.join(package_dir, "__init__.py") - if os.path.isfile(init_py): - return init_py - else: - logging.warning(("package init file '%s' not found " + - "(or not a regular file)"), init_py) - - # Either not in a package at all (__init__.py not expected), or - # __init__.py doesn't exist -- so don't return the filename. - return None - - def check_module(self, module, module_file): - if not os.path.isfile(module_file): - logging.warning("file %s (for module %s) not found", - module_file, module) - return False - else: - return True - - def find_package_modules(self, package, package_dir): - self.check_package(package, package_dir) - module_files = glob(os.path.join(package_dir, "*.py")) - modules = [] - setup_script = os.path.abspath(self.distribution.script_name) - - for f in module_files: - abs_f = os.path.abspath(f) - if abs_f != setup_script: - module = os.path.splitext(os.path.basename(f))[0] - modules.append((package, module, f)) - else: - self.debug_print("excluding %s" % setup_script) - return modules - - def find_modules(self): - """Finds individually-specified Python modules, ie. those listed by - module name in 'self.py_modules'. Returns a list of tuples (package, - module_base, filename): 'package' is a tuple of the path through - package-space to the module; 'module_base' is the bare (no - packages, no dots) module name, and 'filename' is the path to the - ".py" file (relative to the distribution root) that implements the - module. - """ - # Map package names to tuples of useful info about the package: - # (package_dir, checked) - # package_dir - the directory where we'll find source files for - # this package - # checked - true if we have checked that the package directory - # is valid (exists, contains __init__.py, ... ?) - packages = {} - - # List of (package, module, filename) tuples to return - modules = [] - - # We treat modules-in-packages almost the same as toplevel modules, - # just the "package" for a toplevel is empty (either an empty - # string or empty list, depending on context). Differences: - # - don't check for __init__.py in directory for empty package - for module in self.py_modules: - path = module.split('.') - package = '.'.join(path[0:-1]) - module_base = path[-1] - - try: - (package_dir, checked) = packages[package] - except KeyError: - package_dir = self.get_package_dir(package) - checked = 0 - - if not checked: - init_py = self.check_package(package, package_dir) - packages[package] = (package_dir, 1) - if init_py: - modules.append((package, "__init__", init_py)) - - # XXX perhaps we should also check for just .pyc files - # (so greedy closed-source bastards can distribute Python - # modules too) - module_file = os.path.join(package_dir, module_base + ".py") - if not self.check_module(module, module_file): - continue - - modules.append((package, module_base, module_file)) - - return modules - - def find_all_modules(self): - """Compute the list of all modules that will be built, whether - they are specified one-module-at-a-time ('self.py_modules') or - by whole packages ('self.packages'). Return a list of tuples - (package, module, module_file), just like 'find_modules()' and - 'find_package_modules()' do.""" - modules = [] - if self.py_modules: - modules.extend(self.find_modules()) - if self.packages: - for package in self.packages: - package_dir = self.get_package_dir(package) - m = self.find_package_modules(package, package_dir) - modules.extend(m) - return modules - - def get_source_files(self): - sources = [module[-1] for module in self.find_all_modules()] - sources += [ - os.path.join(src_dir, filename) - for package, src_dir, build_dir, filenames in self.data_files - for filename in filenames] - return sources - - def get_module_outfile(self, build_dir, package, module): - outfile_path = [build_dir] + list(package) + [module + ".py"] - return os.path.join(*outfile_path) - - def get_outputs(self, include_bytecode=1): - modules = self.find_all_modules() - outputs = [] - for (package, module, module_file) in modules: - package = package.split('.') - filename = self.get_module_outfile(self.build_lib, package, module) - outputs.append(filename) - if include_bytecode: - if self.compile: - outputs.append(filename + "c") - if self.optimize > 0: - outputs.append(filename + "o") - - outputs += [ - os.path.join(build_dir, filename) - for package, src_dir, build_dir, filenames in self.data_files - for filename in filenames] - - return outputs - - def build_module(self, module, module_file, package): - if isinstance(package, str): - package = package.split('.') - elif not isinstance(package, (list, tuple)): - raise TypeError( - "'package' must be a string (dot-separated), list, or tuple") - - # Now put the module source file into the "build" area -- this is - # easy, we just copy it somewhere under self.build_lib (the build - # directory for Python source). - outfile = self.get_module_outfile(self.build_lib, package, module) - dir = os.path.dirname(outfile) - self.mkpath(dir) - return self.copy_file(module_file, outfile, preserve_mode=0) - - def build_modules(self): - modules = self.find_modules() - for (package, module, module_file) in modules: - - # Now "build" the module -- ie. copy the source file to - # self.build_lib (the build directory for Python source). - # (Actually, it gets copied to the directory for this package - # under self.build_lib.) - self.build_module(module, module_file, package) - - def build_packages(self): - for package in self.packages: - - # Get list of (package, module, module_file) tuples based on - # scanning the package directory. 'package' is only included - # in the tuple so that 'find_modules()' and - # 'find_package_tuples()' have a consistent interface; it's - # ignored here (apart from a sanity check). Also, 'module' is - # the *unqualified* module name (ie. no dots, no package -- we - # already know its package!), and 'module_file' is the path to - # the .py file, relative to the current directory - # (ie. including 'package_dir'). - package_dir = self.get_package_dir(package) - modules = self.find_package_modules(package, package_dir) - - # Now loop over the modules we found, "building" each one (just - # copy it to self.build_lib). - for (package_, module, module_file) in modules: - assert package == package_ - self.build_module(module, module_file, package) - - def byte_compile(self, files): - if hasattr(sys, 'dont_write_bytecode') and sys.dont_write_bytecode: - self.warn('byte-compiling is disabled, skipping.') - return - - from distutils2.util import byte_compile - prefix = self.build_lib - if prefix[-1] != os.sep: - prefix = prefix + os.sep - - # XXX this code is essentially the same as the 'byte_compile() - # method of the "install_lib" command, except for the determination - # of the 'prefix' string. Hmmm. - - if self.compile: - byte_compile(files, optimize=0, - force=self.force, prefix=prefix, dry_run=self.dry_run) - if self.optimize > 0: - byte_compile(files, optimize=self.optimize, - force=self.force, prefix=prefix, dry_run=self.dry_run) diff --git a/src/distutils2/command/build_scripts.py b/src/distutils2/command/build_scripts.py deleted file mode 100644 index 758e4d6..0000000 --- a/src/distutils2/command/build_scripts.py +++ /dev/null @@ -1,139 +0,0 @@ -"""distutils.command.build_scripts - -Implements the Distutils 'build_scripts' command.""" - -__revision__ = "$Id: build_scripts.py 77704 2010-01-23 09:23:15Z tarek.ziade $" - -import os, re -from stat import ST_MODE -from distutils2.core import Command -from distutils2.util import convert_path, newer -from distutils2 import log -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig -from distutils2.compat import Mixin2to3 - -# check if Python is called on the first line with this expression -first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$') - -class build_scripts (Command, Mixin2to3): - - description = "\"build\" scripts (copy and fixup #! line)" - - user_options = [ - ('build-dir=', 'd', "directory to \"build\" (copy) to"), - ('force', 'f', "forcibly build everything (ignore file timestamps"), - ('executable=', 'e', "specify final destination interpreter path"), - ] - - boolean_options = ['force'] - - - def initialize_options (self): - self.build_dir = None - self.scripts = None - self.force = None - self.executable = None - self.outfiles = None - self.use_2to3 = False - self.convert_2to3_doctests = None - self.use_2to3_fixers = None - - def finalize_options (self): - self.set_undefined_options('build', - ('build_scripts', 'build_dir'), - 'use_2to3', 'use_2to3_fixers', - 'convert_2to3_doctests', 'force', - 'executable') - self.scripts = self.distribution.scripts - - def get_source_files(self): - return self.scripts - - def run (self): - if not self.scripts: - return - copied_files = self.copy_scripts() - if self.use_2to3 and self.copied_files: - self._run_2to3(self.copied_files, fixers=self.use_2to3_fixers) - - def copy_scripts (self): - """Copy each script listed in 'self.scripts'; if it's marked as a - Python script in the Unix way (first line matches 'first_line_re', - ie. starts with "\#!" and contains "python"), then adjust the first - line to refer to the current Python interpreter as we copy. - """ - self.mkpath(self.build_dir) - outfiles = [] - for script in self.scripts: - adjust = 0 - script = convert_path(script) - outfile = os.path.join(self.build_dir, os.path.basename(script)) - outfiles.append(outfile) - - if not self.force and not newer(script, outfile): - log.debug("not copying %s (up-to-date)", script) - continue - - # Always open the file, but ignore failures in dry-run mode -- - # that way, we'll get accurate feedback if we can read the - # script. - try: - f = open(script, "r") - except IOError: - if not self.dry_run: - raise - f = None - else: - first_line = f.readline() - if not first_line: - self.warn("%s is an empty file (skipping)" % script) - continue - - match = first_line_re.match(first_line) - if match: - adjust = 1 - post_interp = match.group(1) or '' - - if adjust: - log.info("copying and adjusting %s -> %s", script, - self.build_dir) - if not self.dry_run: - outf = open(outfile, "w") - if not sysconfig.is_python_build(): - outf.write("#!%s%s\n" % - (self.executable, - post_interp)) - else: - outf.write("#!%s%s\n" % - (os.path.join( - sysconfig.get_config_var("BINDIR"), - "python%s%s" % (sysconfig.get_config_var("VERSION"), - sysconfig.get_config_var("EXE"))), - post_interp)) - outf.writelines(f.readlines()) - outf.close() - if f: - f.close() - else: - if f: - f.close() - self.copy_file(script, outfile) - - if os.name == 'posix': - for file in outfiles: - if self.dry_run: - log.info("changing mode of %s", file) - else: - oldmode = os.stat(file)[ST_MODE] & 07777 - newmode = (oldmode | 0555) & 07777 - if newmode != oldmode: - log.info("changing mode of %s from %o to %o", - file, oldmode, newmode) - os.chmod(file, newmode) - return outfiles - # copy_scripts () - -# class build_scripts diff --git a/src/distutils2/command/check.py b/src/distutils2/command/check.py deleted file mode 100644 index cfb6694..0000000 --- a/src/distutils2/command/check.py +++ /dev/null @@ -1,88 +0,0 @@ -"""distutils.command.check - -Implements the Distutils 'check' command. -""" -__revision__ = "$Id: check.py 75266 2009-10-05 22:32:48Z andrew.kuchling $" - -from distutils2.core import Command -from distutils2.errors import DistutilsSetupError -from distutils2.util import resolve_name - -class check(Command): - """This command checks the metadata of the package. - """ - description = ("perform some checks on the package") - user_options = [('metadata', 'm', 'Verify metadata'), - ('all', 'a', - ('runs extended set of checks')), - ('strict', 's', - 'Will exit with an error if a check fails')] - - boolean_options = ['metadata', 'all', 'strict'] - - def initialize_options(self): - """Sets default values for options.""" - self.all = 0 - self.metadata = 1 - self.strict = 0 - self._warnings = [] - - def finalize_options(self): - pass - - def warn(self, msg): - """Counts the number of warnings that occurs.""" - self._warnings.append(msg) - return Command.warn(self, msg) - - def run(self): - """Runs the command.""" - # perform the various tests - if self.metadata: - self.check_metadata() - if self.all: - self.check_restructuredtext() - self.check_hooks_resolvable() - - # let's raise an error in strict mode, if we have at least - # one warning - if self.strict and len(self._warnings) > 0: - msg = '\n'.join(self._warnings) - raise DistutilsSetupError(msg) - - def check_metadata(self): - """Ensures that all required elements of metadata are supplied. - - name, version, URL, (author and author_email) or - (maintainer and maintainer_email)). - - Warns if any are missing. - """ - missing, __ = self.distribution.metadata.check() - if missing != []: - self.warn("missing required metadata: %s" % ', '.join(missing)) - - def check_restructuredtext(self): - """Checks if the long string fields are reST-compliant.""" - missing, warnings = self.distribution.metadata.check() - if self.distribution.metadata.docutils_support: - for warning in warnings: - line = warning[-1].get('line') - if line is None: - warning = warning[1] - else: - warning = '%s (line %s)' % (warning[1], line) - self.warn(warning) - elif self.strict: - raise DistutilsSetupError('The docutils package is needed.') - - def check_hooks_resolvable(self): - for options in self.distribution.command_options.values(): - for hook_kind in ("pre_hook", "post_hook"): - if hook_kind not in options: - break - for hook_name in options[hook_kind][1].values(): - try: - resolve_name(hook_name) - except ImportError: - self.warn("Name '%s' cannot be resolved." % hook_name) diff --git a/src/distutils2/command/clean.py b/src/distutils2/command/clean.py deleted file mode 100644 index 8125dcd..0000000 --- a/src/distutils2/command/clean.py +++ /dev/null @@ -1,82 +0,0 @@ -"""distutils.command.clean - -Implements the Distutils 'clean' command.""" - -# contributed by Bastian Kleineidam <calvin@cs.uni-sb.de>, added 2000-03-18 - -__revision__ = "$Id: clean.py 70886 2009-03-31 20:50:59Z tarek.ziade $" - -import os -from shutil import rmtree -from distutils2.core import Command -from distutils2 import log - -class clean(Command): - - description = "clean up temporary files from 'build' command" - user_options = [ - ('build-base=', 'b', - "base build directory (default: 'build.build-base')"), - ('build-lib=', None, - "build directory for all modules (default: 'build.build-lib')"), - ('build-temp=', 't', - "temporary build directory (default: 'build.build-temp')"), - ('build-scripts=', None, - "build directory for scripts (default: 'build.build-scripts')"), - ('bdist-base=', None, - "temporary directory for built distributions"), - ('all', 'a', - "remove all build output, not just temporary by-products") - ] - - boolean_options = ['all'] - - def initialize_options(self): - self.build_base = None - self.build_lib = None - self.build_temp = None - self.build_scripts = None - self.bdist_base = None - self.all = None - - def finalize_options(self): - self.set_undefined_options('build', 'build_base', 'build_lib', - 'build_scripts', 'build_temp') - self.set_undefined_options('bdist', 'bdist_base') - - def run(self): - # remove the build/temp.<plat> directory (unless it's already - # gone) - if os.path.exists(self.build_temp): - if self.dry_run: - log.info('Removing %s' % self.build_temp) - else: - rmtree(self.build_temp) - else: - log.debug("'%s' does not exist -- can't clean it", - self.build_temp) - - if self.all: - # remove build directories - for directory in (self.build_lib, - self.bdist_base, - self.build_scripts): - if os.path.exists(directory): - if self.dry_run: - log.info('Removing %s' % directory) - else: - rmtree(directory) - else: - log.warn("'%s' does not exist -- can't clean it", - directory) - - # just for the heck of it, try to remove the base build directory: - # we might have emptied it right now, but if not we don't care - if not self.dry_run: - try: - os.rmdir(self.build_base) - log.info("removing '%s'", self.build_base) - except OSError: - pass - -# class clean diff --git a/src/distutils2/command/cmd.py b/src/distutils2/command/cmd.py deleted file mode 100644 index 17a4379..0000000 --- a/src/distutils2/command/cmd.py +++ /dev/null @@ -1,494 +0,0 @@ -"""distutils.cmd - -Provides the Command class, the base class for the command classes -in the distutils.command package. -""" - -__revision__ = "$Id: cmd.py 75192 2009-10-02 23:49:48Z tarek.ziade $" - -import os, re -from distutils2.errors import DistutilsOptionError -from distutils2 import util -from distutils2 import log - -# XXX see if we want to backport this -from distutils2._backport.shutil import copytree, copyfile, move - -try: - from shutil import make_archive -except ImportError: - from distutils2._backport.shutil import make_archive - -class Command(object): - """Abstract base class for defining command classes, the "worker bees" - of the Distutils. A useful analogy for command classes is to think of - them as subroutines with local variables called "options". The options - are "declared" in 'initialize_options()' and "defined" (given their - final values, aka "finalized") in 'finalize_options()', both of which - must be defined by every command class. The distinction between the - two is necessary because option values might come from the outside - world (command line, config file, ...), and any options dependent on - other options must be computed *after* these outside influences have - been processed -- hence 'finalize_options()'. The "body" of the - subroutine, where it does all its work based on the values of its - options, is the 'run()' method, which must also be implemented by every - command class. - """ - - # 'sub_commands' formalizes the notion of a "family" of commands, - # eg. "install" as the parent with sub-commands "install_lib", - # "install_headers", etc. The parent of a family of commands - # defines 'sub_commands' as a class attribute; it's a list of - # (command_name : string, predicate : unbound_method | string | None) - # tuples, where 'predicate' is a method of the parent command that - # determines whether the corresponding command is applicable in the - # current situation. (Eg. we "install_headers" is only applicable if - # we have any C header files to install.) If 'predicate' is None, - # that command is always applicable. - # - # 'sub_commands' is usually defined at the *end* of a class, because - # predicates can be unbound methods, so they must already have been - # defined. The canonical example is the "install" command. - sub_commands = [] - - # Pre and post command hooks are run just before or just after the command - # itself. They are simple functions that receive the command instance. They - # are specified as callable objects or dotted strings (for lazy loading). - pre_hook = None - post_hook = None - - - # -- Creation/initialization methods ------------------------------- - - def __init__(self, dist): - """Create and initialize a new Command object. Most importantly, - invokes the 'initialize_options()' method, which is the real - initializer and depends on the actual command being instantiated. - """ - # late import because of mutual dependence between these classes - from distutils2.dist import Distribution - - if not isinstance(dist, Distribution): - raise TypeError, "dist must be a Distribution instance" - if self.__class__ is Command: - raise RuntimeError, "Command is an abstract class" - - self.distribution = dist - self.initialize_options() - - # Per-command versions of the global flags, so that the user can - # customize Distutils' behaviour command-by-command and let some - # commands fall back on the Distribution's behaviour. None means - # "not defined, check self.distribution's copy", while 0 or 1 mean - # false and true (duh). Note that this means figuring out the real - # value of each flag is a touch complicated -- hence "self._dry_run" - # will be handled by a property, below. - # XXX This needs to be fixed. [I changed it to a property--does that - # "fix" it?] - self._dry_run = None - - # verbose is largely ignored, but needs to be set for - # backwards compatibility (I think)? - self.verbose = dist.verbose - - # Some commands define a 'self.force' option to ignore file - # timestamps, but methods defined *here* assume that - # 'self.force' exists for all commands. So define it here - # just to be safe. - self.force = None - - # The 'help' flag is just used for command line parsing, so - # none of that complicated bureaucracy is needed. - self.help = 0 - - # 'finalized' records whether or not 'finalize_options()' has been - # called. 'finalize_options()' itself should not pay attention to - # this flag: it is the business of 'ensure_finalized()', which - # always calls 'finalize_options()', to respect/update it. - self.finalized = 0 - - # XXX A more explicit way to customize dry_run would be better. - @property - def dry_run(self): - if self._dry_run is None: - return getattr(self.distribution, 'dry_run') - else: - return self._dry_run - - def ensure_finalized(self): - if not self.finalized: - self.finalize_options() - self.finalized = 1 - - # Subclasses must define: - # initialize_options() - # provide default values for all options; may be customized by - # setup script, by options from config file(s), or by command-line - # options - # finalize_options() - # decide on the final values for all options; this is called - # after all possible intervention from the outside world - # (command line, option file, etc.) has been processed - # run() - # run the command: do whatever it is we're here to do, - # controlled by the command's various option values - - def initialize_options(self): - """Set default values for all the options that this command - supports. Note that these defaults may be overridden by other - commands, by the setup script, by config files, or by the - command line. Thus, this is not the place to code dependencies - between options; generally, 'initialize_options()' implementations - are just a bunch of "self.foo = None" assignments. - - This method must be implemented by all command classes. - """ - raise RuntimeError, \ - "abstract method -- subclass %s must override" % self.__class__ - - def finalize_options(self): - """Set final values for all the options that this command supports. - This is always called as late as possible, ie. after any option - assignments from the command line or from other commands have been - done. Thus, this is the place to code option dependencies: if - 'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as - long as 'foo' still has the same value it was assigned in - 'initialize_options()'. - - This method must be implemented by all command classes. - """ - raise RuntimeError, \ - "abstract method -- subclass %s must override" % self.__class__ - - - def dump_options(self, header=None, indent=""): - if header is None: - header = "command options for '%s':" % self.get_command_name() - self.announce(indent + header, level=log.INFO) - indent = indent + " " - for (option, _, _) in self.user_options: - option = option.replace('-', '_') - if option[-1] == "=": - option = option[:-1] - value = getattr(self, option) - self.announce(indent + "%s = %s" % (option, value), - level=log.INFO) - - def run(self): - """A command's raison d'etre: carry out the action it exists to - perform, controlled by the options initialized in - 'initialize_options()', customized by other commands, the setup - script, the command line and config files, and finalized in - 'finalize_options()'. All terminal output and filesystem - interaction should be done by 'run()'. - - This method must be implemented by all command classes. - """ - raise RuntimeError, \ - "abstract method -- subclass %s must override" % self.__class__ - - def announce(self, msg, level=1): - """If the current verbosity level is of greater than or equal to - 'level' print 'msg' to stdout. - """ - log.log(level, msg) - - # -- External interface -------------------------------------------- - # (called by outsiders) - - def get_source_files(self): - """Return the list of files that are used as inputs to this command, - i.e. the files used to generate the output files. The result is used - by the `sdist` command in determining the set of default files. - - Command classes should implement this method if they operate on files - from the source tree. - """ - return [] - - def get_outputs(self): - """Return the list of files that would be produced if this command - were actually run. Not affected by the "dry-run" flag or whether - any other commands have been run. - - Command classes should implement this method if they produce any - output files that get consumed by another command. e.g., `build_ext` - returns the list of built extension modules, but not any temporary - files used in the compilation process. - """ - return [] - - # -- Option validation methods ------------------------------------- - # (these are very handy in writing the 'finalize_options()' method) - # - # NB. the general philosophy here is to ensure that a particular option - # value meets certain type and value constraints. If not, we try to - # force it into conformance (eg. if we expect a list but have a string, - # split the string on comma and/or whitespace). If we can't force the - # option into conformance, raise DistutilsOptionError. Thus, command - # classes need do nothing more than (eg.) - # self.ensure_string_list('foo') - # and they can be guaranteed that thereafter, self.foo will be - # a list of strings. - - def _ensure_stringlike(self, option, what, default=None): - val = getattr(self, option) - if val is None: - setattr(self, option, default) - return default - elif not isinstance(val, str): - raise DistutilsOptionError, \ - "'%s' must be a %s (got `%s`)" % (option, what, val) - return val - - def ensure_string(self, option, default=None): - """Ensure that 'option' is a string; if not defined, set it to - 'default'. - """ - self._ensure_stringlike(option, "string", default) - - def ensure_string_list(self, option): - """Ensure that 'option' is a list of strings. If 'option' is - currently a string, we split it either on /,\s*/ or /\s+/, so - "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become - ["foo", "bar", "baz"]. - """ - val = getattr(self, option) - if val is None: - return - elif isinstance(val, str): - setattr(self, option, re.split(r',\s*|\s+', val)) - else: - if isinstance(val, list): - # checks if all elements are str - ok = 1 - for element in val: - if not isinstance(element, str): - ok = 0 - break - else: - ok = 0 - - if not ok: - raise DistutilsOptionError, \ - "'%s' must be a list of strings (got %r)" % \ - (option, val) - - - def _ensure_tested_string(self, option, tester, - what, error_fmt, default=None): - val = self._ensure_stringlike(option, what, default) - if val is not None and not tester(val): - raise DistutilsOptionError, \ - ("error in '%s' option: " + error_fmt) % (option, val) - - def ensure_filename(self, option): - """Ensure that 'option' is the name of an existing file.""" - self._ensure_tested_string(option, os.path.isfile, - "filename", - "'%s' does not exist or is not a file") - - def ensure_dirname(self, option): - self._ensure_tested_string(option, os.path.isdir, - "directory name", - "'%s' does not exist or is not a directory") - - - # -- Convenience methods for commands ------------------------------ - - def get_command_name(self): - if hasattr(self, 'command_name'): - return self.command_name - else: - return self.__class__.__name__ - - def set_undefined_options(self, src_cmd, *options): - """Set values of undefined options from another command. - - Undefined options are options set to None, which is the convention - used to indicate that an option has not been changed between - 'initialize_options()' and 'finalize_options()'. This method is - usually called from 'finalize_options()' for options that depend on - some other command rather than another option of the same command, - typically subcommands. - - The 'src_cmd' argument is the other command from which option values - will be taken (a command object will be created for it if necessary); - the remaining positional arguments are strings that give the name of - the option to set. If the name is different on the source and target - command, you can pass a tuple with '(name_on_source, name_on_dest)' so - that 'self.name_on_dest' will be set from 'src_cmd.name_on_source'. - """ - src_cmd_obj = self.distribution.get_command_obj(src_cmd) - src_cmd_obj.ensure_finalized() - for obj in options: - if isinstance(obj, tuple): - src_option, dst_option = obj - else: - src_option, dst_option = obj, obj - if getattr(self, dst_option) is None: - setattr(self, dst_option, - getattr(src_cmd_obj, src_option)) - - def get_finalized_command(self, command, create=1): - """Wrapper around Distribution's 'get_command_obj()' method: find - (create if necessary and 'create' is true) the command object for - 'command', call its 'ensure_finalized()' method, and return the - finalized command object. - """ - cmd_obj = self.distribution.get_command_obj(command, create) - cmd_obj.ensure_finalized() - return cmd_obj - - def get_reinitialized_command(self, command, reinit_subcommands=0): - return self.distribution.get_reinitialized_command( - command, reinit_subcommands) - - def run_command(self, command): - """Run some other command: uses the 'run_command()' method of - Distribution, which creates and finalizes the command object if - necessary and then invokes its 'run()' method. - """ - self.distribution.run_command(command) - - def get_sub_commands(self): - """Determine the sub-commands that are relevant in the current - distribution (ie., that need to be run). This is based on the - 'sub_commands' class attribute: each tuple in that list may include - a method that we call to determine if the subcommand needs to be - run for the current distribution. Return a list of command names. - """ - commands = [] - for (cmd_name, method) in self.sub_commands: - if method is None or method(self): - commands.append(cmd_name) - return commands - - - # -- External world manipulation ----------------------------------- - - def warn(self, msg): - log.warn("warning: %s: %s\n" % - (self.get_command_name(), msg)) - - def execute(self, func, args, msg=None, level=1): - util.execute(func, args, msg, dry_run=self.dry_run) - - def mkpath(self, name, mode=0777, dry_run=None, verbose=0): - if dry_run is None: - dry_run = self.dry_run - name = os.path.normpath(name) - if os.path.isdir(name) or name == '': - return - if dry_run: - head = '' - for part in name.split(os.sep): - log.info("created directory %s%s", head, part) - head += part + os.sep - return - os.makedirs(name, mode) - - def copy_file(self, infile, outfile, - preserve_mode=1, preserve_times=1, link=None, level=1): - """Copy a file respecting verbose, dry-run and force flags. (The - former two default to whatever is in the Distribution object, and - the latter defaults to false for commands that don't define it.)""" - if self.dry_run: - # XXX add a comment - return - if os.path.isdir(outfile): - outfile = os.path.join(outfile, os.path.split(infile)[-1]) - copyfile(infile, outfile) - return outfile, None # XXX - - def copy_tree(self, infile, outfile, - preserve_mode=1, preserve_times=1, preserve_symlinks=0, - level=1): - """Copy an entire directory tree respecting verbose, dry-run, - and force flags. - """ - if self.dry_run: - return # see if we want to display something - return copytree(infile, outfile, preserve_symlinks) - - def move_file(self, src, dst, level=1): - """Move a file respectin dry-run flag.""" - if self.dry_run: - return # XXX log ? - return move(src, dst) - - def spawn(self, cmd, search_path=1, level=1): - """Spawn an external command respecting dry-run flag.""" - from distutils2.util import spawn - spawn(cmd, search_path, dry_run= self.dry_run) - - def make_archive(self, base_name, format, root_dir=None, base_dir=None, - owner=None, group=None): - return make_archive(base_name, format, root_dir, - base_dir, dry_run=self.dry_run, - owner=owner, group=group) - - def make_file(self, infiles, outfile, func, args, - exec_msg=None, skip_msg=None, level=1): - """Special case of 'execute()' for operations that process one or - more input files and generate one output file. Works just like - 'execute()', except the operation is skipped and a different - message printed if 'outfile' already exists and is newer than all - files listed in 'infiles'. If the command defined 'self.force', - and it is true, then the command is unconditionally run -- does no - timestamp checks. - """ - if skip_msg is None: - skip_msg = "skipping %s (inputs unchanged)" % outfile - - # Allow 'infiles' to be a single string - if isinstance(infiles, str): - infiles = (infiles,) - elif not isinstance(infiles, (list, tuple)): - raise TypeError, \ - "'infiles' must be a string, or a list or tuple of strings" - - if exec_msg is None: - exec_msg = "generating %s from %s" % \ - (outfile, ', '.join(infiles)) - - # If 'outfile' must be regenerated (either because it doesn't - # exist, is out-of-date, or the 'force' flag is true) then - # perform the action that presumably regenerates it - if self.force or util.newer_group(infiles, outfile): - self.execute(func, args, exec_msg, level) - - # Otherwise, print the "skip" message - else: - log.debug(skip_msg) - -# XXX 'install_misc' class not currently used -- it was the base class for -# both 'install_scripts' and 'install_data', but they outgrew it. It might -# still be useful for 'install_headers', though, so I'm keeping it around -# for the time being. - -class install_misc(Command): - """Common base class for installing some files in a subdirectory. - Currently used by install_data and install_scripts. - """ - - user_options = [('install-dir=', 'd', "directory to install the files to")] - - def initialize_options (self): - self.install_dir = None - self.outfiles = [] - - def _install_dir_from(self, dirname): - self.set_undefined_options('install', (dirname, 'install_dir')) - - def _copy_files(self, filelist): - self.outfiles = [] - if not filelist: - return - self.mkpath(self.install_dir) - for f in filelist: - self.copy_file(f, self.install_dir) - self.outfiles.append(os.path.join(self.install_dir, f)) - - def get_outputs(self): - return self.outfiles diff --git a/src/distutils2/command/command_template b/src/distutils2/command/command_template deleted file mode 100644 index 50bbab7..0000000 --- a/src/distutils2/command/command_template +++ /dev/null @@ -1,45 +0,0 @@ -"""distutils.command.x - -Implements the Distutils 'x' command. -""" - -# created 2000/mm/dd, John Doe - -__revision__ = "$Id$" - -from distutils.core import Command - - -class x (Command): - - # Brief (40-50 characters) description of the command - description = "" - - # List of option tuples: long name, short name (None if no short - # name), and help string. - user_options = [('', '', - ""), - ] - - - def initialize_options (self): - self. = None - self. = None - self. = None - - # initialize_options() - - - def finalize_options (self): - if self.x is None: - self.x = - - # finalize_options() - - - def run (self): - - - # run() - -# class x diff --git a/src/distutils2/command/config.py b/src/distutils2/command/config.py deleted file mode 100644 index ab26f77..0000000 --- a/src/distutils2/command/config.py +++ /dev/null @@ -1,357 +0,0 @@ -"""distutils.command.config - -Implements the Distutils 'config' command, a (mostly) empty command class -that exists mainly to be sub-classed by specific module distributions and -applications. The idea is that while every "config" command is different, -at least they're all named the same, and users always see "config" in the -list of standard commands. Also, this is a good place to put common -configure-like tasks: "try to compile this C code", or "figure out where -this header file lives". -""" - -__revision__ = "$Id: config.py 77704 2010-01-23 09:23:15Z tarek.ziade $" - -import os -import re - -from distutils2.core import Command -from distutils2.errors import DistutilsExecError -from distutils2.compiler.ccompiler import customize_compiler -from distutils2 import log - -LANG_EXT = {'c': '.c', 'c++': '.cxx'} - -class config(Command): - - description = "prepare to build" - - user_options = [ - ('compiler=', None, - "specify the compiler type"), - ('cc=', None, - "specify the compiler executable"), - ('include-dirs=', 'I', - "list of directories to search for header files"), - ('define=', 'D', - "C preprocessor macros to define"), - ('undef=', 'U', - "C preprocessor macros to undefine"), - ('libraries=', 'l', - "external C libraries to link with"), - ('library-dirs=', 'L', - "directories to search for external C libraries"), - - ('noisy', None, - "show every action (compile, link, run, ...) taken"), - ('dump-source', None, - "dump generated source files before attempting to compile them"), - ] - - - # The three standard command methods: since the "config" command - # does nothing by default, these are empty. - - def initialize_options(self): - self.compiler = None - self.cc = None - self.include_dirs = None - self.libraries = None - self.library_dirs = None - - # maximal output for now - self.noisy = 1 - self.dump_source = 1 - - # list of temporary files generated along-the-way that we have - # to clean at some point - self.temp_files = [] - - def finalize_options(self): - if self.include_dirs is None: - self.include_dirs = self.distribution.include_dirs or [] - elif isinstance(self.include_dirs, str): - self.include_dirs = self.include_dirs.split(os.pathsep) - - if self.libraries is None: - self.libraries = [] - elif isinstance(self.libraries, str): - self.libraries = [self.libraries] - - if self.library_dirs is None: - self.library_dirs = [] - elif isinstance(self.library_dirs, str): - self.library_dirs = self.library_dirs.split(os.pathsep) - - def run(self): - pass - - - # Utility methods for actual "config" commands. The interfaces are - # loosely based on Autoconf macros of similar names. Sub-classes - # may use these freely. - - def _check_compiler(self): - """Check that 'self.compiler' really is a CCompiler object; - if not, make it one. - """ - # We do this late, and only on-demand, because this is an expensive - # import. - from distutils2.compiler.ccompiler import CCompiler, new_compiler - if not isinstance(self.compiler, CCompiler): - self.compiler = new_compiler(compiler=self.compiler, - dry_run=self.dry_run, force=1) - customize_compiler(self.compiler) - if self.include_dirs: - self.compiler.set_include_dirs(self.include_dirs) - if self.libraries: - self.compiler.set_libraries(self.libraries) - if self.library_dirs: - self.compiler.set_library_dirs(self.library_dirs) - - - def _gen_temp_sourcefile(self, body, headers, lang): - filename = "_configtest" + LANG_EXT[lang] - file = open(filename, "w") - if headers: - for header in headers: - file.write("#include <%s>\n" % header) - file.write("\n") - file.write(body) - if body[-1] != "\n": - file.write("\n") - file.close() - return filename - - def _preprocess(self, body, headers, include_dirs, lang): - src = self._gen_temp_sourcefile(body, headers, lang) - out = "_configtest.i" - self.temp_files.extend([src, out]) - self.compiler.preprocess(src, out, include_dirs=include_dirs) - return (src, out) - - def _compile(self, body, headers, include_dirs, lang): - src = self._gen_temp_sourcefile(body, headers, lang) - if self.dump_source: - dump_file(src, "compiling '%s':" % src) - (obj,) = self.compiler.object_filenames([src]) - self.temp_files.extend([src, obj]) - self.compiler.compile([src], include_dirs=include_dirs) - return (src, obj) - - def _link(self, body, headers, include_dirs, libraries, library_dirs, - lang): - (src, obj) = self._compile(body, headers, include_dirs, lang) - prog = os.path.splitext(os.path.basename(src))[0] - self.compiler.link_executable([obj], prog, - libraries=libraries, - library_dirs=library_dirs, - target_lang=lang) - - if self.compiler.exe_extension is not None: - prog = prog + self.compiler.exe_extension - self.temp_files.append(prog) - - return (src, obj, prog) - - def _clean(self, *filenames): - if not filenames: - filenames = self.temp_files - self.temp_files = [] - log.info("removing: %s", ' '.join(filenames)) - for filename in filenames: - try: - os.remove(filename) - except OSError: - pass - - - # XXX these ignore the dry-run flag: what to do, what to do? even if - # you want a dry-run build, you still need some sort of configuration - # info. My inclination is to make it up to the real config command to - # consult 'dry_run', and assume a default (minimal) configuration if - # true. The problem with trying to do it here is that you'd have to - # return either true or false from all the 'try' methods, neither of - # which is correct. - - # XXX need access to the header search path and maybe default macros. - - def try_cpp(self, body=None, headers=None, include_dirs=None, lang="c"): - """Construct a source file from 'body' (a string containing lines - of C/C++ code) and 'headers' (a list of header files to include) - and run it through the preprocessor. Return true if the - preprocessor succeeded, false if there were any errors. - ('body' probably isn't of much use, but what the heck.) - """ - from distutils2.compiler.ccompiler import CompileError - self._check_compiler() - ok = 1 - try: - self._preprocess(body, headers, include_dirs, lang) - except CompileError: - ok = 0 - - self._clean() - return ok - - def search_cpp(self, pattern, body=None, headers=None, include_dirs=None, - lang="c"): - """Construct a source file (just like 'try_cpp()'), run it through - the preprocessor, and return true if any line of the output matches - 'pattern'. 'pattern' should either be a compiled regex object or a - string containing a regex. If both 'body' and 'headers' are None, - preprocesses an empty file -- which can be useful to determine the - symbols the preprocessor and compiler set by default. - """ - self._check_compiler() - src, out = self._preprocess(body, headers, include_dirs, lang) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - file = open(out) - match = 0 - while 1: - line = file.readline() - if line == '': - break - if pattern.search(line): - match = 1 - break - - file.close() - self._clean() - return match - - def try_compile(self, body, headers=None, include_dirs=None, lang="c"): - """Try to compile a source file built from 'body' and 'headers'. - Return true on success, false otherwise. - """ - from distutils2.compiler.ccompiler import CompileError - self._check_compiler() - try: - self._compile(body, headers, include_dirs, lang) - ok = 1 - except CompileError: - ok = 0 - - log.info(ok and "success!" or "failure.") - self._clean() - return ok - - def try_link(self, body, headers=None, include_dirs=None, libraries=None, - library_dirs=None, lang="c"): - """Try to compile and link a source file, built from 'body' and - 'headers', to executable form. Return true on success, false - otherwise. - """ - from distutils2.compiler.ccompiler import CompileError, LinkError - self._check_compiler() - try: - self._link(body, headers, include_dirs, - libraries, library_dirs, lang) - ok = 1 - except (CompileError, LinkError): - ok = 0 - - log.info(ok and "success!" or "failure.") - self._clean() - return ok - - def try_run(self, body, headers=None, include_dirs=None, libraries=None, - library_dirs=None, lang="c"): - """Try to compile, link to an executable, and run a program - built from 'body' and 'headers'. Return true on success, false - otherwise. - """ - from distutils2.compiler.ccompiler import CompileError, LinkError - self._check_compiler() - try: - src, obj, exe = self._link(body, headers, include_dirs, - libraries, library_dirs, lang) - self.spawn([exe]) - ok = 1 - except (CompileError, LinkError, DistutilsExecError): - ok = 0 - - log.info(ok and "success!" or "failure.") - self._clean() - return ok - - - # -- High-level methods -------------------------------------------- - # (these are the ones that are actually likely to be useful - # when implementing a real-world config command!) - - def check_func(self, func, headers=None, include_dirs=None, - libraries=None, library_dirs=None, decl=0, call=0): - - """Determine if function 'func' is available by constructing a - source file that refers to 'func', and compiles and links it. - If everything succeeds, returns true; otherwise returns false. - - The constructed source file starts out by including the header - files listed in 'headers'. If 'decl' is true, it then declares - 'func' (as "int func()"); you probably shouldn't supply 'headers' - and set 'decl' true in the same call, or you might get errors about - a conflicting declarations for 'func'. Finally, the constructed - 'main()' function either references 'func' or (if 'call' is true) - calls it. 'libraries' and 'library_dirs' are used when - linking. - """ - - self._check_compiler() - body = [] - if decl: - body.append("int %s ();" % func) - body.append("int main () {") - if call: - body.append(" %s();" % func) - else: - body.append(" %s;" % func) - body.append("}") - body = "\n".join(body) + "\n" - - return self.try_link(body, headers, include_dirs, - libraries, library_dirs) - - # check_func () - - def check_lib(self, library, library_dirs=None, headers=None, - include_dirs=None, other_libraries=[]): - """Determine if 'library' is available to be linked against, - without actually checking that any particular symbols are provided - by it. 'headers' will be used in constructing the source file to - be compiled, but the only effect of this is to check if all the - header files listed are available. Any libraries listed in - 'other_libraries' will be included in the link, in case 'library' - has symbols that depend on other libraries. - """ - self._check_compiler() - return self.try_link("int main (void) { }", - headers, include_dirs, - [library]+other_libraries, library_dirs) - - def check_header(self, header, include_dirs=None, library_dirs=None, - lang="c"): - """Determine if the system header file named by 'header_file' - exists and can be found by the preprocessor; return true if so, - false otherwise. - """ - return self.try_cpp(body="/* No body */", headers=[header], - include_dirs=include_dirs) - - -def dump_file(filename, head=None): - """Dumps a file content into log.info. - - If head is not None, will be dumped before the file content. - """ - if head is None: - log.info('%s' % filename) - else: - log.info(head) - file = open(filename) - try: - log.info(file.read()) - finally: - file.close() diff --git a/src/distutils2/command/install.py b/src/distutils2/command/install.py deleted file mode 100644 index 5692a93..0000000 --- a/src/distutils2/command/install.py +++ /dev/null @@ -1,626 +0,0 @@ -"""distutils.command.install - -Implements the Distutils 'install' command.""" - -__revision__ = "$Id: install.py 77949 2010-02-03 15:38:12Z tarek.ziade $" - -import sys -import os - -from distutils2._backport import sysconfig -from distutils2._backport.sysconfig import (get_config_vars, get_paths, - get_path, get_config_var) - -from distutils2 import log -from distutils2.core import Command -from distutils2.errors import DistutilsPlatformError -from distutils2.util import write_file -from distutils2.util import convert_path, change_root, get_platform -from distutils2.errors import DistutilsOptionError - -# compatibility with 2.4 and 2.5 -if sys.version < '2.6': - HAS_USER_SITE = False -else: - HAS_USER_SITE = True - - -class install(Command): - - description = "install everything from build directory" - - user_options = [ - # Select installation scheme and set base director(y|ies) - ('prefix=', None, - "installation prefix"), - ('exec-prefix=', None, - "(Unix only) prefix for platform-specific files"), - ('home=', None, - "(Unix only) home directory to install under"), - - # Or just set the base director(y|ies) - ('install-base=', None, - "base installation directory (instead of --prefix or --home)"), - ('install-platbase=', None, - "base installation directory for platform-specific files " + - "(instead of --exec-prefix or --home)"), - ('root=', None, - "install everything relative to this alternate root directory"), - - # Or explicitly set the installation scheme - ('install-purelib=', None, - "installation directory for pure Python module distributions"), - ('install-platlib=', None, - "installation directory for non-pure module distributions"), - ('install-lib=', None, - "installation directory for all module distributions " + - "(overrides --install-purelib and --install-platlib)"), - - ('install-headers=', None, - "installation directory for C/C++ headers"), - ('install-scripts=', None, - "installation directory for Python scripts"), - ('install-data=', None, - "installation directory for data files"), - - # Byte-compilation options -- see install_lib.py for details, as - # these are duplicated from there (but only install_lib does - # anything with them). - ('compile', 'c', "compile .py to .pyc [default]"), - ('no-compile', None, "don't compile .py files"), - ('optimize=', 'O', - 'also compile with optimization: -O1 for "python -O", ' - '-O2 for "python -OO", and -O0 to disable [default: -O0]'), - - # Miscellaneous control options - ('force', 'f', - "force installation (overwrite any existing files)"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - - # Where to install documentation (eventually!) - #('doc-format=', None, "format of documentation to generate"), - #('install-man=', None, "directory for Unix man pages"), - #('install-html=', None, "directory for HTML documentation"), - #('install-info=', None, "directory for GNU info files"), - - # XXX use a name that makes clear this is the old format - ('record=', None, - "filename in which to record a list of installed files " - "(not PEP 376-compliant)"), - - # .dist-info related arguments, read by install_dist_info - ('no-distinfo', None, - "do not create a .dist-info directory"), - ('installer=', None, - "the name of the installer"), - ('requested', None, - "generate a REQUESTED file (i.e."), - ('no-requested', None, - "do not generate a REQUESTED file"), - ('no-record', None, - "do not generate a RECORD file"), - ] - - boolean_options = ['compile', 'force', 'skip-build', 'no-distinfo', - 'requested', 'no-record'] - - if HAS_USER_SITE: - user_options.append( - ('user', None, - "install in user site-packages directory [%s]" % - get_path('purelib', '%s_user' % os.name))) - - boolean_options.append('user') - - negative_opt = {'no-compile': 'compile', 'no-requested': 'requested'} - - def initialize_options(self): - # High-level options: these select both an installation base - # and scheme. - self.prefix = None - self.exec_prefix = None - self.home = None - if HAS_USER_SITE: - self.user = 0 - - # These select only the installation base; it's up to the user to - # specify the installation scheme (currently, that means supplying - # the --install-{platlib,purelib,scripts,data} options). - self.install_base = None - self.install_platbase = None - self.root = None - - # These options are the actual installation directories; if not - # supplied by the user, they are filled in using the installation - # scheme implied by prefix/exec-prefix/home and the contents of - # that installation scheme. - self.install_purelib = None # for pure module distributions - self.install_platlib = None # non-pure (dists w/ extensions) - self.install_headers = None # for C/C++ headers - self.install_lib = None # set to either purelib or platlib - self.install_scripts = None - self.install_data = None - if HAS_USER_SITE: - self.install_userbase = get_config_var('userbase') - self.install_usersite = get_path('purelib', '%s_user' % os.name) - - self.compile = None - self.optimize = None - - # These two are for putting non-packagized distributions into their - # own directory and creating a .pth file if it makes sense. - # 'extra_path' comes from the setup file; 'install_path_file' can - # be turned off if it makes no sense to install a .pth file. (But - # better to install it uselessly than to guess wrong and not - # install it when it's necessary and would be used!) Currently, - # 'install_path_file' is always true unless some outsider meddles - # with it. - self.extra_path = None - self.install_path_file = 1 - - # 'force' forces installation, even if target files are not - # out-of-date. 'skip_build' skips running the "build" command, - # handy if you know it's not necessary. 'warn_dir' (which is *not* - # a user option, it's just there so the bdist_* commands can turn - # it off) determines whether we warn about installing to a - # directory not in sys.path. - self.force = 0 - self.skip_build = 0 - self.warn_dir = 1 - - # These are only here as a conduit from the 'build' command to the - # 'install_*' commands that do the real work. ('build_base' isn't - # actually used anywhere, but it might be useful in future.) They - # are not user options, because if the user told the install - # command where the build directory is, that wouldn't affect the - # build command. - self.build_base = None - self.build_lib = None - - # Not defined yet because we don't know anything about - # documentation yet. - #self.install_man = None - #self.install_html = None - #self.install_info = None - - self.record = None - - # .dist-info related options - self.no_distinfo = None - self.installer = None - self.requested = None - self.no_record = None - - # -- Option finalizing methods ------------------------------------- - # (This is rather more involved than for most commands, - # because this is where the policy for installing third- - # party Python modules on various platforms given a wide - # array of user input is decided. Yes, it's quite complex!) - - def finalize_options(self): - # This method (and its pliant slaves, like 'finalize_unix()', - # 'finalize_other()', and 'select_scheme()') is where the default - # installation directories for modules, extension modules, and - # anything else we care to install from a Python module - # distribution. Thus, this code makes a pretty important policy - # statement about how third-party stuff is added to a Python - # installation! Note that the actual work of installation is done - # by the relatively simple 'install_*' commands; they just take - # their orders from the installation directory options determined - # here. - - # Check for errors/inconsistencies in the options; first, stuff - # that's wrong on any platform. - - if ((self.prefix or self.exec_prefix or self.home) and - (self.install_base or self.install_platbase)): - raise DistutilsOptionError( - "must supply either prefix/exec-prefix/home or " - "install-base/install-platbase -- not both") - - if self.home and (self.prefix or self.exec_prefix): - raise DistutilsOptionError( - "must supply either home or prefix/exec-prefix -- not both") - - if HAS_USER_SITE and self.user and ( - self.prefix or self.exec_prefix or self.home or - self.install_base or self.install_platbase): - raise DistutilsOptionError( - "can't combine user with prefix/exec_prefix/home or " - "install_base/install_platbase") - - # Next, stuff that's wrong (or dubious) only on certain platforms. - if os.name != "posix": - if self.exec_prefix: - self.warn("exec-prefix option ignored on this platform") - self.exec_prefix = None - - # Now the interesting logic -- so interesting that we farm it out - # to other methods. The goal of these methods is to set the final - # values for the install_{lib,scripts,data,...} options, using as - # input a heady brew of prefix, exec_prefix, home, install_base, - # install_platbase, user-supplied versions of - # install_{purelib,platlib,lib,scripts,data,...}, and the - # INSTALL_SCHEME dictionary above. Phew! - - self.dump_dirs("pre-finalize_{unix,other}") - - if os.name == 'posix': - self.finalize_unix() - else: - self.finalize_other() - - self.dump_dirs("post-finalize_{unix,other}()") - - # Expand configuration variables, tilde, etc. in self.install_base - # and self.install_platbase -- that way, we can use $base or - # $platbase in the other installation directories and not worry - # about needing recursive variable expansion (shudder). - - py_version = sys.version.split()[0] - prefix, exec_prefix, srcdir, projectbase = get_config_vars( - 'prefix', 'exec_prefix', 'srcdir', 'projectbase') - - metadata = self.distribution.metadata - self.config_vars = { - 'dist_name': metadata['Name'], - 'dist_version': metadata['Version'], - 'dist_fullname': metadata.get_fullname(), - 'py_version': py_version, - 'py_version_short': py_version[:3], - 'py_version_nodot': py_version[:3:2], - 'sys_prefix': prefix, - 'prefix': prefix, - 'sys_exec_prefix': exec_prefix, - 'exec_prefix': exec_prefix, - 'srcdir': srcdir, - 'projectbase': projectbase, - } - - if HAS_USER_SITE: - self.config_vars['userbase'] = self.install_userbase - self.config_vars['usersite'] = self.install_usersite - - self.expand_basedirs() - - self.dump_dirs("post-expand_basedirs()") - - # Now define config vars for the base directories so we can expand - # everything else. - self.config_vars['base'] = self.install_base - self.config_vars['platbase'] = self.install_platbase - - # Expand "~" and configuration variables in the installation - # directories. - self.expand_dirs() - - self.dump_dirs("post-expand_dirs()") - - # Create directories in the home dir: - if HAS_USER_SITE and self.user: - self.create_home_path() - - # Pick the actual directory to install all modules to: either - # install_purelib or install_platlib, depending on whether this - # module distribution is pure or not. Of course, if the user - # already specified install_lib, use their selection. - if self.install_lib is None: - if self.distribution.ext_modules: # has extensions: non-pure - self.install_lib = self.install_platlib - else: - self.install_lib = self.install_purelib - - # Convert directories from Unix /-separated syntax to the local - # convention. - self.convert_paths('lib', 'purelib', 'platlib', - 'scripts', 'data', 'headers') - if HAS_USER_SITE: - self.convert_paths('userbase', 'usersite') - - # Well, we're not actually fully completely finalized yet: we still - # have to deal with 'extra_path', which is the hack for allowing - # non-packagized module distributions (hello, Numerical Python!) to - # get their own directories. - self.handle_extra_path() - self.install_libbase = self.install_lib # needed for .pth file - self.install_lib = os.path.join(self.install_lib, self.extra_dirs) - - # If a new root directory was supplied, make all the installation - # dirs relative to it. - if self.root is not None: - self.change_roots('libbase', 'lib', 'purelib', 'platlib', - 'scripts', 'data', 'headers') - - self.dump_dirs("after prepending root") - - # Find out the build directories, ie. where to install from. - self.set_undefined_options('build', 'build_base', 'build_lib') - - # Punt on doc directories for now -- after all, we're punting on - # documentation completely! - - if self.no_distinfo is None: - self.no_distinfo = False - - def finalize_unix(self): - """Finalize options for posix platforms.""" - if self.install_base is not None or self.install_platbase is not None: - if ((self.install_lib is None and - self.install_purelib is None and - self.install_platlib is None) or - self.install_headers is None or - self.install_scripts is None or - self.install_data is None): - raise DistutilsOptionError( - "install-base or install-platbase supplied, but " - "installation scheme is incomplete") - return - - if HAS_USER_SITE and self.user: - if self.install_userbase is None: - raise DistutilsPlatformError( - "user base directory is not specified") - self.install_base = self.install_platbase = self.install_userbase - self.select_scheme("posix_user") - elif self.home is not None: - self.install_base = self.install_platbase = self.home - self.select_scheme("posix_home") - else: - if self.prefix is None: - if self.exec_prefix is not None: - raise DistutilsOptionError( - "must not supply exec-prefix without prefix") - - self.prefix = os.path.normpath(sys.prefix) - self.exec_prefix = os.path.normpath(sys.exec_prefix) - - else: - if self.exec_prefix is None: - self.exec_prefix = self.prefix - - self.install_base = self.prefix - self.install_platbase = self.exec_prefix - self.select_scheme("posix_prefix") - - def finalize_other(self): - """Finalize options for non-posix platforms""" - if HAS_USER_SITE and self.user: - if self.install_userbase is None: - raise DistutilsPlatformError( - "user base directory is not specified") - self.install_base = self.install_platbase = self.install_userbase - self.select_scheme(os.name + "_user") - elif self.home is not None: - self.install_base = self.install_platbase = self.home - self.select_scheme("posix_home") - else: - if self.prefix is None: - self.prefix = os.path.normpath(sys.prefix) - - self.install_base = self.install_platbase = self.prefix - try: - self.select_scheme(os.name) - except KeyError: - raise DistutilsPlatformError( - "no support for installation on '%s'" % os.name) - - def dump_dirs(self, msg): - """Dump the list of user options.""" - log.debug(msg + ":") - for opt in self.user_options: - opt_name = opt[0] - if opt_name[-1] == "=": - opt_name = opt_name[0:-1] - if opt_name in self.negative_opt: - opt_name = self.negative_opt[opt_name] - opt_name = opt_name.replace('-', '_') - val = not getattr(self, opt_name) - else: - opt_name = opt_name.replace('-', '_') - val = getattr(self, opt_name) - log.debug(" %s: %s" % (opt_name, val)) - - def select_scheme(self, name): - """Set the install directories by applying the install schemes.""" - # it's the caller's problem if they supply a bad name! - scheme = get_paths(name, expand=False) - for key, value in scheme.items(): - if key == 'platinclude': - key = 'headers' - value = os.path.join(value, self.distribution.metadata['Name']) - attrname = 'install_' + key - if hasattr(self, attrname): - if getattr(self, attrname) is None: - setattr(self, attrname, value) - - def _expand_attrs(self, attrs): - for attr in attrs: - val = getattr(self, attr) - if val is not None: - if os.name == 'posix' or os.name == 'nt': - val = os.path.expanduser(val) - # see if we want to push this work in sysconfig XXX - val = sysconfig._subst_vars(val, self.config_vars) - setattr(self, attr, val) - - def expand_basedirs(self): - """Call `os.path.expanduser` on install_{base,platbase} and root.""" - self._expand_attrs(['install_base', 'install_platbase', 'root']) - - def expand_dirs(self): - """Call `os.path.expanduser` on install dirs.""" - self._expand_attrs(['install_purelib', 'install_platlib', - 'install_lib', 'install_headers', - 'install_scripts', 'install_data']) - - def convert_paths(self, *names): - """Call `convert_path` over `names`.""" - for name in names: - attr = "install_" + name - setattr(self, attr, convert_path(getattr(self, attr))) - - def handle_extra_path(self): - """Set `path_file` and `extra_dirs` using `extra_path`.""" - if self.extra_path is None: - self.extra_path = self.distribution.extra_path - - if self.extra_path is not None: - if isinstance(self.extra_path, str): - self.extra_path = self.extra_path.split(',') - - if len(self.extra_path) == 1: - path_file = extra_dirs = self.extra_path[0] - elif len(self.extra_path) == 2: - path_file, extra_dirs = self.extra_path - else: - raise DistutilsOptionError( - "'extra_path' option must be a list, tuple, or " - "comma-separated string with 1 or 2 elements") - - # convert to local form in case Unix notation used (as it - # should be in setup scripts) - extra_dirs = convert_path(extra_dirs) - else: - path_file = None - extra_dirs = '' - - # XXX should we warn if path_file and not extra_dirs? (in which - # case the path file would be harmless but pointless) - self.path_file = path_file - self.extra_dirs = extra_dirs - - def change_roots(self, *names): - """Change the install direcories pointed by name using root.""" - for name in names: - attr = "install_" + name - setattr(self, attr, change_root(self.root, getattr(self, attr))) - - def create_home_path(self): - """Create directories under ~.""" - if HAS_USER_SITE and not self.user: - return - home = convert_path(os.path.expanduser("~")) - for name, path in self.config_vars.iteritems(): - if path.startswith(home) and not os.path.isdir(path): - os.makedirs(path, 0700) - - # -- Command execution methods ------------------------------------- - - def run(self): - """Runs the command.""" - # Obviously have to build before we can install - if not self.skip_build: - self.run_command('build') - # If we built for any other platform, we can't install. - build_plat = self.distribution.get_command_obj('build').plat_name - # check warn_dir - it is a clue that the 'install' is happening - # internally, and not to sys.path, so we don't check the platform - # matches what we are running. - if self.warn_dir and build_plat != get_platform(): - raise DistutilsPlatformError("Can't install when " - "cross-compiling") - - # Run all sub-commands (at least those that need to be run) - for cmd_name in self.get_sub_commands(): - self.run_command(cmd_name) - - if self.path_file: - self.create_path_file() - - # write list of installed files, if requested. - if self.record: - outputs = self.get_outputs() - if self.root: # strip any package prefix - root_len = len(self.root) - for counter in xrange(len(outputs)): - outputs[counter] = outputs[counter][root_len:] - self.execute(write_file, - (self.record, outputs), - "writing list of installed files to '%s'" % - self.record) - - sys_path = map(os.path.normpath, sys.path) - sys_path = map(os.path.normcase, sys_path) - install_lib = os.path.normcase(os.path.normpath(self.install_lib)) - if (self.warn_dir and - not (self.path_file and self.install_path_file) and - install_lib not in sys_path): - log.debug(("modules installed to '%s', which is not in " - "Python's module search path (sys.path) -- " - "you'll have to change the search path yourself"), - self.install_lib) - - def create_path_file(self): - """Creates the .pth file""" - filename = os.path.join(self.install_libbase, - self.path_file + ".pth") - if self.install_path_file: - self.execute(write_file, - (filename, [self.extra_dirs]), - "creating %s" % filename) - else: - self.warn("path file '%s' not created" % filename) - - # -- Reporting methods --------------------------------------------- - - def get_outputs(self): - """Assembles the outputs of all the sub-commands.""" - outputs = [] - for cmd_name in self.get_sub_commands(): - cmd = self.get_finalized_command(cmd_name) - # Add the contents of cmd.get_outputs(), ensuring - # that outputs doesn't contain duplicate entries - for filename in cmd.get_outputs(): - if filename not in outputs: - outputs.append(filename) - - if self.path_file and self.install_path_file: - outputs.append(os.path.join(self.install_libbase, - self.path_file + ".pth")) - - return outputs - - def get_inputs(self): - """Returns the inputs of all the sub-commands""" - # XXX gee, this looks familiar ;-( - inputs = [] - for cmd_name in self.get_sub_commands(): - cmd = self.get_finalized_command(cmd_name) - inputs.extend(cmd.get_inputs()) - - return inputs - - # -- Predicates for sub-command list ------------------------------- - - def has_lib(self): - """Returns true if the current distribution has any Python - modules to install.""" - return (self.distribution.has_pure_modules() or - self.distribution.has_ext_modules()) - - def has_headers(self): - """Returns true if the current distribution has any headers to - install.""" - return self.distribution.has_headers() - - def has_scripts(self): - """Returns true if the current distribution has any scripts to. - install.""" - return self.distribution.has_scripts() - - def has_data(self): - """Returns true if the current distribution has any data to. - install.""" - return self.distribution.has_data_files() - - # 'sub_commands': a list of commands this command might have to run to - # get its work done. See cmd.py for more info. - sub_commands = [('install_lib', has_lib), - ('install_headers', has_headers), - ('install_scripts', has_scripts), - ('install_data', has_data), - # keep install_distinfo last, as it needs the record - # with files to be completely generated - ('install_distinfo', lambda self: not self.no_distinfo), - ] diff --git a/src/distutils2/command/install_data.py b/src/distutils2/command/install_data.py deleted file mode 100644 index 1256a0d..0000000 --- a/src/distutils2/command/install_data.py +++ /dev/null @@ -1,94 +0,0 @@ -"""distutils.command.install_data - -Implements the Distutils 'install_data' command, for installing -platform-independent data files.""" - -# contributed by Bastian Kleineidam - -__revision__ = "$Id: install_data.py 76849 2009-12-15 06:29:19Z tarek.ziade $" - -import os -from distutils2.core import Command -from distutils2.util import change_root, convert_path - -class install_data(Command): - - description = "install data files" - - user_options = [ - ('install-dir=', 'd', - "base directory for installing data files " - "(default: installation base dir)"), - ('root=', None, - "install everything relative to this alternate root directory"), - ('force', 'f', "force installation (overwrite existing files)"), - ] - - boolean_options = ['force'] - - def initialize_options(self): - self.install_dir = None - self.outfiles = [] - self.root = None - self.force = 0 - self.data_files = self.distribution.data_files - self.warn_dir = 1 - - def finalize_options(self): - self.set_undefined_options('install', - ('install_data', 'install_dir'), - 'root', 'force') - - def run(self): - self.mkpath(self.install_dir) - for f in self.data_files: - if isinstance(f, str): - # it's a simple file, so copy it - f = convert_path(f) - if self.warn_dir: - self.warn("setup script did not provide a directory for " - "'%s' -- installing right in '%s'" % - (f, self.install_dir)) - (out, _) = self.copy_file(f, self.install_dir) - self.outfiles.append(out) - else: - # it's a tuple with path to install to and a list of files - dir = convert_path(f[0]) - if not os.path.isabs(dir): - dir = os.path.join(self.install_dir, dir) - elif self.root: - dir = change_root(self.root, dir) - self.mkpath(dir) - - if f[1] == []: - # If there are no files listed, the user must be - # trying to create an empty directory, so add the - # directory to the list of output files. - self.outfiles.append(dir) - else: - # Copy files, adding them to the list of output files. - for data in f[1]: - data = convert_path(data) - (out, _) = self.copy_file(data, dir) - self.outfiles.append(out) - - def get_source_files(self): - sources = [] - for item in self.data_files: - if isinstance(item, str): # plain file - item = convert_path(item) - if os.path.isfile(item): - sources.append(item) - else: # a (dirname, filenames) tuple - dirname, filenames = item - for f in filenames: - f = convert_path(f) - if os.path.isfile(f): - sources.append(f) - return sources - - def get_inputs(self): - return self.data_files or [] - - def get_outputs(self): - return self.outfiles diff --git a/src/distutils2/command/install_distinfo.py b/src/distutils2/command/install_distinfo.py deleted file mode 100644 index 64174dd..0000000 --- a/src/distutils2/command/install_distinfo.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -distutils.command.install_distinfo -================================== - -:Author: Josip Djolonga - -This module implements the ``install_distinfo`` command that creates the -``.dist-info`` directory for the distribution, as specified in :pep:`376`. -Usually, you do not have to call this command directly, it gets called -automatically by the ``install`` command. -""" - -# This file was created from the code for the former command install_egg_info - -import os -import csv -import re -from distutils2.command.cmd import Command -from distutils2 import log -from distutils2._backport.shutil import rmtree -try: - import hashlib -except ImportError: - from distutils2._backport import hashlib - - -class install_distinfo(Command): - - description = 'create a .dist-info directory for the distribution' - - user_options = [ - ('distinfo-dir=', None, - "directory where the the .dist-info directory will be installed"), - ('installer=', None, - "the name of the installer"), - ('requested', None, - "generate a REQUESTED file"), - ('no-requested', None, - "do not generate a REQUESTED file"), - ('no-record', None, - "do not generate a RECORD file"), - ] - - boolean_options = ['requested', 'no-record'] - - negative_opt = {'no-requested': 'requested'} - - def initialize_options(self): - self.distinfo_dir = None - self.installer = None - self.requested = None - self.no_record = None - - def finalize_options(self): - self.set_undefined_options('install', - 'installer', 'requested', 'no_record') - - self.set_undefined_options('install_lib', - ('install_dir', 'distinfo_dir')) - - if self.installer is None: - # FIXME distutils or distutils2? - # + document default in the option help text above and in install - self.installer = 'distutils' - if self.requested is None: - self.requested = True - if self.no_record is None: - self.no_record = False - - metadata = self.distribution.metadata - - basename = "%s-%s.dist-info" % ( - to_filename(safe_name(metadata['Name'])), - to_filename(safe_version(metadata['Version'])), - ) - - self.distinfo_dir = os.path.join(self.distinfo_dir, basename) - self.outputs = [] - - def run(self): - # FIXME dry-run should be used at a finer level, so that people get - # useful logging output and can have an idea of what the command would - # have done - if not self.dry_run: - target = self.distinfo_dir - - if os.path.isdir(target) and not os.path.islink(target): - rmtree(target) - elif os.path.exists(target): - self.execute(os.unlink, (self.distinfo_dir,), - "removing " + target) - - self.execute(os.makedirs, (target,), "creating " + target) - - metadata_path = os.path.join(self.distinfo_dir, 'METADATA') - log.info('creating %s', metadata_path) - self.distribution.metadata.write(metadata_path) - self.outputs.append(metadata_path) - - installer_path = os.path.join(self.distinfo_dir, 'INSTALLER') - log.info('creating %s', installer_path) - f = open(installer_path, 'w') - try: - f.write(self.installer) - finally: - f.close() - self.outputs.append(installer_path) - - if self.requested: - requested_path = os.path.join(self.distinfo_dir, 'REQUESTED') - log.info('creating %s', requested_path) - f = open(requested_path, 'w') - f.close() - self.outputs.append(requested_path) - - if not self.no_record: - record_path = os.path.join(self.distinfo_dir, 'RECORD') - log.info('creating %s', record_path) - f = open(record_path, 'wb') - try: - writer = csv.writer(f, delimiter=',', - lineterminator=os.linesep, - quotechar='"') - - install = self.get_finalized_command('install') - - for fpath in install.get_outputs(): - if fpath.endswith('.pyc') or fpath.endswith('.pyo'): - # do not put size and md5 hash, as in PEP-376 - writer.writerow((fpath, '', '')) - else: - size = os.path.getsize(fpath) - fd = open(fpath, 'r') - hash = hashlib.md5() - hash.update(fd.read()) - md5sum = hash.hexdigest() - writer.writerow((fpath, md5sum, size)) - - # add the RECORD file itself - writer.writerow((record_path, '', '')) - self.outputs.append(record_path) - finally: - f.close() - - def get_outputs(self): - return self.outputs - - -# The following functions are taken from setuptools' pkg_resources module. - -def safe_name(name): - """Convert an arbitrary string to a standard distribution name - - Any runs of non-alphanumeric/. characters are replaced with a single '-'. - """ - return re.sub('[^A-Za-z0-9.]+', '-', name) - - -def safe_version(version): - """Convert an arbitrary string to a standard version string - - Spaces become dots, and all other non-alphanumeric characters become - dashes, with runs of multiple dashes condensed to a single dash. - """ - version = version.replace(' ', '.') - return re.sub('[^A-Za-z0-9.]+', '-', version) - - -def to_filename(name): - """Convert a project or version name to its filename-escaped form - - Any '-' characters are currently replaced with '_'. - """ - return name.replace('-', '_') diff --git a/src/distutils2/command/install_headers.py b/src/distutils2/command/install_headers.py deleted file mode 100644 index dd63128..0000000 --- a/src/distutils2/command/install_headers.py +++ /dev/null @@ -1,50 +0,0 @@ -"""distutils.command.install_headers - -Implements the Distutils 'install_headers' command, to install C/C++ header -files to the Python include directory.""" - -__revision__ = "$Id: install_headers.py 70891 2009-03-31 20:55:21Z tarek.ziade $" - -from distutils2.core import Command - - -# XXX force is never used -class install_headers(Command): - - description = "install C/C++ header files" - - user_options = [('install-dir=', 'd', - "directory to install header files to"), - ('force', 'f', - "force installation (overwrite existing files)"), - ] - - boolean_options = ['force'] - - def initialize_options(self): - self.install_dir = None - self.force = 0 - self.outfiles = [] - - def finalize_options(self): - self.set_undefined_options('install', - ('install_headers', 'install_dir'), - 'force') - - def run(self): - headers = self.distribution.headers - if not headers: - return - - self.mkpath(self.install_dir) - for header in headers: - (out, _) = self.copy_file(header, self.install_dir) - self.outfiles.append(out) - - def get_inputs(self): - return self.distribution.headers or [] - - def get_outputs(self): - return self.outfiles - -# class install_headers diff --git a/src/distutils2/command/install_lib.py b/src/distutils2/command/install_lib.py deleted file mode 100644 index c5e78f7..0000000 --- a/src/distutils2/command/install_lib.py +++ /dev/null @@ -1,215 +0,0 @@ -"""distutils.command.install_lib - -Implements the Distutils 'install_lib' command -(install all Python modules).""" - -__revision__ = "$Id: install_lib.py 75671 2009-10-24 15:51:30Z tarek.ziade $" - -import os -import sys - -from distutils2.core import Command -from distutils2.errors import DistutilsOptionError - - -# Extension for Python source files. -if hasattr(os, 'extsep'): - PYTHON_SOURCE_EXTENSION = os.extsep + "py" -else: - PYTHON_SOURCE_EXTENSION = ".py" - -class install_lib(Command): - - description = "install all Python modules (extensions and pure Python)" - - # The byte-compilation options are a tad confusing. Here are the - # possible scenarios: - # 1) no compilation at all (--no-compile --no-optimize) - # 2) compile .pyc only (--compile --no-optimize; default) - # 3) compile .pyc and "level 1" .pyo (--compile --optimize) - # 4) compile "level 1" .pyo only (--no-compile --optimize) - # 5) compile .pyc and "level 2" .pyo (--compile --optimize-more) - # 6) compile "level 2" .pyo only (--no-compile --optimize-more) - # - # The UI for this is two option, 'compile' and 'optimize'. - # 'compile' is strictly boolean, and only decides whether to - # generate .pyc files. 'optimize' is three-way (0, 1, or 2), and - # decides both whether to generate .pyo files and what level of - # optimization to use. - - user_options = [ - ('install-dir=', 'd', "directory to install to"), - ('build-dir=','b', "build directory (where to install from)"), - ('force', 'f', "force installation (overwrite existing files)"), - ('compile', 'c', "compile .py to .pyc [default]"), - ('no-compile', None, "don't compile .py files"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), - ('skip-build', None, "skip the build steps"), - ] - - boolean_options = ['force', 'compile', 'skip-build'] - negative_opt = {'no-compile' : 'compile'} - - def initialize_options(self): - # let the 'install' command dictate our installation directory - self.install_dir = None - self.build_dir = None - self.force = 0 - self.compile = None - self.optimize = None - self.skip_build = None - - def finalize_options(self): - # Get all the information we need to install pure Python modules - # from the umbrella 'install' command -- build (source) directory, - # install (target) directory, and whether to compile .py files. - self.set_undefined_options('install', - ('build_lib', 'build_dir'), - ('install_lib', 'install_dir'), - 'force', 'compile', 'optimize', 'skip_build') - - if self.compile is None: - self.compile = 1 - if self.optimize is None: - self.optimize = 0 - - if not isinstance(self.optimize, int): - try: - self.optimize = int(self.optimize) - if self.optimize not in (0, 1, 2): - raise AssertionError - except (ValueError, AssertionError): - raise DistutilsOptionError, "optimize must be 0, 1, or 2" - - def run(self): - # Make sure we have built everything we need first - self.build() - - # Install everything: simply dump the entire contents of the build - # directory to the installation directory (that's the beauty of - # having a build directory!) - outfiles = self.install() - - # (Optionally) compile .py to .pyc - if outfiles is not None and self.distribution.has_pure_modules(): - self.byte_compile(outfiles) - - # -- Top-level worker functions ------------------------------------ - # (called from 'run()') - - def build(self): - if not self.skip_build: - if self.distribution.has_pure_modules(): - self.run_command('build_py') - if self.distribution.has_ext_modules(): - self.run_command('build_ext') - - def install(self): - if os.path.isdir(self.build_dir): - outfiles = self.copy_tree(self.build_dir, self.install_dir) - else: - self.warn("'%s' does not exist -- no Python modules to install" % - self.build_dir) - return - return outfiles - - def byte_compile(self, files): - if hasattr(sys, 'dont_write_bytecode') and sys.dont_write_bytecode: - self.warn('byte-compiling is disabled, skipping.') - return - - from distutils2.util import byte_compile - - # Get the "--root" directory supplied to the "install" command, - # and use it as a prefix to strip off the purported filename - # encoded in bytecode files. This is far from complete, but it - # should at least generate usable bytecode in RPM distributions. - install_root = self.get_finalized_command('install').root - - if self.compile: - byte_compile(files, optimize=0, - force=self.force, prefix=install_root, - dry_run=self.dry_run) - if self.optimize > 0: - byte_compile(files, optimize=self.optimize, - force=self.force, prefix=install_root, - verbose=self.verbose, dry_run=self.dry_run) - - - # -- Utility methods ----------------------------------------------- - - def _mutate_outputs(self, has_any, build_cmd, cmd_option, output_dir): - if not has_any: - return [] - - build_cmd = self.get_finalized_command(build_cmd) - build_files = build_cmd.get_outputs() - build_dir = getattr(build_cmd, cmd_option) - - prefix_len = len(build_dir) + len(os.sep) - outputs = [] - for file in build_files: - outputs.append(os.path.join(output_dir, file[prefix_len:])) - - return outputs - - def _bytecode_filenames(self, py_filenames): - bytecode_files = [] - for py_file in py_filenames: - # Since build_py handles package data installation, the - # list of outputs can contain more than just .py files. - # Make sure we only report bytecode for the .py files. - ext = os.path.splitext(os.path.normcase(py_file))[1] - if ext != PYTHON_SOURCE_EXTENSION: - continue - if self.compile: - bytecode_files.append(py_file + "c") - if self.optimize > 0: - bytecode_files.append(py_file + "o") - - return bytecode_files - - - # -- External interface -------------------------------------------- - # (called by outsiders) - - def get_outputs(self): - """Return the list of files that would be installed if this command - were actually run. Not affected by the "dry-run" flag or whether - modules have actually been built yet. - """ - pure_outputs = \ - self._mutate_outputs(self.distribution.has_pure_modules(), - 'build_py', 'build_lib', - self.install_dir) - if self.compile: - bytecode_outputs = self._bytecode_filenames(pure_outputs) - else: - bytecode_outputs = [] - - ext_outputs = \ - self._mutate_outputs(self.distribution.has_ext_modules(), - 'build_ext', 'build_lib', - self.install_dir) - - return pure_outputs + bytecode_outputs + ext_outputs - - def get_inputs(self): - """Get the list of files that are input to this command, ie. the - files that get installed as they are named in the build tree. - The files in this list correspond one-to-one to the output - filenames returned by 'get_outputs()'. - """ - inputs = [] - - if self.distribution.has_pure_modules(): - build_py = self.get_finalized_command('build_py') - inputs.extend(build_py.get_outputs()) - - if self.distribution.has_ext_modules(): - build_ext = self.get_finalized_command('build_ext') - inputs.extend(build_ext.get_outputs()) - - return inputs diff --git a/src/distutils2/command/install_scripts.py b/src/distutils2/command/install_scripts.py deleted file mode 100644 index fa7587e..0000000 --- a/src/distutils2/command/install_scripts.py +++ /dev/null @@ -1,62 +0,0 @@ -"""distutils.command.install_scripts - -Implements the Distutils 'install_scripts' command, for installing -Python scripts.""" - -# contributed by Bastian Kleineidam - -__revision__ = "$Id: install_scripts.py 68943 2009-01-25 22:09:10Z tarek.ziade $" - -import os -from distutils2.core import Command -from distutils2 import log -from stat import ST_MODE - -class install_scripts (Command): - - description = "install scripts (Python or otherwise)" - - user_options = [ - ('install-dir=', 'd', "directory to install scripts to"), - ('build-dir=','b', "build directory (where to install from)"), - ('force', 'f', "force installation (overwrite existing files)"), - ('skip-build', None, "skip the build steps"), - ] - - boolean_options = ['force', 'skip-build'] - - - def initialize_options (self): - self.install_dir = None - self.force = 0 - self.build_dir = None - self.skip_build = None - - def finalize_options (self): - self.set_undefined_options('build', ('build_scripts', 'build_dir')) - self.set_undefined_options('install', - ('install_scripts', 'install_dir'), - 'force', 'skip_build') - - def run (self): - if not self.skip_build: - self.run_command('build_scripts') - self.outfiles = self.copy_tree(self.build_dir, self.install_dir) - if os.name == 'posix': - # Set the executable bits (owner, group, and world) on - # all the scripts we just installed. - for file in self.get_outputs(): - if self.dry_run: - log.info("changing mode of %s", file) - else: - mode = ((os.stat(file)[ST_MODE]) | 0555) & 07777 - log.info("changing mode of %s to %o", file, mode) - os.chmod(file, mode) - - def get_inputs (self): - return self.distribution.scripts or [] - - def get_outputs(self): - return self.outfiles or [] - -# class install_scripts diff --git a/src/distutils2/command/register.py b/src/distutils2/command/register.py deleted file mode 100644 index bb97936..0000000 --- a/src/distutils2/command/register.py +++ /dev/null @@ -1,298 +0,0 @@ -"""distutils.command.register - -Implements the Distutils 'register' command (register with the repository). -""" - -# created 2002/10/21, Richard Jones - -__revision__ = "$Id: register.py 77717 2010-01-24 00:33:32Z tarek.ziade $" - -import urllib2 -import getpass -import urlparse -import StringIO -from warnings import warn - -from distutils2.command.cmd import Command -from distutils2 import log -from distutils2.util import (metadata_to_dict, read_pypirc, generate_pypirc, - DEFAULT_REPOSITORY, DEFAULT_REALM, - get_pypirc_path) - -class register(Command): - - description = "register the distribution with the Python package index" - user_options = [ - ('repository=', 'r', - "repository URL [default: %s]" % DEFAULT_REPOSITORY), - ('show-response', None, - "display full response text from server"), - ('list-classifiers', None, - "list valid Trove classifiers"), - ('strict', None , - "stop the registration if the metadata is not fully compliant") - ] - - boolean_options = ['show-response', 'verify', 'list-classifiers', - 'strict'] - - def initialize_options(self): - self.repository = None - self.realm = None - self.show_response = 0 - self.list_classifiers = 0 - self.strict = 0 - - def finalize_options(self): - if self.repository is None: - self.repository = DEFAULT_REPOSITORY - if self.realm is None: - self.realm = DEFAULT_REALM - # setting options for the `check` subcommand - check_options = {'strict': ('register', self.strict), - 'all': ('register', 1)} - self.distribution.command_options['check'] = check_options - - def run(self): - self.finalize_options() - self._set_config() - - # Check the package metadata - self.run_command('check') - - if self.dry_run: - self.verify_metadata() - elif self.list_classifiers: - self.classifiers() - else: - self.send_metadata() - - def check_metadata(self): - """Deprecated API.""" - warn("distutils.command.register.check_metadata is deprecated, \ - use the check command instead", PendingDeprecationWarning) - check = self.distribution.get_command_obj('check') - check.ensure_finalized() - check.strict = self.strict - check.all = 1 - check.run() - - def _set_config(self): - ''' Reads the configuration file and set attributes. - ''' - config = read_pypirc(self.repository, self.realm) - if config != {}: - self.username = config['username'] - self.password = config['password'] - self.repository = config['repository'] - self.realm = config['realm'] - self.has_config = True - else: - if self.repository not in ('pypi', DEFAULT_REPOSITORY): - raise ValueError('%s not found in .pypirc' % self.repository) - if self.repository == 'pypi': - self.repository = DEFAULT_REPOSITORY - self.has_config = False - - def classifiers(self): - ''' Fetch the list of classifiers from the server. - ''' - response = urllib2.urlopen(self.repository+'?:action=list_classifiers') - log.info(response.read()) - - def verify_metadata(self): - ''' Send the metadata to the package index server to be checked. - ''' - # send the info to the server and report the result - (code, result) = self.post_to_server(self.build_post_data('verify')) - log.info('Server response (%s): %s' % (code, result)) - - - def send_metadata(self): - ''' Send the metadata to the package index server. - - Well, do the following: - 1. figure who the user is, and then - 2. send the data as a Basic auth'ed POST. - - First we try to read the username/password from $HOME/.pypirc, - which is a ConfigParser-formatted file with a section - [distutils] containing username and password entries (both - in clear text). Eg: - - [distutils] - index-servers = - pypi - - [pypi] - username: fred - password: sekrit - - Otherwise, to figure who the user is, we offer the user three - choices: - - 1. use existing login, - 2. register as a new user, or - 3. set the password to a random string and email the user. - - ''' - # see if we can short-cut and get the username/password from the - # config - if self.has_config: - choice = '1' - username = self.username - password = self.password - else: - choice = 'x' - username = password = '' - - # get the user's login info - choices = '1 2 3 4'.split() - while choice not in choices: - self.announce('''\ -We need to know who you are, so please choose either: - 1. use your existing login, - 2. register as a new user, - 3. have the server generate a new password for you (and email it to you), or - 4. quit -Your selection [default 1]: ''', log.INFO) - - choice = raw_input() - if not choice: - choice = '1' - elif choice not in choices: - print 'Please choose one of the four options!' - - if choice == '1': - # get the username and password - while not username: - username = raw_input('Username: ') - while not password: - password = getpass.getpass('Password: ') - - # set up the authentication - auth = urllib2.HTTPPasswordMgr() - host = urlparse.urlparse(self.repository)[1] - auth.add_password(self.realm, host, username, password) - # send the info to the server and report the result - code, result = self.post_to_server(self.build_post_data('submit'), - auth) - self.announce('Server response (%s): %s' % (code, result), - log.INFO) - - # possibly save the login - if code == 200: - if self.has_config: - # sharing the password in the distribution instance - # so the upload command can reuse it - self.distribution.password = password - else: - self.announce(('I can store your PyPI login so future ' - 'submissions will be faster.'), log.INFO) - self.announce('(the login will be stored in %s)' % \ - get_pypirc_path(), log.INFO) - choice = 'X' - while choice.lower() not in 'yn': - choice = raw_input('Save your login (y/N)?') - if not choice: - choice = 'n' - if choice.lower() == 'y': - generate_pypirc(username, password) - - elif choice == '2': - data = {':action': 'user'} - data['name'] = data['password'] = data['email'] = '' - data['confirm'] = None - while not data['name']: - data['name'] = raw_input('Username: ') - while data['password'] != data['confirm']: - while not data['password']: - data['password'] = getpass.getpass('Password: ') - while not data['confirm']: - data['confirm'] = getpass.getpass(' Confirm: ') - if data['password'] != data['confirm']: - data['password'] = '' - data['confirm'] = None - print "Password and confirm don't match!" - while not data['email']: - data['email'] = raw_input(' EMail: ') - code, result = self.post_to_server(data) - if code != 200: - log.info('Server response (%s): %s' % (code, result)) - else: - log.info('You will receive an email shortly.') - log.info(('Follow the instructions in it to ' - 'complete registration.')) - elif choice == '3': - data = {':action': 'password_reset'} - data['email'] = '' - while not data['email']: - data['email'] = raw_input('Your email address: ') - code, result = self.post_to_server(data) - log.info('Server response (%s): %s' % (code, result)) - - def build_post_data(self, action): - # figure the data to send - the metadata plus some additional - # information used by the package server - data = metadata_to_dict(self.distribution.metadata) - data[':action'] = action - return data - - # XXX to be refactored with upload.upload_file - def post_to_server(self, data, auth=None): - ''' Post a query to the server, and return a string response. - ''' - if 'name' in data: - self.announce('Registering %s to %s' % (data['name'], - self.repository), - log.INFO) - # Build up the MIME payload for the urllib2 POST data - boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' - sep_boundary = '\n--' + boundary - end_boundary = sep_boundary + '--' - body = StringIO.StringIO() - for key, value in data.items(): - # handle multiple entries for the same name - if not isinstance(value, (tuple, list)): - value = [value] - - for value in value: - body.write(sep_boundary) - body.write('\nContent-Disposition: form-data; name="%s"'%key) - body.write("\n\n") - body.write(value) - if value and value[-1] == '\r': - body.write('\n') # write an extra newline (lurve Macs) - body.write(end_boundary) - body.write("\n") - body = body.getvalue() - - # build the Request - headers = { - 'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary, - 'Content-length': str(len(body)) - } - req = urllib2.Request(self.repository, body, headers) - - # handle HTTP and include the Basic Auth handler - opener = urllib2.build_opener( - urllib2.HTTPBasicAuthHandler(password_mgr=auth) - ) - data = '' - try: - result = opener.open(req) - except urllib2.HTTPError, e: - if self.show_response: - data = e.fp.read() - result = e.code, e.msg - except urllib2.URLError, e: - result = 500, str(e) - else: - if self.show_response: - data = result.read() - result = 200, 'OK' - if self.show_response: - dashes = '-' * 75 - self.announce('%s%s%s' % (dashes, data, dashes)) - - return result diff --git a/src/distutils2/command/sdist.py b/src/distutils2/command/sdist.py deleted file mode 100644 index 4e7764c..0000000 --- a/src/distutils2/command/sdist.py +++ /dev/null @@ -1,360 +0,0 @@ -"""distutils.command.sdist - -Implements the Distutils 'sdist' command (create a source distribution).""" - -__revision__ = "$Id: sdist.py 76956 2009-12-21 01:22:46Z tarek.ziade $" - -import os -import string -import sys -from glob import glob -from warnings import warn -from shutil import rmtree -import re - -try: - from shutil import get_archive_formats -except ImportError: - from distutils2._backport.shutil import get_archive_formats - -from distutils2.core import Command -from distutils2.errors import (DistutilsPlatformError, DistutilsOptionError, - DistutilsTemplateError) -from distutils2.manifest import Manifest -from distutils2 import log -from distutils2.util import convert_path - -def show_formats(): - """Print all possible values for the 'formats' option (used by - the "--help-formats" command-line option). - """ - from distutils2.fancy_getopt import FancyGetopt - formats = [] - for name, desc in get_archive_formats(): - formats.append(("formats=" + name, None, desc)) - formats.sort() - FancyGetopt(formats).print_help( - "List of available source distribution formats:") - -# a \ followed by some spaces + EOL -_COLLAPSE_PATTERN = re.compile('\\\w\n', re.M) -_COMMENTED_LINE = re.compile('^#.*\n$|^\w*\n$', re.M) - -class sdist(Command): - - description = "create a source distribution (tarball, zip file, etc.)" - - user_options = [ - ('template=', 't', - "name of manifest template file [default: MANIFEST.in]"), - ('manifest=', 'm', - "name of manifest file [default: MANIFEST]"), - ('use-defaults', None, - "include the default file set in the manifest " - "[default; disable with --no-defaults]"), - ('no-defaults', None, - "don't include the default file set"), - ('prune', None, - "specifically exclude files/directories that should not be " - "distributed (build tree, RCS/CVS dirs, etc.) " - "[default; disable with --no-prune]"), - ('no-prune', None, - "don't automatically exclude anything"), - ('manifest-only', 'o', - "just regenerate the manifest and then stop "), - ('formats=', None, - "formats for source distribution (comma-separated list)"), - ('keep-temp', 'k', - "keep the distribution tree around after creating " + - "archive file(s)"), - ('dist-dir=', 'd', - "directory to put the source distribution archive(s) in " - "[default: dist]"), - ('check-metadata', None, - "Ensure that all required elements of metadata " - "are supplied. Warn if any missing. [default]"), - ('owner=', 'u', - "Owner name used when creating a tar file [default: current user]"), - ('group=', 'g', - "Group name used when creating a tar file [default: current group]"), - ] - - boolean_options = ['use-defaults', 'prune', - 'manifest-only', 'keep-temp', 'check-metadata'] - - help_options = [ - ('help-formats', None, - "list available distribution formats", show_formats), - ] - - negative_opt = {'no-defaults': 'use-defaults', - 'no-prune': 'prune' } - - default_format = {'posix': 'gztar', - 'nt': 'zip' } - - def initialize_options(self): - # 'template' and 'manifest' are, respectively, the names of - # the manifest template and manifest file. - self.template = None - self.manifest = None - - # 'use_defaults': if true, we will include the default file set - # in the manifest - self.use_defaults = 1 - self.prune = 1 - self.manifest_only = 0 - self.formats = None - self.keep_temp = 0 - self.dist_dir = None - - self.archive_files = None - self.metadata_check = 1 - self.owner = None - self.group = None - self.filelist = None - - def _check_archive_formats(self, formats): - supported_formats = [name for name, desc in get_archive_formats()] - for format in formats: - if format not in supported_formats: - return format - return None - - def finalize_options(self): - if self.manifest is None: - self.manifest = "MANIFEST" - if self.template is None: - self.template = "MANIFEST.in" - - self.ensure_string_list('formats') - if self.formats is None: - try: - self.formats = [self.default_format[os.name]] - except KeyError: - raise DistutilsPlatformError, \ - "don't know how to create source distributions " + \ - "on platform %s" % os.name - - bad_format = self._check_archive_formats(self.formats) - if bad_format: - raise DistutilsOptionError, \ - "unknown archive format '%s'" % bad_format - - if self.dist_dir is None: - self.dist_dir = "dist" - - if self.filelist is None: - self.filelist = Manifest() - - - def run(self): - # 'filelist' contains the list of files that will make up the - # manifest - self.filelist.clear() - - # Check the package metadata - if self.metadata_check: - self.run_command('check') - - # Do whatever it takes to get the list of files to process - # (process the manifest template, read an existing manifest, - # whatever). File list is accumulated in 'self.filelist'. - self.get_file_list() - - # If user just wanted us to regenerate the manifest, stop now. - if self.manifest_only: - return - - # Otherwise, go ahead and create the source distribution tarball, - # or zipfile, or whatever. - self.make_distribution() - - def get_file_list(self): - """Figure out the list of files to include in the source - distribution, and put it in 'self.filelist'. This might involve - reading the manifest template (and writing the manifest), or just - reading the manifest, or just using the default file set -- it all - depends on the user's options. - """ - template_exists = os.path.isfile(self.template) - if not template_exists: - self.warn(("manifest template '%s' does not exist " + - "(using default file list)") % - self.template) - - self.filelist.findall() - - if self.use_defaults: - self.add_defaults() - if template_exists: - self.filelist.read_template(self.template) - if self.prune: - self.prune_file_list() - - self.filelist.write(self.manifest) - - def add_defaults(self): - """Add all the default files to self.filelist: - - README or README.txt - - setup.py - - test/test*.py - - all pure Python modules mentioned in setup script - - all files pointed by package_data (build_py) - - all files defined in data_files. - - all files defined as scripts. - - all C sources listed as part of extensions or C libraries - in the setup script (doesn't catch C headers!) - Warns if (README or README.txt) or setup.py are missing; everything - else is optional. - """ - - standards = [('README', 'README.txt'), self.distribution.script_name] - for fn in standards: - if isinstance(fn, tuple): - alts = fn - got_it = 0 - for fn in alts: - if os.path.exists(fn): - got_it = 1 - self.filelist.append(fn) - break - - if not got_it: - self.warn("standard file not found: should have one of " + - string.join(alts, ', ')) - else: - if os.path.exists(fn): - self.filelist.append(fn) - else: - self.warn("standard file '%s' not found" % fn) - - optional = ['test/test*.py', 'setup.cfg'] - for pattern in optional: - files = filter(os.path.isfile, glob(pattern)) - if files: - self.filelist.extend(files) - - for cmd_name in self.distribution.get_command_names(): - cmd_obj = self.get_finalized_command(cmd_name) - self.filelist.extend(cmd_obj.get_source_files()) - - def prune_file_list(self): - """Prune off branches that might slip into the file list as created - by 'read_template()', but really don't belong there: - * the build tree (typically "build") - * the release tree itself (only an issue if we ran "sdist" - previously with --keep-temp, or it aborted) - * any RCS, CVS, .svn, .hg, .git, .bzr, _darcs directories - """ - build = self.get_finalized_command('build') - base_dir = self.distribution.get_fullname() - - self.filelist.exclude_pattern(None, prefix=build.build_base) - self.filelist.exclude_pattern(None, prefix=base_dir) - - # pruning out vcs directories - # both separators are used under win32 - if sys.platform == 'win32': - seps = r'/|\\' - else: - seps = '/' - - vcs_dirs = ['RCS', 'CVS', r'\.svn', r'\.hg', r'\.git', r'\.bzr', - '_darcs'] - vcs_ptrn = r'(^|%s)(%s)(%s).*' % (seps, '|'.join(vcs_dirs), seps) - self.filelist.exclude_pattern(vcs_ptrn, is_regex=1) - - - def make_release_tree(self, base_dir, files): - """Create the directory tree that will become the source - distribution archive. All directories implied by the filenames in - 'files' are created under 'base_dir', and then we hard link or copy - (if hard linking is unavailable) those files into place. - Essentially, this duplicates the developer's source tree, but in a - directory named after the distribution, containing only the files - to be distributed. - """ - # Create all the directories under 'base_dir' necessary to - # put 'files' there; the 'mkpath()' is just so we don't die - # if the manifest happens to be empty. - self.mkpath(base_dir) - self.create_tree(base_dir, files, dry_run=self.dry_run) - - # And walk over the list of files, either making a hard link (if - # os.link exists) to each one that doesn't already exist in its - # corresponding location under 'base_dir', or copying each file - # that's out-of-date in 'base_dir'. (Usually, all files will be - # out-of-date, because by default we blow away 'base_dir' when - # we're done making the distribution archives.) - - if hasattr(os, 'link'): # can make hard links on this system - link = 'hard' - msg = "making hard links in %s..." % base_dir - else: # nope, have to copy - link = None - msg = "copying files to %s..." % base_dir - - if not files: - log.warn("no files to distribute -- empty manifest?") - else: - log.info(msg) - for file in files: - if not os.path.isfile(file): - log.warn("'%s' not a regular file -- skipping" % file) - else: - dest = os.path.join(base_dir, file) - self.copy_file(file, dest, link=link) - - self.distribution.metadata.write(os.path.join(base_dir, 'PKG-INFO')) - - def make_distribution(self): - """Create the source distribution(s). First, we create the release - tree with 'make_release_tree()'; then, we create all required - archive files (according to 'self.formats') from the release tree. - Finally, we clean up by blowing away the release tree (unless - 'self.keep_temp' is true). The list of archive files created is - stored so it can be retrieved later by 'get_archive_files()'. - """ - # Don't warn about missing metadata here -- should be (and is!) - # done elsewhere. - base_dir = self.distribution.get_fullname() - base_name = os.path.join(self.dist_dir, base_dir) - - self.make_release_tree(base_dir, self.filelist.files) - archive_files = [] # remember names of files we create - # tar archive must be created last to avoid overwrite and remove - if 'tar' in self.formats: - self.formats.append(self.formats.pop(self.formats.index('tar'))) - - for fmt in self.formats: - file = self.make_archive(base_name, fmt, base_dir=base_dir, - owner=self.owner, group=self.group) - archive_files.append(file) - self.distribution.dist_files.append(('sdist', '', file)) - - self.archive_files = archive_files - - if not self.keep_temp: - if self.dry_run: - log.info('Removing %s' % base_dir) - else: - rmtree(base_dir) - - def get_archive_files(self): - """Return the list of archive files created when the command - was run, or None if the command hasn't run yet. - """ - return self.archive_files - - def create_tree(self, base_dir, files, mode=0777, verbose=1, dry_run=0): - need_dir = {} - for file in files: - need_dir[os.path.join(base_dir, os.path.dirname(file))] = 1 - need_dirs = need_dir.keys() - need_dirs.sort() - - # Now create them - for dir in need_dirs: - self.mkpath(dir, mode, verbose=verbose, dry_run=dry_run) - diff --git a/src/distutils2/command/test.py b/src/distutils2/command/test.py deleted file mode 100644 index d64ebd3..0000000 --- a/src/distutils2/command/test.py +++ /dev/null @@ -1,75 +0,0 @@ -import os -import sys -import unittest - -from distutils2.core import Command -from distutils2.errors import DistutilsOptionError -from distutils2.util import resolve_name - -try: - from pkgutil import get_distribution -except ImportError: - from distutils2._backport.pkgutil import get_distribution - - -class test(Command): - - description = "run the distribution's test suite" - - user_options = [ - ('suite=', 's', - "test suite to run (for example: 'some_module.test_suite')"), - ('runner=', None, - "test runner to be called."), - ('tests-require=', None, - "list of distributions required to run the test suite."), - ] - - def initialize_options(self): - self.suite = None - self.runner = None - self.tests_require = [] - - def finalize_options(self): - self.build_lib = self.get_finalized_command("build").build_lib - for requirement in self.tests_require: - if get_distribution(requirement) is None: - self.announce("test dependency %s is not installed, " - "tests may fail" % requirement) - if (not self.suite and not self.runner and - self.get_ut_with_discovery() is None): - raise DistutilsOptionError( - "no test discovery available, please give a 'suite' or " - "'runner' option or install unittest2") - - def get_ut_with_discovery(self): - if hasattr(unittest.TestLoader, "discover"): - return unittest - else: - try: - import unittest2 - return unittest2 - except ImportError: - return None - - def run(self): - prev_syspath = sys.path[:] - try: - # build release - build = self.get_reinitialized_command('build') - self.run_command('build') - sys.path.insert(0, build.build_lib) - - # run the tests - if self.runner: - resolve_name(self.runner)() - elif self.suite: - runner = unittest.TextTestRunner(verbosity=self.verbose + 1) - runner.run(resolve_name(self.suite)()) - elif self.get_ut_with_discovery(): - ut = self.get_ut_with_discovery() - test_suite = ut.TestLoader().discover(os.curdir) - runner = ut.TextTestRunner(verbosity=self.verbose + 1) - runner.run(test_suite) - finally: - sys.path[:] = prev_syspath diff --git a/src/distutils2/command/upload.py b/src/distutils2/command/upload.py deleted file mode 100644 index 3fdb5b3..0000000 --- a/src/distutils2/command/upload.py +++ /dev/null @@ -1,207 +0,0 @@ -"""distutils.command.upload - -Implements the Distutils 'upload' subcommand (upload package to PyPI).""" -import os -import socket -import platform -from urllib2 import urlopen, Request, HTTPError -from base64 import standard_b64encode -import urlparse -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO -try: - from hashlib import md5 -except ImportError: - from distutils2._backport.hashlib import md5 - -from distutils2.errors import DistutilsOptionError -from distutils2.util import spawn -from distutils2 import log -from distutils2.command.cmd import Command -from distutils2 import log -from distutils2.util import (metadata_to_dict, read_pypirc, - DEFAULT_REPOSITORY, DEFAULT_REALM) - - -class upload(Command): - - description = "upload distribution to PyPI" - - user_options = [ - ('repository=', 'r', - "repository URL [default: %s]" % DEFAULT_REPOSITORY), - ('show-response', None, - "display full response text from server"), - ('sign', 's', - "sign files to upload using gpg"), - ('identity=', 'i', - "GPG identity used to sign files"), - ('upload-docs', None, - "upload documentation too"), - ] - - boolean_options = ['show-response', 'sign'] - - def initialize_options(self): - self.repository = None - self.realm = None - self.show_response = 0 - self.username = '' - self.password = '' - self.show_response = 0 - self.sign = False - self.identity = None - self.upload_docs = False - - def finalize_options(self): - if self.repository is None: - self.repository = DEFAULT_REPOSITORY - if self.realm is None: - self.realm = DEFAULT_REALM - if self.identity and not self.sign: - raise DistutilsOptionError( - "Must use --sign for --identity to have meaning" - ) - config = read_pypirc(self.repository, self.realm) - if config != {}: - self.username = config['username'] - self.password = config['password'] - self.repository = config['repository'] - self.realm = config['realm'] - - # getting the password from the distribution - # if previously set by the register command - if not self.password and self.distribution.password: - self.password = self.distribution.password - - def run(self): - if not self.distribution.dist_files: - raise DistutilsOptionError("No dist file created in earlier command") - for command, pyversion, filename in self.distribution.dist_files: - self.upload_file(command, pyversion, filename) - if self.upload_docs: - upload_docs = self.get_finalized_command("upload_docs") - upload_docs.repository = self.repository - upload_docs.username = self.username - upload_docs.password = self.password - upload_docs.run() - - # XXX to be refactored with register.post_to_server - def upload_file(self, command, pyversion, filename): - # Makes sure the repository URL is compliant - schema, netloc, url, params, query, fragments = \ - urlparse.urlparse(self.repository) - if params or query or fragments: - raise AssertionError("Incompatible url %s" % self.repository) - - if schema not in ('http', 'https'): - raise AssertionError("unsupported schema " + schema) - - # Sign if requested - if self.sign: - gpg_args = ["gpg", "--detach-sign", "-a", filename] - if self.identity: - gpg_args[2:2] = ["--local-user", self.identity] - spawn(gpg_args, - dry_run=self.dry_run) - - # Fill in the data - send all the metadata in case we need to - # register a new release - content = open(filename,'rb').read() - - data = metadata_to_dict(self.distribution.metadata) - - # extra upload infos - data[':action'] = 'file_upload' - data['protcol_version'] = '1' - data['content'] = [os.path.basename(filename), content] - data['filetype'] = command - data['pyversion'] = pyversion - data['md5_digest'] = md5(content).hexdigest() - - comment = '' - if command == 'bdist_dumb': - comment = 'built for %s' % platform.platform(terse=1) - data['comment'] = comment - - if self.sign: - data['gpg_signature'] = [(os.path.basename(filename) + ".asc", - open(filename+".asc").read())] - - # set up the authentication - auth = "Basic " + standard_b64encode(self.username + ":" + - self.password) - - # Build up the MIME payload for the POST data - boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' - sep_boundary = '\n--' + boundary - end_boundary = sep_boundary + '--' - body = StringIO() - file_fields = ('content', 'gpg_signature') - - for key, values in data.items(): - # handle multiple entries for the same name - if not isinstance(values, (tuple, list)): - values = [values] - - content_dispo = 'Content-Disposition: form-data; name="%s"' % key - - if key in file_fields: - filename_, content = values - filename_ = ';filename="%s"' % filename_ - body.write(sep_boundary) - body.write("\n") - body.write(content_dispo) - body.write(filename_) - body.write("\n\n") - body.write(content) - else: - for value in values: - body.write(sep_boundary) - body.write("\n") - body.write(content_dispo) - body.write("\n\n") - body.write(value) - if value and value[-1] == '\r': - # write an extra newline (lurve Macs) - body.write('\n') - - body.write(end_boundary) - body.write("\n") - body = body.getvalue() - - self.announce("Submitting %s to %s" % (filename, self.repository), - log.INFO) - - # build the Request - headers = {'Content-type': - 'multipart/form-data; boundary=%s' % boundary, - 'Content-length': str(len(body)), - 'Authorization': auth} - - request = Request(self.repository, data=body, - headers=headers) - # send the data - try: - result = urlopen(request) - status = result.code - reason = result.msg - except socket.error, e: - self.announce(str(e), log.ERROR) - return - except HTTPError, e: - status = e.code - reason = e.msg - - if status == 200: - self.announce('Server response (%s): %s' % (status, reason), - log.INFO) - else: - self.announce('Upload failed (%s): %s' % (status, reason), - log.ERROR) - - if self.show_response: - msg = '\n'.join(('-' * 75, result.read(), '-' * 75)) - self.announce(msg, log.INFO) diff --git a/src/distutils2/command/upload_docs.py b/src/distutils2/command/upload_docs.py deleted file mode 100644 index d53dd03..0000000 --- a/src/distutils2/command/upload_docs.py +++ /dev/null @@ -1,156 +0,0 @@ -import os -import base64 -import httplib -import socket -import urlparse -import zipfile -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -from distutils2 import log -from distutils2.command.upload import upload -from distutils2.command.cmd import Command -from distutils2.errors import DistutilsFileError -from distutils2.util import read_pypirc, DEFAULT_REPOSITORY, DEFAULT_REALM - -def zip_dir(directory): - """Compresses recursively contents of directory into a StringIO object""" - destination = StringIO() - zip_file = zipfile.ZipFile(destination, "w") - for root, dirs, files in os.walk(directory): - for name in files: - full = os.path.join(root, name) - relative = root[len(directory):].lstrip(os.path.sep) - dest = os.path.join(relative, name) - zip_file.write(full, dest) - zip_file.close() - return destination - -# grabbed from -# http://code.activestate.com/recipes/146306-http-client-to-post-using-multipartform-data/ -def encode_multipart(fields, files, boundary=None): - """ - fields is a sequence of (name, value) elements for regular form fields. - files is a sequence of (name, filename, value) elements for data to be uploaded as files - Return (content_type, body) ready for httplib.HTTP instance - """ - if boundary is None: - boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' - l = [] - for (key, value) in fields: - l.extend([ - '--' + boundary, - 'Content-Disposition: form-data; name="%s"' % key, - '', - value]) - for (key, filename, value) in files: - l.extend([ - '--' + boundary, - 'Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename), - '', - value]) - l.append('--' + boundary + '--') - l.append('') - body = '\r\n'.join(l) - content_type = 'multipart/form-data; boundary=%s' % boundary - return content_type, body - -class upload_docs(Command): - - user_options = [ - ('repository=', 'r', - "repository URL [default: %s]" % DEFAULT_REPOSITORY), - ('show-response', None, - "display full response text from server"), - ('upload-dir=', None, - "directory to upload"), - ] - - def initialize_options(self): - self.repository = None - self.realm = None - self.show_response = 0 - self.upload_dir = None - self.username = '' - self.password = '' - - def finalize_options(self): - if self.repository is None: - self.repository = DEFAULT_REPOSITORY - if self.realm is None: - self.realm = DEFAULT_REALM - if self.upload_dir is None: - build = self.get_finalized_command('build') - self.upload_dir = os.path.join(build.build_base, "docs") - self.announce('Using upload directory %s' % self.upload_dir) - self.verify_upload_dir(self.upload_dir) - config = read_pypirc(self.repository, self.realm) - if config != {}: - self.username = config['username'] - self.password = config['password'] - self.repository = config['repository'] - self.realm = config['realm'] - - def verify_upload_dir(self, upload_dir): - self.ensure_dirname('upload_dir') - index_location = os.path.join(upload_dir, "index.html") - if not os.path.exists(index_location): - mesg = "No 'index.html found in docs directory (%s)" - raise DistutilsFileError(mesg % upload_dir) - - def run(self): - name = self.distribution.metadata['Name'] - version = self.distribution.metadata['Version'] - zip_file = zip_dir(self.upload_dir) - - fields = [(':action', 'doc_upload'), ('name', name), ('version', version)] - files = [('content', name, zip_file.getvalue())] - content_type, body = encode_multipart(fields, files) - - credentials = self.username + ':' + self.password - auth = "Basic " + base64.encodestring(credentials).strip() - - self.announce("Submitting documentation to %s" % (self.repository), - log.INFO) - - schema, netloc, url, params, query, fragments = \ - urlparse.urlparse(self.repository) - if schema == "http": - conn = httplib.HTTPConnection(netloc) - elif schema == "https": - conn = httplib.HTTPSConnection(netloc) - else: - raise AssertionError("unsupported schema "+schema) - - try: - conn.connect() - conn.putrequest("POST", url) - conn.putheader('Content-type', content_type) - conn.putheader('Content-length', str(len(body))) - conn.putheader('Authorization', auth) - conn.endheaders() - conn.send(body) - except socket.error, e: - self.announce(str(e), log.ERROR) - return - - r = conn.getresponse() - - if r.status == 200: - self.announce('Server response (%s): %s' % (r.status, r.reason), - log.INFO) - elif r.status == 301: - location = r.getheader('Location') - if location is None: - location = 'http://packages.python.org/%s/' % name - self.announce('Upload successful. Visit %s' % location, - log.INFO) - else: - self.announce('Upload failed (%s): %s' % (r.status, r.reason), - log.ERROR) - - if self.show_response: - msg = '\n'.join(('-' * 75, r.read(), '-' * 75)) - self.announce(msg, log.INFO) diff --git a/src/distutils2/command/wininst-6.0.exe b/src/distutils2/command/wininst-6.0.exe Binary files differdeleted file mode 100644 index f57c855..0000000 --- a/src/distutils2/command/wininst-6.0.exe +++ /dev/null diff --git a/src/distutils2/command/wininst-7.1.exe b/src/distutils2/command/wininst-7.1.exe Binary files differdeleted file mode 100644 index 1433bc1..0000000 --- a/src/distutils2/command/wininst-7.1.exe +++ /dev/null diff --git a/src/distutils2/command/wininst-8.0.exe b/src/distutils2/command/wininst-8.0.exe Binary files differdeleted file mode 100644 index 7403bfa..0000000 --- a/src/distutils2/command/wininst-8.0.exe +++ /dev/null diff --git a/src/distutils2/command/wininst-9.0-amd64.exe b/src/distutils2/command/wininst-9.0-amd64.exe Binary files differdeleted file mode 100644 index 11d8011..0000000 --- a/src/distutils2/command/wininst-9.0-amd64.exe +++ /dev/null diff --git a/src/distutils2/command/wininst-9.0.exe b/src/distutils2/command/wininst-9.0.exe Binary files differdeleted file mode 100644 index dadb31d..0000000 --- a/src/distutils2/command/wininst-9.0.exe +++ /dev/null diff --git a/src/distutils2/compat.py b/src/distutils2/compat.py deleted file mode 100644 index 86c733a..0000000 --- a/src/distutils2/compat.py +++ /dev/null @@ -1,64 +0,0 @@ -""" distutils2.compat - -Used to provide classes, variables and imports which can be used to -support distutils2 across versions(2.x and 3.x) -""" - -import logging - - -try: - from distutils2.util import Mixin2to3 as _Mixin2to3 - from distutils2 import run_2to3_on_doctests - from lib2to3.refactor import get_fixers_from_package - _CONVERT = True - _KLASS = _Mixin2to3 -except ImportError: - _CONVERT = False - _KLASS = object - -# marking public APIs -__all__ = ['Mixin2to3'] - -class Mixin2to3(_KLASS): - """ The base class which can be used for refactoring. When run under - Python 3.0, the run_2to3 method provided by Mixin2to3 is overridden. - When run on Python 2.x, it merely creates a class which overrides run_2to3, - yet does nothing in particular with it. - """ - if _CONVERT: - def _run_2to3(self, files, doctests=[], fixers=[]): - """ Takes a list of files and doctests, and performs conversion - on those. - - First, the files which contain the code(`files`) are converted. - - Second, the doctests in `files` are converted. - - Thirdly, the doctests in `doctests` are converted. - """ - # if additional fixers are present, use them - if fixers: - self.fixer_names = fixers - - # Convert the ".py" files. - logging.info("Converting Python code") - _KLASS.run_2to3(self, files) - - # Convert the doctests in the ".py" files. - logging.info("Converting doctests with '.py' files") - _KLASS.run_2to3(self, files, doctests_only=True) - - # If the following conditions are met, then convert:- - # 1. User has specified the 'convert_2to3_doctests' option. So, we - # can expect that the list 'doctests' is not empty. - # 2. The default is allow distutils2 to allow conversion of text files - # containing doctests. It is set as - # distutils2.run_2to3_on_doctests - - if doctests != [] and run_2to3_on_doctests: - logging.info("Converting text files which contain doctests") - _KLASS.run_2to3(self, doctests, doctests_only=True) - else: - # If run on Python 2.x, there is nothing to do. - def _run_2to3(self, files, doctests=[], fixers=[]): - pass - - diff --git a/src/distutils2/compiler/__init__.py b/src/distutils2/compiler/__init__.py deleted file mode 100644 index 139597f..0000000 --- a/src/distutils2/compiler/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/src/distutils2/compiler/bcppcompiler.py b/src/distutils2/compiler/bcppcompiler.py deleted file mode 100644 index 71100df..0000000 --- a/src/distutils2/compiler/bcppcompiler.py +++ /dev/null @@ -1,394 +0,0 @@ -"""distutils.bcppcompiler - -Contains BorlandCCompiler, an implementation of the abstract CCompiler class -for the Borland C++ compiler. -""" - -# This implementation by Lyle Johnson, based on the original msvccompiler.py -# module and using the directions originally published by Gordon Williams. - -# XXX looks like there's a LOT of overlap between these two classes: -# someone should sit down and factor out the common code as -# WindowsCCompiler! --GPW - -__revision__ = "$Id: bcppcompiler.py 76956 2009-12-21 01:22:46Z tarek.ziade $" - -import os - -from distutils2.errors import (DistutilsExecError, CompileError, LibError, - LinkError, UnknownFileError) -from distutils2.compiler.ccompiler import CCompiler, gen_preprocess_options -from distutils2.file_util import write_file -from distutils2.dep_util import newer -from distutils2 import log - -class BCPPCompiler(CCompiler) : - """Concrete class that implements an interface to the Borland C/C++ - compiler, as defined by the CCompiler abstract class. - """ - - compiler_type = 'bcpp' - - # Just set this so CCompiler's constructor doesn't barf. We currently - # don't use the 'set_executables()' bureaucracy provided by CCompiler, - # as it really isn't necessary for this sort of single-compiler class. - # Would be nice to have a consistent interface with UnixCCompiler, - # though, so it's worth thinking about. - executables = {} - - # Private class data (need to distinguish C from C++ source for compiler) - _c_extensions = ['.c'] - _cpp_extensions = ['.cc', '.cpp', '.cxx'] - - # Needed for the filename generation methods provided by the - # base class, CCompiler. - src_extensions = _c_extensions + _cpp_extensions - obj_extension = '.obj' - static_lib_extension = '.lib' - shared_lib_extension = '.dll' - static_lib_format = shared_lib_format = '%s%s' - exe_extension = '.exe' - - - def __init__ (self, - verbose=0, - dry_run=0, - force=0): - - CCompiler.__init__ (self, verbose, dry_run, force) - - # These executables are assumed to all be in the path. - # Borland doesn't seem to use any special registry settings to - # indicate their installation locations. - - self.cc = "bcc32.exe" - self.linker = "ilink32.exe" - self.lib = "tlib.exe" - - self.preprocess_options = None - self.compile_options = ['/tWM', '/O2', '/q', '/g0'] - self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0'] - - self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x'] - self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x'] - self.ldflags_static = [] - self.ldflags_exe = ['/Gn', '/q', '/x'] - self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r'] - - - # -- Worker methods ------------------------------------------------ - - def compile(self, sources, - output_dir=None, macros=None, include_dirs=None, debug=0, - extra_preargs=None, extra_postargs=None, depends=None): - - macros, objects, extra_postargs, pp_opts, build = \ - self._setup_compile(output_dir, macros, include_dirs, sources, - depends, extra_postargs) - compile_opts = extra_preargs or [] - compile_opts.append ('-c') - if debug: - compile_opts.extend (self.compile_options_debug) - else: - compile_opts.extend (self.compile_options) - - for obj in objects: - try: - src, ext = build[obj] - except KeyError: - continue - # XXX why do the normpath here? - src = os.path.normpath(src) - obj = os.path.normpath(obj) - # XXX _setup_compile() did a mkpath() too but before the normpath. - # Is it possible to skip the normpath? - self.mkpath(os.path.dirname(obj)) - - if ext == '.res': - # This is already a binary file -- skip it. - continue # the 'for' loop - if ext == '.rc': - # This needs to be compiled to a .res file -- do it now. - try: - self.spawn (["brcc32", "-fo", obj, src]) - except DistutilsExecError, msg: - raise CompileError, msg - continue # the 'for' loop - - # The next two are both for the real compiler. - if ext in self._c_extensions: - input_opt = "" - elif ext in self._cpp_extensions: - input_opt = "-P" - else: - # Unknown file type -- no extra options. The compiler - # will probably fail, but let it just in case this is a - # file the compiler recognizes even if we don't. - input_opt = "" - - output_opt = "-o" + obj - - # Compiler command line syntax is: "bcc32 [options] file(s)". - # Note that the source file names must appear at the end of - # the command line. - try: - self.spawn ([self.cc] + compile_opts + pp_opts + - [input_opt, output_opt] + - extra_postargs + [src]) - except DistutilsExecError, msg: - raise CompileError, msg - - return objects - - # compile () - - - def create_static_lib (self, - objects, - output_libname, - output_dir=None, - debug=0, - target_lang=None): - - (objects, output_dir) = self._fix_object_args (objects, output_dir) - output_filename = \ - self.library_filename (output_libname, output_dir=output_dir) - - if self._need_link (objects, output_filename): - lib_args = [output_filename, '/u'] + objects - if debug: - pass # XXX what goes here? - try: - self.spawn ([self.lib] + lib_args) - except DistutilsExecError, msg: - raise LibError, msg - else: - log.debug("skipping %s (up-to-date)", output_filename) - - # create_static_lib () - - - def link (self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): - - # XXX this ignores 'build_temp'! should follow the lead of - # msvccompiler.py - - (objects, output_dir) = self._fix_object_args (objects, output_dir) - (libraries, library_dirs, runtime_library_dirs) = \ - self._fix_lib_args (libraries, library_dirs, runtime_library_dirs) - - if runtime_library_dirs: - log.warn("I don't know what to do with 'runtime_library_dirs': %s", - str(runtime_library_dirs)) - - if output_dir is not None: - output_filename = os.path.join (output_dir, output_filename) - - if self._need_link (objects, output_filename): - - # Figure out linker args based on type of target. - if target_desc == CCompiler.EXECUTABLE: - startup_obj = 'c0w32' - if debug: - ld_args = self.ldflags_exe_debug[:] - else: - ld_args = self.ldflags_exe[:] - else: - startup_obj = 'c0d32' - if debug: - ld_args = self.ldflags_shared_debug[:] - else: - ld_args = self.ldflags_shared[:] - - - # Create a temporary exports file for use by the linker - if export_symbols is None: - def_file = '' - else: - head, tail = os.path.split (output_filename) - modname, ext = os.path.splitext (tail) - temp_dir = os.path.dirname(objects[0]) # preserve tree structure - def_file = os.path.join (temp_dir, '%s.def' % modname) - contents = ['EXPORTS'] - for sym in (export_symbols or []): - contents.append(' %s=_%s' % (sym, sym)) - self.execute(write_file, (def_file, contents), - "writing %s" % def_file) - - # Borland C++ has problems with '/' in paths - objects2 = map(os.path.normpath, objects) - # split objects in .obj and .res files - # Borland C++ needs them at different positions in the command line - objects = [startup_obj] - resources = [] - for file in objects2: - (base, ext) = os.path.splitext(os.path.normcase(file)) - if ext == '.res': - resources.append(file) - else: - objects.append(file) - - - for l in library_dirs: - ld_args.append("/L%s" % os.path.normpath(l)) - ld_args.append("/L.") # we sometimes use relative paths - - # list of object files - ld_args.extend(objects) - - # XXX the command line syntax for Borland C++ is a bit wonky; - # certain filenames are jammed together in one big string, but - # comma-delimited. This doesn't mesh too well with the - # Unix-centric attitude (with a DOS/Windows quoting hack) of - # 'spawn()', so constructing the argument list is a bit - # awkward. Note that doing the obvious thing and jamming all - # the filenames and commas into one argument would be wrong, - # because 'spawn()' would quote any filenames with spaces in - # them. Arghghh!. Apparently it works fine as coded... - - # name of dll/exe file - ld_args.extend([',',output_filename]) - # no map file and start libraries - ld_args.append(',,') - - for lib in libraries: - # see if we find it and if there is a bcpp specific lib - # (xxx_bcpp.lib) - libfile = self.find_library_file(library_dirs, lib, debug) - if libfile is None: - ld_args.append(lib) - # probably a BCPP internal library -- don't warn - else: - # full name which prefers bcpp_xxx.lib over xxx.lib - ld_args.append(libfile) - - # some default libraries - ld_args.append ('import32') - ld_args.append ('cw32mt') - - # def file for export symbols - ld_args.extend([',',def_file]) - # add resource files - ld_args.append(',') - ld_args.extend(resources) - - - if extra_preargs: - ld_args[:0] = extra_preargs - if extra_postargs: - ld_args.extend(extra_postargs) - - self.mkpath (os.path.dirname (output_filename)) - try: - self.spawn ([self.linker] + ld_args) - except DistutilsExecError, msg: - raise LinkError, msg - - else: - log.debug("skipping %s (up-to-date)", output_filename) - - # link () - - # -- Miscellaneous methods ----------------------------------------- - - - def find_library_file (self, dirs, lib, debug=0): - # List of effective library names to try, in order of preference: - # xxx_bcpp.lib is better than xxx.lib - # and xxx_d.lib is better than xxx.lib if debug is set - # - # The "_bcpp" suffix is to handle a Python installation for people - # with multiple compilers (primarily Distutils hackers, I suspect - # ;-). The idea is they'd have one static library for each - # compiler they care about, since (almost?) every Windows compiler - # seems to have a different format for static libraries. - if debug: - dlib = (lib + "_d") - try_names = (dlib + "_bcpp", lib + "_bcpp", dlib, lib) - else: - try_names = (lib + "_bcpp", lib) - - for dir in dirs: - for name in try_names: - libfile = os.path.join(dir, self.library_filename(name)) - if os.path.exists(libfile): - return libfile - else: - # Oops, didn't find it in *any* of 'dirs' - return None - - # overwrite the one from CCompiler to support rc and res-files - def object_filenames (self, - source_filenames, - strip_dir=0, - output_dir=''): - if output_dir is None: output_dir = '' - obj_names = [] - for src_name in source_filenames: - # use normcase to make sure '.rc' is really '.rc' and not '.RC' - (base, ext) = os.path.splitext (os.path.normcase(src_name)) - if ext not in (self.src_extensions + ['.rc','.res']): - raise UnknownFileError, \ - "unknown file type '%s' (from '%s')" % \ - (ext, src_name) - if strip_dir: - base = os.path.basename (base) - if ext == '.res': - # these can go unchanged - obj_names.append (os.path.join (output_dir, base + ext)) - elif ext == '.rc': - # these need to be compiled to .res-files - obj_names.append (os.path.join (output_dir, base + '.res')) - else: - obj_names.append (os.path.join (output_dir, - base + self.obj_extension)) - return obj_names - - # object_filenames () - - def preprocess (self, - source, - output_file=None, - macros=None, - include_dirs=None, - extra_preargs=None, - extra_postargs=None): - - (_, macros, include_dirs) = \ - self._fix_compile_args(None, macros, include_dirs) - pp_opts = gen_preprocess_options(macros, include_dirs) - pp_args = ['cpp32.exe'] + pp_opts - if output_file is not None: - pp_args.append('-o' + output_file) - if extra_preargs: - pp_args[:0] = extra_preargs - if extra_postargs: - pp_args.extend(extra_postargs) - pp_args.append(source) - - # We need to preprocess: either we're being forced to, or the - # source file is newer than the target (or the target doesn't - # exist). - if self.force or output_file is None or newer(source, output_file): - if output_file: - self.mkpath(os.path.dirname(output_file)) - try: - self.spawn(pp_args) - except DistutilsExecError, msg: - print msg - raise CompileError, msg - - # preprocess() diff --git a/src/distutils2/compiler/ccompiler.py b/src/distutils2/compiler/ccompiler.py deleted file mode 100644 index 3a8d8dd..0000000 --- a/src/distutils2/compiler/ccompiler.py +++ /dev/null @@ -1,1158 +0,0 @@ -"""distutils.ccompiler - -Contains CCompiler, an abstract base class that defines the interface -for the Distutils compiler abstraction model.""" - -__revision__ = "$Id: ccompiler.py 77704 2010-01-23 09:23:15Z tarek.ziade $" - -import sys -import os -import re - -from distutils2.errors import (CompileError, LinkError, UnknownFileError, - DistutilsPlatformError, DistutilsModuleError) -from distutils2.util import split_quoted, execute, newer_group, spawn -from distutils2 import log -from shutil import move - -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig - -def customize_compiler(compiler): - """Do any platform-specific customization of a CCompiler instance. - - Mainly needed on Unix, so we can plug in the information that - varies across Unices and is stored in Python's Makefile. - """ - if compiler.compiler_type == "unix": - (cc, cxx, opt, cflags, ccshared, ldshared, so_ext, ar, ar_flags) = \ - sysconfig.get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', - 'CCSHARED', 'LDSHARED', 'SO', 'AR', - 'ARFLAGS') - - if 'CC' in os.environ: - cc = os.environ['CC'] - if 'CXX' in os.environ: - cxx = os.environ['CXX'] - if 'LDSHARED' in os.environ: - ldshared = os.environ['LDSHARED'] - if 'CPP' in os.environ: - cpp = os.environ['CPP'] - else: - cpp = cc + " -E" # not always - if 'LDFLAGS' in os.environ: - ldshared = ldshared + ' ' + os.environ['LDFLAGS'] - if 'CFLAGS' in os.environ: - cflags = opt + ' ' + os.environ['CFLAGS'] - ldshared = ldshared + ' ' + os.environ['CFLAGS'] - if 'CPPFLAGS' in os.environ: - cpp = cpp + ' ' + os.environ['CPPFLAGS'] - cflags = cflags + ' ' + os.environ['CPPFLAGS'] - ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] - if 'AR' in os.environ: - ar = os.environ['AR'] - if 'ARFLAGS' in os.environ: - archiver = ar + ' ' + os.environ['ARFLAGS'] - else: - if ar_flags is not None: - archiver = ar + ' ' + ar_flags - else: - # see if its the proper default value - # mmm I don't want to backport the makefile - archiver = ar + ' rc' - - cc_cmd = cc + ' ' + cflags - compiler.set_executables( - preprocessor=cpp, - compiler=cc_cmd, - compiler_so=cc_cmd + ' ' + ccshared, - compiler_cxx=cxx, - linker_so=ldshared, - linker_exe=cc, - archiver=archiver) - - compiler.shared_lib_extension = so_ext - -class CCompiler(object): - """Abstract base class to define the interface that must be implemented - by real compiler classes. Also has some utility methods used by - several compiler classes. - - The basic idea behind a compiler abstraction class is that each - instance can be used for all the compile/link steps in building a - single project. Thus, attributes common to all of those compile and - link steps -- include directories, macros to define, libraries to link - against, etc. -- are attributes of the compiler instance. To allow for - variability in how individual files are treated, most of those - attributes may be varied on a per-compilation or per-link basis. - """ - - # 'compiler_type' is a class attribute that identifies this class. It - # keeps code that wants to know what kind of compiler it's dealing with - # from having to import all possible compiler classes just to do an - # 'isinstance'. In concrete CCompiler subclasses, 'compiler_type' - # should really, really be one of the keys of the 'compiler_class' - # dictionary (see below -- used by the 'new_compiler()' factory - # function) -- authors of new compiler interface classes are - # responsible for updating 'compiler_class'! - compiler_type = None - - # XXX things not handled by this compiler abstraction model: - # * client can't provide additional options for a compiler, - # e.g. warning, optimization, debugging flags. Perhaps this - # should be the domain of concrete compiler abstraction classes - # (UnixCCompiler, MSVCCompiler, etc.) -- or perhaps the base - # class should have methods for the common ones. - # * can't completely override the include or library searchg - # path, ie. no "cc -I -Idir1 -Idir2" or "cc -L -Ldir1 -Ldir2". - # I'm not sure how widely supported this is even by Unix - # compilers, much less on other platforms. And I'm even less - # sure how useful it is; maybe for cross-compiling, but - # support for that is a ways off. (And anyways, cross - # compilers probably have a dedicated binary with the - # right paths compiled in. I hope.) - # * can't do really freaky things with the library list/library - # dirs, e.g. "-Ldir1 -lfoo -Ldir2 -lfoo" to link against - # different versions of libfoo.a in different locations. I - # think this is useless without the ability to null out the - # library search path anyways. - - - # Subclasses that rely on the standard filename generation methods - # implemented below should override these; see the comment near - # those methods ('object_filenames()' et. al.) for details: - src_extensions = None # list of strings - obj_extension = None # string - static_lib_extension = None - shared_lib_extension = None # string - static_lib_format = None # format string - shared_lib_format = None # prob. same as static_lib_format - exe_extension = None # string - - # Default language settings. language_map is used to detect a source - # file or Extension target language, checking source filenames. - # language_order is used to detect the language precedence, when deciding - # what language to use when mixing source types. For example, if some - # extension has two files with ".c" extension, and one with ".cpp", it - # is still linked as c++. - language_map = {".c" : "c", - ".cc" : "c++", - ".cpp" : "c++", - ".cxx" : "c++", - ".m" : "objc", - } - language_order = ["c++", "objc", "c"] - - def __init__ (self, verbose=0, dry_run=0, force=0): - self.dry_run = dry_run - self.force = force - self.verbose = verbose - - # 'output_dir': a common output directory for object, library, - # shared object, and shared library files - self.output_dir = None - - # 'macros': a list of macro definitions (or undefinitions). A - # macro definition is a 2-tuple (name, value), where the value is - # either a string or None (no explicit value). A macro - # undefinition is a 1-tuple (name,). - self.macros = [] - - # 'include_dirs': a list of directories to search for include files - self.include_dirs = [] - - # 'libraries': a list of libraries to include in any link - # (library names, not filenames: eg. "foo" not "libfoo.a") - self.libraries = [] - - # 'library_dirs': a list of directories to search for libraries - self.library_dirs = [] - - # 'runtime_library_dirs': a list of directories to search for - # shared libraries/objects at runtime - self.runtime_library_dirs = [] - - # 'objects': a list of object files (or similar, such as explicitly - # named library files) to include on any link - self.objects = [] - - for key in self.executables.keys(): - self.set_executable(key, self.executables[key]) - - def set_executables(self, **args): - """Define the executables (and options for them) that will be run - to perform the various stages of compilation. The exact set of - executables that may be specified here depends on the compiler - class (via the 'executables' class attribute), but most will have: - compiler the C/C++ compiler - linker_so linker used to create shared objects and libraries - linker_exe linker used to create binary executables - archiver static library creator - - On platforms with a command line (Unix, DOS/Windows), each of these - is a string that will be split into executable name and (optional) - list of arguments. (Splitting the string is done similarly to how - Unix shells operate: words are delimited by spaces, but quotes and - backslashes can override this. See - 'distutils.util.split_quoted()'.) - """ - - # Note that some CCompiler implementation classes will define class - # attributes 'cpp', 'cc', etc. with hard-coded executable names; - # this is appropriate when a compiler class is for exactly one - # compiler/OS combination (eg. MSVCCompiler). Other compiler - # classes (UnixCCompiler, in particular) are driven by information - # discovered at run-time, since there are many different ways to do - # basically the same things with Unix C compilers. - - for key in args.keys(): - if key not in self.executables: - raise ValueError, \ - "unknown executable '%s' for class %s" % \ - (key, self.__class__.__name__) - self.set_executable(key, args[key]) - - def set_executable(self, key, value): - if isinstance(value, str): - setattr(self, key, split_quoted(value)) - else: - setattr(self, key, value) - - def _find_macro(self, name): - i = 0 - for defn in self.macros: - if defn[0] == name: - return i - i = i + 1 - return None - - def _check_macro_definitions(self, definitions): - """Ensures that every element of 'definitions' is a valid macro - definition, ie. either (name,value) 2-tuple or a (name,) tuple. Do - nothing if all definitions are OK, raise TypeError otherwise. - """ - for defn in definitions: - if not (isinstance(defn, tuple) and - (len (defn) == 1 or - (len (defn) == 2 and - (isinstance(defn[1], str) or defn[1] is None))) and - isinstance(defn[0], str)): - raise TypeError, \ - ("invalid macro definition '%s': " % defn) + \ - "must be tuple (string,), (string, string), or " + \ - "(string, None)" - - - # -- Bookkeeping methods ------------------------------------------- - - def define_macro(self, name, value=None): - """Define a preprocessor macro for all compilations driven by this - compiler object. The optional parameter 'value' should be a - string; if it is not supplied, then the macro will be defined - without an explicit value and the exact outcome depends on the - compiler used (XXX true? does ANSI say anything about this?) - """ - # Delete from the list of macro definitions/undefinitions if - # already there (so that this one will take precedence). - i = self._find_macro (name) - if i is not None: - del self.macros[i] - - defn = (name, value) - self.macros.append (defn) - - def undefine_macro(self, name): - """Undefine a preprocessor macro for all compilations driven by - this compiler object. If the same macro is defined by - 'define_macro()' and undefined by 'undefine_macro()' the last call - takes precedence (including multiple redefinitions or - undefinitions). If the macro is redefined/undefined on a - per-compilation basis (ie. in the call to 'compile()'), then that - takes precedence. - """ - # Delete from the list of macro definitions/undefinitions if - # already there (so that this one will take precedence). - i = self._find_macro (name) - if i is not None: - del self.macros[i] - - undefn = (name,) - self.macros.append (undefn) - - def add_include_dir(self, dir): - """Add 'dir' to the list of directories that will be searched for - header files. The compiler is instructed to search directories in - the order in which they are supplied by successive calls to - 'add_include_dir()'. - """ - self.include_dirs.append (dir) - - def set_include_dirs(self, dirs): - """Set the list of directories that will be searched to 'dirs' (a - list of strings). Overrides any preceding calls to - 'add_include_dir()'; subsequence calls to 'add_include_dir()' add - to the list passed to 'set_include_dirs()'. This does not affect - any list of standard include directories that the compiler may - search by default. - """ - self.include_dirs = dirs[:] - - def add_library(self, libname): - """Add 'libname' to the list of libraries that will be included in - all links driven by this compiler object. Note that 'libname' - should *not* be the name of a file containing a library, but the - name of the library itself: the actual filename will be inferred by - the linker, the compiler, or the compiler class (depending on the - platform). - - The linker will be instructed to link against libraries in the - order they were supplied to 'add_library()' and/or - 'set_libraries()'. It is perfectly valid to duplicate library - names; the linker will be instructed to link against libraries as - many times as they are mentioned. - """ - self.libraries.append (libname) - - def set_libraries(self, libnames): - """Set the list of libraries to be included in all links driven by - this compiler object to 'libnames' (a list of strings). This does - not affect any standard system libraries that the linker may - include by default. - """ - self.libraries = libnames[:] - - - def add_library_dir(self, dir): - """Add 'dir' to the list of directories that will be searched for - libraries specified to 'add_library()' and 'set_libraries()'. The - linker will be instructed to search for libraries in the order they - are supplied to 'add_library_dir()' and/or 'set_library_dirs()'. - """ - self.library_dirs.append(dir) - - def set_library_dirs(self, dirs): - """Set the list of library search directories to 'dirs' (a list of - strings). This does not affect any standard library search path - that the linker may search by default. - """ - self.library_dirs = dirs[:] - - def add_runtime_library_dir(self, dir): - """Add 'dir' to the list of directories that will be searched for - shared libraries at runtime. - """ - self.runtime_library_dirs.append(dir) - - def set_runtime_library_dirs(self, dirs): - """Set the list of directories to search for shared libraries at - runtime to 'dirs' (a list of strings). This does not affect any - standard search path that the runtime linker may search by - default. - """ - self.runtime_library_dirs = dirs[:] - - def add_link_object(self, object): - """Add 'object' to the list of object files (or analogues, such as - explicitly named library files or the output of "resource - compilers") to be included in every link driven by this compiler - object. - """ - self.objects.append(object) - - def set_link_objects(self, objects): - """Set the list of object files (or analogues) to be included in - every link to 'objects'. This does not affect any standard object - files that the linker may include by default (such as system - libraries). - """ - self.objects = objects[:] - - - # -- Private utility methods -------------------------------------- - # (here for the convenience of subclasses) - - # Helper method to prep compiler in subclass compile() methods - - def _setup_compile(self, outdir, macros, incdirs, sources, depends, - extra): - """Process arguments and decide which source files to compile.""" - if outdir is None: - outdir = self.output_dir - elif not isinstance(outdir, str): - raise TypeError, "'output_dir' must be a string or None" - - if macros is None: - macros = self.macros - elif isinstance(macros, list): - macros = macros + (self.macros or []) - else: - raise TypeError, "'macros' (if supplied) must be a list of tuples" - - if incdirs is None: - incdirs = self.include_dirs - elif isinstance(incdirs, (list, tuple)): - incdirs = list(incdirs) + (self.include_dirs or []) - else: - raise TypeError, \ - "'include_dirs' (if supplied) must be a list of strings" - - if extra is None: - extra = [] - - # Get the list of expected output (object) files - objects = self.object_filenames(sources, - strip_dir=0, - output_dir=outdir) - assert len(objects) == len(sources) - - pp_opts = gen_preprocess_options(macros, incdirs) - - build = {} - for i in range(len(sources)): - src = sources[i] - obj = objects[i] - ext = os.path.splitext(src)[1] - self.mkpath(os.path.dirname(obj)) - build[obj] = (src, ext) - - return macros, objects, extra, pp_opts, build - - def _get_cc_args(self, pp_opts, debug, before): - # works for unixccompiler, emxccompiler, cygwinccompiler - cc_args = pp_opts + ['-c'] - if debug: - cc_args[:0] = ['-g'] - if before: - cc_args[:0] = before - return cc_args - - def _fix_compile_args(self, output_dir, macros, include_dirs): - """Typecheck and fix-up some of the arguments to the 'compile()' - method, and return fixed-up values. Specifically: if 'output_dir' - is None, replaces it with 'self.output_dir'; ensures that 'macros' - is a list, and augments it with 'self.macros'; ensures that - 'include_dirs' is a list, and augments it with 'self.include_dirs'. - Guarantees that the returned values are of the correct type, - i.e. for 'output_dir' either string or None, and for 'macros' and - 'include_dirs' either list or None. - """ - if output_dir is None: - output_dir = self.output_dir - elif not isinstance(output_dir, str): - raise TypeError, "'output_dir' must be a string or None" - - if macros is None: - macros = self.macros - elif isinstance(macros, list): - macros = macros + (self.macros or []) - else: - raise TypeError, "'macros' (if supplied) must be a list of tuples" - - if include_dirs is None: - include_dirs = self.include_dirs - elif isinstance(include_dirs, (list, tuple)): - include_dirs = list (include_dirs) + (self.include_dirs or []) - else: - raise TypeError, \ - "'include_dirs' (if supplied) must be a list of strings" - - return output_dir, macros, include_dirs - - def _fix_object_args(self, objects, output_dir): - """Typecheck and fix up some arguments supplied to various methods. - Specifically: ensure that 'objects' is a list; if output_dir is - None, replace with self.output_dir. Return fixed versions of - 'objects' and 'output_dir'. - """ - if not isinstance(objects, (list, tuple)): - raise TypeError, \ - "'objects' must be a list or tuple of strings" - objects = list (objects) - - if output_dir is None: - output_dir = self.output_dir - elif not isinstance(output_dir, str): - raise TypeError, "'output_dir' must be a string or None" - - return (objects, output_dir) - - def _fix_lib_args(self, libraries, library_dirs, runtime_library_dirs): - """Typecheck and fix up some of the arguments supplied to the - 'link_*' methods. Specifically: ensure that all arguments are - lists, and augment them with their permanent versions - (eg. 'self.libraries' augments 'libraries'). Return a tuple with - fixed versions of all arguments. - """ - if libraries is None: - libraries = self.libraries - elif isinstance(libraries, (list, tuple)): - libraries = list (libraries) + (self.libraries or []) - else: - raise TypeError, \ - "'libraries' (if supplied) must be a list of strings" - - if library_dirs is None: - library_dirs = self.library_dirs - elif isinstance(library_dirs, (list, tuple)): - library_dirs = list (library_dirs) + (self.library_dirs or []) - else: - raise TypeError, \ - "'library_dirs' (if supplied) must be a list of strings" - - if runtime_library_dirs is None: - runtime_library_dirs = self.runtime_library_dirs - elif isinstance(runtime_library_dirs, (list, tuple)): - runtime_library_dirs = (list (runtime_library_dirs) + - (self.runtime_library_dirs or [])) - else: - raise TypeError, \ - "'runtime_library_dirs' (if supplied) " + \ - "must be a list of strings" - - return (libraries, library_dirs, runtime_library_dirs) - - def _need_link(self, objects, output_file): - """Return true if we need to relink the files listed in 'objects' - to recreate 'output_file'. - """ - if self.force: - return 1 - else: - if self.dry_run: - newer = newer_group(objects, output_file, missing='newer') - else: - newer = newer_group(objects, output_file) - return newer - - def detect_language(self, sources): - """Detect the language of a given file, or list of files. Uses - language_map, and language_order to do the job. - """ - if not isinstance(sources, list): - sources = [sources] - lang = None - index = len(self.language_order) - for source in sources: - base, ext = os.path.splitext(source) - extlang = self.language_map.get(ext) - try: - extindex = self.language_order.index(extlang) - if extindex < index: - lang = extlang - index = extindex - except ValueError: - pass - return lang - - # -- Worker methods ------------------------------------------------ - # (must be implemented by subclasses) - - def preprocess(self, source, output_file=None, macros=None, - include_dirs=None, extra_preargs=None, extra_postargs=None): - """Preprocess a single C/C++ source file, named in 'source'. - Output will be written to file named 'output_file', or stdout if - 'output_file' not supplied. 'macros' is a list of macro - definitions as for 'compile()', which will augment the macros set - with 'define_macro()' and 'undefine_macro()'. 'include_dirs' is a - list of directory names that will be added to the default list. - - Raises PreprocessError on failure. - """ - pass - - def compile(self, sources, output_dir=None, macros=None, - include_dirs=None, debug=0, extra_preargs=None, - extra_postargs=None, depends=None): - """Compile one or more source files. - - 'sources' must be a list of filenames, most likely C/C++ - files, but in reality anything that can be handled by a - particular compiler and compiler class (eg. MSVCCompiler can - handle resource files in 'sources'). Return a list of object - filenames, one per source filename in 'sources'. Depending on - the implementation, not all source files will necessarily be - compiled, but all corresponding object filenames will be - returned. - - If 'output_dir' is given, object files will be put under it, while - retaining their original path component. That is, "foo/bar.c" - normally compiles to "foo/bar.o" (for a Unix implementation); if - 'output_dir' is "build", then it would compile to - "build/foo/bar.o". - - 'macros', if given, must be a list of macro definitions. A macro - definition is either a (name, value) 2-tuple or a (name,) 1-tuple. - The former defines a macro; if the value is None, the macro is - defined without an explicit value. The 1-tuple case undefines a - macro. Later definitions/redefinitions/ undefinitions take - precedence. - - 'include_dirs', if given, must be a list of strings, the - directories to add to the default include file search path for this - compilation only. - - 'debug' is a boolean; if true, the compiler will be instructed to - output debug symbols in (or alongside) the object file(s). - - 'extra_preargs' and 'extra_postargs' are implementation- dependent. - On platforms that have the notion of a command line (e.g. Unix, - DOS/Windows), they are most likely lists of strings: extra - command-line arguments to prepand/append to the compiler command - line. On other platforms, consult the implementation class - documentation. In any event, they are intended as an escape hatch - for those occasions when the abstract compiler framework doesn't - cut the mustard. - - 'depends', if given, is a list of filenames that all targets - depend on. If a source file is older than any file in - depends, then the source file will be recompiled. This - supports dependency tracking, but only at a coarse - granularity. - - Raises CompileError on failure. - """ - # A concrete compiler class can either override this method - # entirely or implement _compile(). - - macros, objects, extra_postargs, pp_opts, build = \ - self._setup_compile(output_dir, macros, include_dirs, sources, - depends, extra_postargs) - cc_args = self._get_cc_args(pp_opts, debug, extra_preargs) - - for obj in objects: - try: - src, ext = build[obj] - except KeyError: - continue - self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) - - # Return *all* object filenames, not just the ones we just built. - return objects - - def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): - """Compile 'src' to product 'obj'.""" - - # A concrete compiler class that does not override compile() - # should implement _compile(). - pass - - def create_static_lib(self, objects, output_libname, output_dir=None, - debug=0, target_lang=None): - """Link a bunch of stuff together to create a static library file. - The "bunch of stuff" consists of the list of object files supplied - as 'objects', the extra object files supplied to - 'add_link_object()' and/or 'set_link_objects()', the libraries - supplied to 'add_library()' and/or 'set_libraries()', and the - libraries supplied as 'libraries' (if any). - - 'output_libname' should be a library name, not a filename; the - filename will be inferred from the library name. 'output_dir' is - the directory where the library file will be put. - - 'debug' is a boolean; if true, debugging information will be - included in the library (note that on most platforms, it is the - compile step where this matters: the 'debug' flag is included here - just for consistency). - - 'target_lang' is the target language for which the given objects - are being compiled. This allows specific linkage time treatment of - certain languages. - - Raises LibError on failure. - """ - pass - - # values for target_desc parameter in link() - SHARED_OBJECT = "shared_object" - SHARED_LIBRARY = "shared_library" - EXECUTABLE = "executable" - - def link(self, target_desc, objects, output_filename, output_dir=None, - libraries=None, library_dirs=None, runtime_library_dirs=None, - export_symbols=None, debug=0, extra_preargs=None, - extra_postargs=None, build_temp=None, target_lang=None): - """Link a bunch of stuff together to create an executable or - shared library file. - - The "bunch of stuff" consists of the list of object files supplied - as 'objects'. 'output_filename' should be a filename. If - 'output_dir' is supplied, 'output_filename' is relative to it - (i.e. 'output_filename' can provide directory components if - needed). - - 'libraries' is a list of libraries to link against. These are - library names, not filenames, since they're translated into - filenames in a platform-specific way (eg. "foo" becomes "libfoo.a" - on Unix and "foo.lib" on DOS/Windows). However, they can include a - directory component, which means the linker will look in that - specific directory rather than searching all the normal locations. - - 'library_dirs', if supplied, should be a list of directories to - search for libraries that were specified as bare library names - (ie. no directory component). These are on top of the system - default and those supplied to 'add_library_dir()' and/or - 'set_library_dirs()'. 'runtime_library_dirs' is a list of - directories that will be embedded into the shared library and used - to search for other shared libraries that *it* depends on at - run-time. (This may only be relevant on Unix.) - - 'export_symbols' is a list of symbols that the shared library will - export. (This appears to be relevant only on Windows.) - - 'debug' is as for 'compile()' and 'create_static_lib()', with the - slight distinction that it actually matters on most platforms (as - opposed to 'create_static_lib()', which includes a 'debug' flag - mostly for form's sake). - - 'extra_preargs' and 'extra_postargs' are as for 'compile()' (except - of course that they supply command-line arguments for the - particular linker being used). - - 'target_lang' is the target language for which the given objects - are being compiled. This allows specific linkage time treatment of - certain languages. - - Raises LinkError on failure. - """ - raise NotImplementedError - - - # Old 'link_*()' methods, rewritten to use the new 'link()' method. - - def link_shared_lib(self, objects, output_libname, output_dir=None, - libraries=None, library_dirs=None, - runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, - build_temp=None, target_lang=None): - self.link(CCompiler.SHARED_LIBRARY, objects, - self.library_filename(output_libname, lib_type='shared'), - output_dir, - libraries, library_dirs, runtime_library_dirs, - export_symbols, debug, - extra_preargs, extra_postargs, build_temp, target_lang) - - - def link_shared_object(self, objects, output_filename, output_dir=None, - libraries=None, library_dirs=None, - runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, - build_temp=None, target_lang=None): - self.link(CCompiler.SHARED_OBJECT, objects, - output_filename, output_dir, - libraries, library_dirs, runtime_library_dirs, - export_symbols, debug, - extra_preargs, extra_postargs, build_temp, target_lang) - - def link_executable(self, objects, output_progname, output_dir=None, - libraries=None, library_dirs=None, - runtime_library_dirs=None, debug=0, extra_preargs=None, - extra_postargs=None, target_lang=None): - self.link(CCompiler.EXECUTABLE, objects, - self.executable_filename(output_progname), output_dir, - libraries, library_dirs, runtime_library_dirs, None, - debug, extra_preargs, extra_postargs, None, target_lang) - - - # -- Miscellaneous methods ----------------------------------------- - # These are all used by the 'gen_lib_options() function; there is - # no appropriate default implementation so subclasses should - # implement all of these. - - def library_dir_option(self, dir): - """Return the compiler option to add 'dir' to the list of - directories searched for libraries. - """ - raise NotImplementedError - - def runtime_library_dir_option(self, dir): - """Return the compiler option to add 'dir' to the list of - directories searched for runtime libraries. - """ - raise NotImplementedError - - def library_option(self, lib): - """Return the compiler option to add 'dir' to the list of libraries - linked into the shared library or executable. - """ - raise NotImplementedError - - def has_function(self, funcname, includes=None, include_dirs=None, - libraries=None, library_dirs=None): - """Return a boolean indicating whether funcname is supported on - the current platform. The optional arguments can be used to - augment the compilation environment. - """ - - # this can't be included at module scope because it tries to - # import math which might not be available at that point - maybe - # the necessary logic should just be inlined? - import tempfile - if includes is None: - includes = [] - if include_dirs is None: - include_dirs = [] - if libraries is None: - libraries = [] - if library_dirs is None: - library_dirs = [] - fd, fname = tempfile.mkstemp(".c", funcname, text=True) - f = os.fdopen(fd, "w") - try: - for incl in includes: - f.write("""#include "%s"\n""" % incl) - f.write("""\ -main (int argc, char **argv) { - %s(); -} -""" % funcname) - finally: - f.close() - try: - objects = self.compile([fname], include_dirs=include_dirs) - except CompileError: - return False - - try: - self.link_executable(objects, "a.out", - libraries=libraries, - library_dirs=library_dirs) - except (LinkError, TypeError): - return False - return True - - def find_library_file (self, dirs, lib, debug=0): - """Search the specified list of directories for a static or shared - library file 'lib' and return the full path to that file. If - 'debug' true, look for a debugging version (if that makes sense on - the current platform). Return None if 'lib' wasn't found in any of - the specified directories. - """ - raise NotImplementedError - - # -- Filename generation methods ----------------------------------- - - # The default implementation of the filename generating methods are - # prejudiced towards the Unix/DOS/Windows view of the world: - # * object files are named by replacing the source file extension - # (eg. .c/.cpp -> .o/.obj) - # * library files (shared or static) are named by plugging the - # library name and extension into a format string, eg. - # "lib%s.%s" % (lib_name, ".a") for Unix static libraries - # * executables are named by appending an extension (possibly - # empty) to the program name: eg. progname + ".exe" for - # Windows - # - # To reduce redundant code, these methods expect to find - # several attributes in the current object (presumably defined - # as class attributes): - # * src_extensions - - # list of C/C++ source file extensions, eg. ['.c', '.cpp'] - # * obj_extension - - # object file extension, eg. '.o' or '.obj' - # * static_lib_extension - - # extension for static library files, eg. '.a' or '.lib' - # * shared_lib_extension - - # extension for shared library/object files, eg. '.so', '.dll' - # * static_lib_format - - # format string for generating static library filenames, - # eg. 'lib%s.%s' or '%s.%s' - # * shared_lib_format - # format string for generating shared library filenames - # (probably same as static_lib_format, since the extension - # is one of the intended parameters to the format string) - # * exe_extension - - # extension for executable files, eg. '' or '.exe' - - def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): - if output_dir is None: - output_dir = '' - obj_names = [] - for src_name in source_filenames: - base, ext = os.path.splitext(src_name) - base = os.path.splitdrive(base)[1] # Chop off the drive - base = base[os.path.isabs(base):] # If abs, chop off leading / - if ext not in self.src_extensions: - raise UnknownFileError, \ - "unknown file type '%s' (from '%s')" % (ext, src_name) - if strip_dir: - base = os.path.basename(base) - obj_names.append(os.path.join(output_dir, - base + self.obj_extension)) - return obj_names - - def shared_object_filename(self, basename, strip_dir=0, output_dir=''): - assert output_dir is not None - if strip_dir: - basename = os.path.basename (basename) - return os.path.join(output_dir, basename + self.shared_lib_extension) - - def executable_filename(self, basename, strip_dir=0, output_dir=''): - assert output_dir is not None - if strip_dir: - basename = os.path.basename (basename) - return os.path.join(output_dir, basename + (self.exe_extension or '')) - - def library_filename(self, libname, lib_type='static', # or 'shared' - strip_dir=0, output_dir=''): - assert output_dir is not None - if lib_type not in ("static", "shared", "dylib"): - raise ValueError, "'lib_type' must be \"static\", \"shared\" or \"dylib\"" - fmt = getattr(self, lib_type + "_lib_format") - ext = getattr(self, lib_type + "_lib_extension") - - dir, base = os.path.split (libname) - filename = fmt % (base, ext) - if strip_dir: - dir = '' - - return os.path.join(output_dir, dir, filename) - - - # -- Utility methods ----------------------------------------------- - - def announce(self, msg, level=1): - log.debug(msg) - - def debug_print(self, msg): - from distutils2.debug import DEBUG - if DEBUG: - print msg - - def warn(self, msg): - sys.stderr.write("warning: %s\n" % msg) - - def execute(self, func, args, msg=None, level=1): - execute(func, args, msg, self.dry_run) - - def spawn(self, cmd): - spawn(cmd, dry_run=self.dry_run) - - def move_file(self, src, dst): - if self.dry_run: - return # XXX log ? - return move(src, dst) - - def mkpath(self, name, mode=0777): - name = os.path.normpath(name) - if os.path.isdir(name) or name == '': - return - if self.dry_run: - head = '' - for part in name.split(os.sep): - log.info("created directory %s%s", head, part) - head += part + os.sep - return - os.makedirs(name, mode) - - -# Map a sys.platform/os.name ('posix', 'nt') to the default compiler -# type for that platform. Keys are interpreted as re match -# patterns. Order is important; platform mappings are preferred over -# OS names. -_default_compilers = ( - - # Platform string mappings - - # on a cygwin built python we can use gcc like an ordinary UNIXish - # compiler - ('cygwin.*', 'unix'), - ('os2emx', 'emx'), - - # OS name mappings - ('posix', 'unix'), - ('nt', 'msvc'), - - ) - -def get_default_compiler(osname=None, platform=None): - """ Determine the default compiler to use for the given platform. - - osname should be one of the standard Python OS names (i.e. the - ones returned by os.name) and platform the common value - returned by sys.platform for the platform in question. - - The default values are os.name and sys.platform in case the - parameters are not given. - - """ - if osname is None: - osname = os.name - if platform is None: - platform = sys.platform - for pattern, compiler in _default_compilers: - if re.match(pattern, platform) is not None or \ - re.match(pattern, osname) is not None: - return compiler - # Default to Unix compiler - return 'unix' - -# Map compiler types to (module_name, class_name) pairs -- ie. where to -# find the code that implements an interface to this compiler. (The module -# is assumed to be in the 'distutils' package.) -compiler_class = { 'unix': ('unixccompiler', 'UnixCCompiler', - "standard UNIX-style compiler"), - 'msvc': ('msvccompiler', 'MSVCCompiler', - "Microsoft Visual C++"), - 'cygwin': ('cygwinccompiler', 'CygwinCCompiler', - "Cygwin port of GNU C Compiler for Win32"), - 'mingw32': ('cygwinccompiler', 'Mingw32CCompiler', - "Mingw32 port of GNU C Compiler for Win32"), - 'bcpp': ('bcppcompiler', 'BCPPCompiler', - "Borland C++ Compiler"), - 'emx': ('emxccompiler', 'EMXCCompiler', - "EMX port of GNU C Compiler for OS/2"), - } - -def show_compilers(): - """Print list of available compilers (used by the "--help-compiler" - options to "build", "build_ext", "build_clib"). - """ - # XXX this "knows" that the compiler option it's describing is - # "--compiler", which just happens to be the case for the three - # commands that use it. - from distutils2.fancy_getopt import FancyGetopt - compilers = [] - for compiler in compiler_class.keys(): - compilers.append(("compiler="+compiler, None, - compiler_class[compiler][2])) - compilers.sort() - pretty_printer = FancyGetopt(compilers) - pretty_printer.print_help("List of available compilers:") - - -def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0): - """Generate an instance of some CCompiler subclass for the supplied - platform/compiler combination. 'plat' defaults to 'os.name' - (eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler - for that platform. Currently only 'posix' and 'nt' are supported, and - the default compilers are "traditional Unix interface" (UnixCCompiler - class) and Visual C++ (MSVCCompiler class). Note that it's perfectly - possible to ask for a Unix compiler object under Windows, and a - Microsoft compiler object under Unix -- if you supply a value for - 'compiler', 'plat' is ignored. - """ - if plat is None: - plat = os.name - - try: - if compiler is None: - compiler = get_default_compiler(plat) - - (module_name, class_name, long_description) = compiler_class[compiler] - except KeyError: - msg = "don't know how to compile C/C++ code on platform '%s'" % plat - if compiler is not None: - msg = msg + " with '%s' compiler" % compiler - raise DistutilsPlatformError, msg - - try: - module_name = "distutils2.compiler." + module_name - __import__ (module_name) - module = sys.modules[module_name] - cls = vars(module)[class_name] - except ImportError: - raise DistutilsModuleError, \ - "can't compile C/C++ code: unable to load module '%s'" % \ - module_name - except KeyError: - raise DistutilsModuleError, \ - ("can't compile C/C++ code: unable to find class '%s' " + - "in module '%s'") % (class_name, module_name) - - # XXX The None is necessary to preserve backwards compatibility - # with classes that expect verbose to be the first positional - # argument. - return cls(None, dry_run, force) - - -def gen_preprocess_options(macros, include_dirs): - """Generate C pre-processor options (-D, -U, -I) as used by at least - two types of compilers: the typical Unix compiler and Visual C++. - 'macros' is the usual thing, a list of 1- or 2-tuples, where (name,) - means undefine (-U) macro 'name', and (name,value) means define (-D) - macro 'name' to 'value'. 'include_dirs' is just a list of directory - names to be added to the header file search path (-I). Returns a list - of command-line options suitable for either Unix compilers or Visual - C++. - """ - # XXX it would be nice (mainly aesthetic, and so we don't generate - # stupid-looking command lines) to go over 'macros' and eliminate - # redundant definitions/undefinitions (ie. ensure that only the - # latest mention of a particular macro winds up on the command - # line). I don't think it's essential, though, since most (all?) - # Unix C compilers only pay attention to the latest -D or -U - # mention of a macro on their command line. Similar situation for - # 'include_dirs'. I'm punting on both for now. Anyways, weeding out - # redundancies like this should probably be the province of - # CCompiler, since the data structures used are inherited from it - # and therefore common to all CCompiler classes. - - pp_opts = [] - for macro in macros: - - if not (isinstance(macro, tuple) and - 1 <= len (macro) <= 2): - raise TypeError, \ - ("bad macro definition '%s': " + - "each element of 'macros' list must be a 1- or 2-tuple") % \ - macro - - if len (macro) == 1: # undefine this macro - pp_opts.append ("-U%s" % macro[0]) - elif len (macro) == 2: - if macro[1] is None: # define with no explicit value - pp_opts.append ("-D%s" % macro[0]) - else: - # XXX *don't* need to be clever about quoting the - # macro value here, because we're going to avoid the - # shell at all costs when we spawn the command! - pp_opts.append ("-D%s=%s" % macro) - - for dir in include_dirs: - pp_opts.append ("-I%s" % dir) - - return pp_opts - - -def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries): - """Generate linker options for searching library directories and - linking with specific libraries. - - 'libraries' and 'library_dirs' are, respectively, lists of library names - (not filenames!) and search directories. Returns a list of command-line - options suitable for use with some compiler (depending on the two format - strings passed in). - """ - lib_opts = [] - - for dir in library_dirs: - lib_opts.append(compiler.library_dir_option(dir)) - - for dir in runtime_library_dirs: - opt = compiler.runtime_library_dir_option(dir) - if isinstance(opt, list): - lib_opts.extend(opt) - else: - lib_opts.append(opt) - - # XXX it's important that we *not* remove redundant library mentions! - # sometimes you really do have to say "-lfoo -lbar -lfoo" in order to - # resolve all symbols. I just hope we never have to say "-lfoo obj.o - # -lbar" to get things to work -- that's certainly a possibility, but a - # pretty nasty way to arrange your C code. - - for lib in libraries: - lib_dir, lib_name = os.path.split(lib) - if lib_dir != '': - lib_file = compiler.find_library_file([lib_dir], lib_name) - if lib_file is not None: - lib_opts.append(lib_file) - else: - compiler.warn("no library file corresponding to " - "'%s' found (skipping)" % lib) - else: - lib_opts.append(compiler.library_option(lib)) - - return lib_opts diff --git a/src/distutils2/compiler/cygwinccompiler.py b/src/distutils2/compiler/cygwinccompiler.py deleted file mode 100644 index 9f5ce77..0000000 --- a/src/distutils2/compiler/cygwinccompiler.py +++ /dev/null @@ -1,385 +0,0 @@ -"""distutils.cygwinccompiler - -Provides the CygwinCCompiler class, a subclass of UnixCCompiler that -handles the Cygwin port of the GNU C compiler to Windows. It also contains -the Mingw32CCompiler class which handles the mingw32 port of GCC (same as -cygwin in no-cygwin mode). -""" - -# problems: -# -# * if you use a msvc compiled python version (1.5.2) -# 1. you have to insert a __GNUC__ section in its config.h -# 2. you have to generate a import library for its dll -# - create a def-file for python??.dll -# - create a import library using -# dlltool --dllname python15.dll --def python15.def \ -# --output-lib libpython15.a -# -# see also http://starship.python.net/crew/kernr/mingw32/Notes.html -# -# * We put export_symbols in a def-file, and don't use -# --export-all-symbols because it doesn't worked reliable in some -# tested configurations. And because other windows compilers also -# need their symbols specified this no serious problem. -# -# tested configurations: -# -# * cygwin gcc 2.91.57/ld 2.9.4/dllwrap 0.2.4 works -# (after patching python's config.h and for C++ some other include files) -# see also http://starship.python.net/crew/kernr/mingw32/Notes.html -# * mingw32 gcc 2.95.2/ld 2.9.4/dllwrap 0.2.4 works -# (ld doesn't support -shared, so we use dllwrap) -# * cygwin gcc 2.95.2/ld 2.10.90/dllwrap 2.10.90 works now -# - its dllwrap doesn't work, there is a bug in binutils 2.10.90 -# see also http://sources.redhat.com/ml/cygwin/2000-06/msg01274.html -# - using gcc -mdll instead dllwrap doesn't work without -static because -# it tries to link against dlls instead their import libraries. (If -# it finds the dll first.) -# By specifying -static we force ld to link against the import libraries, -# this is windows standard and there are normally not the necessary symbols -# in the dlls. -# *** only the version of June 2000 shows these problems -# * cygwin gcc 3.2/ld 2.13.90 works -# (ld supports -shared) -# * mingw gcc 3.2/ld 2.13 works -# (ld supports -shared) - -__revision__ = "$Id: cygwinccompiler.py 77704 2010-01-23 09:23:15Z tarek.ziade $" - -import os -import sys -import copy -import re -from warnings import warn - -from distutils2.compiler.unixccompiler import UnixCCompiler -from distutils2.util import write_file -from distutils2.errors import DistutilsExecError, CompileError, UnknownFileError -from distutils2.util import get_compiler_versions -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig - -def get_msvcr(): - """Include the appropriate MSVC runtime library if Python was built - with MSVC 7.0 or later. - """ - msc_pos = sys.version.find('MSC v.') - if msc_pos != -1: - msc_ver = sys.version[msc_pos+6:msc_pos+10] - if msc_ver == '1300': - # MSVC 7.0 - return ['msvcr70'] - elif msc_ver == '1310': - # MSVC 7.1 - return ['msvcr71'] - elif msc_ver == '1400': - # VS2005 / MSVC 8.0 - return ['msvcr80'] - elif msc_ver == '1500': - # VS2008 / MSVC 9.0 - return ['msvcr90'] - else: - raise ValueError("Unknown MS Compiler version %s " % msc_ver) - - -class CygwinCCompiler(UnixCCompiler): - """ Handles the Cygwin port of the GNU C compiler to Windows. - """ - compiler_type = 'cygwin' - obj_extension = ".o" - static_lib_extension = ".a" - shared_lib_extension = ".dll" - static_lib_format = "lib%s%s" - shared_lib_format = "%s%s" - exe_extension = ".exe" - - def __init__(self, verbose=0, dry_run=0, force=0): - - UnixCCompiler.__init__(self, verbose, dry_run, force) - - status, details = check_config_h() - self.debug_print("Python's GCC status: %s (details: %s)" % - (status, details)) - if status is not CONFIG_H_OK: - self.warn( - "Python's pyconfig.h doesn't seem to support your compiler. " - "Reason: %s. " - "Compiling may fail because of undefined preprocessor macros." - % details) - - self.gcc_version, self.ld_version, self.dllwrap_version = \ - get_compiler_versions() - self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" % - (self.gcc_version, - self.ld_version, - self.dllwrap_version) ) - - # ld_version >= "2.10.90" and < "2.13" should also be able to use - # gcc -mdll instead of dllwrap - # Older dllwraps had own version numbers, newer ones use the - # same as the rest of binutils ( also ld ) - # dllwrap 2.10.90 is buggy - if self.ld_version >= "2.10.90": - self.linker_dll = "gcc" - else: - self.linker_dll = "dllwrap" - - # ld_version >= "2.13" support -shared so use it instead of - # -mdll -static - if self.ld_version >= "2.13": - shared_option = "-shared" - else: - shared_option = "-mdll -static" - - # Hard-code GCC because that's what this is all about. - # XXX optimization, warnings etc. should be customizable. - self.set_executables(compiler='gcc -mcygwin -O -Wall', - compiler_so='gcc -mcygwin -mdll -O -Wall', - compiler_cxx='g++ -mcygwin -O -Wall', - linker_exe='gcc -mcygwin', - linker_so=('%s -mcygwin %s' % - (self.linker_dll, shared_option))) - - # cygwin and mingw32 need different sets of libraries - if self.gcc_version == "2.91.57": - # cygwin shouldn't need msvcrt, but without the dlls will crash - # (gcc version 2.91.57) -- perhaps something about initialization - self.dll_libraries=["msvcrt"] - self.warn( - "Consider upgrading to a newer version of gcc") - else: - # Include the appropriate MSVC runtime library if Python was built - # with MSVC 7.0 or later. - self.dll_libraries = get_msvcr() - - def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): - """Compiles the source by spawing GCC and windres if needed.""" - if ext == '.rc' or ext == '.res': - # gcc needs '.res' and '.rc' compiled to object files !!! - try: - self.spawn(["windres", "-i", src, "-o", obj]) - except DistutilsExecError, msg: - raise CompileError, msg - else: # for other files use the C-compiler - try: - self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + - extra_postargs) - except DistutilsExecError, msg: - raise CompileError, msg - - def link(self, target_desc, objects, output_filename, output_dir=None, - libraries=None, library_dirs=None, runtime_library_dirs=None, - export_symbols=None, debug=0, extra_preargs=None, - extra_postargs=None, build_temp=None, target_lang=None): - """Link the objects.""" - # use separate copies, so we can modify the lists - extra_preargs = copy.copy(extra_preargs or []) - libraries = copy.copy(libraries or []) - objects = copy.copy(objects or []) - - # Additional libraries - libraries.extend(self.dll_libraries) - - # handle export symbols by creating a def-file - # with executables this only works with gcc/ld as linker - if ((export_symbols is not None) and - (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): - # (The linker doesn't do anything if output is up-to-date. - # So it would probably better to check if we really need this, - # but for this we had to insert some unchanged parts of - # UnixCCompiler, and this is not what we want.) - - # we want to put some files in the same directory as the - # object files are, build_temp doesn't help much - # where are the object files - temp_dir = os.path.dirname(objects[0]) - # name of dll to give the helper files the same base name - (dll_name, dll_extension) = os.path.splitext( - os.path.basename(output_filename)) - - # generate the filenames for these files - def_file = os.path.join(temp_dir, dll_name + ".def") - lib_file = os.path.join(temp_dir, 'lib' + dll_name + ".a") - - # Generate .def file - contents = [ - "LIBRARY %s" % os.path.basename(output_filename), - "EXPORTS"] - for sym in export_symbols: - contents.append(sym) - self.execute(write_file, (def_file, contents), - "writing %s" % def_file) - - # next add options for def-file and to creating import libraries - - # dllwrap uses different options than gcc/ld - if self.linker_dll == "dllwrap": - extra_preargs.extend(["--output-lib", lib_file]) - # for dllwrap we have to use a special option - extra_preargs.extend(["--def", def_file]) - # we use gcc/ld here and can be sure ld is >= 2.9.10 - else: - # doesn't work: bfd_close build\...\libfoo.a: Invalid operation - #extra_preargs.extend(["-Wl,--out-implib,%s" % lib_file]) - # for gcc/ld the def-file is specified as any object files - objects.append(def_file) - - #end: if ((export_symbols is not None) and - # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): - - # who wants symbols and a many times larger output file - # should explicitly switch the debug mode on - # otherwise we let dllwrap/ld strip the output file - # (On my machine: 10KB < stripped_file < ??100KB - # unstripped_file = stripped_file + XXX KB - # ( XXX=254 for a typical python extension)) - if not debug: - extra_preargs.append("-s") - - UnixCCompiler.link(self, target_desc, objects, output_filename, - output_dir, libraries, library_dirs, - runtime_library_dirs, - None, # export_symbols, we do this in our def-file - debug, extra_preargs, extra_postargs, build_temp, - target_lang) - - # -- Miscellaneous methods ----------------------------------------- - - def object_filenames(self, source_filenames, strip_dir=0, output_dir=''): - """Adds supports for rc and res files.""" - if output_dir is None: - output_dir = '' - obj_names = [] - for src_name in source_filenames: - # use normcase to make sure '.rc' is really '.rc' and not '.RC' - base, ext = os.path.splitext(os.path.normcase(src_name)) - if ext not in (self.src_extensions + ['.rc','.res']): - raise UnknownFileError, \ - "unknown file type '%s' (from '%s')" % (ext, src_name) - if strip_dir: - base = os.path.basename (base) - if ext in ('.res', '.rc'): - # these need to be compiled to object files - obj_names.append (os.path.join(output_dir, - base + ext + self.obj_extension)) - else: - obj_names.append (os.path.join(output_dir, - base + self.obj_extension)) - return obj_names - -# the same as cygwin plus some additional parameters -class Mingw32CCompiler(CygwinCCompiler): - """ Handles the Mingw32 port of the GNU C compiler to Windows. - """ - compiler_type = 'mingw32' - - def __init__(self, verbose=0, dry_run=0, force=0): - - CygwinCCompiler.__init__ (self, verbose, dry_run, force) - - # ld_version >= "2.13" support -shared so use it instead of - # -mdll -static - if self.ld_version >= "2.13": - shared_option = "-shared" - else: - shared_option = "-mdll -static" - - # A real mingw32 doesn't need to specify a different entry point, - # but cygwin 2.91.57 in no-cygwin-mode needs it. - if self.gcc_version <= "2.91.57": - entry_point = '--entry _DllMain@12' - else: - entry_point = '' - - self.set_executables(compiler='gcc -mno-cygwin -O -Wall', - compiler_so='gcc -mno-cygwin -mdll -O -Wall', - compiler_cxx='g++ -mno-cygwin -O -Wall', - linker_exe='gcc -mno-cygwin', - linker_so='%s -mno-cygwin %s %s' - % (self.linker_dll, shared_option, - entry_point)) - # Maybe we should also append -mthreads, but then the finished - # dlls need another dll (mingwm10.dll see Mingw32 docs) - # (-mthreads: Support thread-safe exception handling on `Mingw32') - - # no additional libraries needed - self.dll_libraries=[] - - # Include the appropriate MSVC runtime library if Python was built - # with MSVC 7.0 or later. - self.dll_libraries = get_msvcr() - -# Because these compilers aren't configured in Python's pyconfig.h file by -# default, we should at least warn the user if he is using a unmodified -# version. - -CONFIG_H_OK = "ok" -CONFIG_H_NOTOK = "not ok" -CONFIG_H_UNCERTAIN = "uncertain" - -def check_config_h(): - """Check if the current Python installation appears amenable to building - extensions with GCC. - - Returns a tuple (status, details), where 'status' is one of the following - constants: - - - CONFIG_H_OK: all is well, go ahead and compile - - CONFIG_H_NOTOK: doesn't look good - - CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h - - 'details' is a human-readable string explaining the situation. - - Note there are two ways to conclude "OK": either 'sys.version' contains - the string "GCC" (implying that this Python was built with GCC), or the - installed "pyconfig.h" contains the string "__GNUC__". - """ - - # XXX since this function also checks sys.version, it's not strictly a - # "pyconfig.h" check -- should probably be renamed... - # if sys.version contains GCC then python was compiled with GCC, and the - # pyconfig.h file should be OK - if "GCC" in sys.version: - return CONFIG_H_OK, "sys.version mentions 'GCC'" - - # let's see if __GNUC__ is mentioned in python.h - fn = sysconfig.get_config_h_filename() - try: - config_h = open(fn) - try: - if "__GNUC__" in config_h.read(): - return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn - else: - return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn - finally: - config_h.close() - except IOError, exc: - return (CONFIG_H_UNCERTAIN, - "couldn't read '%s': %s" % (fn, exc.strerror)) - -class _Deprecated_SRE_Pattern(object): - def __init__(self, pattern): - self.pattern = pattern - - def __getattr__(self, name): - if name in ('findall', 'finditer', 'match', 'scanner', 'search', - 'split', 'sub', 'subn'): - warn("'distutils.cygwinccompiler.RE_VERSION' is deprecated " - "and will be removed in the next version", DeprecationWarning) - return getattr(self.pattern, name) - -RE_VERSION = _Deprecated_SRE_Pattern(re.compile('(\d+\.\d+(\.\d+)*)')) - -def get_versions(): - """ Try to find out the versions of gcc, ld and dllwrap. - - If not possible it returns None for it. - """ - warn("'distutils.cygwinccompiler.get_versions' is deprecated " - "use 'distutils.util.get_compiler_versions' instead", - DeprecationWarning) - - return get_compiler_versions() diff --git a/src/distutils2/compiler/emxccompiler.py b/src/distutils2/compiler/emxccompiler.py deleted file mode 100644 index 6247c00..0000000 --- a/src/distutils2/compiler/emxccompiler.py +++ /dev/null @@ -1,305 +0,0 @@ -"""distutils.emxccompiler - -Provides the EMXCCompiler class, a subclass of UnixCCompiler that -handles the EMX port of the GNU C compiler to OS/2. -""" - -# issues: -# -# * OS/2 insists that DLLs can have names no longer than 8 characters -# We put export_symbols in a def-file, as though the DLL can have -# an arbitrary length name, but truncate the output filename. -# -# * only use OMF objects and use LINK386 as the linker (-Zomf) -# -# * always build for multithreading (-Zmt) as the accompanying OS/2 port -# of Python is only distributed with threads enabled. -# -# tested configurations: -# -# * EMX gcc 2.81/EMX 0.9d fix03 - -__revision__ = "$Id: emxccompiler.py 76956 2009-12-21 01:22:46Z tarek.ziade $" - -import os, sys, copy -from warnings import warn - -from distutils2.compiler.unixccompiler import UnixCCompiler -from distutils2.errors import DistutilsExecError, CompileError, UnknownFileError -from distutils2.util import get_compiler_versions, write_file - -class EMXCCompiler (UnixCCompiler): - - compiler_type = 'emx' - obj_extension = ".obj" - static_lib_extension = ".lib" - shared_lib_extension = ".dll" - static_lib_format = "%s%s" - shared_lib_format = "%s%s" - res_extension = ".res" # compiled resource file - exe_extension = ".exe" - - def __init__ (self, - verbose=0, - dry_run=0, - force=0): - - UnixCCompiler.__init__ (self, verbose, dry_run, force) - - (status, details) = check_config_h() - self.debug_print("Python's GCC status: %s (details: %s)" % - (status, details)) - if status is not CONFIG_H_OK: - self.warn( - "Python's pyconfig.h doesn't seem to support your compiler. " + - ("Reason: %s." % details) + - "Compiling may fail because of undefined preprocessor macros.") - - gcc_version, ld_version, dllwrap_version = get_compiler_versions() - self.gcc_version, self.ld_version = gcc_version, ld_version - self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" % - (self.gcc_version, - self.ld_version) ) - - # Hard-code GCC because that's what this is all about. - # XXX optimization, warnings etc. should be customizable. - self.set_executables(compiler='gcc -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall', - compiler_so='gcc -Zomf -Zmt -O3 -fomit-frame-pointer -mprobe -Wall', - linker_exe='gcc -Zomf -Zmt -Zcrtdll', - linker_so='gcc -Zomf -Zmt -Zcrtdll -Zdll') - - # want the gcc library statically linked (so that we don't have - # to distribute a version dependent on the compiler we have) - self.dll_libraries=["gcc"] - - # __init__ () - - def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): - if ext == '.rc': - # gcc requires '.rc' compiled to binary ('.res') files !!! - try: - self.spawn(["rc", "-r", src]) - except DistutilsExecError, msg: - raise CompileError, msg - else: # for other files use the C-compiler - try: - self.spawn(self.compiler_so + cc_args + [src, '-o', obj] + - extra_postargs) - except DistutilsExecError, msg: - raise CompileError, msg - - def link (self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): - - # use separate copies, so we can modify the lists - extra_preargs = copy.copy(extra_preargs or []) - libraries = copy.copy(libraries or []) - objects = copy.copy(objects or []) - - # Additional libraries - libraries.extend(self.dll_libraries) - - # handle export symbols by creating a def-file - # with executables this only works with gcc/ld as linker - if ((export_symbols is not None) and - (target_desc != self.EXECUTABLE)): - # (The linker doesn't do anything if output is up-to-date. - # So it would probably better to check if we really need this, - # but for this we had to insert some unchanged parts of - # UnixCCompiler, and this is not what we want.) - - # we want to put some files in the same directory as the - # object files are, build_temp doesn't help much - # where are the object files - temp_dir = os.path.dirname(objects[0]) - # name of dll to give the helper files the same base name - (dll_name, dll_extension) = os.path.splitext( - os.path.basename(output_filename)) - - # generate the filenames for these files - def_file = os.path.join(temp_dir, dll_name + ".def") - - # Generate .def file - contents = [ - "LIBRARY %s INITINSTANCE TERMINSTANCE" % \ - os.path.splitext(os.path.basename(output_filename))[0], - "DATA MULTIPLE NONSHARED", - "EXPORTS"] - for sym in export_symbols: - contents.append(' "%s"' % sym) - self.execute(write_file, (def_file, contents), - "writing %s" % def_file) - - # next add options for def-file and to creating import libraries - # for gcc/ld the def-file is specified as any other object files - objects.append(def_file) - - #end: if ((export_symbols is not None) and - # (target_desc != self.EXECUTABLE or self.linker_dll == "gcc")): - - # who wants symbols and a many times larger output file - # should explicitly switch the debug mode on - # otherwise we let dllwrap/ld strip the output file - # (On my machine: 10KB < stripped_file < ??100KB - # unstripped_file = stripped_file + XXX KB - # ( XXX=254 for a typical python extension)) - if not debug: - extra_preargs.append("-s") - - UnixCCompiler.link(self, - target_desc, - objects, - output_filename, - output_dir, - libraries, - library_dirs, - runtime_library_dirs, - None, # export_symbols, we do this in our def-file - debug, - extra_preargs, - extra_postargs, - build_temp, - target_lang) - - # link () - - # -- Miscellaneous methods ----------------------------------------- - - # override the object_filenames method from CCompiler to - # support rc and res-files - def object_filenames (self, - source_filenames, - strip_dir=0, - output_dir=''): - if output_dir is None: output_dir = '' - obj_names = [] - for src_name in source_filenames: - # use normcase to make sure '.rc' is really '.rc' and not '.RC' - (base, ext) = os.path.splitext (os.path.normcase(src_name)) - if ext not in (self.src_extensions + ['.rc']): - raise UnknownFileError, \ - "unknown file type '%s' (from '%s')" % \ - (ext, src_name) - if strip_dir: - base = os.path.basename (base) - if ext == '.rc': - # these need to be compiled to object files - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) - else: - obj_names.append (os.path.join (output_dir, - base + self.obj_extension)) - return obj_names - - # object_filenames () - - # override the find_library_file method from UnixCCompiler - # to deal with file naming/searching differences - def find_library_file(self, dirs, lib, debug=0): - shortlib = '%s.lib' % lib - longlib = 'lib%s.lib' % lib # this form very rare - - # get EMX's default library directory search path - try: - emx_dirs = os.environ['LIBRARY_PATH'].split(';') - except KeyError: - emx_dirs = [] - - for dir in dirs + emx_dirs: - shortlibp = os.path.join(dir, shortlib) - longlibp = os.path.join(dir, longlib) - if os.path.exists(shortlibp): - return shortlibp - elif os.path.exists(longlibp): - return longlibp - - # Oops, didn't find it in *any* of 'dirs' - return None - -# class EMXCCompiler - - -# Because these compilers aren't configured in Python's pyconfig.h file by -# default, we should at least warn the user if he is using a unmodified -# version. - -CONFIG_H_OK = "ok" -CONFIG_H_NOTOK = "not ok" -CONFIG_H_UNCERTAIN = "uncertain" - -def check_config_h(): - - """Check if the current Python installation (specifically, pyconfig.h) - appears amenable to building extensions with GCC. Returns a tuple - (status, details), where 'status' is one of the following constants: - CONFIG_H_OK - all is well, go ahead and compile - CONFIG_H_NOTOK - doesn't look good - CONFIG_H_UNCERTAIN - not sure -- unable to read pyconfig.h - 'details' is a human-readable string explaining the situation. - - Note there are two ways to conclude "OK": either 'sys.version' contains - the string "GCC" (implying that this Python was built with GCC), or the - installed "pyconfig.h" contains the string "__GNUC__". - """ - - # XXX since this function also checks sys.version, it's not strictly a - # "pyconfig.h" check -- should probably be renamed... - - from distutils2 import sysconfig - import string - # if sys.version contains GCC then python was compiled with - # GCC, and the pyconfig.h file should be OK - if string.find(sys.version,"GCC") >= 0: - return (CONFIG_H_OK, "sys.version mentions 'GCC'") - - fn = sysconfig.get_config_h_filename() - try: - # It would probably better to read single lines to search. - # But we do this only once, and it is fast enough - f = open(fn) - try: - s = f.read() - finally: - f.close() - - except IOError, exc: - # if we can't read this file, we cannot say it is wrong - # the compiler will complain later about this file as missing - return (CONFIG_H_UNCERTAIN, - "couldn't read '%s': %s" % (fn, exc.strerror)) - - else: - # "pyconfig.h" contains an "#ifdef __GNUC__" or something similar - if string.find(s,"__GNUC__") >= 0: - return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn) - else: - return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn) - - -def get_versions(): - """ Try to find out the versions of gcc and ld. - If not possible it returns None for it. - """ - warn("'distutils.emxccompiler.get_versions' is deprecated " - "use 'distutils.util.get_compiler_versions' instead", - DeprecationWarning) - - # EMX ld has no way of reporting version number, and we use GCC - # anyway - so we can link OMF DLLs - gcc_version, ld_version, dllwrap_version = get_compiler_versions() - return gcc_version, None diff --git a/src/distutils2/compiler/msvc9compiler.py b/src/distutils2/compiler/msvc9compiler.py deleted file mode 100644 index 46cffa5..0000000 --- a/src/distutils2/compiler/msvc9compiler.py +++ /dev/null @@ -1,740 +0,0 @@ -"""distutils.msvc9compiler - -Contains MSVCCompiler, an implementation of the abstract CCompiler class -for the Microsoft Visual Studio 2008. - -The module is compatible with VS 2005 and VS 2008. You can find legacy support -for older versions of VS in distutils.msvccompiler. -""" - -# Written by Perry Stoll -# hacked by Robin Becker and Thomas Heller to do a better job of -# finding DevStudio (through the registry) -# ported to VS2005 and VS 2008 by Christian Heimes - -__revision__ = "$Id: msvc9compiler.py 77761 2010-01-26 22:46:15Z tarek.ziade $" - -import os -import subprocess -import sys -import re - -from distutils2.errors import (DistutilsExecError, DistutilsPlatformError, - CompileError, LibError, LinkError) -from distutils2.compiler.ccompiler import CCompiler, gen_lib_options -from distutils2 import log -from distutils2.util import get_platform - -import _winreg - -RegOpenKeyEx = _winreg.OpenKeyEx -RegEnumKey = _winreg.EnumKey -RegEnumValue = _winreg.EnumValue -RegError = _winreg.error - -HKEYS = (_winreg.HKEY_USERS, - _winreg.HKEY_CURRENT_USER, - _winreg.HKEY_LOCAL_MACHINE, - _winreg.HKEY_CLASSES_ROOT) - -VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f" -WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows" -NET_BASE = r"Software\Microsoft\.NETFramework" - -# A map keyed by get_platform() return values to values accepted by -# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is -# the param to cross-compile on x86 targetting amd64.) -PLAT_TO_VCVARS = { - 'win32' : 'x86', - 'win-amd64' : 'amd64', - 'win-ia64' : 'ia64', -} - -class Reg(object): - """Helper class to read values from the registry - """ - - def get_value(cls, path, key): - for base in HKEYS: - d = cls.read_values(base, path) - if d and key in d: - return d[key] - raise KeyError(key) - get_value = classmethod(get_value) - - def read_keys(cls, base, key): - """Return list of registry keys.""" - try: - handle = RegOpenKeyEx(base, key) - except RegError: - return None - L = [] - i = 0 - while True: - try: - k = RegEnumKey(handle, i) - except RegError: - break - L.append(k) - i += 1 - return L - read_keys = classmethod(read_keys) - - def read_values(cls, base, key): - """Return dict of registry keys and values. - - All names are converted to lowercase. - """ - try: - handle = RegOpenKeyEx(base, key) - except RegError: - return None - d = {} - i = 0 - while True: - try: - name, value, type = RegEnumValue(handle, i) - except RegError: - break - name = name.lower() - d[cls.convert_mbcs(name)] = cls.convert_mbcs(value) - i += 1 - return d - read_values = classmethod(read_values) - - def convert_mbcs(s): - dec = getattr(s, "decode", None) - if dec is not None: - try: - s = dec("mbcs") - except UnicodeError: - pass - return s - convert_mbcs = staticmethod(convert_mbcs) - -class MacroExpander(object): - - def __init__(self, version): - self.macros = {} - self.vsbase = VS_BASE % version - self.load_macros(version) - - def set_macro(self, macro, path, key): - self.macros["$(%s)" % macro] = Reg.get_value(path, key) - - def load_macros(self, version): - self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir") - self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir") - self.set_macro("FrameworkDir", NET_BASE, "installroot") - try: - if version >= 8.0: - self.set_macro("FrameworkSDKDir", NET_BASE, - "sdkinstallrootv2.0") - else: - raise KeyError("sdkinstallrootv2.0") - except KeyError: - raise DistutilsPlatformError( - """Python was built with Visual Studio 2008; -extensions must be built with a compiler than can generate compatible binaries. -Visual Studio 2008 was not found on this system. If you have Cygwin installed, -you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") - - if version >= 9.0: - self.set_macro("FrameworkVersion", self.vsbase, "clr version") - self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder") - else: - p = r"Software\Microsoft\NET Framework Setup\Product" - for base in HKEYS: - try: - h = RegOpenKeyEx(base, p) - except RegError: - continue - key = RegEnumKey(h, 0) - d = Reg.get_value(base, r"%s\%s" % (p, key)) - self.macros["$(FrameworkVersion)"] = d["version"] - - def sub(self, s): - for k, v in self.macros.items(): - s = s.replace(k, v) - return s - -def get_build_version(): - """Return the version of MSVC that was used to build Python. - - For Python 2.3 and up, the version number is included in - sys.version. For earlier versions, assume the compiler is MSVC 6. - """ - prefix = "MSC v." - i = sys.version.find(prefix) - if i == -1: - return 6 - i = i + len(prefix) - s, rest = sys.version[i:].split(" ", 1) - majorVersion = int(s[:-2]) - 6 - minorVersion = int(s[2:3]) / 10.0 - # I don't think paths are affected by minor version in version 6 - if majorVersion == 6: - minorVersion = 0 - if majorVersion >= 6: - return majorVersion + minorVersion - # else we don't know what version of the compiler this is - return None - -def normalize_and_reduce_paths(paths): - """Return a list of normalized paths with duplicates removed. - - The current order of paths is maintained. - """ - # Paths are normalized so things like: /a and /a/ aren't both preserved. - reduced_paths = [] - for p in paths: - np = os.path.normpath(p) - # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. - if np not in reduced_paths: - reduced_paths.append(np) - return reduced_paths - -def removeDuplicates(variable): - """Remove duplicate values of an environment variable. - """ - oldList = variable.split(os.pathsep) - newList = [] - for i in oldList: - if i not in newList: - newList.append(i) - newVariable = os.pathsep.join(newList) - return newVariable - -def find_vcvarsall(version): - """Find the vcvarsall.bat file - - At first it tries to find the productdir of VS 2008 in the registry. If - that fails it falls back to the VS90COMNTOOLS env var. - """ - vsbase = VS_BASE % version - try: - productdir = Reg.get_value(r"%s\Setup\VC" % vsbase, - "productdir") - except KeyError: - log.debug("Unable to find productdir in registry") - productdir = None - - if not productdir or not os.path.isdir(productdir): - toolskey = "VS%0.f0COMNTOOLS" % version - toolsdir = os.environ.get(toolskey, None) - - if toolsdir and os.path.isdir(toolsdir): - productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC") - productdir = os.path.abspath(productdir) - if not os.path.isdir(productdir): - log.debug("%s is not a valid directory" % productdir) - return None - else: - log.debug("Env var %s is not set or invalid" % toolskey) - if not productdir: - log.debug("No productdir found") - return None - vcvarsall = os.path.join(productdir, "vcvarsall.bat") - if os.path.isfile(vcvarsall): - return vcvarsall - log.debug("Unable to find vcvarsall.bat") - return None - -def query_vcvarsall(version, arch="x86"): - """Launch vcvarsall.bat and read the settings from its environment - """ - vcvarsall = find_vcvarsall(version) - interesting = set(("include", "lib", "libpath", "path")) - result = {} - - if vcvarsall is None: - raise DistutilsPlatformError("Unable to find vcvarsall.bat") - log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version) - popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - stdout, stderr = popen.communicate() - if popen.wait() != 0: - raise DistutilsPlatformError(stderr.decode("mbcs")) - - stdout = stdout.decode("mbcs") - for line in stdout.split("\n"): - line = Reg.convert_mbcs(line) - if '=' not in line: - continue - line = line.strip() - key, value = line.split('=', 1) - key = key.lower() - if key in interesting: - if value.endswith(os.pathsep): - value = value[:-1] - result[key] = removeDuplicates(value) - - if len(result) != len(interesting): - raise ValueError(str(list(result.keys()))) - - return result - -# More globals -VERSION = get_build_version() -if VERSION < 8.0: - raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION) -# MACROS = MacroExpander(VERSION) - -class MSVCCompiler(CCompiler) : - """Concrete class that implements an interface to Microsoft Visual C++, - as defined by the CCompiler abstract class.""" - - compiler_type = 'msvc' - - # Just set this so CCompiler's constructor doesn't barf. We currently - # don't use the 'set_executables()' bureaucracy provided by CCompiler, - # as it really isn't necessary for this sort of single-compiler class. - # Would be nice to have a consistent interface with UnixCCompiler, - # though, so it's worth thinking about. - executables = {} - - # Private class data (need to distinguish C from C++ source for compiler) - _c_extensions = ['.c'] - _cpp_extensions = ['.cc', '.cpp', '.cxx'] - _rc_extensions = ['.rc'] - _mc_extensions = ['.mc'] - - # Needed for the filename generation methods provided by the - # base class, CCompiler. - src_extensions = (_c_extensions + _cpp_extensions + - _rc_extensions + _mc_extensions) - res_extension = '.res' - obj_extension = '.obj' - static_lib_extension = '.lib' - shared_lib_extension = '.dll' - static_lib_format = shared_lib_format = '%s%s' - exe_extension = '.exe' - - def __init__(self, verbose=0, dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) - self.__version = VERSION - self.__root = r"Software\Microsoft\VisualStudio" - # self.__macros = MACROS - self.__paths = [] - # target platform (.plat_name is consistent with 'bdist') - self.plat_name = None - self.__arch = None # deprecated name - self.initialized = False - - def initialize(self, plat_name=None): - # multi-init means we would need to check platform same each time... - assert not self.initialized, "don't init multiple times" - if plat_name is None: - plat_name = get_platform() - # sanity check for platforms to prevent obscure errors later. - ok_plats = 'win32', 'win-amd64', 'win-ia64' - if plat_name not in ok_plats: - raise DistutilsPlatformError("--plat-name must be one of %s" % - (ok_plats,)) - - if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): - # Assume that the SDK set up everything alright; don't try to be - # smarter - self.cc = "cl.exe" - self.linker = "link.exe" - self.lib = "lib.exe" - self.rc = "rc.exe" - self.mc = "mc.exe" - else: - # On x86, 'vcvars32.bat amd64' creates an env that doesn't work; - # to cross compile, you use 'x86_amd64'. - # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross - # compile use 'x86' (ie, it runs the x86 compiler directly) - # No idea how itanium handles this, if at all. - if plat_name == get_platform() or plat_name == 'win32': - # native build or cross-compile to win32 - plat_spec = PLAT_TO_VCVARS[plat_name] - else: - # cross compile from win32 -> some 64bit - plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \ - PLAT_TO_VCVARS[plat_name] - - vc_env = query_vcvarsall(VERSION, plat_spec) - - # take care to only use strings in the environment. - self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep) - os.environ['lib'] = vc_env['lib'].encode('mbcs') - os.environ['include'] = vc_env['include'].encode('mbcs') - - if len(self.__paths) == 0: - raise DistutilsPlatformError("Python was built with %s, " - "and extensions need to be built with the same " - "version of the compiler, but it isn't installed." - % self.__product) - - self.cc = self.find_exe("cl.exe") - self.linker = self.find_exe("link.exe") - self.lib = self.find_exe("lib.exe") - self.rc = self.find_exe("rc.exe") # resource compiler - self.mc = self.find_exe("mc.exe") # message compiler - #self.set_path_env_var('lib') - #self.set_path_env_var('include') - - # extend the MSVC path with the current path - try: - for p in os.environ['path'].split(';'): - self.__paths.append(p) - except KeyError: - pass - self.__paths = normalize_and_reduce_paths(self.__paths) - os.environ['path'] = ";".join(self.__paths) - - self.preprocess_options = None - if self.__arch == "x86": - self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', - '/DNDEBUG'] - self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', - '/Z7', '/D_DEBUG'] - else: - # Win64 - self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' , - '/DNDEBUG'] - self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', - '/Z7', '/D_DEBUG'] - - self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] - if self.__version >= 7: - self.ldflags_shared_debug = [ - '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None' - ] - self.ldflags_static = [ '/nologo'] - - self.initialized = True - - # -- Worker methods ------------------------------------------------ - - def object_filenames(self, - source_filenames, - strip_dir=0, - output_dir=''): - # Copied from ccompiler.py, extended to return .res as 'object'-file - # for .rc input file - if output_dir is None: output_dir = '' - obj_names = [] - for src_name in source_filenames: - (base, ext) = os.path.splitext (src_name) - base = os.path.splitdrive(base)[1] # Chop off the drive - base = base[os.path.isabs(base):] # If abs, chop off leading / - if ext not in self.src_extensions: - # Better to raise an exception instead of silently continuing - # and later complain about sources and targets having - # different lengths - raise CompileError ("Don't know how to compile %s" % src_name) - if strip_dir: - base = os.path.basename (base) - if ext in self._rc_extensions: - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) - elif ext in self._mc_extensions: - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) - else: - obj_names.append (os.path.join (output_dir, - base + self.obj_extension)) - return obj_names - - - def compile(self, sources, - output_dir=None, macros=None, include_dirs=None, debug=0, - extra_preargs=None, extra_postargs=None, depends=None): - - if not self.initialized: - self.initialize() - compile_info = self._setup_compile(output_dir, macros, include_dirs, - sources, depends, extra_postargs) - macros, objects, extra_postargs, pp_opts, build = compile_info - - compile_opts = extra_preargs or [] - compile_opts.append ('/c') - if debug: - compile_opts.extend(self.compile_options_debug) - else: - compile_opts.extend(self.compile_options) - - for obj in objects: - try: - src, ext = build[obj] - except KeyError: - continue - if debug: - # pass the full pathname to MSVC in debug mode, - # this allows the debugger to find the source file - # without asking the user to browse for it - src = os.path.abspath(src) - - if ext in self._c_extensions: - input_opt = "/Tc" + src - elif ext in self._cpp_extensions: - input_opt = "/Tp" + src - elif ext in self._rc_extensions: - # compile .RC to .RES file - input_opt = src - output_opt = "/fo" + obj - try: - self.spawn([self.rc] + pp_opts + - [output_opt] + [input_opt]) - except DistutilsExecError, msg: - raise CompileError(msg) - continue - elif ext in self._mc_extensions: - # Compile .MC to .RC file to .RES file. - # * '-h dir' specifies the directory for the - # generated include file - # * '-r dir' specifies the target directory of the - # generated RC file and the binary message resource - # it includes - # - # For now (since there are no options to change this), - # we use the source-directory for the include file and - # the build directory for the RC file and message - # resources. This works at least for win32all. - h_dir = os.path.dirname(src) - rc_dir = os.path.dirname(obj) - try: - # first compile .MC to .RC and .H file - self.spawn([self.mc] + - ['-h', h_dir, '-r', rc_dir] + [src]) - base, _ = os.path.splitext (os.path.basename (src)) - rc_file = os.path.join (rc_dir, base + '.rc') - # then compile .RC to .RES file - self.spawn([self.rc] + - ["/fo" + obj] + [rc_file]) - - except DistutilsExecError, msg: - raise CompileError(msg) - continue - else: - # how to handle this file? - raise CompileError("Don't know how to compile %s to %s" - % (src, obj)) - - output_opt = "/Fo" + obj - try: - self.spawn([self.cc] + compile_opts + pp_opts + - [input_opt, output_opt] + - extra_postargs) - except DistutilsExecError, msg: - raise CompileError(msg) - - return objects - - - def create_static_lib(self, - objects, - output_libname, - output_dir=None, - debug=0, - target_lang=None): - - if not self.initialized: - self.initialize() - (objects, output_dir) = self._fix_object_args(objects, output_dir) - output_filename = self.library_filename(output_libname, - output_dir=output_dir) - - if self._need_link(objects, output_filename): - lib_args = objects + ['/OUT:' + output_filename] - if debug: - pass # XXX what goes here? - try: - self.spawn([self.lib] + lib_args) - except DistutilsExecError, msg: - raise LibError(msg) - else: - log.debug("skipping %s (up-to-date)", output_filename) - - - def link(self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): - - if not self.initialized: - self.initialize() - (objects, output_dir) = self._fix_object_args(objects, output_dir) - fixed_args = self._fix_lib_args(libraries, library_dirs, - runtime_library_dirs) - (libraries, library_dirs, runtime_library_dirs) = fixed_args - - if runtime_library_dirs: - self.warn ("I don't know what to do with 'runtime_library_dirs': " - + str (runtime_library_dirs)) - - lib_opts = gen_lib_options(self, - library_dirs, runtime_library_dirs, - libraries) - if output_dir is not None: - output_filename = os.path.join(output_dir, output_filename) - - if self._need_link(objects, output_filename): - if target_desc == CCompiler.EXECUTABLE: - if debug: - ldflags = self.ldflags_shared_debug[1:] - else: - ldflags = self.ldflags_shared[1:] - else: - if debug: - ldflags = self.ldflags_shared_debug - else: - ldflags = self.ldflags_shared - - export_opts = [] - for sym in (export_symbols or []): - export_opts.append("/EXPORT:" + sym) - - ld_args = (ldflags + lib_opts + export_opts + - objects + ['/OUT:' + output_filename]) - - # The MSVC linker generates .lib and .exp files, which cannot be - # suppressed by any linker switches. The .lib files may even be - # needed! Make sure they are generated in the temporary build - # directory. Since they have different names for debug and release - # builds, they can go into the same directory. - build_temp = os.path.dirname(objects[0]) - if export_symbols is not None: - (dll_name, dll_ext) = os.path.splitext( - os.path.basename(output_filename)) - implib_file = os.path.join( - build_temp, - self.library_filename(dll_name)) - ld_args.append ('/IMPLIB:' + implib_file) - - # Embedded manifests are recommended - see MSDN article titled - # "How to: Embed a Manifest Inside a C/C++ Application" - # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx) - # Ask the linker to generate the manifest in the temp dir, so - # we can embed it later. - temp_manifest = os.path.join( - build_temp, - os.path.basename(output_filename) + ".manifest") - ld_args.append('/MANIFESTFILE:' + temp_manifest) - - if extra_preargs: - ld_args[:0] = extra_preargs - if extra_postargs: - ld_args.extend(extra_postargs) - - self.mkpath(os.path.dirname(output_filename)) - try: - self.spawn([self.linker] + ld_args) - except DistutilsExecError, msg: - raise LinkError(msg) - - # embed the manifest - # XXX - this is somewhat fragile - if mt.exe fails, distutils - # will still consider the DLL up-to-date, but it will not have a - # manifest. Maybe we should link to a temp file? OTOH, that - # implies a build environment error that shouldn't go undetected. - if target_desc == CCompiler.EXECUTABLE: - mfid = 1 - else: - mfid = 2 - self._remove_visual_c_ref(temp_manifest) - out_arg = '-outputresource:%s;%s' % (output_filename, mfid) - try: - self.spawn(['mt.exe', '-nologo', '-manifest', - temp_manifest, out_arg]) - except DistutilsExecError, msg: - raise LinkError(msg) - else: - log.debug("skipping %s (up-to-date)", output_filename) - - def _remove_visual_c_ref(self, manifest_file): - try: - # Remove references to the Visual C runtime, so they will - # fall through to the Visual C dependency of Python.exe. - # This way, when installed for a restricted user (e.g. - # runtimes are not in WinSxS folder, but in Python's own - # folder), the runtimes do not need to be in every folder - # with .pyd's. - manifest_f = open(manifest_file) - try: - manifest_buf = manifest_f.read() - finally: - manifest_f.close() - pattern = re.compile( - r"""<assemblyIdentity.*?name=("|')Microsoft\."""\ - r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""", - re.DOTALL) - manifest_buf = re.sub(pattern, "", manifest_buf) - pattern = "<dependentAssembly>\s*</dependentAssembly>" - manifest_buf = re.sub(pattern, "", manifest_buf) - manifest_f = open(manifest_file, 'w') - try: - manifest_f.write(manifest_buf) - finally: - manifest_f.close() - except IOError: - pass - - # -- Miscellaneous methods ----------------------------------------- - # These are all used by the 'gen_lib_options() function, in - # ccompiler.py. - - def library_dir_option(self, dir): - return "/LIBPATH:" + dir - - def runtime_library_dir_option(self, dir): - raise DistutilsPlatformError( - "don't know how to set runtime library search path for MSVC++") - - def library_option(self, lib): - return self.library_filename(lib) - - - def find_library_file(self, dirs, lib, debug=0): - # Prefer a debugging library if found (and requested), but deal - # with it if we don't have one. - if debug: - try_names = [lib + "_d", lib] - else: - try_names = [lib] - for dir in dirs: - for name in try_names: - libfile = os.path.join(dir, self.library_filename (name)) - if os.path.exists(libfile): - return libfile - else: - # Oops, didn't find it in *any* of 'dirs' - return None - - # Helper methods for using the MSVC registry settings - - def find_exe(self, exe): - """Return path to an MSVC executable program. - - Tries to find the program in several places: first, one of the - MSVC program search paths from the registry; next, the directories - in the PATH environment variable. If any of those work, return an - absolute path that is known to exist. If none of them work, just - return the original program name, 'exe'. - """ - for p in self.__paths: - fn = os.path.join(os.path.abspath(p), exe) - if os.path.isfile(fn): - return fn - - # didn't find it; try existing path - for p in os.environ['Path'].split(';'): - fn = os.path.join(os.path.abspath(p),exe) - if os.path.isfile(fn): - return fn - - return exe diff --git a/src/distutils2/compiler/msvccompiler.py b/src/distutils2/compiler/msvccompiler.py deleted file mode 100644 index d2b049f..0000000 --- a/src/distutils2/compiler/msvccompiler.py +++ /dev/null @@ -1,659 +0,0 @@ -"""distutils.msvccompiler - -Contains MSVCCompiler, an implementation of the abstract CCompiler class -for the Microsoft Visual Studio. -""" - -# Written by Perry Stoll -# hacked by Robin Becker and Thomas Heller to do a better job of -# finding DevStudio (through the registry) - -__revision__ = "$Id: msvccompiler.py 76956 2009-12-21 01:22:46Z tarek.ziade $" - -import sys -import os -import string - -from distutils2.errors import (DistutilsExecError, DistutilsPlatformError, - CompileError, LibError, LinkError) -from distutils2.compiler.ccompiler import CCompiler, gen_lib_options -from distutils2 import log - -_can_read_reg = 0 -try: - import _winreg - - _can_read_reg = 1 - hkey_mod = _winreg - - RegOpenKeyEx = _winreg.OpenKeyEx - RegEnumKey = _winreg.EnumKey - RegEnumValue = _winreg.EnumValue - RegError = _winreg.error - -except ImportError: - try: - import win32api - import win32con - _can_read_reg = 1 - hkey_mod = win32con - - RegOpenKeyEx = win32api.RegOpenKeyEx - RegEnumKey = win32api.RegEnumKey - RegEnumValue = win32api.RegEnumValue - RegError = win32api.error - - except ImportError: - log.info("Warning: Can't read registry to find the " - "necessary compiler setting\n" - "Make sure that Python modules _winreg, " - "win32api or win32con are installed.") - pass - -if _can_read_reg: - HKEYS = (hkey_mod.HKEY_USERS, - hkey_mod.HKEY_CURRENT_USER, - hkey_mod.HKEY_LOCAL_MACHINE, - hkey_mod.HKEY_CLASSES_ROOT) - -def read_keys(base, key): - """Return list of registry keys.""" - - try: - handle = RegOpenKeyEx(base, key) - except RegError: - return None - L = [] - i = 0 - while 1: - try: - k = RegEnumKey(handle, i) - except RegError: - break - L.append(k) - i = i + 1 - return L - -def read_values(base, key): - """Return dict of registry keys and values. - - All names are converted to lowercase. - """ - try: - handle = RegOpenKeyEx(base, key) - except RegError: - return None - d = {} - i = 0 - while 1: - try: - name, value, type = RegEnumValue(handle, i) - except RegError: - break - name = name.lower() - d[convert_mbcs(name)] = convert_mbcs(value) - i = i + 1 - return d - -def convert_mbcs(s): - enc = getattr(s, "encode", None) - if enc is not None: - try: - s = enc("mbcs") - except UnicodeError: - pass - return s - -class MacroExpander(object): - - def __init__(self, version): - self.macros = {} - self.load_macros(version) - - def set_macro(self, macro, path, key): - for base in HKEYS: - d = read_values(base, path) - if d: - self.macros["$(%s)" % macro] = d[key] - break - - def load_macros(self, version): - vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version - self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir") - self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir") - net = r"Software\Microsoft\.NETFramework" - self.set_macro("FrameworkDir", net, "installroot") - try: - if version > 7.0: - self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1") - else: - self.set_macro("FrameworkSDKDir", net, "sdkinstallroot") - except KeyError: - raise DistutilsPlatformError, \ - ("""Python was built with Visual Studio 2003; -extensions must be built with a compiler than can generate compatible binaries. -Visual Studio 2003 was not found on this system. If you have Cygwin installed, -you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""") - - p = r"Software\Microsoft\NET Framework Setup\Product" - for base in HKEYS: - try: - h = RegOpenKeyEx(base, p) - except RegError: - continue - key = RegEnumKey(h, 0) - d = read_values(base, r"%s\%s" % (p, key)) - self.macros["$(FrameworkVersion)"] = d["version"] - - def sub(self, s): - for k, v in self.macros.items(): - s = string.replace(s, k, v) - return s - -def get_build_version(): - """Return the version of MSVC that was used to build Python. - - For Python 2.3 and up, the version number is included in - sys.version. For earlier versions, assume the compiler is MSVC 6. - """ - - prefix = "MSC v." - i = string.find(sys.version, prefix) - if i == -1: - return 6 - i = i + len(prefix) - s, rest = sys.version[i:].split(" ", 1) - majorVersion = int(s[:-2]) - 6 - minorVersion = int(s[2:3]) / 10.0 - # I don't think paths are affected by minor version in version 6 - if majorVersion == 6: - minorVersion = 0 - if majorVersion >= 6: - return majorVersion + minorVersion - # else we don't know what version of the compiler this is - return None - -def get_build_architecture(): - """Return the processor architecture. - - Possible results are "Intel", "Itanium", or "AMD64". - """ - - prefix = " bit (" - i = string.find(sys.version, prefix) - if i == -1: - return "Intel" - j = string.find(sys.version, ")", i) - return sys.version[i+len(prefix):j] - -def normalize_and_reduce_paths(paths): - """Return a list of normalized paths with duplicates removed. - - The current order of paths is maintained. - """ - # Paths are normalized so things like: /a and /a/ aren't both preserved. - reduced_paths = [] - for p in paths: - np = os.path.normpath(p) - # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set. - if np not in reduced_paths: - reduced_paths.append(np) - return reduced_paths - - -class MSVCCompiler (CCompiler) : - """Concrete class that implements an interface to Microsoft Visual C++, - as defined by the CCompiler abstract class.""" - - compiler_type = 'msvc' - - # Just set this so CCompiler's constructor doesn't barf. We currently - # don't use the 'set_executables()' bureaucracy provided by CCompiler, - # as it really isn't necessary for this sort of single-compiler class. - # Would be nice to have a consistent interface with UnixCCompiler, - # though, so it's worth thinking about. - executables = {} - - # Private class data (need to distinguish C from C++ source for compiler) - _c_extensions = ['.c'] - _cpp_extensions = ['.cc', '.cpp', '.cxx'] - _rc_extensions = ['.rc'] - _mc_extensions = ['.mc'] - - # Needed for the filename generation methods provided by the - # base class, CCompiler. - src_extensions = (_c_extensions + _cpp_extensions + - _rc_extensions + _mc_extensions) - res_extension = '.res' - obj_extension = '.obj' - static_lib_extension = '.lib' - shared_lib_extension = '.dll' - static_lib_format = shared_lib_format = '%s%s' - exe_extension = '.exe' - - def __init__ (self, verbose=0, dry_run=0, force=0): - CCompiler.__init__ (self, verbose, dry_run, force) - self.__version = get_build_version() - self.__arch = get_build_architecture() - if self.__arch == "Intel": - # x86 - if self.__version >= 7: - self.__root = r"Software\Microsoft\VisualStudio" - self.__macros = MacroExpander(self.__version) - else: - self.__root = r"Software\Microsoft\Devstudio" - self.__product = "Visual Studio version %s" % self.__version - else: - # Win64. Assume this was built with the platform SDK - self.__product = "Microsoft SDK compiler %s" % (self.__version + 6) - - self.initialized = False - - def initialize(self): - self.__paths = [] - if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): - # Assume that the SDK set up everything alright; don't try to be - # smarter - self.cc = "cl.exe" - self.linker = "link.exe" - self.lib = "lib.exe" - self.rc = "rc.exe" - self.mc = "mc.exe" - else: - self.__paths = self.get_msvc_paths("path") - - if len (self.__paths) == 0: - raise DistutilsPlatformError, \ - ("Python was built with %s, " - "and extensions need to be built with the same " - "version of the compiler, but it isn't installed." % self.__product) - - self.cc = self.find_exe("cl.exe") - self.linker = self.find_exe("link.exe") - self.lib = self.find_exe("lib.exe") - self.rc = self.find_exe("rc.exe") # resource compiler - self.mc = self.find_exe("mc.exe") # message compiler - self.set_path_env_var('lib') - self.set_path_env_var('include') - - # extend the MSVC path with the current path - try: - for p in string.split(os.environ['path'], ';'): - self.__paths.append(p) - except KeyError: - pass - self.__paths = normalize_and_reduce_paths(self.__paths) - os.environ['path'] = string.join(self.__paths, ';') - - self.preprocess_options = None - if self.__arch == "Intel": - self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' , - '/DNDEBUG'] - self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX', - '/Z7', '/D_DEBUG'] - else: - # Win64 - self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' , - '/DNDEBUG'] - self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-', - '/Z7', '/D_DEBUG'] - - self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO'] - if self.__version >= 7: - self.ldflags_shared_debug = [ - '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG' - ] - else: - self.ldflags_shared_debug = [ - '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG' - ] - self.ldflags_static = [ '/nologo'] - - self.initialized = True - - # -- Worker methods ------------------------------------------------ - - def object_filenames (self, - source_filenames, - strip_dir=0, - output_dir=''): - # Copied from ccompiler.py, extended to return .res as 'object'-file - # for .rc input file - if output_dir is None: output_dir = '' - obj_names = [] - for src_name in source_filenames: - (base, ext) = os.path.splitext (src_name) - base = os.path.splitdrive(base)[1] # Chop off the drive - base = base[os.path.isabs(base):] # If abs, chop off leading / - if ext not in self.src_extensions: - # Better to raise an exception instead of silently continuing - # and later complain about sources and targets having - # different lengths - raise CompileError ("Don't know how to compile %s" % src_name) - if strip_dir: - base = os.path.basename (base) - if ext in self._rc_extensions: - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) - elif ext in self._mc_extensions: - obj_names.append (os.path.join (output_dir, - base + self.res_extension)) - else: - obj_names.append (os.path.join (output_dir, - base + self.obj_extension)) - return obj_names - - # object_filenames () - - - def compile(self, sources, - output_dir=None, macros=None, include_dirs=None, debug=0, - extra_preargs=None, extra_postargs=None, depends=None): - - if not self.initialized: self.initialize() - macros, objects, extra_postargs, pp_opts, build = \ - self._setup_compile(output_dir, macros, include_dirs, sources, - depends, extra_postargs) - - compile_opts = extra_preargs or [] - compile_opts.append ('/c') - if debug: - compile_opts.extend(self.compile_options_debug) - else: - compile_opts.extend(self.compile_options) - - for obj in objects: - try: - src, ext = build[obj] - except KeyError: - continue - if debug: - # pass the full pathname to MSVC in debug mode, - # this allows the debugger to find the source file - # without asking the user to browse for it - src = os.path.abspath(src) - - if ext in self._c_extensions: - input_opt = "/Tc" + src - elif ext in self._cpp_extensions: - input_opt = "/Tp" + src - elif ext in self._rc_extensions: - # compile .RC to .RES file - input_opt = src - output_opt = "/fo" + obj - try: - self.spawn ([self.rc] + pp_opts + - [output_opt] + [input_opt]) - except DistutilsExecError, msg: - raise CompileError, msg - continue - elif ext in self._mc_extensions: - - # Compile .MC to .RC file to .RES file. - # * '-h dir' specifies the directory for the - # generated include file - # * '-r dir' specifies the target directory of the - # generated RC file and the binary message resource - # it includes - # - # For now (since there are no options to change this), - # we use the source-directory for the include file and - # the build directory for the RC file and message - # resources. This works at least for win32all. - - h_dir = os.path.dirname (src) - rc_dir = os.path.dirname (obj) - try: - # first compile .MC to .RC and .H file - self.spawn ([self.mc] + - ['-h', h_dir, '-r', rc_dir] + [src]) - base, _ = os.path.splitext (os.path.basename (src)) - rc_file = os.path.join (rc_dir, base + '.rc') - # then compile .RC to .RES file - self.spawn ([self.rc] + - ["/fo" + obj] + [rc_file]) - - except DistutilsExecError, msg: - raise CompileError, msg - continue - else: - # how to handle this file? - raise CompileError ( - "Don't know how to compile %s to %s" % \ - (src, obj)) - - output_opt = "/Fo" + obj - try: - self.spawn ([self.cc] + compile_opts + pp_opts + - [input_opt, output_opt] + - extra_postargs) - except DistutilsExecError, msg: - raise CompileError, msg - - return objects - - # compile () - - - def create_static_lib (self, - objects, - output_libname, - output_dir=None, - debug=0, - target_lang=None): - - if not self.initialized: self.initialize() - (objects, output_dir) = self._fix_object_args (objects, output_dir) - output_filename = \ - self.library_filename (output_libname, output_dir=output_dir) - - if self._need_link (objects, output_filename): - lib_args = objects + ['/OUT:' + output_filename] - if debug: - pass # XXX what goes here? - try: - self.spawn ([self.lib] + lib_args) - except DistutilsExecError, msg: - raise LibError, msg - - else: - log.debug("skipping %s (up-to-date)", output_filename) - - # create_static_lib () - - def link (self, - target_desc, - objects, - output_filename, - output_dir=None, - libraries=None, - library_dirs=None, - runtime_library_dirs=None, - export_symbols=None, - debug=0, - extra_preargs=None, - extra_postargs=None, - build_temp=None, - target_lang=None): - - if not self.initialized: self.initialize() - (objects, output_dir) = self._fix_object_args (objects, output_dir) - (libraries, library_dirs, runtime_library_dirs) = \ - self._fix_lib_args (libraries, library_dirs, runtime_library_dirs) - - if runtime_library_dirs: - self.warn ("I don't know what to do with 'runtime_library_dirs': " - + str (runtime_library_dirs)) - - lib_opts = gen_lib_options (self, - library_dirs, runtime_library_dirs, - libraries) - if output_dir is not None: - output_filename = os.path.join (output_dir, output_filename) - - if self._need_link (objects, output_filename): - - if target_desc == CCompiler.EXECUTABLE: - if debug: - ldflags = self.ldflags_shared_debug[1:] - else: - ldflags = self.ldflags_shared[1:] - else: - if debug: - ldflags = self.ldflags_shared_debug - else: - ldflags = self.ldflags_shared - - export_opts = [] - for sym in (export_symbols or []): - export_opts.append("/EXPORT:" + sym) - - ld_args = (ldflags + lib_opts + export_opts + - objects + ['/OUT:' + output_filename]) - - # The MSVC linker generates .lib and .exp files, which cannot be - # suppressed by any linker switches. The .lib files may even be - # needed! Make sure they are generated in the temporary build - # directory. Since they have different names for debug and release - # builds, they can go into the same directory. - if export_symbols is not None: - (dll_name, dll_ext) = os.path.splitext( - os.path.basename(output_filename)) - implib_file = os.path.join( - os.path.dirname(objects[0]), - self.library_filename(dll_name)) - ld_args.append ('/IMPLIB:' + implib_file) - - if extra_preargs: - ld_args[:0] = extra_preargs - if extra_postargs: - ld_args.extend(extra_postargs) - - self.mkpath (os.path.dirname (output_filename)) - try: - self.spawn ([self.linker] + ld_args) - except DistutilsExecError, msg: - raise LinkError, msg - - else: - log.debug("skipping %s (up-to-date)", output_filename) - - # link () - - - # -- Miscellaneous methods ----------------------------------------- - # These are all used by the 'gen_lib_options() function, in - # ccompiler.py. - - def library_dir_option (self, dir): - return "/LIBPATH:" + dir - - def runtime_library_dir_option (self, dir): - raise DistutilsPlatformError, \ - "don't know how to set runtime library search path for MSVC++" - - def library_option (self, lib): - return self.library_filename (lib) - - - def find_library_file (self, dirs, lib, debug=0): - # Prefer a debugging library if found (and requested), but deal - # with it if we don't have one. - if debug: - try_names = [lib + "_d", lib] - else: - try_names = [lib] - for dir in dirs: - for name in try_names: - libfile = os.path.join(dir, self.library_filename (name)) - if os.path.exists(libfile): - return libfile - else: - # Oops, didn't find it in *any* of 'dirs' - return None - - # find_library_file () - - # Helper methods for using the MSVC registry settings - - def find_exe(self, exe): - """Return path to an MSVC executable program. - - Tries to find the program in several places: first, one of the - MSVC program search paths from the registry; next, the directories - in the PATH environment variable. If any of those work, return an - absolute path that is known to exist. If none of them work, just - return the original program name, 'exe'. - """ - - for p in self.__paths: - fn = os.path.join(os.path.abspath(p), exe) - if os.path.isfile(fn): - return fn - - # didn't find it; try existing path - for p in string.split(os.environ['Path'],';'): - fn = os.path.join(os.path.abspath(p),exe) - if os.path.isfile(fn): - return fn - - return exe - - def get_msvc_paths(self, path, platform='x86'): - """Get a list of devstudio directories (include, lib or path). - - Return a list of strings. The list will be empty if unable to - access the registry or appropriate registry keys not found. - """ - - if not _can_read_reg: - return [] - - path = path + " dirs" - if self.__version >= 7: - key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories" - % (self.__root, self.__version)) - else: - key = (r"%s\6.0\Build System\Components\Platforms" - r"\Win32 (%s)\Directories" % (self.__root, platform)) - - for base in HKEYS: - d = read_values(base, key) - if d: - if self.__version >= 7: - return string.split(self.__macros.sub(d[path]), ";") - else: - return string.split(d[path], ";") - # MSVC 6 seems to create the registry entries we need only when - # the GUI is run. - if self.__version == 6: - for base in HKEYS: - if read_values(base, r"%s\6.0" % self.__root) is not None: - self.warn("It seems you have Visual Studio 6 installed, " - "but the expected registry settings are not present.\n" - "You must at least run the Visual Studio GUI once " - "so that these entries are created.") - break - return [] - - def set_path_env_var(self, name): - """Set environment variable 'name' to an MSVC path type value. - - This is equivalent to a SET command prior to execution of spawned - commands. - """ - - if name == "lib": - p = self.get_msvc_paths("library") - else: - p = self.get_msvc_paths(name) - if p: - os.environ[name] = string.join(p, ';') - - -if get_build_version() >= 8.0: - log.debug("Importing new compiler from distutils.msvc9compiler") - OldMSVCCompiler = MSVCCompiler - from distutils2.msvc9compiler import MSVCCompiler - # get_build_architecture not really relevant now we support cross-compile - from distutils2.msvc9compiler import MacroExpander diff --git a/src/distutils2/compiler/unixccompiler.py b/src/distutils2/compiler/unixccompiler.py deleted file mode 100644 index 7e52959..0000000 --- a/src/distutils2/compiler/unixccompiler.py +++ /dev/null @@ -1,345 +0,0 @@ -"""distutils.unixccompiler - -Contains the UnixCCompiler class, a subclass of CCompiler that handles -the "typical" Unix-style command-line C compiler: - * macros defined with -Dname[=value] - * macros undefined with -Uname - * include search directories specified with -Idir - * libraries specified with -lllib - * library search directories specified with -Ldir - * compile handled by 'cc' (or similar) executable with -c option: - compiles .c to .o - * link static library handled by 'ar' command (possibly with 'ranlib') - * link shared library handled by 'cc -shared' -""" - -__revision__ = "$Id: unixccompiler.py 77704 2010-01-23 09:23:15Z tarek.ziade $" - -import os, sys -from types import StringType, NoneType - -from distutils2.util import newer -from distutils2.compiler.ccompiler import (CCompiler, gen_preprocess_options, - gen_lib_options) -from distutils2.errors import (DistutilsExecError, CompileError, - LibError, LinkError) -from distutils2 import log - -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig - - -# XXX Things not currently handled: -# * optimization/debug/warning flags; we just use whatever's in Python's -# Makefile and live with it. Is this adequate? If not, we might -# have to have a bunch of subclasses GNUCCompiler, SGICCompiler, -# SunCCompiler, and I suspect down that road lies madness. -# * even if we don't know a warning flag from an optimization flag, -# we need some way for outsiders to feed preprocessor/compiler/linker -# flags in to us -- eg. a sysadmin might want to mandate certain flags -# via a site config file, or a user might want to set something for -# compiling this module distribution only via the setup.py command -# line, whatever. As long as these options come from something on the -# current system, they can be as system-dependent as they like, and we -# should just happily stuff them into the preprocessor/compiler/linker -# options and carry on. - -def _darwin_compiler_fixup(compiler_so, cc_args): - """ - This function will strip '-isysroot PATH' and '-arch ARCH' from the - compile flags if the user has specified one them in extra_compile_flags. - - This is needed because '-arch ARCH' adds another architecture to the - build, without a way to remove an architecture. Furthermore GCC will - barf if multiple '-isysroot' arguments are present. - """ - stripArch = stripSysroot = 0 - - compiler_so = list(compiler_so) - kernel_version = os.uname()[2] # 8.4.3 - major_version = int(kernel_version.split('.')[0]) - - if major_version < 8: - # OSX before 10.4.0, these don't support -arch and -isysroot at - # all. - stripArch = stripSysroot = True - else: - stripArch = '-arch' in cc_args - stripSysroot = '-isysroot' in cc_args - - if stripArch or 'ARCHFLAGS' in os.environ: - while 1: - try: - index = compiler_so.index('-arch') - # Strip this argument and the next one: - del compiler_so[index:index+2] - except ValueError: - break - - if 'ARCHFLAGS' in os.environ and not stripArch: - # User specified different -arch flags in the environ, - # see also the sysconfig - compiler_so = compiler_so + os.environ['ARCHFLAGS'].split() - - if stripSysroot: - try: - index = compiler_so.index('-isysroot') - # Strip this argument and the next one: - del compiler_so[index:index+2] - except ValueError: - pass - - # Check if the SDK that is used during compilation actually exists, - # the universal build requires the usage of a universal SDK and not all - # users have that installed by default. - sysroot = None - if '-isysroot' in cc_args: - idx = cc_args.index('-isysroot') - sysroot = cc_args[idx+1] - elif '-isysroot' in compiler_so: - idx = compiler_so.index('-isysroot') - sysroot = compiler_so[idx+1] - - if sysroot and not os.path.isdir(sysroot): - log.warn("Compiling with an SDK that doesn't seem to exist: %s", - sysroot) - log.warn("Please check your Xcode installation") - - return compiler_so - -class UnixCCompiler(CCompiler): - - compiler_type = 'unix' - - # These are used by CCompiler in two places: the constructor sets - # instance attributes 'preprocessor', 'compiler', etc. from them, and - # 'set_executable()' allows any of these to be set. The defaults here - # are pretty generic; they will probably have to be set by an outsider - # (eg. using information discovered by the sysconfig about building - # Python extensions). - executables = {'preprocessor' : None, - 'compiler' : ["cc"], - 'compiler_so' : ["cc"], - 'compiler_cxx' : ["cc"], - 'linker_so' : ["cc", "-shared"], - 'linker_exe' : ["cc"], - 'archiver' : ["ar", "-cr"], - 'ranlib' : None, - } - - if sys.platform[:6] == "darwin": - executables['ranlib'] = ["ranlib"] - - # Needed for the filename generation methods provided by the base - # class, CCompiler. NB. whoever instantiates/uses a particular - # UnixCCompiler instance should set 'shared_lib_ext' -- we set a - # reasonable common default here, but it's not necessarily used on all - # Unices! - - src_extensions = [".c",".C",".cc",".cxx",".cpp",".m"] - obj_extension = ".o" - static_lib_extension = ".a" - shared_lib_extension = ".so" - dylib_lib_extension = ".dylib" - static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s" - if sys.platform == "cygwin": - exe_extension = ".exe" - - def preprocess(self, source, - output_file=None, macros=None, include_dirs=None, - extra_preargs=None, extra_postargs=None): - ignore, macros, include_dirs = \ - self._fix_compile_args(None, macros, include_dirs) - pp_opts = gen_preprocess_options(macros, include_dirs) - pp_args = self.preprocessor + pp_opts - if output_file: - pp_args.extend(['-o', output_file]) - if extra_preargs: - pp_args[:0] = extra_preargs - if extra_postargs: - pp_args.extend(extra_postargs) - pp_args.append(source) - - # We need to preprocess: either we're being forced to, or we're - # generating output to stdout, or there's a target output file and - # the source file is newer than the target (or the target doesn't - # exist). - if self.force or output_file is None or newer(source, output_file): - if output_file: - self.mkpath(os.path.dirname(output_file)) - try: - self.spawn(pp_args) - except DistutilsExecError, msg: - raise CompileError, msg - - def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts): - compiler_so = self.compiler_so - if sys.platform == 'darwin': - compiler_so = _darwin_compiler_fixup(compiler_so, cc_args + extra_postargs) - try: - self.spawn(compiler_so + cc_args + [src, '-o', obj] + - extra_postargs) - except DistutilsExecError, msg: - raise CompileError, msg - - def create_static_lib(self, objects, output_libname, - output_dir=None, debug=0, target_lang=None): - objects, output_dir = self._fix_object_args(objects, output_dir) - - output_filename = \ - self.library_filename(output_libname, output_dir=output_dir) - - if self._need_link(objects, output_filename): - self.mkpath(os.path.dirname(output_filename)) - self.spawn(self.archiver + - [output_filename] + - objects + self.objects) - - # Not many Unices required ranlib anymore -- SunOS 4.x is, I - # think the only major Unix that does. Maybe we need some - # platform intelligence here to skip ranlib if it's not - # needed -- or maybe Python's configure script took care of - # it for us, hence the check for leading colon. - if self.ranlib: - try: - self.spawn(self.ranlib + [output_filename]) - except DistutilsExecError, msg: - raise LibError, msg - else: - log.debug("skipping %s (up-to-date)", output_filename) - - def link(self, target_desc, objects, - output_filename, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, - export_symbols=None, debug=0, extra_preargs=None, - extra_postargs=None, build_temp=None, target_lang=None): - objects, output_dir = self._fix_object_args(objects, output_dir) - libraries, library_dirs, runtime_library_dirs = \ - self._fix_lib_args(libraries, library_dirs, runtime_library_dirs) - - lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, - libraries) - if type(output_dir) not in (StringType, NoneType): - raise TypeError, "'output_dir' must be a string or None" - if output_dir is not None: - output_filename = os.path.join(output_dir, output_filename) - - if self._need_link(objects, output_filename): - ld_args = (objects + self.objects + - lib_opts + ['-o', output_filename]) - if debug: - ld_args[:0] = ['-g'] - if extra_preargs: - ld_args[:0] = extra_preargs - if extra_postargs: - ld_args.extend(extra_postargs) - self.mkpath(os.path.dirname(output_filename)) - try: - if target_desc == CCompiler.EXECUTABLE: - linker = self.linker_exe[:] - else: - linker = self.linker_so[:] - if target_lang == "c++" and self.compiler_cxx: - # skip over environment variable settings if /usr/bin/env - # is used to set up the linker's environment. - # This is needed on OSX. Note: this assumes that the - # normal and C++ compiler have the same environment - # settings. - i = 0 - if os.path.basename(linker[0]) == "env": - i = 1 - while '=' in linker[i]: - i = i + 1 - - linker[i] = self.compiler_cxx[i] - - if sys.platform == 'darwin': - linker = _darwin_compiler_fixup(linker, ld_args) - - self.spawn(linker + ld_args) - except DistutilsExecError, msg: - raise LinkError, msg - else: - log.debug("skipping %s (up-to-date)", output_filename) - - # -- Miscellaneous methods ----------------------------------------- - # These are all used by the 'gen_lib_options() function, in - # ccompiler.py. - - def library_dir_option(self, dir): - return "-L" + dir - - def _is_gcc(self, compiler_name): - return "gcc" in compiler_name or "g++" in compiler_name - - def runtime_library_dir_option(self, dir): - # XXX Hackish, at the very least. See Python bug #445902: - # http://sourceforge.net/tracker/index.php - # ?func=detail&aid=445902&group_id=5470&atid=105470 - # Linkers on different platforms need different options to - # specify that directories need to be added to the list of - # directories searched for dependencies when a dynamic library - # is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to - # be told to pass the -R option through to the linker, whereas - # other compilers and gcc on other systems just know this. - # Other compilers may need something slightly different. At - # this time, there's no way to determine this information from - # the configuration data stored in the Python installation, so - # we use this hack. - - compiler = os.path.basename(sysconfig.get_config_var("CC")) - if sys.platform[:6] == "darwin": - # MacOSX's linker doesn't understand the -R flag at all - return "-L" + dir - elif sys.platform[:5] == "hp-ux": - if self._is_gcc(compiler): - return ["-Wl,+s", "-L" + dir] - return ["+s", "-L" + dir] - elif sys.platform[:7] == "irix646" or sys.platform[:6] == "osf1V5": - return ["-rpath", dir] - elif self._is_gcc(compiler): - # gcc on non-GNU systems does not need -Wl, but can - # use it anyway. Since distutils has always passed in - # -Wl whenever gcc was used in the past it is probably - # safest to keep doing so. - if sysconfig.get_config_var("GNULD") == "yes": - # GNU ld needs an extra option to get a RUNPATH - # instead of just an RPATH. - return "-Wl,--enable-new-dtags,-R" + dir - else: - return "-Wl,-R" + dir - elif sys.platform[:3] == "aix": - return "-blibpath:" + dir - else: - # No idea how --enable-new-dtags would be passed on to - # ld if this system was using GNU ld. Don't know if a - # system like this even exists. - return "-R" + dir - - def library_option(self, lib): - return "-l" + lib - - def find_library_file(self, dirs, lib, debug=0): - shared_f = self.library_filename(lib, lib_type='shared') - dylib_f = self.library_filename(lib, lib_type='dylib') - static_f = self.library_filename(lib, lib_type='static') - - for dir in dirs: - shared = os.path.join(dir, shared_f) - dylib = os.path.join(dir, dylib_f) - static = os.path.join(dir, static_f) - # We're second-guessing the linker here, with not much hard - # data to go on: GCC seems to prefer the shared library, so I'm - # assuming that *all* Unix C compilers do. And of course I'm - # ignoring even GCC's "-static" option. So sue me. - if os.path.exists(dylib): - return dylib - elif os.path.exists(shared): - return shared - elif os.path.exists(static): - return static - - # Oops, didn't find it in *any* of 'dirs' - return None diff --git a/src/distutils2/converter/__init__.py b/src/distutils2/converter/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/converter/__init__.py +++ /dev/null diff --git a/src/distutils2/converter/fixers/__init__.py b/src/distutils2/converter/fixers/__init__.py deleted file mode 100644 index cd6acf4..0000000 --- a/src/distutils2/converter/fixers/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""distutils2.converter.fixers - -Contains all fixers for the converter. -""" diff --git a/src/distutils2/converter/fixers/fix_imports.py b/src/distutils2/converter/fixers/fix_imports.py deleted file mode 100644 index 38d185e..0000000 --- a/src/distutils2/converter/fixers/fix_imports.py +++ /dev/null @@ -1,52 +0,0 @@ -"""distutils2.converter.fixers.fix_imports - -Fixer for import statements in setup.py -""" -from lib2to3.fixer_base import BaseFix -from lib2to3.fixer_util import syms - - -class FixImports(BaseFix): - """Makes sure all import in setup.py are translated""" - - PATTERN = """ - import_from< 'from' imp=any 'import' ['('] any [')'] > - | - import_name< 'import' imp=any > - """ - - def transform(self, node, results): - imp = results['imp'] - if node.type != syms.import_from: - return - - if not hasattr(imp, "next_sibling"): - imp.next_sibling = imp.get_next_sibling() - - while not hasattr(imp, 'value'): - imp = imp.children[0] - - if imp.value == 'distutils': - imp.value = 'distutils2' - imp.changed() - return node - - if imp.value == 'setuptools': - # catching "from setuptools import setup" - pattern = [] - next = imp.next_sibling - while next is not None: - # Get the first child if we have a Node - if not hasattr(next, "value"): - next = next.children[0] - pattern.append(next.value) - if not hasattr(next, "next_sibling"): - next.next_sibling = next.get_next_sibling() - next = next.next_sibling - - if set(pattern).issubset(set( - ['import', ',', 'setup', 'find_packages'])): - imp.value = 'distutils2.core' - imp.changed() - - return node diff --git a/src/distutils2/converter/fixers/fix_setup_options.py b/src/distutils2/converter/fixers/fix_setup_options.py deleted file mode 100644 index 7d319fb..0000000 --- a/src/distutils2/converter/fixers/fix_setup_options.py +++ /dev/null @@ -1,85 +0,0 @@ -"""Fixer for setup() options. - -All distutils or setuptools options are translated -into PEP 345-style options. -""" -from lib2to3.pytree import Leaf, Node -from lib2to3.pgen2 import token -from lib2to3.fixer_base import BaseFix - -# XXX where is that defined ? -_ARG = 260 - -# name mapping : we want to convert -# all old-style options to distutils2 style -_OLD_NAMES = {'url': 'home_page', - 'long_description': 'description', - 'description': 'summary', - 'install_requires': 'requires_dist'} - -_SEQUENCE_NAMES = ['requires_dist'] - - -class FixSetupOptions(BaseFix): - - # XXX need to find something better here : - # identify a setup call, whatever alias is used - PATTERN = """ - power< name='setup' trailer< '(' [any] ')' > any* > - """ - - def _get_list(self, *nodes): - """A List node, filled""" - lbrace = Leaf(token.LBRACE, u"[") - lbrace.prefix = u" " - if len(nodes) > 0: - nodes[0].prefix = u"" - return Node(self.syms.trailer, - [lbrace] + - [node.clone() for node in nodes] + - [Leaf(token.RBRACE, u"]")]) - - def _fix_name(self, argument, remove_list): - name = argument.children[0] - - if not hasattr(name, "next_sibling"): - name.next_sibling = name.get_next_sibling() - - sibling = name.next_sibling - if sibling is None or sibling.type != token.EQUAL: - return False - - if name.value in _OLD_NAMES: - name.value = _OLD_NAMES[name.value] - if name.value in _SEQUENCE_NAMES: - if not hasattr(sibling, "next_sibling"): - sibling.next_sibling = sibling.get_next_sibling() - right_operand = sibling.next_sibling - # replacing string -> list[string] - if right_operand.type == token.STRING: - # we want this to be a list now - new_node = self._get_list(right_operand) - right_operand.replace(new_node) - - - return True - - return False - - def transform(self, node, results): - arglist = node.children[1].children[1] - remove_list = [] - changed = False - - for subnode in arglist.children: - if subnode.type != _ARG: - continue - if self._fix_name(subnode, remove_list) and not changed: - changed = True - - for subnode in remove_list: - subnode.remove() - - if changed: - node.changed() - return node diff --git a/src/distutils2/converter/refactor.py b/src/distutils2/converter/refactor.py deleted file mode 100644 index 28fbd44..0000000 --- a/src/distutils2/converter/refactor.py +++ /dev/null @@ -1,12 +0,0 @@ -"""distutils2.converter.refactor - -""" -try: - from lib2to3.refactor import RefactoringTool - _LIB2TO3 = True -except ImportError: - # we need 2.6 at least to run this - _LIB2TO3 = False - -_DISTUTILS_FIXERS = ['distutils2.converter.fixers.fix_imports', - 'distutils2.converter.fixers.fix_setup_options']
\ No newline at end of file diff --git a/src/distutils2/core.py b/src/distutils2/core.py deleted file mode 100644 index 2a76a70..0000000 --- a/src/distutils2/core.py +++ /dev/null @@ -1,219 +0,0 @@ -"""distutils2.core - -The only module that needs to be imported to use the Distutils; provides -the 'setup' function (which is to be called from the setup script). Also -exports useful classes so that setup scripts can import them from here -although they are really defined in other modules: Distribution, Command, -PyPIRCommand, Extension, find_packages. -""" - -__revision__ = "$Id: core.py 77704 2010-01-23 09:23:15Z tarek.ziade $" - -import sys -import os - -from distutils2.errors import (DistutilsSetupError, DistutilsArgError, - DistutilsError, CCompilerError) -from distutils2.util import grok_environment_error - -# Mainly import these so setup scripts can "from distutils2.core import" them. -from distutils2.dist import Distribution -from distutils2.command.cmd import Command -from distutils2.extension import Extension -from distutils2.util import find_packages - -# This is a barebones help message generated displayed when the user -# runs the setup script with no arguments at all. More useful help -# is generated with various --help options: global help, list commands, -# and per-command help. -USAGE = """\ -usage: %(script)s [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] - or: %(script)s --help [cmd1 cmd2 ...] - or: %(script)s --help-commands - or: %(script)s cmd --help -""" - - -def gen_usage(script_name): - script = os.path.basename(script_name) - return USAGE % {'script': script} - - -# Some mild magic to control the behaviour of 'setup()' from 'run_setup()'. -_setup_stop_after = None -_setup_distribution = None - -# Legal keyword arguments for the setup() function -setup_keywords = ('distclass', 'script_name', 'script_args', 'options', - 'name', 'version', 'author', 'author_email', - 'maintainer', 'maintainer_email', 'url', 'license', - 'description', 'long_description', 'keywords', - 'platforms', 'classifiers', 'download_url', - 'requires', 'provides', 'obsoletes', 'use_2to3_fixers', - 'convert_2to3_doctests', 'use_2to3_fixers' - ) - -# Legal keyword arguments for the Extension constructor -extension_keywords = ('name', 'sources', 'include_dirs', - 'define_macros', 'undef_macros', - 'library_dirs', 'libraries', 'runtime_library_dirs', - 'extra_objects', 'extra_compile_args', 'extra_link_args', - 'swig_opts', 'export_symbols', 'depends', 'language') - - -def setup(**attrs): - """The gateway to the Distutils: do everything your setup script needs - to do, in a highly flexible and user-driven way. Briefly: create a - Distribution instance; find and parse config files; parse the command - line; run each Distutils command found there, customized by the options - supplied to 'setup()' (as keyword arguments), in config files, and on - the command line. - - The Distribution instance might be an instance of a class supplied via - the 'distclass' keyword argument to 'setup'; if no such class is - supplied, then the Distribution class (in dist.py) is instantiated. - All other arguments to 'setup' (except for 'cmdclass') are used to set - attributes of the Distribution instance. - - The 'cmdclass' argument, if supplied, is a dictionary mapping command - names to command classes. Each command encountered on the command line - will be turned into a command class, which is in turn instantiated; any - class found in 'cmdclass' is used in place of the default, which is - (for command 'foo_bar') class 'foo_bar' in module - 'distutils2.command.foo_bar'. The command class must provide a - 'user_options' attribute which is a list of option specifiers for - 'distutils2.fancy_getopt'. Any command-line options between the current - and the next command are used to set attributes of the current command - object. - - When the entire command line has been successfully parsed, calls the - 'run()' method on each command object in turn. This method will be - driven entirely by the Distribution object (which each command object - has a reference to, thanks to its constructor), and the - command-specific options that became attributes of each command - object. - """ - - global _setup_stop_after, _setup_distribution - - # Determine the distribution class -- either caller-supplied or - # our Distribution (see below). - distclass = attrs.pop('distclass', Distribution) - - if 'script_name' not in attrs: - attrs['script_name'] = os.path.basename(sys.argv[0]) - if 'script_args' not in attrs: - attrs['script_args'] = sys.argv[1:] - - # Create the Distribution instance, using the remaining arguments - # (ie. everything except distclass) to initialize it - try: - _setup_distribution = dist = distclass(attrs) - except DistutilsSetupError, msg: - if 'name' in attrs: - raise SystemExit, "error in %s setup command: %s" % \ - (attrs['name'], msg) - else: - raise SystemExit, "error in setup command: %s" % msg - - if _setup_stop_after == "init": - return dist - - # Find and parse the config file(s): they will override options from - # the setup script, but be overridden by the command line. - dist.parse_config_files() - - if _setup_stop_after == "config": - return dist - - # Parse the command line and override config files; any - # command line errors are the end user's fault, so turn them into - # SystemExit to suppress tracebacks. - try: - ok = dist.parse_command_line() - except DistutilsArgError, msg: - raise SystemExit, gen_usage(dist.script_name) + "\nerror: %s" % msg - - if _setup_stop_after == "commandline": - return dist - - # And finally, run all the commands found on the command line. - if ok: - try: - dist.run_commands() - except KeyboardInterrupt: - raise SystemExit, "interrupted" - except (IOError, os.error), exc: - error = grok_environment_error(exc) - raise SystemExit, error - - except (DistutilsError, - CCompilerError), msg: - raise SystemExit, "error: " + str(msg) - - return dist - - -def run_setup(script_name, script_args=None, stop_after="run"): - """Run a setup script in a somewhat controlled environment, and - return the Distribution instance that drives things. This is useful - if you need to find out the distribution metadata (passed as - keyword args from 'script' to 'setup()', or the contents of the - config files or command line. - - 'script_name' is a file that will be run with 'execfile()'; - 'sys.argv[0]' will be replaced with 'script' for the duration of the - call. 'script_args' is a list of strings; if supplied, - 'sys.argv[1:]' will be replaced by 'script_args' for the duration of - the call. - - 'stop_after' tells 'setup()' when to stop processing; possible - values: - init - stop after the Distribution instance has been created and - populated with the keyword arguments to 'setup()' - config - stop after config files have been parsed (and their data - stored in the Distribution instance) - commandline - stop after the command line ('sys.argv[1:]' or 'script_args') - has been parsed (and the data stored in the Distribution) - run [default] - stop after all commands have been run (the same as if 'setup()' - had been called in the usual way - - Returns the Distribution instance, which provides all information - used to drive the Distutils. - """ - if stop_after not in ('init', 'config', 'commandline', 'run'): - raise ValueError, "invalid value for 'stop_after': %r" % (stop_after,) - - global _setup_stop_after, _setup_distribution - _setup_stop_after = stop_after - - save_argv = sys.argv - g = {'__file__': script_name} - l = {} - try: - try: - sys.argv[0] = script_name - if script_args is not None: - sys.argv[1:] = script_args - exec open(script_name, 'r').read() in g, l - finally: - sys.argv = save_argv - _setup_stop_after = None - except SystemExit: - # Hmm, should we do something if exiting with a non-zero code - # (ie. error)? - pass - - if _setup_distribution is None: - raise RuntimeError, \ - ("'distutils2.core.setup()' was never called -- " - "perhaps '%s' is not a Distutils setup script?") % \ - script_name - - # I wonder if the setup script's namespace -- g and l -- would be of - # any interest to callers? - return _setup_distribution diff --git a/src/distutils2/depgraph.py b/src/distutils2/depgraph.py deleted file mode 100644 index 2d66a39..0000000 --- a/src/distutils2/depgraph.py +++ /dev/null @@ -1,188 +0,0 @@ -"""Analyse the relationships between the distributions in the system -and generate a dependency graph. -""" - -from distutils2.errors import DistutilsError -from distutils2.version import VersionPredicate - -__all__ = ['DependencyGraph', 'generate_graph', 'dependent_dists', - 'graph_to_dot'] - - -class DependencyGraph(object): - """ - Represents a dependency graph between distributions. - - The dependency relationships are stored in an ``adjacency_list`` that maps - distributions to a list of ``(other, label)`` tuples where ``other`` - is a distribution and the edge is labelled with ``label`` (i.e. the version - specifier, if such was provided). Also, for more efficient traversal, for - every distribution ``x``, a list of predecessors is kept in - ``reverse_list[x]``. An edge from distribution ``a`` to - distribution ``b`` means that ``a`` depends on ``b``. If any missing - depencies are found, they are stored in ``missing``, which is a dictionary - that maps distributions to a list of requirements that were not provided by - any other distributions. - """ - - def __init__(self): - self.adjacency_list = {} - self.reverse_list = {} - self.missing = {} - - def add_distribution(self, distribution): - """Add the *distribution* to the graph. - - :type distribution: :class:`pkgutil.Distribution` or - :class:`pkgutil.EggInfoDistribution` - """ - self.adjacency_list[distribution] = list() - self.reverse_list[distribution] = list() - self.missing[distribution] = list() - - def add_edge(self, x, y, label=None): - """Add an edge from distribution *x* to distribution *y* with the given - *label*. - - :type x: :class:`pkgutil.Distribution` or - :class:`pkgutil.EggInfoDistribution` - :type y: :class:`pkgutil.Distribution` or - :class:`pkgutil.EggInfoDistribution` - :type label: ``str`` or ``None`` - """ - self.adjacency_list[x].append((y, label)) - # multiple edges are allowed, so be careful - if not x in self.reverse_list[y]: - self.reverse_list[y].append(x) - - def add_missing(self, distribution, requirement): - """ - Add a missing *requirement* for the given *distribution*. - - :type distribution: :class:`pkgutil.Distribution` or - :class:`pkgutil.EggInfoDistribution` - :type requirement: ``str`` - """ - self.missing[distribution].append(requirement) - - -def graph_to_dot(graph, f, skip_disconnected=True): - """Writes a DOT output for the graph to the provided file *f*. - - If *skip_disconnected* is set to ``True``, then all distributions - that are not dependent on any other distribution are skipped. - - :type f: has to support ``file``-like operations - :type skip_disconnected: ``bool`` - """ - disconnected = [] - - f.write("digraph dependencies {\n") - for dist, adjs in graph.adjacency_list.iteritems(): - if len(adjs) == 0 and not skip_disconnected: - disconnected.append(dist) - for (other, label) in adjs: - if not label is None: - f.write('"%s" -> "%s" [label="%s"]\n' % - (dist.name, other.name, label)) - else: - f.write('"%s" -> "%s"\n' % (dist.name, other.name)) - if not skip_disconnected and len(disconnected) > 0: - f.write('subgraph disconnected {\n') - f.write('label = "Disconnected"\n') - f.write('bgcolor = red\n') - - for dist in disconnected: - f.write('"%s"' % dist.name) - f.write('\n') - f.write('}\n') - f.write('}\n') - - -def generate_graph(dists): - """Generates a dependency graph from the given distributions. - - :parameter dists: a list of distributions - :type dists: list of :class:`pkgutil.Distribution` and - :class:`pkgutil.EggInfoDistribution` instances - :rtype: an :class:`DependencyGraph` instance - """ - graph = DependencyGraph() - provided = {} # maps names to lists of (version, dist) tuples - dists = list(dists) # maybe use generator_tools in future - - # first, build the graph and find out the provides - for dist in dists: - graph.add_distribution(dist) - provides = dist.metadata['Provides-Dist'] + dist.metadata['Provides'] - - for p in provides: - comps = p.strip().rsplit(" ", 1) - name = comps[0] - version = None - if len(comps) == 2: - version = comps[1] - if len(version) < 3 or version[0] != '(' or version[-1] != ')': - raise DistutilsError('Distribution %s has ill formed' \ - 'provides field: %s' % (dist.name, p)) - version = version[1:-1] # trim off parenthesis - if not name in provided: - provided[name] = [] - provided[name].append((version, dist)) - - # now make the edges - for dist in dists: - requires = dist.metadata['Requires-Dist'] + dist.metadata['Requires'] - for req in requires: - predicate = VersionPredicate(req) - name = predicate.name - - if not name in provided: - graph.add_missing(dist, req) - else: - matched = False - for (version, provider) in provided[name]: - if predicate.match(version): - graph.add_edge(dist, provider, req) - matched = True - break - if not matched: - graph.add_missing(dist, req) - - return graph - - -def dependent_dists(dists, dist): - """Recursively generate a list of distributions from *dists* that are - dependent on *dist*. - - :param dists: a list of distributions - :param dist: a distribution, member of *dists* for which we are interested - """ - if not dist in dists: - raise ValueError('The given distribution is not a member of the list') - graph = generate_graph(dists) - - dep = [dist] # dependent distributions - fringe = graph.reverse_list[dist] # list of nodes we should inspect - - while not len(fringe) == 0: - node = fringe.pop() - dep.append(node) - for prev in graph.reverse_list[node]: - if not prev in dep: - fringe.append(prev) - - dep.pop(0) # remove dist from dep, was there to prevent infinite loops - return dep - -if __name__ == '__main__': - from distutils2._backport.pkgutil import get_distributions - dists = list(get_distributions(use_egg_info=True)) - graph = generate_graph(dists) - for dist, reqs in graph.missing.iteritems(): - if len(reqs) > 0: - print("Missing dependencies for %s: %s" % (dist.name, - ", ".join(reqs))) - f = open('output.dot', 'w') - graph_to_dot(graph, f, True) diff --git a/src/distutils2/dist.py b/src/distutils2/dist.py deleted file mode 100644 index 2f491ca..0000000 --- a/src/distutils2/dist.py +++ /dev/null @@ -1,1032 +0,0 @@ -"""distutils.dist - -Provides the Distribution class, which represents the module distribution -being built/installed/distributed. -""" - -__revision__ = "$Id: dist.py 77717 2010-01-24 00:33:32Z tarek.ziade $" - -import sys -import os -import re -import warnings - -from ConfigParser import RawConfigParser - -from distutils2.errors import (DistutilsOptionError, DistutilsArgError, - DistutilsModuleError, DistutilsClassError) -from distutils2.fancy_getopt import FancyGetopt -from distutils2.util import check_environ, strtobool, resolve_name -from distutils2 import log -from distutils2.metadata import DistributionMetadata - -# Regex to define acceptable Distutils command names. This is not *quite* -# the same as a Python NAME -- I don't allow leading underscores. The fact -# that they're very similar is no coincidence; the default naming scheme is -# to look for a Python module named after the command. -command_re = re.compile(r'^[a-zA-Z]([a-zA-Z0-9_]*)$') - - -class Distribution(object): - """The core of the Distutils. Most of the work hiding behind 'setup' - is really done within a Distribution instance, which farms the work out - to the Distutils commands specified on the command line. - - Setup scripts will almost never instantiate Distribution directly, - unless the 'setup()' function is totally inadequate to their needs. - However, it is conceivable that a setup script might wish to subclass - Distribution for some specialized purpose, and then pass the subclass - to 'setup()' as the 'distclass' keyword argument. If so, it is - necessary to respect the expectations that 'setup' has of Distribution. - See the code for 'setup()', in core.py, for details. - """ - - # 'global_options' describes the command-line options that may be - # supplied to the setup script prior to any actual commands. - # Eg. "./setup.py -n" or "./setup.py --quiet" both take advantage of - # these global options. This list should be kept to a bare minimum, - # since every global option is also valid as a command option -- and we - # don't want to pollute the commands with too many options that they - # have minimal control over. - # The fourth entry for verbose means that it can be repeated. - global_options = [('verbose', 'v', "run verbosely (default)", 1), - ('quiet', 'q', "run quietly (turns verbosity off)"), - ('dry-run', 'n', "don't actually do anything"), - ('help', 'h', "show detailed help message"), - ('no-user-cfg', None, - 'ignore pydistutils.cfg in your home directory'), - ] - - # 'common_usage' is a short (2-3 line) string describing the common - # usage of the setup script. - common_usage = """\ -Common commands: (see '--help-commands' for more) - - setup.py build will build the package underneath 'build/' - setup.py install will install the package -""" - - # options that are not propagated to the commands - display_options = [ - ('help-commands', None, - "list all available commands"), - ('name', None, - "print package name"), - ('version', 'V', - "print package version"), - ('fullname', None, - "print <package name>-<version>"), - ('author', None, - "print the author's name"), - ('author-email', None, - "print the author's email address"), - ('maintainer', None, - "print the maintainer's name"), - ('maintainer-email', None, - "print the maintainer's email address"), - ('contact', None, - "print the maintainer's name if known, else the author's"), - ('contact-email', None, - "print the maintainer's email address if known, else the author's"), - ('url', None, - "print the URL for this package"), - ('license', None, - "print the license of the package"), - ('licence', None, - "alias for --license"), - ('description', None, - "print the package description"), - ('long-description', None, - "print the long package description"), - ('platforms', None, - "print the list of platforms"), - ('classifier', None, - "print the list of classifiers"), - ('keywords', None, - "print the list of keywords"), - ('provides', None, - "print the list of packages/modules provided"), - ('requires', None, - "print the list of packages/modules required"), - ('obsoletes', None, - "print the list of packages/modules made obsolete"), - ('use-2to3', None, - "use 2to3 to make source python 3.x compatible"), - ('convert-2to3-doctests', None, - "use 2to3 to convert doctests in seperate text files"), - ] - display_option_names = [x[0].replace('-', '_') for x in display_options] - - # negative options are options that exclude other options - negative_opt = {'quiet': 'verbose'} - - # -- Creation/initialization methods ------------------------------- - def __init__(self, attrs=None): - """Construct a new Distribution instance: initialize all the - attributes of a Distribution, and then use 'attrs' (a dictionary - mapping attribute names to values) to assign some of those - attributes their "real" values. (Any attributes not mentioned in - 'attrs' will be assigned to some null value: 0, None, an empty list - or dictionary, etc.) Most importantly, initialize the - 'command_obj' attribute to the empty dictionary; this will be - filled in with real command objects by 'parse_command_line()'. - """ - - # Default values for our command-line options - self.verbose = 1 - self.dry_run = 0 - self.help = 0 - for attr in self.display_option_names: - setattr(self, attr, 0) - - # Store the distribution metadata (name, version, author, and so - # forth) in a separate object -- we're getting to have enough - # information here (and enough command-line options) that it's - # worth it. - self.metadata = DistributionMetadata() - - # 'cmdclass' maps command names to class objects, so we - # can 1) quickly figure out which class to instantiate when - # we need to create a new command object, and 2) have a way - # for the setup script to override command classes - self.cmdclass = {} - - # 'command_packages' is a list of packages in which commands - # are searched for. The factory for command 'foo' is expected - # to be named 'foo' in the module 'foo' in one of the packages - # named here. This list is searched from the left; an error - # is raised if no named package provides the command being - # searched for. (Always access using get_command_packages().) - self.command_packages = None - - # 'script_name' and 'script_args' are usually set to sys.argv[0] - # and sys.argv[1:], but they can be overridden when the caller is - # not necessarily a setup script run from the command line. - self.script_name = None - self.script_args = None - - # 'command_options' is where we store command options between - # parsing them (from config files, the command line, etc.) and when - # they are actually needed -- ie. when the command in question is - # instantiated. It is a dictionary of dictionaries of 2-tuples: - # command_options = { command_name : { option : (source, value) } } - self.command_options = {} - - # 'dist_files' is the list of (command, pyversion, file) that - # have been created by any dist commands run so far. This is - # filled regardless of whether the run is dry or not. pyversion - # gives sysconfig.get_python_version() if the dist file is - # specific to a Python version, 'any' if it is good for all - # Python versions on the target platform, and '' for a source - # file. pyversion should not be used to specify minimum or - # maximum required Python versions; use the metainfo for that - # instead. - self.dist_files = [] - - # These options are really the business of various commands, rather - # than of the Distribution itself. We provide aliases for them in - # Distribution as a convenience to the developer. - self.packages = [] - self.package_data = {} - self.package_dir = None - self.py_modules = [] - self.libraries = [] - self.headers = [] - self.ext_modules = [] - self.ext_package = None - self.include_dirs = [] - self.extra_path = None - self.scripts = [] - self.data_files = [] - self.password = '' - self.use_2to3 = False - self.convert_2to3_doctests = [] - - # And now initialize bookkeeping stuff that can't be supplied by - # the caller at all. 'command_obj' maps command names to - # Command instances -- that's how we enforce that every command - # class is a singleton. - self.command_obj = {} - - # 'have_run' maps command names to boolean values; it keeps track - # of whether we have actually run a particular command, to make it - # cheap to "run" a command whenever we think we might need to -- if - # it's already been done, no need for expensive filesystem - # operations, we just check the 'have_run' dictionary and carry on. - # It's only safe to query 'have_run' for a command class that has - # been instantiated -- a false value will be inserted when the - # command object is created, and replaced with a true value when - # the command is successfully run. Thus it's probably best to use - # '.get()' rather than a straight lookup. - self.have_run = {} - - # Now we'll use the attrs dictionary (ultimately, keyword args from - # the setup script) to possibly override any or all of these - # distribution options. - - if attrs is not None: - # Pull out the set of command options and work on them - # specifically. Note that this order guarantees that aliased - # command options will override any supplied redundantly - # through the general options dictionary. - options = attrs.get('options') - if options is not None: - del attrs['options'] - for (command, cmd_options) in options.items(): - opt_dict = self.get_option_dict(command) - for (opt, val) in cmd_options.items(): - opt_dict[opt] = ("setup script", val) - - # Now work on the rest of the attributes. Any attribute that's - # not already defined is invalid! - for key, val in attrs.items(): - if self.metadata.is_metadata_field(key): - self.metadata[key] = val - elif hasattr(self, key): - setattr(self, key, val) - else: - msg = "Unknown distribution option: %r" % key - warnings.warn(msg) - - # no-user-cfg is handled before other command line args - # because other args override the config files, and this - # one is needed before we can load the config files. - # If attrs['script_args'] wasn't passed, assume false. - # - # This also make sure we just look at the global options - self.want_user_cfg = True - - if self.script_args is not None: - for arg in self.script_args: - if not arg.startswith('-'): - break - if arg == '--no-user-cfg': - self.want_user_cfg = False - break - - self.finalize_options() - - def get_option_dict(self, command): - """Get the option dictionary for a given command. If that - command's option dictionary hasn't been created yet, then create it - and return the new dictionary; otherwise, return the existing - option dictionary. - """ - d = self.command_options.get(command) - if d is None: - d = self.command_options[command] = {} - return d - - def get_fullname(self): - return self.metadata.get_fullname() - - def dump_option_dicts(self, header=None, commands=None, indent=""): - from pprint import pformat - - if commands is None: # dump all command option dicts - commands = self.command_options.keys() - commands.sort() - - if header is not None: - self.announce(indent + header) - indent = indent + " " - - if not commands: - self.announce(indent + "no commands known yet") - return - - for cmd_name in commands: - opt_dict = self.command_options.get(cmd_name) - if opt_dict is None: - self.announce(indent + - "no option dict for '%s' command" % cmd_name) - else: - self.announce(indent + - "option dict for '%s' command:" % cmd_name) - out = pformat(opt_dict) - for line in out.split('\n'): - self.announce(indent + " " + line) - - # -- Config file finding/parsing methods --------------------------- - - def find_config_files(self): - """Find as many configuration files as should be processed for this - platform, and return a list of filenames in the order in which they - should be parsed. The filenames returned are guaranteed to exist - (modulo nasty race conditions). - - There are three possible config files: distutils.cfg in the - Distutils installation directory (ie. where the top-level - Distutils __inst__.py file lives), a file in the user's home - directory named .pydistutils.cfg on Unix and pydistutils.cfg - on Windows/Mac; and setup.cfg in the current directory. - - The file in the user's home directory can be disabled with the - --no-user-cfg option. - """ - files = [] - check_environ() - - # Where to look for the system-wide Distutils config file - sys_dir = os.path.dirname(sys.modules['distutils2'].__file__) - - # Look for the system config file - sys_file = os.path.join(sys_dir, "distutils.cfg") - if os.path.isfile(sys_file): - files.append(sys_file) - - # What to call the per-user config file - if os.name == 'posix': - user_filename = ".pydistutils.cfg" - else: - user_filename = "pydistutils.cfg" - - # And look for the user config file - if self.want_user_cfg: - user_file = os.path.join(os.path.expanduser('~'), user_filename) - if os.path.isfile(user_file): - files.append(user_file) - - # All platforms support local setup.cfg - local_file = "setup.cfg" - if os.path.isfile(local_file): - files.append(local_file) - - log.debug("using config files: %s" % ', '.join(files)) - return files - - def parse_config_files(self, filenames=None): - if filenames is None: - filenames = self.find_config_files() - - log.debug("Distribution.parse_config_files():") - - parser = RawConfigParser() - for filename in filenames: - log.debug(" reading %s" % filename) - parser.read(filename) - for section in parser.sections(): - options = parser.options(section) - opt_dict = self.get_option_dict(section) - - for opt in options: - if opt != '__name__': - val = parser.get(section, opt) - opt = opt.replace('-', '_') - - # Hooks use a suffix system to prevent being overriden - # by a config file processed later (i.e. a hook set in - # the user config file cannot be replaced by a hook - # set in a project config file, unless they have the - # same suffix). - if opt.startswith("pre_hook.") or opt.startswith("post_hook."): - hook_type, alias = opt.split(".") - hook_dict = opt_dict.setdefault(hook_type, (filename, {}))[1] - hook_dict[alias] = val - else: - opt_dict[opt] = (filename, val) - - # Make the RawConfigParser forget everything (so we retain - # the original filenames that options come from) - parser.__init__() - - # If there was a "global" section in the config file, use it - # to set Distribution options. - - if 'global' in self.command_options: - for (opt, (src, val)) in self.command_options['global'].items(): - alias = self.negative_opt.get(opt) - try: - if alias: - setattr(self, alias, not strtobool(val)) - elif opt in ('verbose', 'dry_run'): # ugh! - setattr(self, opt, strtobool(val)) - else: - setattr(self, opt, val) - except ValueError, msg: - raise DistutilsOptionError(msg) - - # -- Command-line parsing methods ---------------------------------- - - def parse_command_line(self): - """Parse the setup script's command line, taken from the - 'script_args' instance attribute (which defaults to 'sys.argv[1:]' - -- see 'setup()' in core.py). This list is first processed for - "global options" -- options that set attributes of the Distribution - instance. Then, it is alternately scanned for Distutils commands - and options for that command. Each new command terminates the - options for the previous command. The allowed options for a - command are determined by the 'user_options' attribute of the - command class -- thus, we have to be able to load command classes - in order to parse the command line. Any error in that 'options' - attribute raises DistutilsGetoptError; any error on the - command line raises DistutilsArgError. If no Distutils commands - were found on the command line, raises DistutilsArgError. Return - true if command line was successfully parsed and we should carry - on with executing commands; false if no errors but we shouldn't - execute commands (currently, this only happens if user asks for - help). - """ - # - # We now have enough information to show the Macintosh dialog - # that allows the user to interactively specify the "command line". - # - toplevel_options = self._get_toplevel_options() - - # We have to parse the command line a bit at a time -- global - # options, then the first command, then its options, and so on -- - # because each command will be handled by a different class, and - # the options that are valid for a particular class aren't known - # until we have loaded the command class, which doesn't happen - # until we know what the command is. - - self.commands = [] - parser = FancyGetopt(toplevel_options + self.display_options) - parser.set_negative_aliases(self.negative_opt) - parser.set_aliases({'licence': 'license'}) - args = parser.getopt(args=self.script_args, object=self) - option_order = parser.get_option_order() - log.set_verbosity(self.verbose) - - # for display options we return immediately - if self.handle_display_options(option_order): - return - - while args: - args = self._parse_command_opts(parser, args) - if args is None: # user asked for help (and got it) - return - - # Handle the cases of --help as a "global" option, ie. - # "setup.py --help" and "setup.py --help command ...". For the - # former, we show global options (--verbose, --dry-run, etc.) - # and display-only options (--name, --version, etc.); for the - # latter, we omit the display-only options and show help for - # each command listed on the command line. - if self.help: - self._show_help(parser, - display_options=len(self.commands) == 0, - commands=self.commands) - return - - # Oops, no commands found -- an end-user error - if not self.commands: - raise DistutilsArgError("no commands supplied") - - # All is well: return true - return 1 - - def _get_toplevel_options(self): - """Return the non-display options recognized at the top level. - - This includes options that are recognized *only* at the top - level as well as options recognized for commands. - """ - return self.global_options + [ - ("command-packages=", None, - "list of packages that provide distutils commands"), - ] - - def _parse_command_opts(self, parser, args): - """Parse the command-line options for a single command. - 'parser' must be a FancyGetopt instance; 'args' must be the list - of arguments, starting with the current command (whose options - we are about to parse). Returns a new version of 'args' with - the next command at the front of the list; will be the empty - list if there are no more commands on the command line. Returns - None if the user asked for help on this command. - """ - # late import because of mutual dependence between these modules - from distutils2.command.cmd import Command - - # Pull the current command from the head of the command line - command = args[0] - if not command_re.match(command): - raise SystemExit("invalid command name '%s'" % command) - self.commands.append(command) - - # Dig up the command class that implements this command, so we - # 1) know that it's a valid command, and 2) know which options - # it takes. - try: - cmd_class = self.get_command_class(command) - except DistutilsModuleError, msg: - raise DistutilsArgError(msg) - - # Require that the command class be derived from Command -- want - # to be sure that the basic "command" interface is implemented. - if not issubclass(cmd_class, Command): - raise DistutilsClassError( - "command class %s must subclass Command" % cmd_class) - - # Also make sure that the command object provides a list of its - # known options. - if not (hasattr(cmd_class, 'user_options') and - isinstance(cmd_class.user_options, list)): - raise DistutilsClassError( - ("command class %s must provide " - "'user_options' attribute (a list of tuples)") % cmd_class) - - # If the command class has a list of negative alias options, - # merge it in with the global negative aliases. - negative_opt = self.negative_opt - if hasattr(cmd_class, 'negative_opt'): - negative_opt = negative_opt.copy() - negative_opt.update(cmd_class.negative_opt) - - # Check for help_options in command class. They have a different - # format (tuple of four) so we need to preprocess them here. - if (hasattr(cmd_class, 'help_options') and - isinstance(cmd_class.help_options, list)): - help_options = fix_help_options(cmd_class.help_options) - else: - help_options = [] - - # All commands support the global options too, just by adding - # in 'global_options'. - parser.set_option_table(self.global_options + - cmd_class.user_options + - help_options) - parser.set_negative_aliases(negative_opt) - (args, opts) = parser.getopt(args[1:]) - if hasattr(opts, 'help') and opts.help: - self._show_help(parser, display_options=0, commands=[cmd_class]) - return - - if (hasattr(cmd_class, 'help_options') and - isinstance(cmd_class.help_options, list)): - help_option_found = 0 - for (help_option, short, desc, func) in cmd_class.help_options: - if hasattr(opts, help_option.replace('-', '_')): - help_option_found = 1 - if hasattr(func, '__call__'): - func() - else: - raise DistutilsClassError( - "invalid help function %r for help option '%s': " - "must be a callable object (function, etc.)" - % (func, help_option)) - - if help_option_found: - return - - # Put the options from the command line into their official - # holding pen, the 'command_options' dictionary. - opt_dict = self.get_option_dict(command) - for (name, value) in vars(opts).items(): - opt_dict[name] = ("command line", value) - - return args - - def finalize_options(self): - """Set final values for all the options on the Distribution - instance, analogous to the .finalize_options() method of Command - objects. - """ - if getattr(self, 'convert_2to3_doctests', None): - self.convert_2to3_doctests = [os.path.join(p) - for p in self.convert_2to3_doctests] - else: - self.convert_2to3_doctests = [] - - def _show_help(self, parser, global_options=1, display_options=1, - commands=[]): - """Show help for the setup script command line in the form of - several lists of command-line options. 'parser' should be a - FancyGetopt instance; do not expect it to be returned in the - same state, as its option table will be reset to make it - generate the correct help text. - - If 'global_options' is true, lists the global options: - --verbose, --dry-run, etc. If 'display_options' is true, lists - the "display-only" options: --name, --version, etc. Finally, - lists per-command help for every command name or command class - in 'commands'. - """ - # late import because of mutual dependence between these modules - from distutils2.core import gen_usage - from distutils2.command.cmd import Command - - if global_options: - if display_options: - options = self._get_toplevel_options() - else: - options = self.global_options - parser.set_option_table(options) - parser.print_help(self.common_usage + "\nGlobal options:") - print('') - - if display_options: - parser.set_option_table(self.display_options) - parser.print_help( - "Information display options (just display " + - "information, ignore any commands)") - print('') - - for command in self.commands: - if isinstance(command, type) and issubclass(command, Command): - cls = command - else: - cls = self.get_command_class(command) - if (hasattr(cls, 'help_options') and - isinstance(cls.help_options, list)): - parser.set_option_table(cls.user_options + - fix_help_options(cls.help_options)) - else: - parser.set_option_table(cls.user_options) - parser.print_help("Options for '%s' command:" % cls.__name__) - print('') - - print(gen_usage(self.script_name)) - - def handle_display_options(self, option_order): - """If there were any non-global "display-only" options - (--help-commands or the metadata display options) on the command - line, display the requested info and return true; else return - false. - """ - from distutils2.core import gen_usage - - # User just wants a list of commands -- we'll print it out and stop - # processing now (ie. if they ran "setup --help-commands foo bar", - # we ignore "foo bar"). - if self.help_commands: - self.print_commands() - print('') - print(gen_usage(self.script_name)) - return 1 - - # If user supplied any of the "display metadata" options, then - # display that metadata in the order in which the user supplied the - # metadata options. - any_display_options = 0 - is_display_option = {} - for option in self.display_options: - is_display_option[option[0]] = 1 - - for opt, val in option_order: - if val and is_display_option.get(opt): - opt = opt.replace('-', '_') - value = self.metadata[opt] - if opt in ['keywords', 'platform']: - print(','.join(value)) - elif opt in ('classifier', 'provides', 'requires', - 'obsoletes'): - print('\n'.join(value)) - else: - print(value) - any_display_options = 1 - - return any_display_options - - def print_command_list(self, commands, header, max_length): - """Print a subset of the list of all commands -- used by - 'print_commands()'. - """ - print(header + ":") - - for cmd in commands: - cls = self.cmdclass.get(cmd) - if not cls: - cls = self.get_command_class(cmd) - try: - description = cls.description - except AttributeError: - description = "(no description available)" - - print(" %-*s %s" % (max_length, cmd, description)) - - def _get_command_groups(self): - """Helper function to retrieve all the command class names divided - into standard commands (listed in distutils2.command.__all__) - and extra commands (given in self.cmdclass and not standard - commands). - """ - from distutils2.command import __all__ as std_commands - extra_commands = [cmd for cmd in self.cmdclass - if cmd not in std_commands] - return std_commands, extra_commands - - def print_commands(self): - """Print out a help message listing all available commands with a - description of each. The list is divided into standard commands - (listed in distutils2.command.__all__) and extra commands - (given in self.cmdclass and not standard commands). The - descriptions come from the command class attribute - 'description'. - """ - std_commands, extra_commands = self._get_command_groups() - max_length = 0 - for cmd in (std_commands + extra_commands): - if len(cmd) > max_length: - max_length = len(cmd) - - self.print_command_list(std_commands, - "Standard commands", - max_length) - if extra_commands: - print - self.print_command_list(extra_commands, - "Extra commands", - max_length) - - def get_command_list(self): - """Get a list of (command, description) tuples. - - The list is divided into standard commands (listed in - distutils2.command.__all__) and extra commands (given in - self.cmdclass and not standard commands). The descriptions come - from the command class attribute 'description'. - """ - # Currently this is only used on Mac OS, for the Mac-only GUI - # Distutils interface (by Jack Jansen) - - rv = [] - for cls in self.get_command_classes(): - try: - description = cls.description - except AttributeError: - description = "(no description available)" - rv.append((cmd, description)) - return rv - - # -- Command class/object methods ---------------------------------- - - def get_command_packages(self): - """Return a list of packages from which commands are loaded.""" - pkgs = self.command_packages - if not isinstance(pkgs, list): - if pkgs is None: - pkgs = '' - pkgs = [pkg.strip() for pkg in pkgs.split(',') if pkg != ''] - if "distutils2.command" not in pkgs: - pkgs.insert(0, "distutils2.command") - self.command_packages = pkgs - return pkgs - - def get_command_names(self): - """Return a list of all command names.""" - return [getattr(cls, 'command_name', cls.__name__) - for cls in self.get_command_classes()] - - def get_command_classes(self): - """Return a list of all command classes.""" - std_commands, extra_commands = self._get_command_groups() - classes = [] - for cmd in (std_commands + extra_commands): - try: - cls = self.cmdclass[cmd] - except KeyError: - cls = self.get_command_class(cmd) - classes.append(cls) - return classes - - def get_command_class(self, command): - """Return the class that implements the Distutils command named by - 'command'. First we check the 'cmdclass' dictionary; if the - command is mentioned there, we fetch the class object from the - dictionary and return it. Otherwise we load the command module - ("distutils.command." + command) and fetch the command class from - the module. The loaded class is also stored in 'cmdclass' - to speed future calls to 'get_command_class()'. - - Raises DistutilsModuleError if the expected module could not be - found, or if that module does not define the expected class. - """ - cls = self.cmdclass.get(command) - if cls: - return cls - - for pkgname in self.get_command_packages(): - module_name = "%s.%s" % (pkgname, command) - class_name = command - - try: - __import__(module_name) - module = sys.modules[module_name] - except ImportError: - continue - - try: - cls = getattr(module, class_name) - except AttributeError: - raise DistutilsModuleError( - "invalid command '%s' (no class '%s' in module '%s')" % - (command, class_name, module_name)) - - self.cmdclass[command] = cls - return cls - - raise DistutilsModuleError("invalid command '%s'" % command) - - def get_command_obj(self, command, create=1): - """Return the command object for 'command'. Normally this object - is cached on a previous call to 'get_command_obj()'; if no command - object for 'command' is in the cache, then we either create and - return it (if 'create' is true) or return None. - """ - cmd_obj = self.command_obj.get(command) - if not cmd_obj and create: - log.debug("Distribution.get_command_obj(): " \ - "creating '%s' command object" % command) - - cls = self.get_command_class(command) - cmd_obj = self.command_obj[command] = cls(self) - self.have_run[command] = 0 - - # Set any options that were supplied in config files - # or on the command line. (NB. support for error - # reporting is lame here: any errors aren't reported - # until 'finalize_options()' is called, which means - # we won't report the source of the error.) - options = self.command_options.get(command) - if options: - self._set_command_options(cmd_obj, options) - - return cmd_obj - - def _set_command_options(self, command_obj, option_dict=None): - """Set the options for 'command_obj' from 'option_dict'. Basically - this means copying elements of a dictionary ('option_dict') to - attributes of an instance ('command'). - - 'command_obj' must be a Command instance. If 'option_dict' is not - supplied, uses the standard option dictionary for this command - (from 'self.command_options'). - """ - command_name = command_obj.get_command_name() - if option_dict is None: - option_dict = self.get_option_dict(command_name) - - log.debug(" setting options for '%s' command:" % command_name) - - for (option, (source, value)) in option_dict.items(): - log.debug(" %s = %s (from %s)" % (option, value, - source)) - try: - bool_opts = [x.replace('-', '_') - for x in command_obj.boolean_options] - except AttributeError: - bool_opts = [] - try: - neg_opt = command_obj.negative_opt - except AttributeError: - neg_opt = {} - - try: - is_string = isinstance(value, str) - if option in neg_opt and is_string: - setattr(command_obj, neg_opt[option], not strtobool(value)) - elif option in bool_opts and is_string: - setattr(command_obj, option, strtobool(value)) - elif hasattr(command_obj, option): - setattr(command_obj, option, value) - else: - raise DistutilsOptionError( - "error in %s: command '%s' has no such option '%s'" % - (source, command_name, option)) - except ValueError, msg: - raise DistutilsOptionError(msg) - - def get_reinitialized_command(self, command, reinit_subcommands=0): - """Reinitializes a command to the state it was in when first - returned by 'get_command_obj()': ie., initialized but not yet - finalized. This provides the opportunity to sneak option - values in programmatically, overriding or supplementing - user-supplied values from the config files and command line. - You'll have to re-finalize the command object (by calling - 'finalize_options()' or 'ensure_finalized()') before using it for - real. - - 'command' should be a command name (string) or command object. If - 'reinit_subcommands' is true, also reinitializes the command's - sub-commands, as declared by the 'sub_commands' class attribute (if - it has one). See the "install" command for an example. Only - reinitializes the sub-commands that actually matter, ie. those - whose test predicates return true. - - Returns the reinitialized command object. - """ - from distutils2.command.cmd import Command - if not isinstance(command, Command): - command_name = command - command = self.get_command_obj(command_name) - else: - command_name = command.get_command_name() - - if not command.finalized: - return command - command.initialize_options() - command.finalized = 0 - self.have_run[command_name] = 0 - self._set_command_options(command) - - if reinit_subcommands: - for sub in command.get_sub_commands(): - self.get_reinitialized_command(sub, reinit_subcommands) - - return command - - # -- Methods that operate on the Distribution ---------------------- - - def announce(self, msg, level=log.INFO): - log.log(level, msg) - - def run_commands(self): - """Run each command that was seen on the setup script command line. - Uses the list of commands found and cache of command objects - created by 'get_command_obj()'. - """ - for cmd in self.commands: - self.run_command(cmd) - - # -- Methods that operate on its Commands -------------------------- - - def run_command(self, command): - """Do whatever it takes to run a command (including nothing at all, - if the command has already been run). Specifically: if we have - already created and run the command named by 'command', return - silently without doing anything. If the command named by 'command' - doesn't even have a command object yet, create one. Then invoke - 'run()' on that command object (or an existing one). - """ - # Already been here, done that? then return silently. - if self.have_run.get(command): - return - - cmd_obj = self.get_command_obj(command) - cmd_obj.ensure_finalized() - self.run_command_hooks(cmd_obj, 'pre_hook') - log.info("running %s", command) - cmd_obj.run() - self.run_command_hooks(cmd_obj, 'post_hook') - self.have_run[command] = 1 - - def run_command_hooks(self, cmd_obj, hook_kind): - """Run hooks registered for that command and phase. - - *cmd_obj* is a finalized command object; *hook_kind* is either - 'pre_hook' or 'post_hook'. - """ - if hook_kind not in ('pre_hook', 'post_hook'): - raise ValueError('invalid hook kind: %r' % hook_kind) - - hooks = getattr(cmd_obj, hook_kind) - - if hooks is None: - return - - for hook in hooks.itervalues(): - if isinstance(hook, basestring): - try: - hook_obj = resolve_name(hook) - except ImportError, e: - raise DistutilsModuleError(e) - else: - hook_obj = hook - - if not hasattr(hook_obj, '__call__'): - raise DistutilsOptionError('hook %r is not callable' % hook) - - log.info('running %s %s for command %s', - hook_kind, hook, cmd_obj.get_command_name()) - hook_obj(cmd_obj) - - # -- Distribution query methods ------------------------------------ - def has_pure_modules(self): - return len(self.packages or self.py_modules or []) > 0 - - def has_ext_modules(self): - return self.ext_modules and len(self.ext_modules) > 0 - - def has_c_libraries(self): - return self.libraries and len(self.libraries) > 0 - - def has_modules(self): - return self.has_pure_modules() or self.has_ext_modules() - - def has_headers(self): - return self.headers and len(self.headers) > 0 - - def has_scripts(self): - return self.scripts and len(self.scripts) > 0 - - def has_data_files(self): - return self.data_files and len(self.data_files) > 0 - - def is_pure(self): - return (self.has_pure_modules() and - not self.has_ext_modules() and - not self.has_c_libraries()) - - -# XXX keep for compat or remove? - -def fix_help_options(options): - """Convert a 4-tuple 'help_options' list as found in various command - classes to the 3-tuple form required by FancyGetopt. - """ - new_options = [] - for help_tuple in options: - new_options.append(help_tuple[0:3]) - return new_options diff --git a/src/distutils2/errors.py b/src/distutils2/errors.py deleted file mode 100644 index 43469ce..0000000 --- a/src/distutils2/errors.py +++ /dev/null @@ -1,134 +0,0 @@ -"""distutils.errors - -Provides exceptions used by the Distutils modules. Note that Distutils -modules may raise standard exceptions; in particular, SystemExit is -usually raised for errors that are obviously the end-user's fault -(eg. bad command-line arguments). - -This module is safe to use in "from ... import *" mode; it only exports -symbols whose names start with "Distutils" and end with "Error".""" - -__revision__ = "$Id: errors.py 75901 2009-10-28 06:45:18Z tarek.ziade $" - - -class DistutilsError(Exception): - """The root of all Distutils evil.""" - - -class DistutilsModuleError(DistutilsError): - """Unable to load an expected module, or to find an expected class - within some module (in particular, command modules and classes).""" - - -class DistutilsClassError(DistutilsError): - """Some command class (or possibly distribution class, if anyone - feels a need to subclass Distribution) is found not to be holding - up its end of the bargain, ie. implementing some part of the - "command "interface.""" - - -class DistutilsGetoptError(DistutilsError): - """The option table provided to 'fancy_getopt()' is bogus.""" - - -class DistutilsArgError(DistutilsError): - """Raised by fancy_getopt in response to getopt.error -- ie. an - error in the command line usage.""" - - -class DistutilsFileError(DistutilsError): - """Any problems in the filesystem: expected file not found, etc. - Typically this is for problems that we detect before IOError or - OSError could be raised.""" - - -class DistutilsOptionError(DistutilsError): - """Syntactic/semantic errors in command options, such as use of - mutually conflicting options, or inconsistent options, - badly-spelled values, etc. No distinction is made between option - values originating in the setup script, the command line, config - files, or what-have-you -- but if we *know* something originated in - the setup script, we'll raise DistutilsSetupError instead.""" - - -class DistutilsSetupError(DistutilsError): - """For errors that can be definitely blamed on the setup script, - such as invalid keyword arguments to 'setup()'.""" - - -class DistutilsPlatformError(DistutilsError): - """We don't know how to do something on the current platform (but - we do know how to do it on some platform) -- eg. trying to compile - C files on a platform not supported by a CCompiler subclass.""" - - -class DistutilsExecError(DistutilsError): - """Any problems executing an external program (such as the C - compiler, when compiling C files).""" - - -class DistutilsInternalError(DistutilsError): - """Internal inconsistencies or impossibilities (obviously, this - should never be seen if the code is working!).""" - - -class DistutilsTemplateError(DistutilsError): - """Syntax error in a file list template.""" - - -class DistutilsByteCompileError(DistutilsError): - """Byte compile error.""" - - -class DistutilsIndexError(DistutilsError): - """Any problem occuring during using the indexes.""" - - -# Exception classes used by the CCompiler implementation classes -class CCompilerError(Exception): - """Some compile/link operation failed.""" - - -class PreprocessError(CCompilerError): - """Failure to preprocess one or more C/C++ files.""" - - -class CompileError(CCompilerError): - """Failure to compile one or more C/C++ source files.""" - - -class LibError(CCompilerError): - """Failure to create a static library from one or more C/C++ object - files.""" - - -class LinkError(CCompilerError): - """Failure to link one or more C/C++ object files into an executable - or shared library file.""" - - -class UnknownFileError(CCompilerError): - """Attempt to process an unknown file type.""" - - -class MetadataConflictError(DistutilsError): - """Attempt to read or write metadata fields that are conflictual.""" - - -class MetadataUnrecognizedVersionError(DistutilsError): - """Unknown metadata version number.""" - - -class IrrationalVersionError(Exception): - """This is an irrational version.""" - pass - - -class HugeMajorVersionNumError(IrrationalVersionError): - """An irrational version because the major version number is huge - (often because a year or date was used). - - See `error_on_huge_major_num` option in `NormalizedVersion` for details. - This guard can be disabled by setting that option False. - """ - pass diff --git a/src/distutils2/extension.py b/src/distutils2/extension.py deleted file mode 100644 index f38bf60..0000000 --- a/src/distutils2/extension.py +++ /dev/null @@ -1,137 +0,0 @@ -"""distutils.extension - -Provides the Extension class, used to describe C/C++ extension -modules in setup scripts.""" - -__revision__ = "$Id: extension.py 77704 2010-01-23 09:23:15Z tarek.ziade $" - -import warnings - -# This class is really only used by the "build_ext" command, so it might -# make sense to put it in distutils.command.build_ext. However, that -# module is already big enough, and I want to make this class a bit more -# complex to simplify some common cases ("foo" module in "foo.c") and do -# better error-checking ("foo.c" actually exists). -# -# Also, putting this in build_ext.py means every setup script would have to -# import that large-ish module (indirectly, through distutils.core) in -# order to do anything. - - -class Extension(object): - """Just a collection of attributes that describes an extension - module and everything needed to build it (hopefully in a portable - way, but there are hooks that let you be as unportable as you need). - - Instance attributes: - name : string - the full name of the extension, including any packages -- ie. - *not* a filename or pathname, but Python dotted name - sources : [string] - list of source filenames, relative to the distribution root - (where the setup script lives), in Unix form (slash-separated) - for portability. Source files may be C, C++, SWIG (.i), - platform-specific resource files, or whatever else is recognized - by the "build_ext" command as source for a Python extension. - include_dirs : [string] - list of directories to search for C/C++ header files (in Unix - form for portability) - define_macros : [(name : string, value : string|None)] - list of macros to define; each macro is defined using a 2-tuple, - where 'value' is either the string to define it to or None to - define it without a particular value (equivalent of "#define - FOO" in source or -DFOO on Unix C compiler command line) - undef_macros : [string] - list of macros to undefine explicitly - library_dirs : [string] - list of directories to search for C/C++ libraries at link time - libraries : [string] - list of library names (not filenames or paths) to link against - runtime_library_dirs : [string] - list of directories to search for C/C++ libraries at run time - (for shared extensions, this is when the extension is loaded) - extra_objects : [string] - list of extra files to link with (eg. object files not implied - by 'sources', static library that must be explicitly specified, - binary resource files, etc.) - extra_compile_args : [string] - any extra platform- and compiler-specific information to use - when compiling the source files in 'sources'. For platforms and - compilers where "command line" makes sense, this is typically a - list of command-line arguments, but for other platforms it could - be anything. - extra_link_args : [string] - any extra platform- and compiler-specific information to use - when linking object files together to create the extension (or - to create a new static Python interpreter). Similar - interpretation as for 'extra_compile_args'. - export_symbols : [string] - list of symbols to be exported from a shared extension. Not - used on all platforms, and not generally necessary for Python - extensions, which typically export exactly one symbol: "init" + - extension_name. - swig_opts : [string] - any extra options to pass to SWIG if a source file has the .i - extension. - depends : [string] - list of files that the extension depends on - language : string - extension language (i.e. "c", "c++", "objc"). Will be detected - from the source extensions if not provided. - optional : boolean - specifies that a build failure in the extension should not abort the - build process, but simply not install the failing extension. - """ - - # When adding arguments to this constructor, be sure to update - # setup_keywords in core.py. - def __init__(self, name, sources, - include_dirs=None, - define_macros=None, - undef_macros=None, - library_dirs=None, - libraries=None, - runtime_library_dirs=None, - extra_objects=None, - extra_compile_args=None, - extra_link_args=None, - export_symbols=None, - swig_opts=None, - depends=None, - language=None, - optional=None, - **kw # To catch unknown keywords - ): - if not isinstance(name, str): - raise AssertionError("'name' must be a string") - - if not isinstance(sources, list): - raise AssertionError("'sources' must be a list of strings") - - for v in sources: - if not isinstance(v, str): - raise AssertionError("'sources' must be a list of strings") - - self.name = name - self.sources = sources - self.include_dirs = include_dirs or [] - self.define_macros = define_macros or [] - self.undef_macros = undef_macros or [] - self.library_dirs = library_dirs or [] - self.libraries = libraries or [] - self.runtime_library_dirs = runtime_library_dirs or [] - self.extra_objects = extra_objects or [] - self.extra_compile_args = extra_compile_args or [] - self.extra_link_args = extra_link_args or [] - self.export_symbols = export_symbols or [] - self.swig_opts = swig_opts or [] - self.depends = depends or [] - self.language = language - self.optional = optional - - # If there are unknown keyword options, warn about them - if len(kw) > 0: - options = [repr(option) for option in kw] - options = ', '.join(sorted(options)) - msg = "Unknown Extension options: %s" % options - warnings.warn(msg) diff --git a/src/distutils2/fancy_getopt.py b/src/distutils2/fancy_getopt.py deleted file mode 100644 index 304fb8a..0000000 --- a/src/distutils2/fancy_getopt.py +++ /dev/null @@ -1,467 +0,0 @@ -"""distutils.fancy_getopt - -Wrapper around the standard getopt module that provides the following -additional features: - * short and long options are tied together - * options have help strings, so fancy_getopt could potentially - create a complete usage summary - * options set attributes of a passed-in object -""" - -__revision__ = "$Id: fancy_getopt.py 76956 2009-12-21 01:22:46Z tarek.ziade $" - -import sys -import string -import re -import getopt -from distutils2.errors import DistutilsGetoptError, DistutilsArgError - -# Much like command_re in distutils.core, this is close to but not quite -# the same as a Python NAME -- except, in the spirit of most GNU -# utilities, we use '-' in place of '_'. (The spirit of LISP lives on!) -# The similarities to NAME are again not a coincidence... -longopt_pat = r'[a-zA-Z](?:[a-zA-Z0-9-]*)' -longopt_re = re.compile(r'^%s$' % longopt_pat) - -# For recognizing "negative alias" options, eg. "quiet=!verbose" -neg_alias_re = re.compile("^(%s)=!(%s)$" % (longopt_pat, longopt_pat)) - -class FancyGetopt(object): - """Wrapper around the standard 'getopt()' module that provides some - handy extra functionality: - * short and long options are tied together - * options have help strings, and help text can be assembled - from them - * options set attributes of a passed-in object - * boolean options can have "negative aliases" -- eg. if - --quiet is the "negative alias" of --verbose, then "--quiet" - on the command line sets 'verbose' to false - """ - - def __init__(self, option_table=None): - - # The option table is (currently) a list of tuples. The - # tuples may have 3 or four values: - # (long_option, short_option, help_string [, repeatable]) - # if an option takes an argument, its long_option should have '=' - # appended; short_option should just be a single character, no ':' - # in any case. If a long_option doesn't have a corresponding - # short_option, short_option should be None. All option tuples - # must have long options. - self.option_table = option_table - - # 'option_index' maps long option names to entries in the option - # table (ie. those 3-tuples). - self.option_index = {} - if self.option_table: - self._build_index() - - # 'alias' records (duh) alias options; {'foo': 'bar'} means - # --foo is an alias for --bar - self.alias = {} - - # 'negative_alias' keeps track of options that are the boolean - # opposite of some other option - self.negative_alias = {} - - # These keep track of the information in the option table. We - # don't actually populate these structures until we're ready to - # parse the command line, since the 'option_table' passed in here - # isn't necessarily the final word. - self.short_opts = [] - self.long_opts = [] - self.short2long = {} - self.attr_name = {} - self.takes_arg = {} - - # And 'option_order' is filled up in 'getopt()'; it records the - # original order of options (and their values) on the command line, - # but expands short options, converts aliases, etc. - self.option_order = [] - - # __init__ () - - - def _build_index (self): - self.option_index.clear() - for option in self.option_table: - self.option_index[option[0]] = option - - def set_option_table (self, option_table): - self.option_table = option_table - self._build_index() - - def add_option (self, long_option, short_option=None, help_string=None): - if long_option in self.option_index: - raise DistutilsGetoptError, \ - "option conflict: already an option '%s'" % long_option - else: - option = (long_option, short_option, help_string) - self.option_table.append(option) - self.option_index[long_option] = option - - - def has_option (self, long_option): - """Return true if the option table for this parser has an - option with long name 'long_option'.""" - return long_option in self.option_index - - def _check_alias_dict (self, aliases, what): - assert isinstance(aliases, dict) - for (alias, opt) in aliases.items(): - if alias not in self.option_index: - raise DistutilsGetoptError, \ - ("invalid %s '%s': " - "option '%s' not defined") % (what, alias, alias) - if opt not in self.option_index: - raise DistutilsGetoptError, \ - ("invalid %s '%s': " - "aliased option '%s' not defined") % (what, alias, opt) - - def set_aliases (self, alias): - """Set the aliases for this option parser.""" - self._check_alias_dict(alias, "alias") - self.alias = alias - - def set_negative_aliases (self, negative_alias): - """Set the negative aliases for this option parser. - 'negative_alias' should be a dictionary mapping option names to - option names, both the key and value must already be defined - in the option table.""" - self._check_alias_dict(negative_alias, "negative alias") - self.negative_alias = negative_alias - - - def _grok_option_table (self): - """Populate the various data structures that keep tabs on the - option table. Called by 'getopt()' before it can do anything - worthwhile. - """ - self.long_opts = [] - self.short_opts = [] - self.short2long.clear() - self.repeat = {} - - for option in self.option_table: - if len(option) == 3: - long, short, help = option - repeat = 0 - elif len(option) == 4: - long, short, help, repeat = option - else: - # the option table is part of the code, so simply - # assert that it is correct - raise ValueError, "invalid option tuple: %r" % (option,) - - # Type- and value-check the option names - if not isinstance(long, str) or len(long) < 2: - raise DistutilsGetoptError, \ - ("invalid long option '%s': " - "must be a string of length >= 2") % long - - if (not ((short is None) or - (isinstance(short, str) and len(short) == 1))): - raise DistutilsGetoptError, \ - ("invalid short option '%s': " - "must a single character or None") % short - - self.repeat[long] = repeat - self.long_opts.append(long) - - if long[-1] == '=': # option takes an argument? - if short: - short = short + ':' - long = long[0:-1] - self.takes_arg[long] = 1 - else: - - # Is option is a "negative alias" for some other option (eg. - # "quiet" == "!verbose")? - alias_to = self.negative_alias.get(long) - if alias_to is not None: - if self.takes_arg[alias_to]: - raise DistutilsGetoptError, \ - ("invalid negative alias '%s': " - "aliased option '%s' takes a value") % \ - (long, alias_to) - - self.long_opts[-1] = long # XXX redundant?! - self.takes_arg[long] = 0 - - else: - self.takes_arg[long] = 0 - - # If this is an alias option, make sure its "takes arg" flag is - # the same as the option it's aliased to. - alias_to = self.alias.get(long) - if alias_to is not None: - if self.takes_arg[long] != self.takes_arg[alias_to]: - raise DistutilsGetoptError, \ - ("invalid alias '%s': inconsistent with " - "aliased option '%s' (one of them takes a value, " - "the other doesn't") % (long, alias_to) - - - # Now enforce some bondage on the long option name, so we can - # later translate it to an attribute name on some object. Have - # to do this a bit late to make sure we've removed any trailing - # '='. - if not longopt_re.match(long): - raise DistutilsGetoptError, \ - ("invalid long option name '%s' " + - "(must be letters, numbers, hyphens only") % long - - self.attr_name[long] = long.replace('-', '_') - if short: - self.short_opts.append(short) - self.short2long[short[0]] = long - - # for option_table - - # _grok_option_table() - - - def getopt (self, args=None, object=None): - """Parse command-line options in args. Store as attributes on object. - - If 'args' is None or not supplied, uses 'sys.argv[1:]'. If - 'object' is None or not supplied, creates a new OptionDummy - object, stores option values there, and returns a tuple (args, - object). If 'object' is supplied, it is modified in place and - 'getopt()' just returns 'args'; in both cases, the returned - 'args' is a modified copy of the passed-in 'args' list, which - is left untouched. - """ - if args is None: - args = sys.argv[1:] - if object is None: - object = OptionDummy() - created_object = 1 - else: - created_object = 0 - - self._grok_option_table() - - short_opts = string.join(self.short_opts) - try: - opts, args = getopt.getopt(args, short_opts, self.long_opts) - except getopt.error, msg: - raise DistutilsArgError, msg - - for opt, val in opts: - if len(opt) == 2 and opt[0] == '-': # it's a short option - opt = self.short2long[opt[1]] - else: - assert len(opt) > 2 and opt[:2] == '--' - opt = opt[2:] - - alias = self.alias.get(opt) - if alias: - opt = alias - - if not self.takes_arg[opt]: # boolean option? - assert val == '', "boolean option can't have value" - alias = self.negative_alias.get(opt) - if alias: - opt = alias - val = 0 - else: - val = 1 - - attr = self.attr_name[opt] - # The only repeating option at the moment is 'verbose'. - # It has a negative option -q quiet, which should set verbose = 0. - if val and self.repeat.get(attr) is not None: - val = getattr(object, attr, 0) + 1 - setattr(object, attr, val) - self.option_order.append((opt, val)) - - # for opts - if created_object: - return args, object - else: - return args - - # getopt() - - - def get_option_order (self): - """Returns the list of (option, value) tuples processed by the - previous run of 'getopt()'. Raises RuntimeError if - 'getopt()' hasn't been called yet. - """ - if self.option_order is None: - raise RuntimeError, "'getopt()' hasn't been called yet" - else: - return self.option_order - - - def generate_help (self, header=None): - """Generate help text (a list of strings, one per suggested line of - output) from the option table for this FancyGetopt object. - """ - # Blithely assume the option table is good: probably wouldn't call - # 'generate_help()' unless you've already called 'getopt()'. - - # First pass: determine maximum length of long option names - max_opt = 0 - for option in self.option_table: - long = option[0] - short = option[1] - l = len(long) - if long[-1] == '=': - l = l - 1 - if short is not None: - l = l + 5 # " (-x)" where short == 'x' - if l > max_opt: - max_opt = l - - opt_width = max_opt + 2 + 2 + 2 # room for indent + dashes + gutter - - # Typical help block looks like this: - # --foo controls foonabulation - # Help block for longest option looks like this: - # --flimflam set the flim-flam level - # and with wrapped text: - # --flimflam set the flim-flam level (must be between - # 0 and 100, except on Tuesdays) - # Options with short names will have the short name shown (but - # it doesn't contribute to max_opt): - # --foo (-f) controls foonabulation - # If adding the short option would make the left column too wide, - # we push the explanation off to the next line - # --flimflam (-l) - # set the flim-flam level - # Important parameters: - # - 2 spaces before option block start lines - # - 2 dashes for each long option name - # - min. 2 spaces between option and explanation (gutter) - # - 5 characters (incl. space) for short option name - - # Now generate lines of help text. (If 80 columns were good enough - # for Jesus, then 78 columns are good enough for me!) - line_width = 78 - text_width = line_width - opt_width - big_indent = ' ' * opt_width - if header: - lines = [header] - else: - lines = ['Option summary:'] - - for option in self.option_table: - long, short, help = option[:3] - text = wrap_text(help, text_width) - if long[-1] == '=': - long = long[0:-1] - - # Case 1: no short option at all (makes life easy) - if short is None: - if text: - lines.append(" --%-*s %s" % (max_opt, long, text[0])) - else: - lines.append(" --%-*s " % (max_opt, long)) - - # Case 2: we have a short option, so we have to include it - # just after the long option - else: - opt_names = "%s (-%s)" % (long, short) - if text: - lines.append(" --%-*s %s" % - (max_opt, opt_names, text[0])) - else: - lines.append(" --%-*s" % opt_names) - - for l in text[1:]: - lines.append(big_indent + l) - - # for self.option_table - - return lines - - # generate_help () - - def print_help (self, header=None, file=None): - if file is None: - file = sys.stdout - for line in self.generate_help(header): - file.write(line + "\n") - -# class FancyGetopt - - -def fancy_getopt (options, negative_opt, object, args): - parser = FancyGetopt(options) - parser.set_negative_aliases(negative_opt) - return parser.getopt(args, object) - - -WS_TRANS = string.maketrans(string.whitespace, ' ' * len(string.whitespace)) - -def wrap_text (text, width): - """wrap_text(text : string, width : int) -> [string] - - Split 'text' into multiple lines of no more than 'width' characters - each, and return the list of strings that results. - """ - - if text is None: - return [] - if len(text) <= width: - return [text] - - text = string.expandtabs(text) - text = string.translate(text, WS_TRANS) - chunks = re.split(r'( +|-+)', text) - chunks = filter(None, chunks) # ' - ' results in empty strings - lines = [] - - while chunks: - - cur_line = [] # list of chunks (to-be-joined) - cur_len = 0 # length of current line - - while chunks: - l = len(chunks[0]) - if cur_len + l <= width: # can squeeze (at least) this chunk in - cur_line.append(chunks[0]) - del chunks[0] - cur_len = cur_len + l - else: # this line is full - # drop last chunk if all space - if cur_line and cur_line[-1][0] == ' ': - del cur_line[-1] - break - - if chunks: # any chunks left to process? - - # if the current line is still empty, then we had a single - # chunk that's too big too fit on a line -- so we break - # down and break it up at the line width - if cur_len == 0: - cur_line.append(chunks[0][0:width]) - chunks[0] = chunks[0][width:] - - # all-whitespace chunks at the end of a line can be discarded - # (and we know from the re.split above that if a chunk has - # *any* whitespace, it is *all* whitespace) - if chunks[0][0] == ' ': - del chunks[0] - - # and store this line in the list-of-all-lines -- as a single - # string, of course! - lines.append(string.join(cur_line, '')) - - # while chunks - - return lines - - -class OptionDummy(object): - """Dummy class just used as a place to hold command-line option - values as instance attributes.""" - - def __init__ (self, options=[]): - """Create a new OptionDummy instance. The attributes listed in - 'options' will be initialized to None.""" - for opt in options: - setattr(self, opt, None) diff --git a/src/distutils2/index/__init__.py b/src/distutils2/index/__init__.py deleted file mode 100644 index 312662f..0000000 --- a/src/distutils2/index/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Package containing ways to interact with Index APIs. - -""" - -__all__ = ['simple', - 'xmlrpc', - 'dist', - 'errors', - 'mirrors',] - -from dist import ReleaseInfo, ReleasesList, DistInfo diff --git a/src/distutils2/index/base.py b/src/distutils2/index/base.py deleted file mode 100644 index 04582a3..0000000 --- a/src/distutils2/index/base.py +++ /dev/null @@ -1,46 +0,0 @@ -from distutils2.index.dist import ReleasesList - - -class BaseClient(object): - """Base class containing common methods for the index crawlers/clients""" - - def __init__(self, prefer_final, prefer_source): - self._prefer_final = prefer_final - self._prefer_source = prefer_source - self._index = self - - def _get_prefer_final(self, prefer_final=None): - """Return the prefer_final internal parameter or the specified one if - provided""" - if prefer_final: - return prefer_final - else: - return self._prefer_final - - def _get_prefer_source(self, prefer_source=None): - """Return the prefer_source internal parameter or the specified one if - provided""" - if prefer_source: - return prefer_source - else: - return self._prefer_source - - def _get_project(self, project_name): - """Return an project instance, create it if necessary""" - return self._projects.setdefault(project_name.lower(), - ReleasesList(project_name, index=self._index)) - - def download_distribution(self, requirements, temp_path=None, - prefer_source=None, prefer_final=None): - """Download a distribution from the last release according to the - requirements. - - If temp_path is provided, download to this path, otherwise, create a - temporary location for the download and return it. - """ - prefer_final = self._get_prefer_final(prefer_final) - prefer_source = self._get_prefer_source(prefer_source) - release = self.get_release(requirements, prefer_final) - if release: - dist = release.get_distribution(prefer_source=prefer_source) - return dist.download(temp_path) diff --git a/src/distutils2/index/dist.py b/src/distutils2/index/dist.py deleted file mode 100644 index f5d0fd9..0000000 --- a/src/distutils2/index/dist.py +++ /dev/null @@ -1,544 +0,0 @@ -"""distutils2.index.dist - -Provides useful classes to represent the release and distributions retrieved -from indexes. - -A project can have several releases (=versions) and each release can have -several distributions (sdist, bdist). - -The release contains the metadata related informations (see PEP 384), and the -distributions contains download related informations. - -""" -import mimetypes -import re -import tarfile -import tempfile -import urllib -import urlparse -import zipfile - -try: - import hashlib -except ImportError: - from distutils2._backport import hashlib - -from distutils2.errors import IrrationalVersionError -from distutils2.index.errors import (HashDoesNotMatch, UnsupportedHashName, - CantParseArchiveName) -from distutils2.version import (suggest_normalized_version, NormalizedVersion, - get_version_predicate) -from distutils2.metadata import DistributionMetadata -from distutils2.util import untar_file, unzip_file, splitext - -__all__ = ['ReleaseInfo', 'DistInfo', 'ReleasesList', 'get_infos_from_url'] - -EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz .egg".split() -MD5_HASH = re.compile(r'^.*#md5=([a-f0-9]+)$') -DIST_TYPES = ['bdist', 'sdist'] - - -class IndexReference(object): - """Mixin used to store the index reference""" - def set_index(self, index=None): - self._index = index - - -class ReleaseInfo(IndexReference): - """Represent a release of a project (a project with a specific version). - The release contain the _metadata informations related to this specific - version, and is also a container for distribution related informations. - - See the DistInfo class for more information about distributions. - """ - - def __init__(self, name, version, metadata=None, hidden=False, - index=None, **kwargs): - """ - :param name: the name of the distribution - :param version: the version of the distribution - :param metadata: the metadata fields of the release. - :type metadata: dict - :param kwargs: optional arguments for a new distribution. - """ - self.set_index(index) - self.name = name - self._version = None - self.version = version - if metadata: - self.metadata = DistributionMetadata(mapping=metadata) - else: - self.metadata = None - self.dists = {} - self.hidden = hidden - - if 'dist_type' in kwargs: - dist_type = kwargs.pop('dist_type') - self.add_distribution(dist_type, **kwargs) - - def set_version(self, version): - try: - self._version = NormalizedVersion(version) - except IrrationalVersionError: - suggestion = suggest_normalized_version(version) - if suggestion: - self.version = suggestion - else: - raise IrrationalVersionError(version) - - def get_version(self): - return self._version - - version = property(get_version, set_version) - - def fetch_metadata(self): - """If the metadata is not set, use the indexes to get it""" - if not self.metadata: - self._index.get_metadata(self.name, '%s' % self.version) - return self.metadata - - @property - def is_final(self): - """proxy to version.is_final""" - return self.version.is_final - - def fetch_distributions(self): - if self.dists is None: - self._index.get_distributions(self.name, '%s' % self.version) - if self.dists is None: - self.dists = {} - return self.dists - - def add_distribution(self, dist_type='sdist', python_version=None, **params): - """Add distribution informations to this release. - If distribution information is already set for this distribution type, - add the given url paths to the distribution. This can be useful while - some of them fails to download. - - :param dist_type: the distribution type (eg. "sdist", "bdist", etc.) - :param params: the fields to be passed to the distribution object - (see the :class:DistInfo constructor). - """ - if dist_type not in DIST_TYPES: - raise ValueError(dist_type) - if dist_type in self.dists: - self.dists[dist_type].add_url(**params) - else: - self.dists[dist_type] = DistInfo(self, dist_type, - index=self._index, **params) - if python_version: - self.dists[dist_type].python_version = python_version - - def get_distribution(self, dist_type=None, prefer_source=True): - """Return a distribution. - - If dist_type is set, find first for this distribution type, and just - act as an alias of __get_item__. - - If prefer_source is True, search first for source distribution, and if - not return one existing distribution. - """ - if len(self.dists) == 0: - raise LookupError() - if dist_type: - return self[dist_type] - if prefer_source: - if "sdist" in self.dists: - dist = self["sdist"] - else: - dist = self.dists.values()[0] - return dist - - def download(self, temp_path=None, prefer_source=True): - """Download the distribution, using the requirements. - - If more than one distribution match the requirements, use the last - version. - Download the distribution, and put it in the temp_path. If no temp_path - is given, creates and return one. - - Returns the complete absolute path to the downloaded archive. - """ - return self.get_distribution(prefer_source=prefer_source)\ - .download(path=temp_path) - - def set_metadata(self, metadata): - if not self.metadata: - self.metadata = DistributionMetadata() - self.metadata.update(metadata) - - def __getitem__(self, item): - """distributions are available using release["sdist"]""" - return self.dists[item] - - def _check_is_comparable(self, other): - if not isinstance(other, ReleaseInfo): - raise TypeError("cannot compare %s and %s" - % (type(self).__name__, type(other).__name__)) - elif self.name != other.name: - raise TypeError("cannot compare %s and %s" - % (self.name, other.name)) - - def __repr__(self): - return "<%s %s>" % (self.name, self.version) - - def __eq__(self, other): - self._check_is_comparable(other) - return self.version == other.version - - def __lt__(self, other): - self._check_is_comparable(other) - return self.version < other.version - - def __ne__(self, other): - return not self.__eq__(other) - - def __gt__(self, other): - return not (self.__lt__(other) or self.__eq__(other)) - - def __le__(self, other): - return self.__eq__(other) or self.__lt__(other) - - def __ge__(self, other): - return self.__eq__(other) or self.__gt__(other) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - __hash__ = object.__hash__ - - -class DistInfo(IndexReference): - """Represents a distribution retrieved from an index (sdist, bdist, ...) - """ - - def __init__(self, release, dist_type=None, url=None, hashname=None, - hashval=None, is_external=True, python_version=None, - index=None): - """Create a new instance of DistInfo. - - :param release: a DistInfo class is relative to a release. - :param dist_type: the type of the dist (eg. source, bin-*, etc.) - :param url: URL where we found this distribution - :param hashname: the name of the hash we want to use. Refer to the - hashlib.new documentation for more information. - :param hashval: the hash value. - :param is_external: we need to know if the provided url comes from - an index browsing, or from an external resource. - - """ - self.set_index(index) - self.release = release - self.dist_type = dist_type - self.python_version = python_version - self._unpacked_dir = None - # set the downloaded path to None by default. The goal here - # is to not download distributions multiple times - self.downloaded_location = None - # We store urls in dict, because we need to have a bit more infos - # than the simple URL. It will be used later to find the good url to - # use. - # We have two _url* attributes: _url and urls. urls contains a list - # of dict for the different urls, and _url contains the choosen url, in - # order to dont make the selection process multiple times. - self.urls = [] - self._url = None - self.add_url(url, hashname, hashval, is_external) - - def add_url(self, url, hashname=None, hashval=None, is_external=True): - """Add a new url to the list of urls""" - if hashname is not None: - try: - hashlib.new(hashname) - except ValueError: - raise UnsupportedHashName(hashname) - if not url in [u['url'] for u in self.urls]: - self.urls.append({ - 'url': url, - 'hashname': hashname, - 'hashval': hashval, - 'is_external': is_external, - }) - # reset the url selection process - self._url = None - - @property - def url(self): - """Pick up the right url for the list of urls in self.urls""" - # We return internal urls over externals. - # If there is more than one internal or external, return the first - # one. - if self._url is None: - if len(self.urls) > 1: - internals_urls = [u for u in self.urls \ - if u['is_external'] == False] - if len(internals_urls) >= 1: - self._url = internals_urls[0] - if self._url is None: - self._url = self.urls[0] - return self._url - - @property - def is_source(self): - """return if the distribution is a source one or not""" - return self.dist_type == 'sdist' - - def download(self, path=None): - """Download the distribution to a path, and return it. - - If the path is given in path, use this, otherwise, generates a new one - Return the download location. - """ - if path is None: - path = tempfile.mkdtemp() - - # if we do not have downloaded it yet, do it. - if self.downloaded_location is None: - url = self.url['url'] - archive_name = urlparse.urlparse(url)[2].split('/')[-1] - filename, headers = urllib.urlretrieve(url, - path + "/" + archive_name) - self.downloaded_location = filename - self._check_md5(filename) - return self.downloaded_location - - def unpack(self, path=None): - """Unpack the distribution to the given path. - - If not destination is given, creates a temporary location. - - Returns the location of the extracted files (root). - """ - if not self._unpacked_dir: - if path is None: - path = tempfile.mkdtemp() - - filename = self.download() - content_type = mimetypes.guess_type(filename)[0] - - if (content_type == 'application/zip' - or filename.endswith('.zip') - or filename.endswith('.pybundle') - or zipfile.is_zipfile(filename)): - unzip_file(filename, path, flatten=not filename.endswith('.pybundle')) - elif (content_type == 'application/x-gzip' - or tarfile.is_tarfile(filename) - or splitext(filename)[1].lower() in ('.tar', '.tar.gz', '.tar.bz2', '.tgz', '.tbz')): - untar_file(filename, path) - self._unpacked_dir = path - return self._unpacked_dir - - def _check_md5(self, filename): - """Check that the md5 checksum of the given file matches the one in - url param""" - hashname = self.url['hashname'] - expected_hashval = self.url['hashval'] - if not None in (expected_hashval, hashname): - f = open(filename) - hashval = hashlib.new(hashname) - hashval.update(f.read()) - if hashval.hexdigest() != expected_hashval: - raise HashDoesNotMatch("got %s instead of %s" - % (hashval.hexdigest(), expected_hashval)) - - def __repr__(self): - return "<%s %s %s>" % ( - self.release.name, self.release.version, self.dist_type or "") - - -class ReleasesList(IndexReference): - """A container of Release. - - Provides useful methods and facilities to sort and filter releases. - """ - def __init__(self, name, releases=None, contains_hidden=False, index=None): - self.set_index(index) - self.releases = [] - self.name = name - self.contains_hidden = contains_hidden - if releases: - self.add_releases(releases) - - def fetch_releases(self): - self._index.get_releases(self.name) - return self.releases - - def filter(self, predicate): - """Filter and return a subset of releases matching the given predicate. - """ - return ReleasesList(self.name, [release for release in self.releases - if predicate.match(release.version)], - index=self._index) - - def get_last(self, requirements, prefer_final=None): - """Return the "last" release, that satisfy the given predicates. - - "last" is defined by the version number of the releases, you also could - set prefer_final parameter to True or False to change the order results - """ - predicate = get_version_predicate(requirements) - releases = self.filter(predicate) - releases.sort_releases(prefer_final, reverse=True) - return releases[0] - - def add_releases(self, releases): - """Add releases in the release list. - - :param: releases is a list of ReleaseInfo objects. - """ - for r in releases: - self.add_release(release=r) - - def add_release(self, version=None, dist_type='sdist', release=None, - **dist_args): - """Add a release to the list. - - The release can be passed in the `release` parameter, and in this case, - it will be crawled to extract the useful informations if necessary, or - the release informations can be directly passed in the `version` and - `dist_type` arguments. - - Other keywords arguments can be provided, and will be forwarded to the - distribution creation (eg. the arguments of the DistInfo constructor). - """ - if release: - if release.name.lower() != self.name.lower(): - raise ValueError("%s is not the same project than %s" % - (release.name, self.name)) - version = '%s' % release.version - - if not version in self.get_versions(): - # append only if not already exists - self.releases.append(release) - for dist in release.dists.values(): - for url in dist.urls: - self.add_release(version, dist.dist_type, **url) - else: - matches = [r for r in self.releases if '%s' % r.version == version - and r.name == self.name] - if not matches: - release = ReleaseInfo(self.name, version, index=self._index) - self.releases.append(release) - else: - release = matches[0] - - release.add_distribution(dist_type=dist_type, **dist_args) - - def sort_releases(self, prefer_final=False, reverse=True, *args, **kwargs): - """Sort the results with the given properties. - - The `prefer_final` argument can be used to specify if final - distributions (eg. not dev, bet or alpha) would be prefered or not. - - Results can be inverted by using `reverse`. - - Any other parameter provided will be forwarded to the sorted call. You - cannot redefine the key argument of "sorted" here, as it is used - internally to sort the releases. - """ - - sort_by = [] - if prefer_final: - sort_by.append("is_final") - sort_by.append("version") - - self.releases.sort( - key=lambda i: [getattr(i, arg) for arg in sort_by], - reverse=reverse, *args, **kwargs) - - def get_release(self, version): - """Return a release from it's version. - """ - matches = [r for r in self.releases if "%s" % r.version == version] - if len(matches) != 1: - raise KeyError(version) - return matches[0] - - def get_versions(self): - """Return a list of releases versions contained""" - return ["%s" % r.version for r in self.releases] - - def __getitem__(self, key): - return self.releases[key] - - def __len__(self): - return len(self.releases) - - def __repr__(self): - string = 'Project "%s"' % self.name - if self.get_versions(): - string += ' versions: %s' % ', '.join(self.get_versions()) - return '<%s>' % string - - -def get_infos_from_url(url, probable_dist_name=None, is_external=True): - """Get useful informations from an URL. - - Return a dict of (name, version, url, hashtype, hash, is_external) - - :param url: complete url of the distribution - :param probable_dist_name: A probable name of the project. - :param is_external: Tell if the url commes from an index or from - an external URL. - """ - # if the url contains a md5 hash, get it. - md5_hash = None - match = MD5_HASH.match(url) - if match is not None: - md5_hash = match.group(1) - # remove the hash - url = url.replace("#md5=%s" % md5_hash, "") - - # parse the archive name to find dist name and version - archive_name = urlparse.urlparse(url)[2].split('/')[-1] - extension_matched = False - # remove the extension from the name - for ext in EXTENSIONS: - if archive_name.endswith(ext): - archive_name = archive_name[:-len(ext)] - extension_matched = True - - name, version = split_archive_name(archive_name) - if extension_matched is True: - return {'name': name, - 'version': version, - 'url': url, - 'hashname': "md5", - 'hashval': md5_hash, - 'is_external': is_external, - 'dist_type': 'sdist'} - - -def split_archive_name(archive_name, probable_name=None): - """Split an archive name into two parts: name and version. - - Return the tuple (name, version) - """ - # Try to determine wich part is the name and wich is the version using the - # "-" separator. Take the larger part to be the version number then reduce - # if this not works. - def eager_split(str, maxsplit=2): - # split using the "-" separator - splits = str.rsplit("-", maxsplit) - name = splits[0] - version = "-".join(splits[1:]) - if version.startswith("-"): - version = version[1:] - if suggest_normalized_version(version) is None and maxsplit >= 0: - # we dont get a good version number: recurse ! - return eager_split(str, maxsplit - 1) - else: - return (name, version) - if probable_name is not None: - probable_name = probable_name.lower() - name = None - if probable_name is not None and probable_name in archive_name: - # we get the name from probable_name, if given. - name = probable_name - version = archive_name.lstrip(name) - else: - name, version = eager_split(archive_name) - - version = suggest_normalized_version(version) - if version is not None and name != "": - return (name.lower(), version) - else: - raise CantParseArchiveName(archive_name) diff --git a/src/distutils2/index/errors.py b/src/distutils2/index/errors.py deleted file mode 100644 index e6e5870..0000000 --- a/src/distutils2/index/errors.py +++ /dev/null @@ -1,41 +0,0 @@ -"""distutils2.pypi.errors - -All errors and exceptions raised by PyPiIndex classes. -""" -from distutils2.errors import DistutilsIndexError - - -class ProjectNotFound(DistutilsIndexError): - """Project has not been found""" - - -class DistributionNotFound(DistutilsIndexError): - """The release has not been found""" - - -class ReleaseNotFound(DistutilsIndexError): - """The release has not been found""" - - -class CantParseArchiveName(DistutilsIndexError): - """An archive name can't be parsed to find distribution name and version""" - - -class DownloadError(DistutilsIndexError): - """An error has occurs while downloading""" - - -class HashDoesNotMatch(DownloadError): - """Compared hashes does not match""" - - -class UnsupportedHashName(DistutilsIndexError): - """A unsupported hashname has been used""" - - -class UnableToDownload(DistutilsIndexError): - """All mirrors have been tried, without success""" - - -class InvalidSearchField(DistutilsIndexError): - """An invalid search field has been used""" diff --git a/src/distutils2/index/mirrors.py b/src/distutils2/index/mirrors.py deleted file mode 100644 index 49d5dd1..0000000 --- a/src/distutils2/index/mirrors.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Utilities related to the mirror infrastructure defined in PEP 381. -See http://www.python.org/dev/peps/pep-0381/ -""" - -from string import ascii_lowercase -import socket - -DEFAULT_MIRROR_URL = "last.pypi.python.org" - -def get_mirrors(hostname=None): - """Return the list of mirrors from the last record found on the DNS - entry:: - - >>> from distutils2.index.mirrors import get_mirrors - >>> get_mirrors() - ['a.pypi.python.org', 'b.pypi.python.org', 'c.pypi.python.org', - 'd.pypi.python.org'] - - """ - if hostname is None: - hostname = DEFAULT_MIRROR_URL - - # return the last mirror registered on PyPI. - try: - hostname = socket.gethostbyname_ex(hostname)[0] - except socket.gaierror: - return [] - end_letter = hostname.split(".", 1) - - # determine the list from the last one. - return ["%s.%s" % (s, end_letter[1]) for s in string_range(end_letter[0])] - -def string_range(last): - """Compute the range of string between "a" and last. - - This works for simple "a to z" lists, but also for "a to zz" lists. - """ - for k in range(len(last)): - for x in product(ascii_lowercase, repeat=k+1): - result = ''.join(x) - yield result - if result == last: - return - -def product(*args, **kwds): - pools = map(tuple, args) * kwds.get('repeat', 1) - result = [[]] - for pool in pools: - result = [x+[y] for x in result for y in pool] - for prod in result: - yield tuple(prod) - diff --git a/src/distutils2/index/simple.py b/src/distutils2/index/simple.py deleted file mode 100644 index 75fb851..0000000 --- a/src/distutils2/index/simple.py +++ /dev/null @@ -1,434 +0,0 @@ -"""index.simple - -Contains the class "SimpleIndexCrawler", a simple spider to find and retrieve -distributions on the Python Package Index, using it's "simple" API, -avalaible at http://pypi.python.org/simple/ -""" -from fnmatch import translate -import httplib -import re -import socket -import sys -import urllib2 -import urlparse -import logging -import os - -from distutils2.index.base import BaseClient -from distutils2.index.dist import (ReleasesList, EXTENSIONS, - get_infos_from_url, MD5_HASH) -from distutils2.index.errors import (DistutilsIndexError, DownloadError, - UnableToDownload, CantParseArchiveName, - ReleaseNotFound, ProjectNotFound) -from distutils2.index.mirrors import get_mirrors -from distutils2.metadata import DistributionMetadata -from distutils2.version import get_version_predicate -from distutils2 import __version__ as __distutils2_version__ - -__all__ = ['Crawler', 'DEFAULT_SIMPLE_INDEX_URL'] - -# -- Constants ----------------------------------------------- -DEFAULT_SIMPLE_INDEX_URL = "http://a.pypi.python.org/simple/" -DEFAULT_HOSTS = ("*",) -SOCKET_TIMEOUT = 15 -USER_AGENT = "Python-urllib/%s distutils2/%s" % ( - sys.version[:3], __distutils2_version__) - -# -- Regexps ------------------------------------------------- -EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.]+)$') -HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I) -URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):', re.I).match - -# This pattern matches a character entity reference (a decimal numeric -# references, a hexadecimal numeric reference, or a named reference). -ENTITY_SUB = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub -REL = re.compile("""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I) - - -def socket_timeout(timeout=SOCKET_TIMEOUT): - """Decorator to add a socket timeout when requesting pages on PyPI. - """ - def _socket_timeout(func): - def _socket_timeout(self, *args, **kwargs): - old_timeout = socket.getdefaulttimeout() - if hasattr(self, "_timeout"): - timeout = self._timeout - socket.setdefaulttimeout(timeout) - try: - return func(self, *args, **kwargs) - finally: - socket.setdefaulttimeout(old_timeout) - return _socket_timeout - return _socket_timeout - - -def with_mirror_support(): - """Decorator that makes the mirroring support easier""" - def wrapper(func): - def wrapped(self, *args, **kwargs): - try: - return func(self, *args, **kwargs) - except DownloadError: - # if an error occurs, try with the next index_url - if self._mirrors_tries >= self._mirrors_max_tries: - try: - self._switch_to_next_mirror() - except KeyError: - raise UnableToDownload("Tried all mirrors") - else: - self._mirrors_tries += 1 - self._projects.clear() - return wrapped(self, *args, **kwargs) - return wrapped - return wrapper - - -class Crawler(BaseClient): - """Provides useful tools to request the Python Package Index simple API. - - You can specify both mirrors and mirrors_url, but mirrors_url will only be - used if mirrors is set to None. - - :param index_url: the url of the simple index to search on. - :param prefer_final: if the version is not mentioned, and the last - version is not a "final" one (alpha, beta, etc.), - pick up the last final version. - :param prefer_source: if the distribution type is not mentioned, pick up - the source one if available. - :param follow_externals: tell if following external links is needed or - not. Default is False. - :param hosts: a list of hosts allowed to be processed while using - follow_externals=True. Default behavior is to follow all - hosts. - :param follow_externals: tell if following external links is needed or - not. Default is False. - :param mirrors_url: the url to look on for DNS records giving mirror - adresses. - :param mirrors: a list of mirrors (see PEP 381). - :param timeout: time in seconds to consider a url has timeouted. - :param mirrors_max_tries": number of times to try requesting informations - on mirrors before switching. - """ - - def __init__(self, index_url=DEFAULT_SIMPLE_INDEX_URL, prefer_final=False, - prefer_source=True, hosts=DEFAULT_HOSTS, - follow_externals=False, mirrors_url=None, mirrors=None, - timeout=SOCKET_TIMEOUT, mirrors_max_tries=0): - super(Crawler, self).__init__(prefer_final, prefer_source) - self.follow_externals = follow_externals - - # mirroring attributes. - if not index_url.endswith("/"): - index_url += "/" - # if no mirrors are defined, use the method described in PEP 381. - if mirrors is None: - mirrors = get_mirrors(mirrors_url) - self._mirrors = set(mirrors) - self._mirrors_used = set() - self.index_url = index_url - self._mirrors_max_tries = mirrors_max_tries - self._mirrors_tries = 0 - self._timeout = timeout - - # create a regexp to match all given hosts - self._allowed_hosts = re.compile('|'.join(map(translate, hosts))).match - - # we keep an index of pages we have processed, in order to avoid - # scanning them multple time (eg. if there is multiple pages pointing - # on one) - self._processed_urls = [] - self._projects = {} - - @with_mirror_support() - def search_projects(self, name=None, **kwargs): - """Search the index for projects containing the given name. - - Return a list of names. - """ - index = self._open_url(self.index_url) - projectname = re.compile("""<a[^>]*>(.?[^<]*%s.?[^<]*)</a>""" % name, - flags=re.I) - matching_projects = [] - for match in projectname.finditer(index.read()): - project_name = match.group(1) - matching_projects.append(self._get_project(project_name)) - return matching_projects - - def get_releases(self, requirements, prefer_final=None, - force_update=False): - """Search for releases and return a ReleaseList object containing - the results. - """ - predicate = get_version_predicate(requirements) - if predicate.name.lower() in self._projects and not force_update: - return self._projects.get(predicate.name.lower()) - prefer_final = self._get_prefer_final(prefer_final) - self._process_index_page(predicate.name) - - if predicate.name.lower() not in self._projects: - raise ProjectNotFound() - - releases = self._projects.get(predicate.name.lower()) - releases.sort_releases(prefer_final=prefer_final) - return releases - - def get_release(self, requirements, prefer_final=None): - """Return only one release that fulfill the given requirements""" - predicate = get_version_predicate(requirements) - release = self.get_releases(predicate, prefer_final)\ - .get_last(predicate) - if not release: - raise ReleaseNotFound("No release matches the given criterias") - return release - - def get_distributions(self, project_name, version): - """Return the distributions found on the index for the specific given - release""" - # as the default behavior of get_release is to return a release - # containing the distributions, just alias it. - return self.get_release("%s (%s)" % (project_name, version)) - - def get_metadata(self, project_name, version): - """Return the metadatas from the simple index. - - Currently, download one archive, extract it and use the PKG-INFO file. - """ - release = self.get_distributions(project_name, version) - if not release._metadata: - location = release.get_distribution().unpack() - pkg_info = os.path.join(location, 'PKG-INFO') - release._metadata = DistributionMetadata(pkg_info) - return release - - def _switch_to_next_mirror(self): - """Switch to the next mirror (eg. point self.index_url to the next - mirror url. - - Raise a KeyError if all mirrors have been tried. - """ - self._mirrors_used.add(self.index_url) - index_url = self._mirrors.pop() - if not ("http://" or "https://" or "file://") in index_url: - index_url = "http://%s" % index_url - - if not index_url.endswith("/simple"): - index_url = "%s/simple/" % index_url - - self.index_url = index_url - - def _is_browsable(self, url): - """Tell if the given URL can be browsed or not. - - It uses the follow_externals and the hosts list to tell if the given - url is browsable or not. - """ - # if _index_url is contained in the given URL, we are browsing the - # index, and it's always "browsable". - # local files are always considered browable resources - if self.index_url in url or urlparse.urlparse(url)[0] == "file": - return True - elif self.follow_externals: - if self._allowed_hosts(urlparse.urlparse(url)[1]): # 1 is netloc - return True - else: - return False - return False - - def _is_distribution(self, link): - """Tell if the given URL matches to a distribution name or not. - """ - #XXX find a better way to check that links are distributions - # Using a regexp ? - for ext in EXTENSIONS: - if ext in link: - return True - return False - - def _register_release(self, release=None, release_info={}): - """Register a new release. - - Both a release or a dict of release_info can be provided, the prefered - way (eg. the quicker) is the dict one. - - Return the list of existing releases for the given project. - """ - # Check if the project already has a list of releases (refering to - # the project name). If not, create a new release list. - # Then, add the release to the list. - if release: - name = release.name - else: - name = release_info['name'] - if not name.lower() in self._projects: - self._projects[name.lower()] = ReleasesList(name, - index=self._index) - - if release: - self._projects[name.lower()].add_release(release=release) - else: - name = release_info.pop('name') - version = release_info.pop('version') - dist_type = release_info.pop('dist_type') - self._projects[name.lower()].add_release(version, dist_type, - **release_info) - return self._projects[name.lower()] - - def _process_url(self, url, project_name=None, follow_links=True): - """Process an url and search for distributions packages. - - For each URL found, if it's a download, creates a PyPIdistribution - object. If it's a homepage and we can follow links, process it too. - - :param url: the url to process - :param project_name: the project name we are searching for. - :param follow_links: Do not want to follow links more than from one - level. This parameter tells if we want to follow - the links we find (eg. run recursively this - method on it) - """ - f = self._open_url(url) - base_url = f.url - if url not in self._processed_urls: - self._processed_urls.append(url) - link_matcher = self._get_link_matcher(url) - for link, is_download in link_matcher(f.read(), base_url): - if link not in self._processed_urls: - if self._is_distribution(link) or is_download: - self._processed_urls.append(link) - # it's a distribution, so create a dist object - try: - infos = get_infos_from_url(link, project_name, - is_external=not self.index_url in url) - except CantParseArchiveName, e: - logging.warning("version has not been parsed: %s" - % e) - else: - self._register_release(release_info=infos) - else: - if self._is_browsable(link) and follow_links: - self._process_url(link, project_name, - follow_links=False) - - def _get_link_matcher(self, url): - """Returns the right link matcher function of the given url - """ - if self.index_url in url: - return self._simple_link_matcher - else: - return self._default_link_matcher - - def _get_full_url(self, url, base_url): - return urlparse.urljoin(base_url, self._htmldecode(url)) - - def _simple_link_matcher(self, content, base_url): - """Yield all links with a rel="download" or rel="homepage". - - This matches the simple index requirements for matching links. - If follow_externals is set to False, dont yeld the external - urls. - """ - for match in HREF.finditer(content): - url = self._get_full_url(match.group(1), base_url) - if MD5_HASH.match(url): - yield (url, True) - - for match in REL.finditer(content): - # search for rel links. - tag, rel = match.groups() - rels = map(str.strip, rel.lower().split(',')) - if 'homepage' in rels or 'download' in rels: - for match in HREF.finditer(tag): - url = self._get_full_url(match.group(1), base_url) - if 'download' in rels or self._is_browsable(url): - # yield a list of (url, is_download) - yield (url, 'download' in rels) - - def _default_link_matcher(self, content, base_url): - """Yield all links found on the page. - """ - for match in HREF.finditer(content): - url = self._get_full_url(match.group(1), base_url) - if self._is_browsable(url): - yield (url, False) - - @with_mirror_support() - def _process_index_page(self, name): - """Find and process a PyPI page for the given project name. - - :param name: the name of the project to find the page - """ - # Browse and index the content of the given PyPI page. - url = self.index_url + name + "/" - self._process_url(url, name) - - @socket_timeout() - def _open_url(self, url): - """Open a urllib2 request, handling HTTP authentication, and local - files support. - - """ - scheme, netloc, path, params, query, frag = urlparse.urlparse(url) - - # authentication stuff - if scheme in ('http', 'https'): - auth, host = urllib2.splituser(netloc) - else: - auth = None - - # add index.html automatically for filesystem paths - if scheme == 'file': - if url.endswith('/'): - url += "index.html" - - # add authorization headers if auth is provided - if auth: - auth = "Basic " + \ - urllib2.unquote(auth).encode('base64').strip() - new_url = urlparse.urlunparse(( - scheme, host, path, params, query, frag)) - request = urllib2.Request(new_url) - request.add_header("Authorization", auth) - else: - request = urllib2.Request(url) - request.add_header('User-Agent', USER_AGENT) - try: - fp = urllib2.urlopen(request) - except (ValueError, httplib.InvalidURL), v: - msg = ' '.join([str(arg) for arg in v.args]) - raise DistutilsIndexError('%s %s' % (url, msg)) - except urllib2.HTTPError, v: - return v - except urllib2.URLError, v: - raise DownloadError("Download error for %s: %s" % (url, v.reason)) - except httplib.BadStatusLine, v: - raise DownloadError('%s returned a bad status line. ' - 'The server might be down, %s' % (url, v.line)) - except httplib.HTTPException, v: - raise DownloadError("Download error for %s: %s" % (url, v)) - except socket.timeout: - raise DownloadError("The server timeouted") - - if auth: - # Put authentication info back into request URL if same host, - # so that links found on the page will work - s2, h2, path2, param2, query2, frag2 = \ - urlparse.urlparse(fp.url) - if s2 == scheme and h2 == host: - fp.url = urlparse.urlunparse( - (s2, netloc, path2, param2, query2, frag2)) - return fp - - def _decode_entity(self, match): - what = match.group(1) - if what.startswith('#x'): - what = int(what[2:], 16) - elif what.startswith('#'): - what = int(what[1:]) - else: - from htmlentitydefs import name2codepoint - what = name2codepoint.get(what, match.group(0)) - return unichr(what) - - def _htmldecode(self, text): - """Decode HTML entities in the given text.""" - return ENTITY_SUB(self._decode_entity, text) diff --git a/src/distutils2/index/wrapper.py b/src/distutils2/index/wrapper.py deleted file mode 100644 index e3c4551..0000000 --- a/src/distutils2/index/wrapper.py +++ /dev/null @@ -1,93 +0,0 @@ -import xmlrpc -import simple - -_WRAPPER_MAPPINGS = {'get_release': 'simple', - 'get_releases': 'simple', - 'search_projects': 'simple', - 'get_metadata': 'xmlrpc', - 'get_distributions': 'simple'} - -_WRAPPER_INDEXES = {'xmlrpc': xmlrpc.Client, - 'simple': simple.Crawler} - -def switch_index_if_fails(func, wrapper): - """Decorator that switch of index (for instance from xmlrpc to simple) - if the first mirror return an empty list or raises an exception. - """ - def decorator(*args, **kwargs): - retry = True - exception = None - methods = [func] - for f in wrapper._indexes.values(): - if f != func.im_self and hasattr(f, func.__name__): - methods.append(getattr(f, func.__name__)) - for method in methods: - try: - response = method(*args, **kwargs) - retry = False - except Exception, e: - exception = e - if not retry: - break - if retry and exception: - raise exception - else: - return response - return decorator - - -class ClientWrapper(object): - """Wrapper around simple and xmlrpc clients, - - Choose the best implementation to use depending the needs, using the given - mappings. - If one of the indexes returns an error, tries to use others indexes. - - :param index: tell wich index to rely on by default. - :param index_classes: a dict of name:class to use as indexes. - :param indexes: a dict of name:index already instantiated - :param mappings: the mappings to use for this wrapper - """ - - def __init__(self, default_index='simple', index_classes=_WRAPPER_INDEXES, - indexes={}, mappings=_WRAPPER_MAPPINGS): - self._projects = {} - self._mappings = mappings - self._indexes = indexes - self._default_index = default_index - - # instantiate the classes and set their _project attribute to the one - # of the wrapper. - for name, cls in index_classes.items(): - obj = self._indexes.setdefault(name, cls()) - obj._projects = self._projects - obj._index = self - - def __getattr__(self, method_name): - """When asking for methods of the wrapper, return the implementation of - the wrapped classes, depending the mapping. - - Decorate the methods to switch of implementation if an error occurs - """ - real_method = None - if method_name in _WRAPPER_MAPPINGS: - obj = self._indexes[_WRAPPER_MAPPINGS[method_name]] - real_method = getattr(obj, method_name) - else: - # the method is not defined in the mappings, so we try first to get - # it via the default index, and rely on others if needed. - try: - real_method = getattr(self._indexes[self._default_index], - method_name) - except AttributeError: - other_indexes = [i for i in self._indexes - if i != self._default_index] - for index in other_indexes: - real_method = getattr(self._indexes[index], method_name, None) - if real_method: - break - if real_method: - return switch_index_if_fails(real_method, self) - else: - raise AttributeError("No index have attribute '%s'" % method_name) - diff --git a/src/distutils2/index/xmlrpc.py b/src/distutils2/index/xmlrpc.py deleted file mode 100644 index b9d66e0..0000000 --- a/src/distutils2/index/xmlrpc.py +++ /dev/null @@ -1,179 +0,0 @@ -import logging -import xmlrpclib - -from distutils2.errors import IrrationalVersionError -from distutils2.index.base import BaseClient -from distutils2.index.errors import (ProjectNotFound, InvalidSearchField, - ReleaseNotFound) -from distutils2.index.dist import ReleaseInfo -from distutils2.version import get_version_predicate - -__all__ = ['Client', 'DEFAULT_XMLRPC_INDEX_URL'] - -DEFAULT_XMLRPC_INDEX_URL = 'http://python.org/pypi' - -_SEARCH_FIELDS = ['name', 'version', 'author', 'author_email', 'maintainer', - 'maintainer_email', 'home_page', 'license', 'summary', - 'description', 'keywords', 'platform', 'download_url'] - - -class Client(BaseClient): - """Client to query indexes using XML-RPC method calls. - - If no server_url is specified, use the default PyPI XML-RPC URL, - defined in the DEFAULT_XMLRPC_INDEX_URL constant:: - - >>> client = XMLRPCClient() - >>> client.server_url == DEFAULT_XMLRPC_INDEX_URL - True - - >>> client = XMLRPCClient("http://someurl/") - >>> client.server_url - 'http://someurl/' - """ - - def __init__(self, server_url=DEFAULT_XMLRPC_INDEX_URL, prefer_final=False, - prefer_source=True): - super(Client, self).__init__(prefer_final, prefer_source) - self.server_url = server_url - self._projects = {} - - def get_release(self, requirements, prefer_final=False): - """Return a release with all complete metadata and distribution - related informations. - """ - prefer_final = self._get_prefer_final(prefer_final) - predicate = get_version_predicate(requirements) - releases = self.get_releases(predicate.name) - release = releases.get_last(predicate, prefer_final) - self.get_metadata(release.name, "%s" % release.version) - self.get_distributions(release.name, "%s" % release.version) - return release - - def get_releases(self, requirements, prefer_final=None, show_hidden=True, - force_update=False): - """Return the list of existing releases for a specific project. - - Cache the results from one call to another. - - If show_hidden is True, return the hidden releases too. - If force_update is True, reprocess the index to update the - informations (eg. make a new XML-RPC call). - :: - - >>> client = XMLRPCClient() - >>> client.get_releases('Foo') - ['1.1', '1.2', '1.3'] - - If no such project exists, raise a ProjectNotFound exception:: - - >>> client.get_project_versions('UnexistingProject') - ProjectNotFound: UnexistingProject - - """ - def get_versions(project_name, show_hidden): - return self.proxy.package_releases(project_name, show_hidden) - - predicate = get_version_predicate(requirements) - prefer_final = self._get_prefer_final(prefer_final) - project_name = predicate.name - if not force_update and (project_name.lower() in self._projects): - project = self._projects[project_name.lower()] - if not project.contains_hidden and show_hidden: - # if hidden releases are requested, and have an existing - # list of releases that does not contains hidden ones - all_versions = get_versions(project_name, show_hidden) - existing_versions = project.get_versions() - hidden_versions = list(set(all_versions) - - set(existing_versions)) - for version in hidden_versions: - project.add_release(release=ReleaseInfo(project_name, - version, index=self._index)) - else: - versions = get_versions(project_name, show_hidden) - if not versions: - raise ProjectNotFound(project_name) - project = self._get_project(project_name) - project.add_releases([ReleaseInfo(project_name, version, - index=self._index) - for version in versions]) - project = project.filter(predicate) - if len(project) == 0: - raise ReleaseNotFound("%s" % predicate) - project.sort_releases(prefer_final) - return project - - - def get_distributions(self, project_name, version): - """Grab informations about distributions from XML-RPC. - - Return a ReleaseInfo object, with distribution-related informations - filled in. - """ - url_infos = self.proxy.release_urls(project_name, version) - project = self._get_project(project_name) - if version not in project.get_versions(): - project.add_release(release=ReleaseInfo(project_name, version, - index=self._index)) - release = project.get_release(version) - for info in url_infos: - packagetype = info['packagetype'] - dist_infos = {'url': info['url'], - 'hashval': info['md5_digest'], - 'hashname': 'md5', - 'is_external': False, - 'python_version': info['python_version']} - release.add_distribution(packagetype, **dist_infos) - return release - - def get_metadata(self, project_name, version): - """Retreive project metadatas. - - Return a ReleaseInfo object, with metadata informations filled in. - """ - metadata = self.proxy.release_data(project_name, version) - project = self._get_project(project_name) - if version not in project.get_versions(): - project.add_release(release=ReleaseInfo(project_name, version, - index=self._index)) - release = project.get_release(version) - release.set_metadata(metadata) - return release - - def search_projects(self, name=None, operator="or", **kwargs): - """Find using the keys provided in kwargs. - - You can set operator to "and" or "or". - """ - for key in kwargs: - if key not in _SEARCH_FIELDS: - raise InvalidSearchField(key) - if name: - kwargs["name"] = name - projects = self.proxy.search(kwargs, operator) - for p in projects: - project = self._get_project(p['name']) - try: - project.add_release(release=ReleaseInfo(p['name'], - p['version'], metadata={'summary': p['summary']}, - index=self._index)) - except IrrationalVersionError, e: - logging.warn("Irrational version error found: %s" % e) - - return [self._projects[p['name'].lower()] for p in projects] - - @property - def proxy(self): - """Property used to return the XMLRPC server proxy. - - If no server proxy is defined yet, creates a new one:: - - >>> client = XmlRpcClient() - >>> client.proxy() - <ServerProxy for python.org/pypi> - - """ - if not hasattr(self, '_server_proxy'): - self._server_proxy = xmlrpclib.ServerProxy(self.server_url) - - return self._server_proxy diff --git a/src/distutils2/install_tools.py b/src/distutils2/install_tools.py deleted file mode 100644 index 1efeb64..0000000 --- a/src/distutils2/install_tools.py +++ /dev/null @@ -1,95 +0,0 @@ -import logging -from distutils2.index import wrapper -from distutils2.index.errors import ProjectNotFound, ReleaseNotFound -from distutils2.depgraph import generate_graph -from distutils2._backport.pkgutil import get_distributions - - -"""Provides installations scripts. - -The goal of this script is to install a release from the indexes (eg. -PyPI), including the dependencies of the releases if needed. - -It uses the work made in pkgutil and by the index crawlers to browse the -installed distributions, and rely on the instalation commands to install. -""" - - -class InstallationException(Exception): - pass - - -def _update_infos(infos, new_infos): - """extends the lists contained in the `info` dict with those contained - in the `new_info` one - """ - for key, value in infos.items(): - if key in new_infos: - infos[key].extend(new_infos[key]) - - -def get_infos(requirements, index=None, installed=None, - prefer_final=True): - """Return the informations on what's going to be installed and upgraded. - - :param requirements: is a *string* containing the requirements for this - project (for instance "FooBar 1.1" or "BarBaz (<1.2)") - :param index: If an index is specified, use this one, otherwise, use - :class index.ClientWrapper: to get project metadatas. - :param installed: a list of already installed distributions. - :param prefer_final: when picking up the releases, prefer a "final" one - over a beta/alpha/etc one. - - The results are returned in a dict, containing all the operations - needed to install the given requirements:: - - >>> get_install_info("FooBar (<=1.2)") - {'install': [<FooBar 1.1>], 'remove': [], 'conflict': []} - - Conflict contains all the conflicting distributions, if there is a - conflict. - """ - - if not index: - index = wrapper.ClientWrapper() - - if not installed: - installed = get_distributions() - - # Get all the releases that match the requirements - try: - releases = index.get_releases(requirements) - except (ReleaseNotFound, ProjectNotFound), e: - raise InstallationException('Release not found: "%s"' % requirements) - - # Pick up a release, and try to get the dependency tree - release = releases.get_last(requirements, prefer_final=prefer_final) - - # Iter since we found something without conflicts - metadata = release.fetch_metadata() - - # Get the distributions already_installed on the system - # and add the one we want to install - - distributions = installed + [release] - depgraph = generate_graph(distributions) - - # Store all the already_installed packages in a list, in case of rollback. - infos = {'install': [], 'remove': [], 'conflict': []} - - # Get what the missing deps are - for dists in depgraph.missing.values(): - if dists: - logging.info("missing dependencies found, installing them") - # we have missing deps - for dist in dists: - _update_infos(infos, - get_infos(dist, index, installed)) - - # Fill in the infos - existing = [d for d in installed if d.name == release.name] - if existing: - infos['remove'].append(existing[0]) - infos['conflict'].extend(depgraph.reverse_list[existing[0]]) - infos['install'].append(release) - return infos diff --git a/src/distutils2/log.py b/src/distutils2/log.py deleted file mode 100644 index 1293bf4..0000000 --- a/src/distutils2/log.py +++ /dev/null @@ -1,71 +0,0 @@ -"""A simple log mechanism styled after PEP 282.""" - -# The class here is styled after PEP 282 so that it could later be -# replaced with a standard Python logging implementation. - -DEBUG = 1 -INFO = 2 -WARN = 3 -ERROR = 4 -FATAL = 5 - -import sys - -class Log(object): - - def __init__(self, threshold=WARN): - self.threshold = threshold - - def _log(self, level, msg, args): - if level not in (DEBUG, INFO, WARN, ERROR, FATAL): - raise ValueError('%s wrong log level' % level) - - if level >= self.threshold: - if args: - msg = msg % args - if level in (WARN, ERROR, FATAL): - stream = sys.stderr - else: - stream = sys.stdout - stream.write('%s\n' % msg) - stream.flush() - - def log(self, level, msg, *args): - self._log(level, msg, args) - - def debug(self, msg, *args): - self._log(DEBUG, msg, args) - - def info(self, msg, *args): - self._log(INFO, msg, args) - - def warn(self, msg, *args): - self._log(WARN, msg, args) - - def error(self, msg, *args): - self._log(ERROR, msg, args) - - def fatal(self, msg, *args): - self._log(FATAL, msg, args) - -_global_log = Log() -log = _global_log.log -debug = _global_log.debug -info = _global_log.info -warn = _global_log.warn -error = _global_log.error -fatal = _global_log.fatal - -def set_threshold(level): - # return the old threshold for use from tests - old = _global_log.threshold - _global_log.threshold = level - return old - -def set_verbosity(v): - if v <= 0: - set_threshold(WARN) - elif v == 1: - set_threshold(INFO) - elif v >= 2: - set_threshold(DEBUG) diff --git a/src/distutils2/manifest.py b/src/distutils2/manifest.py deleted file mode 100644 index 27b3dce..0000000 --- a/src/distutils2/manifest.py +++ /dev/null @@ -1,376 +0,0 @@ -"""distutils2.manifest - -Provides a Manifest class that can be used to: - - - read or write a MANIFEST file - - read a template file and find out the file list - -Basically, Manifest *is* the file list. - -XXX todo: document + add tests -""" -import re -import os -import fnmatch -import logging - -from distutils2.util import write_file, convert_path -from distutils2.errors import (DistutilsTemplateError, - DistutilsInternalError) - -__all__ = ['Manifest'] - -# a \ followed by some spaces + EOL -_COLLAPSE_PATTERN = re.compile('\\\w*\n', re.M) -_COMMENTED_LINE = re.compile('#.*?(?=\n)|^\w*\n|\n(?=$)', re.M | re.S) - -class Manifest(object): - """A list of files built by on exploring the filesystem and filtered by - applying various patterns to what we find there. - """ - - def __init__(self): - self.allfiles = None - self.files = [] - - # - # Public API - # - - def findall(self, dir=os.curdir): - self.allfiles = _findall(dir) - - def append(self, item): - self.files.append(item) - - def extend(self, items): - self.files.extend(items) - - def sort(self): - # Not a strict lexical sort! - sortable_files = map(os.path.split, self.files) - sortable_files.sort() - self.files = [] - for sort_tuple in sortable_files: - self.files.append(os.path.join(*sort_tuple)) - - def clear(self): - """Clear all collected files.""" - self.files = [] - if self.allfiles is not None: - self.allfiles = [] - - def remove_duplicates(self): - # Assumes list has been sorted! - for i in range(len(self.files) - 1, 0, -1): - if self.files[i] == self.files[i - 1]: - del self.files[i] - - def read_template(self, path): - """Read and parse a manifest template file. - - Updates the list accordingly. - """ - f = open(path) - try: - content = f.read() - # first, let's unwrap collapsed lines - content = _COLLAPSE_PATTERN.sub('', content) - - # next, let's remove commented lines and empty lines - content = _COMMENTED_LINE.sub('', content) - - # now we have our cleaned up lines - lines = [line.strip() for line in content.split('\n')] - finally: - f.close() - - for line in lines: - try: - self._process_template_line(line) - except DistutilsTemplateError, msg: - logging.warning("%s, %s" % (path, msg)) - - def write(self, path): - """Write the file list in 'self.filelist' (presumably as filled in - by 'add_defaults()' and 'read_template()') to the manifest file - named by 'self.manifest'. - """ - if os.path.isfile(path): - fp = open(path) - try: - first_line = fp.readline() - finally: - fp.close() - - if first_line != '# file GENERATED by distutils, do NOT edit\n': - logging.info("not writing to manually maintained " - "manifest file '%s'", path) - return - - self.sort() - self.remove_duplicates() - content = self.files[:] - content.insert(0, '# file GENERATED by distutils, do NOT edit') - logging.info("writing manifest file '%s'", path) - write_file(path, content) - - def read(self, path): - """Read the manifest file (named by 'self.manifest') and use it to - fill in 'self.filelist', the list of files to include in the source - distribution. - """ - logging.info("reading manifest file '%s'" % path) - manifest = open(path) - try: - for line in manifest.readlines(): - self.append(line) - finally: - manifest.close() - - def exclude_pattern(self, pattern, anchor=1, prefix=None, is_regex=0): - """Remove strings (presumably filenames) from 'files' that match - 'pattern'. - - Other parameters are the same as for 'include_pattern()', above. - The list 'self.files' is modified in place. Return 1 if files are - found. - """ - files_found = 0 - pattern_re = _translate_pattern(pattern, anchor, prefix, is_regex) - for i in range(len(self.files)-1, -1, -1): - if pattern_re.search(self.files[i]): - del self.files[i] - files_found = 1 - - return files_found - - # - # Private API - # - - def _parse_template_line(self, line): - words = line.split() - action = words[0] - - patterns = dir = dir_pattern = None - - if action in ('include', 'exclude', - 'global-include', 'global-exclude'): - if len(words) < 2: - raise DistutilsTemplateError( - "'%s' expects <pattern1> <pattern2> ..." % action) - - patterns = map(convert_path, words[1:]) - - elif action in ('recursive-include', 'recursive-exclude'): - if len(words) < 3: - raise DistutilsTemplateError( - "'%s' expects <dir> <pattern1> <pattern2> ..." % action) - - dir = convert_path(words[1]) - patterns = map(convert_path, words[2:]) - - elif action in ('graft', 'prune'): - if len(words) != 2: - raise DistutilsTemplateError( - "'%s' expects a single <dir_pattern>" % action) - - dir_pattern = convert_path(words[1]) - - else: - raise DistutilsTemplateError("unknown action '%s'" % action) - - return action, patterns, dir, dir_pattern - - def _process_template_line(self, line): - # Parse the line: split it up, make sure the right number of words - # is there, and return the relevant words. 'action' is always - # defined: it's the first word of the line. Which of the other - # three are defined depends on the action; it'll be either - # patterns, (dir and patterns), or (dir_pattern). - action, patterns, dir, dir_pattern = self._parse_template_line(line) - - # OK, now we know that the action is valid and we have the - # right number of words on the line for that action -- so we - # can proceed with minimal error-checking. - if action == 'include': - for pattern in patterns: - if not self._include_pattern(pattern, anchor=1): - logging.warning("warning: no files found matching '%s'" % - pattern) - - elif action == 'exclude': - for pattern in patterns: - if not self.exclude_pattern(pattern, anchor=1): - logging.warning(("warning: no previously-included files " - "found matching '%s'") % pattern) - - elif action == 'global-include': - for pattern in patterns: - if not self._include_pattern(pattern, anchor=0): - logging.warning(("warning: no files found matching '%s' " + - "anywhere in distribution") % pattern) - - elif action == 'global-exclude': - for pattern in patterns: - if not self.exclude_pattern(pattern, anchor=0): - logging.warning(("warning: no previously-included files " - "matching '%s' found anywhere in distribution") % - pattern) - - elif action == 'recursive-include': - for pattern in patterns: - if not self._include_pattern(pattern, prefix=dir): - logging.warning(("warning: no files found matching '%s' " - "under directory '%s'" % (pattern, dir))) - - elif action == 'recursive-exclude': - for pattern in patterns: - if not self.exclude_pattern(pattern, prefix=dir): - logging.warning(("warning: no previously-included files " - "matching '%s' found under directory '%s'") % - (pattern, dir)) - - elif action == 'graft': - if not self._include_pattern(None, prefix=dir_pattern): - logging.warning("warning: no directories found matching '%s'" % - dir_pattern) - - elif action == 'prune': - if not self.exclude_pattern(None, prefix=dir_pattern): - logging.warning(("no previously-included directories found " + - "matching '%s'") % dir_pattern) - else: - raise DistutilsInternalError( - "this cannot happen: invalid action '%s'" % action) - - def _include_pattern(self, pattern, anchor=1, prefix=None, is_regex=0): - """Select strings (presumably filenames) from 'self.files' that - match 'pattern', a Unix-style wildcard (glob) pattern. - - Patterns are not quite the same as implemented by the 'fnmatch' - module: '*' and '?' match non-special characters, where "special" - is platform-dependent: slash on Unix; colon, slash, and backslash on - DOS/Windows; and colon on Mac OS. - - If 'anchor' is true (the default), then the pattern match is more - stringent: "*.py" will match "foo.py" but not "foo/bar.py". If - 'anchor' is false, both of these will match. - - If 'prefix' is supplied, then only filenames starting with 'prefix' - (itself a pattern) and ending with 'pattern', with anything in between - them, will match. 'anchor' is ignored in this case. - - If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and - 'pattern' is assumed to be either a string containing a regex or a - regex object -- no translation is done, the regex is just compiled - and used as-is. - - Selected strings will be added to self.files. - - Return 1 if files are found. - """ - files_found = 0 - pattern_re = _translate_pattern(pattern, anchor, prefix, is_regex) - - # delayed loading of allfiles list - if self.allfiles is None: - self.findall() - - for name in self.allfiles: - if pattern_re.search(name): - self.files.append(name) - files_found = 1 - - return files_found - - - -# -# Utility functions -# - -def _findall(dir=os.curdir): - """Find all files under 'dir' and return the list of full filenames - (relative to 'dir'). - """ - from stat import ST_MODE, S_ISREG, S_ISDIR, S_ISLNK - - list = [] - stack = [dir] - pop = stack.pop - push = stack.append - - while stack: - dir = pop() - names = os.listdir(dir) - - for name in names: - if dir != os.curdir: # avoid the dreaded "./" syndrome - fullname = os.path.join(dir, name) - else: - fullname = name - - # Avoid excess stat calls -- just one will do, thank you! - stat = os.stat(fullname) - mode = stat[ST_MODE] - if S_ISREG(mode): - list.append(fullname) - elif S_ISDIR(mode) and not S_ISLNK(mode): - push(fullname) - - return list - - - -def _glob_to_re(pattern): - """Translate a shell-like glob pattern to a regular expression. - - Return a string containing the regex. Differs from - 'fnmatch.translate()' in that '*' does not match "special characters" - (which are platform-specific). - """ - pattern_re = fnmatch.translate(pattern) - - # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which - # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, - # and by extension they shouldn't match such "special characters" under - # any OS. So change all non-escaped dots in the RE to match any - # character except the special characters. - # XXX currently the "special characters" are just slash -- i.e. this is - # Unix-only. - pattern_re = re.sub(r'((?<!\\)(\\\\)*)\.', r'\1[^/]', pattern_re) - - return pattern_re - - -def _translate_pattern(pattern, anchor=1, prefix=None, is_regex=0): - """Translate a shell-like wildcard pattern to a compiled regular - expression. - - Return the compiled regex. If 'is_regex' true, - then 'pattern' is directly compiled to a regex (if it's a string) - or just returned as-is (assumes it's a regex object). - """ - if is_regex: - if isinstance(pattern, str): - return re.compile(pattern) - else: - return pattern - - if pattern: - pattern_re = _glob_to_re(pattern) - else: - pattern_re = '' - - if prefix is not None: - # ditch end of pattern character - empty_pattern = _glob_to_re('') - prefix_re = _glob_to_re(prefix)[:-len(empty_pattern)] - pattern_re = "^" + os.path.join(prefix_re, ".*" + pattern_re) - else: # no prefix -- respect anchor flag - if anchor: - pattern_re = "^" + pattern_re - - return re.compile(pattern_re) diff --git a/src/distutils2/metadata.py b/src/distutils2/metadata.py deleted file mode 100644 index 3743d0e..0000000 --- a/src/distutils2/metadata.py +++ /dev/null @@ -1,670 +0,0 @@ -"""Implementation of the Metadata for Python packages PEPs. - -Supports all metadata formats (1.0, 1.1, 1.2). -""" - -import os -import sys -import platform -import re -from StringIO import StringIO -from email import message_from_file -from tokenize import tokenize, NAME, OP, STRING, ENDMARKER - -from distutils2.log import warn -from distutils2.version import (is_valid_predicate, is_valid_version, - is_valid_versions) -from distutils2.errors import (MetadataConflictError, - MetadataUnrecognizedVersionError) - -try: - # docutils is installed - from docutils.utils import Reporter - from docutils.parsers.rst import Parser - from docutils import frontend - from docutils import nodes - - class SilentReporter(Reporter): - - def __init__(self, source, report_level, halt_level, stream=None, - debug=0, encoding='ascii', error_handler='replace'): - self.messages = [] - Reporter.__init__(self, source, report_level, halt_level, stream, - debug, encoding, error_handler) - - def system_message(self, level, message, *children, **kwargs): - self.messages.append((level, message, children, kwargs)) - - _HAS_DOCUTILS = True -except ImportError: - # docutils is not installed - _HAS_DOCUTILS = False - -# public API of this module -__all__ = ('DistributionMetadata', 'PKG_INFO_ENCODING', - 'PKG_INFO_PREFERRED_VERSION') - -# Encoding used for the PKG-INFO files -PKG_INFO_ENCODING = 'utf-8' - -# preferred version. Hopefully will be changed -# to 1.2 once PEP 345 is supported everywhere -PKG_INFO_PREFERRED_VERSION = '1.0' - -_LINE_PREFIX = re.compile('\n \|') -_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'License') - -_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Supported-Platform', 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'License', 'Classifier', 'Download-URL', 'Obsoletes', - 'Provides', 'Requires') - -_314_MARKERS = ('Obsoletes', 'Provides', 'Requires') - -_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Supported-Platform', 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'Maintainer', 'Maintainer-email', 'License', - 'Classifier', 'Download-URL', 'Obsoletes-Dist', - 'Project-URL', 'Provides-Dist', 'Requires-Dist', - 'Requires-Python', 'Requires-External') - -_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python', - 'Obsoletes-Dist', 'Requires-External', 'Maintainer', - 'Maintainer-email', 'Project-URL') - -_ALL_FIELDS = set() -_ALL_FIELDS.update(_241_FIELDS) -_ALL_FIELDS.update(_314_FIELDS) -_ALL_FIELDS.update(_345_FIELDS) - - -def _version2fieldlist(version): - if version == '1.0': - return _241_FIELDS - elif version == '1.1': - return _314_FIELDS - elif version == '1.2': - return _345_FIELDS - raise MetadataUnrecognizedVersionError(version) - - -def _best_version(fields): - """Detect the best version depending on the fields used.""" - def _has_marker(keys, markers): - for marker in markers: - if marker in keys: - return True - return False - - keys = fields.keys() - possible_versions = ['1.0', '1.1', '1.2'] - - # first let's try to see if a field is not part of one of the version - for key in keys: - if key not in _241_FIELDS and '1.0' in possible_versions: - possible_versions.remove('1.0') - if key not in _314_FIELDS and '1.1' in possible_versions: - possible_versions.remove('1.1') - if key not in _345_FIELDS and '1.2' in possible_versions: - possible_versions.remove('1.2') - - # possible_version contains qualified versions - if len(possible_versions) == 1: - return possible_versions[0] # found ! - elif len(possible_versions) == 0: - raise MetadataConflictError('Unknown metadata set') - - # let's see if one unique marker is found - is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS) - is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS) - if is_1_1 and is_1_2: - raise MetadataConflictError('You used incompatible 1.1 and 1.2 fields') - - # we have the choice, either 1.0, or 1.2 - # - 1.0 has a broken Summary field but works with all tools - # - 1.1 is to avoid - # - 1.2 fixes Summary but is not widespread yet - if not is_1_1 and not is_1_2: - # we couldn't find any specific marker - if PKG_INFO_PREFERRED_VERSION in possible_versions: - return PKG_INFO_PREFERRED_VERSION - if is_1_1: - return '1.1' - - # default marker when 1.0 is disqualified - return '1.2' - -_ATTR2FIELD = {'metadata_version': 'Metadata-Version', - 'name': 'Name', - 'version': 'Version', - 'platform': 'Platform', - 'supported_platform': 'Supported-Platform', - 'summary': 'Summary', - 'description': 'Description', - 'keywords': 'Keywords', - 'home_page': 'Home-page', - 'author': 'Author', - 'author_email': 'Author-email', - 'maintainer': 'Maintainer', - 'maintainer_email': 'Maintainer-email', - 'license': 'License', - 'classifier': 'Classifier', - 'download_url': 'Download-URL', - 'obsoletes_dist': 'Obsoletes-Dist', - 'provides_dist': 'Provides-Dist', - 'requires_dist': 'Requires-Dist', - 'requires_python': 'Requires-Python', - 'requires_external': 'Requires-External', - 'requires': 'Requires', - 'provides': 'Provides', - 'obsoletes': 'Obsoletes', - 'project_url': 'Project-URL', - } - -_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist') -_VERSIONS_FIELDS = ('Requires-Python',) -_VERSION_FIELDS = ('Version',) -_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', - 'Requires', 'Provides', 'Obsoletes-Dist', - 'Provides-Dist', 'Requires-Dist', 'Requires-External', - 'Project-URL') -_LISTTUPLEFIELDS = ('Project-URL',) - -_ELEMENTSFIELD = ('Keywords',) - -_UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') - - -class DistributionMetadata(object): - """The metadata of a release. - - Supports versions 1.0, 1.1 and 1.2 (auto-detected). You can - instantiate the class with one of these arguments (or none): - - *path*, the path to a METADATA file - - *fileobj* give a file-like object with METADATA as content - - *mapping* is a dict-like object - """ - # TODO document that execution_context and platform_dependent are used - # to filter on query, not when setting a key - # also document the mapping API and UNKNOWN default key - - def __init__(self, path=None, platform_dependent=False, - execution_context=None, fileobj=None, mapping=None): - self._fields = {} - self.version = None - self.docutils_support = _HAS_DOCUTILS - self.platform_dependent = platform_dependent - self.execution_context = execution_context - if [path, fileobj, mapping].count(None) < 2: - raise TypeError('path, fileobj and mapping are exclusive') - if path is not None: - self.read(path) - elif fileobj is not None: - self.read_file(fileobj) - elif mapping is not None: - self.update(mapping) - - def _set_best_version(self): - self.version = _best_version(self._fields) - self._fields['Metadata-Version'] = self.version - - def _write_field(self, file, name, value): - file.write('%s: %s\n' % (name, value)) - - def _encode_field(self, value): - if isinstance(value, unicode): - return value.encode(PKG_INFO_ENCODING) - return str(value) - - def __getitem__(self, name): - return self.get(name) - - def __setitem__(self, name, value): - return self.set(name, value) - - def __delitem__(self, name): - del self._fields[name] - self._set_best_version() - - def _convert_name(self, name): - if name in _ALL_FIELDS: - return name - name = name.replace('-', '_').lower() - return _ATTR2FIELD.get(name, name) - - def _default_value(self, name): - if name in _LISTFIELDS or name in _ELEMENTSFIELD: - return [] - return 'UNKNOWN' - - def _check_rst_data(self, data): - """Return warnings when the provided data has syntax errors.""" - source_path = StringIO() - parser = Parser() - settings = frontend.OptionParser().get_default_values() - settings.tab_width = 4 - settings.pep_references = None - settings.rfc_references = None - reporter = SilentReporter(source_path, - settings.report_level, - settings.halt_level, - stream=settings.warning_stream, - debug=settings.debug, - encoding=settings.error_encoding, - error_handler=settings.error_encoding_error_handler) - - document = nodes.document(settings, reporter, source=source_path) - document.note_source(source_path, -1) - try: - parser.parse(data, document) - except AttributeError: - reporter.messages.append((-1, 'Could not finish the parsing.', - '', {})) - - return reporter.messages - - def _platform(self, value): - if not self.platform_dependent or ';' not in value: - return True, value - value, marker = value.split(';') - return _interpret(marker, self.execution_context), value - - def _remove_line_prefix(self, value): - return _LINE_PREFIX.sub('\n', value) - - # - # Public API - # - def get_fullname(self): - return '%s-%s' % (self['Name'], self['Version']) - - def is_metadata_field(self, name): - name = self._convert_name(name) - return name in _ALL_FIELDS - - def read(self, filepath): - self.read_file(open(filepath)) - - def read_file(self, fileob): - """Read the metadata values from a file object.""" - msg = message_from_file(fileob) - self.version = msg['metadata-version'] - - for field in _version2fieldlist(self.version): - if field in _LISTFIELDS: - # we can have multiple lines - values = msg.get_all(field) - if field in _LISTTUPLEFIELDS and values is not None: - values = [tuple(value.split(',')) for value in values] - self.set(field, values) - else: - # single line - value = msg[field] - if value is not None: - self.set(field, value) - - def write(self, filepath): - """Write the metadata fields to filepath.""" - pkg_info = open(filepath, 'w') - try: - self.write_file(pkg_info) - finally: - pkg_info.close() - - def write_file(self, fileobject): - """Write the PKG-INFO format data to a file object.""" - self._set_best_version() - for field in _version2fieldlist(self.version): - values = self.get(field) - if field in _ELEMENTSFIELD: - self._write_field(fileobject, field, ','.join(values)) - continue - if field not in _LISTFIELDS: - if field == 'Description': - values = values.replace('\n', '\n |') - values = [values] - - if field in _LISTTUPLEFIELDS: - values = [','.join(value) for value in values] - - for value in values: - self._write_field(fileobject, field, value) - - def update(self, other=None, **kwargs): - """Set metadata values from the given iterable `other` and kwargs. - - Behavior is like `dict.update`: If `other` has a ``keys`` method, - they are looped over and ``self[key]`` is assigned ``other[key]``. - Else, ``other`` is an iterable of ``(key, value)`` iterables. - - Keys that don't match a metadata field or that have an empty value are - dropped. - """ - def _set(key, value): - if key in _ATTR2FIELD and value: - self.set(self._convert_name(key), value) - - if other is None: - pass - elif hasattr(other, 'keys'): - for k in other.keys(): - _set(k, other[k]) - else: - for k, v in other: - _set(k, v) - - if kwargs: - self.update(kwargs) - - def set(self, name, value): - """Control then set a metadata field.""" - name = self._convert_name(name) - - if ((name in _ELEMENTSFIELD or name == 'Platform') and - not isinstance(value, (list, tuple))): - if isinstance(value, str): - value = value.split(',') - else: - value = [] - elif (name in _LISTFIELDS and - not isinstance(value, (list, tuple))): - if isinstance(value, str): - value = [value] - else: - value = None - - if name in _PREDICATE_FIELDS and value is not None: - for v in value: - # check that the values are valid predicates - if not is_valid_predicate(v.split(';')[0]): - warn('"%s" is not a valid predicate (field "%s")' % - (v, name)) - # FIXME this rejects UNKNOWN, is that right? - elif name in _VERSIONS_FIELDS and value is not None: - if not is_valid_versions(value): - warn('"%s" is not a valid version (field "%s")' % - (value, name)) - elif name in _VERSION_FIELDS and value is not None: - if not is_valid_version(value): - warn('"%s" is not a valid version (field "%s")' % - (value, name)) - - if name in _UNICODEFIELDS: - value = self._encode_field(value) - if name == 'Description': - value = self._remove_line_prefix(value) - - self._fields[name] = value - self._set_best_version() - - def get(self, name): - """Get a metadata field.""" - name = self._convert_name(name) - if name not in self._fields: - return self._default_value(name) - if name in _UNICODEFIELDS: - value = self._fields[name] - return self._encode_field(value) - elif name in _LISTFIELDS: - value = self._fields[name] - if value is None: - return [] - res = [] - for val in value: - valid, val = self._platform(val) - if not valid: - continue - if name not in _LISTTUPLEFIELDS: - res.append(self._encode_field(val)) - else: - # That's for Project-URL - res.append((self._encode_field(val[0]), val[1])) - return res - - elif name in _ELEMENTSFIELD: - valid, value = self._platform(self._fields[name]) - if not valid: - return [] - if isinstance(value, str): - return value.split(',') - valid, value = self._platform(self._fields[name]) - if not valid: - return None - return value - - def check(self): - """Check if the metadata is compliant.""" - # XXX should check the versions (if the file was loaded) - missing, warnings = [], [] - for attr in ('Name', 'Version', 'Home-page'): - value = self[attr] - if value == 'UNKNOWN': - missing.append(attr) - - if _HAS_DOCUTILS: - warnings.extend(self._check_rst_data(self['Description'])) - - # checking metadata 1.2 (XXX needs to check 1.1, 1.0) - if self['Metadata-Version'] != '1.2': - return missing, warnings - - def is_valid_predicates(value): - for v in value: - if not is_valid_predicate(v.split(';')[0]): - return False - return True - - for fields, controller in ((_PREDICATE_FIELDS, is_valid_predicates), - (_VERSIONS_FIELDS, is_valid_versions), - (_VERSION_FIELDS, is_valid_version)): - for field in fields: - value = self[field] - if value == 'UNKNOWN': - continue - - if not controller(value): - warnings.append('Wrong value for %r: %s' % (field, value)) - - return missing, warnings - - def keys(self): - return _version2fieldlist(self.version) - - def values(self): - return [self[key] for key in self.keys()] - - def items(self): - return [(key, self[key]) for key in self.keys()] - - -# -# micro-language for PEP 345 environment markers -# - -# allowed operators -_OPERATORS = {'==': lambda x, y: x == y, - '!=': lambda x, y: x != y, - '>': lambda x, y: x > y, - '>=': lambda x, y: x >= y, - '<': lambda x, y: x < y, - '<=': lambda x, y: x <= y, - 'in': lambda x, y: x in y, - 'not in': lambda x, y: x not in y} - - -def _operate(operation, x, y): - return _OPERATORS[operation](x, y) - -# restricted set of variables -_VARS = {'sys.platform': sys.platform, - 'python_version': sys.version[:3], - 'python_full_version': sys.version.split(' ', 1)[0], - 'os.name': os.name, - 'platform.version': platform.version(), - 'platform.machine': platform.machine()} - - -class _Operation(object): - - def __init__(self, execution_context=None): - self.left = None - self.op = None - self.right = None - if execution_context is None: - execution_context = {} - self.execution_context = execution_context - - def _get_var(self, name): - if name in self.execution_context: - return self.execution_context[name] - return _VARS[name] - - def __repr__(self): - return '%s %s %s' % (self.left, self.op, self.right) - - def _is_string(self, value): - if value is None or len(value) < 2: - return False - for delimiter in '"\'': - if value[0] == value[-1] == delimiter: - return True - return False - - def _is_name(self, value): - return value in _VARS - - def _convert(self, value): - if value in _VARS: - return self._get_var(value) - return value.strip('"\'') - - def _check_name(self, value): - if value not in _VARS: - raise NameError(value) - - def _nonsense_op(self): - msg = 'This operation is not supported : "%s"' % self - raise SyntaxError(msg) - - def __call__(self): - # make sure we do something useful - if self._is_string(self.left): - if self._is_string(self.right): - self._nonsense_op() - self._check_name(self.right) - else: - if not self._is_string(self.right): - self._nonsense_op() - self._check_name(self.left) - - if self.op not in _OPERATORS: - raise TypeError('Operator not supported "%s"' % self.op) - - left = self._convert(self.left) - right = self._convert(self.right) - return _operate(self.op, left, right) - - -class _OR(object): - def __init__(self, left, right=None): - self.left = left - self.right = right - - def filled(self): - return self.right is not None - - def __repr__(self): - return 'OR(%r, %r)' % (self.left, self.right) - - def __call__(self): - return self.left() or self.right() - - -class _AND(object): - def __init__(self, left, right=None): - self.left = left - self.right = right - - def filled(self): - return self.right is not None - - def __repr__(self): - return 'AND(%r, %r)' % (self.left, self.right) - - def __call__(self): - return self.left() and self.right() - - -class _CHAIN(object): - - def __init__(self, execution_context=None): - self.ops = [] - self.op_starting = True - self.execution_context = execution_context - - def eat(self, toktype, tokval, rowcol, line, logical_line): - if toktype not in (NAME, OP, STRING, ENDMARKER): - raise SyntaxError('Type not supported "%s"' % tokval) - - if self.op_starting: - op = _Operation(self.execution_context) - if len(self.ops) > 0: - last = self.ops[-1] - if isinstance(last, (_OR, _AND)) and not last.filled(): - last.right = op - else: - self.ops.append(op) - else: - self.ops.append(op) - self.op_starting = False - else: - op = self.ops[-1] - - if (toktype == ENDMARKER or - (toktype == NAME and tokval in ('and', 'or'))): - if toktype == NAME and tokval == 'and': - self.ops.append(_AND(self.ops.pop())) - elif toktype == NAME and tokval == 'or': - self.ops.append(_OR(self.ops.pop())) - self.op_starting = True - return - - if isinstance(op, (_OR, _AND)) and op.right is not None: - op = op.right - - if ((toktype in (NAME, STRING) and tokval not in ('in', 'not')) - or (toktype == OP and tokval == '.')): - if op.op is None: - if op.left is None: - op.left = tokval - else: - op.left += tokval - else: - if op.right is None: - op.right = tokval - else: - op.right += tokval - elif toktype == OP or tokval in ('in', 'not'): - if tokval == 'in' and op.op == 'not': - op.op = 'not in' - else: - op.op = tokval - - def result(self): - for op in self.ops: - if not op(): - return False - return True - - -def _interpret(marker, execution_context=None): - """Interpret a marker and return a result depending on environment.""" - marker = marker.strip() - operations = _CHAIN(execution_context) - tokenize(StringIO(marker).readline, operations.eat) - return operations.result() diff --git a/src/distutils2/mkpkg.py b/src/distutils2/mkpkg.py deleted file mode 100644 index 438fb87..0000000 --- a/src/distutils2/mkpkg.py +++ /dev/null @@ -1,417 +0,0 @@ -#!/usr/bin/env python -# -# Helper for automating the creation of a package by looking at you -# current directory and asking the user questions. -# -# Available as either a stand-alone file or callable from the distutils2 -# package: -# -# python -m distutils2.mkpkg -# or: -# python mkpkg.py -# -# Written by Sean Reifschneider <jafo@tummy.com> -# -# Original TODO list: -# Look for a license file and automatically add the category. -# When a .c file is found during the walk, can we add it as an extension? -# Ask if there is a maintainer different that the author -# Ask for the platform (can we detect this via "import win32" or something?) -# Ask for the dependencies. -# Ask for the Requires-Dist -# Ask for the Provides-Dist -# Detect scripts (not sure how. #! outside of package?) - -import os -import sys -import re -import shutil -from ConfigParser import RawConfigParser -from textwrap import dedent -# importing this with an underscore as it should be replaced by the -# dict form or another structures for all purposes -from distutils2._trove import all_classifiers as _CLASSIFIERS_LIST - - -_helptext = { - 'name': ''' -The name of the program to be packaged, usually a single word composed -of lower-case characters such as "python", "sqlalchemy", or "CherryPy". -''', - 'version': ''' -Version number of the software, typically 2 or 3 numbers separated by dots -such as "1.00", "0.6", or "3.02.01". "0.1.0" is recommended for initial -development. -''', - 'description': ''' -A short summary of what this package is or does, typically a sentence 80 -characters or less in length. -''', - 'author': ''' -The full name of the author (typically you). -''', - 'author_email': ''' -E-mail address of the package author (typically you). -''', - 'do_classifier': ''' -Trove classifiers are optional identifiers that allow you to specify the -intended audience by saying things like "Beta software with a text UI -for Linux under the PSF license. However, this can be a somewhat involved -process. -''', - 'url': ''' -The home page for the package, typically starting with "http://". -''', - 'trove_license': ''' -Optionally you can specify a license. Type a string that identifies a common -license, and then you can select a list of license specifiers. -''', - 'trove_generic': ''' -Optionally, you can set other trove identifiers for things such as the -human language, programming language, user interface, etc... -''', -} - -# XXX everything needs docstrings and tests (both low-level tests of various -# methods and functional tests of running the script) - - -def ask_yn(question, default=None, helptext=None): - while True: - answer = ask(question, default, helptext, required=True) - if answer and answer[0].lower() in 'yn': - return answer[0].lower() - - print '\nERROR: You must select "Y" or "N".\n' - - -def ask(question, default=None, helptext=None, required=True, - lengthy=False, multiline=False): - prompt = '%s: ' % (question,) - if default: - prompt = '%s [%s]: ' % (question, default) - if default and len(question) + len(default) > 70: - prompt = '%s\n [%s]: ' % (question, default) - if lengthy or multiline: - prompt += '\n >' - - if not helptext: - helptext = 'No additional help available.' - - helptext = helptext.strip("\n") - - while True: - sys.stdout.write(prompt) - sys.stdout.flush() - - line = sys.stdin.readline().strip() - if line == '?': - print '=' * 70 - print helptext - print '=' * 70 - continue - if default and not line: - return default - if not line and required: - print '*' * 70 - print 'This value cannot be empty.' - print '===========================' - if helptext: - print helptext - print '*' * 70 - continue - return line - - -def _build_classifiers_dict(classifiers): - d = {} - for key in classifiers: - subDict = d - for subkey in key.split(' :: '): - if not subkey in subDict: - subDict[subkey] = {} - subDict = subDict[subkey] - return d - -CLASSIFIERS = _build_classifiers_dict(_CLASSIFIERS_LIST) - - -class MainProgram(object): - def __init__(self): - self.configparser = None - self.classifiers = {} - self.data = {} - self.data['classifier'] = self.classifiers - self.data['packages'] = {} - self.load_config_file() - - def lookup_option(self, key): - if not self.configparser.has_option('DEFAULT', key): - return None - return self.configparser.get('DEFAULT', key) - - def load_config_file(self): - self.configparser = RawConfigParser() - # TODO replace with section in distutils config file - self.configparser.read(os.path.expanduser('~/.mkpkgpy')) - self.data['author'] = self.lookup_option('author') - self.data['author_email'] = self.lookup_option('author_email') - - def update_config_file(self): - valuesDifferent = False - # FIXME looking only for those two fields seems wrong - for compareKey in ('author', 'author_email'): - if self.lookup_option(compareKey) != self.data[compareKey]: - valuesDifferent = True - self.configparser.set('DEFAULT', compareKey, - self.data[compareKey]) - - if not valuesDifferent: - return - - fp = open(os.path.expanduser('~/.mkpkgpy'), 'w') - try: - self.configparser.write(fp) - finally: - fp.close() - - def load_existing_setup_script(self): - raise NotImplementedError - # Ideas: - # - define a mock module to assign to sys.modules['distutils'] before - # importing the setup script as a module (or executing it); it would - # provide setup (a function that just returns its args as a dict), - # Extension (ditto), find_packages (the real function) - # - we could even mock Distribution and commands to handle more setup - # scripts - # - we could use a sandbox (http://bugs.python.org/issue8680) - # - the cleanest way is to parse the file, not import it, but there is - # no way to do that across versions (the compiler package is - # deprecated or removed in recent Pythons, the ast module is not - # present before 2.6) - - def inspect_file(self, path): - fp = open(path, 'r') - try: - for line in [fp.readline() for _ in range(10)]: - m = re.match(r'^#!.*python((?P<major>\d)(\.\d+)?)?$', line) - if m: - if m.group('major') == '3': - self.classifiers['Programming Language :: Python :: 3'] = 1 - else: - self.classifiers['Programming Language :: Python :: 2'] = 1 - finally: - fp.close() - - def inspect_directory(self): - dirName = os.path.basename(os.getcwd()) - self.data['name'] = dirName - m = re.match(r'(.*)-(\d.+)', dirName) - if m: - self.data['name'] = m.group(1) - self.data['version'] = m.group(2) - - for root, dirs, files in os.walk(os.curdir): - for filename in files: - if root == os.curdir and filename == 'setup.py': - continue - self.inspect_file(os.path.join(root, filename)) - - if filename == '__init__.py': - trySrc = os.path.join(os.curdir, 'src') - tmpRoot = root - if tmpRoot.startswith(trySrc): - tmpRoot = tmpRoot[len(trySrc):] - if tmpRoot.startswith(os.path.sep): - tmpRoot = tmpRoot[len(os.path.sep):] - - self.data['packages'][tmpRoot] = root[1 + len(os.path.sep):] - - def query_user(self): - self.data['name'] = ask('Package name', self.data['name'], - _helptext['name']) - self.data['version'] = ask('Current version number', - self.data.get('version'), _helptext['version']) - self.data['description'] = ask('Package description', - self.data.get('description'), _helptext['description'], - lengthy=True) - self.data['author'] = ask('Author name', - self.data.get('author'), _helptext['author']) - self.data['author_email'] = ask('Author e-mail address', - self.data.get('author_email'), _helptext['author_email']) - self.data['url'] = ask('Project URL', - self.data.get('url'), _helptext['url'], required=False) - - if ask_yn('Do you want to set Trove classifiers?', - helptext=_helptext['do_classifier']) == 'y': - self.set_classifier() - - def set_classifier(self): - self.set_devel_status(self.classifiers) - self.set_license(self.classifiers) - self.set_other_classifier(self.classifiers) - - def set_other_classifier(self, classifiers): - if ask_yn('Do you want to set other trove identifiers', 'n', - _helptext['trove_generic']) != 'y': - return - self.walk_classifiers(classifiers, [CLASSIFIERS], '') - - def walk_classifiers(self, classifiers, trovepath, desc): - trove = trovepath[-1] - - if not trove: - return - - for key in sorted(trove.keys()): - if len(trove[key]) == 0: - if ask_yn('Add "%s"' % desc[4:] + ' :: ' + key, 'n') == 'y': - classifiers[desc[4:] + ' :: ' + key] = 1 - continue - - if ask_yn('Do you want to set items under\n "%s" (%d sub-items)' - % (key, len(trove[key])), 'n', - _helptext['trove_generic']) == 'y': - self.walk_classifiers(classifiers, trovepath + [trove[key]], - desc + ' :: ' + key) - - def set_license(self, classifiers): - while True: - license = ask('What license do you use', - helptext=_helptext['trove_license'], required=False) - if not license: - return - - licenseWords = license.lower().split(' ') - - foundList = [] - # TODO use enumerate - for index in range(len(_CLASSIFIERS_LIST)): - troveItem = _CLASSIFIERS_LIST[index] - if not troveItem.startswith('License :: '): - continue - troveItem = troveItem[11:].lower() - - allMatch = True - for word in licenseWords: - if not word in troveItem: - allMatch = False - break - if allMatch: - foundList.append(index) - - question = 'Matching licenses:\n\n' - # TODO use enumerate? - for i in xrange(1, len(foundList) + 1): - question += ' %s) %s\n' % (i, _CLASSIFIERS_LIST[foundList[i - 1]]) - question += ('\nType the number of the license you wish to use or ' - '? to try again:') - troveLicense = ask(question, required=False) - - if troveLicense == '?': - continue - if troveLicense == '': - return - # FIXME the int conversion can fail - foundIndex = foundList[int(troveLicense) - 1] - classifiers[_CLASSIFIERS_LIST[foundIndex]] = 1 - try: - return - except IndexError: - print ("ERROR: Invalid selection, type a number from the list " - "above.") - - def set_devel_status(self, classifiers): - while True: - choice = ask(dedent('''\ - Please select the project status: - - 1 - Planning - 2 - Pre-Alpha - 3 - Alpha - 4 - Beta - 5 - Production/Stable - 6 - Mature - 7 - Inactive - - Status'''), required=False) - if choice: - try: - choice = int(choice) - 1 - key = ['Development Status :: 1 - Planning', - 'Development Status :: 2 - Pre-Alpha', - 'Development Status :: 3 - Alpha', - 'Development Status :: 4 - Beta', - 'Development Status :: 5 - Production/Stable', - 'Development Status :: 6 - Mature', - 'Development Status :: 7 - Inactive'][choice] - classifiers[key] = 1 - return - except (IndexError, ValueError): - print ("ERROR: Invalid selection, type a single digit " - "number.") - - def _dotted_packages(self, data): - packages = sorted(data.keys()) - modified_pkgs = [] - for pkg in packages: - pkg = pkg.lstrip('./') - pkg = pkg.replace('/', '.') - modified_pkgs.append(pkg) - return modified_pkgs - - def write_setup_script(self): - if os.path.exists('setup.py'): - if os.path.exists('setup.py.old'): - print ("ERROR: setup.py.old backup exists, please check that " - "current setup.py is correct and remove setup.py.old") - return - shutil.move('setup.py', 'setup.py.old') - - fp = open('setup.py', 'w') - try: - # XXX do LFs work on all platforms? - fp.write('#!/usr/bin/env python\n\n') - fp.write('from distutils2.core import setup\n\n') - fp.write('setup(name=%s,\n' % repr(self.data['name'])) - fp.write(' version=%s,\n' % repr(self.data['version'])) - fp.write(' description=%s,\n' - % repr(self.data['description'])) - fp.write(' author=%s,\n' % repr(self.data['author'])) - fp.write(' author_email=%s,\n' - % repr(self.data['author_email'])) - if self.data['url']: - fp.write(' url=%s,\n' % repr(self.data['url'])) - if self.data['classifier']: - fp.write(' classifier=[\n') - for classifier in sorted(self.data['classifier'].keys()): - fp.write(' %s,\n' % repr(classifier)) - fp.write(' ],\n') - if self.data['packages']: - fp.write(' packages=%s,\n' - % repr(self._dotted_packages(self.data['packages']))) - fp.write(' package_dir=%s,\n' - % repr(self.data['packages'])) - fp.write(' #scripts=[\'path/to/script\']\n') - - fp.write(' )\n') - finally: - fp.close() - os.chmod('setup.py', 0755) - - print 'Wrote "setup.py".' - - -def main(): - """Main entry point.""" - program = MainProgram() - # uncomment when implemented - #program.load_existing_setup_script() - program.inspect_directory() - program.query_user() - program.update_config_file() - program.write_setup() - - -if __name__ == '__main__': - main() diff --git a/src/distutils2/tests/LONG_DESC.txt b/src/distutils2/tests/LONG_DESC.txt deleted file mode 100644 index 2b4358a..0000000 --- a/src/distutils2/tests/LONG_DESC.txt +++ /dev/null @@ -1,44 +0,0 @@ -CLVault -======= - -CLVault uses Keyring to provide a command-line utility to safely store -and retrieve passwords. - -Install it using pip or the setup.py script:: - - $ python setup.py install - - $ pip install clvault - -Once it's installed, you will have three scripts installed in your -Python scripts folder, you can use to list, store and retrieve passwords:: - - $ clvault-set blog - Set your password: - Set the associated username (can be blank): tarek - Set a description (can be blank): My blog password - Password set. - - $ clvault-get blog - The username is "tarek" - The password has been copied in your clipboard - - $ clvault-list - Registered services: - blog My blog password - - -*clvault-set* takes a service name then prompt you for a password, and some -optional information about your service. The password is safely stored in -a keyring while the description is saved in a ``.clvault`` file in your -home directory. This file is created automatically the first time the command -is used. - -*clvault-get* copies the password for a given service in your clipboard, and -displays the associated user if any. - -*clvault-list* lists all registered services, with their description when -given. - - -Project page: http://bitbucket.org/tarek/clvault diff --git a/src/distutils2/tests/PKG-INFO b/src/distutils2/tests/PKG-INFO deleted file mode 100644 index f48546e..0000000 --- a/src/distutils2/tests/PKG-INFO +++ /dev/null @@ -1,57 +0,0 @@ -Metadata-Version: 1.2 -Name: CLVault -Version: 0.5 -Summary: Command-Line utility to store and retrieve passwords -Home-page: http://bitbucket.org/tarek/clvault -Author: Tarek Ziade -Author-email: tarek@ziade.org -License: PSF -Keywords: keyring,password,crypt -Requires-Dist: foo; sys.platform == 'okook' -Requires-Dist: bar; sys.platform == '%s' -Platform: UNKNOWN -Description: CLVault - |======= - | - |CLVault uses Keyring to provide a command-line utility to safely store - |and retrieve passwords. - | - |Install it using pip or the setup.py script:: - | - | $ python setup.py install - | - | $ pip install clvault - | - |Once it's installed, you will have three scripts installed in your - |Python scripts folder, you can use to list, store and retrieve passwords:: - | - | $ clvault-set blog - | Set your password: - | Set the associated username (can be blank): tarek - | Set a description (can be blank): My blog password - | Password set. - | - | $ clvault-get blog - | The username is "tarek" - | The password has been copied in your clipboard - | - | $ clvault-list - | Registered services: - | blog My blog password - | - | - |*clvault-set* takes a service name then prompt you for a password, and some - |optional information about your service. The password is safely stored in - |a keyring while the description is saved in a ``.clvault`` file in your - |home directory. This file is created automatically the first time the command - |is used. - | - |*clvault-get* copies the password for a given service in your clipboard, and - |displays the associated user if any. - | - |*clvault-list* lists all registered services, with their description when - |given. - | - | - |Project page: http://bitbucket.org/tarek/clvault - | diff --git a/src/distutils2/tests/SETUPTOOLS-PKG-INFO b/src/distutils2/tests/SETUPTOOLS-PKG-INFO deleted file mode 100644 index dff8d00..0000000 --- a/src/distutils2/tests/SETUPTOOLS-PKG-INFO +++ /dev/null @@ -1,182 +0,0 @@ -Metadata-Version: 1.0 -Name: setuptools -Version: 0.6c9 -Summary: Download, build, install, upgrade, and uninstall Python packages -- easily! -Home-page: http://pypi.python.org/pypi/setuptools -Author: Phillip J. Eby -Author-email: distutils-sig@python.org -License: PSF or ZPL -Description: =============================== - Installing and Using Setuptools - =============================== - - .. contents:: **Table of Contents** - - - ------------------------- - Installation Instructions - ------------------------- - - Windows - ======= - - Install setuptools using the provided ``.exe`` installer. If you've previously - installed older versions of setuptools, please delete all ``setuptools*.egg`` - and ``setuptools.pth`` files from your system's ``site-packages`` directory - (and any other ``sys.path`` directories) FIRST. - - If you are upgrading a previous version of setuptools that was installed using - an ``.exe`` installer, please be sure to also *uninstall that older version* - via your system's "Add/Remove Programs" feature, BEFORE installing the newer - version. - - Once installation is complete, you will find an ``easy_install.exe`` program in - your Python ``Scripts`` subdirectory. Be sure to add this directory to your - ``PATH`` environment variable, if you haven't already done so. - - - RPM-Based Systems - ================= - - Install setuptools using the provided source RPM. The included ``.spec`` file - assumes you are installing using the default ``python`` executable, and is not - specific to a particular Python version. The ``easy_install`` executable will - be installed to a system ``bin`` directory such as ``/usr/bin``. - - If you wish to install to a location other than the default Python - installation's default ``site-packages`` directory (and ``$prefix/bin`` for - scripts), please use the ``.egg``-based installation approach described in the - following section. - - - Cygwin, Mac OS X, Linux, Other - ============================== - - 1. Download the appropriate egg for your version of Python (e.g. - ``setuptools-0.6c9-py2.4.egg``). Do NOT rename it. - - 2. Run it as if it were a shell script, e.g. ``sh setuptools-0.6c9-py2.4.egg``. - Setuptools will install itself using the matching version of Python (e.g. - ``python2.4``), and will place the ``easy_install`` executable in the - default location for installing Python scripts (as determined by the - standard distutils configuration files, or by the Python installation). - - If you want to install setuptools to somewhere other than ``site-packages`` or - your default distutils installation locations for libraries and scripts, you - may include EasyInstall command-line options such as ``--prefix``, - ``--install-dir``, and so on, following the ``.egg`` filename on the same - command line. For example:: - - sh setuptools-0.6c9-py2.4.egg --prefix=~ - - You can use ``--help`` to get a full options list, but we recommend consulting - the `EasyInstall manual`_ for detailed instructions, especially `the section - on custom installation locations`_. - - .. _EasyInstall manual: http://peak.telecommunity.com/DevCenter/EasyInstall - .. _the section on custom installation locations: http://peak.telecommunity.com/DevCenter/EasyInstall#custom-installation-locations - - - Cygwin Note - ----------- - - If you are trying to install setuptools for the **Windows** version of Python - (as opposed to the Cygwin version that lives in ``/usr/bin``), you must make - sure that an appropriate executable (``python2.3``, ``python2.4``, or - ``python2.5``) is on your **Cygwin** ``PATH`` when invoking the egg. For - example, doing the following at a Cygwin bash prompt will install setuptools - for the **Windows** Python found at ``C:\\Python24``:: - - ln -s /cygdrive/c/Python24/python.exe python2.4 - PATH=.:$PATH sh setuptools-0.6c9-py2.4.egg - rm python2.4 - - - Downloads - ========= - - All setuptools downloads can be found at `the project's home page in the Python - Package Index`_. Scroll to the very bottom of the page to find the links. - - .. _the project's home page in the Python Package Index: http://pypi.python.org/pypi/setuptools - - In addition to the PyPI downloads, the development version of ``setuptools`` - is available from the `Python SVN sandbox`_, and in-development versions of the - `0.6 branch`_ are available as well. - - .. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 - - .. _Python SVN sandbox: http://svn.python.org/projects/sandbox/trunk/setuptools/#egg=setuptools-dev - - -------------------------------- - Using Setuptools and EasyInstall - -------------------------------- - - Here are some of the available manuals, tutorials, and other resources for - learning about Setuptools, Python Eggs, and EasyInstall: - - * `The EasyInstall user's guide and reference manual`_ - * `The setuptools Developer's Guide`_ - * `The pkg_resources API reference`_ - * `Package Compatibility Notes`_ (user-maintained) - * `The Internal Structure of Python Eggs`_ - - Questions, comments, and bug reports should be directed to the `distutils-sig - mailing list`_. If you have written (or know of) any tutorials, documentation, - plug-ins, or other resources for setuptools users, please let us know about - them there, so this reference list can be updated. If you have working, - *tested* patches to correct problems or add features, you may submit them to - the `setuptools bug tracker`_. - - .. _setuptools bug tracker: http://bugs.python.org/setuptools/ - .. _Package Compatibility Notes: http://peak.telecommunity.com/DevCenter/PackageNotes - .. _The Internal Structure of Python Eggs: http://peak.telecommunity.com/DevCenter/EggFormats - .. _The setuptools Developer's Guide: http://peak.telecommunity.com/DevCenter/setuptools - .. _The pkg_resources API reference: http://peak.telecommunity.com/DevCenter/PkgResources - .. _The EasyInstall user's guide and reference manual: http://peak.telecommunity.com/DevCenter/EasyInstall - .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ - - - ------- - Credits - ------- - - * The original design for the ``.egg`` format and the ``pkg_resources`` API was - co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first - version of ``pkg_resources``, and supplied the OS X operating system version - compatibility algorithm. - - * Ian Bicking implemented many early "creature comfort" features of - easy_install, including support for downloading via Sourceforge and - Subversion repositories. Ian's comments on the Web-SIG about WSGI - application deployment also inspired the concept of "entry points" in eggs, - and he has given talks at PyCon and elsewhere to inform and educate the - community about eggs and setuptools. - - * Jim Fulton contributed time and effort to build automated tests of various - aspects of ``easy_install``, and supplied the doctests for the command-line - ``.exe`` wrappers on Windows. - - * Phillip J. Eby is the principal author and maintainer of setuptools, and - first proposed the idea of an importable binary distribution format for - Python application plug-ins. - - * Significant parts of the implementation of setuptools were funded by the Open - Source Applications Foundation, to provide a plug-in infrastructure for the - Chandler PIM application. In addition, many OSAF staffers (such as Mike - "Code Bear" Taylor) contributed their time and stress as guinea pigs for the - use of eggs and setuptools, even before eggs were "cool". (Thanks, guys!) - - -Keywords: CPAN PyPI distutils eggs package management -Platform: UNKNOWN -Classifier: Development Status :: 3 - Alpha -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Python Software Foundation License -Classifier: License :: OSI Approved :: Zope Public License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: System :: Archiving :: Packaging -Classifier: Topic :: System :: Systems Administration -Classifier: Topic :: Utilities diff --git a/src/distutils2/tests/SETUPTOOLS-PKG-INFO2 b/src/distutils2/tests/SETUPTOOLS-PKG-INFO2 deleted file mode 100644 index 4b3906a..0000000 --- a/src/distutils2/tests/SETUPTOOLS-PKG-INFO2 +++ /dev/null @@ -1,183 +0,0 @@ -Metadata-Version: 1.1 -Name: setuptools -Version: 0.6c9 -Summary: Download, build, install, upgrade, and uninstall Python packages -- easily! -Home-page: http://pypi.python.org/pypi/setuptools -Author: Phillip J. Eby -Author-email: distutils-sig@python.org -License: PSF or ZPL -Description: =============================== - Installing and Using Setuptools - =============================== - - .. contents:: **Table of Contents** - - - ------------------------- - Installation Instructions - ------------------------- - - Windows - ======= - - Install setuptools using the provided ``.exe`` installer. If you've previously - installed older versions of setuptools, please delete all ``setuptools*.egg`` - and ``setuptools.pth`` files from your system's ``site-packages`` directory - (and any other ``sys.path`` directories) FIRST. - - If you are upgrading a previous version of setuptools that was installed using - an ``.exe`` installer, please be sure to also *uninstall that older version* - via your system's "Add/Remove Programs" feature, BEFORE installing the newer - version. - - Once installation is complete, you will find an ``easy_install.exe`` program in - your Python ``Scripts`` subdirectory. Be sure to add this directory to your - ``PATH`` environment variable, if you haven't already done so. - - - RPM-Based Systems - ================= - - Install setuptools using the provided source RPM. The included ``.spec`` file - assumes you are installing using the default ``python`` executable, and is not - specific to a particular Python version. The ``easy_install`` executable will - be installed to a system ``bin`` directory such as ``/usr/bin``. - - If you wish to install to a location other than the default Python - installation's default ``site-packages`` directory (and ``$prefix/bin`` for - scripts), please use the ``.egg``-based installation approach described in the - following section. - - - Cygwin, Mac OS X, Linux, Other - ============================== - - 1. Download the appropriate egg for your version of Python (e.g. - ``setuptools-0.6c9-py2.4.egg``). Do NOT rename it. - - 2. Run it as if it were a shell script, e.g. ``sh setuptools-0.6c9-py2.4.egg``. - Setuptools will install itself using the matching version of Python (e.g. - ``python2.4``), and will place the ``easy_install`` executable in the - default location for installing Python scripts (as determined by the - standard distutils configuration files, or by the Python installation). - - If you want to install setuptools to somewhere other than ``site-packages`` or - your default distutils installation locations for libraries and scripts, you - may include EasyInstall command-line options such as ``--prefix``, - ``--install-dir``, and so on, following the ``.egg`` filename on the same - command line. For example:: - - sh setuptools-0.6c9-py2.4.egg --prefix=~ - - You can use ``--help`` to get a full options list, but we recommend consulting - the `EasyInstall manual`_ for detailed instructions, especially `the section - on custom installation locations`_. - - .. _EasyInstall manual: http://peak.telecommunity.com/DevCenter/EasyInstall - .. _the section on custom installation locations: http://peak.telecommunity.com/DevCenter/EasyInstall#custom-installation-locations - - - Cygwin Note - ----------- - - If you are trying to install setuptools for the **Windows** version of Python - (as opposed to the Cygwin version that lives in ``/usr/bin``), you must make - sure that an appropriate executable (``python2.3``, ``python2.4``, or - ``python2.5``) is on your **Cygwin** ``PATH`` when invoking the egg. For - example, doing the following at a Cygwin bash prompt will install setuptools - for the **Windows** Python found at ``C:\\Python24``:: - - ln -s /cygdrive/c/Python24/python.exe python2.4 - PATH=.:$PATH sh setuptools-0.6c9-py2.4.egg - rm python2.4 - - - Downloads - ========= - - All setuptools downloads can be found at `the project's home page in the Python - Package Index`_. Scroll to the very bottom of the page to find the links. - - .. _the project's home page in the Python Package Index: http://pypi.python.org/pypi/setuptools - - In addition to the PyPI downloads, the development version of ``setuptools`` - is available from the `Python SVN sandbox`_, and in-development versions of the - `0.6 branch`_ are available as well. - - .. _0.6 branch: http://svn.python.org/projects/sandbox/branches/setuptools-0.6/#egg=setuptools-dev06 - - .. _Python SVN sandbox: http://svn.python.org/projects/sandbox/trunk/setuptools/#egg=setuptools-dev - - -------------------------------- - Using Setuptools and EasyInstall - -------------------------------- - - Here are some of the available manuals, tutorials, and other resources for - learning about Setuptools, Python Eggs, and EasyInstall: - - * `The EasyInstall user's guide and reference manual`_ - * `The setuptools Developer's Guide`_ - * `The pkg_resources API reference`_ - * `Package Compatibility Notes`_ (user-maintained) - * `The Internal Structure of Python Eggs`_ - - Questions, comments, and bug reports should be directed to the `distutils-sig - mailing list`_. If you have written (or know of) any tutorials, documentation, - plug-ins, or other resources for setuptools users, please let us know about - them there, so this reference list can be updated. If you have working, - *tested* patches to correct problems or add features, you may submit them to - the `setuptools bug tracker`_. - - .. _setuptools bug tracker: http://bugs.python.org/setuptools/ - .. _Package Compatibility Notes: http://peak.telecommunity.com/DevCenter/PackageNotes - .. _The Internal Structure of Python Eggs: http://peak.telecommunity.com/DevCenter/EggFormats - .. _The setuptools Developer's Guide: http://peak.telecommunity.com/DevCenter/setuptools - .. _The pkg_resources API reference: http://peak.telecommunity.com/DevCenter/PkgResources - .. _The EasyInstall user's guide and reference manual: http://peak.telecommunity.com/DevCenter/EasyInstall - .. _distutils-sig mailing list: http://mail.python.org/pipermail/distutils-sig/ - - - ------- - Credits - ------- - - * The original design for the ``.egg`` format and the ``pkg_resources`` API was - co-created by Phillip Eby and Bob Ippolito. Bob also implemented the first - version of ``pkg_resources``, and supplied the OS X operating system version - compatibility algorithm. - - * Ian Bicking implemented many early "creature comfort" features of - easy_install, including support for downloading via Sourceforge and - Subversion repositories. Ian's comments on the Web-SIG about WSGI - application deployment also inspired the concept of "entry points" in eggs, - and he has given talks at PyCon and elsewhere to inform and educate the - community about eggs and setuptools. - - * Jim Fulton contributed time and effort to build automated tests of various - aspects of ``easy_install``, and supplied the doctests for the command-line - ``.exe`` wrappers on Windows. - - * Phillip J. Eby is the principal author and maintainer of setuptools, and - first proposed the idea of an importable binary distribution format for - Python application plug-ins. - - * Significant parts of the implementation of setuptools were funded by the Open - Source Applications Foundation, to provide a plug-in infrastructure for the - Chandler PIM application. In addition, many OSAF staffers (such as Mike - "Code Bear" Taylor) contributed their time and stress as guinea pigs for the - use of eggs and setuptools, even before eggs were "cool". (Thanks, guys!) - - -Keywords: CPAN PyPI distutils eggs package management -Platform: UNKNOWN -Classifier: Development Status :: 3 - Alpha -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Python Software Foundation License -Classifier: License :: OSI Approved :: Zope Public License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: System :: Archiving :: Packaging -Classifier: Topic :: System :: Systems Administration -Classifier: Topic :: Utilities -Requires: Foo diff --git a/src/distutils2/tests/__init__.py b/src/distutils2/tests/__init__.py deleted file mode 100644 index a459bda..0000000 --- a/src/distutils2/tests/__init__.py +++ /dev/null @@ -1,135 +0,0 @@ -"""Test suite for distutils2. - -This test suite consists of a collection of test modules in the -distutils2.tests package. Each test module has a name starting with -'test' and contains a function test_suite(). The function is expected -to return an initialized unittest.TestSuite instance. - -Tests for the command classes in the distutils2.command package are -included in distutils2.tests as well, instead of using a separate -distutils2.command.tests package, since command identification is done -by import rather than matching pre-defined names. - -Utility code is included in distutils2.tests.support. Always import -unittest from that module, it will be the right version (standard -library unittest for 2.7 and higher, third-party unittest2 release for -older versions). -""" - -import os -import sys -from distutils2.tests.support import unittest - -from test.test_support import TESTFN # use TESTFN from stdlib/test_support. - -here = os.path.dirname(__file__) or os.curdir - -verbose = 1 - -def test_suite(): - suite = unittest.TestSuite() - for fn in os.listdir(here): - if fn.startswith("test") and fn.endswith(".py"): - modname = "distutils2.tests." + fn[:-3] - __import__(modname) - module = sys.modules[modname] - suite.addTest(module.test_suite()) - return suite - -class Error(Exception): - """Base class for regression test exceptions.""" - - -class TestFailed(Error): - """Test failed.""" - - -class BasicTestRunner(object): - def run(self, test): - result = unittest.TestResult() - test(result) - return result - - -def _run_suite(suite, verbose_=1): - """Run tests from a unittest.TestSuite-derived class.""" - global verbose - verbose = verbose_ - if verbose_: - runner = unittest.TextTestRunner(sys.stdout, verbosity=2) - else: - runner = BasicTestRunner() - - result = runner.run(suite) - if not result.wasSuccessful(): - if len(result.errors) == 1 and not result.failures: - err = result.errors[0][1] - elif len(result.failures) == 1 and not result.errors: - err = result.failures[0][1] - else: - err = "errors occurred; run in verbose mode for details" - raise TestFailed(err) - - -def run_unittest(classes, verbose_=1): - """Run tests from unittest.TestCase-derived classes. - - Extracted from stdlib test.test_support and modified to support unittest. - """ - valid_types = (unittest.TestSuite, unittest.TestCase) - suite = unittest.TestSuite() - for cls in classes: - if isinstance(cls, str): - if cls in sys.modules: - suite.addTest(unittest.findTestCases(sys.modules[cls])) - else: - raise ValueError("str arguments must be keys in sys.modules") - elif isinstance(cls, valid_types): - suite.addTest(cls) - else: - suite.addTest(unittest.makeSuite(cls)) - _run_suite(suite, verbose_) - - -def reap_children(): - """Use this function at the end of test_main() whenever sub-processes - are started. This will help ensure that no extra children (zombies) - stick around to hog resources and create problems when looking - for refleaks. - - Extracted from stdlib test.test_support. - """ - - # Reap all our dead child processes so we don't leave zombies around. - # These hog resources and might be causing some of the buildbots to die. - if hasattr(os, 'waitpid'): - any_process = -1 - while True: - try: - # This will raise an exception on Windows. That's ok. - pid, status = os.waitpid(any_process, os.WNOHANG) - if pid == 0: - break - except: - break - -def captured_stdout(func, *args, **kw): - import StringIO - orig_stdout = getattr(sys, 'stdout') - setattr(sys, 'stdout', StringIO.StringIO()) - try: - res = func(*args, **kw) - sys.stdout.seek(0) - return res, sys.stdout.read() - finally: - setattr(sys, 'stdout', orig_stdout) - -def unload(name): - try: - del sys.modules[name] - except KeyError: - pass - - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/conversions/01_after.py b/src/distutils2/tests/conversions/01_after.py deleted file mode 100644 index 93f818a..0000000 --- a/src/distutils2/tests/conversions/01_after.py +++ /dev/null @@ -1,4 +0,0 @@ -from distutils2.core import setup - -setup(name='Foo') - diff --git a/src/distutils2/tests/conversions/01_before.py b/src/distutils2/tests/conversions/01_before.py deleted file mode 100644 index 3e818d8..0000000 --- a/src/distutils2/tests/conversions/01_before.py +++ /dev/null @@ -1,4 +0,0 @@ -from distutils.core import setup - -setup(name='Foo') - diff --git a/src/distutils2/tests/conversions/02_after.py b/src/distutils2/tests/conversions/02_after.py deleted file mode 100644 index bfc2d8f..0000000 --- a/src/distutils2/tests/conversions/02_after.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- encoding: utf-8 -*- -import sys -import os -from distutils2.core import setup, Extension -from distutils2.errors import CCompilerError, DistutilsError, CompileError -from distutils2.command.build_ext import build_ext as distutils_build_ext - -VERSION = "0.1" - -class build_ext(distutils_build_ext): - - def build_extension(self, ext): - try: - return distutils_build_ext.build_extension(self, ext) - except (CCompilerError, DistutilsError, CompileError), e: - pass - -def _get_ext_modules(): - levenshtein = Extension('_levenshtein', - sources=[os.path.join('texttools', - '_levenshtein.c')]) - return [levenshtein] - -with open('README.txt') as f: - LONG_DESCRIPTION = f.read() - -setup(name="TextTools", version=VERSION, author="Tarek Ziade", - author_email="tarek@ziade.org", - home_page="http://bitbucket.org/tarek/texttools", - summary="Text manipulation utilities", - description=LONG_DESCRIPTION, - keywords="text,guess,levenshtein", - classifiers=[ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Python Software Foundation License' - ], - cmdclass={'build_ext': build_ext}, - packages=['texttools'], - package_dir={'texttools': 'texttools'}, - package_data={'texttools': [os.path.join('samples', '*.txt')]}, - scripts=[os.path.join('scripts', 'levenshtein.py'), - os.path.join('scripts', 'guesslang.py')], - ext_modules=_get_ext_modules() - ) - diff --git a/src/distutils2/tests/conversions/02_before.py b/src/distutils2/tests/conversions/02_before.py deleted file mode 100644 index f7ccc12..0000000 --- a/src/distutils2/tests/conversions/02_before.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- encoding: utf-8 -*- -import sys -import os -from distutils.core import setup, Extension -from distutils.errors import CCompilerError, DistutilsError, CompileError -from distutils.command.build_ext import build_ext as distutils_build_ext - -VERSION = "0.1" - -class build_ext(distutils_build_ext): - - def build_extension(self, ext): - try: - return distutils_build_ext.build_extension(self, ext) - except (CCompilerError, DistutilsError, CompileError), e: - pass - -def _get_ext_modules(): - levenshtein = Extension('_levenshtein', - sources=[os.path.join('texttools', - '_levenshtein.c')]) - return [levenshtein] - -with open('README.txt') as f: - LONG_DESCRIPTION = f.read() - -setup(name="TextTools", version=VERSION, author="Tarek Ziade", - author_email="tarek@ziade.org", - url="http://bitbucket.org/tarek/texttools", - description="Text manipulation utilities", - long_description=LONG_DESCRIPTION, - keywords="text,guess,levenshtein", - classifiers=[ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Python Software Foundation License' - ], - cmdclass={'build_ext': build_ext}, - packages=['texttools'], - package_dir={'texttools': 'texttools'}, - package_data={'texttools': [os.path.join('samples', '*.txt')]}, - scripts=[os.path.join('scripts', 'levenshtein.py'), - os.path.join('scripts', 'guesslang.py')], - ext_modules=_get_ext_modules() - ) - diff --git a/src/distutils2/tests/conversions/03_after.py b/src/distutils2/tests/conversions/03_after.py deleted file mode 100644 index 3d4dafa..0000000 --- a/src/distutils2/tests/conversions/03_after.py +++ /dev/null @@ -1,93 +0,0 @@ -############################################################################## -# -# Copyright (c) 2006-2009 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -name = "zc.buildout" -version = "1.5.0dev" - -import os -from distutils2.core import setup - -def read(*rnames): - return open(os.path.join(os.path.dirname(__file__), *rnames)).read() - -long_description=( - read('README.txt') - + '\n' + - 'Detailed Documentation\n' - '**********************\n' - + '\n' + - read('src', 'zc', 'buildout', 'buildout.txt') - + '\n' + - read('src', 'zc', 'buildout', 'unzip.txt') - + '\n' + - read('src', 'zc', 'buildout', 'repeatable.txt') - + '\n' + - read('src', 'zc', 'buildout', 'download.txt') - + '\n' + - read('src', 'zc', 'buildout', 'downloadcache.txt') - + '\n' + - read('src', 'zc', 'buildout', 'extends-cache.txt') - + '\n' + - read('src', 'zc', 'buildout', 'setup.txt') - + '\n' + - read('src', 'zc', 'buildout', 'update.txt') - + '\n' + - read('src', 'zc', 'buildout', 'debugging.txt') - + '\n' + - read('src', 'zc', 'buildout', 'testing.txt') - + '\n' + - read('src', 'zc', 'buildout', 'easy_install.txt') - + '\n' + - read('src', 'zc', 'buildout', 'distribute.txt') - + '\n' + - read('CHANGES.txt') - + '\n' + - 'Download\n' - '**********************\n' - ) - -entry_points = """ -[console_scripts] -buildout = %(name)s.buildout:main - -[zc.buildout] -debug = %(name)s.testrecipes:Debug - -""" % dict(name=name) - -setup( - name = name, - version = version, - author = "Jim Fulton", - author_email = "jim@zope.com", - summary = "System for managing development buildouts", - description=long_description, - license = "ZPL 2.1", - keywords = "development build", - home_page='http://buildout.org', - - data_files = [('.', ['README.txt'])], - packages = ['zc', 'zc.buildout'], - package_dir = {'': 'src'}, - namespace_packages = ['zc'], - requires_dist = ['setuptools'], - include_package_data = True, - entry_points = entry_points, - zip_safe=False, - classifiers = [ - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Zope Public License', - 'Topic :: Software Development :: Build Tools', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - ) diff --git a/src/distutils2/tests/conversions/03_before.py b/src/distutils2/tests/conversions/03_before.py deleted file mode 100644 index 31a99fc..0000000 --- a/src/distutils2/tests/conversions/03_before.py +++ /dev/null @@ -1,93 +0,0 @@ -############################################################################## -# -# Copyright (c) 2006-2009 Zope Corporation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -name = "zc.buildout" -version = "1.5.0dev" - -import os -from setuptools import setup - -def read(*rnames): - return open(os.path.join(os.path.dirname(__file__), *rnames)).read() - -long_description=( - read('README.txt') - + '\n' + - 'Detailed Documentation\n' - '**********************\n' - + '\n' + - read('src', 'zc', 'buildout', 'buildout.txt') - + '\n' + - read('src', 'zc', 'buildout', 'unzip.txt') - + '\n' + - read('src', 'zc', 'buildout', 'repeatable.txt') - + '\n' + - read('src', 'zc', 'buildout', 'download.txt') - + '\n' + - read('src', 'zc', 'buildout', 'downloadcache.txt') - + '\n' + - read('src', 'zc', 'buildout', 'extends-cache.txt') - + '\n' + - read('src', 'zc', 'buildout', 'setup.txt') - + '\n' + - read('src', 'zc', 'buildout', 'update.txt') - + '\n' + - read('src', 'zc', 'buildout', 'debugging.txt') - + '\n' + - read('src', 'zc', 'buildout', 'testing.txt') - + '\n' + - read('src', 'zc', 'buildout', 'easy_install.txt') - + '\n' + - read('src', 'zc', 'buildout', 'distribute.txt') - + '\n' + - read('CHANGES.txt') - + '\n' + - 'Download\n' - '**********************\n' - ) - -entry_points = """ -[console_scripts] -buildout = %(name)s.buildout:main - -[zc.buildout] -debug = %(name)s.testrecipes:Debug - -""" % dict(name=name) - -setup( - name = name, - version = version, - author = "Jim Fulton", - author_email = "jim@zope.com", - description = "System for managing development buildouts", - long_description=long_description, - license = "ZPL 2.1", - keywords = "development build", - url='http://buildout.org', - - data_files = [('.', ['README.txt'])], - packages = ['zc', 'zc.buildout'], - package_dir = {'': 'src'}, - namespace_packages = ['zc'], - install_requires = 'setuptools', - include_package_data = True, - entry_points = entry_points, - zip_safe=False, - classifiers = [ - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Zope Public License', - 'Topic :: Software Development :: Build Tools', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - ) diff --git a/src/distutils2/tests/conversions/04_after.py b/src/distutils2/tests/conversions/04_after.py deleted file mode 100644 index f366a48..0000000 --- a/src/distutils2/tests/conversions/04_after.py +++ /dev/null @@ -1,69 +0,0 @@ -import sys, os -try: - from distutils2.core import setup - kw = {'entry_points': - """[console_scripts]\nvirtualenv = virtualenv:main\n""", - 'zip_safe': False} -except ImportError: - from distutils2.core import setup - if sys.platform == 'win32': - print('Note: without Setuptools installed you will have to use "python -m virtualenv ENV"') - else: - kw = {'scripts': ['scripts/virtualenv']} -import re - -here = os.path.dirname(os.path.abspath(__file__)) - -## Figure out the version from virtualenv.py: -version_re = re.compile( - r'virtualenv_version = "(.*?)"') -fp = open(os.path.join(here, 'virtualenv.py')) -version = None -for line in fp: - match = version_re.search(line) - if match: - version = match.group(1) - break -else: - raise Exception("Cannot find version in virtualenv.py") -fp.close() - -## Get long_description from index.txt: -f = open(os.path.join(here, 'docs', 'index.txt')) -long_description = f.read().strip() -long_description = long_description.split('split here', 1)[1] -f.close() - -## A warning just for Ian (related to distribution): -try: - import getpass -except ImportError: - is_ianb = False -else: - is_ianb = getpass.getuser() == 'ianb' - -if is_ianb and 'register' in sys.argv: - if 'hg tip\n~~~~~~' in long_description: - print >> sys.stderr, ( - "WARNING: hg tip is in index.txt") - -setup(name='virtualenv', - version=version, - summary="Virtual Python Environment builder", - description=long_description, - classifiers=[ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - ], - keywords='setuptools deployment installation distutils', - author='Ian Bicking', - author_email='ianb@colorstudy.com', - home_page='http://virtualenv.openplans.org', - license='MIT', - use_2to3=True, - py_modules=['virtualenv'], - packages=['virtualenv_support'], - package_data={'virtualenv_support': ['*-py%s.egg' % sys.version[:3], '*.tar.gz']}, - **kw - ) diff --git a/src/distutils2/tests/conversions/04_before.py b/src/distutils2/tests/conversions/04_before.py deleted file mode 100644 index 4792595..0000000 --- a/src/distutils2/tests/conversions/04_before.py +++ /dev/null @@ -1,69 +0,0 @@ -import sys, os -try: - from setuptools import setup - kw = {'entry_points': - """[console_scripts]\nvirtualenv = virtualenv:main\n""", - 'zip_safe': False} -except ImportError: - from distutils.core import setup - if sys.platform == 'win32': - print('Note: without Setuptools installed you will have to use "python -m virtualenv ENV"') - else: - kw = {'scripts': ['scripts/virtualenv']} -import re - -here = os.path.dirname(os.path.abspath(__file__)) - -## Figure out the version from virtualenv.py: -version_re = re.compile( - r'virtualenv_version = "(.*?)"') -fp = open(os.path.join(here, 'virtualenv.py')) -version = None -for line in fp: - match = version_re.search(line) - if match: - version = match.group(1) - break -else: - raise Exception("Cannot find version in virtualenv.py") -fp.close() - -## Get long_description from index.txt: -f = open(os.path.join(here, 'docs', 'index.txt')) -long_description = f.read().strip() -long_description = long_description.split('split here', 1)[1] -f.close() - -## A warning just for Ian (related to distribution): -try: - import getpass -except ImportError: - is_ianb = False -else: - is_ianb = getpass.getuser() == 'ianb' - -if is_ianb and 'register' in sys.argv: - if 'hg tip\n~~~~~~' in long_description: - print >> sys.stderr, ( - "WARNING: hg tip is in index.txt") - -setup(name='virtualenv', - version=version, - description="Virtual Python Environment builder", - long_description=long_description, - classifiers=[ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - ], - keywords='setuptools deployment installation distutils', - author='Ian Bicking', - author_email='ianb@colorstudy.com', - url='http://virtualenv.openplans.org', - license='MIT', - use_2to3=True, - py_modules=['virtualenv'], - packages=['virtualenv_support'], - package_data={'virtualenv_support': ['*-py%s.egg' % sys.version[:3], '*.tar.gz']}, - **kw - ) diff --git a/src/distutils2/tests/conversions/05_after.py b/src/distutils2/tests/conversions/05_after.py deleted file mode 100644 index 2f6a7b3..0000000 --- a/src/distutils2/tests/conversions/05_after.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2003-2009 Edgewall Software -# All rights reserved. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at http://trac.edgewall.org/wiki/TracLicense. -# -# This software consists of voluntary contributions made by many -# individuals. For the exact contribution history, see the revision -# history and logs, available at http://trac.edgewall.org/log/. - -from distutils2.core import setup, find_packages - -extra = {} - -try: - import babel - - extractors = [ - ('**.py', 'python', None), - ('**/templates/**.html', 'genshi', None), - ('**/templates/**.txt', 'genshi', - {'template_class': 'genshi.template:NewTextTemplate'}), - ] - extra['message_extractors'] = { - 'trac': extractors, - 'tracopt': extractors, - } - - from trac.util.dist import get_l10n_js_cmdclass - extra['cmdclass'] = get_l10n_js_cmdclass() - -except ImportError, e: - pass - -setup( - name = 'Trac', - version = '0.12.1', - summary = 'Integrated SCM, wiki, issue tracker and project environment', - description = """ -Trac is a minimalistic web-based software project management and bug/issue -tracking system. It provides an interface to the Subversion revision control -systems, an integrated wiki, flexible issue tracking and convenient report -facilities. -""", - author = 'Edgewall Software', - author_email = 'info@edgewall.com', - license = 'BSD', - home_page = 'http://trac.edgewall.org/', - download_url = 'http://trac.edgewall.org/wiki/TracDownload', - classifiers = [ - 'Environment :: Web Environment', - 'Framework :: Trac', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Software Development :: Bug Tracking', - 'Topic :: Software Development :: Version Control', - ], - - packages = find_packages(exclude=['*.tests']), - package_data = { - '': ['templates/*'], - 'trac': ['htdocs/*.*', 'htdocs/README', 'htdocs/js/*.*', - 'htdocs/js/messages/*.*', 'htdocs/css/*.*', - 'htdocs/guide/*', 'locale/*/LC_MESSAGES/messages.mo'], - 'trac.wiki': ['default-pages/*'], - 'trac.ticket': ['workflows/*.ini'], - }, - - test_suite = 'trac.test.suite', - zip_safe = True, - - requires_dist = [ - 'setuptools>=0.6b1', - 'Genshi>=0.6', - ], - extras_require = { - 'Babel': ['Babel>=0.9.5'], - 'Pygments': ['Pygments>=0.6'], - 'reST': ['docutils>=0.3'], - 'SilverCity': ['SilverCity>=0.9.4'], - 'Textile': ['textile>=2.0'], - }, - - entry_points = """ - [console_scripts] - trac-admin = trac.admin.console:run - tracd = trac.web.standalone:main - - [trac.plugins] - trac.about = trac.about - trac.admin.console = trac.admin.console - trac.admin.web_ui = trac.admin.web_ui - trac.attachment = trac.attachment - trac.db.mysql = trac.db.mysql_backend - trac.db.postgres = trac.db.postgres_backend - trac.db.sqlite = trac.db.sqlite_backend - trac.mimeview.patch = trac.mimeview.patch - trac.mimeview.pygments = trac.mimeview.pygments[Pygments] - trac.mimeview.rst = trac.mimeview.rst[reST] - trac.mimeview.silvercity = trac.mimeview.silvercity[SilverCity] - trac.mimeview.txtl = trac.mimeview.txtl[Textile] - trac.prefs = trac.prefs.web_ui - trac.search = trac.search.web_ui - trac.ticket.admin = trac.ticket.admin - trac.ticket.query = trac.ticket.query - trac.ticket.report = trac.ticket.report - trac.ticket.roadmap = trac.ticket.roadmap - trac.ticket.web_ui = trac.ticket.web_ui - trac.timeline = trac.timeline.web_ui - trac.versioncontrol.admin = trac.versioncontrol.admin - trac.versioncontrol.svn_authz = trac.versioncontrol.svn_authz - trac.versioncontrol.svn_fs = trac.versioncontrol.svn_fs - trac.versioncontrol.svn_prop = trac.versioncontrol.svn_prop - trac.versioncontrol.web_ui = trac.versioncontrol.web_ui - trac.web.auth = trac.web.auth - trac.web.session = trac.web.session - trac.wiki.admin = trac.wiki.admin - trac.wiki.interwiki = trac.wiki.interwiki - trac.wiki.macros = trac.wiki.macros - trac.wiki.web_ui = trac.wiki.web_ui - trac.wiki.web_api = trac.wiki.web_api - tracopt.mimeview.enscript = tracopt.mimeview.enscript - tracopt.mimeview.php = tracopt.mimeview.php - tracopt.perm.authz_policy = tracopt.perm.authz_policy - tracopt.perm.config_perm_provider = tracopt.perm.config_perm_provider - tracopt.ticket.commit_updater = tracopt.ticket.commit_updater - tracopt.ticket.deleter = tracopt.ticket.deleter - """, - - **extra -) diff --git a/src/distutils2/tests/conversions/05_before.py b/src/distutils2/tests/conversions/05_before.py deleted file mode 100755 index ccce17b..0000000 --- a/src/distutils2/tests/conversions/05_before.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright (C) 2003-2009 Edgewall Software -# All rights reserved. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at http://trac.edgewall.org/wiki/TracLicense. -# -# This software consists of voluntary contributions made by many -# individuals. For the exact contribution history, see the revision -# history and logs, available at http://trac.edgewall.org/log/. - -from setuptools import setup, find_packages - -extra = {} - -try: - import babel - - extractors = [ - ('**.py', 'python', None), - ('**/templates/**.html', 'genshi', None), - ('**/templates/**.txt', 'genshi', - {'template_class': 'genshi.template:NewTextTemplate'}), - ] - extra['message_extractors'] = { - 'trac': extractors, - 'tracopt': extractors, - } - - from trac.util.dist import get_l10n_js_cmdclass - extra['cmdclass'] = get_l10n_js_cmdclass() - -except ImportError, e: - pass - -setup( - name = 'Trac', - version = '0.12.1', - description = 'Integrated SCM, wiki, issue tracker and project environment', - long_description = """ -Trac is a minimalistic web-based software project management and bug/issue -tracking system. It provides an interface to the Subversion revision control -systems, an integrated wiki, flexible issue tracking and convenient report -facilities. -""", - author = 'Edgewall Software', - author_email = 'info@edgewall.com', - license = 'BSD', - url = 'http://trac.edgewall.org/', - download_url = 'http://trac.edgewall.org/wiki/TracDownload', - classifiers = [ - 'Environment :: Web Environment', - 'Framework :: Trac', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', - 'Topic :: Software Development :: Bug Tracking', - 'Topic :: Software Development :: Version Control', - ], - - packages = find_packages(exclude=['*.tests']), - package_data = { - '': ['templates/*'], - 'trac': ['htdocs/*.*', 'htdocs/README', 'htdocs/js/*.*', - 'htdocs/js/messages/*.*', 'htdocs/css/*.*', - 'htdocs/guide/*', 'locale/*/LC_MESSAGES/messages.mo'], - 'trac.wiki': ['default-pages/*'], - 'trac.ticket': ['workflows/*.ini'], - }, - - test_suite = 'trac.test.suite', - zip_safe = True, - - install_requires = [ - 'setuptools>=0.6b1', - 'Genshi>=0.6', - ], - extras_require = { - 'Babel': ['Babel>=0.9.5'], - 'Pygments': ['Pygments>=0.6'], - 'reST': ['docutils>=0.3'], - 'SilverCity': ['SilverCity>=0.9.4'], - 'Textile': ['textile>=2.0'], - }, - - entry_points = """ - [console_scripts] - trac-admin = trac.admin.console:run - tracd = trac.web.standalone:main - - [trac.plugins] - trac.about = trac.about - trac.admin.console = trac.admin.console - trac.admin.web_ui = trac.admin.web_ui - trac.attachment = trac.attachment - trac.db.mysql = trac.db.mysql_backend - trac.db.postgres = trac.db.postgres_backend - trac.db.sqlite = trac.db.sqlite_backend - trac.mimeview.patch = trac.mimeview.patch - trac.mimeview.pygments = trac.mimeview.pygments[Pygments] - trac.mimeview.rst = trac.mimeview.rst[reST] - trac.mimeview.silvercity = trac.mimeview.silvercity[SilverCity] - trac.mimeview.txtl = trac.mimeview.txtl[Textile] - trac.prefs = trac.prefs.web_ui - trac.search = trac.search.web_ui - trac.ticket.admin = trac.ticket.admin - trac.ticket.query = trac.ticket.query - trac.ticket.report = trac.ticket.report - trac.ticket.roadmap = trac.ticket.roadmap - trac.ticket.web_ui = trac.ticket.web_ui - trac.timeline = trac.timeline.web_ui - trac.versioncontrol.admin = trac.versioncontrol.admin - trac.versioncontrol.svn_authz = trac.versioncontrol.svn_authz - trac.versioncontrol.svn_fs = trac.versioncontrol.svn_fs - trac.versioncontrol.svn_prop = trac.versioncontrol.svn_prop - trac.versioncontrol.web_ui = trac.versioncontrol.web_ui - trac.web.auth = trac.web.auth - trac.web.session = trac.web.session - trac.wiki.admin = trac.wiki.admin - trac.wiki.interwiki = trac.wiki.interwiki - trac.wiki.macros = trac.wiki.macros - trac.wiki.web_ui = trac.wiki.web_ui - trac.wiki.web_api = trac.wiki.web_api - tracopt.mimeview.enscript = tracopt.mimeview.enscript - tracopt.mimeview.php = tracopt.mimeview.php - tracopt.perm.authz_policy = tracopt.perm.authz_policy - tracopt.perm.config_perm_provider = tracopt.perm.config_perm_provider - tracopt.ticket.commit_updater = tracopt.ticket.commit_updater - tracopt.ticket.deleter = tracopt.ticket.deleter - """, - - **extra -) diff --git a/src/distutils2/tests/fixer/__init__.py b/src/distutils2/tests/fixer/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/tests/fixer/__init__.py +++ /dev/null diff --git a/src/distutils2/tests/fixer/fix_idioms.py b/src/distutils2/tests/fixer/fix_idioms.py deleted file mode 100644 index 9cfac51..0000000 --- a/src/distutils2/tests/fixer/fix_idioms.py +++ /dev/null @@ -1,134 +0,0 @@ -"""Adjust some old Python 2 idioms to their modern counterparts. - -* Change some type comparisons to isinstance() calls: - type(x) == T -> isinstance(x, T) - type(x) is T -> isinstance(x, T) - type(x) != T -> not isinstance(x, T) - type(x) is not T -> not isinstance(x, T) - -* Change "while 1:" into "while True:". - -* Change both - - v = list(EXPR) - v.sort() - foo(v) - -and the more general - - v = EXPR - v.sort() - foo(v) - -into - - v = sorted(EXPR) - foo(v) -""" -# Author: Jacques Frechet, Collin Winter - -# Local imports -from lib2to3 import fixer_base -from lib2to3.fixer_util import Call, Comma, Name, Node, syms - -CMP = "(n='!=' | '==' | 'is' | n=comp_op< 'is' 'not' >)" -TYPE = "power< 'type' trailer< '(' x=any ')' > >" - -class FixIdioms(fixer_base.BaseFix): - - explicit = False # The user must ask for this fixer - - PATTERN = r""" - isinstance=comparison< %s %s T=any > - | - isinstance=comparison< T=any %s %s > - | - while_stmt< 'while' while='1' ':' any+ > - | - sorted=any< - any* - simple_stmt< - expr_stmt< id1=any '=' - power< list='list' trailer< '(' (not arglist<any+>) any ')' > > - > - '\n' - > - sort= - simple_stmt< - power< id2=any - trailer< '.' 'sort' > trailer< '(' ')' > - > - '\n' - > - next=any* - > - | - sorted=any< - any* - simple_stmt< expr_stmt< id1=any '=' expr=any > '\n' > - sort= - simple_stmt< - power< id2=any - trailer< '.' 'sort' > trailer< '(' ')' > - > - '\n' - > - next=any* - > - """ % (TYPE, CMP, CMP, TYPE) - - def match(self, node): - r = super(FixIdioms, self).match(node) - # If we've matched one of the sort/sorted subpatterns above, we - # want to reject matches where the initial assignment and the - # subsequent .sort() call involve different identifiers. - if r and "sorted" in r: - if r["id1"] == r["id2"]: - return r - return None - return r - - def transform(self, node, results): - if "isinstance" in results: - return self.transform_isinstance(node, results) - elif "while" in results: - return self.transform_while(node, results) - elif "sorted" in results: - return self.transform_sort(node, results) - else: - raise RuntimeError("Invalid match") - - def transform_isinstance(self, node, results): - x = results["x"].clone() # The thing inside of type() - T = results["T"].clone() # The type being compared against - x.set_prefix("") - T.set_prefix(" ") - test = Call(Name("isinstance"), [x, Comma(), T]) - if "n" in results: - test.set_prefix(" ") - test = Node(syms.not_test, [Name("not"), test]) - test.set_prefix(node.get_prefix()) - return test - - def transform_while(self, node, results): - one = results["while"] - one.replace(Name("True", prefix=one.get_prefix())) - - def transform_sort(self, node, results): - sort_stmt = results["sort"] - next_stmt = results["next"] - list_call = results.get("list") - simple_expr = results.get("expr") - - if list_call: - list_call.replace(Name("sorted", prefix=list_call.get_prefix())) - elif simple_expr: - new = simple_expr.clone() - new.set_prefix("") - simple_expr.replace(Call(Name("sorted"), [new], - prefix=simple_expr.get_prefix())) - else: - raise RuntimeError("should not have reached here") - sort_stmt.remove() - if next_stmt: - next_stmt[0].set_prefix(sort_stmt.get_prefix()) diff --git a/src/distutils2/tests/pypi_server.py b/src/distutils2/tests/pypi_server.py deleted file mode 100644 index 2db4577..0000000 --- a/src/distutils2/tests/pypi_server.py +++ /dev/null @@ -1,428 +0,0 @@ -"""Mock PyPI Server implementation, to use in tests. - -This module also provides a simple test case to extend if you need to use -the PyPIServer all along your test case. Be sure to read the documentation -before any use. - -XXX TODO: - -The mock server can handle simple HTTP request (to simulate a simple index) or -XMLRPC requests, over HTTP. Both does not have the same intergface to deal -with, and I think it's a pain. - -A good idea could be to re-think a bit the way dstributions are handled in the -mock server. As it should return malformed HTML pages, we need to keep the -static behavior. - -I think of something like that: - - >>> server = PyPIMockServer() - >>> server.startHTTP() - >>> server.startXMLRPC() - -Then, the server must have only one port to rely on, eg. - - >>> server.fulladress() - "http://ip:port/" - -It could be simple to have one HTTP server, relaying the requests to the two -implementations (static HTTP and XMLRPC over HTTP). -""" - -import Queue -import SocketServer -import os.path -import select -import socket -import threading - -from BaseHTTPServer import HTTPServer -from SimpleHTTPServer import SimpleHTTPRequestHandler -from SimpleXMLRPCServer import SimpleXMLRPCServer - -from distutils2.tests.support import unittest - -PYPI_DEFAULT_STATIC_PATH = os.path.dirname(os.path.abspath(__file__)) + "/pypiserver" - -def use_xmlrpc_server(*server_args, **server_kwargs): - server_kwargs['serve_xmlrpc'] = True - return use_pypi_server(*server_args, **server_kwargs) - -def use_http_server(*server_args, **server_kwargs): - server_kwargs['serve_xmlrpc'] = False - return use_pypi_server(*server_args, **server_kwargs) - -def use_pypi_server(*server_args, **server_kwargs): - """Decorator to make use of the PyPIServer for test methods, - just when needed, and not for the entire duration of the testcase. - """ - def wrapper(func): - def wrapped(*args, **kwargs): - server = PyPIServer(*server_args, **server_kwargs) - server.start() - try: - func(server=server, *args, **kwargs) - finally: - server.stop() - return wrapped - return wrapper - -class PyPIServerTestCase(unittest.TestCase): - - def setUp(self): - super(PyPIServerTestCase, self).setUp() - self.pypi = PyPIServer() - self.pypi.start() - - def tearDown(self): - super(PyPIServerTestCase, self).tearDown() - self.pypi.stop() - -class PyPIServer(threading.Thread): - """PyPI Mocked server. - Provides a mocked version of the PyPI API's, to ease tests. - - Support serving static content and serving previously given text. - """ - - def __init__(self, test_static_path=None, - static_filesystem_paths=["default"], - static_uri_paths=["simple"], serve_xmlrpc=False) : - """Initialize the server. - - Default behavior is to start the HTTP server. You can either start the - xmlrpc server by setting xmlrpc to True. Caution: Only one server will - be started. - - static_uri_paths and static_base_path are parameters used to provides - respectively the http_paths to serve statically, and where to find the - matching files on the filesystem. - """ - # we want to launch the server in a new dedicated thread, to not freeze - # tests. - threading.Thread.__init__(self) - self._run = True - self._serve_xmlrpc = serve_xmlrpc - - #TODO allow to serve XMLRPC and HTTP static files at the same time. - if not self._serve_xmlrpc: - self.server = HTTPServer(('', 0), PyPIRequestHandler) - self.server.RequestHandlerClass.pypi_server = self - - self.request_queue = Queue.Queue() - self._requests = [] - self.default_response_status = 200 - self.default_response_headers = [('Content-type', 'text/plain')] - self.default_response_data = "hello" - - # initialize static paths / filesystems - self.static_uri_paths = static_uri_paths - if test_static_path is not None: - static_filesystem_paths.append(test_static_path) - self.static_filesystem_paths = [PYPI_DEFAULT_STATIC_PATH + "/" + path - for path in static_filesystem_paths] - else: - # XMLRPC server - self.server = PyPIXMLRPCServer(('', 0)) - self.xmlrpc = XMLRPCMockIndex() - # register the xmlrpc methods - self.server.register_introspection_functions() - self.server.register_instance(self.xmlrpc) - - self.address = (self.server.server_name, self.server.server_port) - # to not have unwanted outputs. - self.server.RequestHandlerClass.log_request = lambda *_: None - - def run(self): - # loop because we can't stop it otherwise, for python < 2.6 - while self._run: - r, w, e = select.select([self.server], [], [], 0.5) - if r: - self.server.handle_request() - - def stop(self): - """self shutdown is not supported for python < 2.6""" - self._run = False - - def get_next_response(self): - return (self.default_response_status, - self.default_response_headers, - self.default_response_data) - - @property - def requests(self): - """Use this property to get all requests that have been made - to the server - """ - while True: - try: - self._requests.append(self.request_queue.get_nowait()) - except Queue.Empty: - break - return self._requests - - @property - def full_address(self): - return "http://%s:%s" % self.address - - -class PyPIRequestHandler(SimpleHTTPRequestHandler): - # we need to access the pypi server while serving the content - pypi_server = None - - def do_POST(self): - return self.serve_request() - def do_GET(self): - return self.serve_request() - def do_DELETE(self): - return self.serve_request() - def do_PUT(self): - return self.serve_request() - - def serve_request(self): - """Serve the content. - - Also record the requests to be accessed later. If trying to access an - url matching a static uri, serve static content, otherwise serve - what is provided by the `get_next_response` method. - """ - # record the request. Read the input only on PUT or POST requests - if self.command in ("PUT", "POST"): - if 'content-length' in self.headers.dict: - request_data = self.rfile.read( - int(self.headers['content-length'])) - else: - request_data = self.rfile.read() - elif self.command in ("GET", "DELETE"): - request_data = '' - - self.pypi_server.request_queue.put((self, request_data)) - - # serve the content from local disc if we request an URL beginning - # by a pattern defined in `static_paths` - url_parts = self.path.split("/") - if (len(url_parts) > 1 and - url_parts[1] in self.pypi_server.static_uri_paths): - data = None - # always take the last first. - fs_paths = [] - fs_paths.extend(self.pypi_server.static_filesystem_paths) - fs_paths.reverse() - relative_path = self.path - for fs_path in fs_paths: - try: - if self.path.endswith("/"): - relative_path += "index.html" - file = open(fs_path + relative_path) - data = file.read() - if relative_path.endswith('.tar.gz'): - headers=[('Content-type', 'application/x-gtar')] - else: - headers=[('Content-type', 'text/html')] - self.make_response(data, headers=headers) - except IOError: - pass - - if data is None: - self.make_response("Not found", 404) - - # otherwise serve the content from get_next_response - else: - # send back a response - status, headers, data = self.pypi_server.get_next_response() - self.make_response(data, status, headers) - - def make_response(self, data, status=200, - headers=[('Content-type', 'text/html')]): - """Send the response to the HTTP client""" - if not isinstance(status, int): - try: - status = int(status) - except ValueError: - # we probably got something like YYY Codename. - # Just get the first 3 digits - status = int(status[:3]) - - self.send_response(status) - for header, value in headers: - self.send_header(header, value) - self.end_headers() - self.wfile.write(data) - -class PyPIXMLRPCServer(SimpleXMLRPCServer): - def server_bind(self): - """Override server_bind to store the server name.""" - SocketServer.TCPServer.server_bind(self) - host, port = self.socket.getsockname()[:2] - self.server_name = socket.getfqdn(host) - self.server_port = port - -class MockDist(object): - """Fake distribution, used in the Mock PyPI Server""" - def __init__(self, name, version="1.0", hidden=False, url="http://url/", - type="sdist", filename="", size=10000, - digest="123456", downloads=7, has_sig=False, - python_version="source", comment="comment", - author="John Doe", author_email="john@doe.name", - maintainer="Main Tayner", maintainer_email="maintainer_mail", - project_url="http://project_url/", homepage="http://homepage/", - keywords="", platform="UNKNOWN", classifiers=[], licence="", - description="Description", summary="Summary", stable_version="", - ordering="", documentation_id="", code_kwalitee_id="", - installability_id="", obsoletes=[], obsoletes_dist=[], - provides=[], provides_dist=[], requires=[], requires_dist=[], - requires_external=[], requires_python=""): - - # basic fields - self.name = name - self.version = version - self.hidden = hidden - - # URL infos - self.url = url - self.digest = digest - self.downloads = downloads - self.has_sig = has_sig - self.python_version = python_version - self.comment = comment - self.type = type - - # metadata - self.author = author - self.author_email = author_email - self.maintainer = maintainer - self.maintainer_email = maintainer_email - self.project_url = project_url - self.homepage = homepage - self.keywords = keywords - self.platform = platform - self.classifiers = classifiers - self.licence = licence - self.description = description - self.summary = summary - self.stable_version = stable_version - self.ordering = ordering - self.cheesecake_documentation_id = documentation_id - self.cheesecake_code_kwalitee_id = code_kwalitee_id - self.cheesecake_installability_id = installability_id - - self.obsoletes = obsoletes - self.obsoletes_dist = obsoletes_dist - self.provides = provides - self.provides_dist = provides_dist - self.requires = requires - self.requires_dist = requires_dist - self.requires_external = requires_external - self.requires_python = requires_python - - def url_infos(self): - return { - 'url': self.url, - 'packagetype': self.type, - 'filename': 'filename.tar.gz', - 'size': '6000', - 'md5_digest': self.digest, - 'downloads': self.downloads, - 'has_sig': self.has_sig, - 'python_version': self.python_version, - 'comment_text': self.comment, - } - - def metadata(self): - return { - 'maintainer': self.maintainer, - 'project_url': [self.project_url], - 'maintainer_email': self.maintainer_email, - 'cheesecake_code_kwalitee_id': self.cheesecake_code_kwalitee_id, - 'keywords': self.keywords, - 'obsoletes_dist': self.obsoletes_dist, - 'requires_external': self.requires_external, - 'author': self.author, - 'author_email': self.author_email, - 'download_url': self.url, - 'platform': self.platform, - 'version': self.version, - 'obsoletes': self.obsoletes, - 'provides': self.provides, - 'cheesecake_documentation_id': self.cheesecake_documentation_id, - '_pypi_hidden': self.hidden, - 'description': self.description, - '_pypi_ordering': 19, - 'requires_dist': self.requires_dist, - 'requires_python': self.requires_python, - 'classifiers': [], - 'name': self.name, - 'licence': self.licence, - 'summary': self.summary, - 'home_page': self.homepage, - 'stable_version': self.stable_version, - 'provides_dist': self.provides_dist or "%s (%s)" % (self.name, - self.version), - 'requires': self.requires, - 'cheesecake_installability_id': self.cheesecake_installability_id, - } - - def search_result(self): - return { - '_pypi_ordering': 0, - 'version': self.version, - 'name': self.name, - 'summary': self.summary, - } - -class XMLRPCMockIndex(object): - """Mock XMLRPC server""" - - def __init__(self, dists=[]): - self._dists = dists - - def add_distributions(self, dists): - for dist in dists: - self._dists.append(MockDist(**dist)) - - def set_distributions(self, dists): - self._dists = [] - self.add_distributions(dists) - - def set_search_result(self, result): - """set a predefined search result""" - self._search_result = result - - def _get_search_results(self): - results = [] - for name in self._search_result: - found_dist = [d for d in self._dists if d.name == name] - if found_dist: - results.append(found_dist[0]) - else: - dist = MockDist(name) - results.append(dist) - self._dists.append(dist) - return [r.search_result() for r in results] - - def list_package(self): - return [d.name for d in self._dists] - - def package_releases(self, package_name, show_hidden=False): - if show_hidden: - # return all - return [d.version for d in self._dists if d.name == package_name] - else: - # return only un-hidden - return [d.version for d in self._dists if d.name == package_name - and not d.hidden] - - def release_urls(self, package_name, version): - return [d.url_infos() for d in self._dists - if d.name == package_name and d.version == version] - - def release_data(self, package_name, version): - release = [d for d in self._dists - if d.name == package_name and d.version == version] - if release: - return release[0].metadata() - else: - return {} - - def search(self, spec, operator="and"): - return self._get_search_results() diff --git a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/badmd5/badmd5-0.1.tar.gz b/src/distutils2/tests/pypiserver/downloads_with_md5/simple/badmd5/badmd5-0.1.tar.gz deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/badmd5/badmd5-0.1.tar.gz +++ /dev/null diff --git a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/badmd5/index.html b/src/distutils2/tests/pypiserver/downloads_with_md5/simple/badmd5/index.html deleted file mode 100644 index b89f1bd..0000000 --- a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/badmd5/index.html +++ /dev/null @@ -1,3 +0,0 @@ -<html><body> -<a href="badmd5-0.1.tar.gz#md5=3e3d86693d6564c807272b11b3069dfe" rel="download">badmd5-0.1.tar.gz</a><br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/foobar-0.1.tar.gz b/src/distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/foobar-0.1.tar.gz deleted file mode 100644 index e69de29..0000000 --- a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/foobar-0.1.tar.gz +++ /dev/null diff --git a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/index.html b/src/distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/index.html deleted file mode 100644 index add0b85..0000000 --- a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/index.html +++ /dev/null @@ -1,3 +0,0 @@ -<html><body> -<a href="foobar-0.1.tar.gz#md5=d41d8cd98f00b204e9800998ecf8427e" rel="download">foobar-0.1.tar.gz</a><br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/index.html b/src/distutils2/tests/pypiserver/downloads_with_md5/simple/index.html deleted file mode 100644 index 9baee04..0000000 --- a/src/distutils2/tests/pypiserver/downloads_with_md5/simple/index.html +++ /dev/null @@ -1,2 +0,0 @@ -<a href="foobar/">foobar/</a> -<a href="badmd5/">badmd5/</a> diff --git a/src/distutils2/tests/pypiserver/foo_bar_baz/simple/bar/index.html b/src/distutils2/tests/pypiserver/foo_bar_baz/simple/bar/index.html deleted file mode 100644 index c3d42c5..0000000 --- a/src/distutils2/tests/pypiserver/foo_bar_baz/simple/bar/index.html +++ /dev/null @@ -1,6 +0,0 @@ -<html><head><title>Links for bar</title></head><body><h1>Links for bar</h1> -<a rel="download" href="../../packages/source/F/bar/bar-1.0.tar.gz">bar-1.0.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/bar/bar-1.0.1.tar.gz">bar-1.0.1.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/bar/bar-2.0.tar.gz">bar-2.0.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/bar/bar-2.0.1.tar.gz">bar-2.0.1.tar.gz</a><br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/foo_bar_baz/simple/baz/index.html b/src/distutils2/tests/pypiserver/foo_bar_baz/simple/baz/index.html deleted file mode 100644 index 4f34312..0000000 --- a/src/distutils2/tests/pypiserver/foo_bar_baz/simple/baz/index.html +++ /dev/null @@ -1,6 +0,0 @@ -<html><head><title>Links for baz</title></head><body><h1>Links for baz</h1> -<a rel="download" href="../../packages/source/F/baz/baz-1.0.tar.gz">baz-1.0.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/baz/baz-1.0.1.tar.gz">baz-1.0.1.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/baz/baz-2.0.tar.gz">baz-2.0.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/baz/baz-2.0.1.tar.gz">baz-2.0.1.tar.gz</a><br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/foo_bar_baz/simple/foo/index.html b/src/distutils2/tests/pypiserver/foo_bar_baz/simple/foo/index.html deleted file mode 100644 index 0565e11..0000000 --- a/src/distutils2/tests/pypiserver/foo_bar_baz/simple/foo/index.html +++ /dev/null @@ -1,6 +0,0 @@ -<html><head><title>Links for foo</title></head><body><h1>Links for foo</h1> -<a rel="download" href="../../packages/source/F/foo/foo-1.0.tar.gz">foo-1.0.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/foo/foo-1.0.1.tar.gz">foo-1.0.1.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/foo/foo-2.0.tar.gz">foo-2.0.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/foo/foo-2.0.1.tar.gz">foo-2.0.1.tar.gz</a><br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/foo_bar_baz/simple/index.html b/src/distutils2/tests/pypiserver/foo_bar_baz/simple/index.html deleted file mode 100644 index a70cfd3..0000000 --- a/src/distutils2/tests/pypiserver/foo_bar_baz/simple/index.html +++ /dev/null @@ -1,3 +0,0 @@ -<a href="foo/">foo/</a> -<a href="bar/">bar/</a> -<a href="baz/">baz/</a> diff --git a/src/distutils2/tests/pypiserver/project_list/simple/index.html b/src/distutils2/tests/pypiserver/project_list/simple/index.html deleted file mode 100644 index b36d728..0000000 --- a/src/distutils2/tests/pypiserver/project_list/simple/index.html +++ /dev/null @@ -1,5 +0,0 @@ -<a class="test" href="yeah">FooBar-bar</a> -<a class="test" href="yeah">Foobar-baz</a> -<a class="test" href="yeah">Baz-FooBar</a> -<a class="test" href="yeah">Baz</a> -<a class="test" href="yeah">Foo</a> diff --git a/src/distutils2/tests/pypiserver/test_found_links/simple/foobar/index.html b/src/distutils2/tests/pypiserver/test_found_links/simple/foobar/index.html deleted file mode 100644 index a282a4e..0000000 --- a/src/distutils2/tests/pypiserver/test_found_links/simple/foobar/index.html +++ /dev/null @@ -1,6 +0,0 @@ -<html><head><title>Links for Foobar</title></head><body><h1>Links for Foobar</h1> -<a rel="download" href="../../packages/source/F/Foobar/Foobar-1.0.tar.gz#md5=98fa833fdabcdd78d00245aead66c174">Foobar-1.0.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/Foobar/Foobar-1.0.1.tar.gz#md5=2351efb20f6b7b5d9ce80fa4cb1bd9ca">Foobar-1.0.1.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/Foobar/Foobar-2.0.tar.gz#md5=98fa833fdabcdd78d00245aead66c274">Foobar-2.0.tar.gz</a><br/> -<a rel="download" href="../../packages/source/F/Foobar/Foobar-2.0.1.tar.gz#md5=2352efb20f6b7b5d9ce80fa4cb2bd9ca">Foobar-2.0.1.tar.gz</a><br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/test_found_links/simple/index.html b/src/distutils2/tests/pypiserver/test_found_links/simple/index.html deleted file mode 100644 index a1a7bb7..0000000 --- a/src/distutils2/tests/pypiserver/test_found_links/simple/index.html +++ /dev/null @@ -1 +0,0 @@ -<a href="foobar/">foobar/</a> diff --git a/src/distutils2/tests/pypiserver/test_pypi_server/external/index.html b/src/distutils2/tests/pypiserver/test_pypi_server/external/index.html deleted file mode 100644 index 265ee0a..0000000 --- a/src/distutils2/tests/pypiserver/test_pypi_server/external/index.html +++ /dev/null @@ -1 +0,0 @@ -index.html from external server diff --git a/src/distutils2/tests/pypiserver/test_pypi_server/simple/index.html b/src/distutils2/tests/pypiserver/test_pypi_server/simple/index.html deleted file mode 100644 index 6f97667..0000000 --- a/src/distutils2/tests/pypiserver/test_pypi_server/simple/index.html +++ /dev/null @@ -1 +0,0 @@ -Yeah diff --git a/src/distutils2/tests/pypiserver/with_externals/external/external.html b/src/distutils2/tests/pypiserver/with_externals/external/external.html deleted file mode 100644 index 92e4702..0000000 --- a/src/distutils2/tests/pypiserver/with_externals/external/external.html +++ /dev/null @@ -1,3 +0,0 @@ -<html><body> -<a href="/foobar-0.1.tar.gz#md5=1__bad_md5___">bad old link</a> -</body></html> diff --git a/src/distutils2/tests/pypiserver/with_externals/simple/foobar/index.html b/src/distutils2/tests/pypiserver/with_externals/simple/foobar/index.html deleted file mode 100644 index b100a26..0000000 --- a/src/distutils2/tests/pypiserver/with_externals/simple/foobar/index.html +++ /dev/null @@ -1,4 +0,0 @@ -<html><body> -<a rel ="download" href="/foobar-0.1.tar.gz#md5=12345678901234567">foobar-0.1.tar.gz</a><br/> -<a href="../../external/external.html" rel="homepage">external homepage</a><br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/with_externals/simple/index.html b/src/distutils2/tests/pypiserver/with_externals/simple/index.html deleted file mode 100644 index a1a7bb7..0000000 --- a/src/distutils2/tests/pypiserver/with_externals/simple/index.html +++ /dev/null @@ -1 +0,0 @@ -<a href="foobar/">foobar/</a> diff --git a/src/distutils2/tests/pypiserver/with_norel_links/external/homepage.html b/src/distutils2/tests/pypiserver/with_norel_links/external/homepage.html deleted file mode 100644 index 1cc0c32..0000000 --- a/src/distutils2/tests/pypiserver/with_norel_links/external/homepage.html +++ /dev/null @@ -1,7 +0,0 @@ -<html> -<body> -<p>a rel=homepage HTML page</p> -<a href="/foobar-2.0.tar.gz">foobar 2.0</a> -</body> -</html> - diff --git a/src/distutils2/tests/pypiserver/with_norel_links/external/nonrel.html b/src/distutils2/tests/pypiserver/with_norel_links/external/nonrel.html deleted file mode 100644 index f6ace22..0000000 --- a/src/distutils2/tests/pypiserver/with_norel_links/external/nonrel.html +++ /dev/null @@ -1 +0,0 @@ -A page linked without rel="download" or rel="homepage" link. diff --git a/src/distutils2/tests/pypiserver/with_norel_links/simple/foobar/index.html b/src/distutils2/tests/pypiserver/with_norel_links/simple/foobar/index.html deleted file mode 100644 index 171df93..0000000 --- a/src/distutils2/tests/pypiserver/with_norel_links/simple/foobar/index.html +++ /dev/null @@ -1,6 +0,0 @@ -<html><body> -<a rel="download" href="/foobar-0.1.tar.gz" rel="download">foobar-0.1.tar.gz</a><br/> -<a href="../../external/homepage.html" rel="homepage">external homepage</a><br/> -<a href="../../external/nonrel.html">unrelated link</a><br/> -<a href="/unrelated-0.2.tar.gz">unrelated download</a></br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/with_norel_links/simple/index.html b/src/distutils2/tests/pypiserver/with_norel_links/simple/index.html deleted file mode 100644 index a1a7bb7..0000000 --- a/src/distutils2/tests/pypiserver/with_norel_links/simple/index.html +++ /dev/null @@ -1 +0,0 @@ -<a href="foobar/">foobar/</a> diff --git a/src/distutils2/tests/pypiserver/with_real_externals/simple/foobar/index.html b/src/distutils2/tests/pypiserver/with_real_externals/simple/foobar/index.html deleted file mode 100644 index b2885ae..0000000 --- a/src/distutils2/tests/pypiserver/with_real_externals/simple/foobar/index.html +++ /dev/null @@ -1,4 +0,0 @@ -<html><body> -<a rel="download" href="/foobar-0.1.tar.gz#md5=0_correct_md5">foobar-0.1.tar.gz</a><br/> -<a href="http://a-really-external-website/external/external.html" rel="homepage">external homepage</a><br/> -</body></html> diff --git a/src/distutils2/tests/pypiserver/with_real_externals/simple/index.html b/src/distutils2/tests/pypiserver/with_real_externals/simple/index.html deleted file mode 100644 index a1a7bb7..0000000 --- a/src/distutils2/tests/pypiserver/with_real_externals/simple/index.html +++ /dev/null @@ -1 +0,0 @@ -<a href="foobar/">foobar/</a> diff --git a/src/distutils2/tests/support.py b/src/distutils2/tests/support.py deleted file mode 100644 index a365548..0000000 --- a/src/distutils2/tests/support.py +++ /dev/null @@ -1,235 +0,0 @@ -"""Support code for distutils2 test cases. - -Always import unittest from this module, it will be the right version -(standard library unittest for 3.2 and higher, third-party unittest2 -release for older versions). - -Four helper classes are provided: LoggingCatcher, TempdirManager, -EnvironGuard and WarningsCatcher. They are written to be used as mixins, -e.g. :: - - from distutils2.tests.support import unittest - from distutils2.tests.support import LoggingCatcher - - class SomeTestCase(LoggingCatcher, unittest.TestCase): - -If you need to define a setUp method on your test class, you have to -call the mixin class' setUp method or it won't work (same thing for -tearDown): - - def setUp(self): - super(SomeTestCase, self).setUp() - ... # other setup code - -Read each class' docstring to see its purpose and usage. - -Also provided is a DummyCommand class, useful to mock commands in the -tests of another command that needs them (see docstring). -""" - -import os -import sys -import shutil -import tempfile -import warnings -from copy import deepcopy - -from distutils2 import log -from distutils2.dist import Distribution -from distutils2.log import DEBUG, INFO, WARN, ERROR, FATAL - -if sys.version_info >= (3, 2): - # improved unittest package from 3.2's standard library - import unittest -else: - # external release of same package for older versions - import unittest2 as unittest - -__all__ = ['LoggingCatcher', 'WarningsCatcher', 'TempdirManager', - 'EnvironGuard', 'DummyCommand', 'unittest'] - - -class LoggingCatcher(object): - """TestCase-compatible mixin to catch logging calls. - - Every log message that goes through distutils2.log will get appended to - self.logs instead of being printed. You can check that your code logs - warnings and errors as documented by inspecting that list; helper methods - get_logs and clear_logs are also provided. - """ - - def setUp(self): - super(LoggingCatcher, self).setUp() - self.threshold = log.set_threshold(FATAL) - # when log is replaced by logging we won't need - # such monkey-patching anymore - self._old_log = log.Log._log - log.Log._log = self._log - self.logs = [] - - def tearDown(self): - log.set_threshold(self.threshold) - log.Log._log = self._old_log - super(LoggingCatcher, self).tearDown() - - def _log(self, level, msg, args): - if level not in (DEBUG, INFO, WARN, ERROR, FATAL): - raise ValueError('%s wrong log level' % level) - self.logs.append((level, msg, args)) - - def get_logs(self, *levels): - """Return a list of caught messages with level in `levels`. - - Example: self.get_logs(log.WARN, log.DEBUG) -> list - """ - def _format(msg, args): - if len(args) == 0: - return msg - return msg % args - return [_format(msg, args) for level, msg, args - in self.logs if level in levels] - - def clear_logs(self): - """Empty the internal list of caught messages.""" - del self.logs[:] - - -class LoggingSilencer(object): - "Class that raises an exception to make sure the renaming is noticed." - - def __init__(self, *args): - raise DeprecationWarning("LoggingSilencer renamed to LoggingCatcher") - - -class WarningsCatcher(object): - - def setUp(self): - self._orig_showwarning = warnings.showwarning - warnings.showwarning = self._record_showwarning - self.warnings = [] - - def _record_showwarning(self, message, category, filename, lineno, - file=None, line=None): - self.warnings.append({"message": message, "category": category, - "filename": filename, "lineno": lineno, - "file": file, "line": line}) - - def tearDown(self): - warnings.showwarning = self._orig_showwarning - - -class TempdirManager(object): - """TestCase-compatible mixin to create temporary directories and files. - - Directories and files created in a test_* method will be removed after it - has run. - """ - - def setUp(self): - super(TempdirManager, self).setUp() - self._basetempdir = tempfile.mkdtemp() - - def tearDown(self): - super(TempdirManager, self).tearDown() - shutil.rmtree(self._basetempdir, os.name in ('nt', 'cygwin')) - - def mktempfile(self): - """Create a read-write temporary file and return it.""" - fd, fn = tempfile.mkstemp(dir=self._basetempdir) - os.close(fd) - return open(fn, 'w+') - - def mkdtemp(self): - """Create a temporary directory and return its path.""" - d = tempfile.mkdtemp(dir=self._basetempdir) - return d - - def write_file(self, path, content='xxx'): - """Write a file at the given path. - - path can be a string, a tuple or a list; if it's a tuple or list, - os.path.join will be used to produce a path. - """ - if isinstance(path, (list, tuple)): - path = os.path.join(*path) - f = open(path, 'w') - try: - f.write(content) - finally: - f.close() - - def create_dist(self, pkg_name='foo', **kw): - """Create a stub distribution object and files. - - This function creates a Distribution instance (use keyword arguments - to customize it) and a temporary directory with a project structure - (currently an empty directory). - - It returns the path to the directory and the Distribution instance. - You can use TempdirManager.write_file to write any file in that - directory, e.g. setup scripts or Python modules. - """ - # Late import so that third parties can import support without - # loading a ton of distutils2 modules in memory. - from distutils2.dist import Distribution - tmp_dir = self.mkdtemp() - pkg_dir = os.path.join(tmp_dir, pkg_name) - os.mkdir(pkg_dir) - dist = Distribution(attrs=kw) - return pkg_dir, dist - - -class EnvironGuard(object): - """TestCase-compatible mixin to save and restore the environment.""" - - def setUp(self): - super(EnvironGuard, self).setUp() - self.old_environ = deepcopy(os.environ) - - def tearDown(self): - for key, value in self.old_environ.iteritems(): - if os.environ.get(key) != value: - os.environ[key] = value - - for key in os.environ.keys(): - if key not in self.old_environ: - del os.environ[key] - - super(EnvironGuard, self).tearDown() - - -class DummyCommand(object): - """Class to store options for retrieval via set_undefined_options(). - - Useful for mocking one dependency command in the tests for another - command, see e.g. the dummy build command in test_build_scripts. - """ - - def __init__(self, **kwargs): - for kw, val in kwargs.iteritems(): - setattr(self, kw, val) - - def ensure_finalized(self): - pass - - -class TestDistribution(Distribution): - """Distribution subclasses that avoids the default search for - configuration files. - - The ._config_files attribute must be set before - .parse_config_files() is called. - """ - - def find_config_files(self): - return self._config_files - - -def create_distribution(configfiles=()): - """Prepares a distribution with given config files parsed.""" - d = TestDistribution() - d._config_files = configfiles - d.parse_config_files() - d.parse_command_line() - return d - diff --git a/src/distutils2/tests/test_Mixin2to3.py b/src/distutils2/tests/test_Mixin2to3.py deleted file mode 100644 index 186d128..0000000 --- a/src/distutils2/tests/test_Mixin2to3.py +++ /dev/null @@ -1,73 +0,0 @@ -"""Tests for distutils.command.build_py.""" -import sys -import logging - -import distutils2 -from distutils2.tests import support -from distutils2.tests.support import unittest -from distutils2.compat import Mixin2to3 - - -class Mixin2to3TestCase(support.TempdirManager, unittest.TestCase): - - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_convert_code_only(self): - # used to check if code gets converted properly. - code_content = "print 'test'\n" - code_handle = self.mktempfile() - code_name = code_handle.name - - code_handle.write(code_content) - code_handle.flush() - - mixin2to3 = Mixin2to3() - mixin2to3._run_2to3([code_name]) - converted_code_content = "print('test')\n" - new_code_content = "".join(open(code_name).readlines()) - - self.assertEquals(new_code_content, converted_code_content) - - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_doctests_only(self): - # used to check if doctests gets converted properly. - doctest_content = '"""\n>>> print test\ntest\n"""\nprint test\n\n' - doctest_handle = self.mktempfile() - doctest_name = doctest_handle.name - - doctest_handle.write(doctest_content) - doctest_handle.flush() - - mixin2to3 = Mixin2to3() - mixin2to3._run_2to3([doctest_name]) - - converted_doctest_content = ['"""', '>>> print(test)', 'test', '"""', - 'print(test)', '', '', ''] - converted_doctest_content = '\n'.join(converted_doctest_content) - new_doctest_content = "".join(open(doctest_name).readlines()) - - self.assertEquals(new_doctest_content, converted_doctest_content) - - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_additional_fixers(self): - # used to check if use_2to3_fixers works - from distutils2.tests import fixer - code_content = "type(x) is T" - code_handle = self.mktempfile() - code_name = code_handle.name - - code_handle.write(code_content) - code_handle.flush() - - mixin2to3 = Mixin2to3() - - mixin2to3._run_2to3(files=[code_name], - fixers=['distutils2.tests.fixer']) - converted_code_content = "isinstance(x, T)" - new_code_content = "".join(open(code_name).readlines()) - self.assertEquals(new_code_content, converted_code_content) - -def test_suite(): - return unittest.makeSuite(Mixin2to3TestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_bdist.py b/src/distutils2/tests/test_bdist.py deleted file mode 100644 index 2be01e1..0000000 --- a/src/distutils2/tests/test_bdist.py +++ /dev/null @@ -1,41 +0,0 @@ -"""Tests for distutils.command.bdist.""" -import sys -import os - -from distutils2.tests import run_unittest - -from distutils2.core import Distribution -from distutils2.command.bdist import bdist -from distutils2.tests import support -from distutils2.tests.support import unittest -from distutils2.util import find_executable -from distutils2.errors import DistutilsExecError - -class BuildTestCase(support.TempdirManager, - unittest.TestCase): - - def test_formats(self): - - # let's create a command and make sure - # we can fix the format - pkg_pth, dist = self.create_dist() - cmd = bdist(dist) - cmd.formats = ['msi'] - cmd.ensure_finalized() - self.assertEqual(cmd.formats, ['msi']) - - # what format bdist offers ? - # XXX an explicit list in bdist is - # not the best way to bdist_* commands - # we should add a registry - formats = ['zip', 'gztar', 'bztar', 'ztar', 'tar', 'wininst', 'msi'] - formats.sort() - found = cmd.format_command.keys() - found.sort() - self.assertEqual(found, formats) - -def test_suite(): - return unittest.makeSuite(BuildTestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_bdist_dumb.py b/src/distutils2/tests/test_bdist_dumb.py deleted file mode 100644 index a33210e..0000000 --- a/src/distutils2/tests/test_bdist_dumb.py +++ /dev/null @@ -1,105 +0,0 @@ -"""Tests for distutils.command.bdist_dumb.""" - -import sys -import os - -# zlib is not used here, but if it's not available -# test_simple_built will fail -try: - import zlib -except ImportError: - zlib = None - -from distutils2.tests import run_unittest -from distutils2.tests.support import unittest - -from distutils2.core import Distribution -from distutils2.command.bdist_dumb import bdist_dumb -from distutils2.tests import support - -SETUP_PY = """\ -from distutils.core import setup -import foo - -setup(name='foo', version='0.1', py_modules=['foo'], - url='xxx', author='xxx', author_email='xxx') - -""" - -class BuildDumbTestCase(support.TempdirManager, - support.LoggingCatcher, - support.EnvironGuard, - unittest.TestCase): - - def setUp(self): - super(BuildDumbTestCase, self).setUp() - self.old_location = os.getcwd() - self.old_sys_argv = sys.argv, sys.argv[:] - - def tearDown(self): - os.chdir(self.old_location) - sys.argv = self.old_sys_argv[0] - sys.argv[:] = self.old_sys_argv[1] - super(BuildDumbTestCase, self).tearDown() - - @unittest.skipUnless(zlib, "requires zlib") - def test_simple_built(self): - - # let's create a simple package - tmp_dir = self.mkdtemp() - pkg_dir = os.path.join(tmp_dir, 'foo') - os.mkdir(pkg_dir) - self.write_file((pkg_dir, 'setup.py'), SETUP_PY) - self.write_file((pkg_dir, 'foo.py'), '#') - self.write_file((pkg_dir, 'MANIFEST.in'), 'include foo.py') - self.write_file((pkg_dir, 'README'), '') - - dist = Distribution({'name': 'foo', 'version': '0.1', - 'py_modules': ['foo'], - 'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx'}) - dist.script_name = 'setup.py' - os.chdir(pkg_dir) - - sys.argv = ['setup.py'] - cmd = bdist_dumb(dist) - - # so the output is the same no matter - # what is the platform - cmd.format = 'zip' - - cmd.ensure_finalized() - cmd.run() - - # see what we have - dist_created = os.listdir(os.path.join(pkg_dir, 'dist')) - base = "%s.%s" % (dist.get_fullname(), cmd.plat_name) - if os.name == 'os2': - base = base.replace(':', '-') - - wanted = ['%s.zip' % base] - self.assertEqual(dist_created, wanted) - - # now let's check what we have in the zip file - # XXX to be done - - def test_finalize_options(self): - pkg_dir, dist = self.create_dist() - os.chdir(pkg_dir) - cmd = bdist_dumb(dist) - self.assertEqual(cmd.bdist_dir, None) - cmd.finalize_options() - - # bdist_dir is initialized to bdist_base/dumb if not set - base = cmd.get_finalized_command('bdist').bdist_base - self.assertEqual(cmd.bdist_dir, os.path.join(base, 'dumb')) - - # the format is set to a default value depending on the os.name - default = cmd.default_format[os.name] - self.assertEqual(cmd.format, default) - -def test_suite(): - return unittest.makeSuite(BuildDumbTestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_bdist_msi.py b/src/distutils2/tests/test_bdist_msi.py deleted file mode 100644 index 0d3bda8..0000000 --- a/src/distutils2/tests/test_bdist_msi.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Tests for distutils.command.bdist_msi.""" -import sys - -from distutils2.tests import run_unittest - -from distutils2.tests import support -from distutils2.tests.support import unittest - -class BDistMSITestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - @unittest.skipUnless(sys.platform == "win32", "runs only on win32") - def test_minimal(self): - # minimal test XXX need more tests - from distutils2.command.bdist_msi import bdist_msi - pkg_pth, dist = self.create_dist() - cmd = bdist_msi(dist) - cmd.ensure_finalized() - -def test_suite(): - return unittest.makeSuite(BDistMSITestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_bdist_wininst.py b/src/distutils2/tests/test_bdist_wininst.py deleted file mode 100644 index f154463..0000000 --- a/src/distutils2/tests/test_bdist_wininst.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Tests for distutils.command.bdist_wininst.""" - -from distutils2.tests import run_unittest - -from distutils2.command.bdist_wininst import bdist_wininst -from distutils2.tests import support -from distutils2.tests.support import unittest - -class BuildWinInstTestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - def test_get_exe_bytes(self): - - # issue5731: command was broken on non-windows platforms - # this test makes sure it works now for every platform - # let's create a command - pkg_pth, dist = self.create_dist() - cmd = bdist_wininst(dist) - cmd.ensure_finalized() - - # let's run the code that finds the right wininst*.exe file - # and make sure it finds it and returns its content - # no matter what platform we have - exe_file = cmd.get_exe_bytes() - self.assertTrue(len(exe_file) > 10) - -def test_suite(): - return unittest.makeSuite(BuildWinInstTestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_build.py b/src/distutils2/tests/test_build.py deleted file mode 100644 index 1245111..0000000 --- a/src/distutils2/tests/test_build.py +++ /dev/null @@ -1,57 +0,0 @@ -"""Tests for distutils.command.build.""" -import os -import sys - -from distutils2.command.build import build -from distutils2.tests import support -from distutils2.tests.support import unittest -try: - from sysconfig import get_platform -except ImportError: - from distutils2._backport.sysconfig import get_platform - -class BuildTestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - def test_finalize_options(self): - pkg_dir, dist = self.create_dist() - cmd = build(dist) - cmd.finalize_options() - - # if not specified, plat_name gets the current platform - self.assertEqual(cmd.plat_name, get_platform()) - - # build_purelib is build + lib - wanted = os.path.join(cmd.build_base, 'lib') - self.assertEqual(cmd.build_purelib, wanted) - - # build_platlib is 'build/lib.platform-x.x[-pydebug]' - # examples: - # build/lib.macosx-10.3-i386-2.7 - plat_spec = '.%s-%s' % (cmd.plat_name, sys.version[0:3]) - if hasattr(sys, 'gettotalrefcount'): - self.assertTrue(cmd.build_platlib.endswith('-pydebug')) - plat_spec += '-pydebug' - wanted = os.path.join(cmd.build_base, 'lib' + plat_spec) - self.assertEqual(cmd.build_platlib, wanted) - - # by default, build_lib = build_purelib - self.assertEqual(cmd.build_lib, cmd.build_purelib) - - # build_temp is build/temp.<plat> - wanted = os.path.join(cmd.build_base, 'temp' + plat_spec) - self.assertEqual(cmd.build_temp, wanted) - - # build_scripts is build/scripts-x.x - wanted = os.path.join(cmd.build_base, 'scripts-' + sys.version[0:3]) - self.assertEqual(cmd.build_scripts, wanted) - - # executable is os.path.normpath(sys.executable) - self.assertEqual(cmd.executable, os.path.normpath(sys.executable)) - -def test_suite(): - return unittest.makeSuite(BuildTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_build_clib.py b/src/distutils2/tests/test_build_clib.py deleted file mode 100644 index b8d51d4..0000000 --- a/src/distutils2/tests/test_build_clib.py +++ /dev/null @@ -1,143 +0,0 @@ -"""Tests for distutils.command.build_clib.""" -import os -import sys - -from distutils2.command.build_clib import build_clib -from distutils2.errors import DistutilsSetupError -from distutils2.tests import support -from distutils2.util import find_executable -from distutils2.tests.support import unittest - -class BuildCLibTestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - def test_check_library_dist(self): - pkg_dir, dist = self.create_dist() - cmd = build_clib(dist) - - # 'libraries' option must be a list - self.assertRaises(DistutilsSetupError, cmd.check_library_list, 'foo') - - # each element of 'libraries' must a 2-tuple - self.assertRaises(DistutilsSetupError, cmd.check_library_list, - ['foo1', 'foo2']) - - # first element of each tuple in 'libraries' - # must be a string (the library name) - self.assertRaises(DistutilsSetupError, cmd.check_library_list, - [(1, 'foo1'), ('name', 'foo2')]) - - # library name may not contain directory separators - self.assertRaises(DistutilsSetupError, cmd.check_library_list, - [('name', 'foo1'), - ('another/name', 'foo2')]) - - # second element of each tuple must be a dictionary (build info) - self.assertRaises(DistutilsSetupError, cmd.check_library_list, - [('name', {}), - ('another', 'foo2')]) - - # those work - libs = [('name', {}), ('name', {'ok': 'good'})] - cmd.check_library_list(libs) - - def test_get_source_files(self): - pkg_dir, dist = self.create_dist() - cmd = build_clib(dist) - - # "in 'libraries' option 'sources' must be present and must be - # a list of source filenames - cmd.libraries = [('name', {})] - self.assertRaises(DistutilsSetupError, cmd.get_source_files) - - cmd.libraries = [('name', {'sources': 1})] - self.assertRaises(DistutilsSetupError, cmd.get_source_files) - - cmd.libraries = [('name', {'sources': ['a', 'b']})] - self.assertEqual(cmd.get_source_files(), ['a', 'b']) - - cmd.libraries = [('name', {'sources': ('a', 'b')})] - self.assertEqual(cmd.get_source_files(), ['a', 'b']) - - cmd.libraries = [('name', {'sources': ('a', 'b')}), - ('name2', {'sources': ['c', 'd']})] - self.assertEqual(cmd.get_source_files(), ['a', 'b', 'c', 'd']) - - def test_build_libraries(self): - - pkg_dir, dist = self.create_dist() - cmd = build_clib(dist) - class FakeCompiler: - def compile(*args, **kw): - pass - create_static_lib = compile - - cmd.compiler = FakeCompiler() - - # build_libraries is also doing a bit of typoe checking - lib = [('name', {'sources': 'notvalid'})] - self.assertRaises(DistutilsSetupError, cmd.build_libraries, lib) - - lib = [('name', {'sources': list()})] - cmd.build_libraries(lib) - - lib = [('name', {'sources': tuple()})] - cmd.build_libraries(lib) - - def test_finalize_options(self): - pkg_dir, dist = self.create_dist() - cmd = build_clib(dist) - - cmd.include_dirs = 'one-dir' - cmd.finalize_options() - self.assertEqual(cmd.include_dirs, ['one-dir']) - - cmd.include_dirs = None - cmd.finalize_options() - self.assertEqual(cmd.include_dirs, []) - - cmd.distribution.libraries = 'WONTWORK' - self.assertRaises(DistutilsSetupError, cmd.finalize_options) - - def test_run(self): - # can't test on windows - if sys.platform == 'win32': - return - - pkg_dir, dist = self.create_dist() - cmd = build_clib(dist) - - foo_c = os.path.join(pkg_dir, 'foo.c') - self.write_file(foo_c, 'int main(void) { return 1;}\n') - cmd.libraries = [('foo', {'sources': [foo_c]})] - - build_temp = os.path.join(pkg_dir, 'build') - os.mkdir(build_temp) - cmd.build_temp = build_temp - cmd.build_clib = build_temp - - # before we run the command, we want to make sure - # all commands are present on the system - # by creating a compiler and checking its executables - from distutils2.compiler.ccompiler import new_compiler, customize_compiler - - compiler = new_compiler() - customize_compiler(compiler) - for ccmd in compiler.executables.values(): - if ccmd is None: - continue - if find_executable(ccmd[0]) is None: - return # can't test - - # this should work - cmd.run() - - # let's check the result - self.assertTrue('libfoo.a' in os.listdir(build_temp)) - -def test_suite(): - return unittest.makeSuite(BuildCLibTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_build_ext.py b/src/distutils2/tests/test_build_ext.py deleted file mode 100644 index 9b1ee45..0000000 --- a/src/distutils2/tests/test_build_ext.py +++ /dev/null @@ -1,366 +0,0 @@ -import sys -import os -import shutil -from StringIO import StringIO - -import distutils2.tests -from distutils2.tests.support import unittest -from distutils2.core import Extension, Distribution -from distutils2.command.build_ext import build_ext -from distutils2.tests import support -from distutils2.extension import Extension -from distutils2.errors import (UnknownFileError, DistutilsSetupError, - CompileError) -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig - - -# http://bugs.python.org/issue4373 -# Don't load the xx module more than once. -ALREADY_TESTED = False -CURDIR = os.path.abspath(os.path.dirname(__file__)) - -def _get_source_filename(): - return os.path.join(CURDIR, 'xxmodule.c') - -class BuildExtTestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - def setUp(self): - # Create a simple test environment - # Note that we're making changes to sys.path - super(BuildExtTestCase, self).setUp() - self.tmp_dir = self.mkdtemp() - self.sys_path = sys.path, sys.path[:] - sys.path.append(self.tmp_dir) - shutil.copy(_get_source_filename(), self.tmp_dir) - if sys.version > "2.6": - import site - self.old_user_base = site.USER_BASE - site.USER_BASE = self.mkdtemp() - from distutils2.command import build_ext - build_ext.USER_BASE = site.USER_BASE - - # XXX only works with 2.6 > -- dunno why yet - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_build_ext(self): - global ALREADY_TESTED - xx_c = os.path.join(self.tmp_dir, 'xxmodule.c') - xx_ext = Extension('xx', [xx_c]) - dist = Distribution({'name': 'xx', 'ext_modules': [xx_ext]}) - dist.package_dir = self.tmp_dir - cmd = build_ext(dist) - if os.name == "nt": - # On Windows, we must build a debug version iff running - # a debug build of Python - cmd.debug = sys.executable.endswith("_d.exe") - cmd.build_lib = self.tmp_dir - cmd.build_temp = self.tmp_dir - - old_stdout = sys.stdout - if not distutils2.tests.verbose: - # silence compiler output - sys.stdout = StringIO() - try: - cmd.ensure_finalized() - cmd.run() - finally: - sys.stdout = old_stdout - - if ALREADY_TESTED: - return - else: - ALREADY_TESTED = True - - import xx - - for attr in ('error', 'foo', 'new', 'roj'): - self.assertTrue(hasattr(xx, attr)) - - self.assertEqual(xx.foo(2, 5), 7) - self.assertEqual(xx.foo(13,15), 28) - self.assertEqual(xx.new().demo(), None) - doc = 'This is a template module just for instruction.' - self.assertEqual(xx.__doc__, doc) - self.assertTrue(isinstance(xx.Null(), xx.Null)) - self.assertTrue(isinstance(xx.Str(), xx.Str)) - - def tearDown(self): - # Get everything back to normal - distutils2.tests.unload('xx') - sys.path = self.sys_path[0] - sys.path[:] = self.sys_path[1] - if sys.version > "2.6": - import site - site.USER_BASE = self.old_user_base - from distutils2.command import build_ext - build_ext.USER_BASE = self.old_user_base - - super(BuildExtTestCase, self).tearDown() - - def test_solaris_enable_shared(self): - dist = Distribution({'name': 'xx'}) - cmd = build_ext(dist) - old = sys.platform - - sys.platform = 'sunos' # fooling finalize_options - try: - from sysconfig import _CONFIG_VARS - except ImportError: - from distutils2._backport.sysconfig import _CONFIG_VARS - - old_var = _CONFIG_VARS.get('Py_ENABLE_SHARED') - _CONFIG_VARS['Py_ENABLE_SHARED'] = 1 - try: - cmd.ensure_finalized() - finally: - sys.platform = old - if old_var is None: - del _CONFIG_VARS['Py_ENABLE_SHARED'] - else: - _CONFIG_VARS['Py_ENABLE_SHARED'] = old_var - - # make sure we get some library dirs under solaris - self.assertTrue(len(cmd.library_dirs) > 0) - - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_user_site(self): - import site - dist = Distribution({'name': 'xx'}) - cmd = build_ext(dist) - - # making sure the user option is there - options = [name for name, short, lable in - cmd.user_options] - self.assertTrue('user' in options) - - # setting a value - cmd.user = 1 - - # setting user based lib and include - lib = os.path.join(site.USER_BASE, 'lib') - incl = os.path.join(site.USER_BASE, 'include') - os.mkdir(lib) - os.mkdir(incl) - - # let's run finalize - cmd.ensure_finalized() - - # see if include_dirs and library_dirs - # were set - self.assertTrue(lib in cmd.library_dirs) - self.assertTrue(lib in cmd.rpath) - self.assertTrue(incl in cmd.include_dirs) - - def test_optional_extension(self): - - # this extension will fail, but let's ignore this failure - # with the optional argument. - modules = [Extension('foo', ['xxx'], optional=False)] - dist = Distribution({'name': 'xx', 'ext_modules': modules}) - cmd = build_ext(dist) - cmd.ensure_finalized() - self.assertRaises((UnknownFileError, CompileError), - cmd.run) # should raise an error - - modules = [Extension('foo', ['xxx'], optional=True)] - dist = Distribution({'name': 'xx', 'ext_modules': modules}) - cmd = build_ext(dist) - cmd.ensure_finalized() - cmd.run() # should pass - - def test_finalize_options(self): - # Make sure Python's include directories (for Python.h, pyconfig.h, - # etc.) are in the include search path. - modules = [Extension('foo', ['xxx'], optional=False)] - dist = Distribution({'name': 'xx', 'ext_modules': modules}) - cmd = build_ext(dist) - cmd.finalize_options() - - py_include = sysconfig.get_path('include') - self.assertTrue(py_include in cmd.include_dirs) - - plat_py_include = sysconfig.get_path('platinclude') - self.assertTrue(plat_py_include in cmd.include_dirs) - - # make sure cmd.libraries is turned into a list - # if it's a string - cmd = build_ext(dist) - cmd.libraries = 'my_lib' - cmd.finalize_options() - self.assertEqual(cmd.libraries, ['my_lib']) - - # make sure cmd.library_dirs is turned into a list - # if it's a string - cmd = build_ext(dist) - cmd.library_dirs = 'my_lib_dir' - cmd.finalize_options() - self.assertTrue('my_lib_dir' in cmd.library_dirs) - - # make sure rpath is turned into a list - # if it's a list of os.pathsep's paths - cmd = build_ext(dist) - cmd.rpath = os.pathsep.join(['one', 'two']) - cmd.finalize_options() - self.assertEqual(cmd.rpath, ['one', 'two']) - - # XXX more tests to perform for win32 - - # make sure define is turned into 2-tuples - # strings if they are ','-separated strings - cmd = build_ext(dist) - cmd.define = 'one,two' - cmd.finalize_options() - self.assertEqual(cmd.define, [('one', '1'), ('two', '1')]) - - # make sure undef is turned into a list of - # strings if they are ','-separated strings - cmd = build_ext(dist) - cmd.undef = 'one,two' - cmd.finalize_options() - self.assertEqual(cmd.undef, ['one', 'two']) - - # make sure swig_opts is turned into a list - cmd = build_ext(dist) - cmd.swig_opts = None - cmd.finalize_options() - self.assertEqual(cmd.swig_opts, []) - - cmd = build_ext(dist) - cmd.swig_opts = '1 2' - cmd.finalize_options() - self.assertEqual(cmd.swig_opts, ['1', '2']) - - def test_get_source_files(self): - modules = [Extension('foo', ['xxx'], optional=False)] - dist = Distribution({'name': 'xx', 'ext_modules': modules}) - cmd = build_ext(dist) - cmd.ensure_finalized() - self.assertEqual(cmd.get_source_files(), ['xxx']) - - def test_compiler_option(self): - # cmd.compiler is an option and - # should not be overriden by a compiler instance - # when the command is run - dist = Distribution() - cmd = build_ext(dist) - cmd.compiler = 'unix' - cmd.ensure_finalized() - cmd.run() - self.assertEqual(cmd.compiler, 'unix') - - def test_get_outputs(self): - tmp_dir = self.mkdtemp() - c_file = os.path.join(tmp_dir, 'foo.c') - self.write_file(c_file, 'void initfoo(void) {};\n') - ext = Extension('foo', [c_file], optional=False) - dist = Distribution({'name': 'xx', - 'ext_modules': [ext]}) - cmd = build_ext(dist) - cmd.ensure_finalized() - self.assertEqual(len(cmd.get_outputs()), 1) - - if os.name == "nt": - cmd.debug = sys.executable.endswith("_d.exe") - - cmd.build_lib = os.path.join(self.tmp_dir, 'build') - cmd.build_temp = os.path.join(self.tmp_dir, 'tempt') - - # issue #5977 : distutils build_ext.get_outputs - # returns wrong result with --inplace - other_tmp_dir = os.path.realpath(self.mkdtemp()) - old_wd = os.getcwd() - os.chdir(other_tmp_dir) - try: - cmd.inplace = 1 - cmd.run() - so_file = cmd.get_outputs()[0] - finally: - os.chdir(old_wd) - self.assertTrue(os.path.exists(so_file)) - so_ext = sysconfig.get_config_var('SO') - self.assertTrue(so_file.endswith(so_ext)) - so_dir = os.path.dirname(so_file) - self.assertEqual(so_dir, other_tmp_dir) - - cmd.inplace = 0 - cmd.run() - so_file = cmd.get_outputs()[0] - self.assertTrue(os.path.exists(so_file)) - self.assertTrue(so_file.endswith(so_ext)) - so_dir = os.path.dirname(so_file) - self.assertEqual(so_dir, cmd.build_lib) - - # inplace = 0, cmd.package = 'bar' - build_py = cmd.get_finalized_command('build_py') - build_py.package_dir = {'': 'bar'} - path = cmd.get_ext_fullpath('foo') - # checking that the last directory is the build_dir - path = os.path.split(path)[0] - self.assertEqual(path, cmd.build_lib) - - # inplace = 1, cmd.package = 'bar' - cmd.inplace = 1 - other_tmp_dir = os.path.realpath(self.mkdtemp()) - old_wd = os.getcwd() - os.chdir(other_tmp_dir) - try: - path = cmd.get_ext_fullpath('foo') - finally: - os.chdir(old_wd) - # checking that the last directory is bar - path = os.path.split(path)[0] - lastdir = os.path.split(path)[-1] - self.assertEqual(lastdir, 'bar') - - def test_ext_fullpath(self): - ext = sysconfig.get_config_vars()['SO'] - # building lxml.etree inplace - #etree_c = os.path.join(self.tmp_dir, 'lxml.etree.c') - #etree_ext = Extension('lxml.etree', [etree_c]) - #dist = Distribution({'name': 'lxml', 'ext_modules': [etree_ext]}) - dist = Distribution() - cmd = build_ext(dist) - cmd.inplace = 1 - cmd.distribution.package_dir = {'': 'src'} - cmd.distribution.packages = ['lxml', 'lxml.html'] - curdir = os.getcwd() - wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext) - path = cmd.get_ext_fullpath('lxml.etree') - self.assertEqual(wanted, path) - - # building lxml.etree not inplace - cmd.inplace = 0 - cmd.build_lib = os.path.join(curdir, 'tmpdir') - wanted = os.path.join(curdir, 'tmpdir', 'lxml', 'etree' + ext) - path = cmd.get_ext_fullpath('lxml.etree') - self.assertEqual(wanted, path) - - # building twisted.runner.portmap not inplace - build_py = cmd.get_finalized_command('build_py') - build_py.package_dir = {} - cmd.distribution.packages = ['twisted', 'twisted.runner.portmap'] - path = cmd.get_ext_fullpath('twisted.runner.portmap') - wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner', - 'portmap' + ext) - self.assertEqual(wanted, path) - - # building twisted.runner.portmap inplace - cmd.inplace = 1 - path = cmd.get_ext_fullpath('twisted.runner.portmap') - wanted = os.path.join(curdir, 'twisted', 'runner', 'portmap' + ext) - self.assertEqual(wanted, path) - -def test_suite(): - src = _get_source_filename() - if not os.path.exists(src): - if distutils2.tests.verbose: - print ('test_build_ext: Cannot find source code (test' - ' must run in python build dir)') - return unittest.TestSuite() - else: return unittest.makeSuite(BuildExtTestCase) - -if __name__ == '__main__': - distutils2.tests.run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_build_py.py b/src/distutils2/tests/test_build_py.py deleted file mode 100644 index 4ee15f1..0000000 --- a/src/distutils2/tests/test_build_py.py +++ /dev/null @@ -1,122 +0,0 @@ -"""Tests for distutils.command.build_py.""" - -import os -import sys -import StringIO - -from distutils2.command.build_py import build_py -from distutils2.core import Distribution -from distutils2.errors import DistutilsFileError - -from distutils2.tests import support -from distutils2.tests.support import unittest - - -class BuildPyTestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - def test_package_data(self): - sources = self.mkdtemp() - f = open(os.path.join(sources, "__init__.py"), "w") - try: - f.write("# Pretend this is a package.") - finally: - f.close() - f = open(os.path.join(sources, "README.txt"), "w") - try: - f.write("Info about this package") - finally: - f.close() - - destination = self.mkdtemp() - - dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": sources}}) - # script_name need not exist, it just need to be initialized - dist.script_name = os.path.join(sources, "setup.py") - dist.command_obj["build"] = support.DummyCommand( - force=0, - build_lib=destination, - use_2to3_fixers=None, - convert_2to3_doctests=None, - use_2to3=False) - dist.packages = ["pkg"] - dist.package_data = {"pkg": ["README.txt"]} - dist.package_dir = {"pkg": sources} - - cmd = build_py(dist) - cmd.compile = 1 - cmd.ensure_finalized() - self.assertEqual(cmd.package_data, dist.package_data) - - cmd.run() - - # This makes sure the list of outputs includes byte-compiled - # files for Python modules but not for package data files - # (there shouldn't *be* byte-code files for those!). - # - self.assertEqual(len(cmd.get_outputs()), 3) - pkgdest = os.path.join(destination, "pkg") - files = os.listdir(pkgdest) - self.assertTrue("__init__.py" in files) - self.assertTrue("__init__.pyc" in files) - self.assertTrue("README.txt" in files) - - def test_empty_package_dir (self): - # See SF 1668596/1720897. - cwd = os.getcwd() - - # create the distribution files. - sources = self.mkdtemp() - open(os.path.join(sources, "__init__.py"), "w").close() - - testdir = os.path.join(sources, "doc") - os.mkdir(testdir) - open(os.path.join(testdir, "testfile"), "w").close() - - os.chdir(sources) - old_stdout = sys.stdout - sys.stdout = StringIO.StringIO() - - try: - dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": ""}, - "package_data": {"pkg": ["doc/*"]}}) - # script_name need not exist, it just need to be initialized - dist.script_name = os.path.join(sources, "setup.py") - dist.script_args = ["build"] - dist.parse_command_line() - - try: - dist.run_commands() - except DistutilsFileError: - self.fail("failed package_data test when package_dir is ''") - finally: - # Restore state. - os.chdir(cwd) - sys.stdout = old_stdout - - @unittest.skipUnless(hasattr(sys, 'dont_write_bytecode'), - 'sys.dont_write_bytecode not supported') - def test_dont_write_bytecode(self): - # makes sure byte_compile is not used - pkg_dir, dist = self.create_dist() - cmd = build_py(dist) - cmd.compile = 1 - cmd.optimize = 1 - - old_dont_write_bytecode = sys.dont_write_bytecode - sys.dont_write_bytecode = True - try: - cmd.byte_compile([]) - finally: - sys.dont_write_bytecode = old_dont_write_bytecode - - self.assertTrue('byte-compiling is disabled' in self.logs[0][1]) - -def test_suite(): - return unittest.makeSuite(BuildPyTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_build_scripts.py b/src/distutils2/tests/test_build_scripts.py deleted file mode 100644 index 3982d99..0000000 --- a/src/distutils2/tests/test_build_scripts.py +++ /dev/null @@ -1,117 +0,0 @@ -"""Tests for distutils.command.build_scripts.""" - -import os - -from distutils2.command.build_scripts import build_scripts -from distutils2.core import Distribution -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig - -from distutils2.tests import support -from distutils2.tests.support import unittest - - -class BuildScriptsTestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - def test_default_settings(self): - cmd = self.get_build_scripts_cmd("/foo/bar", []) - self.assertTrue(not cmd.force) - self.assertTrue(cmd.build_dir is None) - - cmd.finalize_options() - - self.assertTrue(cmd.force) - self.assertEqual(cmd.build_dir, "/foo/bar") - - def test_build(self): - source = self.mkdtemp() - target = self.mkdtemp() - expected = self.write_sample_scripts(source) - - cmd = self.get_build_scripts_cmd(target, - [os.path.join(source, fn) - for fn in expected]) - cmd.finalize_options() - cmd.run() - - built = os.listdir(target) - for name in expected: - self.assertTrue(name in built) - - def get_build_scripts_cmd(self, target, scripts): - import sys - dist = Distribution() - dist.scripts = scripts - dist.command_obj["build"] = support.DummyCommand( - build_scripts=target, - force=1, - executable=sys.executable, - use_2to3=False, - use_2to3_fixers=None, - convert_2to3_doctests=None - ) - return build_scripts(dist) - - def write_sample_scripts(self, dir): - expected = [] - expected.append("script1.py") - self.write_script(dir, "script1.py", - ("#! /usr/bin/env python2.3\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) - expected.append("script2.py") - self.write_script(dir, "script2.py", - ("#!/usr/bin/python\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) - expected.append("shell.sh") - self.write_script(dir, "shell.sh", - ("#!/bin/sh\n" - "# bogus shell script w/ sh-bang\n" - "exit 0\n")) - return expected - - def write_script(self, dir, name, text): - f = open(os.path.join(dir, name), "w") - try: - f.write(text) - finally: - f.close() - - def test_version_int(self): - source = self.mkdtemp() - target = self.mkdtemp() - expected = self.write_sample_scripts(source) - - - cmd = self.get_build_scripts_cmd(target, - [os.path.join(source, fn) - for fn in expected]) - cmd.finalize_options() - - # http://bugs.python.org/issue4524 - # - # On linux-g++-32 with command line `./configure --enable-ipv6 - # --with-suffix=3`, python is compiled okay but the build scripts - # failed when writing the name of the executable - old = sysconfig.get_config_vars().get('VERSION') - sysconfig._CONFIG_VARS['VERSION'] = 4 - try: - cmd.run() - finally: - if old is not None: - sysconfig._CONFIG_VARS['VERSION'] = old - - built = os.listdir(target) - for name in expected: - self.assertTrue(name in built) - -def test_suite(): - return unittest.makeSuite(BuildScriptsTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_ccompiler.py b/src/distutils2/tests/test_ccompiler.py deleted file mode 100644 index df25253..0000000 --- a/src/distutils2/tests/test_ccompiler.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Tests for distutils.ccompiler.""" -import os -from distutils2.tests import captured_stdout - -from distutils2.compiler.ccompiler import (gen_lib_options, CCompiler, - get_default_compiler, customize_compiler) -from distutils2.tests import support -from distutils2.tests.support import unittest - -class FakeCompiler(object): - def library_dir_option(self, dir): - return "-L" + dir - - def runtime_library_dir_option(self, dir): - return ["-cool", "-R" + dir] - - def find_library_file(self, dirs, lib, debug=0): - return 'found' - - def library_option(self, lib): - return "-l" + lib - -class CCompilerTestCase(support.EnvironGuard, unittest.TestCase): - - def test_gen_lib_options(self): - compiler = FakeCompiler() - libdirs = ['lib1', 'lib2'] - runlibdirs = ['runlib1'] - libs = [os.path.join('dir', 'name'), 'name2'] - - opts = gen_lib_options(compiler, libdirs, runlibdirs, libs) - wanted = ['-Llib1', '-Llib2', '-cool', '-Rrunlib1', 'found', - '-lname2'] - self.assertEqual(opts, wanted) - - def test_customize_compiler(self): - - # not testing if default compiler is not unix - if get_default_compiler() != 'unix': - return - - os.environ['AR'] = 'my_ar' - os.environ['ARFLAGS'] = '-arflags' - - # make sure AR gets caught - class compiler: - compiler_type = 'unix' - - def set_executables(self, **kw): - self.exes = kw - - comp = compiler() - customize_compiler(comp) - self.assertEqual(comp.exes['archiver'], 'my_ar -arflags') - -def test_suite(): - return unittest.makeSuite(CCompilerTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_check.py b/src/distutils2/tests/test_check.py deleted file mode 100644 index 02e2484..0000000 --- a/src/distutils2/tests/test_check.py +++ /dev/null @@ -1,85 +0,0 @@ -"""Tests for distutils.command.check.""" - -from distutils2.command.check import check -from distutils2.metadata import _HAS_DOCUTILS -from distutils2.tests import support -from distutils2.tests.support import unittest -from distutils2.errors import DistutilsSetupError - -class CheckTestCase(support.LoggingCatcher, - support.TempdirManager, - unittest.TestCase): - - def _run(self, metadata=None, **options): - if metadata is None: - metadata = {} - pkg_info, dist = self.create_dist(**metadata) - cmd = check(dist) - cmd.initialize_options() - for name, value in options.items(): - setattr(cmd, name, value) - cmd.ensure_finalized() - cmd.run() - return cmd - - def test_check_metadata(self): - # let's run the command with no metadata at all - # by default, check is checking the metadata - # should have some warnings - cmd = self._run() - self.assertTrue(len(cmd._warnings) > 0) - - # now let's add the required fields - # and run it again, to make sure we don't get - # any warning anymore - metadata = {'home_page': 'xxx', 'author': 'xxx', - 'author_email': 'xxx', - 'name': 'xxx', 'version': 'xxx' - } - cmd = self._run(metadata) - self.assertEqual(len(cmd._warnings), 0) - - # now with the strict mode, we should - # get an error if there are missing metadata - self.assertRaises(DistutilsSetupError, self._run, {}, **{'strict': 1}) - - # and of course, no error when all metadata fields are present - cmd = self._run(metadata, strict=1) - self.assertEqual(len(cmd._warnings), 0) - - @unittest.skipUnless(_HAS_DOCUTILS, "requires docutils") - def test_check_restructuredtext(self): - # let's see if it detects broken rest in long_description - broken_rest = 'title\n===\n\ntest' - pkg_info, dist = self.create_dist(description=broken_rest) - cmd = check(dist) - cmd.check_restructuredtext() - self.assertEqual(len(cmd._warnings), 1) - - pkg_info, dist = self.create_dist(description='title\n=====\n\ntest') - cmd = check(dist) - cmd.check_restructuredtext() - self.assertEqual(len(cmd._warnings), 0) - - def test_check_all(self): - - metadata = {'home_page': 'xxx', 'author': 'xxx'} - self.assertRaises(DistutilsSetupError, self._run, - {}, **{'strict': 1, - 'all': 1}) - - def test_check_hooks(self): - pkg_info, dist = self.create_dist() - dist.command_options['install'] = { - 'pre_hook': ('file', {"a": 'some.nonextistant.hook.ghrrraarrhll'}), - } - cmd = check(dist) - cmd.check_hooks_resolvable() - self.assertEqual(len(cmd._warnings), 1) - - -def test_suite(): - return unittest.makeSuite(CheckTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_clean.py b/src/distutils2/tests/test_clean.py deleted file mode 100644 index acc5b66..0000000 --- a/src/distutils2/tests/test_clean.py +++ /dev/null @@ -1,50 +0,0 @@ -"""Tests for distutils.command.clean.""" -import sys -import os -import getpass - -from distutils2.command.clean import clean -from distutils2.tests import support -from distutils2.tests.support import unittest - -class cleanTestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - def test_simple_run(self): - pkg_dir, dist = self.create_dist() - cmd = clean(dist) - - # let's add some elements clean should remove - dirs = [(d, os.path.join(pkg_dir, d)) - for d in ('build_temp', 'build_lib', 'bdist_base', - 'build_scripts', 'build_base')] - - for name, path in dirs: - os.mkdir(path) - setattr(cmd, name, path) - if name == 'build_base': - continue - for f in ('one', 'two', 'three'): - self.write_file(os.path.join(path, f)) - - # let's run the command - cmd.all = 1 - cmd.ensure_finalized() - cmd.run() - - # make sure the files where removed - for name, path in dirs: - self.assertTrue(not os.path.exists(path), - '%s was not removed' % path) - - # let's run the command again (should spit warnings but suceed) - cmd.all = 1 - cmd.ensure_finalized() - cmd.run() - -def test_suite(): - return unittest.makeSuite(cleanTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_cmd.py b/src/distutils2/tests/test_cmd.py deleted file mode 100644 index c768f79..0000000 --- a/src/distutils2/tests/test_cmd.py +++ /dev/null @@ -1,110 +0,0 @@ -"""Tests for distutils.cmd.""" -import os -from distutils2.tests import captured_stdout, run_unittest - -from distutils2.command.cmd import Command -from distutils2.dist import Distribution -from distutils2.errors import DistutilsOptionError -from distutils2.tests.support import unittest - -class MyCmd(Command): - def initialize_options(self): - pass - -class CommandTestCase(unittest.TestCase): - - def setUp(self): - dist = Distribution() - self.cmd = MyCmd(dist) - - def test_ensure_string_list(self): - - cmd = self.cmd - cmd.not_string_list = ['one', 2, 'three'] - cmd.yes_string_list = ['one', 'two', 'three'] - cmd.not_string_list2 = object() - cmd.yes_string_list2 = 'ok' - cmd.ensure_string_list('yes_string_list') - cmd.ensure_string_list('yes_string_list2') - - self.assertRaises(DistutilsOptionError, - cmd.ensure_string_list, 'not_string_list') - - self.assertRaises(DistutilsOptionError, - cmd.ensure_string_list, 'not_string_list2') - - def test_make_file(self): - - cmd = self.cmd - - # making sure it raises when infiles is not a string or a list/tuple - self.assertRaises(TypeError, cmd.make_file, - infiles=1, outfile='', func='func', args=()) - - # making sure execute gets called properly - def _execute(func, args, exec_msg, level): - self.assertEqual(exec_msg, 'generating out from in') - cmd.force = True - cmd.execute = _execute - cmd.make_file(infiles='in', outfile='out', func='func', args=()) - - def test_dump_options(self): - - msgs = [] - def _announce(msg, level): - msgs.append(msg) - cmd = self.cmd - cmd.announce = _announce - cmd.option1 = 1 - cmd.option2 = 1 - cmd.user_options = [('option1', '', ''), ('option2', '', '')] - cmd.dump_options() - - wanted = ["command options for 'MyCmd':", ' option1 = 1', - ' option2 = 1'] - self.assertEqual(msgs, wanted) - - def test_ensure_string(self): - cmd = self.cmd - cmd.option1 = 'ok' - cmd.ensure_string('option1') - - cmd.option2 = None - cmd.ensure_string('option2', 'xxx') - self.assertTrue(hasattr(cmd, 'option2')) - - cmd.option3 = 1 - self.assertRaises(DistutilsOptionError, cmd.ensure_string, 'option3') - - def test_ensure_string_list(self): - cmd = self.cmd - cmd.option1 = 'ok,dok' - cmd.ensure_string_list('option1') - self.assertEqual(cmd.option1, ['ok', 'dok']) - - cmd.option2 = ['xxx', 'www'] - cmd.ensure_string_list('option2') - - cmd.option3 = ['ok', 2] - self.assertRaises(DistutilsOptionError, cmd.ensure_string_list, - 'option3') - - def test_ensure_filename(self): - cmd = self.cmd - cmd.option1 = __file__ - cmd.ensure_filename('option1') - cmd.option2 = 'xxx' - self.assertRaises(DistutilsOptionError, cmd.ensure_filename, 'option2') - - def test_ensure_dirname(self): - cmd = self.cmd - cmd.option1 = os.path.dirname(__file__) or os.curdir - cmd.ensure_dirname('option1') - cmd.option2 = 'xxx' - self.assertRaises(DistutilsOptionError, cmd.ensure_dirname, 'option2') - -def test_suite(): - return unittest.makeSuite(CommandTestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_config_cmd.py b/src/distutils2/tests/test_config_cmd.py deleted file mode 100644 index eab12fd..0000000 --- a/src/distutils2/tests/test_config_cmd.py +++ /dev/null @@ -1,89 +0,0 @@ -"""Tests for distutils.command.config.""" -import os -import sys - -from distutils2.command.config import dump_file, config -from distutils2.tests import support -from distutils2.tests.support import unittest -from distutils2 import log - -class ConfigTestCase(support.LoggingCatcher, - support.TempdirManager, - unittest.TestCase): - - def _info(self, msg, *args): - for line in msg.splitlines(): - self._logs.append(line) - - def setUp(self): - super(ConfigTestCase, self).setUp() - self._logs = [] - self.old_log = log.info - log.info = self._info - - def tearDown(self): - log.info = self.old_log - super(ConfigTestCase, self).tearDown() - - def test_dump_file(self): - this_file = os.path.splitext(__file__)[0] + '.py' - f = open(this_file) - try: - numlines = len(f.readlines()) - finally: - f.close() - - dump_file(this_file, 'I am the header') - self.assertEqual(len(self._logs), numlines+1) - - def test_search_cpp(self): - if sys.platform == 'win32': - return - pkg_dir, dist = self.create_dist() - cmd = config(dist) - - # simple pattern searches - match = cmd.search_cpp(pattern='xxx', body='// xxx') - self.assertEqual(match, 0) - - match = cmd.search_cpp(pattern='_configtest', body='// xxx') - self.assertEqual(match, 1) - - def test_finalize_options(self): - # finalize_options does a bit of transformation - # on options - pkg_dir, dist = self.create_dist() - cmd = config(dist) - cmd.include_dirs = 'one%stwo' % os.pathsep - cmd.libraries = 'one' - cmd.library_dirs = 'three%sfour' % os.pathsep - cmd.ensure_finalized() - - self.assertEqual(cmd.include_dirs, ['one', 'two']) - self.assertEqual(cmd.libraries, ['one']) - self.assertEqual(cmd.library_dirs, ['three', 'four']) - - def test_clean(self): - # _clean removes files - tmp_dir = self.mkdtemp() - f1 = os.path.join(tmp_dir, 'one') - f2 = os.path.join(tmp_dir, 'two') - - self.write_file(f1, 'xxx') - self.write_file(f2, 'xxx') - - for f in (f1, f2): - self.assertTrue(os.path.exists(f)) - - pkg_dir, dist = self.create_dist() - cmd = config(dist) - cmd._clean(f1, f2) - - for f in (f1, f2): - self.assertTrue(not os.path.exists(f)) - -def test_suite(): - return unittest.makeSuite(ConfigTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_core.py b/src/distutils2/tests/test_core.py deleted file mode 100644 index 883187e..0000000 --- a/src/distutils2/tests/test_core.py +++ /dev/null @@ -1,98 +0,0 @@ -"""Tests for distutils2.core.""" - -import StringIO -import distutils2.core -import os -import shutil -import sys -from distutils2.tests import captured_stdout -from distutils2.tests import support -from distutils2.tests.support import unittest - -# setup script that uses __file__ -setup_using___file__ = """\ - -__file__ - -from distutils2.core import setup -setup() -""" - -setup_prints_cwd = """\ - -import os -print os.getcwd() - -from distutils2.core import setup -setup() -""" - - -class CoreTestCase(support.EnvironGuard, unittest.TestCase): - - def setUp(self): - super(CoreTestCase, self).setUp() - self.old_stdout = sys.stdout - self.cleanup_testfn() - self.old_argv = sys.argv, sys.argv[:] - - def tearDown(self): - sys.stdout = self.old_stdout - self.cleanup_testfn() - sys.argv = self.old_argv[0] - sys.argv[:] = self.old_argv[1] - super(CoreTestCase, self).tearDown() - - def cleanup_testfn(self): - path = distutils2.tests.TESTFN - if os.path.isfile(path): - os.remove(path) - elif os.path.isdir(path): - shutil.rmtree(path) - - def write_setup(self, text, path=distutils2.tests.TESTFN): - open(path, "w").write(text) - return path - - def test_run_setup_provides_file(self): - # Make sure the script can use __file__; if that's missing, the test - # setup.py script will raise NameError. - distutils2.core.run_setup( - self.write_setup(setup_using___file__)) - - def test_run_setup_stop_after(self): - f = self.write_setup(setup_using___file__) - for s in ['init', 'config', 'commandline', 'run']: - distutils2.core.run_setup(f, stop_after=s) - self.assertRaises(ValueError, distutils2.core.run_setup, - f, stop_after='bob') - - def test_run_setup_args(self): - f = self.write_setup(setup_using___file__) - d = distutils2.core.run_setup(f, script_args=["--help"], - stop_after="init") - self.assertEqual(['--help'], d.script_args) - - def test_run_setup_uses_current_dir(self): - # This tests that the setup script is run with the current directory - # as its own current directory; this was temporarily broken by a - # previous patch when TESTFN did not use the current directory. - sys.stdout = StringIO.StringIO() - cwd = os.getcwd() - - # Create a directory and write the setup.py file there: - os.mkdir(distutils2.tests.TESTFN) - setup_py = os.path.join(distutils2.tests.TESTFN, "setup.py") - distutils2.core.run_setup( - self.write_setup(setup_prints_cwd, path=setup_py)) - - output = sys.stdout.getvalue() - if output.endswith("\n"): - output = output[:-1] - self.assertEqual(cwd, output) - -def test_suite(): - return unittest.makeSuite(CoreTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_cygwinccompiler.py b/src/distutils2/tests/test_cygwinccompiler.py deleted file mode 100644 index 5516fbd..0000000 --- a/src/distutils2/tests/test_cygwinccompiler.py +++ /dev/null @@ -1,99 +0,0 @@ -"""Tests for distutils.cygwinccompiler.""" -import sys -import os -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig - -from distutils2.tests import run_unittest -from distutils2.tests import captured_stdout - -from distutils2.compiler import cygwinccompiler -from distutils2.compiler.cygwinccompiler import (CygwinCCompiler, check_config_h, - CONFIG_H_OK, CONFIG_H_NOTOK, - CONFIG_H_UNCERTAIN, get_versions, - get_msvcr, RE_VERSION) -from distutils2.util import get_compiler_versions -from distutils2.tests import support -from distutils2.tests.support import unittest - -class CygwinCCompilerTestCase(support.TempdirManager, - unittest.TestCase): - - def setUp(self): - super(CygwinCCompilerTestCase, self).setUp() - self.version = sys.version - self.python_h = os.path.join(self.mkdtemp(), 'python.h') - self.old_get_config_h_filename = sysconfig.get_config_h_filename - sysconfig.get_config_h_filename = self._get_config_h_filename - - def tearDown(self): - sys.version = self.version - sysconfig.get_config_h_filename = self.old_get_config_h_filename - super(CygwinCCompilerTestCase, self).tearDown() - - def _get_config_h_filename(self): - return self.python_h - - def test_check_config_h(self): - - # check_config_h looks for "GCC" in sys.version first - # returns CONFIG_H_OK if found - sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) \n[GCC ' - '4.0.1 (Apple Computer, Inc. build 5370)]') - - self.assertEqual(check_config_h()[0], CONFIG_H_OK) - - # then it tries to see if it can find "__GNUC__" in pyconfig.h - sys.version = 'something without the *CC word' - - # if the file doesn't exist it returns CONFIG_H_UNCERTAIN - self.assertEqual(check_config_h()[0], CONFIG_H_UNCERTAIN) - - # if it exists but does not contain __GNUC__, it returns CONFIG_H_NOTOK - self.write_file(self.python_h, 'xxx') - self.assertEqual(check_config_h()[0], CONFIG_H_NOTOK) - - # and CONFIG_H_OK if __GNUC__ is found - self.write_file(self.python_h, 'xxx __GNUC__ xxx') - self.assertEqual(check_config_h()[0], CONFIG_H_OK) - - def test_get_msvcr(self): - - # none - sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) ' - '\n[GCC 4.0.1 (Apple Computer, Inc. build 5370)]') - self.assertEqual(get_msvcr(), None) - - # MSVC 7.0 - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1300 32 bits (Intel)]') - self.assertEqual(get_msvcr(), ['msvcr70']) - - # MSVC 7.1 - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1310 32 bits (Intel)]') - self.assertEqual(get_msvcr(), ['msvcr71']) - - # VS2005 / MSVC 8.0 - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1400 32 bits (Intel)]') - self.assertEqual(get_msvcr(), ['msvcr80']) - - # VS2008 / MSVC 9.0 - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1500 32 bits (Intel)]') - self.assertEqual(get_msvcr(), ['msvcr90']) - - # unknown - sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) ' - '[MSC v.1999 32 bits (Intel)]') - self.assertRaises(ValueError, get_msvcr) - - -def test_suite(): - return unittest.makeSuite(CygwinCCompilerTestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_depgraph.py b/src/distutils2/tests/test_depgraph.py deleted file mode 100644 index fa38b91..0000000 --- a/src/distutils2/tests/test_depgraph.py +++ /dev/null @@ -1,187 +0,0 @@ -"""Tests for distutils.depgraph """ - -from distutils2.tests import support -from distutils2.tests.support import unittest -from distutils2 import depgraph -from distutils2._backport import pkgutil - -import os -import sys -import re -try: - import cStringIO as StringIO -except ImportError: - import StringIO - -class DepGraphTestCase(support.LoggingCatcher, - unittest.TestCase): - - DISTROS_DIST = ('choxie', 'grammar', 'towel-stuff') - DISTROS_EGG = ('bacon', 'banana', 'strawberry', 'cheese') - EDGE = re.compile( - r'"(?P<from>.*)" -> "(?P<to>.*)" \[label="(?P<label>.*)"\]' - ) - - def checkLists(self, l1, l2): - """ Compare two lists without taking the order into consideration """ - self.assertListEqual(sorted(l1), sorted(l2)) - - def setUp(self): - super(DepGraphTestCase, self).setUp() - path = os.path.join(os.path.dirname(__file__), '..', '_backport', - 'tests', 'fake_dists') - path = os.path.abspath(path) - self.sys_path = sys.path[:] - sys.path[0:0] = [path] - - def test_generate_graph(self): - dists = [] - for name in self.DISTROS_DIST: - dist = pkgutil.get_distribution(name) - self.assertNotEqual(dist, None) - dists.append(dist) - - choxie, grammar, towel = dists - - graph = depgraph.generate_graph(dists) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[choxie]] - self.checkLists([('towel-stuff', 'towel-stuff (0.1)')], deps) - self.assertTrue(choxie in graph.reverse_list[towel]) - self.checkLists(graph.missing[choxie], []) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[grammar]] - self.checkLists([], deps) - self.checkLists(graph.missing[grammar], ['truffles (>=1.2)']) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[towel]] - self.checkLists([], deps) - self.checkLists(graph.missing[towel], ['bacon (<=0.2)']) - - def test_generate_graph_egg(self): - dists = [] - for name in self.DISTROS_DIST + self.DISTROS_EGG: - dist = pkgutil.get_distribution(name, use_egg_info=True) - self.assertNotEqual(dist, None) - dists.append(dist) - - choxie, grammar, towel, bacon, banana, strawberry, cheese = dists - - graph = depgraph.generate_graph(dists) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[choxie]] - self.checkLists([('towel-stuff', 'towel-stuff (0.1)')], deps) - self.assertTrue(choxie in graph.reverse_list[towel]) - self.checkLists(graph.missing[choxie], []) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[grammar]] - self.checkLists([('bacon', 'truffles (>=1.2)')], deps) - self.checkLists(graph.missing[grammar], []) - self.assertTrue(grammar in graph.reverse_list[bacon]) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[towel]] - self.checkLists([('bacon', 'bacon (<=0.2)')], deps) - self.checkLists(graph.missing[towel], []) - self.assertTrue(towel in graph.reverse_list[bacon]) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[bacon]] - self.checkLists([], deps) - self.checkLists(graph.missing[bacon], []) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[banana]] - self.checkLists([('strawberry', 'strawberry (>=0.5)')], deps) - self.checkLists(graph.missing[banana], []) - self.assertTrue(banana in graph.reverse_list[strawberry]) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[strawberry]] - self.checkLists([], deps) - self.checkLists(graph.missing[strawberry], []) - - deps = [(x.name, y) for (x,y) in graph.adjacency_list[cheese]] - self.checkLists([], deps) - self.checkLists(graph.missing[cheese], []) - - def test_dependent_dists(self): - dists = [] - for name in self.DISTROS_DIST: - dist = pkgutil.get_distribution(name) - self.assertNotEqual(dist, None) - dists.append(dist) - - choxie, grammar, towel = dists - - deps = [d.name for d in depgraph.dependent_dists(dists, choxie)] - self.checkLists([], deps) - - deps = [d.name for d in depgraph.dependent_dists(dists, grammar)] - self.checkLists([], deps) - - deps = [d.name for d in depgraph.dependent_dists(dists, towel)] - self.checkLists(['choxie'], deps) - - - def test_dependent_dists_egg(self): - dists = [] - for name in self.DISTROS_DIST + self.DISTROS_EGG: - dist = pkgutil.get_distribution(name, use_egg_info=True) - self.assertNotEqual(dist, None) - dists.append(dist) - - choxie, grammar, towel, bacon, banana, strawberry, cheese = dists - - deps = [d.name for d in depgraph.dependent_dists(dists, choxie)] - self.checkLists([], deps) - - deps = [d.name for d in depgraph.dependent_dists(dists, grammar)] - self.checkLists([], deps) - - deps = [d.name for d in depgraph.dependent_dists(dists, towel)] - self.checkLists(['choxie'], deps) - - deps = [d.name for d in depgraph.dependent_dists(dists, bacon)] - self.checkLists(['choxie', 'towel-stuff', 'grammar'], deps) - - deps = [d.name for d in depgraph.dependent_dists(dists, strawberry)] - self.checkLists(['banana'], deps) - - deps = [d.name for d in depgraph.dependent_dists(dists, cheese)] - self.checkLists([], deps) - - def test_graph_to_dot(self): - expected = ( - ('towel-stuff', 'bacon', 'bacon (<=0.2)'), - ('grammar', 'bacon', 'truffles (>=1.2)'), - ('choxie', 'towel-stuff', 'towel-stuff (0.1)'), - ('banana', 'strawberry', 'strawberry (>=0.5)') - ) - - dists = [] - for name in self.DISTROS_DIST + self.DISTROS_EGG: - dist = pkgutil.get_distribution(name, use_egg_info=True) - self.assertNotEqual(dist, None) - dists.append(dist) - - graph = depgraph.generate_graph(dists) - buf = StringIO.StringIO() - depgraph.graph_to_dot(graph, buf) - buf.seek(0) - matches = [] - lines = buf.readlines() - for line in lines[1:-1]: # skip the first and the last lines - if line[-1] == '\n': - line = line[:-1] - match = self.EDGE.match(line.strip()) - self.assertTrue(match is not None) - matches.append(match.groups()) - - self.checkLists(matches, expected) - - def tearDown(self): - super(DepGraphTestCase, self).tearDown() - sys.path = self.sys_path - -def test_suite(): - return unittest.makeSuite(DepGraphTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_dist.py b/src/distutils2/tests/test_dist.py deleted file mode 100644 index 4cbcbad..0000000 --- a/src/distutils2/tests/test_dist.py +++ /dev/null @@ -1,533 +0,0 @@ -# -*- coding: utf-8 -*- - -"""Tests for distutils2.dist.""" -import os -import StringIO -import sys -import textwrap - -import distutils2.dist -from distutils2.dist import Distribution, fix_help_options -from distutils2.command.cmd import Command -from distutils2.errors import DistutilsModuleError, DistutilsOptionError -from distutils2.tests import TESTFN, captured_stdout -from distutils2.tests import support -from distutils2.tests.support import unittest, create_distribution - - -class test_dist(Command): - """Sample distutils2 extension command.""" - - user_options = [ - ("sample-option=", "S", "help text"), - ] - - def initialize_options(self): - self.sample_option = None - - def finalize_options(self): - pass - - -class DistributionTestCase(support.TempdirManager, - support.LoggingCatcher, - support.WarningsCatcher, - support.EnvironGuard, - unittest.TestCase): - - def setUp(self): - super(DistributionTestCase, self).setUp() - self.argv = sys.argv, sys.argv[:] - del sys.argv[1:] - - def tearDown(self): - sys.argv = self.argv[0] - sys.argv[:] = self.argv[1] - super(DistributionTestCase, self).tearDown() - - def test_debug_mode(self): - self.addCleanup(os.unlink, TESTFN) - f = open(TESTFN, "w") - try: - f.write("[global]\n") - f.write("command_packages = foo.bar, splat") - finally: - f.close() - - files = [TESTFN] - sys.argv.append("build") - - __, stdout = captured_stdout(create_distribution, files) - self.assertEqual(stdout, '') - distutils2.dist.DEBUG = True - try: - __, stdout = captured_stdout(create_distribution, files) - self.assertEqual(stdout, '') - finally: - distutils2.dist.DEBUG = False - - def test_command_packages_unspecified(self): - sys.argv.append("build") - d = create_distribution() - self.assertEqual(d.get_command_packages(), ["distutils2.command"]) - - def test_command_packages_cmdline(self): - from distutils2.tests.test_dist import test_dist - sys.argv.extend(["--command-packages", - "foo.bar,distutils2.tests", - "test_dist", - "-Ssometext", - ]) - d = create_distribution() - # let's actually try to load our test command: - self.assertEqual(d.get_command_packages(), - ["distutils2.command", "foo.bar", "distutils2.tests"]) - cmd = d.get_command_obj("test_dist") - self.assertTrue(isinstance(cmd, test_dist)) - self.assertEqual(cmd.sample_option, "sometext") - - def test_command_packages_configfile(self): - sys.argv.append("build") - f = open(TESTFN, "w") - try: - print >> f, "[global]" - print >> f, "command_packages = foo.bar, splat" - f.close() - d = create_distribution([TESTFN]) - self.assertEqual(d.get_command_packages(), - ["distutils2.command", "foo.bar", "splat"]) - - # ensure command line overrides config: - sys.argv[1:] = ["--command-packages", "spork", "build"] - d = create_distribution([TESTFN]) - self.assertEqual(d.get_command_packages(), - ["distutils2.command", "spork"]) - - # Setting --command-packages to '' should cause the default to - # be used even if a config file specified something else: - sys.argv[1:] = ["--command-packages", "", "build"] - d = create_distribution([TESTFN]) - self.assertEqual(d.get_command_packages(), ["distutils2.command"]) - - finally: - os.unlink(TESTFN) - - def test_write_pkg_file(self): - # Check DistributionMetadata handling of Unicode fields - tmp_dir = self.mkdtemp() - my_file = os.path.join(tmp_dir, 'f') - cls = Distribution - - dist = cls(attrs={'author': u'Mister Café', - 'name': 'my.package', - 'maintainer': u'Café Junior', - 'summary': u'Café torréfié', - 'description': u'Héhéhé'}) - - # let's make sure the file can be written - # with Unicode fields. they are encoded with - # PKG_INFO_ENCODING - dist.metadata.write_file(open(my_file, 'w')) - - # regular ascii is of course always usable - dist = cls(attrs={'author': 'Mister Cafe', - 'name': 'my.package', - 'maintainer': 'Cafe Junior', - 'summary': 'Cafe torrefie', - 'description': 'Hehehe'}) - - dist.metadata.write_file(open(my_file, 'w')) - - def test_bad_attr(self): - Distribution(attrs={'author': 'xxx', - 'name': 'xxx', - 'version': 'xxx', - 'url': 'xxxx', - 'badoptname': 'xxx'}) - - self.assertEqual(len(self.warnings), 1) - self.assertIn("Unknown distribution", - self.warnings[0]['message'].args[0]) - - def test_empty_options(self): - # an empty options dictionary should not stay in the - # list of attributes - Distribution(attrs={'author': 'xxx', - 'name': 'xxx', - 'version': 'xxx', - 'url': 'xxxx', - 'options': {}}) - - self.assertEqual(len(self.warnings), 0) - - def test_non_empty_options(self): - # TODO: how to actually use options is not documented except - # for a few cryptic comments in dist.py. If this is to stay - # in the public API, it deserves some better documentation. - - # Here is an example of how it's used out there: - # http://svn.pythonmac.org/py2app/py2app/trunk/doc/ - # index.html#specifying-customizations - dist = Distribution(attrs={'author': 'xxx', - 'name': 'xxx', - 'version': 'xxx', - 'url': 'xxxx', - 'options': {'sdist': {'owner': 'root'}}}) - - self.assertIn('owner', dist.get_option_dict('sdist')) - - def test_finalize_options(self): - - attrs = {'keywords': 'one,two', - 'platform': 'one,two'} - - dist = Distribution(attrs=attrs) - dist.finalize_options() - - # finalize_option splits platforms and keywords - self.assertEqual(dist.metadata['platform'], ['one', 'two']) - self.assertEqual(dist.metadata['keywords'], ['one', 'two']) - - def test_get_command_packages(self): - dist = Distribution() - self.assertEqual(dist.command_packages, None) - cmds = dist.get_command_packages() - self.assertEqual(cmds, ['distutils2.command']) - self.assertEqual(dist.command_packages, - ['distutils2.command']) - - dist.command_packages = 'one,two' - cmds = dist.get_command_packages() - self.assertEqual(cmds, ['distutils2.command', 'one', 'two']) - - def test_announce(self): - # make sure the level is known - dist = Distribution() - args = ('ok',) - kwargs = {'level': 'ok2'} - self.assertRaises(ValueError, dist.announce, args, kwargs) - - def test_find_config_files_disable(self): - # Bug #1180: Allow users to disable their own config file. - temp_home = self.mkdtemp() - if os.name == 'posix': - user_filename = os.path.join(temp_home, ".pydistutils.cfg") - else: - user_filename = os.path.join(temp_home, "pydistutils.cfg") - - f = open(user_filename, 'w') - try: - f.write('[distutils2]\n') - finally: - f.close() - - def _expander(path): - return temp_home - - old_expander = os.path.expanduser - os.path.expanduser = _expander - try: - d = distutils2.dist.Distribution() - all_files = d.find_config_files() - - d = distutils2.dist.Distribution(attrs={'script_args': - ['--no-user-cfg']}) - files = d.find_config_files() - finally: - os.path.expanduser = old_expander - - # make sure --no-user-cfg disables the user cfg file - self.assertEqual(len(all_files) - 1, len(files)) - - def test_special_hooks_parsing(self): - temp_home = self.mkdtemp() - config_files = [os.path.join(temp_home, "config1.cfg"), - os.path.join(temp_home, "config2.cfg")] - - # Store two aliased hooks in config files - self.write_file((temp_home, "config1.cfg"), - '[test_dist]\npre-hook.a = type') - self.write_file((temp_home, "config2.cfg"), - '[test_dist]\npre-hook.b = type') - - sys.argv.extend(["--command-packages", - "distutils2.tests", - "test_dist"]) - dist = create_distribution(config_files) - cmd = dist.get_command_obj("test_dist") - - self.assertEqual(cmd.pre_hook, {"a": 'type', "b": 'type'}) - - def test_hooks_get_run(self): - temp_home = self.mkdtemp() - config_file = os.path.join(temp_home, "config1.cfg") - hooks_module = os.path.join(temp_home, "testhooks.py") - - self.write_file(config_file, textwrap.dedent(''' - [test_dist] - pre-hook.test = testhooks.log_pre_call - post-hook.test = testhooks.log_post_call''')) - - self.write_file(hooks_module, textwrap.dedent(''' - record = [] - - def log_pre_call(cmd): - record.append('pre-%s' % cmd.get_command_name()) - - def log_post_call(cmd): - record.append('post-%s' % cmd.get_command_name()) - ''')) - - sys.argv.extend(["--command-packages", - "distutils2.tests", - "test_dist"]) - - d = create_distribution([config_file]) - cmd = d.get_command_obj("test_dist") - - # prepare the call recorders - sys.path.append(temp_home) - from testhooks import record - - self.addCleanup(setattr, cmd, 'run', cmd.run) - self.addCleanup(setattr, cmd, 'finalize_options', - cmd.finalize_options) - - cmd.run = lambda: record.append('run') - cmd.finalize_options = lambda: record.append('finalize') - - d.run_command('test_dist') - - self.assertEqual(record, ['finalize', - 'pre-test_dist', - 'run', - 'post-test_dist']) - - def test_hooks_importable(self): - temp_home = self.mkdtemp() - config_file = os.path.join(temp_home, "config1.cfg") - - self.write_file(config_file, textwrap.dedent(''' - [test_dist] - pre-hook.test = nonexistent.dotted.name''')) - - sys.argv.extend(["--command-packages", - "distutils2.tests", - "test_dist"]) - - d = create_distribution([config_file]) - cmd = d.get_command_obj("test_dist") - cmd.ensure_finalized() - - self.assertRaises(DistutilsModuleError, d.run_command, 'test_dist') - - def test_hooks_callable(self): - temp_home = self.mkdtemp() - config_file = os.path.join(temp_home, "config1.cfg") - - self.write_file(config_file, textwrap.dedent(''' - [test_dist] - pre-hook.test = distutils2.tests.test_dist.__doc__''')) - - sys.argv.extend(["--command-packages", - "distutils2.tests", - "test_dist"]) - - d = create_distribution([config_file]) - cmd = d.get_command_obj("test_dist") - cmd.ensure_finalized() - - self.assertRaises(DistutilsOptionError, d.run_command, 'test_dist') - - -class MetadataTestCase(support.TempdirManager, support.EnvironGuard, - support.LoggingCatcher, unittest.TestCase): - - def setUp(self): - super(MetadataTestCase, self).setUp() - self.argv = sys.argv, sys.argv[:] - - def tearDown(self): - sys.argv = self.argv[0] - sys.argv[:] = self.argv[1] - super(MetadataTestCase, self).tearDown() - - def test_simple_metadata(self): - attrs = {"name": "package", - "version": "1.0"} - dist = Distribution(attrs) - meta = self.format_metadata(dist) - self.assertTrue("Metadata-Version: 1.0" in meta) - self.assertTrue("provides:" not in meta.lower()) - self.assertTrue("requires:" not in meta.lower()) - self.assertTrue("obsoletes:" not in meta.lower()) - - def test_provides_dist(self): - attrs = {"name": "package", - "version": "1.0", - "provides_dist": ["package", "package.sub"]} - dist = Distribution(attrs) - self.assertEqual(dist.metadata['Provides-Dist'], - ["package", "package.sub"]) - meta = self.format_metadata(dist) - self.assertTrue("Metadata-Version: 1.2" in meta) - self.assertTrue("requires:" not in meta.lower()) - self.assertTrue("obsoletes:" not in meta.lower()) - - def _test_provides_illegal(self): - # XXX to do: check the versions - self.assertRaises(ValueError, Distribution, - {"name": "package", - "version": "1.0", - "provides_dist": ["my.pkg (splat)"]}) - - def test_requires_dist(self): - attrs = {"name": "package", - "version": "1.0", - "requires_dist": ["other", "another (==1.0)"]} - dist = Distribution(attrs) - self.assertEqual(dist.metadata['Requires-Dist'], - ["other", "another (==1.0)"]) - meta = self.format_metadata(dist) - self.assertTrue("Metadata-Version: 1.2" in meta) - self.assertTrue("provides:" not in meta.lower()) - self.assertTrue("Requires-Dist: other" in meta) - self.assertTrue("Requires-Dist: another (==1.0)" in meta) - self.assertTrue("obsoletes:" not in meta.lower()) - - def _test_requires_illegal(self): - # XXX - self.assertRaises(ValueError, Distribution, - {"name": "package", - "version": "1.0", - "requires": ["my.pkg (splat)"]}) - - def test_obsoletes_dist(self): - attrs = {"name": "package", - "version": "1.0", - "obsoletes_dist": ["other", "another (<1.0)"]} - dist = Distribution(attrs) - self.assertEqual(dist.metadata['Obsoletes-Dist'], - ["other", "another (<1.0)"]) - meta = self.format_metadata(dist) - self.assertTrue("Metadata-Version: 1.2" in meta) - self.assertTrue("provides:" not in meta.lower()) - self.assertTrue("requires:" not in meta.lower()) - self.assertTrue("Obsoletes-Dist: other" in meta) - self.assertTrue("Obsoletes-Dist: another (<1.0)" in meta) - - def _test_obsoletes_illegal(self): - # XXX - self.assertRaises(ValueError, Distribution, - {"name": "package", - "version": "1.0", - "obsoletes": ["my.pkg (splat)"]}) - - def format_metadata(self, dist): - sio = StringIO.StringIO() - dist.metadata.write_file(sio) - return sio.getvalue() - - def test_custom_pydistutils(self): - # fixes #2166 - # make sure pydistutils.cfg is found - if os.name == 'posix': - user_filename = ".pydistutils.cfg" - else: - user_filename = "pydistutils.cfg" - - temp_dir = self.mkdtemp() - user_filename = os.path.join(temp_dir, user_filename) - f = open(user_filename, 'w') - try: - f.write('.') - finally: - f.close() - - try: - dist = Distribution() - - # linux-style - if sys.platform in ('linux', 'darwin'): - os.environ['HOME'] = temp_dir - files = dist.find_config_files() - self.assertTrue(user_filename in files) - - # win32-style - if sys.platform == 'win32': - # home drive should be found - os.environ['HOME'] = temp_dir - files = dist.find_config_files() - self.assertTrue(user_filename in files, - '%r not found in %r' % (user_filename, files)) - finally: - os.remove(user_filename) - - def test_fix_help_options(self): - help_tuples = [('a', 'b', 'c', 'd'), (1, 2, 3, 4)] - fancy_options = fix_help_options(help_tuples) - self.assertEqual(fancy_options[0], ('a', 'b', 'c')) - self.assertEqual(fancy_options[1], (1, 2, 3)) - - def test_show_help(self): - # smoke test, just makes sure some help is displayed - dist = Distribution() - sys.argv = [] - dist.help = 1 - dist.script_name = 'setup.py' - __, stdout = captured_stdout(dist.parse_command_line) - output = [line for line in stdout.split('\n') - if line.strip() != ''] - self.assertTrue(len(output) > 0) - - def test_description(self): - desc = textwrap.dedent("""\ - example:: - We start here - and continue here - and end here.""") - attrs = {"name": "package", - "version": "1.0", - "description": desc} - - dist = distutils2.dist.Distribution(attrs) - meta = self.format_metadata(dist) - meta = meta.replace('\n' + 7 * ' ' + '|', '\n') - self.assertTrue(desc in meta) - - def test_read_metadata(self): - attrs = {"name": "package", - "version": "1.0", - "description": "desc", - "summary": "xxx", - "download_url": "http://example.com", - "keywords": ['one', 'two'], - "requires_dist": ['foo']} - - dist = Distribution(attrs) - metadata = dist.metadata - - # write it then reloads it - PKG_INFO = StringIO.StringIO() - metadata.write_file(PKG_INFO) - PKG_INFO.seek(0) - - metadata.read_file(PKG_INFO) - self.assertEqual(metadata['name'], "package") - self.assertEqual(metadata['version'], "1.0") - self.assertEqual(metadata['summary'], "xxx") - self.assertEqual(metadata['download_url'], 'http://example.com') - self.assertEqual(metadata['keywords'], ['one', 'two']) - self.assertEqual(metadata['platform'], []) - self.assertEqual(metadata['obsoletes'], []) - self.assertEqual(metadata['requires-dist'], ['foo']) - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(DistributionTestCase)) - suite.addTest(unittest.makeSuite(MetadataTestCase)) - return suite - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_emxccompiler.py b/src/distutils2/tests/test_emxccompiler.py deleted file mode 100644 index 5b042dc..0000000 --- a/src/distutils2/tests/test_emxccompiler.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Tests for distutils.emxccompiler.""" -import sys -import os - -from distutils2.tests import run_unittest -from distutils2.tests import captured_stdout - -from distutils2.compiler.emxccompiler import get_versions -from distutils2.util import get_compiler_versions -from distutils2.tests import support -from distutils2.tests.support import unittest - -class EmxCCompilerTestCase(support.TempdirManager, - unittest.TestCase): - - pass - -def test_suite(): - return unittest.makeSuite(EmxCCompilerTestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_extension.py b/src/distutils2/tests/test_extension.py deleted file mode 100644 index d98ce43..0000000 --- a/src/distutils2/tests/test_extension.py +++ /dev/null @@ -1,15 +0,0 @@ -"""Tests for distutils.extension.""" -import os - -from distutils2.extension import Extension -from distutils2.tests.support import unittest - -class ExtensionTestCase(unittest.TestCase): - - pass - -def test_suite(): - return unittest.makeSuite(ExtensionTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_index_dist.py b/src/distutils2/tests/test_index_dist.py deleted file mode 100644 index 9020635..0000000 --- a/src/distutils2/tests/test_index_dist.py +++ /dev/null @@ -1,248 +0,0 @@ -"""Tests for the distutils2.index.dist module.""" - -import os - -from distutils2.tests.pypi_server import use_pypi_server -from distutils2.tests import run_unittest -from distutils2.tests.support import unittest, TempdirManager -from distutils2.version import VersionPredicate -from distutils2.index.errors import HashDoesNotMatch, UnsupportedHashName -from distutils2.index.dist import (ReleaseInfo, ReleasesList, DistInfo, - split_archive_name, get_infos_from_url) - - -def Dist(*args, **kwargs): - # DistInfo takes a release as a first parameter, avoid this in tests. - return DistInfo(None, *args, **kwargs) - - -class TestReleaseInfo(unittest.TestCase): - - def test_instantiation(self): - # Test the DistInfo class provides us the good attributes when - # given on construction - release = ReleaseInfo("FooBar", "1.1") - self.assertEqual("FooBar", release.name) - self.assertEqual("1.1", "%s" % release.version) - - def test_add_dist(self): - # empty distribution type should assume "sdist" - release = ReleaseInfo("FooBar", "1.1") - release.add_distribution(url="http://example.org/") - # should not fail - release['sdist'] - - def test_get_unknown_distribution(self): - # should raise a KeyError - pass - - def test_get_infos_from_url(self): - # Test that the the URLs are parsed the right way - url_list = { - 'FooBar-1.1.0.tar.gz': { - 'name': 'foobar', # lowercase the name - 'version': '1.1.0', - }, - 'Foo-Bar-1.1.0.zip': { - 'name': 'foo-bar', # keep the dash - 'version': '1.1.0', - }, - 'foobar-1.1b2.tar.gz#md5=123123123123123': { - 'name': 'foobar', - 'version': '1.1b2', - 'url': 'http://example.org/foobar-1.1b2.tar.gz', # no hash - 'hashval': '123123123123123', - 'hashname': 'md5', - }, - 'foobar-1.1-rc2.tar.gz': { # use suggested name - 'name': 'foobar', - 'version': '1.1c2', - 'url': 'http://example.org/foobar-1.1-rc2.tar.gz', - } - } - - for url, attributes in url_list.items(): - # for each url - infos = get_infos_from_url("http://example.org/" + url) - for attribute, expected in attributes.items(): - got = infos.get(attribute) - if attribute == "version": - self.assertEqual("%s" % got, expected) - else: - self.assertEqual(got, expected) - - def test_split_archive_name(self): - # Test we can split the archive names - names = { - 'foo-bar-baz-1.0-rc2': ('foo-bar-baz', '1.0c2'), - 'foo-bar-baz-1.0': ('foo-bar-baz', '1.0'), - 'foobarbaz-1.0': ('foobarbaz', '1.0'), - } - for name, results in names.items(): - self.assertEqual(results, split_archive_name(name)) - - -class TestDistInfo(TempdirManager, unittest.TestCase): - - def test_get_url(self): - # Test that the url property works well - - d = Dist(url="test_url") - self.assertDictEqual(d.url, { - "url": "test_url", - "is_external": True, - "hashname": None, - "hashval": None, - }) - - # add a new url - d.add_url(url="internal_url", is_external=False) - self.assertEqual(d._url, None) - self.assertDictEqual(d.url, { - "url": "internal_url", - "is_external": False, - "hashname": None, - "hashval": None, - }) - self.assertEqual(2, len(d.urls)) - - def test_comparison(self): - # Test that we can compare DistInfoributionInfoList - foo1 = ReleaseInfo("foo", "1.0") - foo2 = ReleaseInfo("foo", "2.0") - bar = ReleaseInfo("bar", "2.0") - # assert we use the version to compare - self.assertTrue(foo1 < foo2) - self.assertFalse(foo1 > foo2) - self.assertFalse(foo1 == foo2) - - # assert we can't compare dists with different names - self.assertRaises(TypeError, foo1.__eq__, bar) - - @use_pypi_server("downloads_with_md5") - def test_download(self, server): - # Download is possible, and the md5 is checked if given - - url = "%s/simple/foobar/foobar-0.1.tar.gz" % server.full_address - # check md5 if given - dist = Dist(url=url, hashname="md5", - hashval="d41d8cd98f00b204e9800998ecf8427e") - dist.download(self.mkdtemp()) - - # a wrong md5 fails - dist2 = Dist(url=url, hashname="md5", hashval="wrongmd5") - - self.assertRaises(HashDoesNotMatch, dist2.download, self.mkdtemp()) - - # we can omit the md5 hash - dist3 = Dist(url=url) - dist3.download(self.mkdtemp()) - - # and specify a temporary location - # for an already downloaded dist - path1 = self.mkdtemp() - dist3.download(path=path1) - # and for a new one - path2_base = self.mkdtemp() - dist4 = Dist(url=url) - path2 = dist4.download(path=path2_base) - self.assertTrue(path2_base in path2) - - def test_hashname(self): - # Invalid hashnames raises an exception on assignation - Dist(hashname="md5", hashval="value") - - self.assertRaises(UnsupportedHashName, Dist, - hashname="invalid_hashname", - hashval="value") - - -class TestReleasesList(unittest.TestCase): - - def test_filter(self): - # Test we filter the distributions the right way, using version - # predicate match method - releases = ReleasesList('FooBar', ( - ReleaseInfo("FooBar", "1.1"), - ReleaseInfo("FooBar", "1.1.1"), - ReleaseInfo("FooBar", "1.2"), - ReleaseInfo("FooBar", "1.2.1"), - )) - filtered = releases.filter(VersionPredicate("FooBar (<1.2)")) - self.assertNotIn(releases[2], filtered) - self.assertNotIn(releases[3], filtered) - self.assertIn(releases[0], filtered) - self.assertIn(releases[1], filtered) - - def test_append(self): - # When adding a new item to the list, the behavior is to test if - # a release with the same name and version number already exists, - # and if so, to add a new distribution for it. If the distribution type - # is already defined too, add url informations to the existing DistInfo - # object. - - releases = ReleasesList("FooBar", [ - ReleaseInfo("FooBar", "1.1", url="external_url", - dist_type="sdist"), - ]) - self.assertEqual(1, len(releases)) - releases.add_release(release=ReleaseInfo("FooBar", "1.1", - url="internal_url", - is_external=False, - dist_type="sdist")) - self.assertEqual(1, len(releases)) - self.assertEqual(2, len(releases[0]['sdist'].urls)) - - releases.add_release(release=ReleaseInfo("FooBar", "1.1.1", - dist_type="sdist")) - self.assertEqual(2, len(releases)) - - # when adding a distribution whith a different type, a new distribution - # has to be added. - releases.add_release(release=ReleaseInfo("FooBar", "1.1.1", - dist_type="bdist")) - self.assertEqual(2, len(releases)) - self.assertEqual(2, len(releases[1].dists)) - - def test_prefer_final(self): - # Can order the distributions using prefer_final - - fb10 = ReleaseInfo("FooBar", "1.0") # final distribution - fb11a = ReleaseInfo("FooBar", "1.1a1") # alpha - fb12a = ReleaseInfo("FooBar", "1.2a1") # alpha - fb12b = ReleaseInfo("FooBar", "1.2b1") # beta - dists = ReleasesList("FooBar", [fb10, fb11a, fb12a, fb12b]) - - dists.sort_releases(prefer_final=True) - self.assertEqual(fb10, dists[0]) - - dists.sort_releases(prefer_final=False) - self.assertEqual(fb12b, dists[0]) - -# def test_prefer_source(self): -# # Ordering support prefer_source -# fb_source = Dist("FooBar", "1.0", type="source") -# fb_binary = Dist("FooBar", "1.0", type="binary") -# fb2_binary = Dist("FooBar", "2.0", type="binary") -# dists = ReleasesList([fb_binary, fb_source]) -# -# dists.sort_distributions(prefer_source=True) -# self.assertEqual(fb_source, dists[0]) -# -# dists.sort_distributions(prefer_source=False) -# self.assertEqual(fb_binary, dists[0]) -# -# dists.append(fb2_binary) -# dists.sort_distributions(prefer_source=True) -# self.assertEqual(fb2_binary, dists[0]) - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestDistInfo)) - suite.addTest(unittest.makeSuite(TestReleaseInfo)) - suite.addTest(unittest.makeSuite(TestReleasesList)) - return suite - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_index_simple.py b/src/distutils2/tests/test_index_simple.py deleted file mode 100644 index d21bda5..0000000 --- a/src/distutils2/tests/test_index_simple.py +++ /dev/null @@ -1,316 +0,0 @@ -"""Tests for the pypi.simple module. - -""" -import sys -import os -import urllib2 - -from distutils2.index.simple import Crawler -from distutils2.tests import support -from distutils2.tests.support import unittest -from distutils2.tests.pypi_server import (use_pypi_server, PyPIServer, - PYPI_DEFAULT_STATIC_PATH) - - -class SimpleCrawlerTestCase(support.TempdirManager, unittest.TestCase): - - def _get_simple_crawler(self, server, base_url="/simple/", hosts=None, - *args, **kwargs): - """Build and return a SimpleIndex instance, with the test server - urls - """ - if hosts is None: - hosts = (server.full_address.strip("http://"),) - kwargs['hosts'] = hosts - return Crawler(server.full_address + base_url, *args, - **kwargs) - - @use_pypi_server() - def test_bad_urls(self, server): - crawler = Crawler() - url = 'http://127.0.0.1:0/nonesuch/test_simple' - try: - v = crawler._open_url(url) - except Exception, v: - self.assertTrue(url in str(v)) - else: - self.assertTrue(isinstance(v, urllib2.HTTPError)) - - # issue 16 - # easy_install inquant.contentmirror.plone breaks because of a typo - # in its home URL - crawler = Crawler(hosts=('example.org',)) - url = 'url:%20https://svn.plone.org/svn/collective/inquant.contentmirror.plone/trunk' - try: - v = crawler._open_url(url) - except Exception, v: - self.assertTrue(url in str(v)) - else: - self.assertTrue(isinstance(v, urllib2.HTTPError)) - - def _urlopen(*args): - import httplib - raise httplib.BadStatusLine('line') - - old_urlopen = urllib2.urlopen - urllib2.urlopen = _urlopen - url = 'http://example.org' - try: - try: - v = crawler._open_url(url) - except Exception, v: - self.assertTrue('line' in str(v)) - else: - raise AssertionError('Should have raise here!') - finally: - urllib2.urlopen = old_urlopen - - # issue 20 - url = 'http://http://svn.pythonpaste.org/Paste/wphp/trunk' - try: - crawler._open_url(url) - except Exception, v: - self.assertTrue('nonnumeric port' in str(v)) - - # issue #160 - if sys.version_info[0] == 2 and sys.version_info[1] == 7: - # this should not fail - url = server.full_address - page = ('<a href="http://www.famfamfam.com](' - 'http://www.famfamfam.com/">') - crawler._process_url(url, page) - - @use_pypi_server("test_found_links") - def test_found_links(self, server): - # Browse the index, asking for a specified release version - # The PyPI index contains links for version 1.0, 1.1, 2.0 and 2.0.1 - crawler = self._get_simple_crawler(server) - last_release = crawler.get_release("foobar") - - # we have scanned the index page - self.assertIn(server.full_address + "/simple/foobar/", - crawler._processed_urls) - - # we have found 4 releases in this page - self.assertEqual(len(crawler._projects["foobar"]), 4) - - # and returned the most recent one - self.assertEqual("%s" % last_release.version, '2.0.1') - - def test_is_browsable(self): - crawler = Crawler(follow_externals=False) - self.assertTrue(crawler._is_browsable(crawler.index_url + "test")) - - # Now, when following externals, we can have a list of hosts to trust. - # and don't follow other external links than the one described here. - crawler = Crawler(hosts=["pypi.python.org", "example.org"], - follow_externals=True) - good_urls = ( - "http://pypi.python.org/foo/bar", - "http://pypi.python.org/simple/foobar", - "http://example.org", - "http://example.org/", - "http://example.org/simple/", - ) - bad_urls = ( - "http://python.org", - "http://example.tld", - ) - - for url in good_urls: - self.assertTrue(crawler._is_browsable(url)) - - for url in bad_urls: - self.assertFalse(crawler._is_browsable(url)) - - # allow all hosts - crawler = Crawler(follow_externals=True, hosts=("*",)) - self.assertTrue(crawler._is_browsable("http://an-external.link/path")) - self.assertTrue(crawler._is_browsable("pypi.example.org/a/path")) - - # specify a list of hosts we want to allow - crawler = Crawler(follow_externals=True, - hosts=("*.example.org",)) - self.assertFalse(crawler._is_browsable("http://an-external.link/path")) - self.assertTrue(crawler._is_browsable("http://pypi.example.org/a/path")) - - @use_pypi_server("with_externals") - def test_follow_externals(self, server): - # Include external pages - # Try to request the package index, wich contains links to "externals" - # resources. They have to be scanned too. - crawler = self._get_simple_crawler(server, follow_externals=True) - crawler.get_release("foobar") - self.assertIn(server.full_address + "/external/external.html", - crawler._processed_urls) - - @use_pypi_server("with_real_externals") - def test_restrict_hosts(self, server): - # Only use a list of allowed hosts is possible - # Test that telling the simple pyPI client to not retrieve external - # works - crawler = self._get_simple_crawler(server, follow_externals=False) - crawler.get_release("foobar") - self.assertNotIn(server.full_address + "/external/external.html", - crawler._processed_urls) - - @use_pypi_server(static_filesystem_paths=["with_externals"], - static_uri_paths=["simple", "external"]) - def test_links_priority(self, server): - # Download links from the pypi simple index should be used before - # external download links. - # http://bitbucket.org/tarek/distribute/issue/163/md5-validation-error - # - # Usecase : - # - someone uploads a package on pypi, a md5 is generated - # - someone manually coindexes this link (with the md5 in the url) onto - # an external page accessible from the package page. - # - someone reuploads the package (with a different md5) - # - while easy_installing, an MD5 error occurs because the external - # link is used - # -> The index should use the link from pypi, not the external one. - - # start an index server - index_url = server.full_address + '/simple/' - - # scan a test index - crawler = Crawler(index_url, follow_externals=True) - releases = crawler.get_releases("foobar") - server.stop() - - # we have only one link, because links are compared without md5 - self.assertEqual(1, len(releases)) - self.assertEqual(1, len(releases[0].dists)) - # the link should be from the index - self.assertEqual(2, len(releases[0].dists['sdist'].urls)) - self.assertEqual('12345678901234567', - releases[0].dists['sdist'].url['hashval']) - self.assertEqual('md5', releases[0].dists['sdist'].url['hashname']) - - @use_pypi_server(static_filesystem_paths=["with_norel_links"], - static_uri_paths=["simple", "external"]) - def test_not_scan_all_links(self, server): - # Do not follow all index page links. - # The links not tagged with rel="download" and rel="homepage" have - # to not be processed by the package index, while processing "pages". - - # process the pages - crawler = self._get_simple_crawler(server, follow_externals=True) - crawler.get_releases("foobar") - # now it should have processed only pages with links rel="download" - # and rel="homepage" - self.assertIn("%s/simple/foobar/" % server.full_address, - crawler._processed_urls) # it's the simple index page - self.assertIn("%s/external/homepage.html" % server.full_address, - crawler._processed_urls) # the external homepage is rel="homepage" - self.assertNotIn("%s/external/nonrel.html" % server.full_address, - crawler._processed_urls) # this link contains no rel=* - self.assertNotIn("%s/unrelated-0.2.tar.gz" % server.full_address, - crawler._processed_urls) # linked from simple index (no rel) - self.assertIn("%s/foobar-0.1.tar.gz" % server.full_address, - crawler._processed_urls) # linked from simple index (rel) - self.assertIn("%s/foobar-2.0.tar.gz" % server.full_address, - crawler._processed_urls) # linked from external homepage (rel) - - def test_uses_mirrors(self): - # When the main repository seems down, try using the given mirrors""" - server = PyPIServer("foo_bar_baz") - mirror = PyPIServer("foo_bar_baz") - mirror.start() # we dont start the server here - - try: - # create the index using both servers - crawler = Crawler(server.full_address + "/simple/", - hosts=('*',), timeout=1, # set the timeout to 1s for the tests - mirrors=[mirror.full_address]) - - # this should not raise a timeout - self.assertEqual(4, len(crawler.get_releases("foo"))) - finally: - mirror.stop() - - def test_simple_link_matcher(self): - # Test that the simple link matcher yields the right links""" - crawler = Crawler(follow_externals=False) - - # Here, we define: - # 1. one link that must be followed, cause it's a download one - # 2. one link that must *not* be followed, cause the is_browsable - # returns false for it. - # 3. one link that must be followed cause it's a homepage that is - # browsable - # 4. one link that must be followed, because it contain a md5 hash - self.assertTrue(crawler._is_browsable("%stest" % crawler.index_url)) - self.assertFalse(crawler._is_browsable("http://dl-link2")) - content = """ - <a href="http://dl-link1" rel="download">download_link1</a> - <a href="http://dl-link2" rel="homepage">homepage_link1</a> - <a href="%(index_url)stest" rel="homepage">homepage_link2</a> - <a href="%(index_url)stest/foobar-1.tar.gz#md5=abcdef>download_link2</a> - """ % {'index_url': crawler.index_url } - - # Test that the simple link matcher yield the good links. - generator = crawler._simple_link_matcher(content, crawler.index_url) - self.assertEqual(('%stest/foobar-1.tar.gz#md5=abcdef' % crawler.index_url, - True), generator.next()) - self.assertEqual(('http://dl-link1', True), generator.next()) - self.assertEqual(('%stest' % crawler.index_url, False), - generator.next()) - self.assertRaises(StopIteration, generator.next) - - # Follow the external links is possible (eg. homepages) - crawler.follow_externals = True - generator = crawler._simple_link_matcher(content, crawler.index_url) - self.assertEqual(('%stest/foobar-1.tar.gz#md5=abcdef' % crawler.index_url, - True), generator.next()) - self.assertEqual(('http://dl-link1', True), generator.next()) - self.assertEqual(('http://dl-link2', False), generator.next()) - self.assertEqual(('%stest' % crawler.index_url, False), - generator.next()) - self.assertRaises(StopIteration, generator.next) - - def test_browse_local_files(self): - # Test that we can browse local files""" - index_path = os.sep.join(["file://" + PYPI_DEFAULT_STATIC_PATH, - "test_found_links", "simple"]) - crawler = Crawler(index_path) - dists = crawler.get_releases("foobar") - self.assertEqual(4, len(dists)) - - def test_get_link_matcher(self): - crawler = Crawler("http://example.org") - self.assertEqual('_simple_link_matcher', crawler._get_link_matcher( - "http://example.org/some/file").__name__) - self.assertEqual('_default_link_matcher', crawler._get_link_matcher( - "http://other-url").__name__) - - def test_default_link_matcher(self): - crawler = Crawler("http://example.org", mirrors=[]) - crawler.follow_externals = True - crawler._is_browsable = lambda *args:True - base_url = "http://example.org/some/file/" - content = """ -<a href="../homepage" rel="homepage">link</a> -<a href="../download" rel="download">link2</a> -<a href="../simpleurl">link2</a> - """ - found_links = dict(crawler._default_link_matcher(content, - base_url)).keys() - self.assertIn('http://example.org/some/homepage', found_links) - self.assertIn('http://example.org/some/simpleurl', found_links) - self.assertIn('http://example.org/some/download', found_links) - - @use_pypi_server("project_list") - def test_search_projects(self, server): - # we can search the index for some projects, on their names - # the case used no matters here - crawler = self._get_simple_crawler(server) - projects = [p.name for p in crawler.search_projects("Foobar")] - self.assertListEqual(['FooBar-bar', 'Foobar-baz', 'Baz-FooBar'], - projects) - -def test_suite(): - return unittest.makeSuite(SimpleCrawlerTestCase) - -if __name__ == '__main__': - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_index_xmlrpc.py b/src/distutils2/tests/test_index_xmlrpc.py deleted file mode 100644 index 50ea739..0000000 --- a/src/distutils2/tests/test_index_xmlrpc.py +++ /dev/null @@ -1,92 +0,0 @@ -"""Tests for the distutils2.index.xmlrpc module.""" - -from distutils2.tests.pypi_server import use_xmlrpc_server -from distutils2.tests import run_unittest -from distutils2.tests.support import unittest -from distutils2.index.xmlrpc import Client, InvalidSearchField, ProjectNotFound - - -class TestXMLRPCClient(unittest.TestCase): - def _get_client(self, server, *args, **kwargs): - return Client(server.full_address, *args, **kwargs) - - @use_xmlrpc_server() - def test_search_projects(self, server): - client = self._get_client(server) - server.xmlrpc.set_search_result(['FooBar', 'Foo', 'FooFoo']) - results = [r.name for r in client.search_projects(name='Foo')] - self.assertEqual(3, len(results)) - self.assertIn('FooBar', results) - self.assertIn('Foo', results) - self.assertIn('FooFoo', results) - - def test_search_projects_bad_fields(self): - client = Client() - self.assertRaises(InvalidSearchField, client.search_projects, - invalid="test") - - @use_xmlrpc_server() - def test_get_releases(self, server): - client = self._get_client(server) - server.xmlrpc.set_distributions([ - {'name': 'FooBar', 'version': '1.1'}, - {'name': 'FooBar', 'version': '1.2', 'url': 'http://some/url/'}, - {'name': 'FooBar', 'version': '1.3', 'url': 'http://other/url/'}, - ]) - - # use a lambda here to avoid an useless mock call - server.xmlrpc.list_releases = lambda *a, **k: ['1.1', '1.2', '1.3'] - - releases = client.get_releases('FooBar (<=1.2)') - # dont call release_data and release_url; just return name and version. - self.assertEqual(2, len(releases)) - versions = releases.get_versions() - self.assertIn('1.1', versions) - self.assertIn('1.2', versions) - self.assertNotIn('1.3', versions) - - self.assertRaises(ProjectNotFound, client.get_releases,'Foo') - - @use_xmlrpc_server() - def test_get_distributions(self, server): - client = self._get_client(server) - server.xmlrpc.set_distributions([ - {'name':'FooBar', 'version': '1.1', 'url': - 'http://example.org/foobar-1.1-sdist.tar.gz', - 'digest': '1234567', 'type': 'sdist', 'python_version':'source'}, - {'name':'FooBar', 'version': '1.1', 'url': - 'http://example.org/foobar-1.1-bdist.tar.gz', - 'digest': '8912345', 'type': 'bdist'}, - ]) - - releases = client.get_releases('FooBar', '1.1') - client.get_distributions('FooBar', '1.1') - release = releases.get_release('1.1') - self.assertTrue('http://example.org/foobar-1.1-sdist.tar.gz', - release['sdist'].url['url']) - self.assertTrue('http://example.org/foobar-1.1-bdist.tar.gz', - release['bdist'].url['url']) - self.assertEqual(release['sdist'].python_version, 'source') - - @use_xmlrpc_server() - def test_get_metadata(self, server): - client = self._get_client(server) - server.xmlrpc.set_distributions([ - {'name':'FooBar', - 'version': '1.1', - 'keywords': '', - 'obsoletes_dist': ['FooFoo'], - 'requires_external': ['Foo'], - }]) - release = client.get_metadata('FooBar', '1.1') - self.assertEqual(['Foo'], release.metadata['requires_external']) - self.assertEqual(['FooFoo'], release.metadata['obsoletes_dist']) - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestXMLRPCClient)) - return suite - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_install.py b/src/distutils2/tests/test_install.py deleted file mode 100644 index 783d3fc..0000000 --- a/src/distutils2/tests/test_install.py +++ /dev/null @@ -1,220 +0,0 @@ -"""Tests for distutils.command.install.""" - -import os -import sys - -from distutils2._backport.sysconfig import (get_scheme_names, - get_config_vars, - _SCHEMES, - get_config_var, get_path) - -_CONFIG_VARS = get_config_vars() - -from distutils2.tests import captured_stdout - -from distutils2.command.install import install -from distutils2.command import install as install_module -from distutils2.core import Distribution -from distutils2.errors import DistutilsOptionError - -from distutils2.tests import support -from distutils2.tests.support import unittest - -class InstallTestCase(support.TempdirManager, - support.EnvironGuard, - support.LoggingCatcher, - unittest.TestCase): - - def test_home_installation_scheme(self): - # This ensure two things: - # - that --home generates the desired set of directory names - # - test --home is supported on all platforms - builddir = self.mkdtemp() - destination = os.path.join(builddir, "installation") - - dist = Distribution({"name": "foopkg"}) - # script_name need not exist, it just need to be initialized - dist.script_name = os.path.join(builddir, "setup.py") - dist.command_obj["build"] = support.DummyCommand( - build_base=builddir, - build_lib=os.path.join(builddir, "lib"), - ) - - old_posix_prefix = _SCHEMES.get('posix_prefix', 'platinclude') - old_posix_home = _SCHEMES.get('posix_home', 'platinclude') - - new_path = '{platbase}/include/python{py_version_short}' - _SCHEMES.set('posix_prefix', 'platinclude', new_path) - _SCHEMES.set('posix_home', 'platinclude', '{platbase}/include/python') - - try: - cmd = install(dist) - cmd.home = destination - cmd.ensure_finalized() - finally: - _SCHEMES.set('posix_prefix', 'platinclude', old_posix_prefix) - _SCHEMES.set('posix_home', 'platinclude', old_posix_home) - - self.assertEqual(cmd.install_base, destination) - self.assertEqual(cmd.install_platbase, destination) - - def check_path(got, expected): - got = os.path.normpath(got) - expected = os.path.normpath(expected) - self.assertEqual(got, expected) - - libdir = os.path.join(destination, "lib", "python") - check_path(cmd.install_lib, libdir) - check_path(cmd.install_platlib, libdir) - check_path(cmd.install_purelib, libdir) - check_path(cmd.install_headers, - os.path.join(destination, "include", "python", "foopkg")) - check_path(cmd.install_scripts, os.path.join(destination, "bin")) - check_path(cmd.install_data, destination) - - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_user_site(self): - # test install with --user - # preparing the environment for the test - self.old_user_base = get_config_var('userbase') - self.old_user_site = get_path('purelib', '%s_user' % os.name) - self.tmpdir = self.mkdtemp() - self.user_base = os.path.join(self.tmpdir, 'B') - self.user_site = os.path.join(self.tmpdir, 'S') - _CONFIG_VARS['userbase'] = self.user_base - scheme = '%s_user' % os.name - _SCHEMES.set(scheme, 'purelib', self.user_site) - def _expanduser(path): - if path[0] == '~': - path = os.path.normpath(self.tmpdir) + path[1:] - return path - self.old_expand = os.path.expanduser - os.path.expanduser = _expanduser - - try: - # this is the actual test - self._test_user_site() - finally: - _CONFIG_VARS['userbase'] = self.old_user_base - _SCHEMES.set(scheme, 'purelib', self.old_user_site) - os.path.expanduser = self.old_expand - - def _test_user_site(self): - schemes = get_scheme_names() - for key in ('nt_user', 'posix_user', 'os2_home'): - self.assertTrue(key in schemes) - - dist = Distribution({'name': 'xx'}) - cmd = install(dist) - # making sure the user option is there - options = [name for name, short, lable in - cmd.user_options] - self.assertTrue('user' in options) - - # setting a value - cmd.user = 1 - - # user base and site shouldn't be created yet - self.assertTrue(not os.path.exists(self.user_base)) - self.assertTrue(not os.path.exists(self.user_site)) - - # let's run finalize - cmd.ensure_finalized() - - # now they should - self.assertTrue(os.path.exists(self.user_base)) - self.assertTrue(os.path.exists(self.user_site)) - - self.assertTrue('userbase' in cmd.config_vars) - self.assertTrue('usersite' in cmd.config_vars) - - def test_handle_extra_path(self): - dist = Distribution({'name': 'xx', 'extra_path': 'path,dirs'}) - cmd = install(dist) - - # two elements - cmd.handle_extra_path() - self.assertEqual(cmd.extra_path, ['path', 'dirs']) - self.assertEqual(cmd.extra_dirs, 'dirs') - self.assertEqual(cmd.path_file, 'path') - - # one element - cmd.extra_path = ['path'] - cmd.handle_extra_path() - self.assertEqual(cmd.extra_path, ['path']) - self.assertEqual(cmd.extra_dirs, 'path') - self.assertEqual(cmd.path_file, 'path') - - # none - dist.extra_path = cmd.extra_path = None - cmd.handle_extra_path() - self.assertEqual(cmd.extra_path, None) - self.assertEqual(cmd.extra_dirs, '') - self.assertEqual(cmd.path_file, None) - - # three elements (no way !) - cmd.extra_path = 'path,dirs,again' - self.assertRaises(DistutilsOptionError, cmd.handle_extra_path) - - def test_finalize_options(self): - dist = Distribution({'name': 'xx'}) - cmd = install(dist) - - # must supply either prefix/exec-prefix/home or - # install-base/install-platbase -- not both - cmd.prefix = 'prefix' - cmd.install_base = 'base' - self.assertRaises(DistutilsOptionError, cmd.finalize_options) - - # must supply either home or prefix/exec-prefix -- not both - cmd.install_base = None - cmd.home = 'home' - self.assertRaises(DistutilsOptionError, cmd.finalize_options) - - if sys.version >= '2.6': - # can't combine user with with prefix/exec_prefix/home or - # install_(plat)base - cmd.prefix = None - cmd.user = 'user' - self.assertRaises(DistutilsOptionError, cmd.finalize_options) - - def test_record(self): - - install_dir = self.mkdtemp() - pkgdir, dist = self.create_dist() - - dist = Distribution() - cmd = install(dist) - dist.command_obj['install'] = cmd - cmd.root = install_dir - cmd.record = os.path.join(pkgdir, 'RECORD') - cmd.ensure_finalized() - cmd.run() - - # let's check the RECORD file was created with four - # lines, one for each .dist-info entry: METADATA, - # INSTALLER, REQUSTED, RECORD - f = open(cmd.record) - try: - self.assertEqual(len(f.readlines()), 4) - finally: - f.close() - - # XXX test that fancy_getopt is okay with options named - # record and no-record but unrelated - - def _test_debug_mode(self): - # this covers the code called when DEBUG is set - old_logs_len = len(self.logs) - install_module.DEBUG = True - try: - __, stdout = captured_stdout(self.test_record) - finally: - install_module.DEBUG = False - self.assertTrue(len(self.logs) > old_logs_len) - -def test_suite(): - return unittest.makeSuite(InstallTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_install_data.py b/src/distutils2/tests/test_install_data.py deleted file mode 100644 index 9cae44a..0000000 --- a/src/distutils2/tests/test_install_data.py +++ /dev/null @@ -1,76 +0,0 @@ -"""Tests for distutils.command.install_data.""" -import sys -import os -import getpass - -from distutils2.command.install_data import install_data -from distutils2.tests import support -from distutils2.tests.support import unittest - -class InstallDataTestCase(support.TempdirManager, - support.LoggingCatcher, - support.EnvironGuard, - unittest.TestCase): - - def test_simple_run(self): - pkg_dir, dist = self.create_dist() - cmd = install_data(dist) - cmd.install_dir = inst = os.path.join(pkg_dir, 'inst') - - # data_files can contain - # - simple files - # - a tuple with a path, and a list of file - one = os.path.join(pkg_dir, 'one') - self.write_file(one, 'xxx') - inst2 = os.path.join(pkg_dir, 'inst2') - two = os.path.join(pkg_dir, 'two') - self.write_file(two, 'xxx') - - cmd.data_files = [one, (inst2, [two])] - self.assertEqual(cmd.get_inputs(), [one, (inst2, [two])]) - - # let's run the command - cmd.ensure_finalized() - cmd.run() - - # let's check the result - self.assertEqual(len(cmd.get_outputs()), 2) - rtwo = os.path.split(two)[-1] - self.assertTrue(os.path.exists(os.path.join(inst2, rtwo))) - rone = os.path.split(one)[-1] - self.assertTrue(os.path.exists(os.path.join(inst, rone))) - cmd.outfiles = [] - - # let's try with warn_dir one - cmd.warn_dir = 1 - cmd.ensure_finalized() - cmd.run() - - # let's check the result - self.assertEqual(len(cmd.get_outputs()), 2) - self.assertTrue(os.path.exists(os.path.join(inst2, rtwo))) - self.assertTrue(os.path.exists(os.path.join(inst, rone))) - cmd.outfiles = [] - - # now using root and empty dir - cmd.root = os.path.join(pkg_dir, 'root') - inst3 = os.path.join(cmd.install_dir, 'inst3') - inst4 = os.path.join(pkg_dir, 'inst4') - three = os.path.join(cmd.install_dir, 'three') - self.write_file(three, 'xx') - cmd.data_files = [one, (inst2, [two]), - ('inst3', [three]), - (inst4, [])] - cmd.ensure_finalized() - cmd.run() - - # let's check the result - self.assertEqual(len(cmd.get_outputs()), 4) - self.assertTrue(os.path.exists(os.path.join(inst2, rtwo))) - self.assertTrue(os.path.exists(os.path.join(inst, rone))) - -def test_suite(): - return unittest.makeSuite(InstallDataTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_install_distinfo.py b/src/distutils2/tests/test_install_distinfo.py deleted file mode 100644 index 1bad24b..0000000 --- a/src/distutils2/tests/test_install_distinfo.py +++ /dev/null @@ -1,202 +0,0 @@ -"""Tests for ``distutils2.command.install_distinfo``. """ - -import os -import sys -import csv - -from distutils2.command.install_distinfo import install_distinfo -from distutils2.core import Command -from distutils2.metadata import DistributionMetadata -from distutils2.tests import support -from distutils2.tests.support import unittest - -try: - import hashlib -except ImportError: - from distutils2._backport import hashlib - - -class DummyInstallCmd(Command): - - def __init__(self, dist=None): - self.outputs = [] - self.distribution = dist - - def __getattr__(self, name): - return None - - def ensure_finalized(self): - pass - - def get_outputs(self): - return self.outputs + \ - self.get_finalized_command('install_distinfo').get_outputs() - - -class InstallDistinfoTestCase(support.TempdirManager, - support.LoggingCatcher, - support.EnvironGuard, - unittest.TestCase): - - checkLists = lambda self, x, y: self.assertListEqual(sorted(x), sorted(y)) - - def test_empty_install(self): - pkg_dir, dist = self.create_dist(name='foo', - version='1.0') - install_dir = self.mkdtemp() - - install = DummyInstallCmd(dist) - dist.command_obj['install'] = install - - cmd = install_distinfo(dist) - dist.command_obj['install_distinfo'] = cmd - - cmd.initialize_options() - cmd.distinfo_dir = install_dir - cmd.ensure_finalized() - cmd.run() - - self.checkLists(os.listdir(install_dir), ['foo-1.0.dist-info']) - - dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') - self.checkLists(os.listdir(dist_info), - ['METADATA', 'RECORD', 'REQUESTED', 'INSTALLER']) - self.assertEqual(open(os.path.join(dist_info, 'INSTALLER')).read(), - 'distutils') - self.assertEqual(open(os.path.join(dist_info, 'REQUESTED')).read(), - '') - meta_path = os.path.join(dist_info, 'METADATA') - self.assertTrue(DistributionMetadata(path=meta_path).check()) - - def test_installer(self): - pkg_dir, dist = self.create_dist(name='foo', - version='1.0') - install_dir = self.mkdtemp() - - install = DummyInstallCmd(dist) - dist.command_obj['install'] = install - - cmd = install_distinfo(dist) - dist.command_obj['install_distinfo'] = cmd - - cmd.initialize_options() - cmd.distinfo_dir = install_dir - cmd.installer = 'bacon-python' - cmd.ensure_finalized() - cmd.run() - - dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') - self.assertEqual(open(os.path.join(dist_info, 'INSTALLER')).read(), - 'bacon-python') - - def test_requested(self): - pkg_dir, dist = self.create_dist(name='foo', - version='1.0') - install_dir = self.mkdtemp() - - install = DummyInstallCmd(dist) - dist.command_obj['install'] = install - - cmd = install_distinfo(dist) - dist.command_obj['install_distinfo'] = cmd - - cmd.initialize_options() - cmd.distinfo_dir = install_dir - cmd.requested = False - cmd.ensure_finalized() - cmd.run() - - dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') - self.checkLists(os.listdir(dist_info), - ['METADATA', 'RECORD', 'INSTALLER']) - - def test_no_record(self): - pkg_dir, dist = self.create_dist(name='foo', - version='1.0') - install_dir = self.mkdtemp() - - install = DummyInstallCmd(dist) - dist.command_obj['install'] = install - - cmd = install_distinfo(dist) - dist.command_obj['install_distinfo'] = cmd - - cmd.initialize_options() - cmd.distinfo_dir = install_dir - cmd.no_record = True - cmd.ensure_finalized() - cmd.run() - - dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') - self.checkLists(os.listdir(dist_info), - ['METADATA', 'REQUESTED', 'INSTALLER']) - - def test_record(self): - pkg_dir, dist = self.create_dist(name='foo', - version='1.0') - install_dir = self.mkdtemp() - - install = DummyInstallCmd(dist) - dist.command_obj['install'] = install - - fake_dists = os.path.join(os.path.dirname(__file__), '..', - '_backport', 'tests', 'fake_dists') - fake_dists = os.path.realpath(fake_dists) - - # for testing, we simply add all files from _backport's fake_dists - dirs = [] - for dir in os.listdir(fake_dists): - full_path = os.path.join(fake_dists, dir) - if (not dir.endswith('.egg') or dir.endswith('.egg-info') or - dir.endswith('.dist-info')) and os.path.isdir(full_path): - dirs.append(full_path) - - for dir in dirs: - for (path, subdirs, files) in os.walk(dir): - install.outputs += [os.path.join(path, f) for f in files] - install.outputs += [os.path.join('path', f + 'c') - for f in files if f.endswith('.py')] - - - cmd = install_distinfo(dist) - dist.command_obj['install_distinfo'] = cmd - - cmd.initialize_options() - cmd.distinfo_dir = install_dir - cmd.ensure_finalized() - cmd.run() - - dist_info = os.path.join(install_dir, 'foo-1.0.dist-info') - - expected = [] - for f in install.get_outputs(): - if f.endswith('.pyc') or \ - f == os.path.join(install_dir, 'foo-1.0.dist-info', 'RECORD'): - expected.append([f, '', '']) - else: - size = os.path.getsize(f) - md5 = hashlib.md5() - md5.update(open(f).read()) - hash = md5.hexdigest() - expected.append([f, hash, str(size)]) - - parsed = [] - f = open(os.path.join(dist_info, 'RECORD'), 'rb') - try: - reader = csv.reader(f, delimiter=',', - lineterminator=os.linesep, - quotechar='"') - parsed = list(reader) - finally: - f.close() - - self.maxDiff = None - self.checkLists(parsed, expected) - - -def test_suite(): - return unittest.makeSuite(InstallDistinfoTestCase) - - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_install_headers.py b/src/distutils2/tests/test_install_headers.py deleted file mode 100644 index 5e40257..0000000 --- a/src/distutils2/tests/test_install_headers.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Tests for distutils.command.install_headers.""" -import sys -import os -import getpass - -from distutils2.command.install_headers import install_headers -from distutils2.tests import support -from distutils2.tests.support import unittest - -class InstallHeadersTestCase(support.TempdirManager, - support.LoggingCatcher, - support.EnvironGuard, - unittest.TestCase): - - def test_simple_run(self): - # we have two headers - header_list = self.mkdtemp() - header1 = os.path.join(header_list, 'header1') - header2 = os.path.join(header_list, 'header2') - self.write_file(header1) - self.write_file(header2) - headers = [header1, header2] - - pkg_dir, dist = self.create_dist(headers=headers) - cmd = install_headers(dist) - self.assertEqual(cmd.get_inputs(), headers) - - # let's run the command - cmd.install_dir = os.path.join(pkg_dir, 'inst') - cmd.ensure_finalized() - cmd.run() - - # let's check the results - self.assertEqual(len(cmd.get_outputs()), 2) - -def test_suite(): - return unittest.makeSuite(InstallHeadersTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_install_lib.py b/src/distutils2/tests/test_install_lib.py deleted file mode 100644 index 75eb69e..0000000 --- a/src/distutils2/tests/test_install_lib.py +++ /dev/null @@ -1,107 +0,0 @@ -"""Tests for distutils.command.install_data.""" -import sys -import os - -from distutils2.command.install_lib import install_lib -from distutils2.extension import Extension -from distutils2.tests import support -from distutils2.errors import DistutilsOptionError -from distutils2.tests.support import unittest - -try: - no_bytecode = sys.dont_write_bytecode - bytecode_support = True -except AttributeError: - no_bytecode = False - bytecode_support = False - -class InstallLibTestCase(support.TempdirManager, - support.LoggingCatcher, - support.EnvironGuard, - unittest.TestCase): - - def test_finalize_options(self): - pkg_dir, dist = self.create_dist() - cmd = install_lib(dist) - - cmd.finalize_options() - self.assertEqual(cmd.compile, 1) - self.assertEqual(cmd.optimize, 0) - - # optimize must be 0, 1, or 2 - cmd.optimize = 'foo' - self.assertRaises(DistutilsOptionError, cmd.finalize_options) - cmd.optimize = '4' - self.assertRaises(DistutilsOptionError, cmd.finalize_options) - - cmd.optimize = '2' - cmd.finalize_options() - self.assertEqual(cmd.optimize, 2) - - @unittest.skipIf(no_bytecode, 'byte-compile not supported') - def test_byte_compile(self): - pkg_dir, dist = self.create_dist() - cmd = install_lib(dist) - cmd.compile = cmd.optimize = 1 - - f = os.path.join(pkg_dir, 'foo.py') - self.write_file(f, '# python file') - cmd.byte_compile([f]) - self.assertTrue(os.path.exists(os.path.join(pkg_dir, 'foo.pyc'))) - self.assertTrue(os.path.exists(os.path.join(pkg_dir, 'foo.pyo'))) - - def test_get_outputs(self): - pkg_dir, dist = self.create_dist() - cmd = install_lib(dist) - - # setting up a dist environment - cmd.compile = cmd.optimize = 1 - cmd.install_dir = pkg_dir - f = os.path.join(pkg_dir, '__init__.py') - self.write_file(f, '# python package') - cmd.distribution.ext_modules = [Extension('foo', ['xxx'])] - cmd.distribution.packages = [pkg_dir] - cmd.distribution.script_name = 'setup.py' - - # get_output should return 4 elements - self.assertTrue(len(cmd.get_outputs()) >= 2) - - def test_get_inputs(self): - pkg_dir, dist = self.create_dist() - cmd = install_lib(dist) - - # setting up a dist environment - cmd.compile = cmd.optimize = 1 - cmd.install_dir = pkg_dir - f = os.path.join(pkg_dir, '__init__.py') - self.write_file(f, '# python package') - cmd.distribution.ext_modules = [Extension('foo', ['xxx'])] - cmd.distribution.packages = [pkg_dir] - cmd.distribution.script_name = 'setup.py' - - # get_input should return 2 elements - self.assertEqual(len(cmd.get_inputs()), 2) - - @unittest.skipUnless(bytecode_support, - 'sys.dont_write_bytecode not supported') - def test_dont_write_bytecode(self): - # makes sure byte_compile is not used - pkg_dir, dist = self.create_dist() - cmd = install_lib(dist) - cmd.compile = 1 - cmd.optimize = 1 - - old_dont_write_bytecode = sys.dont_write_bytecode - sys.dont_write_bytecode = True - try: - cmd.byte_compile([]) - finally: - sys.dont_write_bytecode = old_dont_write_bytecode - - self.assertTrue('byte-compiling is disabled' in self.logs[0][1]) - -def test_suite(): - return unittest.makeSuite(InstallLibTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_install_scripts.py b/src/distutils2/tests/test_install_scripts.py deleted file mode 100644 index 2cfab03..0000000 --- a/src/distutils2/tests/test_install_scripts.py +++ /dev/null @@ -1,81 +0,0 @@ -"""Tests for distutils.command.install_scripts.""" - -import os - -from distutils2.command.install_scripts import install_scripts -from distutils2.core import Distribution - -from distutils2.tests import support -from distutils2.tests.support import unittest - - -class InstallScriptsTestCase(support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - def test_default_settings(self): - dist = Distribution() - dist.command_obj["build"] = support.DummyCommand( - build_scripts="/foo/bar") - dist.command_obj["install"] = support.DummyCommand( - install_scripts="/splat/funk", - force=1, - skip_build=1, - ) - cmd = install_scripts(dist) - self.assertTrue(not cmd.force) - self.assertTrue(not cmd.skip_build) - self.assertTrue(cmd.build_dir is None) - self.assertTrue(cmd.install_dir is None) - - cmd.finalize_options() - - self.assertTrue(cmd.force) - self.assertTrue(cmd.skip_build) - self.assertEqual(cmd.build_dir, "/foo/bar") - self.assertEqual(cmd.install_dir, "/splat/funk") - - def test_installation(self): - source = self.mkdtemp() - expected = [] - - def write_script(name, text): - expected.append(name) - f = open(os.path.join(source, name), "w") - try: - f.write(text) - finally: - f.close() - - write_script("script1.py", ("#! /usr/bin/env python2.3\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) - write_script("script2.py", ("#!/usr/bin/python\n" - "# bogus script w/ Python sh-bang\n" - "pass\n")) - write_script("shell.sh", ("#!/bin/sh\n" - "# bogus shell script w/ sh-bang\n" - "exit 0\n")) - - target = self.mkdtemp() - dist = Distribution() - dist.command_obj["build"] = support.DummyCommand(build_scripts=source) - dist.command_obj["install"] = support.DummyCommand( - install_scripts=target, - force=1, - skip_build=1, - ) - cmd = install_scripts(dist) - cmd.finalize_options() - cmd.run() - - installed = os.listdir(target) - for name in expected: - self.assertTrue(name in installed) - - -def test_suite(): - return unittest.makeSuite(InstallScriptsTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_install_tools.py b/src/distutils2/tests/test_install_tools.py deleted file mode 100644 index 2db4add..0000000 --- a/src/distutils2/tests/test_install_tools.py +++ /dev/null @@ -1,160 +0,0 @@ -"""Tests for the distutils2.index.xmlrpc module.""" - -from distutils2.tests.pypi_server import use_xmlrpc_server -from distutils2.tests import run_unittest -from distutils2.tests.support import unittest -from distutils2.index.xmlrpc import Client -from distutils2.install_tools import (get_infos, - InstallationException) -from distutils2.metadata import DistributionMetadata - - -class FakeDist(object): - """A fake distribution object, for tests""" - def __init__(self, name, version, deps): - self.name = name - self.version = version - self.metadata = DistributionMetadata() - self.metadata['Requires-Dist'] = deps - self.metadata['Provides-Dist'] = ['%s (%s)' % (name, version)] - - def __repr__(self): - return '<FakeDist %s>' % self.name - - -def get_fake_dists(dists): - objects = [] - for (name, version, deps) in dists: - objects.append(FakeDist(name, version, deps)) - return objects - - -class TestInstallWithDeps(unittest.TestCase): - def _get_client(self, server, *args, **kwargs): - return Client(server.full_address, *args, **kwargs) - - def _get_results(self, output): - """return a list of results""" - installed = [(o.name, '%s' % o.version) for o in output['install']] - remove = [(o.name, '%s' % o.version) for o in output['remove']] - conflict = [(o.name, '%s' % o.version) for o in output['conflict']] - return (installed, remove, conflict) - - @use_xmlrpc_server() - def test_existing_deps(self, server): - # Test that the installer get the dependencies from the metadatas - # and ask the index for this dependencies. - # In this test case, we have choxie that is dependent from towel-stuff - # 0.1, which is in-turn dependent on bacon <= 0.2: - # choxie -> towel-stuff -> bacon. - # Each release metadata is not provided in metadata 1.2. - client = self._get_client(server) - archive_path = '%s/distribution.tar.gz' % server.full_address - server.xmlrpc.set_distributions([ - {'name':'choxie', - 'version': '2.0.0.9', - 'requires_dist': ['towel-stuff (0.1)',], - 'url': archive_path}, - {'name':'towel-stuff', - 'version': '0.1', - 'requires_dist': ['bacon (<= 0.2)',], - 'url': archive_path}, - {'name':'bacon', - 'version': '0.1', - 'requires_dist': [], - 'url': archive_path}, - ]) - installed = get_fake_dists([('bacon', '0.1', []),]) - output = get_infos("choxie", index=client, - installed=installed) - - # we dont have installed bacon as it's already installed on the system. - self.assertEqual(0, len(output['remove'])) - self.assertEqual(2, len(output['install'])) - readable_output = [(o.name, '%s' % o.version) - for o in output['install']] - self.assertIn(('towel-stuff', '0.1'), readable_output) - self.assertIn(('choxie', '2.0.0.9'), readable_output) - - @use_xmlrpc_server() - def test_upgrade_existing_deps(self, server): - # Tests that the existing distributions can be upgraded if needed. - client = self._get_client(server) - archive_path = '%s/distribution.tar.gz' % server.full_address - server.xmlrpc.set_distributions([ - {'name':'choxie', - 'version': '2.0.0.9', - 'requires_dist': ['towel-stuff (0.1)',], - 'url': archive_path}, - {'name':'towel-stuff', - 'version': '0.1', - 'requires_dist': ['bacon (>= 0.2)',], - 'url': archive_path}, - {'name':'bacon', - 'version': '0.2', - 'requires_dist': [], - 'url': archive_path}, - ]) - - output = get_infos("choxie", index=client, installed= - get_fake_dists([('bacon', '0.1', []),])) - installed = [(o.name, '%s' % o.version) for o in output['install']] - - # we need bacon 0.2, but 0.1 is installed. - # So we expect to remove 0.1 and to install 0.2 instead. - remove = [(o.name, '%s' % o.version) for o in output['remove']] - self.assertIn(('choxie', '2.0.0.9'), installed) - self.assertIn(('towel-stuff', '0.1'), installed) - self.assertIn(('bacon', '0.2'), installed) - self.assertIn(('bacon', '0.1'), remove) - self.assertEqual(0, len(output['conflict'])) - - @use_xmlrpc_server() - def test_conflicts(self, server): - # Tests that conflicts are detected - client = self._get_client(server) - archive_path = '%s/distribution.tar.gz' % server.full_address - server.xmlrpc.set_distributions([ - {'name':'choxie', - 'version': '2.0.0.9', - 'requires_dist': ['towel-stuff (0.1)',], - 'url': archive_path}, - {'name':'towel-stuff', - 'version': '0.1', - 'requires_dist': ['bacon (>= 0.2)',], - 'url': archive_path}, - {'name':'bacon', - 'version': '0.2', - 'requires_dist': [], - 'url': archive_path}, - ]) - already_installed = [('bacon', '0.1', []), - ('chicken', '1.1', ['bacon (0.1)'])] - output = get_infos("choxie", index=client, installed= - get_fake_dists(already_installed)) - - # we need bacon 0.2, but 0.1 is installed. - # So we expect to remove 0.1 and to install 0.2 instead. - installed, remove, conflict = self._get_results(output) - self.assertIn(('choxie', '2.0.0.9'), installed) - self.assertIn(('towel-stuff', '0.1'), installed) - self.assertIn(('bacon', '0.2'), installed) - self.assertIn(('bacon', '0.1'), remove) - self.assertIn(('chicken', '1.1'), conflict) - - @use_xmlrpc_server() - def test_installation_unexisting_project(self, server): - # Test that the isntalled raises an exception if the project does not - # exists. - client = self._get_client(server) - self.assertRaises(InstallationException, get_infos, - 'unexistant project', index=client) - - -def test_suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestInstallWithDeps)) - return suite - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_manifest.py b/src/distutils2/tests/test_manifest.py deleted file mode 100644 index 13893eb..0000000 --- a/src/distutils2/tests/test_manifest.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Tests for distutils.manifest.""" -import os -import sys -import logging - -from distutils2.tests import run_unittest -from distutils2.tests import support -from distutils2.tests.support import unittest -from distutils2.manifest import Manifest - -_MANIFEST = """\ -recursive-include foo *.py # ok -# nothing here - -# - -recursive-include bar \\ - *.dat *.txt -""" - -class ManifestTestCase(support.TempdirManager, - unittest.TestCase): - - def test_manifest_reader(self): - - tmpdir = self.mkdtemp() - MANIFEST = os.path.join(tmpdir, 'MANIFEST.in') - f = open(MANIFEST, 'w') - try: - f.write(_MANIFEST) - finally: - f.close() - manifest = Manifest() - - warns = [] - def _warn(msg): - warns.append(msg) - - old_warn = logging.warning - logging.warning = _warn - try: - manifest.read_template(MANIFEST) - finally: - logging.warning = old_warn - - # the manifest should have been read - # and 3 warnings issued (we ddidn't provided the files) - self.assertEqual(len(warns), 3) - for warn in warns: - self.assertIn('warning: no files found matching', warn) - - - -def test_suite(): - return unittest.makeSuite(ManifestTestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_metadata.py b/src/distutils2/tests/test_metadata.py deleted file mode 100644 index 931f1ba..0000000 --- a/src/distutils2/tests/test_metadata.py +++ /dev/null @@ -1,291 +0,0 @@ -"""Tests for distutils.command.bdist.""" -import os -import sys -import platform -from StringIO import StringIO - -from distutils2.metadata import (DistributionMetadata, _interpret, - PKG_INFO_PREFERRED_VERSION) -from distutils2.tests import run_unittest -from distutils2.tests.support import unittest, LoggingCatcher -from distutils2.errors import (MetadataConflictError, - MetadataUnrecognizedVersionError) - -class DistributionMetadataTestCase(LoggingCatcher, unittest.TestCase): - - def test_instantiation(self): - PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO') - fp = open(PKG_INFO) - try: - contents = fp.read() - finally: - fp.close() - fp = StringIO(contents) - - m = DistributionMetadata() - self.assertRaises(MetadataUnrecognizedVersionError, m.items) - - m = DistributionMetadata(PKG_INFO) - self.assertEqual(len(m.items()), 22) - - m = DistributionMetadata(fileobj=fp) - self.assertEqual(len(m.items()), 22) - - m = DistributionMetadata(mapping=dict(name='Test', version='1.0')) - self.assertEqual(len(m.items()), 11) - - d = dict(m.items()) - self.assertRaises(TypeError, DistributionMetadata, - PKG_INFO, fileobj=fp) - self.assertRaises(TypeError, DistributionMetadata, - PKG_INFO, mapping=d) - self.assertRaises(TypeError, DistributionMetadata, - fileobj=fp, mapping=d) - self.assertRaises(TypeError, DistributionMetadata, - PKG_INFO, mapping=m, fileobj=fp) - - def test_interpret(self): - sys_platform = sys.platform - version = sys.version.split()[0] - os_name = os.name - platform_version = platform.version() - platform_machine = platform.machine() - - self.assertTrue(_interpret("sys.platform == '%s'" % sys_platform)) - self.assertTrue(_interpret( - "sys.platform == '%s' or python_version == '2.4'" % sys_platform)) - self.assertTrue(_interpret( - "sys.platform == '%s' and python_full_version == '%s'" % - (sys_platform, version))) - self.assertTrue(_interpret("'%s' == sys.platform" % sys_platform)) - self.assertTrue(_interpret('os.name == "%s"' % os_name)) - self.assertTrue(_interpret( - 'platform.version == "%s" and platform.machine == "%s"' % - (platform_version, platform_machine))) - - # stuff that need to raise a syntax error - ops = ('os.name == os.name', 'os.name == 2', "'2' == '2'", - 'okpjonon', '', 'os.name ==', 'python_version == 2.4') - for op in ops: - self.assertRaises(SyntaxError, _interpret, op) - - # combined operations - OP = 'os.name == "%s"' % os_name - AND = ' and ' - OR = ' or ' - self.assertTrue(_interpret(OP + AND + OP)) - self.assertTrue(_interpret(OP + AND + OP + AND + OP)) - self.assertTrue(_interpret(OP + OR + OP)) - self.assertTrue(_interpret(OP + OR + OP + OR + OP)) - - # other operators - self.assertTrue(_interpret("os.name != 'buuuu'")) - self.assertTrue(_interpret("python_version > '1.0'")) - self.assertTrue(_interpret("python_version < '5.0'")) - self.assertTrue(_interpret("python_version <= '5.0'")) - self.assertTrue(_interpret("python_version >= '1.0'")) - self.assertTrue(_interpret("'%s' in os.name" % os_name)) - self.assertTrue(_interpret("'buuuu' not in os.name")) - self.assertTrue(_interpret( - "'buuuu' not in os.name and '%s' in os.name" % os_name)) - - # execution context - self.assertTrue(_interpret('python_version == "0.1"', - {'python_version': '0.1'})) - - def test_metadata_read_write(self): - - PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO') - metadata = DistributionMetadata(PKG_INFO) - out = StringIO() - metadata.write_file(out) - out.seek(0) - res = DistributionMetadata() - res.read_file(out) - for k in metadata.keys(): - self.assertTrue(metadata[k] == res[k]) - - def test_metadata_markers(self): - # see if we can be platform-aware - PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO') - content = open(PKG_INFO).read() - content = content % sys.platform - metadata = DistributionMetadata(platform_dependent=True) - metadata.read_file(StringIO(content)) - self.assertEqual(metadata['Requires-Dist'], ['bar']) - metadata['Name'] = "baz; sys.platform == 'blah'" - # FIXME is None or 'UNKNOWN' correct here? - # where is that documented? - self.assertEquals(metadata['Name'], None) - - # test with context - context = {'sys.platform': 'okook'} - metadata = DistributionMetadata(platform_dependent=True, - execution_context=context) - metadata.read_file(StringIO(content)) - self.assertEqual(metadata['Requires-Dist'], ['foo']) - - def test_description(self): - PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO') - content = open(PKG_INFO).read() - content = content % sys.platform - metadata = DistributionMetadata() - metadata.read_file(StringIO(content)) - - # see if we can read the description now - DESC = os.path.join(os.path.dirname(__file__), 'LONG_DESC.txt') - wanted = open(DESC).read() - self.assertEqual(wanted, metadata['Description']) - - # save the file somewhere and make sure we can read it back - out = StringIO() - metadata.write_file(out) - out.seek(0) - metadata.read_file(out) - self.assertEqual(wanted, metadata['Description']) - - def test_mapping_api(self): - PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO') - content = open(PKG_INFO).read() - content = content % sys.platform - metadata = DistributionMetadata(fileobj=StringIO(content)) - self.assertIn('Version', metadata.keys()) - self.assertIn('0.5', metadata.values()) - self.assertIn(('Version', '0.5'), metadata.items()) - - metadata.update({'version': '0.6'}) - self.assertEqual(metadata['Version'], '0.6') - metadata.update([('version', '0.7')]) - self.assertEqual(metadata['Version'], '0.7') - - def test_versions(self): - metadata = DistributionMetadata() - metadata['Obsoletes'] = 'ok' - self.assertEqual(metadata['Metadata-Version'], '1.1') - - del metadata['Obsoletes'] - metadata['Obsoletes-Dist'] = 'ok' - self.assertEqual(metadata['Metadata-Version'], '1.2') - - self.assertRaises(MetadataConflictError, metadata.set, - 'Obsoletes', 'ok') - - del metadata['Obsoletes'] - del metadata['Obsoletes-Dist'] - metadata['Version'] = '1' - self.assertEqual(metadata['Metadata-Version'], '1.0') - - PKG_INFO = os.path.join(os.path.dirname(__file__), - 'SETUPTOOLS-PKG-INFO') - metadata.read_file(StringIO(open(PKG_INFO).read())) - self.assertEqual(metadata['Metadata-Version'], '1.0') - - PKG_INFO = os.path.join(os.path.dirname(__file__), - 'SETUPTOOLS-PKG-INFO2') - metadata.read_file(StringIO(open(PKG_INFO).read())) - self.assertEqual(metadata['Metadata-Version'], '1.1') - - metadata.version = '1.618' - self.assertRaises(MetadataUnrecognizedVersionError, metadata.keys) - - def test_warnings(self): - metadata = DistributionMetadata() - - # these should raise a warning - values = (('Requires-Dist', 'Funky (Groovie)'), - ('Requires-Python', '1-4')) - - from distutils2 import metadata as m - old = m.warn - m.warns = 0 - - def _warn(*args): - m.warns += 1 - - m.warn = _warn - - try: - for name, value in values: - metadata.set(name, value) - finally: - m.warn = old - res = m.warns - del m.warns - - # we should have a certain amount of warnings - num_wanted = len(values) - self.assertEqual(num_wanted, res) - - def test_multiple_predicates(self): - metadata = DistributionMetadata() - - from distutils2 import metadata as m - old = m.warn - m.warns = 0 - - def _warn(*args): - m.warns += 1 - - # see for "3" instead of "3.0" ??? - # its seems like the MINOR VERSION can be omitted - m.warn = _warn - try: - metadata['Requires-Python'] = '>=2.6, <3.0' - metadata['Requires-Dist'] = ['Foo (>=2.6, <3.0)'] - finally: - m.warn = old - res = m.warns - del m.warns - - self.assertEqual(res, 0) - - def test_project_url(self): - metadata = DistributionMetadata() - metadata['Project-URL'] = [('one', 'http://ok')] - self.assertEqual(metadata['Project-URL'], - [('one', 'http://ok')]) - self.assertEqual(metadata.version, '1.2') - - def test_check(self): - metadata = DistributionMetadata() - metadata['Version'] = 'rr' - metadata['Requires-dist'] = ['Foo (a)'] - if metadata.docutils_support: - missing, warnings = metadata.check() - self.assertEqual(len(warnings), 2) - metadata.docutils_support = False - missing, warnings = metadata.check() - self.assertEqual(missing, ['Name', 'Home-page']) - self.assertEqual(len(warnings), 2) - - def test_best_choice(self): - metadata = DistributionMetadata() - metadata['Version'] = '1.0' - self.assertEqual(metadata.version, PKG_INFO_PREFERRED_VERSION) - metadata['Classifier'] = ['ok'] - self.assertEqual(metadata.version, '1.2') - - def test_project_urls(self): - # project-url is a bit specific, make sure we write it - # properly in PKG-INFO - metadata = DistributionMetadata() - metadata['Version'] = '1.0' - metadata['Project-Url'] = [('one', 'http://ok')] - self.assertEqual(metadata['Project-Url'], [('one', 'http://ok')]) - file_ = StringIO() - metadata.write_file(file_) - file_.seek(0) - res = file_.read().split('\n') - self.assertIn('Project-URL: one,http://ok', res) - - file_.seek(0) - metadata = DistributionMetadata() - metadata.read_file(file_) - self.assertEqual(metadata['Project-Url'], [('one', 'http://ok')]) - - -def test_suite(): - return unittest.makeSuite(DistributionMetadataTestCase) - -if __name__ == '__main__': - run_unittest(test_suite()) diff --git a/src/distutils2/tests/test_msvc9compiler.py b/src/distutils2/tests/test_msvc9compiler.py deleted file mode 100644 index eea83fa..0000000 --- a/src/distutils2/tests/test_msvc9compiler.py +++ /dev/null @@ -1,143 +0,0 @@ -"""Tests for distutils.msvc9compiler.""" -import sys -import os - -from distutils2.errors import DistutilsPlatformError -from distutils2.tests import support -from distutils2.tests.support import unittest - -_MANIFEST = """\ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<assembly xmlns="urn:schemas-microsoft-com:asm.v1" - manifestVersion="1.0"> - <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> - <security> - <requestedPrivileges> - <requestedExecutionLevel level="asInvoker" uiAccess="false"> - </requestedExecutionLevel> - </requestedPrivileges> - </security> - </trustInfo> - <dependency> - <dependentAssembly> - <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" - version="9.0.21022.8" processorArchitecture="x86" - publicKeyToken="XXXX"> - </assemblyIdentity> - </dependentAssembly> - </dependency> - <dependency> - <dependentAssembly> - <assemblyIdentity type="win32" name="Microsoft.VC90.MFC" - version="9.0.21022.8" processorArchitecture="x86" - publicKeyToken="XXXX"></assemblyIdentity> - </dependentAssembly> - </dependency> -</assembly> -""" - -_CLEANED_MANIFEST = """\ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<assembly xmlns="urn:schemas-microsoft-com:asm.v1" - manifestVersion="1.0"> - <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> - <security> - <requestedPrivileges> - <requestedExecutionLevel level="asInvoker" uiAccess="false"> - </requestedExecutionLevel> - </requestedPrivileges> - </security> - </trustInfo> - <dependency> - - </dependency> - <dependency> - <dependentAssembly> - <assemblyIdentity type="win32" name="Microsoft.VC90.MFC" - version="9.0.21022.8" processorArchitecture="x86" - publicKeyToken="XXXX"></assemblyIdentity> - </dependentAssembly> - </dependency> -</assembly>""" - - -class msvc9compilerTestCase(support.TempdirManager, - unittest.TestCase): - - @unittest.skipUnless(sys.platform == "win32", "runs only on win32") - def test_no_compiler(self): - # makes sure query_vcvarsall throws - # a DistutilsPlatformError if the compiler - # is not found - from distutils2.msvccompiler import get_build_version - if get_build_version() < 8.0: - # this test is only for MSVC8.0 or above - return - from distutils2.msvc9compiler import query_vcvarsall - def _find_vcvarsall(version): - return None - - from distutils2 import msvc9compiler - old_find_vcvarsall = msvc9compiler.find_vcvarsall - msvc9compiler.find_vcvarsall = _find_vcvarsall - try: - self.assertRaises(DistutilsPlatformError, query_vcvarsall, - 'wont find this version') - finally: - msvc9compiler.find_vcvarsall = old_find_vcvarsall - - @unittest.skipUnless(sys.platform == "win32", "runs only on win32") - def test_reg_class(self): - from distutils2.msvccompiler import get_build_version - if get_build_version() < 8.0: - # this test is only for MSVC8.0 or above - return - - from distutils2.msvc9compiler import Reg - self.assertRaises(KeyError, Reg.get_value, 'xxx', 'xxx') - - # looking for values that should exist on all - # windows registeries versions. - path = r'Control Panel\Desktop' - v = Reg.get_value(path, u'dragfullwindows') - self.assertTrue(v in (u'0', u'1', u'2')) - - import _winreg - HKCU = _winreg.HKEY_CURRENT_USER - keys = Reg.read_keys(HKCU, 'xxxx') - self.assertEqual(keys, None) - - keys = Reg.read_keys(HKCU, r'Control Panel') - self.assertTrue('Desktop' in keys) - - @unittest.skipUnless(sys.platform == "win32", "runs only on win32") - def test_remove_visual_c_ref(self): - from distutils2.msvc9compiler import MSVCCompiler - tempdir = self.mkdtemp() - manifest = os.path.join(tempdir, 'manifest') - f = open(manifest, 'w') - try: - f.write(_MANIFEST) - finally: - f.close() - - compiler = MSVCCompiler() - compiler._remove_visual_c_ref(manifest) - - # see what we got - f = open(manifest) - try: - # removing trailing spaces - content = '\n'.join([line.rstrip() for line in f.readlines()]) - finally: - f.close() - - # makes sure the manifest was properly cleaned - self.assertEqual(content, _CLEANED_MANIFEST) - - -def test_suite(): - return unittest.makeSuite(msvc9compilerTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_pypi_server.py b/src/distutils2/tests/test_pypi_server.py deleted file mode 100644 index 65061ec..0000000 --- a/src/distutils2/tests/test_pypi_server.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Tests for distutils.command.bdist.""" -import urllib -import urllib2 -import os.path - -from distutils2.tests.pypi_server import PyPIServer, PYPI_DEFAULT_STATIC_PATH -from distutils2.tests.support import unittest - - -class PyPIServerTest(unittest.TestCase): - - def test_records_requests(self): - # We expect that PyPIServer can log our requests - server = PyPIServer() - server.start() - self.assertEqual(len(server.requests), 0) - - data = "Rock Around The Bunker" - headers = {"X-test-header": "Mister Iceberg"} - - request = urllib2.Request(server.full_address, data, headers) - urllib2.urlopen(request) - self.assertEqual(len(server.requests), 1) - handler, request_data = server.requests[-1] - self.assertIn("Rock Around The Bunker", request_data) - self.assertIn("x-test-header", handler.headers.dict) - self.assertEqual(handler.headers.dict["x-test-header"], - "Mister Iceberg") - server.stop() - - def test_serve_static_content(self): - # PYPI Mocked server can serve static content from disk. - - def uses_local_files_for(server, url_path): - """Test that files are served statically (eg. the output from the - server is the same than the one made by a simple file read. - """ - url = server.full_address + url_path - request = urllib2.Request(url) - response = urllib2.urlopen(request) - file = open(PYPI_DEFAULT_STATIC_PATH + "/test_pypi_server" + - url_path) - return response.read() == file.read() - - server = PyPIServer(static_uri_paths=["simple", "external"], - static_filesystem_paths=["test_pypi_server"]) - server.start() - - # the file does not exists on the disc, so it might not be served - url = server.full_address + "/simple/unexisting_page" - request = urllib2.Request(url) - try: - urllib2.urlopen(request) - except urllib2.HTTPError,e: - self.assertEqual(e.code, 404) - - # now try serving a content that do exists - self.assertTrue(uses_local_files_for(server, "/simple/index.html")) - - # and another one in another root path - self.assertTrue(uses_local_files_for(server, "/external/index.html")) - server.stop() - - -def test_suite(): - return unittest.makeSuite(PyPIServerTest) - -if __name__ == '__main__': - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_pypi_versions.py b/src/distutils2/tests/test_pypi_versions.py deleted file mode 100644 index bbb9395..0000000 --- a/src/distutils2/tests/test_pypi_versions.py +++ /dev/null @@ -1,127 +0,0 @@ -"""PEP 386 compatibility test with current distributions on PyPI. - -A very simple test to see what percentage of the current PyPI packages -have versions that can be converted automatically by distutils2's new -suggest_normalized_version into PEP 386-compatible versions. -""" - -# XXX This file does not actually run tests, move it to a script - -# Written by ssteinerX@gmail.com - -import os -import xmlrpclib - -try: - import cPickle as pickle -except ImportError: - import pickle - -from distutils2.version import suggest_normalized_version -from distutils2.tests import run_unittest -from distutils2.tests.support import unittest - -def test_pypi(): - # FIXME need a better way to do that - # To re-run from scratch, just delete these two .pkl files - INDEX_PICKLE_FILE = 'pypi-index.pkl' - VERSION_PICKLE_FILE = 'pypi-version.pkl' - - package_info = version_info = [] - - # if there's a saved version of the package list - # restore it - # else: - # pull the list down from pypi - # save a pickled version of it - if os.path.exists(INDEX_PICKLE_FILE): - print "Loading saved pypi data..." - f = open(INDEX_PICKLE_FILE, 'rb') - try: - package_info = pickle.load(f) - finally: - f.close() - else: - print "Retrieving pypi packages..." - server = xmlrpclib.Server('http://pypi.python.org/pypi') - package_info = server.search({'name': ''}) - - print "Saving package info..." - f = open(INDEX_PICKLE_FILE, 'wb') - try: - pickle.dump(package_info, f) - finally: - f.close() - - # If there's a saved list of the versions from the packages - # restore it - # else - # extract versions from the package list - # save a pickled version of it - versions = [] - if os.path.exists(VERSION_PICKLE_FILE): - print "Loading saved version info..." - f = open(VERSION_PICKLE_FILE, 'rb') - try: - versions = pickle.load(f) - finally: - f.close() - else: - print "Extracting and saving version info..." - versions = [p['version'] for p in package_info] - o = open(VERSION_PICKLE_FILE, 'wb') - try: - pickle.dump(versions, o) - finally: - o.close() - - total_versions = len(versions) - matches = 0.00 - no_sugg = 0.00 - have_sugg = 0.00 - - suggs = [] - no_suggs = [] - - for ver in versions: - sugg = suggest_normalized_version(ver) - if sugg == ver: - matches += 1 - elif sugg == None: - no_sugg += 1 - no_suggs.append(ver) - else: - have_sugg += 1 - suggs.append((ver, sugg)) - - pct = "(%2.2f%%)" - print "Results:" - print "--------" - print "" - print "Suggestions" - print "-----------" - print "" - for ver, sugg in suggs: - print "%s -> %s" % (ver, sugg) - print "" - print "No suggestions" - print "--------------" - for ver in no_suggs: - print ver - print "" - print "Summary:" - print "--------" - print "Total Packages : ", total_versions - print "Already Match : ", matches, pct % (matches/total_versions*100,) - print "Have Suggestion : ", have_sugg, pct % (have_sugg/total_versions*100,) - print "No Suggestion : ", no_sugg, pct % (no_sugg/total_versions*100,) - -class TestPyPI(unittest.TestCase): - pass - -def test_suite(): - return unittest.makeSuite(TestPyPI) - -if __name__ == '__main__': - run_unittest(test_suite()) - diff --git a/src/distutils2/tests/test_register.py b/src/distutils2/tests/test_register.py deleted file mode 100644 index d232978..0000000 --- a/src/distutils2/tests/test_register.py +++ /dev/null @@ -1,262 +0,0 @@ -# -*- encoding: utf-8 -*- -"""Tests for distutils.command.register.""" -import sys -import os -import getpass -import urllib2 - -try: - import docutils - DOCUTILS_SUPPORT = True -except ImportError: - DOCUTILS_SUPPORT = False - -from distutils2.command import register as register_module -from distutils2.command.register import register -from distutils2.core import Distribution -from distutils2.errors import DistutilsSetupError - -from distutils2.tests import support -from distutils2.tests.support import unittest - - -PYPIRC_NOPASSWORD = """\ -[distutils] - -index-servers = - server1 - -[server1] -username:me -""" - -WANTED_PYPIRC = """\ -[distutils] -index-servers = - pypi - -[pypi] -username:tarek -password:password -""" - -class RawInputs(object): - """Fakes user inputs.""" - def __init__(self, *answers): - self.answers = answers - self.index = 0 - - def __call__(self, prompt=''): - try: - return self.answers[self.index] - finally: - self.index += 1 - -class FakeOpener(object): - """Fakes a PyPI server""" - def __init__(self): - self.reqs = [] - - def __call__(self, *args): - return self - - def open(self, req): - self.reqs.append(req) - return self - - def read(self): - return 'xxx' - -class RegisterTestCase(support.TempdirManager, support.EnvironGuard, - unittest.TestCase): - - def setUp(self): - super(RegisterTestCase, self).setUp() - self.tmp_dir = self.mkdtemp() - self.rc = os.path.join(self.tmp_dir, '.pypirc') - os.environ['HOME'] = self.tmp_dir - - # patching the password prompt - self._old_getpass = getpass.getpass - def _getpass(prompt): - return 'password' - getpass.getpass = _getpass - self.old_opener = urllib2.build_opener - self.conn = urllib2.build_opener = FakeOpener() - - def tearDown(self): - getpass.getpass = self._old_getpass - urllib2.build_opener = self.old_opener - super(RegisterTestCase, self).tearDown() - - def _get_cmd(self, metadata=None): - if metadata is None: - metadata = {'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx', - 'name': 'xxx', 'version': 'xxx'} - pkg_info, dist = self.create_dist(**metadata) - return register(dist) - - def test_create_pypirc(self): - # this test makes sure a .pypirc file - # is created when requested. - - # let's create a register instance - cmd = self._get_cmd() - - # we shouldn't have a .pypirc file yet - self.assertTrue(not os.path.exists(self.rc)) - - # patching raw_input and getpass.getpass - # so register gets happy - # - # Here's what we are faking : - # use your existing login (choice 1.) - # Username : 'tarek' - # Password : 'password' - # Save your login (y/N)? : 'y' - inputs = RawInputs('1', 'tarek', 'y') - register_module.raw_input = inputs.__call__ - # let's run the command - try: - cmd.run() - finally: - del register_module.raw_input - - # we should have a brand new .pypirc file - self.assertTrue(os.path.exists(self.rc)) - - # with the content similar to WANTED_PYPIRC - content = open(self.rc).read() - self.assertEqual(content, WANTED_PYPIRC) - - # now let's make sure the .pypirc file generated - # really works : we shouldn't be asked anything - # if we run the command again - def _no_way(prompt=''): - raise AssertionError(prompt) - register_module.raw_input = _no_way - - cmd.show_response = 1 - cmd.run() - - # let's see what the server received : we should - # have 2 similar requests - self.assertTrue(self.conn.reqs, 2) - req1 = dict(self.conn.reqs[0].headers) - req2 = dict(self.conn.reqs[1].headers) - self.assertEqual(req2['Content-length'], req1['Content-length']) - self.assertTrue('xxx' in self.conn.reqs[1].data) - - def test_password_not_in_file(self): - - self.write_file(self.rc, PYPIRC_NOPASSWORD) - cmd = self._get_cmd() - cmd.finalize_options() - cmd._set_config() - cmd.send_metadata() - - # dist.password should be set - # therefore used afterwards by other commands - self.assertEqual(cmd.distribution.password, 'password') - - def test_registration(self): - # this test runs choice 2 - cmd = self._get_cmd() - inputs = RawInputs('2', 'tarek', 'tarek@ziade.org') - register_module.raw_input = inputs.__call__ - try: - # let's run the command - # FIXME does this send a real request? use a mock server - # also, silence self.announce (with LoggingCatcher) - cmd.run() - finally: - del register_module.raw_input - - # we should have send a request - self.assertTrue(self.conn.reqs, 1) - req = self.conn.reqs[0] - headers = dict(req.headers) - self.assertEqual(headers['Content-length'], '608') - self.assertTrue('tarek' in req.data) - - def test_password_reset(self): - # this test runs choice 3 - cmd = self._get_cmd() - inputs = RawInputs('3', 'tarek@ziade.org') - register_module.raw_input = inputs.__call__ - try: - # let's run the command - cmd.run() - finally: - del register_module.raw_input - - # we should have send a request - self.assertTrue(self.conn.reqs, 1) - req = self.conn.reqs[0] - headers = dict(req.headers) - self.assertEqual(headers['Content-length'], '290') - self.assertTrue('tarek' in req.data) - - @unittest.skipUnless(DOCUTILS_SUPPORT, 'needs docutils') - def test_strict(self): - # testing the script option - # when on, the register command stops if - # the metadata is incomplete or if - # long_description is not reSt compliant - - # empty metadata - cmd = self._get_cmd({}) - cmd.ensure_finalized() - cmd.strict = 1 - self.assertRaises(DistutilsSetupError, cmd.run) - - # metadata is OK but long_description is broken - metadata = {'home_page': 'xxx', 'author': 'xxx', - 'author_email': u'éxéxé', - 'name': 'xxx', 'version': 'xxx', - 'description': 'title\n==\n\ntext'} - - cmd = self._get_cmd(metadata) - cmd.ensure_finalized() - cmd.strict = 1 - - self.assertRaises(DistutilsSetupError, cmd.run) - - # now something that works - metadata['description'] = 'title\n=====\n\ntext' - cmd = self._get_cmd(metadata) - cmd.ensure_finalized() - cmd.strict = 1 - inputs = RawInputs('1', 'tarek', 'y') - register_module.raw_input = inputs.__call__ - # let's run the command - try: - cmd.run() - finally: - del register_module.raw_input - - # strict is not by default - cmd = self._get_cmd() - cmd.ensure_finalized() - inputs = RawInputs('1', 'tarek', 'y') - register_module.raw_input = inputs.__call__ - # let's run the command - try: - cmd.run() - finally: - del register_module.raw_input - - def test_register_pep345(self): - cmd = self._get_cmd({}) - cmd.ensure_finalized() - cmd.distribution.metadata['Requires-Dist'] = ['lxml'] - data = cmd.build_post_data('submit') - self.assertEqual(data['metadata_version'], '1.2') - self.assertEqual(data['requires_dist'], ['lxml']) - -def test_suite(): - return unittest.makeSuite(RegisterTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_sdist.py b/src/distutils2/tests/test_sdist.py deleted file mode 100644 index 2bd1dfd..0000000 --- a/src/distutils2/tests/test_sdist.py +++ /dev/null @@ -1,423 +0,0 @@ -"""Tests for distutils.command.sdist.""" -import os -import shutil -import zipfile -import tarfile - -# zlib is not used here, but if it's not available -# the tests that use zipfile may fail -try: - import zlib -except ImportError: - zlib = None - -try: - import grp - import pwd - UID_GID_SUPPORT = True -except ImportError: - UID_GID_SUPPORT = False - -from os.path import join -import sys - -from distutils2.tests import captured_stdout - -from distutils2.command.sdist import sdist -from distutils2.command.sdist import show_formats -from distutils2.core import Distribution -from distutils2.tests.support import unittest -from distutils2.errors import DistutilsExecError, DistutilsOptionError -from distutils2.util import find_executable -from distutils2.tests import support -from distutils2.log import WARN -try: - from shutil import get_archive_formats -except ImportError: - from distutils2._backport.shutil import get_archive_formats - -SETUP_PY = """ -from distutils.core import setup -import somecode - -setup(name='fake') -""" - -MANIFEST = """\ -# file GENERATED by distutils, do NOT edit -README -inroot.txt -setup.py -data%(sep)sdata.dt -scripts%(sep)sscript.py -some%(sep)sfile.txt -some%(sep)sother_file.txt -somecode%(sep)s__init__.py -somecode%(sep)sdoc.dat -somecode%(sep)sdoc.txt -""" - -class SDistTestCase(support.TempdirManager, support.LoggingCatcher, - support.EnvironGuard, unittest.TestCase): - - def setUp(self): - # PyPIRCCommandTestCase creates a temp dir already - # and put it in self.tmp_dir - super(SDistTestCase, self).setUp() - self.tmp_dir = self.mkdtemp() - os.environ['HOME'] = self.tmp_dir - # setting up an environment - self.old_path = os.getcwd() - os.mkdir(join(self.tmp_dir, 'somecode')) - os.mkdir(join(self.tmp_dir, 'dist')) - # a package, and a README - self.write_file((self.tmp_dir, 'README'), 'xxx') - self.write_file((self.tmp_dir, 'somecode', '__init__.py'), '#') - self.write_file((self.tmp_dir, 'setup.py'), SETUP_PY) - os.chdir(self.tmp_dir) - - def tearDown(self): - # back to normal - os.chdir(self.old_path) - super(SDistTestCase, self).tearDown() - - def get_cmd(self, metadata=None): - """Returns a cmd""" - if metadata is None: - metadata = {'name': 'fake', 'version': '1.0', - 'url': 'xxx', 'author': 'xxx', - 'author_email': 'xxx'} - dist = Distribution(metadata) - dist.script_name = 'setup.py' - dist.packages = ['somecode'] - dist.include_package_data = True - cmd = sdist(dist) - cmd.dist_dir = 'dist' - def _warn(*args): - pass - cmd.warn = _warn - return dist, cmd - - @unittest.skipUnless(zlib, "requires zlib") - def test_prune_file_list(self): - # this test creates a package with some vcs dirs in it - # and launch sdist to make sure they get pruned - # on all systems - - # creating VCS directories with some files in them - os.mkdir(join(self.tmp_dir, 'somecode', '.svn')) - self.write_file((self.tmp_dir, 'somecode', '.svn', 'ok.py'), 'xxx') - - os.mkdir(join(self.tmp_dir, 'somecode', '.hg')) - self.write_file((self.tmp_dir, 'somecode', '.hg', - 'ok'), 'xxx') - - os.mkdir(join(self.tmp_dir, 'somecode', '.git')) - self.write_file((self.tmp_dir, 'somecode', '.git', - 'ok'), 'xxx') - - # now building a sdist - dist, cmd = self.get_cmd() - - # zip is available universally - # (tar might not be installed under win32) - cmd.formats = ['zip'] - - cmd.ensure_finalized() - cmd.run() - - # now let's check what we have - dist_folder = join(self.tmp_dir, 'dist') - files = os.listdir(dist_folder) - self.assertEqual(files, ['fake-1.0.zip']) - - zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) - try: - content = zip_file.namelist() - finally: - zip_file.close() - - # making sure everything has been pruned correctly - self.assertEqual(len(content), 4) - - @unittest.skipUnless(zlib, "requires zlib") - def test_make_distribution(self): - - # check if tar and gzip are installed - if (find_executable('tar') is None or - find_executable('gzip') is None): - return - - # now building a sdist - dist, cmd = self.get_cmd() - - # creating a gztar then a tar - cmd.formats = ['gztar', 'tar'] - cmd.ensure_finalized() - cmd.run() - - # making sure we have two files - dist_folder = join(self.tmp_dir, 'dist') - result = os.listdir(dist_folder) - result.sort() - self.assertEqual(result, - ['fake-1.0.tar', 'fake-1.0.tar.gz'] ) - - os.remove(join(dist_folder, 'fake-1.0.tar')) - os.remove(join(dist_folder, 'fake-1.0.tar.gz')) - - # now trying a tar then a gztar - cmd.formats = ['tar', 'gztar'] - - cmd.ensure_finalized() - cmd.run() - - result = os.listdir(dist_folder) - result.sort() - self.assertEqual(result, - ['fake-1.0.tar', 'fake-1.0.tar.gz']) - - @unittest.skipUnless(zlib, "requires zlib") - def test_add_defaults(self): - - # http://bugs.python.org/issue2279 - - # add_default should also include - # data_files and package_data - dist, cmd = self.get_cmd() - - # filling data_files by pointing files - # in package_data - dist.package_data = {'': ['*.cfg', '*.dat'], - 'somecode': ['*.txt']} - self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') - self.write_file((self.tmp_dir, 'somecode', 'doc.dat'), '#') - - # adding some data in data_files - data_dir = join(self.tmp_dir, 'data') - os.mkdir(data_dir) - self.write_file((data_dir, 'data.dt'), '#') - some_dir = join(self.tmp_dir, 'some') - os.mkdir(some_dir) - self.write_file((self.tmp_dir, 'inroot.txt'), '#') - self.write_file((some_dir, 'file.txt'), '#') - self.write_file((some_dir, 'other_file.txt'), '#') - - dist.data_files = [('data', ['data/data.dt', - 'inroot.txt', - 'notexisting']), - 'some/file.txt', - 'some/other_file.txt'] - - # adding a script - script_dir = join(self.tmp_dir, 'scripts') - os.mkdir(script_dir) - self.write_file((script_dir, 'script.py'), '#') - dist.scripts = [join('scripts', 'script.py')] - - cmd.formats = ['zip'] - cmd.use_defaults = True - - cmd.ensure_finalized() - cmd.run() - - # now let's check what we have - dist_folder = join(self.tmp_dir, 'dist') - files = os.listdir(dist_folder) - self.assertEqual(files, ['fake-1.0.zip']) - - zip_file = zipfile.ZipFile(join(dist_folder, 'fake-1.0.zip')) - try: - content = zip_file.namelist() - finally: - zip_file.close() - - # making sure everything was added - self.assertEqual(len(content), 11) - - # checking the MANIFEST - manifest = open(join(self.tmp_dir, 'MANIFEST')).read() - self.assertEqual(manifest, MANIFEST % {'sep': os.sep}) - - @unittest.skipUnless(zlib, "requires zlib") - def test_metadata_check_option(self): - # testing the `check-metadata` option - dist, cmd = self.get_cmd(metadata={}) - - # this should raise some warnings ! - # with the `check` subcommand - cmd.ensure_finalized() - cmd.run() - warnings = self.get_logs(WARN) - self.assertEqual(len(warnings), 1) - - # trying with a complete set of metadata - self.clear_logs() - dist, cmd = self.get_cmd() - cmd.ensure_finalized() - cmd.metadata_check = 0 - cmd.run() - warnings = self.get_logs(WARN) - # removing manifest generated warnings - warnings = [warn for warn in warnings if - not warn.endswith('-- skipping')] - self.assertEqual(len(warnings), 0) - - - def test_show_formats(self): - __, stdout = captured_stdout(show_formats) - - # the output should be a header line + one line per format - num_formats = len(get_archive_formats()) - output = [line for line in stdout.split('\n') - if line.strip().startswith('--formats=')] - self.assertEqual(len(output), num_formats) - - def test_finalize_options(self): - - dist, cmd = self.get_cmd() - cmd.finalize_options() - - # default options set by finalize - self.assertEqual(cmd.manifest, 'MANIFEST') - self.assertEqual(cmd.template, 'MANIFEST.in') - self.assertEqual(cmd.dist_dir, 'dist') - - # formats has to be a string splitable on (' ', ',') or - # a stringlist - cmd.formats = 1 - self.assertRaises(DistutilsOptionError, cmd.finalize_options) - cmd.formats = ['zip'] - cmd.finalize_options() - - # formats has to be known - cmd.formats = 'supazipa' - self.assertRaises(DistutilsOptionError, cmd.finalize_options) - - @unittest.skipUnless(zlib, "requires zlib") - @unittest.skipUnless(UID_GID_SUPPORT, "requires grp and pwd support") - def test_make_distribution_owner_group(self): - - # check if tar and gzip are installed - if (find_executable('tar') is None or - find_executable('gzip') is None): - return - - # now building a sdist - dist, cmd = self.get_cmd() - - # creating a gztar and specifying the owner+group - cmd.formats = ['gztar'] - cmd.owner = pwd.getpwuid(0)[0] - cmd.group = grp.getgrgid(0)[0] - cmd.ensure_finalized() - cmd.run() - - # making sure we have the good rights - archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') - archive = tarfile.open(archive_name) - try: - for member in archive.getmembers(): - self.assertEqual(member.uid, 0) - self.assertEqual(member.gid, 0) - finally: - archive.close() - - # building a sdist again - dist, cmd = self.get_cmd() - - # creating a gztar - cmd.formats = ['gztar'] - cmd.ensure_finalized() - cmd.run() - - # making sure we have the good rights - archive_name = join(self.tmp_dir, 'dist', 'fake-1.0.tar.gz') - archive = tarfile.open(archive_name) - - # note that we are not testing the group ownership here - # because, depending on the platforms and the container - # rights (see #7408) - try: - for member in archive.getmembers(): - self.assertEqual(member.uid, os.getuid()) - finally: - archive.close() - - def test_get_file_list(self): - # make sure MANIFEST is recalculated - dist, cmd = self.get_cmd() - - # filling data_files by pointing files in package_data - dist.package_data = {'somecode': ['*.txt']} - self.write_file((self.tmp_dir, 'somecode', 'doc.txt'), '#') - cmd.ensure_finalized() - cmd.run() - - f = open(cmd.manifest) - try: - manifest = [line.strip() for line in f.read().split('\n') - if line.strip() != ''] - finally: - f.close() - - self.assertEquals(len(manifest), 5) - - # adding a file - self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#') - - # make sure build_py is reinitinialized, like a fresh run - build_py = dist.get_command_obj('build_py') - build_py.finalized = False - build_py.ensure_finalized() - - cmd.run() - - f = open(cmd.manifest) - try: - manifest2 = [line.strip() for line in f.read().split('\n') - if line.strip() != ''] - finally: - f.close() - - # do we have the new file in MANIFEST ? - self.assertEquals(len(manifest2), 6) - self.assertIn('doc2.txt', manifest2[-1]) - - def test_manifest_marker(self): - # check that autogenerated MANIFESTs have a marker - dist, cmd = self.get_cmd() - cmd.ensure_finalized() - cmd.run() - - f = open(cmd.manifest) - try: - manifest = [line.strip() for line in f.read().split('\n') - if line.strip() != ''] - finally: - f.close() - - self.assertEqual(manifest[0], - '# file GENERATED by distutils, do NOT edit') - - def test_manual_manifest(self): - # check that a MANIFEST without a marker is left alone - dist, cmd = self.get_cmd() - cmd.ensure_finalized() - self.write_file((self.tmp_dir, cmd.manifest), 'README.manual') - cmd.run() - - f = open(cmd.manifest) - try: - manifest = [line.strip() for line in f.read().split('\n') - if line.strip() != ''] - finally: - f.close() - - self.assertEqual(manifest, ['README.manual']) - -def test_suite(): - return unittest.makeSuite(SDistTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_test.py b/src/distutils2/tests/test_test.py deleted file mode 100644 index 68cd5f3..0000000 --- a/src/distutils2/tests/test_test.py +++ /dev/null @@ -1,198 +0,0 @@ -import os -import re -import sys -import shutil -import unittest as ut1 - -from copy import copy -from os.path import join -from operator import getitem, setitem, delitem -from StringIO import StringIO -from distutils2.core import Command -from distutils2.tests.support import unittest, TempdirManager -from distutils2.command.test import test -from distutils2.dist import Distribution - -try: - any -except NameError: - from distutils2._backport import any - -EXPECTED_OUTPUT_RE = r'''FAIL: test_blah \(myowntestmodule.SomeTest\) ----------------------------------------------------------------------- -Traceback \(most recent call last\): - File ".+/myowntestmodule.py", line \d+, in test_blah - self.fail\("horribly"\) -AssertionError: horribly -''' - -here = os.path.dirname(os.path.abspath(__file__)) - -class TestTest(TempdirManager, - unittest.TestCase): - - def setUp(self): - super(TestTest, self).setUp() - - distutils2path = os.path.dirname(os.path.dirname(here)) - self.old_pythonpath = os.environ.get('PYTHONPATH', '') - os.environ['PYTHONPATH'] = distutils2path + os.pathsep + self.old_pythonpath - - def tearDown(self): - os.environ['PYTHONPATH'] = self.old_pythonpath - super(TestTest, self).tearDown() - - def assert_re_match(self, pattern, string): - def quote(s): - lines = ['## ' + line for line in s.split('\n')] - sep = ["#" * 60] - return [''] + sep + lines + sep - msg = quote(pattern) + ["didn't match"] + quote(string) - msg = "\n".join(msg) - if not re.search(pattern, string): - self.fail(msg) - - def prepare_dist(self, dist_name): - pkg_dir = join(os.path.dirname(__file__), "dists", dist_name) - temp_pkg_dir = join(self.mkdtemp(), dist_name) - shutil.copytree(pkg_dir, temp_pkg_dir) - return temp_pkg_dir - - def safely_replace(self, obj, attr, new_val=None, delete=False, dictionary=False): - """Replace a object's attribute returning to its original state at the - end of the test run. Creates the attribute if not present before - (deleting afterwards). When delete=True, makes sure the value is del'd - for the test run. If dictionary is set to True, operates of its items - rather than attributes.""" - if dictionary: - _setattr, _getattr, _delattr = setitem, getitem, delitem - def _hasattr(_dict, value): - return value in _dict - else: - _setattr, _getattr, _delattr, _hasattr = setattr, getattr, delattr, hasattr - - orig_has_attr = _hasattr(obj, attr) - if orig_has_attr: - orig_val = _getattr(obj, attr) - - if delete is False: - _setattr(obj, attr, new_val) - elif orig_has_attr: - _delattr(obj, attr) - - def do_cleanup(): - if orig_has_attr: - _setattr(obj, attr, orig_val) - elif _hasattr(obj, attr): - _delattr(obj, attr) - - self.addCleanup(do_cleanup) - - def test_runs_unittest(self): - module_name, a_module = self.prepare_a_module() - record = [] - a_module.recorder = lambda *args: record.append("suite") - - class MockTextTestRunner(object): - def __init__(*_, **__): pass - def run(_self, suite): - record.append("run") - self.safely_replace(ut1, "TextTestRunner", MockTextTestRunner) - - dist = Distribution() - cmd = test(dist) - cmd.suite = "%s.recorder" % module_name - cmd.run() - self.assertEqual(record, ["suite", "run"]) - - def test_builds_before_running_tests(self): - dist = Distribution() - cmd = test(dist) - cmd.runner = self.prepare_named_function(lambda: None) - record = [] - class MockBuildCmd(Command): - build_lib = "mock build lib" - def initialize_options(self): pass - def finalize_options(self): pass - def run(self): record.append("build run") - dist.cmdclass['build'] = MockBuildCmd - - cmd.ensure_finalized() - cmd.run() - self.assertEqual(record, ['build run']) - - def _test_works_with_2to3(self): - pass - - def test_checks_requires(self): - dist = Distribution() - cmd = test(dist) - phony_project = 'ohno_ohno-impossible_1234-name_stop-that!' - cmd.tests_require = [phony_project] - record = [] - cmd.announce = lambda *args: record.append(args) - cmd.ensure_finalized() - self.assertEqual(1, len(record)) - self.assertIn(phony_project, record[0][0]) - - def prepare_a_module(self): - tmp_dir = self.mkdtemp() - sys.path.append(tmp_dir) - self.addCleanup(lambda: sys.path.remove(tmp_dir)) - - self.write_file((tmp_dir, 'distutils2_tests_a.py'), '') - import distutils2_tests_a as a_module - return "distutils2_tests_a", a_module - - def prepare_named_function(self, func): - module_name, a_module = self.prepare_a_module() - a_module.recorder = func - return "%s.recorder" % module_name - - def test_custom_runner(self): - dist = Distribution() - cmd = test(dist) - - record = [] - cmd.runner = self.prepare_named_function(lambda: record.append("runner called")) - cmd.ensure_finalized() - cmd.run() - self.assertEqual(["runner called"], record) - - def prepare_mock_ut2(self): - class MockUTClass(object): - def __init__(*_, **__): pass - def discover(self): pass - def run(self, _): pass - class MockUTModule(object): - TestLoader = MockUTClass - TextTestRunner = MockUTClass - mock_ut2 = MockUTModule() - self.safely_replace(sys.modules, "unittest2", mock_ut2, dictionary=True) - return mock_ut2 - - def test_gets_unittest_discovery(self): - mock_ut2 = self.prepare_mock_ut2() - dist = Distribution() - cmd = test(dist) - self.safely_replace(ut1.TestLoader, "discover", lambda: None) - self.assertEqual(cmd.get_ut_with_discovery(), ut1) - - del ut1.TestLoader.discover - self.assertEqual(cmd.get_ut_with_discovery(), mock_ut2) - - def test_calls_discover(self): - self.safely_replace(ut1.TestLoader, "discover", delete=True) - mock_ut2 = self.prepare_mock_ut2() - record = [] - mock_ut2.TestLoader.discover = lambda self, path: record.append(path) - dist = Distribution() - cmd = test(dist) - cmd.run() - self.assertEqual(record, [os.curdir]) - -def test_suite(): - return unittest.makeSuite(TestTest) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_unixccompiler.py b/src/distutils2/tests/test_unixccompiler.py deleted file mode 100644 index 6de616a..0000000 --- a/src/distutils2/tests/test_unixccompiler.py +++ /dev/null @@ -1,133 +0,0 @@ -"""Tests for distutils.unixccompiler.""" -import sys - -try: - import sysconfig -except ImportError: - from distutils2._backport import sysconfig - -from distutils2.compiler.unixccompiler import UnixCCompiler -from distutils2.tests.support import unittest - -class UnixCCompilerTestCase(unittest.TestCase): - - def setUp(self): - self._backup_platform = sys.platform - self._backup_get_config_var = sysconfig.get_config_var - class CompilerWrapper(UnixCCompiler): - def rpath_foo(self): - return self.runtime_library_dir_option('/foo') - self.cc = CompilerWrapper() - - def tearDown(self): - sys.platform = self._backup_platform - sysconfig.get_config_var = self._backup_get_config_var - - def test_runtime_libdir_option(self): - - # not tested under windows - if sys.platform == 'win32': - return - - # Issue#5900 - # - # Ensure RUNPATH is added to extension modules with RPATH if - # GNU ld is used - - # darwin - sys.platform = 'darwin' - self.assertEqual(self.cc.rpath_foo(), '-L/foo') - - # hp-ux - sys.platform = 'hp-ux' - old_gcv = sysconfig.get_config_var - def gcv(v): - return 'xxx' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), ['+s', '-L/foo']) - - def gcv(v): - return 'gcc' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), ['-Wl,+s', '-L/foo']) - - def gcv(v): - return 'g++' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), ['-Wl,+s', '-L/foo']) - - sysconfig.get_config_var = old_gcv - - # irix646 - sys.platform = 'irix646' - self.assertEqual(self.cc.rpath_foo(), ['-rpath', '/foo']) - - # osf1V5 - sys.platform = 'osf1V5' - self.assertEqual(self.cc.rpath_foo(), ['-rpath', '/foo']) - - # GCC GNULD - sys.platform = 'bar' - def gcv(v): - if v == 'CC': - return 'gcc' - elif v == 'GNULD': - return 'yes' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo') - - # GCC non-GNULD - sys.platform = 'bar' - def gcv(v): - if v == 'CC': - return 'gcc' - elif v == 'GNULD': - return 'no' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), '-Wl,-R/foo') - - # GCC GNULD with fully qualified configuration prefix - # see #7617 - sys.platform = 'bar' - def gcv(v): - if v == 'CC': - return 'x86_64-pc-linux-gnu-gcc-4.4.2' - elif v == 'GNULD': - return 'yes' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo') - - - # non-GCC GNULD - sys.platform = 'bar' - def gcv(v): - if v == 'CC': - return 'cc' - elif v == 'GNULD': - return 'yes' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), '-R/foo') - - # non-GCC non-GNULD - sys.platform = 'bar' - def gcv(v): - if v == 'CC': - return 'cc' - elif v == 'GNULD': - return 'no' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), '-R/foo') - - # AIX C/C++ linker - sys.platform = 'aix' - def gcv(v): - return 'xxx' - sysconfig.get_config_var = gcv - self.assertEqual(self.cc.rpath_foo(), '-blibpath:/foo') - - -def test_suite(): - return unittest.makeSuite(UnixCCompilerTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_upload.py b/src/distutils2/tests/test_upload.py deleted file mode 100644 index a12e227..0000000 --- a/src/distutils2/tests/test_upload.py +++ /dev/null @@ -1,140 +0,0 @@ -# -*- encoding: utf-8 -*- -"""Tests for distutils.command.upload.""" -import os -import sys - -from distutils2.command.upload import upload -from distutils2.core import Distribution - -from distutils2.tests import support -from distutils2.tests.pypi_server import PyPIServer, PyPIServerTestCase -from distutils2.tests.support import unittest - - -PYPIRC_NOPASSWORD = """\ -[distutils] - -index-servers = - server1 - -[server1] -username:me -""" - -PYPIRC = """\ -[distutils] - -index-servers = - server1 - server2 - -[server1] -username:me -password:secret - -[server2] -username:meagain -password: secret -realm:acme -repository:http://another.pypi/ -""" - - -class UploadTestCase(support.TempdirManager, support.EnvironGuard, - support.LoggingCatcher, PyPIServerTestCase): - - def setUp(self): - super(UploadTestCase, self).setUp() - self.tmp_dir = self.mkdtemp() - self.rc = os.path.join(self.tmp_dir, '.pypirc') - os.environ['HOME'] = self.tmp_dir - - def test_finalize_options(self): - # new format - self.write_file(self.rc, PYPIRC) - dist = Distribution() - cmd = upload(dist) - cmd.finalize_options() - for attr, expected in (('username', 'me'), ('password', 'secret'), - ('realm', 'pypi'), - ('repository', 'http://pypi.python.org/pypi')): - self.assertEqual(getattr(cmd, attr), expected) - - def test_saved_password(self): - # file with no password - self.write_file(self.rc, PYPIRC_NOPASSWORD) - - # make sure it passes - dist = Distribution() - cmd = upload(dist) - cmd.ensure_finalized() - self.assertEqual(cmd.password, None) - - # make sure we get it as well, if another command - # initialized it at the dist level - dist.password = 'xxx' - cmd = upload(dist) - cmd.finalize_options() - self.assertEqual(cmd.password, 'xxx') - - def test_upload(self): - path = os.path.join(self.tmp_dir, 'xxx') - self.write_file(path) - command, pyversion, filename = 'xxx', '2.6', path - dist_files = [(command, pyversion, filename)] - - # lets run it - pkg_dir, dist = self.create_dist(dist_files=dist_files, author=u'dédé') - cmd = upload(dist) - cmd.ensure_finalized() - cmd.repository = self.pypi.full_address - cmd.run() - - # what did we send ? - handler, request_data = self.pypi.requests[-1] - headers = handler.headers.dict - self.assertIn('dédé', request_data) - self.assertIn('xxx', request_data) - self.assertEqual(int(headers['content-length']), len(request_data)) - self.assertTrue(int(headers['content-length']) < 2000) - self.assertTrue(headers['content-type'].startswith('multipart/form-data')) - self.assertEqual(handler.command, 'POST') - self.assertNotIn('\n', headers['authorization']) - - def test_upload_docs(self): - path = os.path.join(self.tmp_dir, 'xxx') - self.write_file(path) - command, pyversion, filename = 'xxx', '2.6', path - dist_files = [(command, pyversion, filename)] - docs_path = os.path.join(self.tmp_dir, "build", "docs") - os.makedirs(docs_path) - self.write_file(os.path.join(docs_path, "index.html"), "yellow") - self.write_file(self.rc, PYPIRC) - - # lets run it - pkg_dir, dist = self.create_dist(dist_files=dist_files, author=u'dédé') - - cmd = upload(dist) - cmd.get_finalized_command("build").run() - cmd.upload_docs = True - cmd.ensure_finalized() - cmd.repository = self.pypi.full_address - try: - prev_dir = os.getcwd() - os.chdir(self.tmp_dir) - cmd.run() - finally: - os.chdir(prev_dir) - - handler, request_data = self.pypi.requests[-1] - action, name, content =\ - request_data.split("----------------GHSKFJDLGDS7543FJKLFHRE75642756743254")[1:4] - - self.assertIn('name=":action"', action) - self.assertIn("doc_upload", action) - -def test_suite(): - return unittest.makeSuite(UploadTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_upload_docs.py b/src/distutils2/tests/test_upload_docs.py deleted file mode 100644 index f7e323d..0000000 --- a/src/distutils2/tests/test_upload_docs.py +++ /dev/null @@ -1,201 +0,0 @@ -# -*- encoding: utf-8 -*- -"""Tests for distutils.command.upload_docs.""" -import os -import sys -import httplib -import shutil -import zipfile -try: - from cStringIO import StringIO -except ImportError: - from StringIO import StringIO - -from distutils2.command import upload_docs as upload_docs_mod -from distutils2.command.upload_docs import (upload_docs, zip_dir, - encode_multipart) -from distutils2.core import Distribution -from distutils2.errors import DistutilsFileError, DistutilsOptionError - -from distutils2.tests import support -from distutils2.tests.pypi_server import PyPIServer, PyPIServerTestCase -from distutils2.tests.support import unittest - - -EXPECTED_MULTIPART_OUTPUT = "\r\n".join([ -'---x', -'Content-Disposition: form-data; name="a"', -'', -'b', -'---x', -'Content-Disposition: form-data; name="c"', -'', -'d', -'---x', -'Content-Disposition: form-data; name="e"; filename="f"', -'', -'g', -'---x', -'Content-Disposition: form-data; name="h"; filename="i"', -'', -'j', -'---x--', -'', -]) - -PYPIRC = """\ -[distutils] -index-servers = server1 - -[server1] -repository = %s -username = real_slim_shady -password = long_island -""" - -class UploadDocsTestCase(support.TempdirManager, support.EnvironGuard, - support.LoggingCatcher, PyPIServerTestCase): - - def setUp(self): - super(UploadDocsTestCase, self).setUp() - self.tmp_dir = self.mkdtemp() - self.rc = os.path.join(self.tmp_dir, '.pypirc') - os.environ['HOME'] = self.tmp_dir - self.dist = Distribution() - self.dist.metadata['Name'] = "distr-name" - self.cmd = upload_docs(self.dist) - - def test_default_uploaddir(self): - sandbox = self.mkdtemp() - previous = os.getcwd() - os.chdir(sandbox) - try: - os.mkdir("build") - self.prepare_sample_dir("build") - self.cmd.ensure_finalized() - self.assertEqual(self.cmd.upload_dir, os.path.join("build", "docs")) - finally: - os.chdir(previous) - - def prepare_sample_dir(self, sample_dir=None): - if sample_dir is None: - sample_dir = self.mkdtemp() - os.mkdir(os.path.join(sample_dir, "docs")) - self.write_file(os.path.join(sample_dir, "docs", "index.html"), "Ce mortel ennui") - self.write_file(os.path.join(sample_dir, "index.html"), "Oh la la") - return sample_dir - - def test_zip_dir(self): - source_dir = self.prepare_sample_dir() - compressed = zip_dir(source_dir) - - zip_f = zipfile.ZipFile(compressed) - self.assertEqual(zip_f.namelist(), ['index.html', 'docs/index.html']) - - def test_encode_multipart(self): - fields = [("a", "b"), ("c", "d")] - files = [("e", "f", "g"), ("h", "i", "j")] - content_type, body = encode_multipart(fields, files, "-x") - self.assertEqual(content_type, "multipart/form-data; boundary=-x") - self.assertEqual(body, EXPECTED_MULTIPART_OUTPUT) - - def prepare_command(self): - self.cmd.upload_dir = self.prepare_sample_dir() - self.cmd.ensure_finalized() - self.cmd.repository = self.pypi.full_address - self.cmd.username = "username" - self.cmd.password = "password" - - def test_upload(self): - self.prepare_command() - self.cmd.run() - - self.assertEqual(len(self.pypi.requests), 1) - handler, request_data = self.pypi.requests[-1] - self.assertIn("content", request_data) - self.assertIn("Basic", handler.headers.dict['authorization']) - self.assertTrue(handler.headers.dict['content-type'] - .startswith('multipart/form-data;')) - - action, name, version, content =\ - request_data.split("----------------GHSKFJDLGDS7543FJKLFHRE75642756743254")[1:5] - - # check that we picked the right chunks - self.assertIn('name=":action"', action) - self.assertIn('name="name"', name) - self.assertIn('name="version"', version) - self.assertIn('name="content"', content) - - # check their contents - self.assertIn("doc_upload", action) - self.assertIn("distr-name", name) - self.assertIn("docs/index.html", content) - self.assertIn("Ce mortel ennui", content) - - def test_https_connection(self): - https_called = False - orig_https = upload_docs_mod.httplib.HTTPSConnection - def https_conn_wrapper(*args): - https_called = True - return upload_docs_mod.httplib.HTTPConnection(*args) # the testing server is http - upload_docs_mod.httplib.HTTPSConnection = https_conn_wrapper - try: - self.prepare_command() - self.cmd.run() - self.assertFalse(https_called) - - self.cmd.repository = self.cmd.repository.replace("http", "https") - self.cmd.run() - self.assertFalse(https_called) - finally: - upload_docs_mod.httplib.HTTPSConnection = orig_https - - def test_handling_response(self): - calls = [] - def aggr(*args): - calls.append(args) - self.pypi.default_response_status = '403 Forbidden' - self.prepare_command() - self.cmd.announce = aggr - self.cmd.run() - message, _ = calls[-1] - self.assertIn('Upload failed (403): Forbidden', message) - - calls = [] - self.pypi.default_response_status = '301 Moved Permanently' - self.pypi.default_response_headers.append(("Location", "brand_new_location")) - self.cmd.run() - message, _ = calls[-1] - self.assertIn('brand_new_location', message) - - def test_reads_pypirc_data(self): - self.write_file(self.rc, PYPIRC % self.pypi.full_address) - self.cmd.repository = self.pypi.full_address - self.cmd.upload_dir = self.prepare_sample_dir() - self.cmd.ensure_finalized() - self.assertEqual(self.cmd.username, "real_slim_shady") - self.assertEqual(self.cmd.password, "long_island") - - def test_checks_index_html_presence(self): - self.cmd.upload_dir = self.prepare_sample_dir() - os.remove(os.path.join(self.cmd.upload_dir, "index.html")) - self.assertRaises(DistutilsFileError, self.cmd.ensure_finalized) - - def test_checks_upload_dir(self): - self.cmd.upload_dir = self.prepare_sample_dir() - shutil.rmtree(os.path.join(self.cmd.upload_dir)) - self.assertRaises(DistutilsOptionError, self.cmd.ensure_finalized) - - def test_show_response(self): - self.prepare_command() - self.cmd.show_response = True - self.cmd.run() - record = self.logs[-1][1] - - self.assertTrue(record, "should report the response") - self.assertIn(self.pypi.default_response_data, record) - -def test_suite(): - return unittest.makeSuite(UploadDocsTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_util.py b/src/distutils2/tests/test_util.py deleted file mode 100644 index 0907433..0000000 --- a/src/distutils2/tests/test_util.py +++ /dev/null @@ -1,484 +0,0 @@ -"""Tests for distutils.util.""" -import os -import sys -from copy import copy -from StringIO import StringIO -import subprocess -import time - -from distutils2.tests import captured_stdout -from distutils2.tests.support import unittest -from distutils2.errors import (DistutilsPlatformError, - DistutilsByteCompileError, - DistutilsFileError, - DistutilsExecError) -from distutils2.util import (convert_path, change_root, - check_environ, split_quoted, strtobool, - rfc822_escape, get_compiler_versions, - _find_exe_version, _MAC_OS_X_LD_VERSION, - byte_compile, find_packages, spawn, find_executable, - _nt_quote_args, get_pypirc_path, generate_pypirc, - read_pypirc, resolve_name) - -from distutils2 import util -from distutils2.tests import support -from distutils2.tests.support import unittest - - -PYPIRC = """\ -[distutils] -index-servers = - pypi - server1 - -[pypi] -username:me -password:xxxx - -[server1] -repository:http://example.com -username:tarek -password:secret -""" - -PYPIRC_OLD = """\ -[server-login] -username:tarek -password:secret -""" - -WANTED = """\ -[distutils] -index-servers = - pypi - -[pypi] -username:tarek -password:xxx -""" - - -class FakePopen(object): - test_class = None - def __init__(self, cmd, shell, stdout, stderr): - self.cmd = cmd.split()[0] - exes = self.test_class._exes - if self.cmd not in exes: - # we don't want to call the system, returning an empty - # output so it doesn't match - self.stdout = StringIO() - self.stderr = StringIO() - else: - self.stdout = StringIO(exes[self.cmd]) - self.stderr = StringIO() - -class UtilTestCase(support.EnvironGuard, - support.TempdirManager, - support.LoggingCatcher, - unittest.TestCase): - - def setUp(self): - super(UtilTestCase, self).setUp() - self.tmp_dir = self.mkdtemp() - self.rc = os.path.join(self.tmp_dir, '.pypirc') - os.environ['HOME'] = self.tmp_dir - # saving the environment - self.name = os.name - self.platform = sys.platform - self.version = sys.version - self.sep = os.sep - self.join = os.path.join - self.isabs = os.path.isabs - self.splitdrive = os.path.splitdrive - #self._config_vars = copy(sysconfig._config_vars) - - # patching os.uname - if hasattr(os, 'uname'): - self.uname = os.uname - self._uname = os.uname() - else: - self.uname = None - self._uname = None - os.uname = self._get_uname - - # patching POpen - self.old_find_executable = util.find_executable - util.find_executable = self._find_executable - self._exes = {} - self.old_popen = subprocess.Popen - self.old_stdout = sys.stdout - self.old_stderr = sys.stderr - FakePopen.test_class = self - subprocess.Popen = FakePopen - - def tearDown(self): - # getting back the environment - os.name = self.name - sys.platform = self.platform - sys.version = self.version - os.sep = self.sep - os.path.join = self.join - os.path.isabs = self.isabs - os.path.splitdrive = self.splitdrive - if self.uname is not None: - os.uname = self.uname - else: - del os.uname - #sysconfig._config_vars = copy(self._config_vars) - util.find_executable = self.old_find_executable - subprocess.Popen = self.old_popen - sys.old_stdout = self.old_stdout - sys.old_stderr = self.old_stderr - super(UtilTestCase, self).tearDown() - - def _set_uname(self, uname): - self._uname = uname - - def _get_uname(self): - return self._uname - - def test_convert_path(self): - # linux/mac - os.sep = '/' - def _join(path): - return '/'.join(path) - os.path.join = _join - - self.assertEqual(convert_path('/home/to/my/stuff'), - '/home/to/my/stuff') - - # win - os.sep = '\\' - def _join(*path): - return '\\'.join(path) - os.path.join = _join - - self.assertRaises(ValueError, convert_path, '/home/to/my/stuff') - self.assertRaises(ValueError, convert_path, 'home/to/my/stuff/') - - self.assertEqual(convert_path('home/to/my/stuff'), - 'home\\to\\my\\stuff') - self.assertEqual(convert_path('.'), - os.curdir) - - def test_change_root(self): - # linux/mac - os.name = 'posix' - def _isabs(path): - return path[0] == '/' - os.path.isabs = _isabs - def _join(*path): - return '/'.join(path) - os.path.join = _join - - self.assertEqual(change_root('/root', '/old/its/here'), - '/root/old/its/here') - self.assertEqual(change_root('/root', 'its/here'), - '/root/its/here') - - # windows - os.name = 'nt' - def _isabs(path): - return path.startswith('c:\\') - os.path.isabs = _isabs - def _splitdrive(path): - if path.startswith('c:'): - return ('', path.replace('c:', '')) - return ('', path) - os.path.splitdrive = _splitdrive - def _join(*path): - return '\\'.join(path) - os.path.join = _join - - self.assertEqual(change_root('c:\\root', 'c:\\old\\its\\here'), - 'c:\\root\\old\\its\\here') - self.assertEqual(change_root('c:\\root', 'its\\here'), - 'c:\\root\\its\\here') - - # BugsBunny os (it's a great os) - os.name = 'BugsBunny' - self.assertRaises(DistutilsPlatformError, - change_root, 'c:\\root', 'its\\here') - - # XXX platforms to be covered: os2, mac - - def test_split_quoted(self): - self.assertEqual(split_quoted('""one"" "two" \'three\' \\four'), - ['one', 'two', 'three', 'four']) - - def test_strtobool(self): - yes = ('y', 'Y', 'yes', 'True', 't', 'true', 'True', 'On', 'on', '1') - no = ('n', 'no', 'f', 'false', 'off', '0', 'Off', 'No', 'N') - - for y in yes: - self.assertTrue(strtobool(y)) - - for n in no: - self.assertTrue(not strtobool(n)) - - def test_rfc822_escape(self): - header = 'I am a\npoor\nlonesome\nheader\n' - res = rfc822_escape(header) - wanted = ('I am a%(8s)spoor%(8s)slonesome%(8s)s' - 'header%(8s)s') % {'8s': '\n'+8*' '} - self.assertEqual(res, wanted) - - def test_find_exe_version(self): - # the ld version scheme under MAC OS is: - # ^@(#)PROGRAM:ld PROJECT:ld64-VERSION - # - # where VERSION is a 2-digit number for major - # revisions. For instance under Leopard, it's - # currently 77 - # - # Dots are used when branching is done. - # - # The SnowLeopard ld64 is currently 95.2.12 - - for output, version in (('@(#)PROGRAM:ld PROJECT:ld64-77', '77'), - ('@(#)PROGRAM:ld PROJECT:ld64-95.2.12', - '95.2.12')): - result = _MAC_OS_X_LD_VERSION.search(output) - self.assertEqual(result.group(1), version) - - def _find_executable(self, name): - if name in self._exes: - return name - return None - - def test_get_compiler_versions(self): - # get_versions calls distutils.spawn.find_executable on - # 'gcc', 'ld' and 'dllwrap' - self.assertEqual(get_compiler_versions(), (None, None, None)) - - # Let's fake we have 'gcc' and it returns '3.4.5' - self._exes['gcc'] = 'gcc (GCC) 3.4.5 (mingw special)\nFSF' - res = get_compiler_versions() - self.assertEqual(str(res[0]), '3.4.5') - - # and let's see what happens when the version - # doesn't match the regular expression - # (\d+\.\d+(\.\d+)*) - self._exes['gcc'] = 'very strange output' - res = get_compiler_versions() - self.assertEqual(res[0], None) - - # same thing for ld - if sys.platform != 'darwin': - self._exes['ld'] = 'GNU ld version 2.17.50 20060824' - res = get_compiler_versions() - self.assertEqual(str(res[1]), '2.17.50') - self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77' - res = get_compiler_versions() - self.assertEqual(res[1], None) - else: - self._exes['ld'] = 'GNU ld version 2.17.50 20060824' - res = get_compiler_versions() - self.assertEqual(res[1], None) - self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77' - res = get_compiler_versions() - self.assertEqual(str(res[1]), '77') - - # and dllwrap - self._exes['dllwrap'] = 'GNU dllwrap 2.17.50 20060824\nFSF' - res = get_compiler_versions() - self.assertEqual(str(res[2]), '2.17.50') - self._exes['dllwrap'] = 'Cheese Wrap' - res = get_compiler_versions() - self.assertEqual(res[2], None) - - @unittest.skipUnless(hasattr(sys, 'dont_write_bytecode'), - 'sys.dont_write_bytecode not supported') - def test_dont_write_bytecode(self): - # makes sure byte_compile raise a DistutilsError - # if sys.dont_write_bytecode is True - old_dont_write_bytecode = sys.dont_write_bytecode - sys.dont_write_bytecode = True - try: - self.assertRaises(DistutilsByteCompileError, byte_compile, []) - finally: - sys.dont_write_bytecode = old_dont_write_bytecode - - def test_newer(self): - self.assertRaises(DistutilsFileError, util.newer, 'xxx', 'xxx') - self.newer_f1 = self.mktempfile() - time.sleep(1) - self.newer_f2 = self.mktempfile() - self.assertTrue(util.newer(self.newer_f2.name, self.newer_f1.name)) - - def test_find_packages(self): - # let's create a structure we want to scan: - # - # pkg1 - # __init__ - # pkg2 - # __init__ - # pkg3 - # __init__ - # pkg6 - # __init__ - # pkg4 <--- not a pkg - # pkg8 - # __init__ - # pkg5 - # __init__ - # - root = self.mkdtemp() - pkg1 = os.path.join(root, 'pkg1') - os.mkdir(pkg1) - self.write_file(os.path.join(pkg1, '__init__.py')) - os.mkdir(os.path.join(pkg1, 'pkg2')) - self.write_file(os.path.join(pkg1, 'pkg2', '__init__.py')) - os.mkdir(os.path.join(pkg1, 'pkg3')) - self.write_file(os.path.join(pkg1, 'pkg3', '__init__.py')) - os.mkdir(os.path.join(pkg1, 'pkg3', 'pkg6')) - self.write_file(os.path.join(pkg1, 'pkg3', 'pkg6', '__init__.py')) - os.mkdir(os.path.join(pkg1, 'pkg4')) - os.mkdir(os.path.join(pkg1, 'pkg4', 'pkg8')) - self.write_file(os.path.join(pkg1, 'pkg4', 'pkg8', '__init__.py')) - pkg5 = os.path.join(root, 'pkg5') - os.mkdir(pkg5) - self.write_file(os.path.join(pkg5, '__init__.py')) - - res = find_packages([root], ['pkg1.pkg2']) - self.assertEqual(set(res), set(['pkg1', 'pkg5', 'pkg1.pkg3', 'pkg1.pkg3.pkg6'])) - - def test_resolve_name(self): - self.assertEqual(str(42), resolve_name('__builtin__.str')(42)) - self.assertEqual( - UtilTestCase.__name__, - resolve_name("distutils2.tests.test_util.UtilTestCase").__name__) - self.assertEqual( - UtilTestCase.test_resolve_name.__name__, - resolve_name("distutils2.tests.test_util.UtilTestCase.test_resolve_name").__name__) - - self.assertRaises(ImportError, resolve_name, - "distutils2.tests.test_util.UtilTestCaseNot") - self.assertRaises(ImportError, resolve_name, - "distutils2.tests.test_util.UtilTestCase.nonexistent_attribute") - - def test_import_nested_first_time(self): - tmp_dir = self.mkdtemp() - os.makedirs(os.path.join(tmp_dir, 'a', 'b')) - self.write_file(os.path.join(tmp_dir, 'a', '__init__.py'), '') - self.write_file(os.path.join(tmp_dir, 'a', 'b', '__init__.py'), '') - self.write_file(os.path.join(tmp_dir, 'a', 'b', 'c.py'), 'class Foo: pass') - - try: - sys.path.append(tmp_dir) - resolve_name("a.b.c.Foo") - # assert nothing raised - finally: - sys.path.remove(tmp_dir) - - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_run_2to3_on_code(self): - content = "print 'test'" - converted_content = "print('test')" - file_handle = self.mktempfile() - file_name = file_handle.name - file_handle.write(content) - file_handle.flush() - file_handle.seek(0) - from distutils2.util import run_2to3 - run_2to3([file_name]) - new_content = "".join(file_handle.read()) - file_handle.close() - self.assertEquals(new_content, converted_content) - - @unittest.skipIf(sys.version < '2.6', 'requires Python 2.6 or higher') - def test_run_2to3_on_doctests(self): - # to check if text files containing doctests only get converted. - content = ">>> print 'test'\ntest\n" - converted_content = ">>> print('test')\ntest\n\n" - file_handle = self.mktempfile() - file_name = file_handle.name - file_handle.write(content) - file_handle.flush() - file_handle.seek(0) - from distutils2.util import run_2to3 - run_2to3([file_name], doctests_only=True) - new_content = "".join(file_handle.readlines()) - file_handle.close() - self.assertEquals(new_content, converted_content) - - def test_nt_quote_args(self): - - for (args, wanted) in ((['with space', 'nospace'], - ['"with space"', 'nospace']), - (['nochange', 'nospace'], - ['nochange', 'nospace'])): - res = _nt_quote_args(args) - self.assertEqual(res, wanted) - - - @unittest.skipUnless(os.name in ('nt', 'posix'), - 'runs only under posix or nt') - def test_spawn(self): - tmpdir = self.mkdtemp() - - # creating something executable - # through the shell that returns 1 - if os.name == 'posix': - exe = os.path.join(tmpdir, 'foo.sh') - self.write_file(exe, '#!/bin/sh\nexit 1') - os.chmod(exe, 0777) - else: - exe = os.path.join(tmpdir, 'foo.bat') - self.write_file(exe, 'exit 1') - - os.chmod(exe, 0777) - self.assertRaises(DistutilsExecError, spawn, [exe]) - - # now something that works - if os.name == 'posix': - exe = os.path.join(tmpdir, 'foo.sh') - self.write_file(exe, '#!/bin/sh\nexit 0') - os.chmod(exe, 0777) - else: - exe = os.path.join(tmpdir, 'foo.bat') - self.write_file(exe, 'exit 0') - - os.chmod(exe, 0777) - spawn([exe]) # should work without any error - - def test_server_registration(self): - # This test makes sure we know how to: - # 1. handle several sections in .pypirc - # 2. handle the old format - - # new format - self.write_file(self.rc, PYPIRC) - config = read_pypirc() - - config = config.items() - config.sort() - expected = [('password', 'xxxx'), ('realm', 'pypi'), - ('repository', 'http://pypi.python.org/pypi'), - ('server', 'pypi'), ('username', 'me')] - self.assertEqual(config, expected) - - # old format - self.write_file(self.rc, PYPIRC_OLD) - config = read_pypirc() - config = config.items() - config.sort() - expected = [('password', 'secret'), ('realm', 'pypi'), - ('repository', 'http://pypi.python.org/pypi'), - ('server', 'server-login'), ('username', 'tarek')] - self.assertEqual(config, expected) - - def test_server_empty_registration(self): - rc = get_pypirc_path() - self.assertTrue(not os.path.exists(rc)) - generate_pypirc('tarek', 'xxx') - self.assertTrue(os.path.exists(rc)) - content = open(rc).read() - self.assertEqual(content, WANTED) - - -def test_suite(): - return unittest.makeSuite(UtilTestCase) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/test_version.py b/src/distutils2/tests/test_version.py deleted file mode 100644 index 1e392f2..0000000 --- a/src/distutils2/tests/test_version.py +++ /dev/null @@ -1,226 +0,0 @@ -"""Tests for distutils.version.""" -import doctest -import os - -from distutils2.version import NormalizedVersion as V -from distutils2.version import HugeMajorVersionNumError, IrrationalVersionError -from distutils2.version import suggest_normalized_version as suggest -from distutils2.version import VersionPredicate -from distutils2.tests.support import unittest - -class VersionTestCase(unittest.TestCase): - - versions = ((V('1.0'), '1.0'), - (V('1.1'), '1.1'), - (V('1.2.3'), '1.2.3'), - (V('1.2'), '1.2'), - (V('1.2.3a4'), '1.2.3a4'), - (V('1.2c4'), '1.2c4'), - (V('1.2.3.4'), '1.2.3.4'), - (V('1.2.3.4.0b3'), '1.2.3.4b3'), - (V('1.2.0.0.0'), '1.2'), - (V('1.0.dev345'), '1.0.dev345'), - (V('1.0.post456.dev623'), '1.0.post456.dev623')) - - def test_repr(self): - - self.assertEqual(repr(V('1.0')), "NormalizedVersion('1.0')") - - def test_basic_versions(self): - - for v, s in self.versions: - self.assertEqual(str(v), s) - - def test_from_parts(self): - - for v, s in self.versions: - parts = v.parts - v2 = V.from_parts(*v.parts) - self.assertEqual(v, v2) - self.assertEqual(str(v), str(v2)) - - def test_irrational_versions(self): - - irrational = ('1', '1.2a', '1.2.3b', '1.02', '1.2a03', - '1.2a3.04', '1.2.dev.2', '1.2dev', '1.2.dev', - '1.2.dev2.post2', '1.2.post2.dev3.post4') - - for s in irrational: - self.assertRaises(IrrationalVersionError, V, s) - - def test_huge_version(self): - - self.assertEquals(str(V('1980.0')), '1980.0') - self.assertRaises(HugeMajorVersionNumError, V, '1981.0') - self.assertEquals(str(V('1981.0', error_on_huge_major_num=False)), '1981.0') - - def test_comparison(self): - r""" - >>> V('1.2.0') == '1.2' - Traceback (most recent call last): - ... - TypeError: cannot compare NormalizedVersion and str - - >>> V('1.2') < '1.3' - Traceback (most recent call last): - ... - TypeError: cannot compare NormalizedVersion and str - - >>> V('1.2.0') == V('1.2') - True - >>> V('1.2.0') == V('1.2.3') - False - >>> V('1.2.0') != V('1.2.3') - True - >>> V('1.2.0') < V('1.2.3') - True - >>> V('1.2.0') < V('1.2.0') - False - >>> V('1.2.0') <= V('1.2.0') - True - >>> V('1.2.0') <= V('1.2.3') - True - >>> V('1.2.3') <= V('1.2.0') - False - >>> V('1.2.0') >= V('1.2.0') - True - >>> V('1.2.3') >= V('1.2.0') - True - >>> V('1.2.0') >= V('1.2.3') - False - >>> (V('1.0') > V('1.0b2')) - True - >>> (V('1.0') > V('1.0c2') > V('1.0c1') > V('1.0b2') > V('1.0b1') - ... > V('1.0a2') > V('1.0a1')) - True - >>> (V('1.0.0') > V('1.0.0c2') > V('1.0.0c1') > V('1.0.0b2') > V('1.0.0b1') - ... > V('1.0.0a2') > V('1.0.0a1')) - True - - >>> V('1.0') < V('1.0.post456.dev623') - True - - >>> V('1.0.post456.dev623') < V('1.0.post456') < V('1.0.post1234') - True - - >>> (V('1.0a1') - ... < V('1.0a2.dev456') - ... < V('1.0a2') - ... < V('1.0a2.1.dev456') # e.g. need to do a quick post release on 1.0a2 - ... < V('1.0a2.1') - ... < V('1.0b1.dev456') - ... < V('1.0b2') - ... < V('1.0c1.dev456') - ... < V('1.0c1') - ... < V('1.0.dev7') - ... < V('1.0.dev18') - ... < V('1.0.dev456') - ... < V('1.0.dev1234') - ... < V('1.0') - ... < V('1.0.post456.dev623') # development version of a post release - ... < V('1.0.post456')) - True - """ - # must be a simpler way to call the docstrings - doctest.run_docstring_examples(self.test_comparison, globals(), - name='test_comparison') - - def test_suggest_normalized_version(self): - - self.assertEqual(suggest('1.0'), '1.0') - self.assertEqual(suggest('1.0-alpha1'), '1.0a1') - self.assertEqual(suggest('1.0c2'), '1.0c2') - self.assertEqual(suggest('walla walla washington'), None) - self.assertEqual(suggest('2.4c1'), '2.4c1') - self.assertEqual(suggest('v1.0'), '1.0') - - # from setuptools - self.assertEqual(suggest('0.4a1.r10'), '0.4a1.post10') - self.assertEqual(suggest('0.7a1dev-r66608'), '0.7a1.dev66608') - self.assertEqual(suggest('0.6a9.dev-r41475'), '0.6a9.dev41475') - self.assertEqual(suggest('2.4preview1'), '2.4c1') - self.assertEqual(suggest('2.4pre1') , '2.4c1') - self.assertEqual(suggest('2.1-rc2'), '2.1c2') - - # from pypi - self.assertEqual(suggest('0.1dev'), '0.1.dev0') - self.assertEqual(suggest('0.1.dev'), '0.1.dev0') - - # we want to be able to parse Twisted - # development versions are like post releases in Twisted - self.assertEqual(suggest('9.0.0+r2363'), '9.0.0.post2363') - - # pre-releases are using markers like "pre1" - self.assertEqual(suggest('9.0.0pre1'), '9.0.0c1') - - # we want to be able to parse Tcl-TK - # they us "p1" "p2" for post releases - self.assertEqual(suggest('1.4p1'), '1.4.post1') - - def test_predicate(self): - # VersionPredicate knows how to parse stuff like: - # - # Project (>=version, ver2) - - predicates = ('zope.interface (>3.5.0)', - 'AnotherProject (3.4)', - 'OtherProject (<3.0)', - 'NoVersion', - 'Hey (>=2.5,<2.7)') - - for predicate in predicates: - v = VersionPredicate(predicate) - - self.assertTrue(VersionPredicate('Hey (>=2.5,<2.7)').match('2.6')) - self.assertTrue(VersionPredicate('Ho').match('2.6')) - self.assertFalse(VersionPredicate('Hey (>=2.5,!=2.6,<2.7)').match('2.6')) - self.assertTrue(VersionPredicate('Ho (<3.0)').match('2.6')) - self.assertTrue(VersionPredicate('Ho (<3.0,!=2.5)').match('2.6.0')) - self.assertFalse(VersionPredicate('Ho (<3.0,!=2.6)').match('2.6.0')) - self.assertTrue(VersionPredicate('Ho (2.5)').match('2.5.4')) - self.assertFalse(VersionPredicate('Ho (!=2.5)').match('2.5.2')) - self.assertTrue(VersionPredicate('Hey (<=2.5)').match('2.5.9')) - self.assertFalse(VersionPredicate('Hey (<=2.5)').match('2.6.0')) - self.assertTrue(VersionPredicate('Hey (>=2.5)').match('2.5.1')) - - self.assertRaises(ValueError, VersionPredicate, '') - - # XXX need to silent the micro version in this case - #assert not VersionPredicate('Ho (<3.0,!=2.6)').match('2.6.3') - - def test_predicate_name(self): - # Test that names are parsed the right way - - self.assertEqual('Hey', VersionPredicate('Hey (<1.1)').name) - self.assertEqual('Foo-Bar', VersionPredicate('Foo-Bar (1.1)').name) - self.assertEqual('Foo Bar', VersionPredicate('Foo Bar (1.1)').name) - - def test_is_final(self): - # VersionPredicate knows is a distribution is a final one or not. - final_versions = ('1.0', '1.0.post456') - other_versions = ('1.0.dev1', '1.0a2', '1.0c3') - - for version in final_versions: - self.assertTrue(V(version).is_final) - for version in other_versions: - self.assertFalse(V(version).is_final) - -class VersionWhiteBoxTestCase(unittest.TestCase): - - def test_parse_numdots(self): - # For code coverage completeness, as pad_zeros_length can't be set or - # influenced from the public interface - self.assertEquals(V('1.0')._parse_numdots('1.0', '1.0', - pad_zeros_length=3), - [1, 0, 0]) - - -def test_suite(): - #README = os.path.join(os.path.dirname(__file__), 'README.txt') - #suite = [doctest.DocFileSuite(README), unittest.makeSuite(VersionTestCase)] - suite = [unittest.makeSuite(VersionTestCase), - unittest.makeSuite(VersionWhiteBoxTestCase)] - return unittest.TestSuite(suite) - -if __name__ == "__main__": - unittest.main(defaultTest="test_suite") diff --git a/src/distutils2/tests/xxmodule.c b/src/distutils2/tests/xxmodule.c deleted file mode 100644 index 6b498dd..0000000 --- a/src/distutils2/tests/xxmodule.c +++ /dev/null @@ -1,379 +0,0 @@ - -/* Use this file as a template to start implementing a module that - also declares object types. All occurrences of 'Xxo' should be changed - to something reasonable for your objects. After that, all other - occurrences of 'xx' should be changed to something reasonable for your - module. If your module is named foo your sourcefile should be named - foomodule.c. - - You will probably want to delete all references to 'x_attr' and add - your own types of attributes instead. Maybe you want to name your - local variables other than 'self'. If your object type is needed in - other files, you'll have to create a file "foobarobject.h"; see - intobject.h for an example. */ - -/* Xxo objects */ - -#include "Python.h" - -static PyObject *ErrorObject; - -typedef struct { - PyObject_HEAD - PyObject *x_attr; /* Attributes dictionary */ -} XxoObject; - -static PyTypeObject Xxo_Type; - -#define XxoObject_Check(v) (Py_TYPE(v) == &Xxo_Type) - -static XxoObject * -newXxoObject(PyObject *arg) -{ - XxoObject *self; - self = PyObject_New(XxoObject, &Xxo_Type); - if (self == NULL) - return NULL; - self->x_attr = NULL; - return self; -} - -/* Xxo methods */ - -static void -Xxo_dealloc(XxoObject *self) -{ - Py_XDECREF(self->x_attr); - PyObject_Del(self); -} - -static PyObject * -Xxo_demo(XxoObject *self, PyObject *args) -{ - if (!PyArg_ParseTuple(args, ":demo")) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef Xxo_methods[] = { - {"demo", (PyCFunction)Xxo_demo, METH_VARARGS, - PyDoc_STR("demo() -> None")}, - {NULL, NULL} /* sentinel */ -}; - -static PyObject * -Xxo_getattr(XxoObject *self, char *name) -{ - if (self->x_attr != NULL) { - PyObject *v = PyDict_GetItemString(self->x_attr, name); - if (v != NULL) { - Py_INCREF(v); - return v; - } - } - return Py_FindMethod(Xxo_methods, (PyObject *)self, name); -} - -static int -Xxo_setattr(XxoObject *self, char *name, PyObject *v) -{ - if (self->x_attr == NULL) { - self->x_attr = PyDict_New(); - if (self->x_attr == NULL) - return -1; - } - if (v == NULL) { - int rv = PyDict_DelItemString(self->x_attr, name); - if (rv < 0) - PyErr_SetString(PyExc_AttributeError, - "delete non-existing Xxo attribute"); - return rv; - } - else - return PyDict_SetItemString(self->x_attr, name, v); -} - -static PyTypeObject Xxo_Type = { - /* The ob_type field must be initialized in the module init function - * to be portable to Windows without using C++. */ - PyVarObject_HEAD_INIT(NULL, 0) - "xxmodule.Xxo", /*tp_name*/ - sizeof(XxoObject), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)Xxo_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - (getattrfunc)Xxo_getattr, /*tp_getattr*/ - (setattrfunc)Xxo_setattr, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - 0, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ -}; -/* --------------------------------------------------------------------- */ - -/* Function of two integers returning integer */ - -PyDoc_STRVAR(xx_foo_doc, -"foo(i,j)\n\ -\n\ -Return the sum of i and j."); - -static PyObject * -xx_foo(PyObject *self, PyObject *args) -{ - long i, j; - long res; - if (!PyArg_ParseTuple(args, "ll:foo", &i, &j)) - return NULL; - res = i+j; /* XXX Do something here */ - return PyInt_FromLong(res); -} - - -/* Function of no arguments returning new Xxo object */ - -static PyObject * -xx_new(PyObject *self, PyObject *args) -{ - XxoObject *rv; - - if (!PyArg_ParseTuple(args, ":new")) - return NULL; - rv = newXxoObject(args); - if (rv == NULL) - return NULL; - return (PyObject *)rv; -} - -/* Example with subtle bug from extensions manual ("Thin Ice"). */ - -static PyObject * -xx_bug(PyObject *self, PyObject *args) -{ - PyObject *list, *item; - - if (!PyArg_ParseTuple(args, "O:bug", &list)) - return NULL; - - item = PyList_GetItem(list, 0); - /* Py_INCREF(item); */ - PyList_SetItem(list, 1, PyInt_FromLong(0L)); - PyObject_Print(item, stdout, 0); - printf("\n"); - /* Py_DECREF(item); */ - - Py_INCREF(Py_None); - return Py_None; -} - -/* Test bad format character */ - -static PyObject * -xx_roj(PyObject *self, PyObject *args) -{ - PyObject *a; - long b; - if (!PyArg_ParseTuple(args, "O#:roj", &a, &b)) - return NULL; - Py_INCREF(Py_None); - return Py_None; -} - - -/* ---------- */ - -static PyTypeObject Str_Type = { - /* The ob_type field must be initialized in the module init function - * to be portable to Windows without using C++. */ - PyVarObject_HEAD_INIT(NULL, 0) - "xxmodule.Str", /*tp_name*/ - 0, /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /* see initxx */ /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - 0, /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ -}; - -/* ---------- */ - -static PyObject * -null_richcompare(PyObject *self, PyObject *other, int op) -{ - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; -} - -static PyTypeObject Null_Type = { - /* The ob_type field must be initialized in the module init function - * to be portable to Windows without using C++. */ - PyVarObject_HEAD_INIT(NULL, 0) - "xxmodule.Null", /*tp_name*/ - 0, /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash*/ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - null_richcompare, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - 0, /*tp_methods*/ - 0, /*tp_members*/ - 0, /*tp_getset*/ - 0, /* see initxx */ /*tp_base*/ - 0, /*tp_dict*/ - 0, /*tp_descr_get*/ - 0, /*tp_descr_set*/ - 0, /*tp_dictoffset*/ - 0, /*tp_init*/ - 0, /*tp_alloc*/ - 0, /* see initxx */ /*tp_new*/ - 0, /*tp_free*/ - 0, /*tp_is_gc*/ -}; - - -/* ---------- */ - - -/* List of functions defined in the module */ - -static PyMethodDef xx_methods[] = { - {"roj", xx_roj, METH_VARARGS, - PyDoc_STR("roj(a,b) -> None")}, - {"foo", xx_foo, METH_VARARGS, - xx_foo_doc}, - {"new", xx_new, METH_VARARGS, - PyDoc_STR("new() -> new Xx object")}, - {"bug", xx_bug, METH_VARARGS, - PyDoc_STR("bug(o) -> None")}, - {NULL, NULL} /* sentinel */ -}; - -PyDoc_STRVAR(module_doc, -"This is a template module just for instruction."); - -/* Initialization function for the module (*must* be called initxx) */ - -PyMODINIT_FUNC -initxx(void) -{ - PyObject *m; - - /* Due to cross platform compiler issues the slots must be filled - * here. It's required for portability to Windows without requiring - * C++. */ - Null_Type.tp_base = &PyBaseObject_Type; - Null_Type.tp_new = PyType_GenericNew; - Str_Type.tp_base = &PyUnicode_Type; - - /* Finalize the type object including setting type of the new type - * object; doing it here is required for portability, too. */ - if (PyType_Ready(&Xxo_Type) < 0) - return; - - /* Create the module and add the functions */ - m = Py_InitModule3("xx", xx_methods, module_doc); - if (m == NULL) - return; - - /* Add some symbolic constants to the module */ - if (ErrorObject == NULL) { - ErrorObject = PyErr_NewException("xx.error", NULL, NULL); - if (ErrorObject == NULL) - return; - } - Py_INCREF(ErrorObject); - PyModule_AddObject(m, "error", ErrorObject); - - /* Add Str */ - if (PyType_Ready(&Str_Type) < 0) - return; - PyModule_AddObject(m, "Str", (PyObject *)&Str_Type); - - /* Add Null */ - if (PyType_Ready(&Null_Type) < 0) - return; - PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); -} diff --git a/src/distutils2/util.py b/src/distutils2/util.py deleted file mode 100644 index 12b1022..0000000 --- a/src/distutils2/util.py +++ /dev/null @@ -1,1129 +0,0 @@ -"""distutils.util - -Miscellaneous utility functions. -""" - -__revision__ = "$Id: util.py 77761 2010-01-26 22:46:15Z tarek.ziade $" - -import os -import posixpath -import re -import string -import sys -import shutil -import tarfile -import zipfile -from copy import copy -from fnmatch import fnmatchcase -from ConfigParser import RawConfigParser - -from distutils2.errors import (DistutilsPlatformError, DistutilsFileError, - DistutilsByteCompileError, DistutilsExecError) -from distutils2 import log -from distutils2._backport import sysconfig as _sysconfig - -_PLATFORM = None - - -def newer(source, target): - """Tells if the target is newer than the source. - - Return true if 'source' exists and is more recently modified than - 'target', or if 'source' exists and 'target' doesn't. - - Return false if both exist and 'target' is the same age or younger - than 'source'. Raise DistutilsFileError if 'source' does not exist. - - Note that this test is not very accurate: files created in the same second - will have the same "age". - """ - if not os.path.exists(source): - raise DistutilsFileError("file '%s' does not exist" % - os.path.abspath(source)) - if not os.path.exists(target): - return True - - return os.stat(source).st_mtime > os.stat(target).st_mtime - - -def get_platform(): - """Return a string that identifies the current platform. - - By default, will return the value returned by sysconfig.get_platform(), - but it can be changed by calling set_platform(). - """ - global _PLATFORM - if _PLATFORM is None: - _PLATFORM = _sysconfig.get_platform() - return _PLATFORM - - -def set_platform(identifier): - """Sets the platform string identifier returned by get_platform(). - - Note that this change doesn't impact the value returned by - sysconfig.get_platform() and is local to Distutils - """ - global _PLATFORM - _PLATFORM = identifier - - -def convert_path(pathname): - """Return 'pathname' as a name that will work on the native filesystem. - - i.e. split it on '/' and put it back together again using the current - directory separator. Needed because filenames in the setup script are - always supplied in Unix style, and have to be converted to the local - convention before we can actually use them in the filesystem. Raises - ValueError on non-Unix-ish systems if 'pathname' either starts or - ends with a slash. - """ - if os.sep == '/': - return pathname - if not pathname: - return pathname - if pathname[0] == '/': - raise ValueError("path '%s' cannot be absolute" % pathname) - if pathname[-1] == '/': - raise ValueError("path '%s' cannot end with '/'" % pathname) - - paths = pathname.split('/') - while os.curdir in paths: - paths.remove(os.curdir) - if not paths: - return os.curdir - return os.path.join(*paths) - - -def change_root(new_root, pathname): - """Return 'pathname' with 'new_root' prepended. - - If 'pathname' is relative, this is equivalent to - "os.path.join(new_root,pathname)". - Otherwise, it requires making 'pathname' relative and then joining the - two, which is tricky on DOS/Windows and Mac OS. - """ - if os.name == 'posix': - if not os.path.isabs(pathname): - return os.path.join(new_root, pathname) - else: - return os.path.join(new_root, pathname[1:]) - - elif os.name == 'nt': - (drive, path) = os.path.splitdrive(pathname) - if path[0] == '\\': - path = path[1:] - return os.path.join(new_root, path) - - elif os.name == 'os2': - (drive, path) = os.path.splitdrive(pathname) - if path[0] == os.sep: - path = path[1:] - return os.path.join(new_root, path) - - else: - raise DistutilsPlatformError("nothing known about " - "platform '%s'" % os.name) - -_environ_checked = 0 - - -def check_environ(): - """Ensure that 'os.environ' has all the environment variables needed. - - We guarantee that users can use in config files, command-line options, - etc. Currently this includes: - HOME - user's home directory (Unix only) - PLAT - description of the current platform, including hardware - and OS (see 'get_platform()') - """ - global _environ_checked - if _environ_checked: - return - - if os.name == 'posix' and 'HOME' not in os.environ: - import pwd - os.environ['HOME'] = pwd.getpwuid(os.getuid())[5] - - if 'PLAT' not in os.environ: - os.environ['PLAT'] = _sysconfig.get_platform() - - _environ_checked = 1 - - -def subst_vars(s, local_vars): - """Perform shell/Perl-style variable substitution on 'string'. - - Every occurrence of '$' followed by a name is considered a variable, and - variable is substituted by the value found in the 'local_vars' - dictionary, or in 'os.environ' if it's not in 'local_vars'. - 'os.environ' is first checked/augmented to guarantee that it contains - certain values: see 'check_environ()'. Raise ValueError for any - variables not found in either 'local_vars' or 'os.environ'. - """ - check_environ() - - def _subst(match, local_vars=local_vars): - var_name = match.group(1) - if var_name in local_vars: - return str(local_vars[var_name]) - else: - return os.environ[var_name] - - try: - return re.sub(r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, s) - except KeyError, var: - raise ValueError("invalid variable '$%s'" % var) - - -def grok_environment_error(exc, prefix="error: "): - """Generate a useful error message from an EnvironmentError. - - This will generate an IOError or an OSError exception object. - Handles Python 1.5.1 and 1.5.2 styles, and - does what it can to deal with exception objects that don't have a - filename (which happens when the error is due to a two-file operation, - such as 'rename()' or 'link()'. Returns the error message as a string - prefixed with 'prefix'. - """ - # check for Python 1.5.2-style {IO,OS}Error exception objects - if hasattr(exc, 'filename') and hasattr(exc, 'strerror'): - if exc.filename: - error = prefix + "%s: %s" % (exc.filename, exc.strerror) - else: - # two-argument functions in posix module don't - # include the filename in the exception object! - error = prefix + "%s" % exc.strerror - else: - error = prefix + str(exc[-1]) - - return error - -# Needed by 'split_quoted()' -_wordchars_re = _squote_re = _dquote_re = None - - -def _init_regex(): - global _wordchars_re, _squote_re, _dquote_re - _wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace) - _squote_re = re.compile(r"'(?:[^'\\]|\\.)*'") - _dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"') - - -def split_quoted(s): - """Split a string up according to Unix shell-like rules for quotes and - backslashes. - - In short: words are delimited by spaces, as long as those - spaces are not escaped by a backslash, or inside a quoted string. - Single and double quotes are equivalent, and the quote characters can - be backslash-escaped. The backslash is stripped from any two-character - escape sequence, leaving only the escaped character. The quote - characters are stripped from any quoted string. Returns a list of - words. - """ - # This is a nice algorithm for splitting up a single string, since it - # doesn't require character-by-character examination. It was a little - # bit of a brain-bender to get it working right, though... - if _wordchars_re is None: - _init_regex() - - s = s.strip() - words = [] - pos = 0 - - while s: - m = _wordchars_re.match(s, pos) - end = m.end() - if end == len(s): - words.append(s[:end]) - break - - if s[end] in string.whitespace: # unescaped, unquoted whitespace: now - words.append(s[:end]) # we definitely have a word delimiter - s = s[end:].lstrip() - pos = 0 - - elif s[end] == '\\': # preserve whatever is being escaped; - # will become part of the current word - s = s[:end] + s[end + 1:] - pos = end + 1 - - else: - if s[end] == "'": # slurp singly-quoted string - m = _squote_re.match(s, end) - elif s[end] == '"': # slurp doubly-quoted string - m = _dquote_re.match(s, end) - else: - raise RuntimeError("this can't happen " - "(bad char '%c')" % s[end]) - - if m is None: - raise ValueError("bad string (mismatched %s quotes?)" % s[end]) - - (beg, end) = m.span() - s = s[:beg] + s[beg + 1:end - 1] + s[end:] - pos = m.end() - 2 - - if pos >= len(s): - words.append(s) - break - - return words - - -def execute(func, args, msg=None, verbose=0, dry_run=0): - """Perform some action that affects the outside world. - - eg. by writing to the filesystem). Such actions are special because - they are disabled by the 'dry_run' flag. This method takes care of all - that bureaucracy for you; all you have to do is supply the - function to call and an argument tuple for it (to embody the - "external action" being performed), and an optional message to - print. - """ - if msg is None: - msg = "%s%r" % (func.__name__, args) - if msg[-2:] == ',)': # correct for singleton tuple - msg = msg[0:-2] + ')' - - log.info(msg) - if not dry_run: - func(*args) - - -def strtobool(val): - """Convert a string representation of truth to true (1) or false (0). - - True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values - are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if - 'val' is anything else. - """ - val = val.lower() - if val in ('y', 'yes', 't', 'true', 'on', '1'): - return 1 - elif val in ('n', 'no', 'f', 'false', 'off', '0'): - return 0 - else: - raise ValueError("invalid truth value %r" % (val,)) - - -def byte_compile(py_files, optimize=0, force=0, prefix=None, base_dir=None, - verbose=1, dry_run=0, direct=None): - """Byte-compile a collection of Python source files to either .pyc - or .pyo files in the same directory. - - 'py_files' is a list of files to compile; any files that don't end in - ".py" are silently skipped. 'optimize' must be one of the following: - 0 - don't optimize (generate .pyc) - 1 - normal optimization (like "python -O") - 2 - extra optimization (like "python -OO") - If 'force' is true, all files are recompiled regardless of - timestamps. - - The source filename encoded in each bytecode file defaults to the - filenames listed in 'py_files'; you can modify these with 'prefix' and - 'basedir'. 'prefix' is a string that will be stripped off of each - source filename, and 'base_dir' is a directory name that will be - prepended (after 'prefix' is stripped). You can supply either or both - (or neither) of 'prefix' and 'base_dir', as you wish. - - If 'dry_run' is true, doesn't actually do anything that would - affect the filesystem. - - Byte-compilation is either done directly in this interpreter process - with the standard py_compile module, or indirectly by writing a - temporary script and executing it. Normally, you should let - 'byte_compile()' figure out to use direct compilation or not (see - the source for details). The 'direct' flag is used by the script - generated in indirect mode; unless you know what you're doing, leave - it set to None. - """ - # nothing is done if sys.dont_write_bytecode is True - if hasattr(sys, 'dont_write_bytecode') and sys.dont_write_bytecode: - raise DistutilsByteCompileError('byte-compiling is disabled.') - - # First, if the caller didn't force us into direct or indirect mode, - # figure out which mode we should be in. We take a conservative - # approach: choose direct mode *only* if the current interpreter is - # in debug mode and optimize is 0. If we're not in debug mode (-O - # or -OO), we don't know which level of optimization this - # interpreter is running with, so we can't do direct - # byte-compilation and be certain that it's the right thing. Thus, - # always compile indirectly if the current interpreter is in either - # optimize mode, or if either optimization level was requested by - # the caller. - if direct is None: - direct = (__debug__ and optimize == 0) - - # "Indirect" byte-compilation: write a temporary script and then - # run it with the appropriate flags. - if not direct: - from tempfile import mkstemp - script_fd, script_name = mkstemp(".py") - log.info("writing byte-compilation script '%s'", script_name) - if not dry_run: - if script_fd is not None: - script = os.fdopen(script_fd, "w") - else: - script = open(script_name, "w") - - try: - script.write("""\ -from distutils2.util import byte_compile -files = [ -""") - - # XXX would be nice to write absolute filenames, just for - # safety's sake (script should be more robust in the face of - # chdir'ing before running it). But this requires abspath'ing - # 'prefix' as well, and that breaks the hack in build_lib's - # 'byte_compile()' method that carefully tacks on a trailing - # slash (os.sep really) to make sure the prefix here is "just - # right". This whole prefix business is rather delicate -- the - # problem is that it's really a directory, but I'm treating it - # as a dumb string, so trailing slashes and so forth matter. - - #py_files = map(os.path.abspath, py_files) - #if prefix: - # prefix = os.path.abspath(prefix) - - script.write(",\n".join(map(repr, py_files)) + "]\n") - script.write(""" -byte_compile(files, optimize=%r, force=%r, - prefix=%r, base_dir=%r, - verbose=%r, dry_run=0, - direct=1) -""" % (optimize, force, prefix, base_dir, verbose)) - - finally: - script.close() - - cmd = [sys.executable, script_name] - if optimize == 1: - cmd.insert(1, "-O") - elif optimize == 2: - cmd.insert(1, "-OO") - - env = copy(os.environ) - env['PYTHONPATH'] = ':'.join(sys.path) - try: - spawn(cmd, dry_run=dry_run, env=env) - finally: - execute(os.remove, (script_name,), "removing %s" % script_name, - dry_run=dry_run) - - # "Direct" byte-compilation: use the py_compile module to compile - # right here, right now. Note that the script generated in indirect - # mode simply calls 'byte_compile()' in direct mode, a weird sort of - # cross-process recursion. Hey, it works! - else: - from py_compile import compile - - for file in py_files: - if file[-3:] != ".py": - # This lets us be lazy and not filter filenames in - # the "install_lib" command. - continue - - # Terminology from the py_compile module: - # cfile - byte-compiled file - # dfile - purported source filename (same as 'file' by default) - cfile = file + (__debug__ and "c" or "o") - dfile = file - if prefix: - if file[:len(prefix)] != prefix: - raise ValueError("invalid prefix: filename %r doesn't " - "start with %r" % (file, prefix)) - dfile = dfile[len(prefix):] - if base_dir: - dfile = os.path.join(base_dir, dfile) - - cfile_base = os.path.basename(cfile) - if direct: - if force or newer(file, cfile): - log.info("byte-compiling %s to %s", file, cfile_base) - if not dry_run: - compile(file, cfile, dfile) - else: - log.debug("skipping byte-compilation of %s to %s", - file, cfile_base) - - -def rfc822_escape(header): - """Return a version of the string escaped for inclusion in an - RFC-822 header, by ensuring there are 8 spaces space after each newline. - """ - lines = header.split('\n') - sep = '\n' + 8 * ' ' - return sep.join(lines) - -_RE_VERSION = re.compile('(\d+\.\d+(\.\d+)*)') -_MAC_OS_X_LD_VERSION = re.compile('^@\(#\)PROGRAM:ld ' - 'PROJECT:ld64-((\d+)(\.\d+)*)') - - -def _find_ld_version(): - """Finds the ld version. The version scheme differs under Mac OSX.""" - if sys.platform == 'darwin': - return _find_exe_version('ld -v', _MAC_OS_X_LD_VERSION) - else: - return _find_exe_version('ld -v') - - -def _find_exe_version(cmd, pattern=_RE_VERSION): - """Find the version of an executable by running `cmd` in the shell. - - `pattern` is a compiled regular expression. If not provided, default - to _RE_VERSION. If the command is not found, or the output does not - match the mattern, returns None. - """ - from subprocess import Popen, PIPE - executable = cmd.split()[0] - if find_executable(executable) is None: - return None - pipe = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) - try: - stdout, stderr = pipe.stdout.read(), pipe.stderr.read() - finally: - pipe.stdout.close() - pipe.stderr.close() - # some commands like ld under MacOS X, will give the - # output in the stderr, rather than stdout. - if stdout != '': - out_string = stdout - else: - out_string = stderr - - result = pattern.search(out_string) - if result is None: - return None - return result.group(1) - - -def get_compiler_versions(): - """Returns a tuple providing the versions of gcc, ld and dllwrap - - For each command, if a command is not found, None is returned. - Otherwise a string with the version is returned. - """ - gcc = _find_exe_version('gcc -dumpversion') - ld = _find_ld_version() - dllwrap = _find_exe_version('dllwrap --version') - return gcc, ld, dllwrap - - -def newer_group(sources, target, missing='error'): - """Return true if 'target' is out-of-date with respect to any file - listed in 'sources'. - - In other words, if 'target' exists and is newer - than every file in 'sources', return false; otherwise return true. - 'missing' controls what we do when a source file is missing; the - default ("error") is to blow up with an OSError from inside 'stat()'; - if it is "ignore", we silently drop any missing source files; if it is - "newer", any missing source files make us assume that 'target' is - out-of-date (this is handy in "dry-run" mode: it'll make you pretend to - carry out commands that wouldn't work because inputs are missing, but - that doesn't matter because you're not actually going to run the - commands). - """ - # If the target doesn't even exist, then it's definitely out-of-date. - if not os.path.exists(target): - return True - - # Otherwise we have to find out the hard way: if *any* source file - # is more recent than 'target', then 'target' is out-of-date and - # we can immediately return true. If we fall through to the end - # of the loop, then 'target' is up-to-date and we return false. - target_mtime = os.stat(target).st_mtime - - for source in sources: - if not os.path.exists(source): - if missing == 'error': # blow up when we stat() the file - pass - elif missing == 'ignore': # missing source dropped from - continue # target's dependency list - elif missing == 'newer': # missing source means target is - return True # out-of-date - - if os.stat(source).st_mtime > target_mtime: - return True - - return False - - -def write_file(filename, contents): - """Create a file with the specified name and write 'contents' (a - sequence of strings without line terminators) to it. - """ - try: - f = open(filename, "w") - for line in contents: - f.write(line + "\n") - finally: - f.close() - - -def _is_package(path): - """Returns True if path is a package (a dir with an __init__ file.""" - if not os.path.isdir(path): - return False - return os.path.isfile(os.path.join(path, '__init__.py')) - - -def _under(path, root): - path = path.split(os.sep) - root = root.split(os.sep) - if len(root) > len(path): - return False - for pos, part in enumerate(root): - if path[pos] != part: - return False - return True - - -def _package_name(root_path, path): - """Returns a dotted package name, given a subpath.""" - if not _under(path, root_path): - raise ValueError('"%s" is not a subpath of "%s"' % (path, root_path)) - return path[len(root_path) + 1:].replace(os.sep, '.') - - -def find_packages(paths=(os.curdir,), exclude=()): - """Return a list all Python packages found recursively within - directories 'paths' - - 'paths' should be supplied as a sequence of "cross-platform" - (i.e. URL-style) path; it will be converted to the appropriate local - path syntax. - - 'exclude' is a sequence of package names to exclude; '*' can be used as - a wildcard in the names, such that 'foo.*' will exclude all subpackages - of 'foo' (but not 'foo' itself). - """ - packages = [] - discarded = [] - - def _discarded(path): - for discard in discarded: - if _under(path, discard): - return True - return False - - for path in paths: - path = convert_path(path) - for root, dirs, files in os.walk(path): - for dir_ in dirs: - fullpath = os.path.join(root, dir_) - if _discarded(fullpath): - continue - # we work only with Python packages - if not _is_package(fullpath): - discarded.append(fullpath) - continue - # see if it's excluded - excluded = False - package_name = _package_name(path, fullpath) - for pattern in exclude: - if fnmatchcase(package_name, pattern): - excluded = True - break - if excluded: - continue - - # adding it to the list - packages.append(package_name) - return packages - -def resolve_name(name): - """Resolve a name like ``module.object`` to an object and return it. - - Raise ImportError if the module or name is not found. - """ - parts = name.split('.') - cursor = len(parts) - module_name, rest = parts[:cursor], parts[cursor:] - - while cursor > 0: - try: - ret = __import__('.'.join(module_name)) - break - except ImportError: - if cursor == 0: - raise - cursor -= 1 - module_name = parts[:cursor] - rest = parts[cursor:] - ret = '' - - for part in parts[1:]: - try: - ret = getattr(ret, part) - except AttributeError: - raise ImportError - - return ret - -def splitext(path): - """Like os.path.splitext, but take off .tar too""" - base, ext = posixpath.splitext(path) - if base.lower().endswith('.tar'): - ext = base[-4:] + ext - base = base[:-4] - return base, ext - - -def unzip_file(filename, location, flatten=True): - """Unzip the file (zip file located at filename) to the destination - location""" - if not os.path.exists(location): - os.makedirs(location) - zipfp = open(filename, 'rb') - try: - zip = zipfile.ZipFile(zipfp) - leading = has_leading_dir(zip.namelist()) and flatten - for name in zip.namelist(): - data = zip.read(name) - fn = name - if leading: - fn = split_leading_dir(name)[1] - fn = os.path.join(location, fn) - dir = os.path.dirname(fn) - if not os.path.exists(dir): - os.makedirs(dir) - if fn.endswith('/') or fn.endswith('\\'): - # A directory - if not os.path.exists(fn): - os.makedirs(fn) - else: - fp = open(fn, 'wb') - try: - fp.write(data) - finally: - fp.close() - finally: - zipfp.close() - - -def untar_file(filename, location): - """Untar the file (tar file located at filename) to the destination - location - """ - if not os.path.exists(location): - os.makedirs(location) - if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): - mode = 'r:gz' - elif (filename.lower().endswith('.bz2') - or filename.lower().endswith('.tbz')): - mode = 'r:bz2' - elif filename.lower().endswith('.tar'): - mode = 'r' - else: - mode = 'r:*' - tar = tarfile.open(filename, mode) - try: - leading = has_leading_dir([member.name for member in tar.getmembers()]) - for member in tar.getmembers(): - fn = member.name - if leading: - fn = split_leading_dir(fn)[1] - path = os.path.join(location, fn) - if member.isdir(): - if not os.path.exists(path): - os.makedirs(path) - else: - try: - fp = tar.extractfile(member) - except (KeyError, AttributeError), e: - # Some corrupt tar files seem to produce this - # (specifically bad symlinks) - continue - if not os.path.exists(os.path.dirname(path)): - os.makedirs(os.path.dirname(path)) - destfp = open(path, 'wb') - try: - shutil.copyfileobj(fp, destfp) - finally: - destfp.close() - fp.close() - finally: - tar.close() - - -def has_leading_dir(paths): - """Returns true if all the paths have the same leading path name - (i.e., everything is in one subdirectory in an archive)""" - common_prefix = None - for path in paths: - prefix, rest = split_leading_dir(path) - if not prefix: - return False - elif common_prefix is None: - common_prefix = prefix - elif prefix != common_prefix: - return False - return True - - -def split_leading_dir(path): - path = str(path) - path = path.lstrip('/').lstrip('\\') - if '/' in path and (('\\' in path and path.find('/') < path.find('\\')) - or '\\' not in path): - return path.split('/', 1) - elif '\\' in path: - return path.split('\\', 1) - else: - return path, '' - - -def spawn(cmd, search_path=1, verbose=0, dry_run=0, env=None): - """Run another program specified as a command list 'cmd' in a new process. - - 'cmd' is just the argument list for the new process, ie. - cmd[0] is the program to run and cmd[1:] are the rest of its arguments. - There is no way to run a program with a name different from that of its - executable. - - If 'search_path' is true (the default), the system's executable - search path will be used to find the program; otherwise, cmd[0] - must be the exact path to the executable. If 'dry_run' is true, - the command will not actually be run. - - If 'env' is given, it's a environment dictionary used for the execution - environment. - - Raise DistutilsExecError if running the program fails in any way; just - return on success. - """ - if os.name == 'posix': - _spawn_posix(cmd, search_path, dry_run=dry_run, env=env) - elif os.name == 'nt': - _spawn_nt(cmd, search_path, dry_run=dry_run, env=env) - elif os.name == 'os2': - _spawn_os2(cmd, search_path, dry_run=dry_run, env=env) - else: - raise DistutilsPlatformError( - "don't know how to spawn programs on platform '%s'" % os.name) - - -def _nt_quote_args(args): - """Quote command-line arguments for DOS/Windows conventions. - - Just wraps every argument which contains blanks in double quotes, and - returns a new argument list. - """ - # XXX this doesn't seem very robust to me -- but if the Windows guys - # say it'll work, I guess I'll have to accept it. (What if an arg - # contains quotes? What other magic characters, other than spaces, - # have to be escaped? Is there an escaping mechanism other than - # quoting?) - for i, arg in enumerate(args): - if ' ' in arg: - args[i] = '"%s"' % arg - return args - - -def _spawn_nt(cmd, search_path=1, verbose=0, dry_run=0, env=None): - executable = cmd[0] - cmd = _nt_quote_args(cmd) - if search_path: - # either we find one or it stays the same - executable = find_executable(executable) or executable - log.info(' '.join([executable] + cmd[1:])) - if not dry_run: - # spawn for NT requires a full path to the .exe - try: - if env is None: - rc = os.spawnv(os.P_WAIT, executable, cmd) - else: - rc = os.spawnve(os.P_WAIT, executable, cmd, env) - - except OSError, exc: - # this seems to happen when the command isn't found - raise DistutilsExecError( - "command '%s' failed: %s" % (cmd[0], exc[-1])) - if rc != 0: - # and this reflects the command running but failing - raise DistutilsExecError( - "command '%s' failed with exit status %d" % (cmd[0], rc)) - - -def _spawn_os2(cmd, search_path=1, verbose=0, dry_run=0, env=None): - executable = cmd[0] - if search_path: - # either we find one or it stays the same - executable = find_executable(executable) or executable - log.info(' '.join([executable] + cmd[1:])) - if not dry_run: - # spawnv for OS/2 EMX requires a full path to the .exe - try: - if env is None: - rc = os.spawnv(os.P_WAIT, executable, cmd) - else: - rc = os.spawnve(os.P_WAIT, executable, cmd, env) - - except OSError, exc: - # this seems to happen when the command isn't found - raise DistutilsExecError( - "command '%s' failed: %s" % (cmd[0], exc[-1])) - if rc != 0: - # and this reflects the command running but failing - log.debug("command '%s' failed with exit status %d" % (cmd[0], rc)) - raise DistutilsExecError( - "command '%s' failed with exit status %d" % (cmd[0], rc)) - - -def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0, env=None): - log.info(' '.join(cmd)) - if dry_run: - return - - if env is None: - exec_fn = search_path and os.execvp or os.execv - else: - exec_fn = search_path and os.execvpe or os.execve - - pid = os.fork() - - if pid == 0: # in the child - try: - if env is None: - exec_fn(cmd[0], cmd) - else: - exec_fn(cmd[0], cmd, env) - except OSError, e: - sys.stderr.write("unable to execute %s: %s\n" % - (cmd[0], e.strerror)) - os._exit(1) - - sys.stderr.write("unable to execute %s for unknown reasons" % cmd[0]) - os._exit(1) - else: # in the parent - # Loop until the child either exits or is terminated by a signal - # (ie. keep waiting if it's merely stopped) - while 1: - try: - pid, status = os.waitpid(pid, 0) - except OSError, exc: - import errno - if exc.errno == errno.EINTR: - continue - raise DistutilsExecError( - "command '%s' failed: %s" % (cmd[0], exc[-1])) - if os.WIFSIGNALED(status): - raise DistutilsExecError( - "command '%s' terminated by signal %d" % \ - (cmd[0], os.WTERMSIG(status))) - - elif os.WIFEXITED(status): - exit_status = os.WEXITSTATUS(status) - if exit_status == 0: - return # hey, it succeeded! - else: - raise DistutilsExecError( - "command '%s' failed with exit status %d" % \ - (cmd[0], exit_status)) - - elif os.WIFSTOPPED(status): - continue - - else: - raise DistutilsExecError( - "unknown error executing '%s': termination status %d" % \ - (cmd[0], status)) - - -def find_executable(executable, path=None): - """Tries to find 'executable' in the directories listed in 'path'. - - A string listing directories separated by 'os.pathsep'; defaults to - os.environ['PATH']. Returns the complete filename or None if not found. - """ - if path is None: - path = os.environ['PATH'] - paths = path.split(os.pathsep) - base, ext = os.path.splitext(executable) - - if (sys.platform == 'win32' or os.name == 'os2') and (ext != '.exe'): - executable = executable + '.exe' - - if not os.path.isfile(executable): - for p in paths: - f = os.path.join(p, executable) - if os.path.isfile(f): - # the file exists, we have a shot at spawn working - return f - return None - else: - return executable - - -DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi' -DEFAULT_REALM = 'pypi' -DEFAULT_PYPIRC = """\ -[distutils] -index-servers = - pypi - -[pypi] -username:%s -password:%s -""" - -def get_pypirc_path(): - """Returns rc file path.""" - return os.path.join(os.path.expanduser('~'), '.pypirc') - - -def generate_pypirc(username, password): - """Creates a default .pypirc file.""" - rc = get_pypirc_path() - f = open(rc, 'w') - try: - f.write(DEFAULT_PYPIRC % (username, password)) - finally: - f.close() - try: - os.chmod(rc, 0600) - except OSError: - # should do something better here - pass - - -def read_pypirc(repository=DEFAULT_REPOSITORY, realm=DEFAULT_REALM): - """Reads the .pypirc file.""" - rc = get_pypirc_path() - if os.path.exists(rc): - config = RawConfigParser() - config.read(rc) - sections = config.sections() - if 'distutils' in sections: - # let's get the list of servers - index_servers = config.get('distutils', 'index-servers') - _servers = [server.strip() for server in - index_servers.split('\n') - if server.strip() != ''] - if _servers == []: - # nothing set, let's try to get the default pypi - if 'pypi' in sections: - _servers = ['pypi'] - else: - # the file is not properly defined, returning - # an empty dict - return {} - for server in _servers: - current = {'server': server} - current['username'] = config.get(server, 'username') - - # optional params - for key, default in (('repository', - DEFAULT_REPOSITORY), - ('realm', DEFAULT_REALM), - ('password', None)): - if config.has_option(server, key): - current[key] = config.get(server, key) - else: - current[key] = default - if (current['server'] == repository or - current['repository'] == repository): - return current - elif 'server-login' in sections: - # old format - server = 'server-login' - if config.has_option(server, 'repository'): - repository = config.get(server, 'repository') - else: - repository = DEFAULT_REPOSITORY - - return {'username': config.get(server, 'username'), - 'password': config.get(server, 'password'), - 'repository': repository, - 'server': server, - 'realm': DEFAULT_REALM} - - return {} - - -def metadata_to_dict(meta): - """XXX might want to move it to the Metadata class.""" - data = { - 'metadata_version' : meta.version, - 'name': meta['Name'], - 'version': meta['Version'], - 'summary': meta['Summary'], - 'home_page': meta['Home-page'], - 'author': meta['Author'], - 'author_email': meta['Author-email'], - 'license': meta['License'], - 'description': meta['Description'], - 'keywords': meta['Keywords'], - 'platform': meta['Platform'], - 'classifier': meta['Classifier'], - 'download_url': meta['Download-URL'], - } - - if meta.version == '1.2': - data['requires_dist'] = meta['Requires-Dist'] - data['requires_python'] = meta['Requires-Python'] - data['requires_external'] = meta['Requires-External'] - data['provides_dist'] = meta['Provides-Dist'] - data['obsoletes_dist'] = meta['Obsoletes-Dist'] - data['project_url'] = [','.join(url) for url in - meta['Project-URL']] - - elif meta.version == '1.1': - data['provides'] = meta['Provides'] - data['requires'] = meta['Requires'] - data['obsoletes'] = meta['Obsoletes'] - - return data - -# utility functions for 2to3 support - -def run_2to3(files, doctests_only=False, fixer_names=None, options=None, - explicit=None): - """ Wrapper function around the refactor() class which - performs the conversions on a list of python files. - Invoke 2to3 on a list of Python files. The files should all come - from the build area, as the modification is done in-place.""" - - #if not files: - # return - - # Make this class local, to delay import of 2to3 - from lib2to3.refactor import get_fixers_from_package, RefactoringTool - fixers = [] - fixers = get_fixers_from_package('lib2to3.fixes') - - - if fixer_names: - for fixername in fixer_names: - fixers.extend([fixer for fixer in get_fixers_from_package(fixername)]) - r = RefactoringTool(fixers, options=options) - if doctests_only: - r.refactor(files, doctests_only=True, write=True) - else: - r.refactor(files, write=True) - -class Mixin2to3: - """ Wrapper class for commands that run 2to3. - To configure 2to3, setup scripts may either change - the class variables, or inherit from this class - to override how 2to3 is invoked. - """ - # provide list of fixers to run. - # defaults to all from lib2to3.fixers - fixer_names = None - - # options dictionary - options = None - - # list of fixers to invoke even though they are marked as explicit - explicit = None - - def run_2to3(self, files, doctests_only=False): - """ Issues a call to util.run_2to3. """ - return run_2to3(files, doctests_only, self.fixer_names, - self.options, self.explicit) diff --git a/src/distutils2/version.py b/src/distutils2/version.py deleted file mode 100644 index 64c33f7..0000000 --- a/src/distutils2/version.py +++ /dev/null @@ -1,433 +0,0 @@ -import re - -from distutils2.errors import IrrationalVersionError, HugeMajorVersionNumError - -__all__ = ['NormalizedVersion', 'suggest_normalized_version', - 'VersionPredicate', 'is_valid_version', 'is_valid_versions', - 'is_valid_predicate'] - -# A marker used in the second and third parts of the `parts` tuple, for -# versions that don't have those segments, to sort properly. An example -# of versions in sort order ('highest' last): -# 1.0b1 ((1,0), ('b',1), ('f',)) -# 1.0.dev345 ((1,0), ('f',), ('dev', 345)) -# 1.0 ((1,0), ('f',), ('f',)) -# 1.0.post256.dev345 ((1,0), ('f',), ('f', 'post', 256, 'dev', 345)) -# 1.0.post345 ((1,0), ('f',), ('f', 'post', 345, 'f')) -# ^ ^ ^ -# 'b' < 'f' ---------------------/ | | -# | | -# 'dev' < 'f' < 'post' -------------------/ | -# | -# 'dev' < 'f' ----------------------------------------------/ -# Other letters would do, but 'f' for 'final' is kind of nice. -_FINAL_MARKER = ('f',) - -_VERSION_RE = re.compile(r''' - ^ - (?P<version>\d+\.\d+) # minimum 'N.N' - (?P<extraversion>(?:\.\d+)*) # any number of extra '.N' segments - (?: - (?P<prerel>[abc]|rc) # 'a'=alpha, 'b'=beta, 'c'=release candidate - # 'rc'= alias for release candidate - (?P<prerelversion>\d+(?:\.\d+)*) - )? - (?P<postdev>(\.post(?P<post>\d+))?(\.dev(?P<dev>\d+))?)? - $''', re.VERBOSE) - - -class NormalizedVersion(object): - """A rational version. - - Good: - 1.2 # equivalent to "1.2.0" - 1.2.0 - 1.2a1 - 1.2.3a2 - 1.2.3b1 - 1.2.3c1 - 1.2.3.4 - TODO: fill this out - - Bad: - 1 # mininum two numbers - 1.2a # release level must have a release serial - 1.2.3b - """ - def __init__(self, s, error_on_huge_major_num=True): - """Create a NormalizedVersion instance from a version string. - - @param s {str} The version string. - @param error_on_huge_major_num {bool} Whether to consider an - apparent use of a year or full date as the major version number - an error. Default True. One of the observed patterns on PyPI before - the introduction of `NormalizedVersion` was version numbers like - this: - 2009.01.03 - 20040603 - 2005.01 - This guard is here to strongly encourage the package author to - use an alternate version, because a release deployed into PyPI - and, e.g. downstream Linux package managers, will forever remove - the possibility of using a version number like "1.0" (i.e. - where the major number is less than that huge major number). - """ - self.is_final = True # by default, consider a version as final. - self._parse(s, error_on_huge_major_num) - - @classmethod - def from_parts(cls, version, prerelease=_FINAL_MARKER, - devpost=_FINAL_MARKER): - return cls(cls.parts_to_str((version, prerelease, devpost))) - - def _parse(self, s, error_on_huge_major_num=True): - """Parses a string version into parts.""" - match = _VERSION_RE.search(s) - if not match: - raise IrrationalVersionError(s) - - groups = match.groupdict() - parts = [] - - # main version - block = self._parse_numdots(groups['version'], s, False, 2) - extraversion = groups.get('extraversion') - if extraversion not in ('', None): - block += self._parse_numdots(extraversion[1:], s) - parts.append(tuple(block)) - - # prerelease - prerel = groups.get('prerel') - if prerel is not None: - block = [prerel] - block += self._parse_numdots(groups.get('prerelversion'), s, - pad_zeros_length=1) - parts.append(tuple(block)) - self.is_final = False - else: - parts.append(_FINAL_MARKER) - - # postdev - if groups.get('postdev'): - post = groups.get('post') - dev = groups.get('dev') - postdev = [] - if post is not None: - postdev.extend([_FINAL_MARKER[0], 'post', int(post)]) - if dev is None: - postdev.append(_FINAL_MARKER[0]) - if dev is not None: - postdev.extend(['dev', int(dev)]) - self.is_final = False - parts.append(tuple(postdev)) - else: - parts.append(_FINAL_MARKER) - self.parts = tuple(parts) - if error_on_huge_major_num and self.parts[0][0] > 1980: - raise HugeMajorVersionNumError("huge major version number, %r, " - "which might cause future problems: %r" % (self.parts[0][0], s)) - - def _parse_numdots(self, s, full_ver_str, drop_trailing_zeros=True, - pad_zeros_length=0): - """Parse 'N.N.N' sequences, return a list of ints. - - @param s {str} 'N.N.N..." sequence to be parsed - @param full_ver_str {str} The full version string from which this - comes. Used for error strings. - @param drop_trailing_zeros {bool} Whether to drop trailing zeros - from the returned list. Default True. - @param pad_zeros_length {int} The length to which to pad the - returned list with zeros, if necessary. Default 0. - """ - nums = [] - for n in s.split("."): - if len(n) > 1 and n[0] == '0': - raise IrrationalVersionError("cannot have leading zero in " - "version number segment: '%s' in %r" % (n, full_ver_str)) - nums.append(int(n)) - if drop_trailing_zeros: - while nums and nums[-1] == 0: - nums.pop() - while len(nums) < pad_zeros_length: - nums.append(0) - return nums - - def __str__(self): - return self.parts_to_str(self.parts) - - @classmethod - def parts_to_str(cls, parts): - """Transforms a version expressed in tuple into its string - representation.""" - # XXX This doesn't check for invalid tuples - main, prerel, postdev = parts - s = '.'.join(str(v) for v in main) - if prerel is not _FINAL_MARKER: - s += prerel[0] - s += '.'.join(str(v) for v in prerel[1:]) - if postdev and postdev is not _FINAL_MARKER: - if postdev[0] == 'f': - postdev = postdev[1:] - i = 0 - while i < len(postdev): - if i % 2 == 0: - s += '.' - s += str(postdev[i]) - i += 1 - return s - - def __repr__(self): - return "%s('%s')" % (self.__class__.__name__, self) - - def _cannot_compare(self, other): - raise TypeError("cannot compare %s and %s" - % (type(self).__name__, type(other).__name__)) - - def __eq__(self, other): - if not isinstance(other, NormalizedVersion): - self._cannot_compare(other) - return self.parts == other.parts - - def __lt__(self, other): - if not isinstance(other, NormalizedVersion): - self._cannot_compare(other) - return self.parts < other.parts - - def __ne__(self, other): - return not self.__eq__(other) - - def __gt__(self, other): - return not (self.__lt__(other) or self.__eq__(other)) - - def __le__(self, other): - return self.__eq__(other) or self.__lt__(other) - - def __ge__(self, other): - return self.__eq__(other) or self.__gt__(other) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - __hash__ = object.__hash__ - - -def suggest_normalized_version(s): - """Suggest a normalized version close to the given version string. - - If you have a version string that isn't rational (i.e. NormalizedVersion - doesn't like it) then you might be able to get an equivalent (or close) - rational version from this function. - - This does a number of simple normalizations to the given string, based - on observation of versions currently in use on PyPI. Given a dump of - those version during PyCon 2009, 4287 of them: - - 2312 (53.93%) match NormalizedVersion without change - with the automatic suggestion - - 3474 (81.04%) match when using this suggestion method - - @param s {str} An irrational version string. - @returns A rational version string, or None, if couldn't determine one. - """ - try: - NormalizedVersion(s) - return s # already rational - except IrrationalVersionError: - pass - - rs = s.lower() - - # part of this could use maketrans - for orig, repl in (('-alpha', 'a'), ('-beta', 'b'), ('alpha', 'a'), - ('beta', 'b'), ('rc', 'c'), ('-final', ''), - ('-pre', 'c'), - ('-release', ''), ('.release', ''), ('-stable', ''), - ('+', '.'), ('_', '.'), (' ', ''), ('.final', ''), - ('final', '')): - rs = rs.replace(orig, repl) - - # if something ends with dev or pre, we add a 0 - rs = re.sub(r"pre$", r"pre0", rs) - rs = re.sub(r"dev$", r"dev0", rs) - - # if we have something like "b-2" or "a.2" at the end of the - # version, that is pobably beta, alpha, etc - # let's remove the dash or dot - rs = re.sub(r"([abc|rc])[\-\.](\d+)$", r"\1\2", rs) - - # 1.0-dev-r371 -> 1.0.dev371 - # 0.1-dev-r79 -> 0.1.dev79 - rs = re.sub(r"[\-\.](dev)[\-\.]?r?(\d+)$", r".\1\2", rs) - - # Clean: 2.0.a.3, 2.0.b1, 0.9.0~c1 - rs = re.sub(r"[.~]?([abc])\.?", r"\1", rs) - - # Clean: v0.3, v1.0 - if rs.startswith('v'): - rs = rs[1:] - - # Clean leading '0's on numbers. - #TODO: unintended side-effect on, e.g., "2003.05.09" - # PyPI stats: 77 (~2%) better - rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs) - - # Clean a/b/c with no version. E.g. "1.0a" -> "1.0a0". Setuptools infers - # zero. - # PyPI stats: 245 (7.56%) better - rs = re.sub(r"(\d+[abc])$", r"\g<1>0", rs) - - # the 'dev-rNNN' tag is a dev tag - rs = re.sub(r"\.?(dev-r|dev\.r)\.?(\d+)$", r".dev\2", rs) - - # clean the - when used as a pre delimiter - rs = re.sub(r"-(a|b|c)(\d+)$", r"\1\2", rs) - - # a terminal "dev" or "devel" can be changed into ".dev0" - rs = re.sub(r"[\.\-](dev|devel)$", r".dev0", rs) - - # a terminal "dev" can be changed into ".dev0" - rs = re.sub(r"(?![\.\-])dev$", r".dev0", rs) - - # a terminal "final" or "stable" can be removed - rs = re.sub(r"(final|stable)$", "", rs) - - # The 'r' and the '-' tags are post release tags - # 0.4a1.r10 -> 0.4a1.post10 - # 0.9.33-17222 -> 0.9.3.post17222 - # 0.9.33-r17222 -> 0.9.3.post17222 - rs = re.sub(r"\.?(r|-|-r)\.?(\d+)$", r".post\2", rs) - - # Clean 'r' instead of 'dev' usage: - # 0.9.33+r17222 -> 0.9.3.dev17222 - # 1.0dev123 -> 1.0.dev123 - # 1.0.git123 -> 1.0.dev123 - # 1.0.bzr123 -> 1.0.dev123 - # 0.1a0dev.123 -> 0.1a0.dev123 - # PyPI stats: ~150 (~4%) better - rs = re.sub(r"\.?(dev|git|bzr)\.?(\d+)$", r".dev\2", rs) - - # Clean '.pre' (normalized from '-pre' above) instead of 'c' usage: - # 0.2.pre1 -> 0.2c1 - # 0.2-c1 -> 0.2c1 - # 1.0preview123 -> 1.0c123 - # PyPI stats: ~21 (0.62%) better - rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs) - - # Tcl/Tk uses "px" for their post release markers - rs = re.sub(r"p(\d+)$", r".post\1", rs) - - try: - NormalizedVersion(rs) - return rs # already rational - except IrrationalVersionError: - pass - return None - - -_PREDICATE = re.compile(r"(?i)^\s*([a-z_][\sa-zA-Z_-]*(?:\.[a-z_]\w*)*)(.*)") -_VERSIONS = re.compile(r"^\s*\((.*)\)\s*$") -_PLAIN_VERSIONS = re.compile(r"^\s*(.*)\s*$") -_SPLIT_CMP = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$") - - -def _split_predicate(predicate): - match = _SPLIT_CMP.match(predicate) - if match is None: - # probably no op, we'll use "==" - comp, version = '==', predicate - else: - comp, version = match.groups() - return comp, NormalizedVersion(version) - - -class VersionPredicate(object): - """Defines a predicate: ProjectName (>ver1,ver2, ..)""" - - _operators = {"<": lambda x, y: x < y, - ">": lambda x, y: x > y, - "<=": lambda x, y: str(x).startswith(str(y)) or x < y, - ">=": lambda x, y: str(x).startswith(str(y)) or x > y, - "==": lambda x, y: str(x).startswith(str(y)), - "!=": lambda x, y: not str(x).startswith(str(y)), - } - - def __init__(self, predicate): - self._string = predicate - predicate = predicate.strip() - match = _PREDICATE.match(predicate) - if match is None: - raise ValueError('Bad predicate "%s"' % predicate) - - name, predicates = match.groups() - self.name = name.strip() - predicates = predicates.strip() - predicates = _VERSIONS.match(predicates) - if predicates is not None: - predicates = predicates.groups()[0] - self.predicates = [_split_predicate(pred.strip()) - for pred in predicates.split(',')] - else: - self.predicates = [] - - def match(self, version): - """Check if the provided version matches the predicates.""" - if isinstance(version, str): - version = NormalizedVersion(version) - for operator, predicate in self.predicates: - if not self._operators[operator](version, predicate): - return False - return True - - def __repr__(self): - return self._string - - -class _Versions(VersionPredicate): - def __init__(self, predicate): - predicate = predicate.strip() - match = _PLAIN_VERSIONS.match(predicate) - self.name = None - predicates = match.groups()[0] - self.predicates = [_split_predicate(pred.strip()) - for pred in predicates.split(',')] - - -class _Version(VersionPredicate): - def __init__(self, predicate): - predicate = predicate.strip() - match = _PLAIN_VERSIONS.match(predicate) - self.name = None - self.predicates = _split_predicate(match.groups()[0]) - - -def is_valid_predicate(predicate): - try: - VersionPredicate(predicate) - except (ValueError, IrrationalVersionError): - return False - else: - return True - - -def is_valid_versions(predicate): - try: - _Versions(predicate) - except (ValueError, IrrationalVersionError): - return False - else: - return True - - -def is_valid_version(predicate): - try: - _Version(predicate) - except (ValueError, IrrationalVersionError): - return False - else: - return True - - -def get_version_predicate(requirements): - """Return a VersionPredicate object, from a string or an already - existing object. - """ - if isinstance(requirements, str): - requirements = VersionPredicate(requirements) - return requirements diff --git a/src/runtests-cov.py b/src/runtests-cov.py deleted file mode 100755 index d6678b4..0000000 --- a/src/runtests-cov.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python -"""Tests for distutils2. - -The tests for distutils2 are defined in the distutils2.tests package. -""" - -import sys -from os.path import dirname, islink, realpath, join, abspath -from optparse import OptionParser - -COVERAGE_FILE = join(dirname(abspath(__file__)), '.coverage') - -def get_coverage(): - """ Return a usable coverage object. """ - # deferred import because coverage is optional - import coverage - cov = getattr(coverage, "the_coverage", None) - if not cov: - cov = coverage.coverage(COVERAGE_FILE) - return cov - -def ignore_prefixes(module): - """ Return a list of prefixes to ignore in the coverage report if - we want to completely skip `module`. - """ - # A function like that is needed because some GNU/Linux - # distributions, such a Ubuntu, really like to build link farm in - # /usr/lib in order to save a few bytes on the disk. - dirnames = [dirname(module.__file__)] - - pymod = module.__file__.rstrip("c") - if islink(pymod): - dirnames.append(dirname(realpath(pymod))) - return dirnames - - -def parse_opts(): - parser = OptionParser(usage="%prog [OPTIONS]", - description="run the distutils2 unittests") - - parser.add_option("-q", "--quiet", help="do not print verbose messages", - action="store_true", default=False) - parser.add_option("-c", "--coverage", action="store_true", default=False, - help="produce a coverage report at the end of the run") - parser.add_option("-r", "--report", action="store_true", default=False, - help="produce a coverage report from the last test run") - parser.add_option("-m", "--show-missing", action="store_true", - default=False, - help=("Show line numbers of statements in each module " - "that weren't executed.")) - - opts, args = parser.parse_args() - return opts, args - - -def coverage_report(opts): - from distutils2.tests.support import unittest - cov = get_coverage() - if hasattr(cov, "load"): - # running coverage 3.x - cov.load() - morfs = None - else: - # running coverage 2.x - cov.cache = COVERAGE_FILE - cov.restore() - morfs = [m for m in cov.cexecuted.keys() if "distutils2" in m] - - prefixes = ["runtests", "distutils2/tests", "distutils2/_backport"] - prefixes += ignore_prefixes(unittest) - - try: - import docutils - prefixes += ignore_prefixes(docutils) - except ImportError: - # that module is completely optional - pass - - try: - import roman - prefixes += ignore_prefixes(roman) - except ImportError: - # that module is also completely optional - pass - - cov.report(morfs, omit_prefixes=prefixes, show_missing=opts.show_missing) - - -def test_main(): - opts, args = parse_opts() - verbose = not opts.quiet - ret = 0 - - if opts.coverage: - cov = get_coverage() - cov.erase() - cov.start() - if not opts.report: - ret = run_tests(verbose) - if opts.coverage: - cov.stop() - cov.save() - - if opts.report or opts.coverage: - coverage_report(opts) - - return ret - - -def run_tests(verbose): - import distutils2.tests - from distutils2.tests import run_unittest, reap_children, TestFailed - from distutils2._backport.tests import test_suite as btest_suite - # XXX just supporting -q right now to enable detailed/quiet output - if len(sys.argv) > 1: - verbose = sys.argv[-1] != '-q' - else: - verbose = 1 - try: - try: - run_unittest([distutils2.tests.test_suite(), btest_suite()], - verbose_=verbose) - return 0 - except TestFailed: - return 1 - finally: - reap_children() - - -if __name__ == "__main__": - try: - from distutils2.tests.support import unittest - except ImportError: - sys.stderr.write('Error: You have to install unittest2') - sys.exit(1) - sys.exit(test_main()) diff --git a/src/runtests.py b/src/runtests.py deleted file mode 100644 index 415d37a..0000000 --- a/src/runtests.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python -"""Tests for distutils2. - -The tests for distutils2 are defined in the distutils2.tests package. -""" - -import sys - - -def test_main(): - import distutils2.tests - from distutils2.tests import run_unittest, reap_children, TestFailed - from distutils2._backport.tests import test_suite as btest_suite - # XXX just supporting -q right now to enable detailed/quiet output - if len(sys.argv) > 1: - verbose = sys.argv[-1] != '-q' - else: - verbose = 1 - try: - try: - run_unittest([distutils2.tests.test_suite(), btest_suite()], - verbose_=verbose) - return 0 - except TestFailed: - return 1 - finally: - reap_children() - - -if __name__ == "__main__": - try: - from distutils2.tests.support import unittest - except ImportError: - sys.stderr.write('Error: You have to install unittest2') - sys.exit(1) - sys.exit(test_main()) diff --git a/src/setup.cfg b/src/setup.cfg deleted file mode 100644 index 169aaf6..0000000 --- a/src/setup.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[build_ext] -# needed so that tests work without mucking with sys.path -inplace = 1 diff --git a/src/setup.py b/src/setup.py deleted file mode 100644 index 4a1794d..0000000 --- a/src/setup.py +++ /dev/null @@ -1,230 +0,0 @@ -#!/usr/bin/env python -# -*- encoding: utf8 -*- -__revision__ = "$Id$" -import sys -import os -import re - -from distutils2 import __version__ as VERSION -from distutils2 import log -from distutils2.core import setup, Extension -from distutils2.compiler.ccompiler import new_compiler -from distutils2.command.sdist import sdist -from distutils2.command.install import install -from distutils2.util import find_packages - -f = open('README.txt') -try: - README = f.read() -finally: - f.close() - -def get_tip_revision(path=os.getcwd()): - from subprocess import Popen, PIPE - try: - cmd = Popen(['hg', 'tip', '--template', '{rev}', '-R', path], - stdout=PIPE, stderr=PIPE) - except OSError: - return 0 - rev = cmd.stdout.read() - if rev == '': - # there has been an error in the command - return 0 - return int(rev) - -DEV_SUFFIX = '.dev%d' % get_tip_revision('..') - - -class install_hg(install): - - user_options = install.user_options + [ - ('dev', None, "Add a dev marker") - ] - - def initialize_options(self): - install.initialize_options(self) - self.dev = 0 - - def run(self): - if self.dev: - self.distribution.metadata.version += DEV_SUFFIX - install.run(self) - - -class sdist_hg(sdist): - - user_options = sdist.user_options + [ - ('dev', None, "Add a dev marker") - ] - - def initialize_options(self): - sdist.initialize_options(self) - self.dev = 0 - - def run(self): - if self.dev: - self.distribution.metadata.version += DEV_SUFFIX - sdist.run(self) - - -# additional paths to check, set from the command line -SSL_INCDIR = '' # --openssl-incdir= -SSL_LIBDIR = '' # --openssl-libdir= -SSL_DIR = '' # --openssl-prefix= - -def add_dir_to_list(dirlist, dir): - """Add the directory 'dir' to the list 'dirlist' (at the front) if - 'dir' actually exists and is a directory. If 'dir' is already in - 'dirlist' it is moved to the front. - """ - if dir is not None and os.path.isdir(dir) and dir not in dirlist: - if dir in dirlist: - dirlist.remove(dir) - dirlist.insert(0, dir) - - -def prepare_hashlib_extensions(): - """Decide which C extensions to build and create the appropriate - Extension objects to build them. Return a list of Extensions. - """ - # this CCompiler object is only used to locate include files - compiler = new_compiler() - - # Ensure that these paths are always checked - if os.name == 'posix': - add_dir_to_list(compiler.library_dirs, '/usr/local/lib') - add_dir_to_list(compiler.include_dirs, '/usr/local/include') - - add_dir_to_list(compiler.library_dirs, '/usr/local/ssl/lib') - add_dir_to_list(compiler.include_dirs, '/usr/local/ssl/include') - - add_dir_to_list(compiler.library_dirs, '/usr/contrib/ssl/lib') - add_dir_to_list(compiler.include_dirs, '/usr/contrib/ssl/include') - - add_dir_to_list(compiler.library_dirs, '/usr/lib') - add_dir_to_list(compiler.include_dirs, '/usr/include') - - # look in paths supplied on the command line - if SSL_LIBDIR: - add_dir_to_list(compiler.library_dirs, SSL_LIBDIR) - if SSL_INCDIR: - add_dir_to_list(compiler.include_dirs, SSL_INCDIR) - if SSL_DIR: - if os.name == 'nt': - add_dir_to_list(compiler.library_dirs, os.path.join(SSL_DIR, 'out32dll')) - # prefer the static library - add_dir_to_list(compiler.library_dirs, os.path.join(SSL_DIR, 'out32')) - else: - add_dir_to_list(compiler.library_dirs, os.path.join(SSL_DIR, 'lib')) - add_dir_to_list(compiler.include_dirs, os.path.join(SSL_DIR, 'include')) - - oslibs = {'posix': ['ssl', 'crypto'], - 'nt': ['libeay32', 'gdi32', 'advapi32', 'user32']} - - if os.name not in oslibs: - sys.stderr.write( - 'unknown operating system, impossible to compile _hashlib') - sys.exit(1) - - exts = [] - - ssl_inc_dirs = [] - ssl_incs = [] - for inc_dir in compiler.include_dirs: - f = os.path.join(inc_dir, 'openssl', 'ssl.h') - if os.path.exists(f): - ssl_incs.append(f) - ssl_inc_dirs.append(inc_dir) - - ssl_lib = compiler.find_library_file(compiler.library_dirs, oslibs[os.name][0]) - - # find out which version of OpenSSL we have - openssl_ver = 0 - openssl_ver_re = re.compile( - '^\s*#\s*define\s+OPENSSL_VERSION_NUMBER\s+(0x[0-9a-fA-F]+)' ) - ssl_inc_dir = '' - for ssl_inc_dir in ssl_inc_dirs: - name = os.path.join(ssl_inc_dir, 'openssl', 'opensslv.h') - if os.path.isfile(name): - try: - incfile = open(name, 'r') - for line in incfile: - m = openssl_ver_re.match(line) - if m: - openssl_ver = int(m.group(1), 16) - break - except IOError: - pass - - # first version found is what we'll use - if openssl_ver: - break - - if (ssl_inc_dir and ssl_lib is not None and openssl_ver >= 0x00907000): - - log.info('Using OpenSSL version 0x%08x from', openssl_ver) - log.info(' Headers:\t%s', ssl_inc_dir) - log.info(' Library:\t%s', ssl_lib) - - # The _hashlib module wraps optimized implementations - # of hash functions from the OpenSSL library. - exts.append(Extension('distutils2._backport._hashlib', - ['distutils2/_backport/_hashopenssl.c'], - include_dirs = [ssl_inc_dir], - library_dirs = [os.path.dirname(ssl_lib)], - libraries = oslibs[os.name])) - else: - exts.append(Extension('distutils2._backport._sha', - ['distutils2/_backport/shamodule.c'])) - exts.append(Extension('distutils2._backport._md5', - sources=['distutils2/_backport/md5module.c', - 'distutils2/_backport/md5.c'], - depends=['distutils2/_backport/md5.h']) ) - - if (not ssl_lib or openssl_ver < 0x00908000): - # OpenSSL doesn't do these until 0.9.8 so we'll bring our own - exts.append(Extension('distutils2._backport._sha256', - ['distutils2/_backport/sha256module.c'])) - exts.append(Extension('distutils2._backport._sha512', - ['distutils2/_backport/sha512module.c'])) - - return exts - -setup_kwargs = {} -if sys.version < '2.6': - setup_kwargs['scripts'] = ['distutils2/mkpkg.py'] - -if sys.version < '2.5': - setup_kwargs['ext_modules'] = prepare_hashlib_extensions() - -_CLASSIFIERS = """\ -Development Status :: 3 - Alpha -Intended Audience :: Developers -License :: OSI Approved :: Python Software Foundation License -Operating System :: OS Independent -Programming Language :: Python -Topic :: Software Development :: Libraries :: Python Modules -Topic :: System :: Archiving :: Packaging -Topic :: System :: Systems Administration -Topic :: Utilities""" - -setup(name="Distutils2", - version=VERSION, - summary="Python Distribution Utilities", - keywords=['packaging', 'distutils'], - author="Tarek Ziade", - author_email="tarek@ziade.org", - home_page="http://bitbucket.org/tarek/distutils2/wiki/Home", - license="PSF", - description=README, - classifier=_CLASSIFIERS.split('\n'), - packages=find_packages(), - cmdclass={'sdist': sdist_hg, 'install': install_hg}, - package_data={'distutils2._backport': ['sysconfig.cfg']}, - project_url=[('Mailing list', - 'http://mail.python.org/mailman/listinfo/distutils-sig/'), - ('Documentation', - 'http://packages.python.org/Distutils2'), - ('Repository', 'http://hg.python.org/distutils2'), - ('Bug tracker', 'http://bugs.python.org')], - **setup_kwargs) diff --git a/src/tests.sh b/src/tests.sh deleted file mode 100755 index a78c005..0000000 --- a/src/tests.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh -echo -n "Running tests for Python 2.4... " -rm -f distutils2/_backport/_hashlib.so -python2.4 setup.py build_ext -f -q 2> /dev/null > /dev/null -python2.4 -Wd runtests.py -q 2> /dev/null -if [ $? -ne 0 ];then - echo Failed - rm -f distutils2/_backport/_hashlib.so - exit 1 -else - echo Success -fi - -echo -n "Running tests for Python 2.5... " -python2.5 -Wd runtests.py -q 2> /dev/null -if [ $? -ne 0 ];then - echo Failed - exit 1 -else - echo Success -fi - -echo -n "Running tests for Python 2.6... " -python2.6 -Wd runtests.py -q 2> /dev/null -if [ $? -ne 0 ];then - echo Failed - exit 1 -else - echo Success -fi - -echo -n "Running tests for Python 2.7... " -python2.7 -Wd -bb -3 runtests.py -q 2> /dev/null -if [ $? -ne 0 ];then - echo Failed - exit 1 -else - echo Success -fi -echo "Good job, commit now! (or add tests)" |
