diff --git a/pkgsync b/pkgsync index c87d9e4..a5a0c0a 100644 --- a/pkgsync +++ b/pkgsync @@ -25,6 +25,10 @@ class HistoryFileNotFoundError(Exception): pass +class DistroUnsupported(Exception): + pass + + def detect_distro(): """Get the Linux distribution""" distro = None @@ -47,8 +51,8 @@ def detect_distro(): return distro -def compare_version(a, b): - """Compare package versions""" +def compare_debian_version(a, b): + """Compare Debian package versions""" re_digits_non_digits = re.compile(r'\d+|\D+') re_digits = re.compile(r'\d+') re_digit = re.compile(r'\d') @@ -142,6 +146,155 @@ def compare_version(a, b): return 0 +def compare_redhat_version(a, b): + """Compare RedHat package versions""" + def compare_parts(part1, part2): + if part1 == part2: + return 0 + p1 = list(part1) + p2 = list(part2) + + while p1 or p2: + for c in list(p1): + if not c.isalnum() and not c == '~': + p1.pop(0) + else: + break + for c in list(p2): + if not c.isalnum() and not c == '~': + p2.pop(0) + else: + break + try: + c1 = p1[0] + except IndexError: + c1 = '' + + try: + c2 = p2[0] + except IndexError: + c2 = '' + + if c1 == '~' and c2 == '~': + p1.pop(0) + p2.pop(0) + elif c1 == '~': + return 1 + elif c2 == '~': + return -1 + + if not c1 and not c2: + break + + lhs_is_digit = c1.isdigit() + + if c1.isdigit(): + r1 = [] + for cx in list(p1): + if cx.isdigit(): + r1.append(p1.pop(0)) + else: + break + r2 = [] + for c in list(p2): + if c.isdigit(): + r2.append(p2.pop(0)) + else: + break + if r1: + while r1 and r1[0] == '0': + r1.pop(0) + if r2: + while r2 and r2[0] == '0': + r2.pop(0) + + if r1 == r2: + continue + + if not r2: + if lhs_is_digit: + return -1 + else: + return 1 + if len(r1) != len(r2): + if len(r1) > len(r2): + return -1 + else: + return 1 + elif r1 == r2: + return 0 + elif r1 > r2: + return -1 + else: + return 1 + + else: + r1 = [] + for cx in list(p1): + if cx.isalpha(): + r1.append(p1.pop(0)) + else: + break + r2 = [] + for cy in list(p2): + if cy.isalpha(): + r2.append(p2.pop(0)) + else: + break + + if not r2: + if lhs_is_digit: + return -1 + else: + return 1 + + if len(r1) != len(r2): + if len(r1) > len(r2): + return -1 + else: + return 1 + elif r1 == r2: + continue + elif r1 > r2: + return -1 + else: + return 1 + return 0 + + e1 = int(a.epoch) + e2 = int(b.epoch) + + if e1 < e2: + return 1 + if e1 > e2: + return -1 + + v1 = a.version + v2 = b.version + + rc = compare_parts(v1, v2) + + if rc != 0: + return rc + + r1 = a.release + r2 = b.release + + rc = compare_parts(r1, r2) + + if rc != 0: + return rc + + return 0 + +def compare_version(v1, v2, distro): + if distro in RH_FAMILY: + return compare_redhat_version(v1, v2) + elif distro in DEB_FAMILY: + return compare_debian_version(v1, v2) + raise DistroUnsupported(distro) + + def dict_factory(cursor, row): d = dict() for idx, col in enumerate(cursor.description): @@ -480,7 +633,7 @@ def main(options): current = current_packages.get(pkg) imported = imported_packages.get(pkg) - rc = compare_version(current, imported) + rc = compare_version(current, imported, distro) if rc == 1 and options.upgraded: logger.debug('Upgrade: {0} (current) - {1} (imported)'.format(current, imported))