Handle candidate release versions better
Translate the usage of candidate release versions in requirements into an rpm version + release. This translation is not perfect but it will work better than what previously existed (which did not work at all when there were candiate releases being used in requirements of various components). Fixes bug 1304747 Change-Id: I1623112aecc66d6fdc22817704b17c6ff5f3781e
This commit is contained in:
parent
53b9562486
commit
847f62b3d7
109
tools/py2rpm
109
tools/py2rpm
@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import collections
|
||||
import distutils.spawn
|
||||
import email.parser
|
||||
import logging
|
||||
@ -386,6 +387,92 @@ def trim_zeroes(version):
|
||||
|
||||
|
||||
_DOT_ZEROES_TAIL = '.0' * 10
|
||||
_CAND_MAP = {
|
||||
'final-': 'f',
|
||||
'@': 'd',
|
||||
}
|
||||
|
||||
|
||||
def version_release(version):
|
||||
|
||||
# Unformats the parsed versions zero fill.
|
||||
def undo_zfill(piece):
|
||||
piece = piece.lstrip("0")
|
||||
if not piece:
|
||||
piece = '0'
|
||||
return piece
|
||||
|
||||
# Translate usage of pre-release versions into
|
||||
# version and release since rpm will have conflicts
|
||||
# when trying to compare against pre-release versions.
|
||||
parsed_version = pkg_resources.parse_version(version)
|
||||
cand_start = -1
|
||||
for i, piece in enumerate(parsed_version):
|
||||
if piece.startswith("*"):
|
||||
cand_start = i
|
||||
break
|
||||
if cand_start == -1:
|
||||
return (version, None)
|
||||
version = []
|
||||
for v in list(parsed_version)[0:cand_start]:
|
||||
version.append(undo_zfill(v))
|
||||
version = ".".join(version)
|
||||
if not version:
|
||||
version = "0"
|
||||
release = []
|
||||
candidates = collections.deque(parsed_version[cand_start:])
|
||||
while len(candidates):
|
||||
v = candidates.popleft()
|
||||
if v == '*final':
|
||||
break
|
||||
# TODO(harlowja): this will likely require some more work as the
|
||||
# way python and rpm compare release versions is not the same, but the
|
||||
# usage of these types is limited so should not be a major problem.
|
||||
piece = []
|
||||
if v.startswith("*"):
|
||||
v = v[1:]
|
||||
v = _CAND_MAP.get(v, v)
|
||||
piece.append(v)
|
||||
while len(candidates):
|
||||
v = candidates.popleft()
|
||||
if not v.isdigit():
|
||||
candidates.appendleft(v)
|
||||
break
|
||||
else:
|
||||
piece.append(undo_zfill(v))
|
||||
release.append("".join(piece))
|
||||
release = ".".join(release)
|
||||
return (version, release)
|
||||
|
||||
|
||||
def format_version(req, version):
|
||||
version, release = version_release(version)
|
||||
try:
|
||||
version = "%s:%s" % (epoch_map[req.key], version)
|
||||
except KeyError:
|
||||
pass
|
||||
# NOTE(imelnikov): rpm and pip compare versions differently, and
|
||||
# this used to lead to lots problems, pain and sorrows. The most
|
||||
# visible outcome of the difference is that from rpm's point of
|
||||
# view version '2' != '2.0', as well as '2.0' != '2.0.0', but for
|
||||
# pip it's same version.
|
||||
#
|
||||
# Current workaround for this works as follows: if python module
|
||||
# requires module of some version, (like 2.0.0), the actual rpm
|
||||
# version of the module will have the same non-zero beginning and
|
||||
# some '.0's at the end ('2', '2.0', '2.0.0', '2.0.0.0' ...). Thus,
|
||||
# we can calculate lower bound for requirement by trimming '.0'
|
||||
# from the version (we get '2'), and then set upper bound to lower
|
||||
# bound + tail of '.0' repeated several times. Luckily, '2.0' and
|
||||
# '2.00' is the same version for rpm.
|
||||
lower_version = trim_zeroes(version)
|
||||
upper_version = '%s%s' % (lower_version, _DOT_ZEROES_TAIL)
|
||||
# Attach on the release (if any)
|
||||
if release:
|
||||
version = version + "-" + release
|
||||
lower_version = lower_version + "-" + release
|
||||
upper_version = upper_version + "-" + release
|
||||
return (version, lower_version, upper_version)
|
||||
|
||||
|
||||
def requires_and_conflicts(req_list, skip_req_names=()):
|
||||
@ -405,27 +492,7 @@ def requires_and_conflicts(req_list, skip_req_names=()):
|
||||
rpm_mapping[rpm_name] = req
|
||||
continue
|
||||
for kind, version in req.specs:
|
||||
try:
|
||||
version = "%s:%s" % (epoch_map[req.key], version)
|
||||
except KeyError:
|
||||
pass
|
||||
# NOTE(imelnikov): rpm and pip compare versions differently, and
|
||||
# this used to lead to lots problems, pain and sorrows. The most
|
||||
# visible outcome of the difference is that from rpm's point of
|
||||
# view version '2' != '2.0', as well as '2.0' != '2.0.0', but for
|
||||
# pip it's same version.
|
||||
#
|
||||
# Current workaround for this works as follows: if python module
|
||||
# requires module of some version, (like 2.0.0), the actual rpm
|
||||
# version of the module will have the same non-zero beginning and
|
||||
# some '.0's at the end ('2', '2.0', '2.0.0', '2.0.0.0' ...). Thus,
|
||||
# we can calculate lower bound for requirement by trimming '.0'
|
||||
# from the version (we get '2'), and then set upper bound to lower
|
||||
# bound + tail of '.0' repeated several times. Luckily, '2.0' and
|
||||
# '2.00' is the same version for rpm.
|
||||
|
||||
lower_version = trim_zeroes(version)
|
||||
upper_version = '%s%s' % (lower_version, _DOT_ZEROES_TAIL)
|
||||
version, lower_version, upper_version = format_version(req, version)
|
||||
if kind == "!=":
|
||||
# NOTE(imelnikov): we can't conflict with ranges, so we
|
||||
# put version as is and with trimmed zeroes just in case
|
||||
|
Loading…
Reference in New Issue
Block a user