From 2d0afbf1cf8ccbb8f494bffd919a5a945d850123 Mon Sep 17 00:00:00 2001 From: Dirk Mueller Date: Wed, 27 Sep 2017 16:56:20 +0200 Subject: [PATCH] Add option to skip certain python version This can be used on CentOS to default to skipping the py3 expansion as well as, if set to py2, generate python3-only spec files from the same singlespec input. Change-Id: I94926258ebd50a478e79717d4b0ad6fa1736d1c2 --- doc/source/usage.rst | 12 +++++ renderspec/__init__.py | 28 ++++++++--- renderspec/contextfuncs.py | 16 ++++--- renderspec/dist-templates/fedora.spec.j2 | 6 +++ renderspec/dist-templates/suse.spec.j2 | 1 + tests.py | 60 +++++++++++++++--------- 6 files changed, 89 insertions(+), 34 deletions(-) diff --git a/doc/source/usage.rst b/doc/source/usage.rst index 3da4d0d..d937933 100644 --- a/doc/source/usage.rst +++ b/doc/source/usage.rst @@ -23,6 +23,18 @@ be done with:: renderspec --spec-style suse example.spec.j2 +Different pyver variants +************************ + +For singlespec variant spec.j2 templates (i.e. templates that can build for +multiple python flavors in parallel) it might be undesirable to expand requirements +for a particular python flavor. In that case the option `--skip-pyversion` can +be used to skip expansion for those dependencies: + + renderspec --skip-pyversion py3 example.spec.j2 + +For CentOS 7.x hosts :program:`renderspec` defaults to skipping the py3 expansion. + Different template formats ************************** The only supported input template format is currently called `spec.j2` (which is diff --git a/renderspec/__init__.py b/renderspec/__init__.py index a868042..a31e5fd 100644 --- a/renderspec/__init__.py +++ b/renderspec/__init__.py @@ -31,19 +31,20 @@ from renderspec import versions from renderspec import contextfuncs -def generate_spec(spec_style, epochs, requirements, input_template_format, - input_template_path, output_path): +def generate_spec(spec_style, epochs, requirements, skip_pyversion, + input_template_format, input_template_path, output_path): """generate a spec file with the given style and input template""" if input_template_format == 'spec.j2': return _renderer_input_template_format_spec( - spec_style, epochs, requirements, input_template_path, - output_path) + spec_style, epochs, requirements, skip_pyversion, + input_template_path, output_path) else: raise Exception('Unknown input-template-format "%s"' % input_template_format) def _renderer_input_template_format_spec(spec_style, epochs, requirements, + skip_pyversion, input_template_path, output_path): """render a 'traditional' .spec.j2 template into a .spec file""" env = Environment(loader=RenderspecLoader( @@ -64,6 +65,7 @@ def _renderer_input_template_format_spec(spec_style, epochs, requirements, output_dir = None return template.render(spec_style=spec_style, epochs=epochs, requirements=requirements, + skip_pyversion=skip_pyversion, input_template_dir=input_template_dir, output_dir=output_dir) @@ -102,6 +104,15 @@ def _get_default_distro(): return "unknown" +def _get_default_pyskips(distro): + # py3 building is all complicated on CentOS 7.x + if distro == 'fedora': + distname, distver, _ = platform.linux_distribution() + if 'CentOS' in distname and distver.startswith('7'): + return 'py3' + return None + + def _get_default_template(): fns = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.spec.j2')] @@ -145,6 +156,10 @@ def process_args(): parser.add_argument("--spec-style", help="distro style you want to use. " "default: %s" % (distro), default=distro, choices=['suse', 'fedora']) + parser.add_argument("--skip-pyversion", + help='Skip requirements for this pyversion', + default=_get_default_pyskips(distro), + choices=['py2', 'py3']) parser.add_argument("--epochs", help="yaml file with epochs listed.") parser.add_argument("input-template", nargs='?', help="specfile jinja2 template to render. " @@ -191,8 +206,9 @@ def main(): output_path = None spec = generate_spec(args['spec_style'], epochs, requirements, - args['input_template_format'], input_template, - output_path) + args['skip_pyversion'], + args['input_template_format'], + input_template, output_path) if output_path: print("Rendering: %s -> %s" % (input_template, output_path)) with open(output_path, "w") as o: diff --git a/renderspec/contextfuncs.py b/renderspec/contextfuncs.py index 97ac4bd..3e2ea3e 100644 --- a/renderspec/contextfuncs.py +++ b/renderspec/contextfuncs.py @@ -147,12 +147,16 @@ def _context_epoch(context, pkg_name): return context['epochs'].get(pkg_name, 0) -def _pymod2pkg_translate(pkg_name, spec_style, py_versions): +def _pymod2pkg_translate(pkg_name, context, py_versions): """translate a given package name for a single or multiple py versions""" if py_versions and not isinstance(py_versions, (list, tuple)): py_versions = [py_versions] - kwargs = {'py_vers': py_versions} if py_versions else {} - translations = pymod2pkg.module2package(pkg_name, spec_style, **kwargs) + kwargs = {} + if py_versions: + kwargs['py_vers'] = list(set(py_versions) - + set((context['skip_pyversion'],))) + translations = pymod2pkg.module2package( + pkg_name, context['spec_style'], **kwargs) # we want always return a list but module2package() might return a string if not isinstance(translations, (list, tuple)): translations = [translations] @@ -175,14 +179,12 @@ def _context_py2name(context, pkg_name=None, pkg_version=None, 'py2name') pkg_name = context.vars[CONTEXT_VAR_PYPI_NAME] # return always a string to be backwards compat - return ' '.join(_pymod2pkg_translate( - pkg_name, context['spec_style'], py_versions)) + return ' '.join(_pymod2pkg_translate(pkg_name, context, py_versions)) def _context_py2pkg(context, pkg_name, pkg_version=None, py_versions=None): """generate a distro specific package name with optional version tuple.""" - name_list = _pymod2pkg_translate(pkg_name, context['spec_style'], - py_versions) + name_list = _pymod2pkg_translate(pkg_name, context, py_versions) # if no pkg_version is given, look in the requirements and set one if not pkg_version: diff --git a/renderspec/dist-templates/fedora.spec.j2 b/renderspec/dist-templates/fedora.spec.j2 index 1de041f..4d21857 100644 --- a/renderspec/dist-templates/fedora.spec.j2 +++ b/renderspec/dist-templates/fedora.spec.j2 @@ -1,3 +1,9 @@ +%if 0%{?rhel} || 0%{?fedora} +%global rdo 1 +%endif +%if 0%{?rhel} == 7 +%global skip_python3 1 +%endif {% extends ".spec" %} {% block build_requires %} BuildRequires: {{ py2pkg('setuptools') }} diff --git a/renderspec/dist-templates/suse.spec.j2 b/renderspec/dist-templates/suse.spec.j2 index 3c0ff45..ebd4bb1 100644 --- a/renderspec/dist-templates/suse.spec.j2 +++ b/renderspec/dist-templates/suse.spec.j2 @@ -1,3 +1,4 @@ +%{?!python_module:%define python_module() python-%{**} python3-%{**}} {% extends ".spec" %} {% block build_requires %} BuildRequires: openstack-macros diff --git a/tests.py b/tests.py index de61789..1bec892 100644 --- a/tests.py +++ b/tests.py @@ -62,57 +62,73 @@ class RenderspecContextFunctionTests(unittest.TestCase): 'oslo.config', None, ('py', 'py3'), 'python-oslo.config python3-oslo.config'), # with version - ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, + ({'epochs': {}, 'requirements': {}}, 'oslo.config', ('>=', '1.2.3'), None, 'python-oslo.config >= 1.2.3'), ({'spec_style': 'fedora', 'epochs': {}, 'requirements': {}}, 'oslo.config', ('==', '1.2.3~a0'), None, 'python-oslo-config == 1.2.3~a0'), # with version, with epoch - ({'spec_style': 'suse', 'epochs': {'oslo.config': 4}, + ({'epochs': {'oslo.config': 4}, 'requirements': {}}, 'oslo.config', ('>=', '1.2.3'), None, 'python-oslo.config >= 4:1.2.3'), # without version, with epoch - ({'spec_style': 'suse', 'epochs': {'oslo.config': 4}, + ({'epochs': {'oslo.config': 4}, 'requirements': {}}, 'oslo.config', None, None, 'python-oslo.config'), # with version, with requirements - ({'spec_style': 'suse', 'epochs': {}, + ({'epochs': {}, 'requirements': {'oslo.config' '1.2.3'}}, 'oslo.config', ('>=', '4.5.6'), None, 'python-oslo.config >= 4.5.6'), # without version, with requirements - ({'spec_style': 'suse', 'epochs': {}, + ({'epochs': {}, 'requirements': {'oslo.config': '1.2.3'}}, 'oslo.config', None, None, 'python-oslo.config >= 1.2.3'), # without version, with requirements, with epoch - ({'spec_style': 'suse', 'epochs': {'oslo.config': 4}, + ({'epochs': {'oslo.config': 4}, 'requirements': {'oslo.config': '1.2.3'}}, 'oslo.config', None, None, 'python-oslo.config >= 4:1.2.3'), # with version, with requirements, with epoch - ({'spec_style': 'suse', 'epochs': {'oslo.config': 4}, + ({'epochs': {'oslo.config': 4}, 'requirements': {'oslo.config' '1.2.3'}}, 'oslo.config', ('>=', '4.5.6'), None, 'python-oslo.config >= 4:4.5.6'), # with version, with requirements, with epoch, python2 - ({'spec_style': 'suse', 'epochs': {'oslo.config': 4}, + ({'epochs': {'oslo.config': 4}, 'requirements': {'oslo.config' '1.2.3'}}, 'oslo.config', ('>=', '4.5.6'), 'py2', 'python2-oslo.config >= 4:4.5.6'), # with version, with requirements, with epoch, python3 - ({'spec_style': 'suse', 'epochs': {'oslo.config': 4}, + ({'epochs': {'oslo.config': 4}, 'requirements': {'oslo.config' '1.2.3'}}, 'oslo.config', ('>=', '4.5.6'), 'py3', 'python3-oslo.config >= 4:4.5.6'), + # with version, with requirements, python3, skip python3 + ({'epochs': {}, 'skip_pyversion': 'py3', + 'requirements': {'oslo.config' '1.2.3'}}, + 'oslo.config', ('>=', '4.5.6'), 'py3', + ''), # with version, with requirements, with epoch, python2 and python3 - ({'spec_style': 'suse', 'epochs': {'oslo.config': 4}, + ({'epochs': {'oslo.config': 4}, 'requirements': {'oslo.config' '1.2.3'}}, 'oslo.config', ('>=', '4.5.6'), ['py2', 'py3'], 'python2-oslo.config >= 4:4.5.6 python3-oslo.config >= 4:4.5.6'), - + # with version, with requirements, python2 and python3, skip python3 + ({'epochs': {'oslo.config': 4}, 'skip_pyversion': 'py3', + 'requirements': {'oslo.config' '1.2.3'}}, + 'oslo.config', ('>=', '4.5.6'), ['py2', 'py3'], + 'python2-oslo.config >= 4:4.5.6'), + # with version, with requirements, python2 and python3, skip python2 + ({'epochs': {'oslo.config': 4}, 'skip_pyversion': 'py2', + 'requirements': {'oslo.config' '1.2.3'}}, + 'oslo.config', ('>=', '4.5.6'), ['py2', 'py3'], + 'python3-oslo.config >= 4:4.5.6'), ) @unpack def test_context_py2pkg(self, context, pkg_name, pkg_version, py_versions, expected_result): + context.setdefault('skip_pyversion', ()) + context.setdefault('spec_style', 'suse') self.assertEqual( renderspec.contextfuncs._context_py2pkg( context, pkg_name, pkg_version, py_versions), @@ -180,32 +196,32 @@ class RenderspecTemplateFunctionTests(unittest.TestCase): @data( # plain - ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, + ({'epochs': {}, 'requirements': {}}, "{{ py2pkg('requests') }}", "python-requests"), # plain, with multiple py_versions - ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, + ({'epochs': {}, 'requirements': {}}, "{{ py2pkg('requests', py_versions=['py2', 'py3']) }}", "python2-requests python3-requests"), # with version - ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, + ({'epochs': {}, 'requirements': {}}, "{{ py2pkg('requests', ('>=', '2.8.1')) }}", "python-requests >= 2.8.1"), # with version, with epoch - ({'spec_style': 'suse', 'epochs': {'requests': 4}, 'requirements': {}}, + ({'epochs': {'requests': 4}, 'requirements': {}}, "{{ py2pkg('requests', ('>=', '2.8.1')) }}", "python-requests >= 4:2.8.1"), # with version, with epoch, with requirements - ({'spec_style': 'suse', 'epochs': {'requests': 4}, + ({'epochs': {'requests': 4}, 'requirements': {'requests': '1.2.3'}}, "{{ py2pkg('requests', ('>=', '2.8.1')) }}", "python-requests >= 4:2.8.1"), # without version, with epoch, with requirements - ({'spec_style': 'suse', 'epochs': {'requests': 4}, + ({'epochs': {'requests': 4}, 'requirements': {'requests': '1.2.3'}}, "{{ py2pkg('requests') }}", "python-requests >= 4:1.2.3"), # without version, with epoch, with requirements, with py_versions - ({'spec_style': 'suse', 'epochs': {'requests': 4}, + ({'epochs': {'requests': 4}, 'requirements': {'requests': '1.2.3'}}, "{{ py2pkg('requests', py_versions=['py2']) }}", "python2-requests >= 4:1.2.3"), @@ -213,6 +229,8 @@ class RenderspecTemplateFunctionTests(unittest.TestCase): @unpack def test_render_func_py2pkg(self, context, string, expected_result): template = self.env.from_string(string) + context.setdefault('skip_pyversion', ()) + context.setdefault('spec_style', 'suse') self.assertEqual( template.render(**context), expected_result) @@ -421,8 +439,8 @@ class RenderspecCommonTests(unittest.TestCase): with open(f1, 'w+') as f: f.write(template) rendered = renderspec.generate_spec( - style, epochs, requirements, 'spec.j2', f1, None) - self.assertEqual(rendered, expected_result) + style, epochs, requirements, (), 'spec.j2', f1, None) + self.assertTrue(rendered.endswith(expected_result)) finally: shutil.rmtree(tmpdir) @@ -484,7 +502,7 @@ class RenderspecDistTeamplatesTests(unittest.TestCase): # mock this to use testing dist-tempaltes folder mock_dt_path.return_value = dt_dir - out = renderspec.generate_spec('loldistro', {}, {}, 'spec.j2', + out = renderspec.generate_spec('loldistro', {}, {}, (), 'spec.j2', base_path, None) self.assertEqual(out, expected_out) finally: