Skip to content

Commit f09303e

Browse files
author
Dani Pinyol
committed
Support prerelease in version
1 parent 8dd9467 commit f09303e

File tree

2 files changed

+54
-11
lines changed

2 files changed

+54
-11
lines changed

src/juliapkg/compat.py

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,26 @@
22

33
from semver import Version
44

5-
_re_partial_version = re.compile(r"^([0-9]+)(?:\.([0-9]+)(?:\.([0-9]+))?)?$")
5+
_re_digits_g = "[0-9]+"
6+
7+
8+
def _re_group(inner="", numeric=True, delimiter="."):
9+
capture = _re_digits_g if numeric else ".*"
10+
return f"(?:{delimiter}({capture}){inner})?"
11+
12+
13+
_re_prerelease = _re_group(numeric=False)
14+
_re_optional = _re_group(_re_group(_re_prerelease))
15+
_re_partial_version = re.compile(rf"^({_re_digits_g}){_re_optional}$")
616

717

818
def _parse_partial_version(x):
919
m = _re_partial_version.match(x)
1020
if m is None:
1121
return None, None
12-
major, minor, patch = m.groups()
13-
v = Version(major, minor or 0, patch or 0)
14-
n = 1 if minor is None else 2 if patch is None else 3
22+
major, minor, patch, prerelease = m.groups()
23+
v = Version(major, minor or 0, patch or 0, prerelease)
24+
n = 1 if minor is None else 2 if patch is None else 3 if prerelease is None else 4
1525
return (v, n)
1626

1727

@@ -87,20 +97,26 @@ def caret(cls, v, n):
8797
v.major,
8898
v.minor if n >= 2 else 0,
8999
v.patch if n >= 3 else 0,
100+
v.prerelease if n >= 4 else None,
90101
)
91102
hi = (
92103
v.bump_major()
93104
if v.major != 0 or n < 2
94105
else v.bump_minor()
95106
if v.minor != 0 or n < 3
96107
else v.bump_patch()
108+
if v.patch != 0 or n < 4
109+
else v.bump_prerelease()
97110
)
98111
return Range(lo, hi)
99112

100113
@classmethod
101114
def equality(cls, v):
102115
lo = v
103-
hi = v.bump_patch()
116+
if lo.prerelease is not None:
117+
hi = v.bump_prerelease()
118+
else:
119+
hi = v.bump_patch()
104120
return Range(lo, hi)
105121

106122
@classmethod
@@ -120,7 +136,7 @@ def parse(cls, x):
120136
elif x.startswith("="):
121137
# equality specifier
122138
v, n = _parse_partial_version(x[1:])
123-
if v is not None and n == 3:
139+
if v is not None and n >= 3:
124140
return cls.equality(v)
125141
elif " - " in x:
126142
# range specifier
@@ -140,26 +156,40 @@ def __str__(self):
140156
lo = self.lo
141157
hi = self.hi
142158
if self == Range.equality(lo):
143-
return f"={lo.major}.{lo.minor}.{lo.patch}"
159+
prerelease = f"-{lo.prerelease}" if lo.prerelease else ""
160+
return f"={lo.major}.{lo.minor}.{lo.patch}{prerelease}"
144161
if self == Range.caret(lo, 1):
145162
return f"^{lo.major}"
146163
if self == Range.caret(lo, 2):
147164
return f"^{lo.major}.{lo.minor}"
148165
if self == Range.caret(lo, 3):
149166
return f"^{lo.major}.{lo.minor}.{lo.patch}"
167+
if self == Range.caret(lo, 4):
168+
return f"^{lo.major}.{lo.minor}.{lo.patch}-{lo.prerelease}"
150169
if self == Range.tilde(lo, 1):
151170
return f"~{lo.major}"
152171
if self == Range.tilde(lo, 2):
153172
return f"~{lo.major}.{lo.minor}"
154173
if self == Range.tilde(lo, 3):
155174
return f"~{lo.major}.{lo.minor}.{lo.patch}"
156-
lostr = f"{lo.major}.{lo.minor}.{lo.patch}"
175+
if self == Range.tilde(lo, 4):
176+
return f"~{lo.major}.{lo.minor}.{lo.patch}-{lo.prerelease}"
177+
if lo.prerelease is None:
178+
lostr = f"{lo.major}.{lo.minor}.{lo.patch}"
179+
else:
180+
lostr = f"{lo.major}.{lo.minor}.{lo.patch}-{lo.prerelease}"
181+
hi_str = ""
157182
if hi.major > 0 and hi.minor == 0 and hi.patch == 0:
158183
return f"{lostr} - {hi.major - 1}"
184+
hi_str += f"{hi.major}"
159185
if hi.minor > 0 and hi.patch == 0:
160-
return f"{lostr} - {hi.major}.{hi.minor - 1}"
161-
if hi.patch > 0:
162-
return f"{lostr} - {hi.major}.{hi.minor}.{hi.patch - 1}"
186+
return f"{lostr} - {hi_str}.{hi.minor - 1}"
187+
hi_str += f".{hi.minor}"
188+
if hi.patch > 0 and hi.prerelease is None:
189+
return f"{lostr} - {hi_str}.{hi.patch - 1}"
190+
hi_str += f".{hi.patch}"
191+
if hi.prerelease is not None:
192+
return f"{lostr} - {hi_str}-{self._decrease_string(hi.prerelease)}"
163193
raise ValueError("invalid range")
164194

