On 01/08/2016 08:22 AM, Jan Cholasta wrote:
On 8.1.2016 14:13, Martin Basti wrote:
On 08.01.2016 14:14, Jan Cholasta wrote:
On 8.1.2016 14:09, Martin Basti wrote:
On 08.01.2016 14:00, Martin Kosek wrote:
On 01/08/2016 01:45 PM, Martin Basti wrote:
Hello all,
fix for ticket https://fedorahosted.org/freeipa/ticket/5535
requires to import rpm module
This import somehow breaks nsslib in IPA
https://fedorahosted.org/freeipa/ticket/5572
We have 2 ways how to fix it:
1) move import rpm to body of methods (attached patch)
We are not sure how stable is this solution.
2) use solution with rpmdevtools proposed here:
https://www.redhat.com/archives/freeipa-devel/2016-January/msg00092.html
This should be rock stable but it needs many dependencies (rpm-python
too, perl)
The second way looks safer, so I would like to reimplement it, do you
all agree
or do you have better idea?
Feedback welcome, please ASAP.
Martin^2
Since it's Friday, I invested 15 minutes to practice my C skills and
use the
python-cffi library to call rpm rpmvercmp library call directly
(attached):
$ python rpm.py 4.2.0-15.el7 4.2.0-15.el7_2.3
4.2.0-15.el7 < 4.2.0-15.el7_2.3
This would not introduce any additional dependency besides rpm-devel,
right? :-)
Not rpm-devel, but rpm-libs (you should dlopen "librpm.so.3").
I'm afraid that this can cause the same issue as import rpm, because
the
nsslib is used from C library
I would be surprised if NSS was used in this particular function.
I will try it
No NSS here:
<https://github.com/rpm-software-management/rpm/blob/master/lib/rpmvercmp.c>
Anyway, the function looks simple, so it might be safer to just rewrite
it to Python, with no new dependencies.
Leaving aside the whole question of whether re-implementing rpmvercmp in
Python is a good idea or not because of possible divergence from RPM I
offer to you an implementation of rpmvercmp written in Python I did
years ago. It was written based on the published documentation of how
RPM version comparison is implemented (as close to a spec as I was able
to find). I believe I also used the C implementation as a guide but my
memory is fuzzy on that point. I've used it a lot and I've also cross
checked it's results with librpm and I've never seen a differing result.
Use at your pleasure or displeasure :-)
HTH,
John
--
John
#!/usr/bin/python
import re
rpm_name_re = re.compile(r'^(.+)-([^-]+)-([^-]+)$')
def split_rpm_name(rpm_name):
'''
Split an RPM's NVR returning
[name, version, release]
'''
match = rpm_name_re.match(rpm_name)
if match:
name = match.group(1)
version = match.group(2)
release = match.group(3)
return name, version, release
else:
raise ValueError("cannot split rpm NVR for '%s'" % rpm_name)
def split_rpm_label(label):
'''
Each label is separated into a list of maximal alphabetic or numeric
components, with separators (non-alphanumeric characters) ignored.
Alphbetic components are inserted into the list as a Python str object.
Numeric components are inserted into the list as either Python int
or long objects depending on the numeric magnitude of the component.
For example:
'2.0.1' => [2, 0, 1]
'2xFg33.+f.5' => [2, 'xFg', 33, 'f', 5]
'''
components = []
component = None
for c in label:
if c.isalpha():
if component is None:
component = c
else:
if component.isalpha():
component += c
else:
components.append(int(component))
component = c
elif c.isdigit():
if component is None:
component = c
else:
if component.isdigit():
component += c
else:
components.append(component)
component = c
else:
if component is not None:
if component.isdigit():
component = int(component)
components.append(component)
component = None
if component is not None:
if component.isdigit():
component = int(component)
components.append(component)
component = None
return components
def rpm_label_cmp(label1, label2):
'''
The version and release components of a rpm NVR are considered labels.
To compare a label we split the label into components, see split_rpm_label()
for an explanation of how the components are split.
The components in the list are compared one by one using the following
algorithm. If two components are considered to be different, the label with
the newer component wins as the newer label. If the components are
considered to be equal, the next components are compared until we either
reach different components or one of the lists runs out. In case one of the
lists run out, the other label wins as the newer label. So, for example, [1,
2] is newer than [1, 1], and [1, 2, 0] is newer than [1, 2].
Components are compared thusly:
1. If one of the components is a number, while the other is alphabetic, the
numeric components is considered newer. So 10 is newer than 'abc', and 0 is
newer than 'Z'.
2. If both the components are numbers, the larger number is considered
newer. So 5 is newer than 4 and 10 is newer than 2. If the numbers are
equal, the components are considered equal.
3. If both the components are alphabetic, they are compared using the strcmp
function, with the greater string resulting in a newer component. So 'b' is
newer than 'a', 'add' is newer than 'ZULU' (because lowercase characters win
in strcmp comparisons), and 'aba' is newer than 'ab'. If the strings are
identical, the components are considered equal.
'''
result = 0
# Get the components in this label
components1 = split_rpm_label(label1)
components2 = split_rpm_label(label2)
len1 = len(components1)
len2 = len(components2)
min_len = min(len1, len2)
# Iterate over the components
i = 0
while i < min_len:
component1 = components1[i]
component2 = components2[i]
if type(component1) in (int, long):
if type(component2) in (int, long):
# both components were numeric
result = cmp(component1, component2)
if result != 0:
return result
else:
# 1st was numeric, 2nd was alphabetic, thus 1st is newer
return 1
else:
if type(component2) is str:
# both components were alphabetic
result = cmp(component1, component2)
if result != 0:
return result
else:
# 1st was alphabetic, 2nd was numeric, thus 1st is older
return -1
i += 1
return cmp(len1, len2)
def rpm_ver_cmp_nvr(rpm1, rpm2):
'''
The version and release components of a rpm NVR are considered labels.
The package's version label is compared according to the algorithm described
in rpm_label_cmp(). The larger version wins. If the versions are considered
equal then the package's release label is compared according to the algorithm
described in rpm_label_cmp(). The larger release wins. If the releases are
decided equal, the packages are considered equal.
'''
# Get the labels for both RPM's
n1, v1, r1 = split_rpm_name(rpm1)
n2, v2, r2 = split_rpm_name(rpm2)
result = rpm_label_cmp(v1, v2)
if result == 0:
# versions were equal, compare the releases
result = rpm_label_cmp(r1, r2)
return result
def main():
rpm1 = 'ipa-python-1.91-0.git.200912162104.fc13.x86_64'
rpm2 = 'ipa-python-1.91-0.git.200912162104.fc13.x86_64'
result = rpm_ver_cmp_nvr(rpm1, rpm2)
print "%d %s %s" % (result, rpm1, rpm2)
#print '%s => %s' % (rpm1, split_rpm_name(rpm1))
#val = '2xFg33.+f.5'
#components = split_rpm_label(val)
#print "2xFg33.+f.5 => ('2', 'xFg', '33', 'f', '5')"
#print "%s => %s" % (val, components)
#-------------------------------------------------------------------------------
if __name__ == "__main__":
main()
--
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code