diff --git a/pbr/hooks/commands.py b/pbr/hooks/commands.py index d14baeca..a5ed4a6b 100644 --- a/pbr/hooks/commands.py +++ b/pbr/hooks/commands.py @@ -38,6 +38,7 @@ def add_command(self, command): def hook(self): self.add_command('pbr.packaging.LocalSDist') + self.add_command('pbr.packaging.LocalInstallScripts') if packaging.have_sphinx(): self.add_command('pbr.packaging.LocalBuildDoc') diff --git a/pbr/packaging.py b/pbr/packaging.py index 197a7218..04e32905 100644 --- a/pbr/packaging.py +++ b/pbr/packaging.py @@ -30,7 +30,9 @@ import distutils.errors from distutils import log import pkg_resources +from setuptools.command import easy_install from setuptools.command import install +from setuptools.command import install_scripts from setuptools.command import sdist try: @@ -430,6 +432,68 @@ def have_nose(): return _have_nose +_script_text = """# PBR Generated from %(group)r + +import sys + +from %(module_name)s import %(func)s + + +if __name__ == "__main__": + sys.exit(%(func)s()) +""" + + +def _get_script_args(dist, executable, is_wininst): + """Override entrypoints console_script.""" + header = easy_install.get_script_header("", executable, is_wininst) + for group in 'console_scripts', 'gui_scripts': + for name, ep in dist.get_entry_map(group).items(): + script_text = _script_text % dict( + group=group, + module_name=ep.module_name, + func=ep.attrs[0]) + yield (name, header+script_text) + + +class LocalInstallScripts(install_scripts.install_scripts): + """Intercepts console scripts entry_points.""" + command_name = 'install_scripts' + + def run(self): + if os.name != 'nt': + get_script_args = _get_script_args + else: + get_script_args = easy_install.get_script_args + + import distutils.command.install_scripts + + self.run_command("egg_info") + if self.distribution.scripts: + # run first to set up self.outfiles + distutils.command.install_scripts.install_scripts.run(self) + else: + self.outfiles = [] + if self.no_ep: + # don't install entry point scripts into .egg file! + return + + ei_cmd = self.get_finalized_command("egg_info") + dist = pkg_resources.Distribution( + ei_cmd.egg_base, + pkg_resources.PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), + ei_cmd.egg_name, ei_cmd.egg_version, + ) + bs_cmd = self.get_finalized_command('build_scripts') + executable = getattr( + bs_cmd, 'executable', easy_install.sys_executable) + is_wininst = getattr( + self.get_finalized_command("bdist_wininst"), '_is_running', False + ) + for args in get_script_args(dist, executable, is_wininst): + self.write_script(*args) + + class LocalSDist(sdist.sdist): """Builds the ChangeLog and Authors files from VC first.""" diff --git a/pbr/tests/__init__.py b/pbr/tests/__init__.py index a4874c34..14a5b5e5 100644 --- a/pbr/tests/__init__.py +++ b/pbr/tests/__init__.py @@ -100,7 +100,7 @@ def tearDown(self): def run_setup(self, *args): return self._run_cmd(sys.executable, ('setup.py',) + args) - def _run_cmd(self, cmd, 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 diff --git a/pbr/tests/test_core.py b/pbr/tests/test_core.py index f24e5cb3..4b6c49bc 100644 --- a/pbr/tests/test_core.py +++ b/pbr/tests/test_core.py @@ -42,6 +42,8 @@ import os import tarfile +import fixtures + from pbr import tests @@ -73,3 +75,26 @@ def test_sdist_extra_files(self): names = ['/'.join(p.split('/')[1:]) for p in tf.getnames()] assert 'extra-file.txt' in names + + def test_console_script_install(self): + """Test that we install a non-pkg-resources console script.""" + + if os.name == 'nt': + self.skipTest('Windows support is passthrough') + + stdout, _, return_code = self.run_setup( + 'install_scripts', '--install-dir=%s' % self.temp_dir) + + self.assertIn( + 'Installing pbr_test_cmd script to %s' % self.temp_dir, + stdout) + self.assertNotIn( + 'pkg_resources', + open(os.path.join(self.temp_dir, 'pbr_test_cmd'), 'r').read()) + + self.useFixture( + fixtures.EnvironmentVariable('PYTHONPATH', '.')) + + stdout, _, return_code = self._run_cmd( + os.path.join(self.temp_dir, 'pbr_test_cmd')) + self.assertIn("PBR", stdout) diff --git a/pbr/tests/testpackage/pbr_testpackage/cmd.py b/pbr/tests/testpackage/pbr_testpackage/cmd.py new file mode 100644 index 00000000..1b039158 --- /dev/null +++ b/pbr/tests/testpackage/pbr_testpackage/cmd.py @@ -0,0 +1,19 @@ +# 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. +from __future__ import print_function + + +def main(): + print("PBR Test Command") diff --git a/pbr/tests/testpackage/setup.cfg b/pbr/tests/testpackage/setup.cfg index 336668db..9bcc0eec 100644 --- a/pbr/tests/testpackage/setup.cfg +++ b/pbr/tests/testpackage/setup.cfg @@ -31,6 +31,10 @@ package-data = testpackage = package_data/*.txt data-files = testpackage/data_files = data_files/*.txt extra-files = extra-file.txt +[entry_points] +console_scripts = + pbr_test_cmd = pbr_testpackage.cmd:main + [extension=pbr_testpackage.testext] sources = src/testext.c optional = True diff --git a/tools/integration.sh b/tools/integration.sh index 41a350d8..ef0b2f38 100644 --- a/tools/integration.sh +++ b/tools/integration.sh @@ -90,6 +90,49 @@ extra-index-url = http://pypi.openstack.org/openstack log = /home/jenkins/pip.log EOF +eptest=$tmpdir/eptest +mkdir $eptest +cd $eptest + +cat < setup.cfg +[metadata] +name = test_project + +[entry_points] +console_scripts = + test_cmd = test_project:main + +[global] +setup-hooks = + pbr.hooks.setup_hook +EOF + +cat < setup.py +import setuptools + +setuptools.setup( + setup_requires=['pbr'], + pbr=True) +EOF + +mkdir test_project +cat < test_project/__init__.py +def main(): + print "Test cmd" +EOF + +epvenv=$eptest/venv +mkvenv $epvenv setuptools pip + +eppbrdir=$tmpdir/eppbrdir +git clone $REPODIR/pbr $eppbrdir +$epvenv/bin/pip install -e $eppbrdir + +PBR_VERSION=0.0 $epvenv/bin/python setup.py install +cat $epvenv/bin/test_cmd +grep 'PBR Generated' $epvenv/bin/test_cmd +$epvenv/bin/test_cmd | grep 'Test cmd' + projectdir=$tmpdir/projects mkdir -p $projectdir