From 71bea435b6f73644d5d7320001ac56d78bcc4687 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Sun, 21 Jul 2013 09:58:36 -0700 Subject: Move d2to1 more into the source tree When we merged in d2to1, we kept it separate, but I don't think there is a great benefit to doing that. Change-Id: I3972b3132619e8e2dd7e362ca5fe9d1e3add43b8 --- pbr/core.py | 2 +- pbr/d2to1/__init__.py | 0 pbr/d2to1/tests/__init__.py | 86 --- pbr/d2to1/tests/test_commands.py | 58 -- pbr/d2to1/tests/test_core.py | 75 --- pbr/d2to1/tests/test_hooks.py | 93 --- pbr/d2to1/tests/testpackage/CHANGES.txt | 86 --- pbr/d2to1/tests/testpackage/LICENSE.txt | 29 - pbr/d2to1/tests/testpackage/MANIFEST.in | 1 - pbr/d2to1/tests/testpackage/README.txt | 148 ----- .../testpackage/d2to1_testpackage/__init__.py | 0 .../testpackage/d2to1_testpackage/_setup_hooks.py | 65 --- .../d2to1_testpackage/package_data/1.txt | 0 .../d2to1_testpackage/package_data/2.txt | 0 pbr/d2to1/tests/testpackage/data_files/a.txt | 0 pbr/d2to1/tests/testpackage/data_files/b.txt | 0 pbr/d2to1/tests/testpackage/data_files/c.rst | 0 pbr/d2to1/tests/testpackage/extra-file.txt | 0 pbr/d2to1/tests/testpackage/setup.cfg | 46 -- pbr/d2to1/tests/testpackage/setup.py | 22 - pbr/d2to1/tests/testpackage/src/testext.c | 28 - pbr/d2to1/tests/util.py | 74 --- pbr/d2to1/util.py | 628 --------------------- pbr/tests/__init__.py | 63 +++ pbr/tests/test_commands.py | 58 ++ pbr/tests/test_core.py | 75 +++ pbr/tests/test_hooks.py | 91 +++ pbr/tests/testpackage/CHANGES.txt | 86 +++ pbr/tests/testpackage/LICENSE.txt | 29 + pbr/tests/testpackage/MANIFEST.in | 1 + pbr/tests/testpackage/README.txt | 148 +++++ pbr/tests/testpackage/data_files/a.txt | 0 pbr/tests/testpackage/data_files/b.txt | 0 pbr/tests/testpackage/data_files/c.rst | 0 pbr/tests/testpackage/extra-file.txt | 0 pbr/tests/testpackage/pbr_testpackage/__init__.py | 0 .../testpackage/pbr_testpackage/_setup_hooks.py | 65 +++ .../testpackage/pbr_testpackage/package_data/1.txt | 0 .../testpackage/pbr_testpackage/package_data/2.txt | 0 pbr/tests/testpackage/setup.cfg | 46 ++ pbr/tests/testpackage/setup.py | 22 + pbr/tests/testpackage/src/testext.c | 28 + pbr/tests/util.py | 74 +++ pbr/util.py | 628 +++++++++++++++++++++ setup.py | 2 +- tools/integration.sh | 2 +- 46 files changed, 1417 insertions(+), 1442 deletions(-) delete mode 100644 pbr/d2to1/__init__.py delete mode 100644 pbr/d2to1/tests/__init__.py delete mode 100644 pbr/d2to1/tests/test_commands.py delete mode 100644 pbr/d2to1/tests/test_core.py delete mode 100644 pbr/d2to1/tests/test_hooks.py delete mode 100644 pbr/d2to1/tests/testpackage/CHANGES.txt delete mode 100644 pbr/d2to1/tests/testpackage/LICENSE.txt delete mode 100644 pbr/d2to1/tests/testpackage/MANIFEST.in delete mode 100644 pbr/d2to1/tests/testpackage/README.txt delete mode 100644 pbr/d2to1/tests/testpackage/d2to1_testpackage/__init__.py delete mode 100644 pbr/d2to1/tests/testpackage/d2to1_testpackage/_setup_hooks.py delete mode 100644 pbr/d2to1/tests/testpackage/d2to1_testpackage/package_data/1.txt delete mode 100644 pbr/d2to1/tests/testpackage/d2to1_testpackage/package_data/2.txt delete mode 100644 pbr/d2to1/tests/testpackage/data_files/a.txt delete mode 100644 pbr/d2to1/tests/testpackage/data_files/b.txt delete mode 100644 pbr/d2to1/tests/testpackage/data_files/c.rst delete mode 100644 pbr/d2to1/tests/testpackage/extra-file.txt delete mode 100644 pbr/d2to1/tests/testpackage/setup.cfg delete mode 100755 pbr/d2to1/tests/testpackage/setup.py delete mode 100644 pbr/d2to1/tests/testpackage/src/testext.c delete mode 100644 pbr/d2to1/tests/util.py delete mode 100644 pbr/d2to1/util.py create mode 100644 pbr/tests/test_commands.py create mode 100644 pbr/tests/test_core.py create mode 100644 pbr/tests/test_hooks.py create mode 100644 pbr/tests/testpackage/CHANGES.txt create mode 100644 pbr/tests/testpackage/LICENSE.txt create mode 100644 pbr/tests/testpackage/MANIFEST.in create mode 100644 pbr/tests/testpackage/README.txt create mode 100644 pbr/tests/testpackage/data_files/a.txt create mode 100644 pbr/tests/testpackage/data_files/b.txt create mode 100644 pbr/tests/testpackage/data_files/c.rst create mode 100644 pbr/tests/testpackage/extra-file.txt create mode 100644 pbr/tests/testpackage/pbr_testpackage/__init__.py create mode 100644 pbr/tests/testpackage/pbr_testpackage/_setup_hooks.py create mode 100644 pbr/tests/testpackage/pbr_testpackage/package_data/1.txt create mode 100644 pbr/tests/testpackage/pbr_testpackage/package_data/2.txt create mode 100644 pbr/tests/testpackage/setup.cfg create mode 100755 pbr/tests/testpackage/setup.py create mode 100644 pbr/tests/testpackage/src/testext.c create mode 100644 pbr/tests/util.py create mode 100644 pbr/util.py diff --git a/pbr/core.py b/pbr/core.py index 8cee9b0..3e398c3 100644 --- a/pbr/core.py +++ b/pbr/core.py @@ -46,7 +46,7 @@ import warnings from setuptools import dist -from pbr.d2to1 import util +from pbr import util core.Distribution = dist._get_unpatched(core.Distribution) diff --git a/pbr/d2to1/__init__.py b/pbr/d2to1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pbr/d2to1/tests/__init__.py b/pbr/d2to1/tests/__init__.py deleted file mode 100644 index c9144bb..0000000 --- a/pbr/d2to1/tests/__init__.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Copyright (C) 2013 Association of Universities for Research in Astronomy -# (AURA) -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# 3. The name of AURA and its representatives may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - -import os -import shutil -import subprocess -import sys - -import fixtures -import testtools - - -class D2to1TestCase(testtools.TestCase): - def setUp(self): - super(D2to1TestCase, self).setUp() - self.temp_dir = self.useFixture(fixtures.TempDir()).path - self.package_dir = os.path.join(self.temp_dir, 'testpackage') - shutil.copytree(os.path.join(os.path.dirname(__file__), 'testpackage'), - self.package_dir) - self.addCleanup(os.chdir, os.getcwd()) - os.chdir(self.package_dir) - - def tearDown(self): - # Remove d2to1.testpackage from sys.modules so that it can be freshly - # re-imported by the next test - for k in list(sys.modules): - if (k == 'd2to1_testpackage' or - k.startswith('d2to1_testpackage.')): - del sys.modules[k] - super(D2to1TestCase, self).tearDown() - - def run_setup(self, *args): - return self._run_cmd(sys.executable, ('setup.py',) + args) - - def _run_cmd(self, cmd, args): - """Run a command in the root of the test working copy. - - Runs a command, with the given argument list, in the root of the test - working copy--returns the stdout and stderr streams and the exit code - from the subprocess. - """ - - os.chdir(self.package_dir) - p = subprocess.Popen([cmd] + list(args), stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - - streams = tuple(s.decode('latin1').strip() for s in p.communicate()) - print(streams) - return (streams) + (p.returncode,) diff --git a/pbr/d2to1/tests/test_commands.py b/pbr/d2to1/tests/test_commands.py deleted file mode 100644 index 6dbbd3c..0000000 --- a/pbr/d2to1/tests/test_commands.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Copyright (C) 2013 Association of Universities for Research in Astronomy -# (AURA) -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# 3. The name of AURA and its representatives may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - -from testtools import content - -from pbr.d2to1 import tests - - -class TestCommands(tests.D2to1TestCase): - def test_custom_build_py_command(self): - """Test custom build_py command. - - Test that a custom subclass of the build_py command runs when listed in - the commands [global] option, rather than the normal build command. - """ - - stdout, stderr, return_code = self.run_setup('build_py') - self.addDetail('stdout', content.text_content(stdout)) - self.addDetail('stderr', content.text_content(stderr)) - self.assertIn('Running custom build_py command.', stdout) - self.assertEqual(return_code, 0) diff --git a/pbr/d2to1/tests/test_core.py b/pbr/d2to1/tests/test_core.py deleted file mode 100644 index 092eca8..0000000 --- a/pbr/d2to1/tests/test_core.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Copyright (C) 2013 Association of Universities for Research in Astronomy -# (AURA) -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# 3. The name of AURA and its representatives may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - -import glob -import os -import tarfile - -from pbr.d2to1 import tests - - -class TestCore(tests.D2to1TestCase): - - def test_setup_py_keywords(self): - """setup.py --keywords. - - Test that the `./setup.py --keywords` command returns the correct - value without balking. - """ - - self.run_setup('egg_info') - stdout, _, _ = self.run_setup('--keywords') - assert stdout == 'packaging,distutils,setuptools' - - def test_sdist_extra_files(self): - """Test that the extra files are correctly added.""" - - stdout, _, return_code = self.run_setup('sdist', '--formats=gztar') - - # There can be only one - try: - tf_path = glob.glob(os.path.join('dist', '*.tar.gz'))[0] - except IndexError: - assert False, 'source dist not found' - - tf = tarfile.open(tf_path) - names = ['/'.join(p.split('/')[1:]) for p in tf.getnames()] - - assert 'extra-file.txt' in names diff --git a/pbr/d2to1/tests/test_hooks.py b/pbr/d2to1/tests/test_hooks.py deleted file mode 100644 index a9e9864..0000000 --- a/pbr/d2to1/tests/test_hooks.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Copyright (C) 2013 Association of Universities for Research in Astronomy -# (AURA) -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# 3. The name of AURA and its representatives may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - -import os -import textwrap - -from pbr.d2to1 import tests -from pbr.d2to1.tests import util - - -class TestHooks(tests.D2to1TestCase): - def setUp(self): - super(TestHooks, self).setUp() - with util.open_config( - os.path.join(self.package_dir, 'setup.cfg')) as cfg: - cfg.set('global', 'setup-hooks', - 'd2to1_testpackage._setup_hooks.test_hook_1\n' - 'd2to1_testpackage._setup_hooks.test_hook_2') - cfg.set('build_ext', 'pre-hook.test_pre_hook', - 'd2to1_testpackage._setup_hooks.test_pre_hook') - cfg.set('build_ext', 'post-hook.test_post_hook', - 'd2to1_testpackage._setup_hooks.test_post_hook') - - def test_global_setup_hooks(self): - """Test setup_hooks. - - Test that setup_hooks listed in the [global] section of setup.cfg are - executed in order. - """ - - stdout, _, return_code = self.run_setup('egg_info') - assert 'test_hook_1\ntest_hook_2' in stdout - assert return_code == 0 - - def test_command_hooks(self): - """Test command hooks. - - Simple test that the appropriate command hooks run at the - beginning/end of the appropriate command. - """ - - stdout, _, return_code = self.run_setup('egg_info') - assert 'build_ext pre-hook' not in stdout - assert 'build_ext post-hook' not in stdout - assert return_code == 0 - - stdout, _, return_code = self.run_setup('build_ext') - assert textwrap.dedent(""" - running build_ext - running pre_hook d2to1_testpackage._setup_hooks.test_pre_hook for command build_ext - build_ext pre-hook - """) in stdout # flake8: noqa - assert stdout.endswith('build_ext post-hook') - assert return_code == 0 - - diff --git a/pbr/d2to1/tests/testpackage/CHANGES.txt b/pbr/d2to1/tests/testpackage/CHANGES.txt deleted file mode 100644 index 709b9d4..0000000 --- a/pbr/d2to1/tests/testpackage/CHANGES.txt +++ /dev/null @@ -1,86 +0,0 @@ -Changelog -=========== - -0.3 (unreleased) ------------------- - -- The ``glob_data_files`` hook became a pre-command hook for the install_data - command instead of being a setup-hook. This is to support the additional - functionality of requiring data_files with relative destination paths to be - install relative to the package's install path (i.e. site-packages). - -- Dropped support for and deprecated the easier_install custom command. - Although it should still work, it probably won't be used anymore for - stsci_python packages. - -- Added support for the ``build_optional_ext`` command, which replaces/extends - the default ``build_ext`` command. See the README for more details. - -- Added the ``tag_svn_revision`` setup_hook as a replacement for the - setuptools-specific tag_svn_revision option to the egg_info command. This - new hook is easier to use than the old tag_svn_revision option: It's - automatically enabled by the presence of ``.dev`` in the version string, and - disabled otherwise. - -- The ``svn_info_pre_hook`` and ``svn_info_post_hook`` have been replaced with - ``version_pre_command_hook`` and ``version_post_command_hook`` respectively. - However, a new ``version_setup_hook``, which has the same purpose, has been - added. It is generally easier to use and will give more consistent results - in that it will run every time setup.py is run, regardless of which command - is used. ``stsci.distutils`` itself uses this hook--see the `setup.cfg` file - and `stsci/distutils/__init__.py` for example usage. - -- Instead of creating an `svninfo.py` module, the new ``version_`` hooks create - a file called `version.py`. In addition to the SVN info that was included - in `svninfo.py`, it includes a ``__version__`` variable to be used by the - package's `__init__.py`. This allows there to be a hard-coded - ``__version__`` variable included in the source code, rather than using - pkg_resources to get the version. - -- In `version.py`, the variables previously named ``__svn_version__`` and - ``__full_svn_info__`` are now named ``__svn_revision__`` and - ``__svn_full_info__``. - -- Fixed a bug when using stsci.distutils in the installation of other packages - in the ``stsci.*`` namespace package. If stsci.distutils was not already - installed, and was downloaded automatically by distribute through the - setup_requires option, then ``stsci.distutils`` would fail to import. This - is because the way the namespace package (nspkg) mechanism currently works, - all packages belonging to the nspkg *must* be on the import path at initial - import time. - - So when installing stsci.tools, for example, if ``stsci.tools`` is imported - from within the source code at install time, but before ``stsci.distutils`` - is downloaded and added to the path, the ``stsci`` package is already - imported and can't be extended to include the path of ``stsci.distutils`` - after the fact. The easiest way of dealing with this, it seems, is to - delete ``stsci`` from ``sys.modules``, which forces it to be reimported, now - the its ``__path__`` extended to include ``stsci.distutil``'s path. - - -0.2.2 (2011-11-09) ------------------- - -- Fixed check for the issue205 bug on actual setuptools installs; before it - only worked on distribute. setuptools has the issue205 bug prior to version - 0.6c10. - -- Improved the fix for the issue205 bug, especially on setuptools. - setuptools, prior to 0.6c10, did not back of sys.modules either before - sandboxing, which causes serious problems. In fact, it's so bad that it's - not enough to add a sys.modules backup to the current sandbox: It's in fact - necessary to monkeypatch setuptools.sandbox.run_setup so that any subsequent - calls to it also back up sys.modules. - - -0.2.1 (2011-09-02) ------------------- - -- Fixed the dependencies so that setuptools is requirement but 'distribute' - specifically. Previously installation could fail if users had plain - setuptools installed and not distribute - -0.2 (2011-08-23) ------------------- - -- Initial public release diff --git a/pbr/d2to1/tests/testpackage/LICENSE.txt b/pbr/d2to1/tests/testpackage/LICENSE.txt deleted file mode 100644 index 7e8019a..0000000 --- a/pbr/d2to1/tests/testpackage/LICENSE.txt +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (C) 2005 Association of Universities for Research in Astronomy (AURA) - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - 3. The name of AURA and its representatives may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - diff --git a/pbr/d2to1/tests/testpackage/MANIFEST.in b/pbr/d2to1/tests/testpackage/MANIFEST.in deleted file mode 100644 index cdc95ea..0000000 --- a/pbr/d2to1/tests/testpackage/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include data_files/* diff --git a/pbr/d2to1/tests/testpackage/README.txt b/pbr/d2to1/tests/testpackage/README.txt deleted file mode 100644 index 4f00d32..0000000 --- a/pbr/d2to1/tests/testpackage/README.txt +++ /dev/null @@ -1,148 +0,0 @@ -Introduction -============ -This package contains utilities used to package some of STScI's Python -projects; specifically those projects that comprise stsci_python_ and -Astrolib_. - -It currently consists mostly of some setup_hook scripts meant for use with -`distutils2/packaging`_ and/or d2to1_, and a customized easy_install command -meant for use with distribute_. - -This package is not meant for general consumption, though it might be worth -looking at for examples of how to do certain things with your own packages, but -YMMV. - -Features -======== - -Hook Scripts ------------- -Currently the main features of this package are a couple of setup_hook scripts. -In distutils2, a setup_hook is a script that runs at the beginning of any -pysetup command, and can modify the package configuration read from setup.cfg. -There are also pre- and post-command hooks that only run before/after a -specific setup command (eg. build_ext, install) is run. - -stsci.distutils.hooks.use_packages_root -''''''''''''''''''''''''''''''''''''''' -If using the ``packages_root`` option under the ``[files]`` section of -setup.cfg, this hook will add that path to ``sys.path`` so that modules in your -package can be imported and used in setup. This can be used even if -``packages_root`` is not specified--in this case it adds ``''`` to -``sys.path``. - -stsci.distutils.hooks.version_setup_hook -'''''''''''''''''''''''''''''''''''''''' -Creates a Python module called version.py which currently contains four -variables: - -* ``__version__`` (the release version) -* ``__svn_revision__`` (the SVN revision info as returned by the ``svnversion`` - command) -* ``__svn_full_info__`` (as returned by the ``svn info`` command) -* ``__setup_datetime__`` (the date and time that setup.py was last run). - -These variables can be imported in the package's `__init__.py` for degugging -purposes. The version.py module will *only* be created in a package that -imports from the version module in its `__init__.py`. It should be noted that -this is generally preferable to writing these variables directly into -`__init__.py`, since this provides more control and is less likely to -unexpectedly break things in `__init__.py`. - -stsci.distutils.hooks.version_pre_command_hook -'''''''''''''''''''''''''''''''''''''''''''''' -Identical to version_setup_hook, but designed to be used as a pre-command -hook. - -stsci.distutils.hooks.version_post_command_hook -''''''''''''''''''''''''''''''''''''''''''''''' -The complement to version_pre_command_hook. This will delete any version.py -files created during a build in order to prevent them from cluttering an SVN -working copy (note, however, that version.py is *not* deleted from the build/ -directory, so a copy of it is still preserved). It will also not be deleted -if the current directory is not an SVN working copy. For example, if source -code extracted from a source tarball it will be preserved. - -stsci.distutils.hooks.tag_svn_revision -'''''''''''''''''''''''''''''''''''''' -A setup_hook to add the SVN revision of the current working copy path to the -package version string, but only if the version ends in .dev. - -For example, ``mypackage-1.0.dev`` becomes ``mypackage-1.0.dev1234``. This is -in accordance with the version string format standardized by PEP 386. - -This should be used as a replacement for the ``tag_svn_revision`` option to -the egg_info command. This hook is more compatible with packaging/distutils2, -which does not include any VCS support. This hook is also more flexible in -that it turns the revision number on/off depending on the presence of ``.dev`` -in the version string, so that it's not automatically added to the version in -final releases. - -This hook does require the ``svnversion`` command to be available in order to -work. It does not examine the working copy metadata directly. - -stsci.distutils.hooks.numpy_extension_hook -'''''''''''''''''''''''''''''''''''''''''' -This is a pre-command hook for the build_ext command. To use it, add a -``[build_ext]`` section to your setup.cfg, and add to it:: - - pre-hook.numpy-extension-hook = stsci.distutils.hooks.numpy_extension_hook - -This hook must be used to build extension modules that use Numpy. The primary -side-effect of this hook is to add the correct numpy include directories to -`include_dirs`. To use it, add 'numpy' to the 'include-dirs' option of each -extension module that requires numpy to build. The value 'numpy' will be -replaced with the actual path to the numpy includes. - -stsci.distutils.hooks.is_display_option -''''''''''''''''''''''''''''''''''''''' -This is not actually a hook, but is a useful utility function that can be used -in writing other hooks. Basically, it returns ``True`` if setup.py was run -with a "display option" such as --version or --help. This can be used to -prevent your hook from running in such cases. - -stsci.distutils.hooks.glob_data_files -''''''''''''''''''''''''''''''''''''' -A pre-command hook for the install_data command. Allows filename wildcards as -understood by ``glob.glob()`` to be used in the data_files option. This hook -must be used in order to have this functionality since it does not normally -exist in distutils. - -This hook also ensures that data files are installed relative to the package -path. data_files shouldn't normally be installed this way, but the -functionality is required for a few special cases. - - -Commands --------- -build_optional_ext -'''''''''''''''''' -This serves as an optional replacement for the default built_ext command, -which compiles C extension modules. Its purpose is to allow extension modules -to be *optional*, so that if their build fails the rest of the package is -still allowed to be built and installed. This can be used when an extension -module is not definitely required to use the package. - -To use this custom command, add:: - - commands = stsci.distutils.command.build_optional_ext.build_optional_ext - -under the ``[global]`` section of your package's setup.cfg. Then, to mark -an individual extension module as optional, under the setup.cfg section for -that extension add:: - - optional = True - -Optionally, you may also add a custom failure message by adding:: - - fail_message = The foobar extension module failed to compile. - This could be because you lack such and such headers. - This package will still work, but such and such features - will be disabled. - - -.. _stsci_python: http://www.stsci.edu/resources/software_hardware/pyraf/stsci_python -.. _Astrolib: http://www.scipy.org/AstroLib/ -.. _distutils2/packaging: http://distutils2.notmyidea.org/ -.. _d2to1: http://pypi.python.org/pypi/d2to1 -.. _distribute: http://pypi.python.org/pypi/distribute diff --git a/pbr/d2to1/tests/testpackage/d2to1_testpackage/__init__.py b/pbr/d2to1/tests/testpackage/d2to1_testpackage/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pbr/d2to1/tests/testpackage/d2to1_testpackage/_setup_hooks.py b/pbr/d2to1/tests/testpackage/d2to1_testpackage/_setup_hooks.py deleted file mode 100644 index f8b3087..0000000 --- a/pbr/d2to1/tests/testpackage/d2to1_testpackage/_setup_hooks.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Copyright (C) 2013 Association of Universities for Research in Astronomy -# (AURA) -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# 3. The name of AURA and its representatives may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - -from distutils.command import build_py - - -def test_hook_1(config): - print('test_hook_1') - - -def test_hook_2(config): - print('test_hook_2') - - -class test_command(build_py.build_py): - command_name = 'build_py' - - def run(self): - print('Running custom build_py command.') - return build_py.build_py.run(self) - - -def test_pre_hook(cmdobj): - print('build_ext pre-hook') - - -def test_post_hook(cmdobj): - print('build_ext post-hook') diff --git a/pbr/d2to1/tests/testpackage/d2to1_testpackage/package_data/1.txt b/pbr/d2to1/tests/testpackage/d2to1_testpackage/package_data/1.txt deleted file mode 100644 index e69de29..0000000 diff --git a/pbr/d2to1/tests/testpackage/d2to1_testpackage/package_data/2.txt b/pbr/d2to1/tests/testpackage/d2to1_testpackage/package_data/2.txt deleted file mode 100644 index e69de29..0000000 diff --git a/pbr/d2to1/tests/testpackage/data_files/a.txt b/pbr/d2to1/tests/testpackage/data_files/a.txt deleted file mode 100644 index e69de29..0000000 diff --git a/pbr/d2to1/tests/testpackage/data_files/b.txt b/pbr/d2to1/tests/testpackage/data_files/b.txt deleted file mode 100644 index e69de29..0000000 diff --git a/pbr/d2to1/tests/testpackage/data_files/c.rst b/pbr/d2to1/tests/testpackage/data_files/c.rst deleted file mode 100644 index e69de29..0000000 diff --git a/pbr/d2to1/tests/testpackage/extra-file.txt b/pbr/d2to1/tests/testpackage/extra-file.txt deleted file mode 100644 index e69de29..0000000 diff --git a/pbr/d2to1/tests/testpackage/setup.cfg b/pbr/d2to1/tests/testpackage/setup.cfg deleted file mode 100644 index a200616..0000000 --- a/pbr/d2to1/tests/testpackage/setup.cfg +++ /dev/null @@ -1,46 +0,0 @@ -[metadata] -name = d2to1_testpackage -version = 0.1.dev -author = Erik M. Bray -author-email = embray@stsci.edu -home-page = http://www.stsci.edu/resources/software_hardware/stsci_python -summary = Test package for testing d2to1 -description-file = - README.txt - CHANGES.txt -requires-python = >=2.5 - -requires-dist = - setuptools - -classifier = - Development Status :: 3 - Alpha - Intended Audience :: Developers - License :: OSI Approved :: BSD License - Programming Language :: Python - Topic :: Scientific/Engineering - Topic :: Software Development :: Build Tools - Topic :: Software Development :: Libraries :: Python Modules - Topic :: System :: Archiving :: Packaging - -keywords = packaging, distutils, setuptools - -[files] -packages = d2to1_testpackage -package-data = testpackage = package_data/*.txt -data-files = testpackage/data_files = data_files/*.txt -extra-files = extra-file.txt - -[extension=d2to1_testpackage.testext] -sources = src/testext.c -optional = True - -[global] -#setup-hooks = -# d2to1_testpackage._setup_hooks.test_hook_1 -# d2to1_testpackage._setup_hooks.test_hook_2 -commands = d2to1_testpackage._setup_hooks.test_command - -[build_ext] -#pre-hook.test_pre_hook = d2to1_testpackage._setup_hooks.test_pre_hook -#post-hook.test_post_hook = d2to1_testpackage._setup_hooks.test_post_hook diff --git a/pbr/d2to1/tests/testpackage/setup.py b/pbr/d2to1/tests/testpackage/setup.py deleted file mode 100755 index 8866691..0000000 --- a/pbr/d2to1/tests/testpackage/setup.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import setuptools - -setuptools.setup( - setup_requires=['pbr'], - pbr=True, -) diff --git a/pbr/d2to1/tests/testpackage/src/testext.c b/pbr/d2to1/tests/testpackage/src/testext.c deleted file mode 100644 index 872d43c..0000000 --- a/pbr/d2to1/tests/testpackage/src/testext.c +++ /dev/null @@ -1,28 +0,0 @@ -#include - - -static PyMethodDef TestextMethods[] = { - {NULL, NULL, 0, NULL} -}; - - -#if PY_MAJOR_VERSION >=3 -static struct PyModuleDef testextmodule = { - PyModuleDef_HEAD_INIT, - "testext", - -1, - TestextMethods -}; - -PyObject* -PyInit_testext(void) -{ - return PyModule_Create(&testextmodule); -} -#else -PyMODINIT_FUNC -inittestext(void) -{ - Py_InitModule("testext", TestextMethods); -} -#endif diff --git a/pbr/d2to1/tests/util.py b/pbr/d2to1/tests/util.py deleted file mode 100644 index e657508..0000000 --- a/pbr/d2to1/tests/util.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Copyright (C) 2013 Association of Universities for Research in Astronomy -# (AURA) -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# 3. The name of AURA and its representatives may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - -import contextlib -import os -import shutil -import stat - -try: - import configparser -except ImportError: - import ConfigParser as configparser - - -@contextlib.contextmanager -def open_config(filename): - cfg = configparser.ConfigParser() - cfg.read(filename) - yield cfg - with open(filename, 'w') as fp: - cfg.write(fp) - - -def rmtree(path): - """shutil.rmtree() with error handler. - - Handle 'access denied' from trying to delete read-only files. - """ - - def onerror(func, path, exc_info): - if not os.access(path, os.W_OK): - os.chmod(path, stat.S_IWUSR) - func(path) - else: - raise - - return shutil.rmtree(path, onerror=onerror) diff --git a/pbr/d2to1/util.py b/pbr/d2to1/util.py deleted file mode 100644 index c421014..0000000 --- a/pbr/d2to1/util.py +++ /dev/null @@ -1,628 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Copyright (C) 2013 Association of Universities for Research in Astronomy -# (AURA) -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# -# 3. The name of AURA and its representatives may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED -# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - -"""The code in this module is mostly copy/pasted out of the distutils2 source -code, as recommended by Tarek Ziade. As such, it may be subject to some change -as distutils2 development continues, and will have to be kept up to date. - -I didn't want to use it directly from distutils2 itself, since I do not want it -to be an installation dependency for our packages yet--it is still too unstable -(the latest version on PyPI doesn't even install). -""" - -# These first two imports are not used, but are needed to get around an -# irritating Python bug that can crop up when using ./setup.py test. -# See: http://www.eby-sarna.com/pipermail/peak/2010-May/003355.html -try: - import multiprocessing # flake8: noqa -except ImportError: - pass -import logging # flake8: noqa - -import os -import re -import sys -import traceback - -from collections import defaultdict - -import distutils.ccompiler - -from distutils import log -from distutils.errors import (DistutilsOptionError, DistutilsModuleError, - DistutilsFileError) -from setuptools.command.egg_info import manifest_maker -from setuptools.dist import Distribution -from setuptools.extension import Extension - -try: - import configparser -except ImportError: - import ConfigParser as configparser - - -# A simplified RE for this; just checks that the line ends with version -# predicates in () -_VERSION_SPEC_RE = re.compile(r'\s*(.*?)\s*\((.*)\)\s*$') - - -# Mappings from setup() keyword arguments to setup.cfg options; -# The values are (section, option) tuples, or simply (section,) tuples if -# the option has the same name as the setup() argument -D1_D2_SETUP_ARGS = { - "name": ("metadata",), - "version": ("metadata",), - "author": ("metadata",), - "author_email": ("metadata",), - "maintainer": ("metadata",), - "maintainer_email": ("metadata",), - "url": ("metadata", "home_page"), - "description": ("metadata", "summary"), - "keywords": ("metadata",), - "long_description": ("metadata", "description"), - "download-url": ("metadata",), - "classifiers": ("metadata", "classifier"), - "platforms": ("metadata", "platform"), # ** - "license": ("metadata",), - # Use setuptools install_requires, not - # broken distutils requires - "install_requires": ("metadata", "requires_dist"), - "setup_requires": ("metadata", "setup_requires_dist"), - "provides": ("metadata", "provides_dist"), # ** - "obsoletes": ("metadata", "obsoletes_dist"), # ** - "package_dir": ("files", 'packages_root'), - "packages": ("files",), - "package_data": ("files",), - "namespace_packages": ("files",), - "data_files": ("files",), - "scripts": ("files",), - "py_modules": ("files", "modules"), # ** - "cmdclass": ("global", "commands"), - # Not supported in distutils2, but provided for - # backwards compatibility with setuptools - "use_2to3": ("backwards_compat", "use_2to3"), - "zip_safe": ("backwards_compat", "zip_safe"), - "tests_require": ("backwards_compat", "tests_require"), - "dependency_links": ("backwards_compat",), - "include_package_data": ("backwards_compat",), -} - -# setup() arguments that can have multiple values in setup.cfg -MULTI_FIELDS = ("classifiers", - "platforms", - "install_requires", - "provides", - "obsoletes", - "namespace_packages", - "packages", - "package_data", - "data_files", - "scripts", - "py_modules", - "dependency_links", - "setup_requires", - "tests_require", - "cmdclass") - -# setup() arguments that contain boolean values -BOOL_FIELDS = ("use_2to3", "zip_safe", "include_package_data") - - -CSV_FIELDS = ("keywords",) - - -log.set_verbosity(log.INFO) - - -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) - 1 - module_name = parts[:cursor] - attr_name = parts[-1] - - while cursor > 0: - try: - ret = __import__('.'.join(module_name), fromlist=[attr_name]) - break - except ImportError: - if cursor == 0: - raise - cursor -= 1 - module_name = parts[:cursor] - attr_name = parts[cursor] - ret = '' - - for part in parts[cursor:]: - try: - ret = getattr(ret, part) - except AttributeError: - raise ImportError(name) - - return ret - - -def cfg_to_args(path='setup.cfg'): - """ Distutils2 to distutils1 compatibility util. - - This method uses an existing setup.cfg to generate a dictionary of - keywords that can be used by distutils.core.setup(kwargs**). - - :param file: - The setup.cfg path. - :raises DistutilsFileError: - When the setup.cfg file is not found. - - """ - - # The method source code really starts here. - parser = configparser.RawConfigParser() - if not os.path.exists(path): - raise DistutilsFileError("file '%s' does not exist" % - os.path.abspath(path)) - parser.read(path) - config = {} - for section in parser.sections(): - config[section] = dict(parser.items(section)) - - # Run setup_hooks, if configured - setup_hooks = has_get_option(config, 'global', 'setup_hooks') - package_dir = has_get_option(config, 'files', 'packages_root') - - # Add the source package directory to sys.path in case it contains - # additional hooks, and to make sure it's on the path before any existing - # installations of the package - if package_dir: - package_dir = os.path.abspath(package_dir) - sys.path.insert(0, package_dir) - - try: - if setup_hooks: - setup_hooks = split_multiline(setup_hooks) - for hook in setup_hooks: - hook_fn = resolve_name(hook) - try : - hook_fn(config) - except SystemExit: - log.error('setup hook %s terminated the installation') - except: - e = sys.exc_info()[1] - log.error('setup hook %s raised exception: %s\n' % - (hook, e)) - log.error(traceback.format_exc()) - sys.exit(1) - - kwargs = setup_cfg_to_setup_kwargs(config) - - # Set default config overrides - kwargs['include_package_data'] = True - kwargs['zip_safe'] = False - - register_custom_compilers(config) - - ext_modules = get_extension_modules(config) - if ext_modules: - kwargs['ext_modules'] = ext_modules - - entry_points = get_entry_points(config) - if entry_points: - kwargs['entry_points'] = entry_points - - wrap_commands(kwargs) - - # Handle the [files]/extra_files option - extra_files = has_get_option(config, 'files', 'extra_files') - if extra_files: - extra_files = split_multiline(extra_files) - # Let's do a sanity check - for filename in extra_files: - if not os.path.exists(filename): - raise DistutilsFileError( - '%s from the extra_files option in setup.cfg does not ' - 'exist' % filename) - # Unfortunately the only really sensible way to do this is to - # monkey-patch the manifest_maker class - @monkeypatch_method(manifest_maker) - def add_defaults(self, extra_files=extra_files, log=log): - log.info('[d2to1] running patched manifest_maker command ' - 'with extra_files support') - add_defaults._orig(self) - self.filelist.extend(extra_files) - - finally: - # Perform cleanup if any paths were added to sys.path - if package_dir: - sys.path.pop(0) - - return kwargs - - -def setup_cfg_to_setup_kwargs(config): - """Processes the setup.cfg options and converts them to arguments accepted - by setuptools' setup() function. - """ - - kwargs = {} - - for arg in D1_D2_SETUP_ARGS: - if len(D1_D2_SETUP_ARGS[arg]) == 2: - # The distutils field name is different than distutils2's. - section, option = D1_D2_SETUP_ARGS[arg] - - elif len(D1_D2_SETUP_ARGS[arg]) == 1: - # The distutils field name is the same thant distutils2's. - section = D1_D2_SETUP_ARGS[arg][0] - option = arg - - in_cfg_value = has_get_option(config, section, option) - if not in_cfg_value: - # There is no such option in the setup.cfg - if arg == "long_description": - in_cfg_value = has_get_option(config, section, - "description_file") - if in_cfg_value: - in_cfg_value = split_multiline(in_cfg_value) - value = '' - for filename in in_cfg_value: - description_file = open(filename) - try: - value += description_file.read().strip() + '\n\n' - finally: - description_file.close() - in_cfg_value = value - else: - continue - - if arg in CSV_FIELDS: - in_cfg_value = split_csv(in_cfg_value) - if arg in MULTI_FIELDS: - in_cfg_value = split_multiline(in_cfg_value) - elif arg in BOOL_FIELDS: - # Provide some flexibility here... - if in_cfg_value.lower() in ('true', 't', '1', 'yes', 'y'): - in_cfg_value = True - else: - in_cfg_value = False - - if in_cfg_value: - if arg in ('install_requires', 'tests_require'): - # Replaces PEP345-style version specs with the sort expected by - # setuptools - in_cfg_value = [_VERSION_SPEC_RE.sub(r'\1\2', pred) - for pred in in_cfg_value] - elif arg == 'package_dir': - in_cfg_value = {'': in_cfg_value} - elif arg in ('package_data', 'data_files'): - data_files = {} - firstline = True - prev = None - for line in in_cfg_value: - if '=' in line: - key, value = line.split('=', 1) - key, value = (key.strip(), value.strip()) - if key in data_files: - # Multiple duplicates of the same package name; - # this is for backwards compatibility of the old - # format prior to d2to1 0.2.6. - prev = data_files[key] - prev.extend(value.split()) - else: - prev = data_files[key.strip()] = value.split() - elif firstline: - raise DistutilsOptionError( - 'malformed package_data first line %r (misses ' - '"=")' % line) - else: - prev.extend(line.strip().split()) - firstline = False - if arg == 'data_files': - # the data_files value is a pointlessly different structure - # from the package_data value - data_files = data_files.items() - in_cfg_value = data_files - elif arg == 'cmdclass': - cmdclass = {} - dist = Distribution() - for cls in in_cfg_value: - cls = resolve_name(cls) - cmd = cls(dist) - cmdclass[cmd.get_command_name()] = cls - in_cfg_value = cmdclass - - kwargs[arg] = in_cfg_value - - return kwargs - - -def register_custom_compilers(config): - """Handle custom compilers; this has no real equivalent in distutils, where - additional compilers could only be added programmatically, so we have to - hack it in somehow. - """ - - compilers = has_get_option(config, 'global', 'compilers') - if compilers: - compilers = split_multiline(compilers) - for compiler in compilers: - compiler = resolve_name(compiler) - - # In distutils2 compilers these class attributes exist; for - # distutils1 we just have to make something up - if hasattr(compiler, 'name'): - name = compiler.name - else: - name = compiler.__name__ - if hasattr(compiler, 'description'): - desc = compiler.description - else: - desc = 'custom compiler %s' % name - - module_name = compiler.__module__ - # Note; this *will* override built in compilers with the same name - # TODO: Maybe display a warning about this? - cc = distutils.ccompiler.compiler_class - cc[name] = (module_name, compiler.__name__, desc) - - # HACK!!!! Distutils assumes all compiler modules are in the - # distutils package - sys.modules['distutils.' + module_name] = sys.modules[module_name] - - -def get_extension_modules(config): - """Handle extension modules""" - - EXTENSION_FIELDS = ("sources", - "include_dirs", - "define_macros", - "undef_macros", - "library_dirs", - "libraries", - "runtime_library_dirs", - "extra_objects", - "extra_compile_args", - "extra_link_args", - "export_symbols", - "swig_opts", - "depends") - - ext_modules = [] - for section in config: - if ':' in section: - labels = section.split(':', 1) - else: - # Backwards compatibility for old syntax; don't use this though - labels = section.split('=', 1) - labels = [l.strip() for l in labels] - if (len(labels) == 2) and (labels[0] == 'extension'): - ext_args = {} - for field in EXTENSION_FIELDS: - value = has_get_option(config, section, field) - # All extension module options besides name can have multiple - # values - if not value: - continue - value = split_multiline(value) - if field == 'define_macros': - macros = [] - for macro in value: - macro = macro.split('=', 1) - if len(macro) == 1: - macro = (macro[0].strip(), None) - else: - macro = (macro[0].strip(), macro[1].strip()) - macros.append(macro) - value = macros - ext_args[field] = value - if ext_args: - if 'name' not in ext_args: - ext_args['name'] = labels[1] - ext_modules.append(Extension(ext_args.pop('name'), - **ext_args)) - return ext_modules - - -def get_entry_points(config): - """Process the [entry_points] section of setup.cfg to handle setuptools - entry points. This is, of course, not a standard feature of - distutils2/packaging, but as there is not currently a standard alternative - in packaging, we provide support for them. - """ - - if not 'entry_points' in config: - return {} - - return dict((option, split_multiline(value)) - for option, value in config['entry_points'].items()) - - -def wrap_commands(kwargs): - dist = Distribution() - - # This should suffice to get the same config values and command classes - # that the actual Distribution will see (not counting cmdclass, which is - # handled below) - dist.parse_config_files() - - for cmd, _ in dist.get_command_list(): - hooks = {} - for opt, val in dist.get_option_dict(cmd).items(): - val = val[1] - if opt.startswith('pre_hook.') or opt.startswith('post_hook.'): - hook_type, alias = opt.split('.', 1) - hook_dict = hooks.setdefault(hook_type, {}) - hook_dict[alias] = val - if not hooks: - continue - - if 'cmdclass' in kwargs and cmd in kwargs['cmdclass']: - cmdclass = kwargs['cmdclass'][cmd] - else: - cmdclass = dist.get_command_class(cmd) - - new_cmdclass = wrap_command(cmd, cmdclass, hooks) - kwargs.setdefault('cmdclass', {})[cmd] = new_cmdclass - - -def wrap_command(cmd, cmdclass, hooks): - def run(self, cmdclass=cmdclass): - self.run_command_hooks('pre_hook') - cmdclass.run(self) - self.run_command_hooks('post_hook') - - return type(cmd, (cmdclass, object), - {'run': run, 'run_command_hooks': run_command_hooks, - 'pre_hook': hooks.get('pre_hook'), - 'post_hook': hooks.get('post_hook')}) - - -def run_command_hooks(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, None) - - if hooks is None: - return - - for hook in hooks.values(): - if isinstance(hook, str): - try: - hook_obj = resolve_name(hook) - except ImportError: - err = sys.exc_info()[1] # For py3k - raise DistutilsModuleError('cannot find hook %s: %s' % - (hook,err)) - 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()) - - try : - hook_obj(cmd_obj) - except: - e = sys.exc_info()[1] - log.error('hook %s raised exception: %s\n' % (hook, e)) - log.error(traceback.format_exc()) - sys.exit(1) - - -def has_get_option(config, section, option): - if section in config and option in config[section]: - return config[section][option] - elif section in config and option.replace('_', '-') in config[section]: - return config[section][option.replace('_', '-')] - else: - return False - - -def split_multiline(value): - """Special behaviour when we have a multi line options""" - - value = [element for element in - (line.strip() for line in value.split('\n')) - if element] - return value - - -def split_csv(value): - """Special behaviour when we have a comma separated options""" - - value = [element for element in - (chunk.strip() for chunk in value.split(',')) - if element] - return value - - -def monkeypatch_method(cls): - """A function decorator to monkey-patch a method of the same name on the - given class. - """ - - def wrapper(func): - orig = getattr(cls, func.__name__, None) - if orig and not hasattr(orig, '_orig'): # Already patched - setattr(func, '_orig', orig) - setattr(cls, func.__name__, func) - return func - - return wrapper - - -# The following classes are used to hack Distribution.command_options a bit -class DefaultGetDict(defaultdict): - """Like defaultdict, but the get() method also sets and returns the default - value. - """ - - def get(self, key, default=None): - if default is None: - default = self.default_factory() - return super(DefaultGetDict, self).setdefault(key, default) - - -class IgnoreDict(dict): - """A dictionary that ignores any insertions in which the key is a string - matching any string in `ignore`. The ignore list can also contain wildcard - patterns using '*'. - """ - - def __init__(self, ignore): - self.__ignore = re.compile(r'(%s)' % ('|'.join( - [pat.replace('*', '.*') - for pat in ignore]))) - - def __setitem__(self, key, val): - if self.__ignore.match(key): - return - super(IgnoreDict, self).__setitem__(key, val) diff --git a/pbr/tests/__init__.py b/pbr/tests/__init__.py index 4814cfa..5109b0f 100644 --- a/pbr/tests/__init__.py +++ b/pbr/tests/__init__.py @@ -1,6 +1,7 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2010-2011 OpenStack Foundation +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -13,10 +14,37 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +# Copyright (C) 2013 Association of Universities for Research in Astronomy +# (AURA) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. The name of AURA and its representatives may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS """Common utilities used in testing""" import os +import shutil +import subprocess +import sys import fixtures import testresources @@ -51,3 +79,38 @@ class BaseTestCase(testtools.TestCase, testresources.ResourcedTestCase): self.useFixture(fixtures.NestedTempfile()) self.useFixture(fixtures.FakeLogger()) + + self.temp_dir = self.useFixture(fixtures.TempDir()).path + self.package_dir = os.path.join(self.temp_dir, 'testpackage') + shutil.copytree(os.path.join(os.path.dirname(__file__), 'testpackage'), + self.package_dir) + self.addCleanup(os.chdir, os.getcwd()) + os.chdir(self.package_dir) + + def tearDown(self): + # Remove pbr.testpackage from sys.modules so that it can be freshly + # re-imported by the next test + for k in list(sys.modules): + if (k == 'pbr_testpackage' or + k.startswith('pbr_testpackage.')): + del sys.modules[k] + super(BaseTestCase, self).tearDown() + + def run_setup(self, *args): + return self._run_cmd(sys.executable, ('setup.py',) + args) + + def _run_cmd(self, cmd, args): + """Run a command in the root of the test working copy. + + Runs a command, with the given argument list, in the root of the test + working copy--returns the stdout and stderr streams and the exit code + from the subprocess. + """ + + os.chdir(self.package_dir) + p = subprocess.Popen([cmd] + list(args), stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + streams = tuple(s.decode('latin1').strip() for s in p.communicate()) + print(streams) + return (streams) + (p.returncode,) diff --git a/pbr/tests/test_commands.py b/pbr/tests/test_commands.py new file mode 100644 index 0000000..f5831fa --- /dev/null +++ b/pbr/tests/test_commands.py @@ -0,0 +1,58 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright (C) 2013 Association of Universities for Research in Astronomy +# (AURA) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. The name of AURA and its representatives may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + +from testtools import content + +from pbr import tests + + +class TestCommands(tests.BaseTestCase): + def test_custom_build_py_command(self): + """Test custom build_py command. + + Test that a custom subclass of the build_py command runs when listed in + the commands [global] option, rather than the normal build command. + """ + + stdout, stderr, return_code = self.run_setup('build_py') + self.addDetail('stdout', content.text_content(stdout)) + self.addDetail('stderr', content.text_content(stderr)) + self.assertIn('Running custom build_py command.', stdout) + self.assertEqual(return_code, 0) diff --git a/pbr/tests/test_core.py b/pbr/tests/test_core.py new file mode 100644 index 0000000..f24e5cb --- /dev/null +++ b/pbr/tests/test_core.py @@ -0,0 +1,75 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright (C) 2013 Association of Universities for Research in Astronomy +# (AURA) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. The name of AURA and its representatives may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + +import glob +import os +import tarfile + +from pbr import tests + + +class TestCore(tests.BaseTestCase): + + def test_setup_py_keywords(self): + """setup.py --keywords. + + Test that the `./setup.py --keywords` command returns the correct + value without balking. + """ + + self.run_setup('egg_info') + stdout, _, _ = self.run_setup('--keywords') + assert stdout == 'packaging,distutils,setuptools' + + def test_sdist_extra_files(self): + """Test that the extra files are correctly added.""" + + stdout, _, return_code = self.run_setup('sdist', '--formats=gztar') + + # There can be only one + try: + tf_path = glob.glob(os.path.join('dist', '*.tar.gz'))[0] + except IndexError: + assert False, 'source dist not found' + + tf = tarfile.open(tf_path) + names = ['/'.join(p.split('/')[1:]) for p in tf.getnames()] + + assert 'extra-file.txt' in names diff --git a/pbr/tests/test_hooks.py b/pbr/tests/test_hooks.py new file mode 100644 index 0000000..88106a6 --- /dev/null +++ b/pbr/tests/test_hooks.py @@ -0,0 +1,91 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright (C) 2013 Association of Universities for Research in Astronomy +# (AURA) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. The name of AURA and its representatives may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + +import os +import textwrap + +from pbr import tests +from pbr.tests import util + + +class TestHooks(tests.BaseTestCase): + def setUp(self): + super(TestHooks, self).setUp() + with util.open_config( + os.path.join(self.package_dir, 'setup.cfg')) as cfg: + cfg.set('global', 'setup-hooks', + 'pbr_testpackage._setup_hooks.test_hook_1\n' + 'pbr_testpackage._setup_hooks.test_hook_2') + cfg.set('build_ext', 'pre-hook.test_pre_hook', + 'pbr_testpackage._setup_hooks.test_pre_hook') + cfg.set('build_ext', 'post-hook.test_post_hook', + 'pbr_testpackage._setup_hooks.test_post_hook') + + def test_global_setup_hooks(self): + """Test setup_hooks. + + Test that setup_hooks listed in the [global] section of setup.cfg are + executed in order. + """ + + stdout, _, return_code = self.run_setup('egg_info') + assert 'test_hook_1\ntest_hook_2' in stdout + assert return_code == 0 + + def test_command_hooks(self): + """Test command hooks. + + Simple test that the appropriate command hooks run at the + beginning/end of the appropriate command. + """ + + stdout, _, return_code = self.run_setup('egg_info') + assert 'build_ext pre-hook' not in stdout + assert 'build_ext post-hook' not in stdout + assert return_code == 0 + + stdout, _, return_code = self.run_setup('build_ext') + assert textwrap.dedent(""" + running build_ext + running pre_hook pbr_testpackage._setup_hooks.test_pre_hook for command build_ext + build_ext pre-hook + """) in stdout # flake8: noqa + assert stdout.endswith('build_ext post-hook') + assert return_code == 0 diff --git a/pbr/tests/testpackage/CHANGES.txt b/pbr/tests/testpackage/CHANGES.txt new file mode 100644 index 0000000..709b9d4 --- /dev/null +++ b/pbr/tests/testpackage/CHANGES.txt @@ -0,0 +1,86 @@ +Changelog +=========== + +0.3 (unreleased) +------------------ + +- The ``glob_data_files`` hook became a pre-command hook for the install_data + command instead of being a setup-hook. This is to support the additional + functionality of requiring data_files with relative destination paths to be + install relative to the package's install path (i.e. site-packages). + +- Dropped support for and deprecated the easier_install custom command. + Although it should still work, it probably won't be used anymore for + stsci_python packages. + +- Added support for the ``build_optional_ext`` command, which replaces/extends + the default ``build_ext`` command. See the README for more details. + +- Added the ``tag_svn_revision`` setup_hook as a replacement for the + setuptools-specific tag_svn_revision option to the egg_info command. This + new hook is easier to use than the old tag_svn_revision option: It's + automatically enabled by the presence of ``.dev`` in the version string, and + disabled otherwise. + +- The ``svn_info_pre_hook`` and ``svn_info_post_hook`` have been replaced with + ``version_pre_command_hook`` and ``version_post_command_hook`` respectively. + However, a new ``version_setup_hook``, which has the same purpose, has been + added. It is generally easier to use and will give more consistent results + in that it will run every time setup.py is run, regardless of which command + is used. ``stsci.distutils`` itself uses this hook--see the `setup.cfg` file + and `stsci/distutils/__init__.py` for example usage. + +- Instead of creating an `svninfo.py` module, the new ``version_`` hooks create + a file called `version.py`. In addition to the SVN info that was included + in `svninfo.py`, it includes a ``__version__`` variable to be used by the + package's `__init__.py`. This allows there to be a hard-coded + ``__version__`` variable included in the source code, rather than using + pkg_resources to get the version. + +- In `version.py`, the variables previously named ``__svn_version__`` and + ``__full_svn_info__`` are now named ``__svn_revision__`` and + ``__svn_full_info__``. + +- Fixed a bug when using stsci.distutils in the installation of other packages + in the ``stsci.*`` namespace package. If stsci.distutils was not already + installed, and was downloaded automatically by distribute through the + setup_requires option, then ``stsci.distutils`` would fail to import. This + is because the way the namespace package (nspkg) mechanism currently works, + all packages belonging to the nspkg *must* be on the import path at initial + import time. + + So when installing stsci.tools, for example, if ``stsci.tools`` is imported + from within the source code at install time, but before ``stsci.distutils`` + is downloaded and added to the path, the ``stsci`` package is already + imported and can't be extended to include the path of ``stsci.distutils`` + after the fact. The easiest way of dealing with this, it seems, is to + delete ``stsci`` from ``sys.modules``, which forces it to be reimported, now + the its ``__path__`` extended to include ``stsci.distutil``'s path. + + +0.2.2 (2011-11-09) +------------------ + +- Fixed check for the issue205 bug on actual setuptools installs; before it + only worked on distribute. setuptools has the issue205 bug prior to version + 0.6c10. + +- Improved the fix for the issue205 bug, especially on setuptools. + setuptools, prior to 0.6c10, did not back of sys.modules either before + sandboxing, which causes serious problems. In fact, it's so bad that it's + not enough to add a sys.modules backup to the current sandbox: It's in fact + necessary to monkeypatch setuptools.sandbox.run_setup so that any subsequent + calls to it also back up sys.modules. + + +0.2.1 (2011-09-02) +------------------ + +- Fixed the dependencies so that setuptools is requirement but 'distribute' + specifically. Previously installation could fail if users had plain + setuptools installed and not distribute + +0.2 (2011-08-23) +------------------ + +- Initial public release diff --git a/pbr/tests/testpackage/LICENSE.txt b/pbr/tests/testpackage/LICENSE.txt new file mode 100644 index 0000000..7e8019a --- /dev/null +++ b/pbr/tests/testpackage/LICENSE.txt @@ -0,0 +1,29 @@ +Copyright (C) 2005 Association of Universities for Research in Astronomy (AURA) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + 3. The name of AURA and its representatives may not be used to + endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + diff --git a/pbr/tests/testpackage/MANIFEST.in b/pbr/tests/testpackage/MANIFEST.in new file mode 100644 index 0000000..cdc95ea --- /dev/null +++ b/pbr/tests/testpackage/MANIFEST.in @@ -0,0 +1 @@ +include data_files/* diff --git a/pbr/tests/testpackage/README.txt b/pbr/tests/testpackage/README.txt new file mode 100644 index 0000000..b6d84a7 --- /dev/null +++ b/pbr/tests/testpackage/README.txt @@ -0,0 +1,148 @@ +Introduction +============ +This package contains utilities used to package some of STScI's Python +projects; specifically those projects that comprise stsci_python_ and +Astrolib_. + +It currently consists mostly of some setup_hook scripts meant for use with +`distutils2/packaging`_ and/or pbr_, and a customized easy_install command +meant for use with distribute_. + +This package is not meant for general consumption, though it might be worth +looking at for examples of how to do certain things with your own packages, but +YMMV. + +Features +======== + +Hook Scripts +------------ +Currently the main features of this package are a couple of setup_hook scripts. +In distutils2, a setup_hook is a script that runs at the beginning of any +pysetup command, and can modify the package configuration read from setup.cfg. +There are also pre- and post-command hooks that only run before/after a +specific setup command (eg. build_ext, install) is run. + +stsci.distutils.hooks.use_packages_root +''''''''''''''''''''''''''''''''''''''' +If using the ``packages_root`` option under the ``[files]`` section of +setup.cfg, this hook will add that path to ``sys.path`` so that modules in your +package can be imported and used in setup. This can be used even if +``packages_root`` is not specified--in this case it adds ``''`` to +``sys.path``. + +stsci.distutils.hooks.version_setup_hook +'''''''''''''''''''''''''''''''''''''''' +Creates a Python module called version.py which currently contains four +variables: + +* ``__version__`` (the release version) +* ``__svn_revision__`` (the SVN revision info as returned by the ``svnversion`` + command) +* ``__svn_full_info__`` (as returned by the ``svn info`` command) +* ``__setup_datetime__`` (the date and time that setup.py was last run). + +These variables can be imported in the package's `__init__.py` for degugging +purposes. The version.py module will *only* be created in a package that +imports from the version module in its `__init__.py`. It should be noted that +this is generally preferable to writing these variables directly into +`__init__.py`, since this provides more control and is less likely to +unexpectedly break things in `__init__.py`. + +stsci.distutils.hooks.version_pre_command_hook +'''''''''''''''''''''''''''''''''''''''''''''' +Identical to version_setup_hook, but designed to be used as a pre-command +hook. + +stsci.distutils.hooks.version_post_command_hook +''''''''''''''''''''''''''''''''''''''''''''''' +The complement to version_pre_command_hook. This will delete any version.py +files created during a build in order to prevent them from cluttering an SVN +working copy (note, however, that version.py is *not* deleted from the build/ +directory, so a copy of it is still preserved). It will also not be deleted +if the current directory is not an SVN working copy. For example, if source +code extracted from a source tarball it will be preserved. + +stsci.distutils.hooks.tag_svn_revision +'''''''''''''''''''''''''''''''''''''' +A setup_hook to add the SVN revision of the current working copy path to the +package version string, but only if the version ends in .dev. + +For example, ``mypackage-1.0.dev`` becomes ``mypackage-1.0.dev1234``. This is +in accordance with the version string format standardized by PEP 386. + +This should be used as a replacement for the ``tag_svn_revision`` option to +the egg_info command. This hook is more compatible with packaging/distutils2, +which does not include any VCS support. This hook is also more flexible in +that it turns the revision number on/off depending on the presence of ``.dev`` +in the version string, so that it's not automatically added to the version in +final releases. + +This hook does require the ``svnversion`` command to be available in order to +work. It does not examine the working copy metadata directly. + +stsci.distutils.hooks.numpy_extension_hook +'''''''''''''''''''''''''''''''''''''''''' +This is a pre-command hook for the build_ext command. To use it, add a +``[build_ext]`` section to your setup.cfg, and add to it:: + + pre-hook.numpy-extension-hook = stsci.distutils.hooks.numpy_extension_hook + +This hook must be used to build extension modules that use Numpy. The primary +side-effect of this hook is to add the correct numpy include directories to +`include_dirs`. To use it, add 'numpy' to the 'include-dirs' option of each +extension module that requires numpy to build. The value 'numpy' will be +replaced with the actual path to the numpy includes. + +stsci.distutils.hooks.is_display_option +''''''''''''''''''''''''''''''''''''''' +This is not actually a hook, but is a useful utility function that can be used +in writing other hooks. Basically, it returns ``True`` if setup.py was run +with a "display option" such as --version or --help. This can be used to +prevent your hook from running in such cases. + +stsci.distutils.hooks.glob_data_files +''''''''''''''''''''''''''''''''''''' +A pre-command hook for the install_data command. Allows filename wildcards as +understood by ``glob.glob()`` to be used in the data_files option. This hook +must be used in order to have this functionality since it does not normally +exist in distutils. + +This hook also ensures that data files are installed relative to the package +path. data_files shouldn't normally be installed this way, but the +functionality is required for a few special cases. + + +Commands +-------- +build_optional_ext +'''''''''''''''''' +This serves as an optional replacement for the default built_ext command, +which compiles C extension modules. Its purpose is to allow extension modules +to be *optional*, so that if their build fails the rest of the package is +still allowed to be built and installed. This can be used when an extension +module is not definitely required to use the package. + +To use this custom command, add:: + + commands = stsci.distutils.command.build_optional_ext.build_optional_ext + +under the ``[global]`` section of your package's setup.cfg. Then, to mark +an individual extension module as optional, under the setup.cfg section for +that extension add:: + + optional = True + +Optionally, you may also add a custom failure message by adding:: + + fail_message = The foobar extension module failed to compile. + This could be because you lack such and such headers. + This package will still work, but such and such features + will be disabled. + + +.. _stsci_python: http://www.stsci.edu/resources/software_hardware/pyraf/stsci_python +.. _Astrolib: http://www.scipy.org/AstroLib/ +.. _distutils2/packaging: http://distutils2.notmyidea.org/ +.. _d2to1: http://pypi.python.org/pypi/d2to1 +.. _distribute: http://pypi.python.org/pypi/distribute diff --git a/pbr/tests/testpackage/data_files/a.txt b/pbr/tests/testpackage/data_files/a.txt new file mode 100644 index 0000000..e69de29 diff --git a/pbr/tests/testpackage/data_files/b.txt b/pbr/tests/testpackage/data_files/b.txt new file mode 100644 index 0000000..e69de29 diff --git a/pbr/tests/testpackage/data_files/c.rst b/pbr/tests/testpackage/data_files/c.rst new file mode 100644 index 0000000..e69de29 diff --git a/pbr/tests/testpackage/extra-file.txt b/pbr/tests/testpackage/extra-file.txt new file mode 100644 index 0000000..e69de29 diff --git a/pbr/tests/testpackage/pbr_testpackage/__init__.py b/pbr/tests/testpackage/pbr_testpackage/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pbr/tests/testpackage/pbr_testpackage/_setup_hooks.py b/pbr/tests/testpackage/pbr_testpackage/_setup_hooks.py new file mode 100644 index 0000000..f8b3087 --- /dev/null +++ b/pbr/tests/testpackage/pbr_testpackage/_setup_hooks.py @@ -0,0 +1,65 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright (C) 2013 Association of Universities for Research in Astronomy +# (AURA) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. The name of AURA and its representatives may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + +from distutils.command import build_py + + +def test_hook_1(config): + print('test_hook_1') + + +def test_hook_2(config): + print('test_hook_2') + + +class test_command(build_py.build_py): + command_name = 'build_py' + + def run(self): + print('Running custom build_py command.') + return build_py.build_py.run(self) + + +def test_pre_hook(cmdobj): + print('build_ext pre-hook') + + +def test_post_hook(cmdobj): + print('build_ext post-hook') diff --git a/pbr/tests/testpackage/pbr_testpackage/package_data/1.txt b/pbr/tests/testpackage/pbr_testpackage/package_data/1.txt new file mode 100644 index 0000000..e69de29 diff --git a/pbr/tests/testpackage/pbr_testpackage/package_data/2.txt b/pbr/tests/testpackage/pbr_testpackage/package_data/2.txt new file mode 100644 index 0000000..e69de29 diff --git a/pbr/tests/testpackage/setup.cfg b/pbr/tests/testpackage/setup.cfg new file mode 100644 index 0000000..336668d --- /dev/null +++ b/pbr/tests/testpackage/setup.cfg @@ -0,0 +1,46 @@ +[metadata] +name = pbr_testpackage +version = 0.1.dev +author = OpenStack +author-email = openstack-dev@lists.openstack.org +home-page = http://pypi.python.org/pypi/pbr +summary = Test package for testing pbr +description-file = + README.txt + CHANGES.txt +requires-python = >=2.5 + +requires-dist = + setuptools + +classifier = + Development Status :: 3 - Alpha + Intended Audience :: Developers + License :: OSI Approved :: BSD License + Programming Language :: Python + Topic :: Scientific/Engineering + Topic :: Software Development :: Build Tools + Topic :: Software Development :: Libraries :: Python Modules + Topic :: System :: Archiving :: Packaging + +keywords = packaging, distutils, setuptools + +[files] +packages = pbr_testpackage +package-data = testpackage = package_data/*.txt +data-files = testpackage/data_files = data_files/*.txt +extra-files = extra-file.txt + +[extension=pbr_testpackage.testext] +sources = src/testext.c +optional = True + +[global] +#setup-hooks = +# pbr_testpackage._setup_hooks.test_hook_1 +# pbr_testpackage._setup_hooks.test_hook_2 +commands = pbr_testpackage._setup_hooks.test_command + +[build_ext] +#pre-hook.test_pre_hook = pbr_testpackage._setup_hooks.test_pre_hook +#post-hook.test_post_hook = pbr_testpackage._setup_hooks.test_post_hook diff --git a/pbr/tests/testpackage/setup.py b/pbr/tests/testpackage/setup.py new file mode 100755 index 0000000..8866691 --- /dev/null +++ b/pbr/tests/testpackage/setup.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import setuptools + +setuptools.setup( + setup_requires=['pbr'], + pbr=True, +) diff --git a/pbr/tests/testpackage/src/testext.c b/pbr/tests/testpackage/src/testext.c new file mode 100644 index 0000000..872d43c --- /dev/null +++ b/pbr/tests/testpackage/src/testext.c @@ -0,0 +1,28 @@ +#include + + +static PyMethodDef TestextMethods[] = { + {NULL, NULL, 0, NULL} +}; + + +#if PY_MAJOR_VERSION >=3 +static struct PyModuleDef testextmodule = { + PyModuleDef_HEAD_INIT, + "testext", + -1, + TestextMethods +}; + +PyObject* +PyInit_testext(void) +{ + return PyModule_Create(&testextmodule); +} +#else +PyMODINIT_FUNC +inittestext(void) +{ + Py_InitModule("testext", TestextMethods); +} +#endif diff --git a/pbr/tests/util.py b/pbr/tests/util.py new file mode 100644 index 0000000..e657508 --- /dev/null +++ b/pbr/tests/util.py @@ -0,0 +1,74 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright (C) 2013 Association of Universities for Research in Astronomy +# (AURA) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. The name of AURA and its representatives may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + +import contextlib +import os +import shutil +import stat + +try: + import configparser +except ImportError: + import ConfigParser as configparser + + +@contextlib.contextmanager +def open_config(filename): + cfg = configparser.ConfigParser() + cfg.read(filename) + yield cfg + with open(filename, 'w') as fp: + cfg.write(fp) + + +def rmtree(path): + """shutil.rmtree() with error handler. + + Handle 'access denied' from trying to delete read-only files. + """ + + def onerror(func, path, exc_info): + if not os.access(path, os.W_OK): + os.chmod(path, stat.S_IWUSR) + func(path) + else: + raise + + return shutil.rmtree(path, onerror=onerror) diff --git a/pbr/util.py b/pbr/util.py new file mode 100644 index 0000000..353635e --- /dev/null +++ b/pbr/util.py @@ -0,0 +1,628 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Copyright (C) 2013 Association of Universities for Research in Astronomy +# (AURA) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. The name of AURA and its representatives may not be used to +# endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY AURA ``AS IS'' AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL AURA BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + +"""The code in this module is mostly copy/pasted out of the distutils2 source +code, as recommended by Tarek Ziade. As such, it may be subject to some change +as distutils2 development continues, and will have to be kept up to date. + +I didn't want to use it directly from distutils2 itself, since I do not want it +to be an installation dependency for our packages yet--it is still too unstable +(the latest version on PyPI doesn't even install). +""" + +# These first two imports are not used, but are needed to get around an +# irritating Python bug that can crop up when using ./setup.py test. +# See: http://www.eby-sarna.com/pipermail/peak/2010-May/003355.html +try: + import multiprocessing # flake8: noqa +except ImportError: + pass +import logging # flake8: noqa + +import os +import re +import sys +import traceback + +from collections import defaultdict + +import distutils.ccompiler + +from distutils import log +from distutils.errors import (DistutilsOptionError, DistutilsModuleError, + DistutilsFileError) +from setuptools.command.egg_info import manifest_maker +from setuptools.dist import Distribution +from setuptools.extension import Extension + +try: + import configparser +except ImportError: + import ConfigParser as configparser + + +# A simplified RE for this; just checks that the line ends with version +# predicates in () +_VERSION_SPEC_RE = re.compile(r'\s*(.*?)\s*\((.*)\)\s*$') + + +# Mappings from setup() keyword arguments to setup.cfg options; +# The values are (section, option) tuples, or simply (section,) tuples if +# the option has the same name as the setup() argument +D1_D2_SETUP_ARGS = { + "name": ("metadata",), + "version": ("metadata",), + "author": ("metadata",), + "author_email": ("metadata",), + "maintainer": ("metadata",), + "maintainer_email": ("metadata",), + "url": ("metadata", "home_page"), + "description": ("metadata", "summary"), + "keywords": ("metadata",), + "long_description": ("metadata", "description"), + "download-url": ("metadata",), + "classifiers": ("metadata", "classifier"), + "platforms": ("metadata", "platform"), # ** + "license": ("metadata",), + # Use setuptools install_requires, not + # broken distutils requires + "install_requires": ("metadata", "requires_dist"), + "setup_requires": ("metadata", "setup_requires_dist"), + "provides": ("metadata", "provides_dist"), # ** + "obsoletes": ("metadata", "obsoletes_dist"), # ** + "package_dir": ("files", 'packages_root'), + "packages": ("files",), + "package_data": ("files",), + "namespace_packages": ("files",), + "data_files": ("files",), + "scripts": ("files",), + "py_modules": ("files", "modules"), # ** + "cmdclass": ("global", "commands"), + # Not supported in distutils2, but provided for + # backwards compatibility with setuptools + "use_2to3": ("backwards_compat", "use_2to3"), + "zip_safe": ("backwards_compat", "zip_safe"), + "tests_require": ("backwards_compat", "tests_require"), + "dependency_links": ("backwards_compat",), + "include_package_data": ("backwards_compat",), +} + +# setup() arguments that can have multiple values in setup.cfg +MULTI_FIELDS = ("classifiers", + "platforms", + "install_requires", + "provides", + "obsoletes", + "namespace_packages", + "packages", + "package_data", + "data_files", + "scripts", + "py_modules", + "dependency_links", + "setup_requires", + "tests_require", + "cmdclass") + +# setup() arguments that contain boolean values +BOOL_FIELDS = ("use_2to3", "zip_safe", "include_package_data") + + +CSV_FIELDS = ("keywords",) + + +log.set_verbosity(log.INFO) + + +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) - 1 + module_name = parts[:cursor] + attr_name = parts[-1] + + while cursor > 0: + try: + ret = __import__('.'.join(module_name), fromlist=[attr_name]) + break + except ImportError: + if cursor == 0: + raise + cursor -= 1 + module_name = parts[:cursor] + attr_name = parts[cursor] + ret = '' + + for part in parts[cursor:]: + try: + ret = getattr(ret, part) + except AttributeError: + raise ImportError(name) + + return ret + + +def cfg_to_args(path='setup.cfg'): + """ Distutils2 to distutils1 compatibility util. + + This method uses an existing setup.cfg to generate a dictionary of + keywords that can be used by distutils.core.setup(kwargs**). + + :param file: + The setup.cfg path. + :raises DistutilsFileError: + When the setup.cfg file is not found. + + """ + + # The method source code really starts here. + parser = configparser.RawConfigParser() + if not os.path.exists(path): + raise DistutilsFileError("file '%s' does not exist" % + os.path.abspath(path)) + parser.read(path) + config = {} + for section in parser.sections(): + config[section] = dict(parser.items(section)) + + # Run setup_hooks, if configured + setup_hooks = has_get_option(config, 'global', 'setup_hooks') + package_dir = has_get_option(config, 'files', 'packages_root') + + # Add the source package directory to sys.path in case it contains + # additional hooks, and to make sure it's on the path before any existing + # installations of the package + if package_dir: + package_dir = os.path.abspath(package_dir) + sys.path.insert(0, package_dir) + + try: + if setup_hooks: + setup_hooks = split_multiline(setup_hooks) + for hook in setup_hooks: + hook_fn = resolve_name(hook) + try : + hook_fn(config) + except SystemExit: + log.error('setup hook %s terminated the installation') + except: + e = sys.exc_info()[1] + log.error('setup hook %s raised exception: %s\n' % + (hook, e)) + log.error(traceback.format_exc()) + sys.exit(1) + + kwargs = setup_cfg_to_setup_kwargs(config) + + # Set default config overrides + kwargs['include_package_data'] = True + kwargs['zip_safe'] = False + + register_custom_compilers(config) + + ext_modules = get_extension_modules(config) + if ext_modules: + kwargs['ext_modules'] = ext_modules + + entry_points = get_entry_points(config) + if entry_points: + kwargs['entry_points'] = entry_points + + wrap_commands(kwargs) + + # Handle the [files]/extra_files option + extra_files = has_get_option(config, 'files', 'extra_files') + if extra_files: + extra_files = split_multiline(extra_files) + # Let's do a sanity check + for filename in extra_files: + if not os.path.exists(filename): + raise DistutilsFileError( + '%s from the extra_files option in setup.cfg does not ' + 'exist' % filename) + # Unfortunately the only really sensible way to do this is to + # monkey-patch the manifest_maker class + @monkeypatch_method(manifest_maker) + def add_defaults(self, extra_files=extra_files, log=log): + log.info('[pbr] running patched manifest_maker command ' + 'with extra_files support') + add_defaults._orig(self) + self.filelist.extend(extra_files) + + finally: + # Perform cleanup if any paths were added to sys.path + if package_dir: + sys.path.pop(0) + + return kwargs + + +def setup_cfg_to_setup_kwargs(config): + """Processes the setup.cfg options and converts them to arguments accepted + by setuptools' setup() function. + """ + + kwargs = {} + + for arg in D1_D2_SETUP_ARGS: + if len(D1_D2_SETUP_ARGS[arg]) == 2: + # The distutils field name is different than distutils2's. + section, option = D1_D2_SETUP_ARGS[arg] + + elif len(D1_D2_SETUP_ARGS[arg]) == 1: + # The distutils field name is the same thant distutils2's. + section = D1_D2_SETUP_ARGS[arg][0] + option = arg + + in_cfg_value = has_get_option(config, section, option) + if not in_cfg_value: + # There is no such option in the setup.cfg + if arg == "long_description": + in_cfg_value = has_get_option(config, section, + "description_file") + if in_cfg_value: + in_cfg_value = split_multiline(in_cfg_value) + value = '' + for filename in in_cfg_value: + description_file = open(filename) + try: + value += description_file.read().strip() + '\n\n' + finally: + description_file.close() + in_cfg_value = value + else: + continue + + if arg in CSV_FIELDS: + in_cfg_value = split_csv(in_cfg_value) + if arg in MULTI_FIELDS: + in_cfg_value = split_multiline(in_cfg_value) + elif arg in BOOL_FIELDS: + # Provide some flexibility here... + if in_cfg_value.lower() in ('true', 't', '1', 'yes', 'y'): + in_cfg_value = True + else: + in_cfg_value = False + + if in_cfg_value: + if arg in ('install_requires', 'tests_require'): + # Replaces PEP345-style version specs with the sort expected by + # setuptools + in_cfg_value = [_VERSION_SPEC_RE.sub(r'\1\2', pred) + for pred in in_cfg_value] + elif arg == 'package_dir': + in_cfg_value = {'': in_cfg_value} + elif arg in ('package_data', 'data_files'): + data_files = {} + firstline = True + prev = None + for line in in_cfg_value: + if '=' in line: + key, value = line.split('=', 1) + key, value = (key.strip(), value.strip()) + if key in data_files: + # Multiple duplicates of the same package name; + # this is for backwards compatibility of the old + # format prior to d2to1 0.2.6. + prev = data_files[key] + prev.extend(value.split()) + else: + prev = data_files[key.strip()] = value.split() + elif firstline: + raise DistutilsOptionError( + 'malformed package_data first line %r (misses ' + '"=")' % line) + else: + prev.extend(line.strip().split()) + firstline = False + if arg == 'data_files': + # the data_files value is a pointlessly different structure + # from the package_data value + data_files = data_files.items() + in_cfg_value = data_files + elif arg == 'cmdclass': + cmdclass = {} + dist = Distribution() + for cls in in_cfg_value: + cls = resolve_name(cls) + cmd = cls(dist) + cmdclass[cmd.get_command_name()] = cls + in_cfg_value = cmdclass + + kwargs[arg] = in_cfg_value + + return kwargs + + +def register_custom_compilers(config): + """Handle custom compilers; this has no real equivalent in distutils, where + additional compilers could only be added programmatically, so we have to + hack it in somehow. + """ + + compilers = has_get_option(config, 'global', 'compilers') + if compilers: + compilers = split_multiline(compilers) + for compiler in compilers: + compiler = resolve_name(compiler) + + # In distutils2 compilers these class attributes exist; for + # distutils1 we just have to make something up + if hasattr(compiler, 'name'): + name = compiler.name + else: + name = compiler.__name__ + if hasattr(compiler, 'description'): + desc = compiler.description + else: + desc = 'custom compiler %s' % name + + module_name = compiler.__module__ + # Note; this *will* override built in compilers with the same name + # TODO: Maybe display a warning about this? + cc = distutils.ccompiler.compiler_class + cc[name] = (module_name, compiler.__name__, desc) + + # HACK!!!! Distutils assumes all compiler modules are in the + # distutils package + sys.modules['distutils.' + module_name] = sys.modules[module_name] + + +def get_extension_modules(config): + """Handle extension modules""" + + EXTENSION_FIELDS = ("sources", + "include_dirs", + "define_macros", + "undef_macros", + "library_dirs", + "libraries", + "runtime_library_dirs", + "extra_objects", + "extra_compile_args", + "extra_link_args", + "export_symbols", + "swig_opts", + "depends") + + ext_modules = [] + for section in config: + if ':' in section: + labels = section.split(':', 1) + else: + # Backwards compatibility for old syntax; don't use this though + labels = section.split('=', 1) + labels = [l.strip() for l in labels] + if (len(labels) == 2) and (labels[0] == 'extension'): + ext_args = {} + for field in EXTENSION_FIELDS: + value = has_get_option(config, section, field) + # All extension module options besides name can have multiple + # values + if not value: + continue + value = split_multiline(value) + if field == 'define_macros': + macros = [] + for macro in value: + macro = macro.split('=', 1) + if len(macro) == 1: + macro = (macro[0].strip(), None) + else: + macro = (macro[0].strip(), macro[1].strip()) + macros.append(macro) + value = macros + ext_args[field] = value + if ext_args: + if 'name' not in ext_args: + ext_args['name'] = labels[1] + ext_modules.append(Extension(ext_args.pop('name'), + **ext_args)) + return ext_modules + + +def get_entry_points(config): + """Process the [entry_points] section of setup.cfg to handle setuptools + entry points. This is, of course, not a standard feature of + distutils2/packaging, but as there is not currently a standard alternative + in packaging, we provide support for them. + """ + + if not 'entry_points' in config: + return {} + + return dict((option, split_multiline(value)) + for option, value in config['entry_points'].items()) + + +def wrap_commands(kwargs): + dist = Distribution() + + # This should suffice to get the same config values and command classes + # that the actual Distribution will see (not counting cmdclass, which is + # handled below) + dist.parse_config_files() + + for cmd, _ in dist.get_command_list(): + hooks = {} + for opt, val in dist.get_option_dict(cmd).items(): + val = val[1] + if opt.startswith('pre_hook.') or opt.startswith('post_hook.'): + hook_type, alias = opt.split('.', 1) + hook_dict = hooks.setdefault(hook_type, {}) + hook_dict[alias] = val + if not hooks: + continue + + if 'cmdclass' in kwargs and cmd in kwargs['cmdclass']: + cmdclass = kwargs['cmdclass'][cmd] + else: + cmdclass = dist.get_command_class(cmd) + + new_cmdclass = wrap_command(cmd, cmdclass, hooks) + kwargs.setdefault('cmdclass', {})[cmd] = new_cmdclass + + +def wrap_command(cmd, cmdclass, hooks): + def run(self, cmdclass=cmdclass): + self.run_command_hooks('pre_hook') + cmdclass.run(self) + self.run_command_hooks('post_hook') + + return type(cmd, (cmdclass, object), + {'run': run, 'run_command_hooks': run_command_hooks, + 'pre_hook': hooks.get('pre_hook'), + 'post_hook': hooks.get('post_hook')}) + + +def run_command_hooks(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, None) + + if hooks is None: + return + + for hook in hooks.values(): + if isinstance(hook, str): + try: + hook_obj = resolve_name(hook) + except ImportError: + err = sys.exc_info()[1] # For py3k + raise DistutilsModuleError('cannot find hook %s: %s' % + (hook,err)) + 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()) + + try : + hook_obj(cmd_obj) + except: + e = sys.exc_info()[1] + log.error('hook %s raised exception: %s\n' % (hook, e)) + log.error(traceback.format_exc()) + sys.exit(1) + + +def has_get_option(config, section, option): + if section in config and option in config[section]: + return config[section][option] + elif section in config and option.replace('_', '-') in config[section]: + return config[section][option.replace('_', '-')] + else: + return False + + +def split_multiline(value): + """Special behaviour when we have a multi line options""" + + value = [element for element in + (line.strip() for line in value.split('\n')) + if element] + return value + + +def split_csv(value): + """Special behaviour when we have a comma separated options""" + + value = [element for element in + (chunk.strip() for chunk in value.split(',')) + if element] + return value + + +def monkeypatch_method(cls): + """A function decorator to monkey-patch a method of the same name on the + given class. + """ + + def wrapper(func): + orig = getattr(cls, func.__name__, None) + if orig and not hasattr(orig, '_orig'): # Already patched + setattr(func, '_orig', orig) + setattr(cls, func.__name__, func) + return func + + return wrapper + + +# The following classes are used to hack Distribution.command_options a bit +class DefaultGetDict(defaultdict): + """Like defaultdict, but the get() method also sets and returns the default + value. + """ + + def get(self, key, default=None): + if default is None: + default = self.default_factory() + return super(DefaultGetDict, self).setdefault(key, default) + + +class IgnoreDict(dict): + """A dictionary that ignores any insertions in which the key is a string + matching any string in `ignore`. The ignore list can also contain wildcard + patterns using '*'. + """ + + def __init__(self, ignore): + self.__ignore = re.compile(r'(%s)' % ('|'.join( + [pat.replace('*', '.*') + for pat in ignore]))) + + def __setitem__(self, key, val): + if self.__ignore.match(key): + return + super(IgnoreDict, self).__setitem__(key, val) diff --git a/setup.py b/setup.py index c6c202a..65c675b 100755 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ import setuptools -from pbr.d2to1 import util +from pbr import util setuptools.setup( **util.cfg_to_args()) diff --git a/tools/integration.sh b/tools/integration.sh index d4fafa5..41a350d 100644 --- a/tools/integration.sh +++ b/tools/integration.sh @@ -151,7 +151,7 @@ for PROJECT in $PROJECTS ; do # TODO(mordred): need to implement egg filtering # Because install will have caused eggs to be locally downloaded - # pbr and d2to1 can get excluded from being in the actual venv + # pbr can get excluded from being in the actual venv # test that this did not happen # $tempvenv/bin/python -c 'import pkg_resources as p; import sys; pbr=p.working_set.find(p.Requirement.parse("pbr")) is None; sys.exit(pbr or 0)' done -- cgit v1.2.1