Skip to content

Commit 63bd5ae

Browse files
committed
Add version class for pacman
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
1 parent c50b20c commit 63bd5ae

6 files changed

Lines changed: 274 additions & 65 deletions

File tree

src/univers/arch.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Copyright 2016-2020 Christoph Reiter
2+
# SPDX-License-Identifier: MIT
3+
4+
import re
5+
from itertools import zip_longest
6+
from typing import List, Tuple, Optional, Dict, Set
7+
8+
9+
def vercmp(v1: str, v2: str) -> int:
10+
def cmp(a: int, b: int) -> int:
11+
return (a > b) - (a < b)
12+
13+
def split(v: str) -> Tuple[str, str, Optional[str]]:
14+
if ":" in v:
15+
e, v = v.split(":", 1)
16+
else:
17+
e, v = ("0", v)
18+
19+
r: Optional[str] = None
20+
if "-" in v:
21+
v, r = v.rsplit("-", 1)
22+
else:
23+
v, r = (v, None)
24+
25+
return (e, v, r)
26+
27+
digit, alpha, other = range(3)
28+
29+
def get_type(c: str) -> int:
30+
assert c
31+
if c.isdigit():
32+
return digit
33+
elif c.isalpha():
34+
return alpha
35+
else:
36+
return other
37+
38+
def parse(v: str) -> List[str]:
39+
parts: List[str] = []
40+
current = ""
41+
for c in v:
42+
if not current:
43+
current += c
44+
else:
45+
if get_type(c) == get_type(current):
46+
current += c
47+
else:
48+
parts.append(current)
49+
current = c
50+
51+
if current:
52+
parts.append(current)
53+
54+
return parts
55+
56+
def rpmvercmp(v1: str, v2: str) -> int:
57+
for p1, p2 in zip_longest(parse(v1), parse(v2), fillvalue=None):
58+
if p1 is None:
59+
if get_type(p2) == alpha:
60+
return 1
61+
return -1
62+
elif p2 is None:
63+
if get_type(p1) == alpha:
64+
return -1
65+
return 1
66+
67+
t1 = get_type(p1)
68+
t2 = get_type(p2)
69+
if t1 != t2:
70+
if t1 == digit:
71+
return 1
72+
elif t2 == digit:
73+
return -1
74+
elif t1 == other:
75+
return 1
76+
elif t2 == other:
77+
return -1
78+
elif t1 == other:
79+
ret = cmp(len(p1), len(p2))
80+
if ret != 0:
81+
return ret
82+
elif t1 == digit:
83+
ret = cmp(int(p1), int(p2))
84+
if ret != 0:
85+
return ret
86+
elif t1 == alpha:
87+
ret = cmp(p1, p2)
88+
if ret != 0:
89+
return ret
90+
91+
return 0
92+
93+
e1, v1, r1 = split(v1)
94+
e2, v2, r2 = split(v2)
95+
96+
ret = rpmvercmp(e1, e2)
97+
if ret == 0:
98+
ret = rpmvercmp(v1, v2)
99+
if ret == 0 and r1 is not None and r2 is not None:
100+
ret = rpmvercmp(r1, r2)
101+
102+
return ret
103+
104+
105+
def extract_upstream_version(version: str) -> str:
106+
return version.rsplit("-")[0].split("+", 1)[0].split("~", 1)[-1].split(":", 1)[-1]
107+
108+
109+
def strip_vcs(package_name: str) -> str:
110+
if package_name.endswith(("-cvs", "-svn", "-hg", "-darcs", "-bzr", "-git")):
111+
return package_name.rsplit("-", 1)[0]
112+
return package_name
113+
114+
115+
def arch_version_to_msys(v: str) -> str:
116+
return v.replace(":", "~")
117+
118+
119+
def version_is_newer_than(v1: str, v2: str) -> bool:
120+
return vercmp(v1, v2) == 1
121+
122+
123+
def split_depends(deps: List[str]) -> Dict[str, Set[str]]:
124+
r: Dict[str, Set[str]] = {}
125+
for d in deps:
126+
parts = re.split("([<>=]+)", d, 1)
127+
first = parts[0].strip()
128+
second = "".join(parts[1:]).strip()
129+
r.setdefault(first, set()).add(second)
130+
return r
131+
132+
133+
def split_optdepends(deps: List[str]) -> Dict[str, Set[str]]:
134+
r: Dict[str, Set[str]] = {}
135+
for d in deps:
136+
if ":" in d:
137+
a, b = d.split(":", 1)
138+
a, b = a.strip(), b.strip()
139+
else:
140+
a, b = d.strip(), ""
141+
e = r.setdefault(a, set())
142+
if b:
143+
e.add(b)
144+
return r

