diff options
author | Stephen Finucane <sfinucan@redhat.com> | 2017-10-06 15:44:13 +0100 |
---|---|---|
committer | Stephen Finucane <sfinucan@redhat.com> | 2017-10-09 10:48:33 +0100 |
commit | 32c90ba598d7740e52bf21bc5e920fb5df08645a (patch) | |
tree | 3ec86c93f0aa1e5200b2444a22561b516235b75d | |
parent | 87637bdf1d22d5e6aee5650b533e477e8e715b19 (diff) | |
download | pbr-32c90ba598d7740e52bf21bc5e920fb5df08645a.tar.gz |
Remove support for command hooks
distutils2 is long dead and many of its best ideas have been
incorporated into setuptools. One of the ideas that *has not* been
incorporated is the idea of command hooks, of either the pre or post
kind. pbr is still carrying the code for this, and there are several
issues with this:
- No one is using this functionality in OpenStack and, given the
complete lack of documentation on the matter, it's very doubtful that
it's being used anywhere else [1]
- It's causing issues for projects attempting to hook into the
'distutils.commands' entry point on Python 2.7, which it seems no else
must have attempted yet [2].
- distutils2 is dead and advanced features like this that we don't
explicitly need should not be retained
We could attempt to fix this but why bother? Good riddance, I say.
[1] http://codesearch.openstack.org/?q=pre_hook%5C.&i=nope&files=&repos=
[2] http://codesearch.openstack.org/?q=distutils.commands&i=nope&files=&repos=
Change-Id: I01f657034cffbf55ce830b7e8dbb6b3d94c1fd18
-rw-r--r-- | pbr/core.py | 11 | ||||
-rw-r--r-- | pbr/tests/test_hooks.py | 28 | ||||
-rw-r--r-- | pbr/tests/testpackage/setup.cfg | 4 | ||||
-rw-r--r-- | pbr/util.py | 116 | ||||
-rw-r--r-- | releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml | 6 |
5 files changed, 6 insertions, 159 deletions
diff --git a/pbr/core.py b/pbr/core.py index 71d1e56..753387e 100644 --- a/pbr/core.py +++ b/pbr/core.py @@ -141,16 +141,5 @@ def pbr(dist, attr, value): if isinstance(dist.metadata.version, integer_types + (float,)): # Some people apparently take "version number" too literally :) dist.metadata.version = str(dist.metadata.version) - - # This bit of hackery is necessary so that the Distribution will ignore - # normally unsupport command options (namely pre-hooks and post-hooks). - # dist.command_options is normally a dict mapping command names to - # dicts of their options. Now it will be a defaultdict that returns - # IgnoreDicts for the each command's options so we can pass through the - # unsupported options - ignore = ['pre_hook.*', 'post_hook.*'] - dist.command_options = util.DefaultGetDict( - lambda: util.IgnoreDict(ignore) - ) finally: _restore_distribution_monkeypatch() diff --git a/pbr/tests/test_hooks.py b/pbr/tests/test_hooks.py index 0759706..0fcf96c 100644 --- a/pbr/tests/test_hooks.py +++ b/pbr/tests/test_hooks.py @@ -39,9 +39,7 @@ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS import os -import textwrap -from testtools import content from testtools import matchers from pbr.tests import base @@ -56,10 +54,6 @@ class TestHooks(base.BaseTestCase): 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. @@ -72,28 +66,6 @@ class TestHooks(base.BaseTestCase): 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, stderr, return_code = self.run_setup('build_ext') - self.addDetailUniqueName('stderr', content.text_content(stderr)) - 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 - self.expectThat(stdout, matchers.EndsWith('build_ext post-hook')) - assert return_code == 0 - def test_custom_commands_known(self): stdout, _, return_code = self.run_setup('--help-commands') self.assertFalse(return_code) diff --git a/pbr/tests/testpackage/setup.cfg b/pbr/tests/testpackage/setup.cfg index 242c9c6..d10a87e 100644 --- a/pbr/tests/testpackage/setup.cfg +++ b/pbr/tests/testpackage/setup.cfg @@ -51,7 +51,3 @@ optional = True # 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/util.py b/pbr/util.py index c07376e..dc8995e 100644 --- a/pbr/util.py +++ b/pbr/util.py @@ -264,8 +264,6 @@ def cfg_to_args(path='setup.cfg', script_args=()): if entry_points: kwargs['entry_points'] = entry_points - wrap_commands(kwargs) - # Handle the [files]/extra_files option files_extra_files = has_get_option(config, 'files', 'extra_files') if files_extra_files: @@ -552,103 +550,6 @@ def get_entry_points(config): for option, value in config['entry_points'].items()) -def wrap_commands(kwargs): - dist = st_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() - - # Setuptools doesn't patch get_command_list, and as such we do not get - # extra commands from entry_points. As we need to be compatable we deal - # with this here. - for ep in pkg_resources.iter_entry_points('distutils.commands'): - if ep.name not in dist.cmdclass: - if hasattr(ep, 'resolve'): - cmdclass = ep.resolve() - else: - # Old setuptools does not have ep.resolve, and load with - # arguments is depricated in 11+. Use resolve, 12+, if we - # can, otherwise fall back to load. - # Setuptools 11 will throw a deprication warning, as it - # uses _load instead of resolve. - cmdclass = ep.load(False) - dist.cmdclass[ep.name] = cmdclass - - 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 errors.DistutilsModuleError('cannot find hook %s: %s' % - (hook,err)) - else: - hook_obj = hook - - if not hasattr(hook_obj, '__call__'): - raise errors.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] @@ -684,20 +585,3 @@ class DefaultGetDict(defaultdict): 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/releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml b/releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml new file mode 100644 index 0000000..c6ce753 --- /dev/null +++ b/releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + Support for entry point command hooks has been removed. This feature was + poorly tested, poorly documented, and broken in some environments. + Support for global hooks is not affected. |