|
19 | 19 | import ipaddress
|
20 | 20 | import json
|
21 | 21 | import logging
|
| 22 | +import re |
22 | 23 | import ssl
|
23 | 24 | import string
|
24 | 25 | import time
|
@@ -133,39 +134,74 @@ def __init__(self, server_version: str) -> None:
|
133 | 134 | self._major_version: Optional[int] = None
|
134 | 135 | self._minor_version: Optional[int] = None
|
135 | 136 | self._patch_version: Optional[int] = None
|
| 137 | + self._prerelease_version: Optional[str] = None |
| 138 | + self._build_version: Optional[str] = None |
136 | 139 | self._dev_version: Optional[str] = None
|
137 | 140 |
|
138 | 141 | # TODO(@orsinium): use cached_property
|
139 | 142 | def parse_version(self) -> None:
|
140 |
| - v = (self._server_version).split("-") |
141 |
| - if len(v) > 1: |
142 |
| - self._dev_version = v[1] |
143 |
| - tokens = v[0].split(".") |
144 |
| - n = len(tokens) |
145 |
| - if n > 1: |
146 |
| - self._major_version = int(tokens[0]) |
147 |
| - if n > 2: |
148 |
| - self._minor_version = int(tokens[1]) |
149 |
| - if n > 3: |
150 |
| - self._patch_version = int(tokens[2]) |
| 143 | + # https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string |
| 144 | + _SEMVER_REGEX = r""" |
| 145 | + ^ |
| 146 | + (?P<major>0|[1-9]\d*) |
| 147 | + \. |
| 148 | + (?P<minor>0|[1-9]\d*) |
| 149 | + \. |
| 150 | + (?P<patch>0|[1-9]\d*) |
| 151 | + (?:-(?P<prerelease> |
| 152 | + (?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*) |
| 153 | + (?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))* |
| 154 | + ))? |
| 155 | + (?:\+(?P<buildmetadata> |
| 156 | + [0-9a-zA-Z-]+ |
| 157 | + (?:\.[0-9a-zA-Z-]+)* |
| 158 | + ))? |
| 159 | + $ |
| 160 | + """ |
| 161 | + _REGEX = re.compile(_SEMVER_REGEX, re.VERBOSE) |
| 162 | + match = _REGEX.match(self._server_version) |
| 163 | + if match is None: |
| 164 | + raise ValueError( |
| 165 | + f"{self._server_version} is not a valid Semantic Version" |
| 166 | + ) |
| 167 | + matches = match.groupdict() |
| 168 | + |
| 169 | + self._major_version = int(matches["major"]) |
| 170 | + self._minor_version = int(matches["minor"]) |
| 171 | + self._patch_version = int(matches["patch"]) |
| 172 | + self._prerelease_version = matches["prerelease"] or "" |
| 173 | + self._build_version = matches["buildmetadata"] or "" |
| 174 | + self._dev_version = self._prerelease_version + self._build_version |
151 | 175 |
|
152 | 176 | @property
|
153 | 177 | def major(self) -> int:
|
154 | 178 | if not self._major_version:
|
155 | 179 | self.parse_version()
|
156 |
| - return self._major_version or 0 |
| 180 | + return self._major_version |
157 | 181 |
|
158 | 182 | @property
|
159 | 183 | def minor(self) -> int:
|
160 | 184 | if not self._minor_version:
|
161 | 185 | self.parse_version()
|
162 |
| - return self._minor_version or 0 |
| 186 | + return self._minor_version |
163 | 187 |
|
164 | 188 | @property
|
165 | 189 | def patch(self) -> int:
|
166 | 190 | if not self._patch_version:
|
167 | 191 | self.parse_version()
|
168 |
| - return self._patch_version or 0 |
| 192 | + return self._patch_version |
| 193 | + |
| 194 | + @property |
| 195 | + def prerelease(self) -> int: |
| 196 | + if not self._prerelease_version: |
| 197 | + self.parse_version() |
| 198 | + return self._prerelease_version |
| 199 | + |
| 200 | + @property |
| 201 | + def build(self) -> int: |
| 202 | + if not self._build_version: |
| 203 | + self.parse_version() |
| 204 | + return self._build_version |
169 | 205 |
|
170 | 206 | @property
|
171 | 207 | def dev(self) -> str:
|
|
0 commit comments