Andrew Geissler | d1e8949 | 2021-02-12 15:35:20 -0600 | [diff] [blame] | 1 | import collections |
| 2 | import re |
| 3 | import itertools |
| 4 | import functools |
| 5 | |
| 6 | _Version = collections.namedtuple( |
| 7 | "_Version", ["release", "patch_l", "pre_l", "pre_v"] |
| 8 | ) |
| 9 | |
| 10 | @functools.total_ordering |
| 11 | class Version(): |
| 12 | |
| 13 | def __init__(self, version, suffix=None): |
Andrew Geissler | 95ac1b8 | 2021-03-31 14:34:31 -0500 | [diff] [blame] | 14 | |
| 15 | suffixes = ["alphabetical", "patch"] |
| 16 | |
Andrew Geissler | d1e8949 | 2021-02-12 15:35:20 -0600 | [diff] [blame] | 17 | if str(suffix) == "alphabetical": |
| 18 | version_pattern = r"""r?v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<patch>[-_\.]?(?P<patch_l>[a-z]))?(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?""" |
Andrew Geissler | 95ac1b8 | 2021-03-31 14:34:31 -0500 | [diff] [blame] | 19 | elif str(suffix) == "patch": |
| 20 | version_pattern = r"""r?v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<patch>[-_\.]?(p|patch)(?P<patch_l>[0-9]+))?(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?""" |
Andrew Geissler | d1e8949 | 2021-02-12 15:35:20 -0600 | [diff] [blame] | 21 | else: |
| 22 | version_pattern = r"""r?v?(?:(?P<release>[0-9]+(?:[-\.][0-9]+)*)(?P<pre>[-_\.]?(?P<pre_l>(rc|alpha|beta|pre|preview|dev))[-_\.]?(?P<pre_v>[0-9]+)?)?)(.*)?""" |
| 23 | regex = re.compile(r"^\s*" + version_pattern + r"\s*$", re.VERBOSE | re.IGNORECASE) |
| 24 | |
| 25 | match = regex.search(version) |
| 26 | if not match: |
| 27 | raise Exception("Invalid version: '{0}'".format(version)) |
| 28 | |
| 29 | self._version = _Version( |
| 30 | release=tuple(int(i) for i in match.group("release").replace("-",".").split(".")), |
Andrew Geissler | 95ac1b8 | 2021-03-31 14:34:31 -0500 | [diff] [blame] | 31 | patch_l=match.group("patch_l") if str(suffix) in suffixes and match.group("patch_l") else "", |
Andrew Geissler | d1e8949 | 2021-02-12 15:35:20 -0600 | [diff] [blame] | 32 | pre_l=match.group("pre_l"), |
| 33 | pre_v=match.group("pre_v") |
| 34 | ) |
| 35 | |
| 36 | self._key = _cmpkey( |
| 37 | self._version.release, |
| 38 | self._version.patch_l, |
| 39 | self._version.pre_l, |
| 40 | self._version.pre_v |
| 41 | ) |
| 42 | |
| 43 | def __eq__(self, other): |
| 44 | if not isinstance(other, Version): |
| 45 | return NotImplemented |
| 46 | return self._key == other._key |
| 47 | |
| 48 | def __gt__(self, other): |
| 49 | if not isinstance(other, Version): |
| 50 | return NotImplemented |
| 51 | return self._key > other._key |
| 52 | |
| 53 | def _cmpkey(release, patch_l, pre_l, pre_v): |
| 54 | # remove leading 0 |
| 55 | _release = tuple( |
| 56 | reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))) |
| 57 | ) |
| 58 | |
| 59 | _patch = patch_l.upper() |
| 60 | |
| 61 | if pre_l is None and pre_v is None: |
| 62 | _pre = float('inf') |
| 63 | else: |
| 64 | _pre = float(pre_v) if pre_v else float('-inf') |
| 65 | return _release, _patch, _pre |