Source code for toolchest.rpm.rpmvercmp

#!/usr/bin/env python

# (C) 2018 Red Hat, Inc.
# License: Same as librpm: LGPL version 2


# Python copy of rpmvercmp() from rpmvercmp.c
#
# This is _intentionally_ as verbose as possible in order to most
# closely match rpmvercmp.c from librpm.  It is *easy* to make this
# more "pythonic", but then it would be more difficult to track/
# update changes and keeping this implementation bug-for-bug
# compatible with rpmvercmp.c's implementation.
[docs]def rpmvercmp(left, right): """ Determines which label string has a higher value. This is for purposes of determining with version of a build is newer, or if they are equivalent based on string comparison. :param left: The left value to compare. Must be a string. :param right: The right value to compare. Must be a string. :returns: -1, 0, or 1 if the left value is less than, equal to, or greater than, the right value, respectively """ # Note: Enhancement, for Pungi if left == 'None': left = None if right == 'None': right = None if left is None and right is None: return 0 if left is None and right is not None: return -1 if left is not None and right is None: return 1 # # End Enhancement # # if not isinstance(left, str): raise ValueError('left is not a string') if not isinstance(right, str): raise ValueError('right is not a string') if left == right: return 0 llen = len(left) rlen = len(right) li = 0 ri = 0 isnum = False while li < llen or ri < rlen: while (li < llen) and (not left[li].isalnum()) and left[li] != '~': li = li + 1 while (ri < rlen) and (not right[ri].isalnum()) and right[ri] != '~': ri = ri + 1 # The C code will compare vs. \0 here in some cases, which we can't # do directly, so watch for running past the end of the string and # assign a non-tilde if needed for this block. We need two try blocks # since we need to check these values independently. left_str = '' right_str = '' try: left_str = left[li] except IndexError: pass try: right_str = right[ri] except IndexError: pass if (left_str == '~' or right_str == '~'): if (left_str != '~'): return 1 if (right_str != '~'): return -1 li = li + 1 ri = ri + 1 continue if (li >= llen or ri >= rlen): break lp = li rp = ri if (left[lp].isdigit()): while (lp < llen and left[lp].isdigit()): lp = lp + 1 while (rp < rlen and right[rp].isdigit()): rp = rp + 1 isnum = True else: while (lp < llen and left[lp].isalpha()): lp = lp + 1 while (rp < rlen and right[rp].isalpha()): rp = rp + 1 isnum = False str1 = left[li:lp] str2 = right[ri:rp] if len(str1) == 0: return -1 if len(str2) == 0: if isnum: return 1 else: return -1 if isnum: # Clear leading zeroes, if any str1 = str(int(str1)) str2 = str(int(str2)) if len(str1) > len(str2): return 1 if len(str2) > len(str1): return -1 if str1 != str2: if str1 < str2: return -1 else: return 1 li = lp ri = rp if li >= llen and ri >= rlen: return 0 if li >= llen: return -1 return 1
# Python implementation of rpm.labelCompare that does not need # the RPM C libraries/packages; logic is from rpmvercmp.c # rpmVersionCompare() function.
[docs]def labelCompare(left, right): """ Determines which label tuple has a higher value. This is for purposes of determining with version of a build is newer, or if they are equivalent taking into account epoch, version, release. :param left: The left value to compare. Must be a tuple of (epoch, version, release) or (version, release). :param right: The right value to compare. Must be a tuple of (epoch, version, release) or (version, release). :returns: -1, 0, or 1 if the left value is less than, equal to, or greater than, the right value, respectively. """ if not isinstance(left, tuple): raise ValueError('left is not a tuple') if not isinstance(right, tuple): raise ValueError('right is not a tuple') epoch_l = 0 epoch_r = 0 if len(left) == 3: if left[0] != '': epoch_l = int(left[0]) version_l = str(left[1]) release_l = str(left[2]) elif len(left) == 2: version_l = str(left[0]) release_l = str(left[1]) else: raise ValueError('left is not a tuple of 2 or 3') if len(right) == 3: if right[0] != '': epoch_r = int(right[0]) version_r = str(right[1]) release_r = str(right[2]) elif len(right) == 2: version_r = str(right[0]) release_r = str(right[1]) else: raise ValueError('right is not a tuple of 2 or 3') if epoch_l < epoch_r: return -1 if epoch_l > epoch_r: return 1 rc = rpmvercmp(version_l, version_r) if rc != 0: return rc return rpmvercmp(release_l, release_r)