in antlir/rpm/rpm_metadata.py [0:0]
def _compare_values(left: str, right: str) -> int:
# Rpm versions can only be ascii, anything else is just
# ignored
# pyre-fixme[9]: left has type `str`; used as `bytes`.
left = left.encode("ascii", "ignore")
# pyre-fixme[9]: right has type `str`; used as `bytes`.
right = right.encode("ascii", "ignore")
if left == right:
return 0
while left or right:
match_left = R_NON_ALPHA_NUM_TILDE_CARET.match(left)
match_right = R_NON_ALPHA_NUM_TILDE_CARET.match(right)
left_head, left = match_left.group(1), match_left.group(2)
right_head, right = match_right.group(1), match_right.group(2)
# Ignore anything at the start we don't want
if left_head or right_head:
continue
# Look at tilde first, it takes precedent over everything else
if left.startswith(b"~"):
if not right.startswith(b"~"):
return -1 # left < right
# Strip the tilde and start again
left, right = left[1:], right[1:]
continue
# Tilde always means the version is less
if right.startswith(b"~"):
return 1 # left > right
# Now look at the caret, which is like the tilde but pointier.
if left.startswith(b"^"):
# left has a caret but right has ended
if not right:
return 1 # left > right
# left has a caret but right continues on
elif not right.startswith(b"^"):
return -1 # left < right
# strip the ^ and start again
left, right = left[1:], right[1:]
continue
# Caret means the version is less... Unless the other version
# has ended, then do the exact opposite.
if right.startswith(b"^"):
return -1 if not left else 1
# We've run out of characters to compare.
# Note: we have to do this after we compare the ~ and ^ madness
# because ~'s and ^'s take precedance.
if not left or not right:
break
# Lets see if we've got numbers
match_left = R_NUM.match(left)
if match_left:
match_right = R_NUM.match(right)
if not match_right: # right is not a num and nums > alphas
return 1 # left > right
isnum = True
else: # match is alpha
match_left = R_ALPHA.match(left)
match_right = R_ALPHA.match(right)
if not match_right: # right is not an alpha and nums > alphas
return -1 # left < right
isnum = False
# strip off the leading numeric or alpha chars
left_head, left = match_left.group(1), match_left.group(2)
right_head, right = match_right.group(1), match_right.group(2)
if isnum:
left_head = left_head.lstrip(b"0")
right_head = right_head.lstrip(b"0")
# Length of contiguous numbers matters
left_head_len = len(left_head)
right_head_len = len(right_head)
if left_head_len < right_head_len:
return -1 # left < right
if left_head_len > right_head_len:
return 1 # left > right
# Either a number with the same number of chars or
# the leading chars are alpha so lets do a standard compare
if left_head < right_head:
return -1 # left < right
if left_head > right_head:
return 1 # left > right
# Both header segments are of equal length, keep going with the new
continue # pragma: no cover
# if both are now zero length they must be equal
if len(left) == len(right) == 0:
return 0 # left == right
# Longer string is > than shorter string
if len(left) != 0:
return 1 # left > right
return -1 # left < right