src/univers/arch.py.ABOUT

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
about_resource: arch.py
2+
package_url: pkg:github/msys2/msys2-web@3ed2dde45a8761523b749e42c201a737c7613e6e
3+
copyright: |
4+
Copyright 2016-2020 Christoph Reiter
5+
6+
license_expression: MIT
7+
homepage_url: https://github.com/msys2/msys2-web/
8+
9+
notes: |
10+
The version comparision utility is extracted from msys2 and further stripped down.
11+
12+
notice_file: arch.py.NOTICE

src/univers/arch.py.NOTICE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License
2+
3+
Copyright (c) 2017 Christoph Reiter
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

src/univers/versions.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from univers.rpm import vercmp as rpm_vercmp
2929
from univers.gentoo import vercmp as gentoo_vercmp
3030
from univers.gentoo import parse_version_and_revision as parse_gentoo_version_and_revision
31+
from univers.arch import vercmp as arch_vercmp
3132

3233

3334
class InvalidVersion(ValueError):
@@ -118,6 +119,29 @@ def __lt__(self, other):
118119
return self.value.__lt__(other.value)
119120

120121

122+
@attr.s(frozen=True, init=False, order=False, eq=False, hash=True, repr=False)
123+
@total_ordering
124+
class ArchVersion(BaseVersion):
125+
scheme = "arch"
126+
127+
def __init__(self, version_string):
128+
version_string = version_string.lower()
129+
version_string = remove_spaces(version_string)
130+
object.__setattr__(self, "version_string", version_string)
131+
object.__setattr__(self, "value", version_string)
132+
133+
@staticmethod
134+
def validate(version_string):
135+
pass
136+
137+
def __eq__(self, other):
138+
# TBD: Should this verify the type of `other`
139+
return arch_vercmp(self.value, other.value) == 0
140+
141+
def __lt__(self, other):
142+
return arch_vercmp(self.value, other.value) == -1
143+
144+
121145
@total_ordering
122146
@attr.s(frozen=True, init=False, order=False, eq=False, hash=True, repr=False)
123147
class DebianVersion(BaseVersion):

tests/test_pacman_vercmp.py

Lines changed: 67 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,96 @@
1-
from univers.versions import RPMVersion
1+
from univers.versions import ArchVersion
22

33
# all similar length, no pkgrel
44
def test_same_length():
5-
assert RPMVersion("1.5.0") == RPMVersion("1.5.0")
6-
assert RPMVersion("1.5.1") > RPMVersion("1.5.0")
5+
assert ArchVersion("1.5.0") == ArchVersion("1.5.0")
6+
assert ArchVersion("1.5.1") > ArchVersion("1.5.0")
77

88

99
# mixed length
1010
def test_mixed_length():
11-
assert RPMVersion("1.5.1") > RPMVersion("1.5")
11+
assert ArchVersion("1.5.1") > ArchVersion("1.5")
1212

1313

1414
# with pkgrel, simple
1515
def test_with_pkgrel_same_length():
16-
assert RPMVersion("1.5.0-1") == RPMVersion("1.5.0-1")
17-
assert RPMVersion("1.5.0-1") < RPMVersion("1.5.0-2")
18-
assert RPMVersion("1.5.0-1") < RPMVersion("1.5.1-1")
19-
assert RPMVersion("1.5.0-2") < RPMVersion("1.5.1-1")
16+
assert ArchVersion("1.5.0-1") == ArchVersion("1.5.0-1")
17+
assert ArchVersion("1.5.0-1") < ArchVersion("1.5.0-2")
18+
assert ArchVersion("1.5.0-1") < ArchVersion("1.5.1-1")
19+
assert ArchVersion("1.5.0-2") < ArchVersion("1.5.1-1")
2020

2121

