Compare two RPM version strings

    Compares two RPM version strings and returns an integer indicating
    the result of the comparison. The method of comparison mirrors that
    used by RPM, so results should be the same for any standard RPM
    package.

    To perform the comparison, the strings are first checked for
    equality. If they are equal, the versions are equal. Otherwise,
    each string is converted to a character list, and a comparison
    loop is started using these lists.

    In the comparison loop, first any non-alphanumeric, non-~
    characters are trimmed from the front of the list. Then if the first
    character from both ``a`` and ``b`` is a ~ (tilde), it is trimmed.
    The ~ (tilde) character indicates that a given package or version
    should be considered older (even if it is numerically larger), so
    if ``a`` begins with a tilde, ``b`` is newer, and vice-versa. At
    this point, if the length of either list has been reduced to 0, the
    loop is exited. If characters remain in the list, the
    :any:`_get_block_result` function is used to pop consecutive digits
    or letters from the front of hte list and compare them. The result
    of the block comparison is returned if the blocks are not equal.
    The loop then begins again.

    If the loop exits without returning a value, the lengths of the
    remaining character lists are compared. If they have the same length
    (usually 0, since all characters have been popped), they are
    considered to be equal. Otherwise, whichever is longer is considered
    to be newer. Generally, unequal length will be due to one character
    list having been completely consumed while some characters remain on
    the other, for example when comparing 1.05b to 1.05.

    :param unicode version_a: An RPM version or release string
    :param unicode version_b: An RPM version or release string
    :return: 1 (if ``a`` is newer), 0 (if versions are equal), or -1
        (if ``b`` is newer)
    :rtype: int
    :raises RpmError: if an a type is passed that cannot be converted to
        a list

def compare_versions(version_a, version_b):
    """Compare two RPM version strings

    Compares two RPM version strings and returns an integer indicating
    the result of the comparison. The method of comparison mirrors that
    used by RPM, so results should be the same for any standard RPM
    package.

    To perform the comparison, the strings are first checked for
    equality. If they are equal, the versions are equal. Otherwise,
    each string is converted to a character list, and a comparison
    loop is started using these lists.

    In the comparison loop, first any non-alphanumeric, non-~
    characters are trimmed from the front of the list. Then if the first
    character from both ``a`` and ``b`` is a ~ (tilde), it is trimmed.
    The ~ (tilde) character indicates that a given package or version
    should be considered older (even if it is numerically larger), so
    if ``a`` begins with a tilde, ``b`` is newer, and vice-versa. At
    this point, if the length of either list has been reduced to 0, the
    loop is exited. If characters remain in the list, the
    :any:`_get_block_result` function is used to pop consecutive digits
    or letters from the front of hte list and compare them. The result
    of the block comparison is returned if the blocks are not equal.
    The loop then begins again.

    If the loop exits without returning a value, the lengths of the
    remaining character lists are compared. If they have the same length
    (usually 0, since all characters have been popped), they are
    considered to be equal. Otherwise, whichever is longer is considered
    to be newer. Generally, unequal length will be due to one character
    list having been completely consumed while some characters remain on
    the other, for example when comparing 1.05b to 1.05.

    :param unicode version_a: An RPM version or release string
    :param unicode version_b: An RPM version or release string
    :return: 1 (if ``a`` is newer), 0 (if versions are equal), or -1
        (if ``b`` is newer)
    :rtype: int
    :raises RpmError: if an a type is passed that cannot be converted to
        a list
    """
    logger.debug('compare_versions(%s, %s)', version_a, version_b)
    if version_a == version_b:
        return a_eq_b
    try:
        chars_a, chars_b = list(version_a), list(version_b)
    except TypeError:
        raise RpmError('Could not compare {0} to '
                       '{1}'.format(version_a, version_b))
    while len(chars_a) != 0 and len(chars_b) != 0:
        logger.debug('starting loop comparing %s '
                     'to %s', chars_a, chars_b)
        _check_leading(chars_a, chars_b)
        if chars_a[0] == '~' and chars_b[0] == '~':
            map(lambda x: x.pop(0), (chars_a, chars_b))
        elif chars_a[0] == '~':
            return b_newer
        elif chars_b[0] == '~':
            return a_newer
        if len(chars_a) == 0 or len(chars_b) == 0:
            break
        block_res = _get_block_result(chars_a, chars_b)
        if block_res != a_eq_b:
            return block_res
    if len(chars_a) == len(chars_b):
        logger.debug('versions are equal')
        return a_eq_b
    else:
        logger.debug('versions not equal')
        return a_newer if len(chars_a) > len(chars_b) else b_newer