Hello community, here is the log from the commit of package python-renderspec for openSUSE:Factory checked in at 2017-09-15 22:32:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-renderspec (Old) and /work/SRC/openSUSE:Factory/.python-renderspec.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-renderspec" Fri Sep 15 22:32:02 2017 rev:5 rq:526334 version:1.7.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-renderspec/python-renderspec.changes 2017-05-31 12:21:03.669228919 +0200 +++ /work/SRC/openSUSE:Factory/.python-renderspec.new/python-renderspec.changes 2017-09-15 22:32:02.973226125 +0200 @@ -1,0 +2,13 @@ +Fri Sep 15 09:36:33 UTC 2017 - [email protected] + +- update to version 1.7.0 + - Support different py versions in py2name() and py2pkg() + - Clarify variable name + - Add context function `url_pypi` + - Introduce a new --input-template-format switch + - Semantically determine lowest version number, not lexigraphically + - Move context related functions to extra file + - Fix rc version handling on SUSE + - Updated from global requirements + +------------------------------------------------------------------- Old: ---- renderspec-1.6.1.tar.gz New: ---- renderspec-1.7.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-renderspec.spec ++++++ --- /var/tmp/diff_new_pack.QYNtIq/_old 2017-09-15 22:32:03.813107817 +0200 +++ /var/tmp/diff_new_pack.QYNtIq/_new 2017-09-15 22:32:03.817107253 +0200 @@ -18,7 +18,7 @@ %global sname renderspec Name: python-renderspec -Version: 1.6.1 +Version: 1.7.0 Release: 0 Summary: Generate spec files from Jinja2 templates License: Apache-2.0 ++++++ renderspec-1.6.1.tar.gz -> renderspec-1.7.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/ChangeLog new/renderspec-1.7.0/ChangeLog --- old/renderspec-1.6.1/ChangeLog 2017-05-30 14:20:54.000000000 +0200 +++ new/renderspec-1.7.0/ChangeLog 2017-09-14 17:18:50.000000000 +0200 @@ -1,6 +1,25 @@ CHANGES ======= +1.7.0 +----- + +* Support different py versions in py2name() and py2pkg() +* Updated from global requirements +* Fix rc version handling on SUSE +* Updated from global requirements +* Introduce a new --input-template-format switch +* Move context related functions to extra file +* Clarify variable name +* Updated from global requirements +* Add context function \`url\_pypi\` +* Updated from global requirements + +1.6.2 +----- + +* Semantically determine lowest version number, not lexigraphically + 1.6.1 ----- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/PKG-INFO new/renderspec-1.7.0/PKG-INFO --- old/renderspec-1.6.1/PKG-INFO 2017-05-30 14:20:54.000000000 +0200 +++ new/renderspec-1.7.0/PKG-INFO 2017-09-14 17:18:51.000000000 +0200 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: renderspec -Version: 1.6.1 +Version: 1.7.0 Summary: Jinja2 template renderer for generating .spec files Home-page: http://docs.openstack.org/developer/renderspec/ Author: OpenStack Author-email: [email protected] License: UNKNOWN +Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/doc/source/usage.rst new/renderspec-1.7.0/doc/source/usage.rst --- old/renderspec-1.6.1/doc/source/usage.rst 2017-05-30 14:18:19.000000000 +0200 +++ new/renderspec-1.7.0/doc/source/usage.rst 2017-09-14 17:16:57.000000000 +0200 @@ -23,6 +23,10 @@ renderspec --spec-style suse example.spec.j2 +Different template formats +************************** +The only supported input template format is currently called `spec.j2` (which is +the default). Handling epochs *************** @@ -179,6 +183,21 @@ If the context env var `pypi_name` is set **and** `py2name` is called with a parameter, the parameter is used instead of the context var. +Since `pymod2pkg 0.10.0`, there is the possibility to get a name for a specific python +version. Currently there are 3 values + +* `py`: this is the unversioned name +* `py2`: this is the python2 name +* `py3`: this is the python3 name + +This can also be used with `py2name()`:: + + Name: {{ py2name('oslo.config', py_versions='py3') }} + +Rendering this template :program:`renderspec` with the `suse` style would result in:: + + Name: python3-oslo.config + context function `py2pkg` ************************* @@ -211,6 +230,22 @@ BuildRequires: python-oslo-config >= 4.3.0 +The translation for a specific python version can be done with the `py_versions` parameter +similar to `py2name()```:: + + BuildRequires: {{ py2pkg('oslo.config', ('>=', '3.4.0'), py_versions='py3') }} + +renders to:: + + BuildRequires: python3-oslo-config >= 2:3.4.0 + +Multiple versions are also possible:: + + BuildRequires: {{ py2pkg('oslo.config', ('>=', '3.4.0'), py_versions=['py2', 'py3']) }} + +renders to:: + + BuildRequires: python2-oslo-config >= 2:3.4.0 python3-oslo-config >= 2:3.4.0 context function `epoch` ************************ @@ -323,6 +358,17 @@ Source0: {{ source }} +context function `url_pypi` +*************************** +The function `url_pypi` return a full url to a sdist tar.gz tarball on pypi. The function +requires the contect variables `upstream_version` and `pypi_name`. +For example:: + + {% set pypi_name = 'oslo.concurrency' %} + {% set upstream_version = upstream_version('3.20.0') %} + {% set source = fetch_source(url_pypi()) %} + + context filter `basename` ************************* This is a filter which just returns ```os.path.basename()```:: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/renderspec/__init__.py new/renderspec-1.7.0/renderspec/__init__.py --- old/renderspec-1.6.1/renderspec/__init__.py 2017-05-30 14:18:19.000000000 +0200 +++ new/renderspec-1.7.0/renderspec/__init__.py 2017-09-14 17:16:57.000000000 +0200 @@ -21,273 +21,35 @@ import platform import sys -from jinja2 import contextfilter -from jinja2 import contextfunction from jinja2 import Environment -from jinja2.exceptions import TemplateRuntimeError -from packaging.version import parse -import pymod2pkg import yaml from renderspec.distloader import RenderspecLoader -from renderspec import utils from renderspec import versions +from renderspec import contextfuncs -# a variable that needs to be set for some functions in the context -CONTEXT_VAR_PYPI_NAME = "pypi_name" -CONTEXT_VAR_UPSTREAM_VERSION = "upstream_version" -CONTEXT_VAR_RPM_RELEASE = "rpm_release" - - -def _context_check_variable(context, var_name, needed_by): - """check that the context has a given variable""" - if var_name not in context.vars: - raise TemplateRuntimeError("Variable '%s' not available in context but" - " needed for '%s'" % (var_name, needed_by)) - - -def _context_fetch_source(context, url): - """fetch the given url into the output_dir and return the url""" - if context['output_dir']: - filename = os.path.basename(url) - utils._download_file(url, context['output_dir'], filename) - return url - - -def _context_upstream_version(context, pkg_version=None): - """return the version which should be set to the 'upstream_version' - variable in the jinja context""" - if pkg_version: - return pkg_version +def generate_spec(spec_style, epochs, requirements, 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) else: - # try to auto-detect the version - for that we need the pypi name - _context_check_variable(context, CONTEXT_VAR_PYPI_NAME, - 'upstream_version') - pypi_name = context.vars[CONTEXT_VAR_PYPI_NAME] - - # look for archives in: - # 1) the output_dir - # 2) the dir where the input template (.spec.j2) comes from - # 3) the current working dir - archives = utils._find_archives([context['output_dir'], - context['input_template_dir'], - '.'], pypi_name) - for archive in archives: - with utils._extract_archive_to_tempdir(archive) as tmpdir: - pkg_info_file = utils._find_pkg_info(tmpdir) - if pkg_info_file: - return utils._get_version_from_pkg_info(pkg_info_file) - # unable to autodetect the version - raise TemplateRuntimeError("Can not autodetect 'upstream_version' from" - " the following archives: '%s'" % ( - ', '.join(archives))) - - -def _context_py2rpmversion(context): - """get a python PEP0440 compatible version and translate it to an RPM - version""" - # the context needs a variable set via {% set upstream_version = 'ver' %} - _context_check_variable(context, CONTEXT_VAR_UPSTREAM_VERSION, - 'py2rpmversion') - version = context.vars[CONTEXT_VAR_UPSTREAM_VERSION] - v_python = parse(version) - # fedora does not allow '~' in versions but uses a combination of Version - # and Release - # https://fedoraproject.org/wiki/Packaging:Versioning\#Pre-Release_packages - if context['spec_style'] == 'fedora': - if len(v_python._version.release) >= 4: - return "%d.%d.%d" % (v_python._version.release[0:3]) - else: - return v_python.base_version - else: - v_rpm = v_python.public - if v_python.is_prerelease: - # we need to add the 'x' in front of alpha/beta releases because - # in the python world, "1.1a10" > "1.1.dev10" - # but in the rpm world, "1.1~a10" < "1.1~dev10" - v_rpm = v_rpm.replace('a', '~xalpha') - v_rpm = v_rpm.replace('b', '~xbeta') - v_rpm = v_rpm.replace('rc', '~rc') - v_rpm = v_rpm.replace('.dev', '~dev') - return v_rpm - - -def _context_py2rpmrelease(context): - if context['spec_style'] == 'fedora': - # the context needs a var set via {% set upstream_version = 'ver' %} - _context_check_variable(context, CONTEXT_VAR_UPSTREAM_VERSION, - 'py2rpmrelease') - # the context needs a var set via {% set rpm_release = 'ver' %} - _context_check_variable(context, CONTEXT_VAR_RPM_RELEASE, - 'py2rpmrelease') - upstream_version = context.vars[CONTEXT_VAR_UPSTREAM_VERSION] - rpm_release = context.vars[CONTEXT_VAR_RPM_RELEASE] - v_python = parse(upstream_version) - if v_python.is_prerelease: - _, alphatag = v_python.public.split(v_python.base_version) - return '0.{}.{}%{{?dist}}'.format(rpm_release, - alphatag.lstrip('.')) - else: - return '{}%{{?dist}}'.format(rpm_release) - else: - # SUSE uses just '0'. The OpenBuildService handles the Release tag - return '0' - - -def _context_epoch(context, pkg_name): - """get the epoch (or 0 if unknown) for the given pkg name""" - return context['epochs'].get(pkg_name, 0) - - -def _context_py2name(context, pkg_name=None): - if not pkg_name: - # if the name is not given, try to get the name from the context - _context_check_variable(context, CONTEXT_VAR_PYPI_NAME, - 'py2name') - pkg_name = context.vars[CONTEXT_VAR_PYPI_NAME] - return pymod2pkg.module2package(pkg_name, context['spec_style']) - - -def _context_py2pkg(context, pkg_name, pkg_version=None): - """generate a distro specific package name with optional version tuple.""" - # package name handling - name = pymod2pkg.module2package(pkg_name, context['spec_style']) - - # if no pkg_version is given, look in the requirements and set one - if not pkg_version: - if pkg_name in context['requirements']: - pkg_version = ('>=', context['requirements'][pkg_name]) - - # pkg_version is a tuple with comparator and number, i.e. "('>=', '1.2.3')" - if pkg_version: - # epoch handling - if pkg_name in context['epochs'].keys(): - epoch = '%s:' % context['epochs'][pkg_name] - else: - epoch = '' - v_comparator, v_number = pkg_version - v_str = ' %s %s%s' % (v_comparator, epoch, v_number) - else: - v_str = '' - - return '%s%s' % (name, v_str) - - -def _context_license_spdx(context, value): - """convert a given known spdx license to another one""" - # more values can be taken from from https://github.com/hughsie/\ - # appstream-glib/blob/master/libappstream-builder/asb-package-rpm.c#L76 - mapping = { - "Apache-1.1": "ASL 1.1", - "Apache-2.0": "ASL 2.0", - "BSD-3-Clause": "BSD", - "GPL-1.0+": "GPL+", - "GPL-2.0": "GPLv2", - "GPL-2.0+": "GPLv2+", - "GPL-3.0": "GPLv3", - "GPL-3.0+": "GPLv3+", - "LGPL-2.1": "LGPLv2.1", - "LGPL-2.1+": "LGPLv2+", - "LGPL-2.0": "LGPLv2 with exceptions", - "LGPL-2.0+": "LGPLv2+ with exceptions", - "LGPL-3.0": "LGPLv3", - "LGPL-3.0+": "LGPLv3+", - "MIT": "MIT with advertising", - "MPL-1.0": "MPLv1.0", - "MPL-1.1": "MPLv1.1", - "MPL-2.0": "MPLv2.0", - "OFL-1.1": "OFL", - "Python-2.0": "Python", - } - - if context['spec_style'] == 'fedora': - return mapping[value] - else: - # just use the spdx license name - return value - - -############### -# jinja2 filter -############### -@contextfilter -def _filter_epoch(context, value): - return _context_epoch(context, value) - - -@contextfilter -def _filter_basename(context, value): - return os.path.basename(value) - - -################ -# jinja2 globals -################ -@contextfunction -def _globals_py2pkg(context, pkg_name, pkg_version=None): - return _context_py2pkg(context, pkg_name, pkg_version) - - -@contextfunction -def _globals_fetch_source(context, url): - return _context_fetch_source(context, url) - - -@contextfunction -def _globals_upstream_version(context, pkg_version=None): - return _context_upstream_version(context, pkg_version) - - -@contextfunction -def _globals_py2rpmversion(context): - return _context_py2rpmversion(context) - - -@contextfunction -def _globals_py2rpmrelease(context): - return _context_py2rpmrelease(context) - - -@contextfunction -def _globals_epoch(context, value): - return _context_epoch(context, value) - - -@contextfunction -def _globals_license_spdx(context, value): - return _context_license_spdx(context, value) - - -@contextfunction -def _globals_py2name(context, value=None): - return _context_py2name(context, value) - - -def _env_register_filters_and_globals(env): - """register all the jinja2 filters we want in the environment""" - env.filters['epoch'] = _filter_epoch - env.filters['basename'] = _filter_basename - env.globals['py2rpmversion'] = _globals_py2rpmversion - env.globals['py2rpmrelease'] = _globals_py2rpmrelease - env.globals['py2pkg'] = _globals_py2pkg - env.globals['py2name'] = _globals_py2name - env.globals['epoch'] = _globals_epoch - env.globals['license'] = _globals_license_spdx - env.globals['upstream_version'] = _globals_upstream_version - env.globals['fetch_source'] = _globals_fetch_source - + raise Exception('Unknown input-template-format "%s"' % + input_template_format) -def generate_spec(spec_style, epochs, requirements, input_template_path, - output_path): - """generate a spec file with the given style and the given template""" +def _renderer_input_template_format_spec(spec_style, epochs, requirements, + input_template_path, output_path): + """render a 'traditional' .spec.j2 template into a .spec file""" env = Environment(loader=RenderspecLoader( template_fn=input_template_path), trim_blocks=True) - _env_register_filters_and_globals(env) + contextfuncs.env_register_filters_and_globals(env) template_name = '.spec' if spec_style in env.loader.list_templates(): @@ -371,6 +133,9 @@ parser.add_argument("input-template", nargs='?', help="specfile jinja2 template to render. " "default: *.spec.j2") + parser.add_argument("-f", "--input-template-format", help="Format of the " + "input-template file. default: %(default)s", + default="spec.j2", choices=["spec.j2"]) parser.add_argument("--requirements", help="file(s) which contain " "PEP0508 compatible requirement lines. Last mentioned " "file has highest priority. default: %(default)s", @@ -389,13 +154,13 @@ if not input_template: print(errmsg) return 1 - output_fn = args['output'] - if not output_fn: + output_filename = args['output'] + if not output_filename: if not input_template.endswith('.spec.j2'): print("Failed to autodetect output file name. " "Please specify using `-o/--output`.") return 2 - output_fn, _, _ = input_template.rpartition('.') + output_filename, _, _ = input_template.rpartition('.') try: epochs = _get_epochs(args['epochs']) @@ -404,13 +169,14 @@ print(e) return 3 - if output_fn and output_fn != '-': - output_path = os.path.abspath(output_fn) + if output_filename and output_filename != '-': + output_path = os.path.abspath(output_filename) else: output_path = None spec = generate_spec(args['spec_style'], epochs, requirements, - input_template, output_path) + 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/renderspec/contextfuncs.py new/renderspec-1.7.0/renderspec/contextfuncs.py --- old/renderspec-1.6.1/renderspec/contextfuncs.py 1970-01-01 01:00:00.000000000 +0100 +++ new/renderspec-1.7.0/renderspec/contextfuncs.py 2017-09-14 17:16:57.000000000 +0200 @@ -0,0 +1,314 @@ +# Copyright (c) 2017 SUSE Linux GmbH +# +# 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 + +import os + +from jinja2 import contextfilter +from jinja2 import contextfunction +from jinja2.exceptions import TemplateRuntimeError +from packaging.version import parse +import pymod2pkg + +from renderspec import utils + + +# a variable that needs to be set for some functions in the context +CONTEXT_VAR_PYPI_NAME = "pypi_name" +CONTEXT_VAR_UPSTREAM_VERSION = "upstream_version" +CONTEXT_VAR_RPM_RELEASE = "rpm_release" + + +def _context_check_variable(context, var_name, needed_by): + """check that the context has a given variable""" + if var_name not in context.vars: + raise TemplateRuntimeError("Variable '%s' not available in context but" + " needed for '%s'" % (var_name, needed_by)) + + +def _context_fetch_source(context, url): + """fetch the given url into the output_dir and return the url""" + if context['output_dir']: + filename = os.path.basename(url) + utils._download_file(url, context['output_dir'], filename) + return url + + +def _context_url_pypi(context): + """return the full sdist pypi url""" + # we need the pypi_name and the upstream_version variables to construct + # the full url + _context_check_variable(context, CONTEXT_VAR_PYPI_NAME, + 'pypi_name') + + _context_check_variable(context, CONTEXT_VAR_UPSTREAM_VERSION, + 'upstream_version') + name = context.vars[CONTEXT_VAR_PYPI_NAME] + version = context.vars[CONTEXT_VAR_UPSTREAM_VERSION] + return 'https://files.pythonhosted.org/packages/source/' \ + '%s/%s/%s-%s.tar.gz' % (name[0], name, name, version) + + +def _context_upstream_version(context, pkg_version=None): + """return the version which should be set to the 'upstream_version' + variable in the jinja context""" + if pkg_version: + return pkg_version + else: + # try to auto-detect the version - for that we need the pypi name + _context_check_variable(context, CONTEXT_VAR_PYPI_NAME, + 'upstream_version') + pypi_name = context.vars[CONTEXT_VAR_PYPI_NAME] + + # look for archives in: + # 1) the output_dir + # 2) the dir where the input template (.spec.j2) comes from + # 3) the current working dir + archives = utils._find_archives([context['output_dir'], + context['input_template_dir'], + '.'], pypi_name) + for archive in archives: + with utils._extract_archive_to_tempdir(archive) as tmpdir: + pkg_info_file = utils._find_pkg_info(tmpdir) + if pkg_info_file: + return utils._get_version_from_pkg_info(pkg_info_file) + # unable to autodetect the version + raise TemplateRuntimeError("Can not autodetect 'upstream_version' from" + " the following archives: '%s'" % ( + ', '.join(archives))) + + +def _context_py2rpmversion(context): + """get a python PEP0440 compatible version and translate it to an RPM + version""" + # the context needs a variable set via {% set upstream_version = 'ver' %} + _context_check_variable(context, CONTEXT_VAR_UPSTREAM_VERSION, + 'py2rpmversion') + version = context.vars[CONTEXT_VAR_UPSTREAM_VERSION] + v_python = parse(version) + # fedora does not allow '~' in versions but uses a combination of Version + # and Release + # https://fedoraproject.org/wiki/Packaging:Versioning\#Pre-Release_packages + if context['spec_style'] == 'fedora': + if len(v_python._version.release) >= 4: + return "%d.%d.%d" % (v_python._version.release[0:3]) + else: + return v_python.base_version + else: + v_rpm = v_python.public + if v_python.is_prerelease: + # we need to add the 'x' in front of alpha/beta releases because + # in the python world, "1.1a10" > "1.1.dev10" + # but in the rpm world, "1.1~a10" < "1.1~dev10" + v_rpm = v_rpm.replace('a', '~xalpha') + v_rpm = v_rpm.replace('b', '~xbeta') + v_rpm = v_rpm.replace('rc', '~xrc') + v_rpm = v_rpm.replace('.dev', '~dev') + return v_rpm + + +def _context_py2rpmrelease(context): + if context['spec_style'] == 'fedora': + # the context needs a var set via {% set upstream_version = 'ver' %} + _context_check_variable(context, CONTEXT_VAR_UPSTREAM_VERSION, + 'py2rpmrelease') + # the context needs a var set via {% set rpm_release = 'ver' %} + _context_check_variable(context, CONTEXT_VAR_RPM_RELEASE, + 'py2rpmrelease') + upstream_version = context.vars[CONTEXT_VAR_UPSTREAM_VERSION] + rpm_release = context.vars[CONTEXT_VAR_RPM_RELEASE] + v_python = parse(upstream_version) + if v_python.is_prerelease: + _, alphatag = v_python.public.split(v_python.base_version) + return '0.{}.{}%{{?dist}}'.format(rpm_release, + alphatag.lstrip('.')) + else: + return '{}%{{?dist}}'.format(rpm_release) + else: + # SUSE uses just '0'. The OpenBuildService handles the Release tag + return '0' + + +def _context_epoch(context, pkg_name): + """get the epoch (or 0 if unknown) for the given pkg name""" + return context['epochs'].get(pkg_name, 0) + + +def _pymod2pkg_translate(pkg_name, spec_style, 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) + # we want always return a list but module2package() might return a string + if not isinstance(translations, (list, tuple)): + translations = [translations] + return translations + + +def _context_py2name(context, pkg_name=None, pkg_version=None, + py_versions=None): + """ + context: a Jinja2 context + pkg_name: usually the pypi-name. If None, it tries to get the name + from the context variable called 'py2name' + pkg_version: Deprecated and unused + py_versions: the version pymod2pkg should return. Can be currently 'py', + 'py2' and 'py3' or a combination of those in a list + """ + if not pkg_name: + # if the name is not given, try to get the name from the context + _context_check_variable(context, CONTEXT_VAR_PYPI_NAME, + '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)) + + +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) + + # if no pkg_version is given, look in the requirements and set one + if not pkg_version: + if pkg_name in context['requirements']: + pkg_version = ('>=', context['requirements'][pkg_name]) + + # pkg_version is a tuple with comparator and number, i.e. "('>=', '1.2.3')" + if pkg_version: + # epoch handling + if pkg_name in context['epochs'].keys(): + epoch = '%s:' % context['epochs'][pkg_name] + else: + epoch = '' + v_comparator, v_number = pkg_version + v_str = ' %s %s%s' % (v_comparator, epoch, v_number) + else: + v_str = '' + + return ' '.join(['%s%s' % (name, v_str) for name in name_list]) + + +def _context_license_spdx(context, value): + """convert a given known spdx license to another one""" + # more values can be taken from from https://github.com/hughsie/\ + # appstream-glib/blob/master/libappstream-builder/asb-package-rpm.c#L76 + mapping = { + "Apache-1.1": "ASL 1.1", + "Apache-2.0": "ASL 2.0", + "BSD-3-Clause": "BSD", + "GPL-1.0+": "GPL+", + "GPL-2.0": "GPLv2", + "GPL-2.0+": "GPLv2+", + "GPL-3.0": "GPLv3", + "GPL-3.0+": "GPLv3+", + "LGPL-2.1": "LGPLv2.1", + "LGPL-2.1+": "LGPLv2+", + "LGPL-2.0": "LGPLv2 with exceptions", + "LGPL-2.0+": "LGPLv2+ with exceptions", + "LGPL-3.0": "LGPLv3", + "LGPL-3.0+": "LGPLv3+", + "MIT": "MIT with advertising", + "MPL-1.0": "MPLv1.0", + "MPL-1.1": "MPLv1.1", + "MPL-2.0": "MPLv2.0", + "OFL-1.1": "OFL", + "Python-2.0": "Python", + } + + if context['spec_style'] == 'fedora': + return mapping[value] + else: + # just use the spdx license name + return value + + +############### +# jinja2 filter +############### +@contextfilter +def _filter_epoch(context, value): + return _context_epoch(context, value) + + +@contextfilter +def _filter_basename(context, value): + return os.path.basename(value) + + +################ +# jinja2 globals +################ +@contextfunction +def _globals_py2pkg(context, pkg_name, pkg_version=None, py_versions=None): + return _context_py2pkg(context, pkg_name, pkg_version, py_versions) + + +@contextfunction +def _globals_fetch_source(context, url): + return _context_fetch_source(context, url) + + +@contextfunction +def _globals_url_pypi(context): + return _context_url_pypi(context) + + +@contextfunction +def _globals_upstream_version(context, pkg_version=None): + return _context_upstream_version(context, pkg_version) + + +@contextfunction +def _globals_py2rpmversion(context): + return _context_py2rpmversion(context) + + +@contextfunction +def _globals_py2rpmrelease(context): + return _context_py2rpmrelease(context) + + +@contextfunction +def _globals_epoch(context, value): + return _context_epoch(context, value) + + +@contextfunction +def _globals_license_spdx(context, value): + return _context_license_spdx(context, value) + + +@contextfunction +def _globals_py2name(context, value=None, py_versions=None): + return _context_py2name(context, value, py_versions=py_versions) + + +def env_register_filters_and_globals(env): + """register all the jinja2 filters we want in the environment""" + env.filters['epoch'] = _filter_epoch + env.filters['basename'] = _filter_basename + env.globals['py2rpmversion'] = _globals_py2rpmversion + env.globals['py2rpmrelease'] = _globals_py2rpmrelease + env.globals['py2pkg'] = _globals_py2pkg + env.globals['py2name'] = _globals_py2name + env.globals['epoch'] = _globals_epoch + env.globals['license'] = _globals_license_spdx + env.globals['upstream_version'] = _globals_upstream_version + env.globals['fetch_source'] = _globals_fetch_source + env.globals['url_pypi'] = _globals_url_pypi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/renderspec/versions.py new/renderspec-1.7.0/renderspec/versions.py --- old/renderspec-1.6.1/renderspec/versions.py 2017-05-30 14:18:19.000000000 +0200 +++ new/renderspec-1.7.0/renderspec/versions.py 2017-09-14 17:16:57.000000000 +0200 @@ -17,6 +17,7 @@ from __future__ import print_function from packaging.requirements import Requirement +from packaging.version import Version def get_requirements(lines): @@ -46,9 +47,9 @@ # we don't want a lowest version which is not allowed if s.operator == '!=': continue - if not lowest or s.version < lowest.version: - lowest = s + if not lowest or Version(s.version) < lowest: + lowest = Version(s.version) if lowest: - requires[r.name] = lowest.version + requires[r.name] = str(lowest) return requires diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/renderspec.egg-info/PKG-INFO new/renderspec-1.7.0/renderspec.egg-info/PKG-INFO --- old/renderspec-1.6.1/renderspec.egg-info/PKG-INFO 2017-05-30 14:20:54.000000000 +0200 +++ new/renderspec-1.7.0/renderspec.egg-info/PKG-INFO 2017-09-14 17:18:50.000000000 +0200 @@ -1,11 +1,12 @@ Metadata-Version: 1.1 Name: renderspec -Version: 1.6.1 +Version: 1.7.0 Summary: Jinja2 template renderer for generating .spec files Home-page: http://docs.openstack.org/developer/renderspec/ Author: OpenStack Author-email: [email protected] License: UNKNOWN +Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/renderspec.egg-info/SOURCES.txt new/renderspec-1.7.0/renderspec.egg-info/SOURCES.txt --- old/renderspec-1.6.1/renderspec.egg-info/SOURCES.txt 2017-05-30 14:20:54.000000000 +0200 +++ new/renderspec-1.7.0/renderspec.egg-info/SOURCES.txt 2017-09-14 17:18:51.000000000 +0200 @@ -14,6 +14,7 @@ doc/source/installation.rst doc/source/usage.rst renderspec/__init__.py +renderspec/contextfuncs.py renderspec/distloader.py renderspec/utils.py renderspec/versions.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/renderspec.egg-info/pbr.json new/renderspec-1.7.0/renderspec.egg-info/pbr.json --- old/renderspec-1.6.1/renderspec.egg-info/pbr.json 2017-05-30 14:20:54.000000000 +0200 +++ new/renderspec-1.7.0/renderspec.egg-info/pbr.json 2017-09-14 17:18:50.000000000 +0200 @@ -1 +1 @@ -{"git_version": "a97ffcf", "is_release": true} \ No newline at end of file +{"git_version": "2a0409a", "is_release": true} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/renderspec.egg-info/requires.txt new/renderspec-1.7.0/renderspec.egg-info/requires.txt --- old/renderspec-1.6.1/renderspec.egg-info/requires.txt 2017-05-30 14:20:54.000000000 +0200 +++ new/renderspec-1.7.0/renderspec.egg-info/requires.txt 2017-09-14 17:18:50.000000000 +0200 @@ -1,8 +1,8 @@ Jinja2!=2.9.0,!=2.9.1,!=2.9.2,!=2.9.3,!=2.9.4,>=2.8 -pymod2pkg>=0.7.0 -PyYAML>=3.10.0 +pymod2pkg!=0.8.0,>=0.7.0 +PyYAML>=3.10 packaging>=16.5 six>=1.9.0 [bandit] -bandit>=1.1.0 # Apache-2.0 +bandit>=1.1.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/requirements.txt new/renderspec-1.7.0/requirements.txt --- old/renderspec-1.6.1/requirements.txt 2017-05-30 14:18:19.000000000 +0200 +++ new/renderspec-1.7.0/requirements.txt 2017-09-14 17:16:57.000000000 +0200 @@ -2,7 +2,7 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. Jinja2!=2.9.0,!=2.9.1,!=2.9.2,!=2.9.3,!=2.9.4,>=2.8 # BSD License (3 clause) -pymod2pkg>=0.7.0 # Apache-2.0 -PyYAML>=3.10.0 # MIT +pymod2pkg!=0.8.0,>=0.7.0 # Apache-2.0 +PyYAML>=3.10 # MIT packaging>=16.5 # Apache-2.0 six>=1.9.0 # MIT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/test-requirements.txt new/renderspec-1.7.0/test-requirements.txt --- old/renderspec-1.6.1/test-requirements.txt 2017-05-30 14:18:19.000000000 +0200 +++ new/renderspec-1.7.0/test-requirements.txt 2017-09-14 17:16:57.000000000 +0200 @@ -3,10 +3,10 @@ # process, which may cause wedges in the gate later. flake8<2.6.0,>=2.5.4 # MIT testrepository>=0.0.18 # Apache-2.0/BSD -testresources>=0.2.4 # Apache-2.0/BSD +testresources>=2.0.0 # Apache-2.0/BSD testtools>=1.4.0 # MIT ddt>=1.0.1 # MIT -mock>=2.0 # BSD +mock>=2.0.0 # BSD -sphinx!=1.6.1,>=1.5.1 # BSD +sphinx>=1.6.2 # BSD oslosphinx>=4.7.0 # Apache-2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/renderspec-1.6.1/tests.py new/renderspec-1.7.0/tests.py --- old/renderspec-1.6.1/tests.py 2017-05-30 14:18:20.000000000 +0200 +++ new/renderspec-1.7.0/tests.py 2017-09-14 17:16:57.000000000 +0200 @@ -28,6 +28,7 @@ from mock import Mock, patch import os import renderspec +import renderspec.contextfuncs import renderspec.utils import renderspec.versions import shutil @@ -40,12 +41,12 @@ """test functions which do some calculation based on the context""" def test_context_license_spdx(self): self.assertEqual( - renderspec._context_license_spdx( + renderspec.contextfuncs._context_license_spdx( {'spec_style': 'suse'}, 'Apache-2.0'), 'Apache-2.0' ) self.assertEqual( - renderspec._context_license_spdx( + renderspec.contextfuncs._context_license_spdx( {'spec_style': 'fedora'}, 'Apache-2.0'), 'ASL 2.0' ) @@ -53,62 +54,86 @@ @data( # without version ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, - 'oslo.config', None, 'python-oslo.config'), + 'oslo.config', None, None, 'python-oslo.config'), ({'spec_style': 'fedora', 'epochs': {}, 'requirements': {}}, - 'oslo.config', None, 'python-oslo-config'), + 'oslo.config', None, None, 'python-oslo-config'), + # without version, multiple python versions + ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, + 'oslo.config', None, ('py', 'py3'), + 'python-oslo.config python3-oslo.config'), # with version ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, - 'oslo.config', ('>=', '1.2.3'), 'python-oslo.config >= 1.2.3'), + 'oslo.config', ('>=', '1.2.3'), None, 'python-oslo.config >= 1.2.3'), ({'spec_style': 'fedora', 'epochs': {}, 'requirements': {}}, - 'oslo.config', ('==', '1.2.3~a0'), 'python-oslo-config == 1.2.3~a0'), + '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}, 'requirements': {}}, - 'oslo.config', ('>=', '1.2.3'), 'python-oslo.config >= 4:1.2.3'), + 'oslo.config', ('>=', '1.2.3'), None, + 'python-oslo.config >= 4:1.2.3'), # without version, with epoch ({'spec_style': 'suse', 'epochs': {'oslo.config': 4}, 'requirements': {}}, - 'oslo.config', None, 'python-oslo.config'), + 'oslo.config', None, None, 'python-oslo.config'), # with version, with requirements ({'spec_style': 'suse', 'epochs': {}, 'requirements': {'oslo.config' '1.2.3'}}, - 'oslo.config', ('>=', '4.5.6'), 'python-oslo.config >= 4.5.6'), + 'oslo.config', ('>=', '4.5.6'), None, 'python-oslo.config >= 4.5.6'), # without version, with requirements ({'spec_style': 'suse', 'epochs': {}, 'requirements': {'oslo.config': '1.2.3'}}, - 'oslo.config', None, 'python-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}, 'requirements': {'oslo.config': '1.2.3'}}, - 'oslo.config', None, 'python-oslo.config >= 4: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}, 'requirements': {'oslo.config' '1.2.3'}}, - 'oslo.config', ('>=', '4.5.6'), 'python-oslo.config >= 4:4.5.6'), + '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}, + '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}, + 'requirements': {'oslo.config' '1.2.3'}}, + 'oslo.config', ('>=', '4.5.6'), 'py3', + 'python3-oslo.config >= 4:4.5.6'), + # with version, with requirements, with epoch, python2 and python3 + ({'spec_style': 'suse', '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'), + ) @unpack def test_context_py2pkg(self, context, pkg_name, pkg_version, - expected_result): + py_versions, expected_result): self.assertEqual( - renderspec._context_py2pkg(context, pkg_name, pkg_version), + renderspec.contextfuncs._context_py2pkg( + context, pkg_name, pkg_version, py_versions), expected_result) def test_context_epoch_without_epochs(self): self.assertEqual( - renderspec._context_epoch( + renderspec.contextfuncs._context_epoch( {'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, 'oslo.config'), 0) def test_context_epoch_with_epochs(self): self.assertEqual( - renderspec._context_epoch( + renderspec.contextfuncs._context_epoch( {'spec_style': 'suse', 'epochs': {'oslo.config': 4}, 'requirements': {}}, 'oslo.config'), 4) def test_context_upstream_version(self): context = {'spec_style': 'suse', 'epochs': {}, 'requirements': {}} - self.assertEqual(renderspec._context_upstream_version( + self.assertEqual(renderspec.contextfuncs._context_upstream_version( context, '1.2.0'), '1.2.0') @data( @@ -124,7 +149,7 @@ 'requirements': {}, 'output_dir': output_dir} url = 'http://foo/bar' with patch('renderspec.utils._download_file') as m: - self.assertEqual(renderspec._context_fetch_source( + self.assertEqual(renderspec.contextfuncs._context_fetch_source( context, url), url) self.assertEqual(m.call_count, expected_calls) @@ -134,7 +159,7 @@ def setUp(self): """create a Jinja2 environment and register the standard filters""" self.env = Environment() - renderspec._env_register_filters_and_globals(self.env) + renderspec.contextfuncs.env_register_filters_and_globals(self.env) @data( ("{{ 'http://foo/bar'|basename }}", "bar") @@ -157,6 +182,10 @@ # plain ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, "{{ py2pkg('requests') }}", "python-requests"), + # plain, with multiple py_versions + ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, + "{{ py2pkg('requests', py_versions=['py2', 'py3']) }}", + "python2-requests python3-requests"), # with version ({'spec_style': 'suse', 'epochs': {}, 'requirements': {}}, "{{ py2pkg('requests', ('>=', '2.8.1')) }}", @@ -175,6 +204,11 @@ '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}, + 'requirements': {'requests': '1.2.3'}}, + "{{ py2pkg('requests', py_versions=['py2']) }}", + "python2-requests >= 4:1.2.3"), ) @unpack def test_render_func_py2pkg(self, context, string, expected_result): @@ -246,8 +280,8 @@ ('suse', '1.1.0a10', '1.1.0~xalpha10'), ('suse', '1.1.0a10dev5', '1.1.0~xalpha10~dev5'), ('suse', '1.1.0b10', '1.1.0~xbeta10'), - ('suse', '1.1.0rc2', '1.1.0~rc2'), - ('suse', '1.1.0rc2dev2', '1.1.0~rc2~dev2'), + ('suse', '1.1.0rc2', '1.1.0~xrc2'), + ('suse', '1.1.0rc2dev2', '1.1.0~xrc2~dev2'), ('fedora', '1.1.0', '1.1.0'), ('fedora', '1.1.0b10', '1.1.0'), ('fedora', '1.1.0rc2dev2', '1.1.0'), @@ -291,6 +325,18 @@ template.render(**context), rpm_release_expected) + def test_render_func_url_pypi(self): + context = {'spec_style': 'suse', 'epochs': {}, 'requirements': {}} + # need to escape '{' and '}' here + s = "{% set upstream_version = '3.20.0' %}" \ + "{% set pypi_name = 'oslo.concurrency' %}" \ + "{{ url_pypi() }}" + template = self.env.from_string(s) + self.assertEqual( + template.render(**context), + "https://files.pythonhosted.org/packages/source/o/" + "oslo.concurrency/oslo.concurrency-3.20.0.tar.gz") + class RenderspecVersionsTests(unittest.TestCase): def test_without_version(self): @@ -308,6 +354,11 @@ ['sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 # BSD']) self.assertEqual(requires, {'sphinx': '1.1.2'}) + def test_lexical_version(self): + requires = renderspec.versions.get_requirements( + ['django>=1.8,<1.10 # FOO BAR']) + self.assertEqual(requires, {'django': '1.8'}) + def test_with_multiple_versions_and_invalid_lowest(self): requires = renderspec.versions.get_requirements( ['sphinx>=1.1.2,!=1.1.0,!=1.3b1,<1.3 # BSD']) @@ -370,7 +421,7 @@ with open(f1, 'w+') as f: f.write(template) rendered = renderspec.generate_spec( - style, epochs, requirements, f1, None) + style, epochs, requirements, 'spec.j2', f1, None) self.assertEqual(rendered, expected_result) finally: shutil.rmtree(tmpdir) @@ -433,8 +484,8 @@ # mock this to use testing dist-tempaltes folder mock_dt_path.return_value = dt_dir - out = renderspec.generate_spec('loldistro', {}, {}, base_path, - None) + out = renderspec.generate_spec('loldistro', {}, {}, 'spec.j2', + base_path, None) self.assertEqual(out, expected_out) finally: shutil.rmtree(tmpdir)
