Treat them like all other packages. They used to cause various problems by hitting edge cases, but this should all be fixed now.
156 lines
4.0 KiB
Python
156 lines
4.0 KiB
Python
# Copyright 2016-2020 Christoph Reiter
|
|
# SPDX-License-Identifier: MIT
|
|
|
|
import re
|
|
from itertools import zip_longest
|
|
from typing import List, Tuple, Optional, Dict, Set
|
|
|
|
|
|
def vercmp(v1: str, v2: str) -> int:
|
|
|
|
def cmp(a: int, b: int) -> int:
|
|
return (a > b) - (a < b)
|
|
|
|
def split(v: str) -> Tuple[str, str, Optional[str]]:
|
|
if "~" in v:
|
|
e, v = v.split("~", 1)
|
|
else:
|
|
e, v = ("0", v)
|
|
|
|
r: Optional[str] = None
|
|
if "-" in v:
|
|
v, r = v.rsplit("-", 1)
|
|
else:
|
|
v, r = (v, None)
|
|
|
|
return (e, v, r)
|
|
|
|
digit, alpha, other = range(3)
|
|
|
|
def get_type(c: str) -> int:
|
|
assert c
|
|
if c.isdigit():
|
|
return digit
|
|
elif c.isalpha():
|
|
return alpha
|
|
else:
|
|
return other
|
|
|
|
def parse(v: str) -> List[Tuple[int, Optional[str]]]:
|
|
parts: List[Tuple[int, Optional[str]]] = []
|
|
seps = 0
|
|
current = ""
|
|
for c in v:
|
|
if get_type(c) == other:
|
|
if current:
|
|
parts.append((seps, current))
|
|
current = ""
|
|
seps += 1
|
|
else:
|
|
if not current:
|
|
current += c
|
|
else:
|
|
if get_type(c) == get_type(current):
|
|
current += c
|
|
else:
|
|
parts.append((seps, current))
|
|
current = c
|
|
|
|
parts.append((seps, current or None))
|
|
|
|
return parts
|
|
|
|
def rpmvercmp(v1: str, v2: str) -> int:
|
|
for (s1, p1), (s2, p2) in zip_longest(parse(v1), parse(v2),
|
|
fillvalue=(None, None)):
|
|
|
|
if s1 is not None and s2 is not None:
|
|
ret = cmp(s1, s2)
|
|
if ret != 0:
|
|
return ret
|
|
|
|
if p1 is None and p2 is None:
|
|
return 0
|
|
|
|
if p1 is None:
|
|
if get_type(p2) == alpha:
|
|
return 1
|
|
return -1
|
|
elif p2 is None:
|
|
if get_type(p1) == alpha:
|
|
return -1
|
|
return 1
|
|
|
|
t1 = get_type(p1)
|
|
t2 = get_type(p2)
|
|
if t1 != t2:
|
|
if t1 == digit:
|
|
return 1
|
|
elif t2 == digit:
|
|
return -1
|
|
elif t1 == digit:
|
|
ret = cmp(int(p1), int(p2))
|
|
if ret != 0:
|
|
return ret
|
|
elif t1 == alpha:
|
|
ret = cmp(p1, p2)
|
|
if ret != 0:
|
|
return ret
|
|
|
|
return 0
|
|
|
|
e1, v1, r1 = split(v1)
|
|
e2, v2, r2 = split(v2)
|
|
|
|
ret = rpmvercmp(e1, e2)
|
|
if ret == 0:
|
|
ret = rpmvercmp(v1, v2)
|
|
if ret == 0 and r1 is not None and r2 is not None:
|
|
ret = rpmvercmp(r1, r2)
|
|
|
|
return ret
|
|
|
|
|
|
def extract_upstream_version(version: str) -> str:
|
|
return version.rsplit(
|
|
"-")[0].split("+", 1)[0].split("~", 1)[-1].split(":", 1)[-1]
|
|
|
|
|
|
def strip_vcs(package_name: str) -> str:
|
|
if package_name.endswith(
|
|
("-cvs", "-svn", "-hg", "-darcs", "-bzr", "-git")):
|
|
return package_name.rsplit("-", 1)[0]
|
|
return package_name
|
|
|
|
|
|
def arch_version_to_msys(v: str) -> str:
|
|
return v.replace(":", "~")
|
|
|
|
|
|
def version_is_newer_than(v1: str, v2: str) -> bool:
|
|
return vercmp(v1, v2) == 1
|
|
|
|
|
|
def split_depends(deps: List[str]) -> Dict[str, Set[str]]:
|
|
r: Dict[str, Set[str]] = {}
|
|
for d in deps:
|
|
parts = re.split("([<>=]+)", d, 1)
|
|
first = parts[0].strip()
|
|
second = "".join(parts[1:]).strip()
|
|
r.setdefault(first, set()).add(second)
|
|
return r
|
|
|
|
|
|
def split_optdepends(deps: List[str]) -> Dict[str, Set[str]]:
|
|
r: Dict[str, Set[str]] = {}
|
|
for d in deps:
|
|
if ":" in d:
|
|
a, b = d.split(":", 1)
|
|
a, b = a.strip(), b.strip()
|
|
else:
|
|
a, b = d.strip(), ""
|
|
e = r.setdefault(a, set())
|
|
if b:
|
|
e.add(b)
|
|
return r
|