2222
# going crazy? alpha-dotted versions
2323
def test_alpha_dotted():
24-
assert RPMVersion("1.5.a") > RPMVersion("1.5 ")
25-
assert RPMVersion("1.5.b") > RPMVersion("1.5.a")
26-
assert RPMVersion("1.5.1") > RPMVersion("1.5.b")
24+
assert ArchVersion("1.5.a") > ArchVersion("1.5")
25+
assert ArchVersion("1.5.b") > ArchVersion("1.5.a")
26+
assert ArchVersion("1.5.1") > ArchVersion("1.5.b")
2727

2828

2929
# epoch included version comparisons
3030
def test_with_epoch():
31-
assert RPMVersion("0:1.0") == RPMVersion("0:1.0")
32-
assert RPMVersion("0:1.0") < RPMVersion("0:1.1")
33-
assert RPMVersion("1:1.0") > RPMVersion("0:1.0")
34-
assert RPMVersion("1:1.0") > RPMVersion("0:1.1")
35-
assert RPMVersion("1:1.0") < RPMVersion("2:1.1")
31+
assert ArchVersion("0:1.0") == ArchVersion("0:1.0")
32+
assert ArchVersion("0:1.0") < ArchVersion("0:1.1")
33+
assert ArchVersion("1:1.0") > ArchVersion("0:1.0")
34+
assert ArchVersion("1:1.0") > ArchVersion("0:1.1")
35+
assert ArchVersion("1:1.0") < ArchVersion("2:1.1")
3636

3737

3838
# epoch + sometimes present pkgrel
3939
def test_with_epoch_mixed_pkgrel():
40-
assert RPMVersion("1:1.0") > RPMVersion("0:1.0-1")
41-
assert RPMVersion("1:1.0-1") > RPMVersion("0:1.1-1")
40+
assert ArchVersion("1:1.0") > ArchVersion("0:1.0-1")
41+
assert ArchVersion("1:1.0-1") > ArchVersion("0:1.1-1")
4242

4343

44-
# # epoch included on one version
45-
# def test_with_only_one_version_with_epoch():
46-
# assert RPMVersion("0:1.0") == RPMVersion("1.0")
47-
# assert RPMVersion("0:1.0") < RPMVersion("1.1")
48-
# assert RPMVersion("0:1.1") > RPMVersion("1.0")
49-
# assert RPMVersion("1:1.0") > RPMVersion("1.0")
50-
# assert RPMVersion("1:1.0") > RPMVersion("1.1")
51-
# assert RPMVersion("1:1.1") > RPMVersion("1.1")
44+
# epoch included on one version
45+
def test_with_only_one_version_with_epoch():
46+
assert ArchVersion("0:1.0") == ArchVersion("1.0")
47+
assert ArchVersion("0:1.0") < ArchVersion("1.1")
48+
assert ArchVersion("0:1.1") > ArchVersion("1.0")
49+
assert ArchVersion("1:1.0") > ArchVersion("1.0")
50+
assert ArchVersion("1:1.0") > ArchVersion("1.1")
51+
assert ArchVersion("1:1.1") > ArchVersion("1.1")
52+
53+
54+
# alpha dots and dashes
55+
def test_alpha_dot_dash():
56+
assert ArchVersion("1.5.b-1") == ArchVersion("1.5.b")
57+
assert ArchVersion("1.5-1") < ArchVersion("1.5.b")
5258

53-
# # alpha dots and dashes
54-
# def test_alpha_dot_dash():
55-
# assert RPMVersion("1.5.b-1") == RPMVersion("1.5.b")
56-
# assert RPMVersion("1.5-1") < RPMVersion("1.5.b")
5759

