amprolla

devuan's apt repo merger
git clone git://parazyd.org/amprolla.git
Log | Files | Refs | README | LICENSE

commit aea67c63efac81f21a28464d044d3f012339c3c6
parent 5d279f837f4bfd6d393d01cd8b8f03289d1fbf28
Author: KatolaZ <katolaz@freaknet.org>
Date:   Tue, 19 Dec 2017 01:05:29 +0100

Implement Debian Policy versioning alrorithm to parse package versions.

Diffstat:
Mlib/package.py | 33++-------------------------------
Mlib/parse.py | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 157 insertions(+), 31 deletions(-)

diff --git a/lib/package.py b/lib/package.py @@ -13,7 +13,7 @@ from shutil import copyfile import lib.globalvars as globalvars from lib.config import mergedir, packages_keys, sources_keys, spooldir from lib.log import logtofile -from lib.parse import parse_dependencies, parse_packages +from lib.parse import parse_dependencies, parse_packages, cmppkgver def write_packages(packages, filename, sort=True, sources=False): @@ -116,38 +116,9 @@ def package_newer(pkg1, pkg2): if pkg1.get('Package') in _skips: return False - # The choice of dropping [1:] is because we don't care for +deb or +devuan - hi_prio = pkg1.get('Version').split('+')[0] - lo_prio = pkg2.get('Version').split('+')[0] - - # Epoch check - hi_ep = 0 - lo_ep = 0 - if ':' in hi_prio: - hi_ep = int(hi_prio.split(':')[0]) - hi_prio = hi_prio.split(':')[1] - if ':' in lo_prio: - lo_ep = int(lo_prio.split(':')[0]) - lo_prio = lo_prio.split(':')[1] - if lo_ep > hi_ep: + if cmppkgver(pkg1.get('Version'), pkg2.get('Version')) < 1: return True - # [0] will be upstream, [1] should be the package build - hi_prio = hi_prio.split('-') - lo_prio = lo_prio.split('-') - if lo_prio[0] > hi_prio[0]: - return True - - if len(hi_prio) > 1 and len(lo_prio) > 1: - hi_prio[1] = hi_prio[1].replace('.', '') - lo_prio[1] = lo_prio[1].replace('.', '') - if '~' in hi_prio[1]: - hi_prio[1] = hi_prio[1].split('~')[0] - if '~' in lo_prio[1]: - lo_prio[1] = lo_prio[1].split('~')[0] - if int(lo_prio[1]) > int(hi_prio[1]): - return True - return False diff --git a/lib/parse.py b/lib/parse.py @@ -6,6 +6,8 @@ Parsing functions/helpers from time import mktime, strptime +from lib.log import info + def get_time(date): """ @@ -153,6 +155,159 @@ def parse_dependencies(dependencies): return ret +def compare_epochs(epo1, epo2): + """ + Compares two given epochs and returns their difference. + """ + return int(epo1) - int(epo2) + + +def get_epoch(ver): + """ + Parses and returns the epoch, and the rest, split of a version string. + """ + if ':' in ver: + return ver.split(':', 1) + return "0", ver + + +def get_upstream(rest): + """ + Separate upstream_version from debian-version. The latter is whatever is + found after the last "-" (hyphen) + """ + split_s = rest.rsplit('-', 1) + if len(split_s) < 2: + return split_s[0], "" + return split_s + + +def get_non_digit(s): + """ + Get a string and return the longest leading substring consisting exclusively + of non-digits (or an empty string), and the remaining substring. + """ + if not s: + return "", "" + head = "" + tail = s + N = len(s) + i = 0 + while i < N and not s[i].isdigit(): + head += s[i] + tail = tail[1:] + i += 1 + return head, tail + + +def get_digit(s): + """ + Get a string and return the integer value of the longest leading substring + consisting exclusively of digit characters (or zero otherwise), and the + remaining substring. + """ + if not s: + return 0, "" + head = "" + tail = s + N = len(s) + i = 0 + while i < N and s[i].isdigit(): + head += s[i] + tail = tail[1:] + i += 1 + return int(head), tail + + +def char_val(c): + """ + Returns an integer value of a given unicode character. Returns 0 on ~ (since + this is in Debian's policy) + """ + if c == '~': + return 0 + elif not c.isalpha(): + return 256 + ord(c) + return ord(c) + + +def compare_deb_str(a1, a2): + while len(a1) > 0 and len(a2) > 0: + char_diff = char_val(a1[0]) - char_val(a2[0]) + if char_diff != 0: + return char_diff + a1 = a1[1:] + a2 = a2[1:] + if len(a1) == 0: + if len(a2) == 0: + return 0 + else: + if a2[0] == '~': + return 512 + else: + return -ord(a2[0]) + else: + if a1[0] == '~': + return -512 + else: + return ord(a1[0]) + + +def compare_non_epoch(s1, s2): + cont = True + while cont: + alpha1, tail1 = get_non_digit(s1) + alpha2, tail2 = get_non_digit(s2) + if alpha1 == alpha2: + num1, s1 = get_digit(tail1) + num2, s2 = get_digit(tail2) + if num1 == num2: + cont = True + else: + diff = num1 - num2 + cont = False + else: + cont = False + diff = compare_deb_str(alpha1, alpha2) + + return diff + + +def cmppkgver(ver1, ver2): + """ + Main function to compare two package versions. Wraps around other functions + to provide a result. It returns an integer < 0 if ver1 is earlier than ver2, + 0 if ver1 is the same as ver2, and an integer > 0 if ver2 is earlier than + ver2. + + WARNING: The function does not induce a total order (i.e., return values + MUST NOT be added or subtracted) + + https://www.debian.org/doc/debian-policy/#version + """ + epoch1, rest1 = get_epoch(ver1) + epoch2, rest2 = get_epoch(ver2) + + ec = compare_epochs(epoch1, epoch2) + if ec != 0: + # The two versions differ on epoch + info('differing epochs: %d\n' % ec) + return ec + else: + info('equal epochs') + + upst1, rev1 = get_upstream(rest1) + upst2, rev2 = get_upstream(rest2) + + info('v1: up: %s deb: %s' % (upst1, rev1)) + info('v2: up: %s deb: %s' % (upst2, rev2)) + + up_diff = compare_deb_str(upst1, upst2) + if up_diff == 0: + return compare_deb_str(rev1, rev2) + return up_diff + + def compare_dict(dic1, dic2): """ Compares two dicts