Skip to content

Commit 56a3244

Browse files
author
Dani Pinyol
committed
Support prerelease in version
1 parent febe7d5 commit 56a3244

File tree

2 files changed

+51
-11
lines changed

2 files changed

+51
-11
lines changed

src/juliapkg/compat.py

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,22 @@
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+
def _re_group(inner="", numeric = True, delimiter="."):
7+
capture = _re_digits_g if numeric else ".*"
8+
return f"(?:{delimiter}({capture}){inner})?"
9+
_re_prerelease = _re_group(numeric=False)
10+
_re_optional = _re_group(_re_group(_re_prerelease))
11+
_re_partial_version = re.compile(rf"^({_re_digits_g}){_re_optional}$")
612

713

814
def _parse_partial_version(x):
915
m = _re_partial_version.match(x)
1016
if m is None:
1117
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
18+
major, minor, patch, prerelease = m.groups()
19+
v = Version(major, minor or 0, patch or 0, prerelease)
20+
n = 1 if minor is None else 2 if patch is None else 3 if prerelease is None else 4
1521
return (v, n)
1622

1723

@@ -87,20 +93,26 @@ def caret(cls, v, n):
8793
v.major,
8894
v.minor if n >= 2 else 0,
8995
v.patch if n >= 3 else 0,
96+
v.prerelease if n >=4 else None
9097
)
9198
hi = (
9299
v.bump_major()
93100
if v.major != 0 or n < 2
94101
else v.bump_minor()
95102
if v.minor != 0 or n < 3
96103
else v.bump_patch()
104+
if v.patch != 0 or n < 4
105+
else v.bump_prerelease()
97106
)
98107
return Range(lo, hi)
99108

100109
@classmethod
101110
def equality(cls, v):
102111
lo = v
103-
hi = v.bump_patch()
112+
if lo.prerelease is not None:
113+
hi = v.bump_prerelease()
114+
else:
115+
hi = v.bump_patch()
104116
return Range(lo, hi)
105117

106118
@classmethod
@@ -120,7 +132,7 @@ def parse(cls, x):
120132
elif x.startswith("="):
121133
# equality specifier
122134
v, n = _parse_partial_version(x[1:])
123-
if v is not None and n == 3:
135+
if v is not None and n >= 3:
124136
return cls.equality(v)
125137
elif " - " in x:
126138
# range specifier
@@ -140,26 +152,40 @@ def __str__(self):
140152
lo = self.lo
141153
hi = self.hi
142154
if self == Range.equality(lo):
143-
return f"={lo.major}.{lo.minor}.{lo.patch}"
155+
prerelease = f"-{lo.prerelease}" if lo.prerelease else ""
156+
return f"={lo.major}.{lo.minor}.{lo.patch}{prerelease}"
144157
if self == Range.caret(lo, 1):
145158
return f"^{lo.major}"
146159
if self == Range.caret(lo, 2):
147160
return f"^{lo.major}.{lo.minor}"
148161
if self == Range.caret(lo, 3):
149162
return f"^{lo.major}.{lo.minor}.{lo.patch}"
163+
if self == Range.caret(lo, 4):
164+
return f"^{lo.major}.{lo.minor}.{lo.patch}-{lo.prerelease}"
150165
if self == Range.tilde(lo, 1):
151166
return f"~{lo.major}"
152167
if self == Range.tilde(lo, 2):
153168
return f"~{lo.major}.{lo.minor}"
154169
if self == Range.tilde(lo, 3):
155170
return f"~{lo.major}.{lo.minor}.{lo.patch}"
156-
lostr = f"{lo.major}.{lo.minor}.{lo.patch}"
171+
if self == Range.tilde(lo, 4):
172+
return f"~{lo.major}.{lo.minor}.{lo.patch}-{lo.prerelease}"
173+
if lo.prerelease is None:
174+
lostr = f"{lo.major}.{lo.minor}.{lo.patch}"
175+
else:
176+
lostr = f"{lo.major}.{lo.minor}.{lo.patch}-{lo.prerelease}"
177+
hi_str = ""
157178
if hi.major > 0 and hi.minor == 0 and hi.patch == 0:
158179
return f"{lostr} - {hi.major-1}"
180+
hi_str += f"{hi.major}"
159181
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}"
182+
return f"{lostr} - {hi_str}.{hi.minor-1}"
183+
hi_str += f".{hi.minor}"
184+
if hi.patch > 0 and hi.prerelease is None:
185+
return f"{lostr} - {hi_str}.{hi.patch-1}"
186+
hi_str += f".{hi.patch}"
187+
if hi.prerelease is not None:
188+
return f"{lostr} - {hi_str}-{self._decrease_string(hi.prerelease)}"
163189
raise ValueError("invalid range")
164190

165191
def __repr__(self):
@@ -180,3 +206,11 @@ def __eq__(self, other):
180206

181207
def is_empty(self):
182208
return not (self.lo < self.hi)
209+
210+
def _decrease_string(self, string):
211+
match = Version._LAST_NUMBER.search(string)
212+
if match:
213+
prev_ = str(int(match.group(1)) - 1)
214+
start, end = match.span(1)
215+
string = string[: max(end - len(prev_), start)] + prev_ + string[end:]
216+
return string

test/test_compat.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
23
from juliapkg.compat import Compat, Range, Version
34

45
v = Version.parse
@@ -34,6 +35,7 @@ class TestRange:
3435
("~0", Range(v("0.0.0"), v("1.0.0"))),
3536
# equality
3637
("=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"))),
3739
# hyphen
3840
("1.2.3 - 4.5.6", Range(v("1.2.3"), v("4.5.7"))),
3941
("0.2.3 - 4.5.6", Range(v("0.2.3"), v("4.5.7"))),
@@ -64,6 +66,7 @@ def test_parse(self, input, expected_output):
6466
[
6567
(Range(v("0.0.3"), v("0.0.4")), "=0.0.3"),
6668
(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"),
6770
(Range(v("1.2.3"), v("2.0.0")), "^1.2.3"),
6871
(Range(v("1.2.0"), v("2.0.0")), "^1.2"),
6972
(Range(v("1.0.0"), v("2.0.0")), "^1"),
@@ -163,6 +166,7 @@ class TestCompat:
163166
[
164167
("", Compat([])),
165168
("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"))])),
166170
(
167171
"1, 2.3, 4.5.6",
168172
Compat(
@@ -184,6 +188,8 @@ def test_parse(self, input, expected_output):
184188
[
185189
(Compat([]), ""),
186190
(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"),
187193
(
188194
Compat(
189195
[

0 commit comments

Comments
 (0)