bumpver/src/pycalver/version.py

167 lines
4.4 KiB
Python
Raw Normal View History

2018-09-02 21:48:12 +02:00
# This file is part of the pycalver project
# https://github.com/mbarkhau/pycalver
#
2018-11-06 21:45:33 +01:00
# Copyright (c) 2018 Manuel Barkhau (@mbarkhau) - MIT License
2018-09-02 21:48:12 +02:00
# SPDX-License-Identifier: MIT
2018-12-09 14:49:13 +01:00
"""Functions related to version string manipulation.
2018-09-02 21:48:12 +02:00
2018-12-09 14:49:13 +01:00
>>> version_info = PYCALVER_RE.match("v201712.0123-alpha").groupdict()
>>> assert version_info == {
... "version" : "v201712.0123-alpha",
... "calver" : "v201712",
... "year" : "2017",
... "month" : "12",
... "build" : ".0123",
... "build_no" : "0123",
... "release" : "-alpha",
... "release_tag" : "alpha",
2018-12-09 14:49:13 +01:00
... }
>>>
>>> version_info = PYCALVER_RE.match("v201712.0033").groupdict()
>>> assert version_info == {
... "version" : "v201712.0033",
... "calver" : "v201712",
... "year" : "2017",
... "month" : "12",
... "build" : ".0033",
... "build_no" : "0033",
... "release" : None,
... "release_tag": None,
2018-12-09 14:49:13 +01:00
... }
"""
import re
2018-09-02 21:48:12 +02:00
import logging
import pkg_resources
2018-09-04 09:56:53 +02:00
import typing as typ
2018-09-02 21:48:12 +02:00
import datetime as dt
from . import lex_id
2018-09-02 23:36:57 +02:00
2018-09-02 21:48:12 +02:00
log = logging.getLogger("pycalver.version")
2018-12-09 14:49:13 +01:00
# https://regex101.com/r/fnj60p/10
PYCALVER_PATTERN = r"""
\b
(?P<version>
(?P<calver>
v # "v" version prefix
(?P<year>\d{4})
(?P<month>\d{2})
)
(?P<build>
\. # "." build nr prefix
(?P<build_no>\d{4,})
2018-12-09 14:49:13 +01:00
)
(?P<release>
\- # "-" release prefix
(?P<release_tag>alpha|beta|dev|rc|post)
2018-12-09 14:49:13 +01:00
)?
)(?:\s|$)
"""
PYCALVER_RE: typ.Pattern[str] = re.compile(PYCALVER_PATTERN, flags=re.VERBOSE)
class VersionInfo(typ.NamedTuple):
"""Container for parsed version string."""
version : str
pep440_version: str
calver : str
year : str
month : str
build : str
build_no : str
2018-12-09 14:49:13 +01:00
release : typ.Optional[str]
release_tag : typ.Optional[str]
2018-12-09 14:49:13 +01:00
def parse_version_info(version_str: str) -> VersionInfo:
"""Parse a PyCalVer string.
>>> vnfo = parse_version_info("v201712.0033-beta")
>>> assert vnfo == VersionInfo(
... version ="v201712.0033-beta",
2018-12-09 14:49:13 +01:00
... pep440_version="201712.33b0",
... calver ="v201712",
... year ="2017",
... month ="12",
... build =".0033",
... build_no ="0033",
... release ="-beta",
... release_tag ="beta",
2018-12-09 14:49:13 +01:00
... )
"""
match = PYCALVER_RE.match(version_str)
if match is None:
raise ValueError(f"Invalid PyCalVer string: {version_str}")
kwargs = match.groupdict()
kwargs['pep440_version'] = pycalver_to_pep440(kwargs['version'])
if kwargs['release'] is None:
kwargs['release'] = "-final"
if kwargs['release_tag'] is None:
kwargs['release_tag'] = "final"
2018-12-09 14:49:13 +01:00
return VersionInfo(**kwargs)
2018-09-02 21:48:12 +02:00
def current_calver() -> str:
2018-11-06 21:45:33 +01:00
"""Generate calver version string based on current date.
example result: "v201812"
"""
2018-09-03 22:23:51 +02:00
return dt.date.today().strftime("v%Y%m")
2018-09-02 21:48:12 +02:00
2018-11-06 21:45:33 +01:00
def incr(old_version: str, *, release: str = None) -> str:
"""Increment a full PyCalVer version string.
Old_version is assumed to be a valid calver string,
already validated in pycalver.config.parse.
"""
2018-12-09 14:49:13 +01:00
old_ver = parse_version_info(old_version)
2018-09-02 21:48:12 +02:00
new_calver = current_calver()
2018-09-03 22:23:51 +02:00
if old_ver.calver > new_calver:
log.warning(
2018-11-06 21:45:33 +01:00
f"'version.incr' called with '{old_version}', "
2018-11-04 21:11:42 +01:00
+ f"which is from the future, "
+ f"maybe your system clock is out of sync."
2018-09-03 22:23:51 +02:00
)
# leave calver as is (don't go back in time)
new_calver = old_ver.calver
2018-09-02 23:36:57 +02:00
new_build = lex_id.next_id(old_ver.build[1:])
2018-09-04 09:56:53 +02:00
new_release: typ.Optional[str] = None
2018-09-02 21:48:12 +02:00
if release is None:
2018-09-02 23:36:57 +02:00
if old_ver.release:
# preserve existing release
new_release = old_ver.release[1:]
else:
new_release = None
2018-11-04 21:11:42 +01:00
elif release == 'final':
2018-09-03 22:23:51 +02:00
new_release = None
2018-09-02 21:48:12 +02:00
else:
new_release = release
if new_release == 'final':
new_release = None
2018-09-02 21:48:12 +02:00
new_version = new_calver + "." + new_build
if new_release:
new_version += "-" + new_release
return new_version
def pycalver_to_pep440(version: str) -> str:
"""Derive pep440 compliant version string from PyCalVer version string.
>>> pycalver_to_pep440("v201811.0007-beta")
'201811.7b0'
"""
return str(pkg_resources.parse_version(version))