5860
# # same/similar content, differing separators
5961
# def test_same_content_different_separators():
60-
# assert RPMVersion("2.0") == RPMVersion("2_0")
61-
# assert RPMVersion("2.0_a") == RPMVersion("2_0.a")
62-
# assert RPMVersion("2.0a ") < RPMVersion("2.0.a")
63-
# assert RPMVersion("2___a") == RPMVersion("2_a")
64-
65-
# # with pkgrel, mixed lengths
66-
# def test_with_pkgrel_mixed_length():
67-
# assert RPMVersion("1.5-1") < RPMVersion("1.5.1-1")
68-
# assert RPMVersion("1.5-2") < RPMVersion("1.5.1-1")
69-
# assert RPMVersion("1.5-2") < RPMVersion("1.5.1-2")
70-
71-
# # mixed pkgrel inclusion
72-
# def test_with_pkgrel_mixed():
73-
# assert RPMVersion("1.5") == RPMVersion("1.5-1")
74-
# assert RPMVersion("1.5-1") == RPMVersion("1.5 ")
75-
# assert RPMVersion("1.1-1") == RPMVersion("1.1 ")
76-
# assert RPMVersion("1.0-1") < RPMVersion("1.1 ")
77-
# assert RPMVersion("1.1-1") > RPMVersion("1.0 ")
78-
79-
# # alphanumeric versions
80-
# assert RPMVersion("1.5b-1") < RPMVersion("1.5-1")
81-
# assert RPMVersion("1.5b ") < RPMVersion("1.5 ")
82-
# assert RPMVersion("1.5b-1") < RPMVersion("1.5 ")
83-
# assert RPMVersion("1.5b ") < RPMVersion("1.5.1")
84-
85-
# # from the manpage
86-
# def test_manpage_cases():
87-
# assert RPMVersion("1.0a") < RPMVersion("1.0alpha")
88-
# assert RPMVersion("1.0alpha") < RPMVersion("1.0b")
89-
# assert RPMVersion("1.0b") < RPMVersion("1.0beta")
90-
# assert RPMVersion("1.0beta") < RPMVersion("1.0rc")
91-
# assert RPMVersion("1.0rc") < RPMVersion("1.0")
62+
# assert ArchVersion("2.0") == ArchVersion("2_0")
63+
# assert ArchVersion("2.0_a") == ArchVersion("2_0.a")
64+
# assert ArchVersion("2.0a ") < ArchVersion("2.0.a")
65+
# assert ArchVersion("2___a") == ArchVersion("2_a")
66+
67+
68+
# with pkgrel, mixed lengths
69+
def test_with_pkgrel_mixed_length():
70+
assert ArchVersion("1.5-1") < ArchVersion("1.5.1-1")
71+
assert ArchVersion("1.5-2") < ArchVersion("1.5.1-1")
72+
assert ArchVersion("1.5-2") < ArchVersion("1.5.1-2")
73+
74+
75+
# mixed pkgrel inclusion
76+
def test_with_pkgrel_mixed():
77+
assert ArchVersion("1.5") == ArchVersion("1.5-1")
78+
assert ArchVersion("1.5-1") == ArchVersion("1.5")
79+
assert ArchVersion("1.1-1") == ArchVersion("1.1")
80+
assert ArchVersion("1.0-1") < ArchVersion("1.1")
81+
assert ArchVersion("1.1-1") > ArchVersion("1.0")
82+
83+
84+
# alphanumeric versions
85+
assert ArchVersion("1.5b-1") < ArchVersion("1.5-1")
86+
assert ArchVersion("1.5b ") < ArchVersion("1.5 ")
87+
assert ArchVersion("1.5b-1") < ArchVersion("1.5 ")
88+
assert ArchVersion("1.5b ") < ArchVersion("1.5.1")
89+
90+
# from the manpage
91+
def test_manpage_cases():
92+
assert ArchVersion("1.0a") < ArchVersion("1.0alpha")
93+
assert ArchVersion("1.0alpha") < ArchVersion("1.0b")
94+
assert ArchVersion("1.0b") < ArchVersion("1.0beta")
95+
assert ArchVersion("1.0beta") < ArchVersion("1.0rc")
96+
assert ArchVersion("1.0rc") < ArchVersion("1.0")

tests/test_pacman_vercmp.py.ABOUT

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
about_resource: test_pacman_vercmp.py
22
license_expression: apache-2.0
33
download_url: https://git.archlinux.org/pacman.git/plain/test/util/vercmptest.sh
4-
copyright: Copyright (c) 2009-2020 by Pacman Development Team
4+
copyright: |
5+
Copyright (c) 2009-2020 by Pacman Development Team
6+
Copyright (c) 2008 by Dan McGee <dan@archlinux.org>
7+
58
package_url: pkg:pypi/pymaven-patch@0.2.9#tests/test_versioning.py
69
notes: this subset of tests has been modified to tests version comparison and parsing
7-
homepage_url: https://github.com/nexB/pymaven
8-
notice_file: test_maven_version.py.NOTICE
10+
homepage_url: https://git.archlinux.org/pacman.git
11+
notice_file: test_pacman_vercmp.py.NOTICE

0 commit comments

Comments
 (0)