diff options
Diffstat (limited to 'packaging/release/versionhelper/version_helper.py')
-rw-r--r-- | packaging/release/versionhelper/version_helper.py | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/packaging/release/versionhelper/version_helper.py b/packaging/release/versionhelper/version_helper.py new file mode 100644 index 00000000..163494b6 --- /dev/null +++ b/packaging/release/versionhelper/version_helper.py @@ -0,0 +1,195 @@ +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +import argparse +import os +import re +import sys + +from packaging.version import Version, VERSION_PATTERN + + +class AnsibleVersionMunger(object): + tag_offsets = dict( + dev=0, + a=100, + b=200, + rc=1000 + ) + + # TODO: allow overrides here for packaging bump etc + def __init__(self, raw_version, revision=None, codename=None): + self._raw_version = raw_version + self._revision = revision + self._parsed_version = Version(raw_version) + self._codename = codename + self._parsed_regex_match = re.match(VERSION_PATTERN, raw_version, re.VERBOSE | re.IGNORECASE) + + @property + def deb_version(self): + v = self._parsed_version + + match = self._parsed_regex_match + + # treat dev/post as prerelease for now; treat dev/post as equivalent and disallow together + if v.is_prerelease or match.group('dev') or match.group('post'): + if match.group('dev') and match.group('post'): + raise Exception("dev and post may not currently be used together") + if match.group('pre'): + tag_value = match.group('pre') + tag_type = match.group('pre_l') + if match.group('dev'): + tag_value += ('~%s' % match.group('dev').strip('.')) + if match.group('post'): + tag_value += ('~%s' % match.group('post').strip('.')) + elif match.group('dev'): + tag_type = "dev" + tag_value = match.group('dev').strip('.') + elif match.group('post'): + tag_type = "dev" + tag_value = match.group('post').strip('.') + else: + raise Exception("unknown prerelease type for version {0}".format(self._raw_version)) + else: + tag_type = None + tag_value = '' + + # not a pre/post/dev release, just return base version + if not tag_type: + return '{base_version}'.format(base_version=self.base_version) + + # it is a pre/dev release, include the tag value with a ~ + return '{base_version}~{tag_value}'.format(base_version=self.base_version, tag_value=tag_value) + + @property + def deb_release(self): + return '1' if self._revision is None else str(self._revision) + + @property + def rpm_release(self): + v = self._parsed_version + match = self._parsed_regex_match + + # treat presence of dev/post as prerelease for now; treat dev/post the same and disallow together + if v.is_prerelease or match.group('dev') or match.group('post'): + if match.group('dev') and match.group('post'): + raise Exception("dev and post may not currently be used together") + if match.group('pre'): + tag_value = match.group('pre') + tag_type = match.group('pre_l') + tag_ver = match.group('pre_n') + if match.group('dev'): + tag_value += match.group('dev') + if match.group('post'): + tag_value += match.group('post') + elif match.group('dev'): + tag_type = "dev" + tag_value = match.group('dev') + tag_ver = match.group('dev_n') + elif match.group('post'): + tag_type = "dev" + tag_value = match.group('post') + tag_ver = match.group('post_n') + else: + raise Exception("unknown prerelease type for version {0}".format(self._raw_version)) + else: + tag_type = None + tag_value = '' + tag_ver = 0 + + # not a pre/post/dev release, just append revision (default 1) + if not tag_type: + if self._revision is None: + self._revision = 1 + return '{revision}'.format(revision=self._revision) + + # cleanse tag value in case it starts with . + tag_value = tag_value.strip('.') + + # coerce to int and None == 0 + tag_ver = int(tag_ver if tag_ver else 0) + + if self._revision is None: + tag_offset = self.tag_offsets.get(tag_type) + if tag_offset is None: + raise Exception('no tag offset defined for tag {0}'.format(tag_type)) + pkgrel = '0.{0}'.format(tag_offset + tag_ver) + else: + pkgrel = self._revision + + return '{pkgrel}.{tag_value}'.format(pkgrel=pkgrel, tag_value=tag_value) + + @property + def raw(self): + return self._raw_version + + # return the x.y.z version without any other modifiers present + @property + def base_version(self): + return self._parsed_version.base_version + + # return the x.y version without any other modifiers present + @property + def major_version(self): + return re.match(r'^(\d+.\d+)', self._raw_version).group(1) + + @property + def codename(self): + return self._codename if self._codename else "UNKNOWN" + + +def main(): + parser = argparse.ArgumentParser(description='Extract/transform Ansible versions to various packaging formats') + + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument('--raw', action='store_true') + group.add_argument('--majorversion', action='store_true') + group.add_argument('--baseversion', action='store_true') + group.add_argument('--debversion', action='store_true') + group.add_argument('--debrelease', action='store_true') + group.add_argument('--rpmrelease', action='store_true') + group.add_argument('--codename', action='store_true') + group.add_argument('--all', action='store_true') + + parser.add_argument('--revision', action='store', default='auto') + + args = parser.parse_args() + + mydir = os.path.dirname(__file__) + release_loc = os.path.normpath(mydir + '/../../../lib') + + sys.path.insert(0, release_loc) + + from ansible import release + + rev = None + if args.revision != 'auto': + rev = args.revision + + v_raw = release.__version__ + codename = release.__codename__ + v = AnsibleVersionMunger(v_raw, revision=rev, codename=codename) + + if args.raw: + print(v.raw) + elif args.baseversion: + print(v.base_version) + elif args.majorversion: + print(v.major_version) + elif args.debversion: + print(v.deb_version) + elif args.debrelease: + print(v.deb_release) + elif args.rpmrelease: + print(v.rpm_release) + elif args.codename: + print(v.codename) + elif args.all: + props = [name for (name, impl) in vars(AnsibleVersionMunger).items() if isinstance(impl, property)] + + for propname in props: + print('{0}: {1}'.format(propname, getattr(v, propname))) + + +if __name__ == '__main__': + main() |