Add new context functions for version handling
When packaging pre-releases (alpha, beta, RC), the version from the Python sdist tarball needs to be converted into something usable in the RPM world. "py2rpmversion" and "py2rpmrelease" can be used for that. Change-Id: I5990fa4883b381147cefda88d58d40a6e8fe508a
This commit is contained in:
parent
b560536a81
commit
e6577b3f29
@ -76,6 +76,57 @@ package name. Using multiple files looks like this::
|
||||
.. _PEP0508: https://www.python.org/dev/peps/pep-0508/
|
||||
.. _global-requirements.txt: https://git.openstack.org/cgit/openstack/requirements/tree/global-requirements.txt
|
||||
|
||||
Handling the package version
|
||||
****************************
|
||||
|
||||
Distributions handle versions, especially pre-release versions differently.
|
||||
SUSE for example allows using RPM's tilde ('~) while Fedora doesn't allow that
|
||||
and uses a combination of RPM `Version` and `Release` tag to express pre-releases.
|
||||
To support both styles with renderspec, the upstream version and a release
|
||||
must be available in the context::
|
||||
|
||||
{% set upstream_version = '1.2.3.0rc1' %}
|
||||
{% set rpm_release = '1' %}
|
||||
|
||||
This should be done on the first lines in the spec.j2 template. The `rpm_release` is
|
||||
only used in the fedora style.
|
||||
Then for the RPM version and release, use::
|
||||
|
||||
Version: {{ py2rpmversion() }}
|
||||
Release: {{ py2rpmrelease() }}
|
||||
|
||||
For suse-style, this renders to::
|
||||
|
||||
Version: 1.2.3.0~rc1
|
||||
Release: 0
|
||||
|
||||
For fedora-style, this renders to::
|
||||
|
||||
Version: 1.2.3
|
||||
Release: 0.1.0rc1%{?dist}
|
||||
|
||||
Note that in case of pre-releases you may need to adjust the version that is used
|
||||
in the `Source` tag and the `%prep` sections `%setup`. So use e.g. ::
|
||||
|
||||
{% set upstream_version = '1.2.3.0rc1' %}
|
||||
{% set rpm_release = '1' %}
|
||||
%name oslo.config
|
||||
Version: {{ py2rpmversion() }}
|
||||
Release: {{ py2rpmrelease() }}
|
||||
Source0: https://pypi.io/packages/source/o/%{sname}/%{sname}-{{ upstream_version }}.tar.gz
|
||||
%prep
|
||||
%setup -q -n %{sname}-{{upstream_version}}
|
||||
|
||||
which would render (with suse-style) to::
|
||||
|
||||
%name oslo.config
|
||||
Version: 1.2.3.0~rc1
|
||||
Release: 0
|
||||
Source0: https://pypi.io/packages/source/o/%{sname}/%{sname}-1.2.3rc1.tar.gz
|
||||
%prep
|
||||
%setup -q -n %{sname}-1.2.3.0rc1
|
||||
|
||||
|
||||
Template features
|
||||
=================
|
||||
|
||||
@ -164,6 +215,47 @@ With the `suse` spec-style::
|
||||
License: Apache-2.0
|
||||
|
||||
|
||||
context function `py2rpmversion`
|
||||
********************************
|
||||
Python has a semantic version schema (see `PEP0440`_) and converting Python versions
|
||||
to RPM compatible versions is needed in some cases. For example, in the Python world
|
||||
the version "1.1.0a3" is lower than "1.1.0" but for RPM the version is higher.
|
||||
To transform a Python version to a RPM compatible version, use::
|
||||
|
||||
{% set upstream_version = '1.1.0a3' %}
|
||||
{% set rpm_release = '1' %}
|
||||
|
||||
Version: {{ py2rpmversion() }}
|
||||
|
||||
With the `suse` spec-style it will be translated to::
|
||||
|
||||
Version: 1.1.0~xalpha3
|
||||
|
||||
Note that you need to set 2 context variables (`upstream_version` and `rpm_release`)
|
||||
to be able to use the `py2rpmversion()` function.
|
||||
|
||||
|
||||
context function `py2rpmrelease`
|
||||
********************************
|
||||
Fedora doesn't allow the usage of `~` (tilde) in the `Version` tag. So for pre-releases
|
||||
the `Release` tag is used (see `Fedora Packaging Versioning`_)
|
||||
For the fedora-style::
|
||||
|
||||
{% set upstream_version = '1.1.0a3' %}
|
||||
{% set rpm_release = '1' %}
|
||||
|
||||
Version: {{ py2rpmversion() }}
|
||||
Release: {{ py2rpmrelease() }}
|
||||
|
||||
this would render to::
|
||||
|
||||
Version: 1.1.0
|
||||
Release: 0.1a3%{?dist}
|
||||
|
||||
Note that you need to set 2 context variables (`upstream_version` and `rpm_release`)
|
||||
to be able to use the `py2rpmrelease()` function.
|
||||
|
||||
|
||||
distribution specific blocks & child templates
|
||||
**********************************************
|
||||
|
||||
@ -199,3 +291,5 @@ For more information, see current `renderspec/dist-templates` and usage in
|
||||
.. _pymod2pkg: https://git.openstack.org/cgit/openstack/pymod2pkg
|
||||
.. _pypi.python.org: https://pypi.python.org/pypi
|
||||
.. _SPDX: https://spdx.org/licenses/
|
||||
.. _PEP0440: https://www.python.org/dev/peps/pep-0440/
|
||||
.. _Fedora Packaging Versioning: https://fedoraproject.org/wiki/Packaging:Versioning#Pre-Release_packages
|
||||
|
@ -24,6 +24,8 @@ 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
|
||||
@ -32,6 +34,66 @@ from renderspec.distloader import RenderspecLoader
|
||||
from renderspec import versions
|
||||
|
||||
|
||||
# a variable that needs to be set for some functions in the context
|
||||
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_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':
|
||||
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)
|
||||
@ -120,6 +182,16 @@ def _globals_py2pkg(context, pkg_name, pkg_version=None):
|
||||
return _context_py2pkg(context, pkg_name, 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)
|
||||
@ -139,6 +211,8 @@ def _env_register_filters_and_globals(env):
|
||||
"""register all the jinja2 filters we want in the environment"""
|
||||
env.filters['license'] = _filter_license_spdx
|
||||
env.filters['epoch'] = _filter_epoch
|
||||
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
|
||||
|
50
tests.py
50
tests.py
@ -185,6 +185,56 @@ class RenderspecTemplateFunctionTests(unittest.TestCase):
|
||||
template.render(**context),
|
||||
expected_result)
|
||||
|
||||
@data(
|
||||
('suse', '1.1.0', '1.1.0'),
|
||||
('suse', '1.1.0.post2', '1.1.0.post2'),
|
||||
('suse', '1.1.0dev10', '1.1.0~dev10'),
|
||||
('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'),
|
||||
('fedora', '1.1.0', '1.1.0'),
|
||||
('fedora', '1.1.0b10', '1.1.0'),
|
||||
('fedora', '1.1.0rc2dev2', '1.1.0'),
|
||||
)
|
||||
@unpack
|
||||
def test_render_func_py2rpmversion(self, style, py_ver, rpm_ver):
|
||||
context = {'spec_style': style, 'epochs': {}, 'requirements': {}}
|
||||
# need to escape '{' and '}' here
|
||||
s = "{{% set upstream_version = '{}' %}}{{{{ py2rpmversion() }}}}"\
|
||||
.format(py_ver)
|
||||
template = self.env.from_string(s)
|
||||
self.assertEqual(
|
||||
template.render(**context),
|
||||
rpm_ver)
|
||||
|
||||
@data(
|
||||
('suse', '1.1.0', '1', '0'),
|
||||
('suse', '1.1.0.post2', '1', '0'),
|
||||
('suse', '1.1.0dev10', '2', '0'),
|
||||
('fedora', '1.1.0', '1', '1%{?dist}'),
|
||||
# ('fedora', '1.1.0.post2', '1', 'FIXME'),
|
||||
('fedora', '1.1.0dev10', '1', '0.1.dev10%{?dist}'),
|
||||
('fedora', '1.1.0a10', '1', '0.1.a10%{?dist}'),
|
||||
('fedora', '1.1.0a10dev5', '1', '0.1.a10.dev5%{?dist}'),
|
||||
('fedora', '1.1.0b10', '1', '0.1.b10%{?dist}'),
|
||||
('fedora', '1.1.0rc2', '5', '0.5.rc2%{?dist}'),
|
||||
('fedora', '1.1.0rc2dev2', '1', '0.1.rc2.dev2%{?dist}'),
|
||||
)
|
||||
@unpack
|
||||
def test_render_func_py2rpmrelease(self, style, upstream_ver, rpm_release,
|
||||
rpm_release_expected):
|
||||
context = {'spec_style': style, 'epochs': {}, 'requirements': {}}
|
||||
# need to escape '{' and '}' here
|
||||
s = "{{% set upstream_version = '{}' %}}" \
|
||||
"{{% set rpm_release = '{}' %}}" \
|
||||
"{{{{ py2rpmrelease() }}}}".format(upstream_ver, rpm_release)
|
||||
template = self.env.from_string(s)
|
||||
self.assertEqual(
|
||||
template.render(**context),
|
||||
rpm_release_expected)
|
||||
|
||||
|
||||
class RenderspecVersionsTests(unittest.TestCase):
|
||||
def test_without_version(self):
|
||||
|
Loading…
x
Reference in New Issue
Block a user