py2rpm: New workaround for differences in PIP and RPM version handling
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. This change implements new workaround for this. It 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 plus tail of '.0' repeated several times. Luckily, '2.0' and '2.00' is the same version for RPM. Then, exact requirements (like 'pysendfile==2.0.0') are replaced with range (pysendfile >= 2, pysendfile <= 2.0.0.0.0.0.0.0.0.0.0.0), while for '<=' and '>=' we use only upper or lower bound correspondingly. Also, we do not trim zeroes from versions that we put in Version: tag, as we don't need to do that any more. Closes-bug: #1254991 Change-Id: Idb142d0f85d60183e79964baece52e0128cf9d7b
This commit is contained in:
parent
bafa115cc7
commit
ba154fa614
71
tools/py2rpm
71
tools/py2rpm
@ -373,16 +373,19 @@ exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))
|
|||||||
|
|
||||||
|
|
||||||
def trim_zeroes(version):
|
def trim_zeroes(version):
|
||||||
"""RPM mishandles versions like "0.8.0". Make it happy."""
|
"""Trim zeroes from the and of a version"""
|
||||||
match = version_re.match(version)
|
match = version_re.match(version)
|
||||||
if match:
|
if match:
|
||||||
return match.group(1)
|
return match.group(1)
|
||||||
return version
|
return version
|
||||||
|
|
||||||
|
|
||||||
|
_DOT_ZEROES_TAIL = '.0' * 10
|
||||||
|
|
||||||
|
|
||||||
def requires_and_conflicts(req_list, skip_req_names=()):
|
def requires_and_conflicts(req_list, skip_req_names=()):
|
||||||
rpm_requires = ""
|
rpm_requires = []
|
||||||
rpm_conflicts = ""
|
rpm_conflicts = []
|
||||||
for line in req_list:
|
for line in req_list:
|
||||||
try:
|
try:
|
||||||
req = pkg_resources.Requirement.parse(line)
|
req = pkg_resources.Requirement.parse(line)
|
||||||
@ -392,28 +395,50 @@ def requires_and_conflicts(req_list, skip_req_names=()):
|
|||||||
continue
|
continue
|
||||||
rpm_name = python_key_to_rpm(req.key)
|
rpm_name = python_key_to_rpm(req.key)
|
||||||
if not req.specs:
|
if not req.specs:
|
||||||
rpm_requires += "\nRequires:"
|
rpm_requires.append(rpm_name)
|
||||||
rpm_requires = "%s %s" % (
|
for kind, version in req.specs:
|
||||||
rpm_requires, rpm_name)
|
|
||||||
for spec in req.specs:
|
|
||||||
# kind in ("==", "<=", ">=", "!=")
|
|
||||||
kind = spec[0]
|
|
||||||
version = trim_zeroes(spec[1])
|
|
||||||
try:
|
try:
|
||||||
version = "%s:%s" % (epoch_map[req.key], version)
|
version = "%s:%s" % (epoch_map[req.key], version)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
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)
|
||||||
if kind == "!=":
|
if kind == "!=":
|
||||||
rpm_conflicts += "\nConflicts:"
|
# NOTE(imelnikov): we can't conflict with ranges, so we
|
||||||
rpm_conflicts = "%s %s = %s" % (
|
# put version as is and with trimmed zeroes just in case
|
||||||
rpm_conflicts, rpm_name, version)
|
rpm_conflicts.append('%s == %s' % (rpm_name, version))
|
||||||
continue
|
if version != lower_version:
|
||||||
if kind == "==":
|
rpm_conflicts.append('%s == %s' % (rpm_name, lower_version))
|
||||||
kind = "="
|
elif kind == '==':
|
||||||
rpm_requires += "\nRequires:"
|
rpm_requires.extend((
|
||||||
rpm_requires = "%s %s %s %s" % (
|
'%s >= %s' % (rpm_name, lower_version),
|
||||||
rpm_requires, rpm_name, kind, version)
|
'%s <= %s' % (rpm_name, upper_version)
|
||||||
return rpm_requires, rpm_conflicts
|
))
|
||||||
|
elif kind in ('<=', '<'):
|
||||||
|
rpm_requires.append('%s <= %s' % (rpm_name, upper_version))
|
||||||
|
elif kind in ('>=', '>'):
|
||||||
|
rpm_requires.append('%s >= %s' % (rpm_name, lower_version))
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid requirement kind: %r' % kind)
|
||||||
|
|
||||||
|
rpm_requires_str = ''.join("\nRequires: %s" % req for req in rpm_requires)
|
||||||
|
rpm_conflicts_str = ''.join("\nConflicts: %s" % req for req in rpm_conflicts)
|
||||||
|
return rpm_requires_str, rpm_conflicts_str
|
||||||
|
|
||||||
|
|
||||||
def one_line(line, max_len=80):
|
def one_line(line, max_len=80):
|
||||||
@ -465,11 +490,7 @@ def build_rpm(options, filename):
|
|||||||
archive_name = "%s/dist/%s-%s.tar.gz" % (source_dir, pkg_name, version)
|
archive_name = "%s/dist/%s-%s.tar.gz" % (source_dir, pkg_name, version)
|
||||||
shutil.copy(archive_name, os.path.join(build_dir, "SOURCES"))
|
shutil.copy(archive_name, os.path.join(build_dir, "SOURCES"))
|
||||||
|
|
||||||
# We need to do this so that when a package such as hacking depends on
|
cleaned_version = version.replace('-', '_')
|
||||||
# flake8 v2 that we don't go ahead and build a v2.0 version.
|
|
||||||
#
|
|
||||||
# Note(harlowja): Not sure why rpm seems to not understand these are the same...
|
|
||||||
cleaned_version = trim_zeroes(version.replace('-', '_'))
|
|
||||||
with open(spec_name, "w") as spec_file:
|
with open(spec_name, "w") as spec_file:
|
||||||
print >> spec_file, "%define pkg_name", pkg_name
|
print >> spec_file, "%define pkg_name", pkg_name
|
||||||
print >> spec_file, "%define pkg_path", os.path.join(*pkg_name.split('.'))
|
print >> spec_file, "%define pkg_path", os.path.join(*pkg_name.split('.'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user