84 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # -*- coding: utf-8 -*-
 | |
| 
 | |
| import re
 | |
| 
 | |
| _REGEX = re.compile('^(?P<major>[0-9]+)'
 | |
|                     '\.(?P<minor>[0-9]+)'
 | |
|                     '\.(?P<patch>[0-9]+)'
 | |
|                     '(\-(?P<prerelease>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?'
 | |
|                     '(\+(?P<build>[0-9A-Za-z]+(\.[0-9A-Za-z]+)*))?$')
 | |
| 
 | |
| if 'cmp' not in __builtins__:
 | |
|     cmp = lambda a,b: (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):
 | |
|         a, b = a or '', b or ''
 | |
|         convert = lambda text: text.isdigit() and int(text) or text.lower()
 | |
|         alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
 | |
|         return cmp(alphanum_key(a), alphanum_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')
 | |
|         build1, build2 = d1.get('build'), d2.get('build')
 | |
|         rccmp = nat_cmp(rc1, rc2)
 | |
|         buildcmp = nat_cmp(build1, build2)
 | |
|         if not (rc1 or rc2):
 | |
|             return buildcmp
 | |
|         elif not rc1:
 | |
|             return 1
 | |
|         elif not rc2:
 | |
|             return -1
 | |
|         return rccmp or buildcmp or 0
 | |
| 
 | |
|     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,),
 | |
|         '>=': (0, 1),
 | |
|         '<=': (-1, 0)
 | |
|     }
 | |
| 
 | |
|     possibilities = possibilities_dict[prefix]
 | |
|     cmp_res = compare(version, match_version)
 | |
| 
 | |
|     return cmp_res in possibilities
 |