165195
def __repr__(self):
@@ -180,3 +210,11 @@ def __eq__(self, other):
180210

181211
def is_empty(self):
182212
return not (self.lo < self.hi)
213+
214+
def _decrease_string(self, string):
215+
match = Version._LAST_NUMBER.search(string)
216+
if match:
217+
prev_ = str(int(match.group(1)) - 1)
218+
start, end = match.span(1)
219+
string = string[: max(end - len(prev_), start)] + prev_ + string[end:]
220+
return string

test/test_compat.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class TestRange:
3535
("~0", Range(v("0.0.0"), v("1.0.0"))),
3636
# equality
3737
("=1.2.3", Range(v("1.2.3"), v("1.2.4"))),
38+
("=1.2.3-rc4", Range(v("1.2.3-rc4"), v("1.2.3-rc5"))),
3839
# hyphen
3940
("1.2.3 - 4.5.6", Range(v("1.2.3"), v("4.5.7"))),
4041
("0.2.3 - 4.5.6", Range(v("0.2.3"), v("4.5.7"))),
@@ -65,6 +66,7 @@ def test_parse(self, input, expected_output):
6566
[
6667
(Range(v("0.0.3"), v("0.0.4")), "=0.0.3"),
6768
(Range(v("1.2.3"), v("1.2.4")), "=1.2.3"),
69+
(Range(v("1.2.3-rc4"), v("1.2.3-rc5")), "=1.2.3-rc4"),
6870
(Range(v("1.2.3"), v("2.0.0")), "^1.2.3"),
6971
(Range(v("1.2.0"), v("2.0.0")), "^1.2"),
7072
(Range(v("1.0.0"), v("2.0.0")), "^1"),
@@ -164,6 +166,7 @@ class TestCompat:
164166
[
165167
("", Compat([])),
166168
("1.2.3", Compat([Range(v("1.2.3"), v("2.0.0"))])),
169+
("1.2.3-rc4", Compat([Range(v("1.2.3-rc4"), v("2.0.0"))])),
167170
(
168171
"1, 2.3, 4.5.6",
169172
Compat(
@@ -185,6 +188,8 @@ def test_parse(self, input, expected_output):
185188
[
186189
(Compat([]), ""),
187190
(Compat([Range(v("1.2.3"), v("2.0.0"))]), "^1.2.3"),
191+
(Compat([Range(v("1.2.3-rc4"), v("2.0.0"))]), "^1.2.3-rc4"),
192+
(Compat([Range(v("1.2.2"), v("1.2.3-rc4"))]), "1.2.2 - 1.2.3-rc3"),
188193
(
189194
Compat(
190195
[

0 commit comments

Comments
 (0)