def _compare_values()

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