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:
M | lib/package.py | | | 33 | ++------------------------------- |
M | lib/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