123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- """
- Python helper for Semantic Versioning (http://semver.org/)
- """
- import re
- __version__ = '2.6.0'
- __author__ = 'Konstantine Rybnikov'
- __author_email__ = 'k-bx@k-bx.com'
- _REGEX = re.compile('^(?P<major>(?:0|[1-9][0-9]*))'
- '\.(?P<minor>(?:0|[1-9][0-9]*))'
- '\.(?P<patch>(?:0|[1-9][0-9]*))'
- '(\-(?P<prerelease>[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?'
- '(\+(?P<build>[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$')
- _LAST_NUMBER = re.compile(r'(?:[^\d]*(\d+)[^\d]*)+')
- if not hasattr(__builtins__, 'cmp'):
- def cmp(a, b):
- return (a > b) - (a < b)
- def parse(version):
- """
- Parse version to major, minor, patch, pre-release, build parts.
- """
- match = _REGEX.match(version)
- if match is None:
- raise ValueError('%s is not valid SemVer string' % version)
- verinfo = match.groupdict()
- verinfo['major'] = int(verinfo['major'])
- verinfo['minor'] = int(verinfo['minor'])
- verinfo['patch'] = int(verinfo['patch'])
- return verinfo
- def compare(ver1, ver2):
- def nat_cmp(a, b):
- def convert(text):
- return (2, int(text)) if re.match('[0-9]+', text) else (1, text)
- def split_key(key):
- return [convert(c) for c in key.split('.')]
- a, b = a or '', b or ''
- return cmp(split_key(a), split_key(b))
- def compare_by_keys(d1, d2):
- for key in ['major', 'minor', 'patch']:
- v = cmp(d1.get(key), d2.get(key))
- if v:
- return v
- rc1, rc2 = d1.get('prerelease'), d2.get('prerelease')
- rccmp = nat_cmp(rc1, rc2)
- if not rccmp:
- return 0
- if not rc1:
- return 1
- elif not rc2:
- return -1
- return rccmp
- v1, v2 = parse(ver1), parse(ver2)
- return compare_by_keys(v1, v2)
- def match(version, match_expr):
- prefix = match_expr[:2]
- if prefix in ('>=', '<=', '==', '!='):
- match_version = match_expr[2:]
- elif prefix and prefix[0] in ('>', '<'):
- prefix = prefix[0]
- match_version = match_expr[1:]
- else:
- raise ValueError("match_expr parameter should be in format <op><ver>, "
- "where <op> is one of "
- "['<', '>', '==', '<=', '>=', '!=']. "
- "You provided: %r" % match_expr)
- possibilities_dict = {
- '>': (1,),
- '<': (-1,),
- '==': (0,),
- '!=': (-1, 1),
- '>=': (0, 1),
- '<=': (-1, 0)
- }
- possibilities = possibilities_dict[prefix]
- cmp_res = compare(version, match_version)
- return cmp_res in possibilities
- def max_ver(ver1, ver2):
- cmp_res = compare(ver1, ver2)
- if cmp_res == 0 or cmp_res == 1:
- return ver1
- else:
- return ver2
- def min_ver(ver1, ver2):
- cmp_res = compare(ver1, ver2)
- if cmp_res == 0 or cmp_res == -1:
- return ver1
- else:
- return ver2
- def format_version(major, minor, patch, prerelease=None, build=None):
- version = "%d.%d.%d" % (major, minor, patch)
- if prerelease is not None:
- version = version + "-%s" % prerelease
- if build is not None:
- version = version + "+%s" % build
- return version
- def _increment_string(string):
- """
- Look for the last sequence of number(s) in a string and increment, from:
- http://code.activestate.com/recipes/442460-increment-numbers-in-a-string/#c1
- """
- match = _LAST_NUMBER.search(string)
- if match:
- next_ = str(int(match.group(1)) + 1)
- start, end = match.span(1)
- string = string[:max(end - len(next_), start)] + next_ + string[end:]
- return string
- def bump_major(version):
- verinfo = parse(version)
- return format_version(verinfo['major'] + 1, 0, 0)
- def bump_minor(version):
- verinfo = parse(version)
- return format_version(verinfo['major'], verinfo['minor'] + 1, 0)
- def bump_patch(version):
- verinfo = parse(version)
- return format_version(verinfo['major'], verinfo['minor'],
- verinfo['patch'] + 1)
- def bump_prerelease(version):
- verinfo = parse(version)
- verinfo['prerelease'] = _increment_string(verinfo['prerelease'] or 'rc.0')
- return format_version(verinfo['major'], verinfo['minor'], verinfo['patch'],
- verinfo['prerelease'])
- def bump_build(version):
- verinfo = parse(version)
- verinfo['build'] = _increment_string(verinfo['build'] or 'build.0')
- return format_version(verinfo['major'], verinfo['minor'], verinfo['patch'],
- verinfo['prerelease'], verinfo['build'])
|