# Copyright (c) 2013, 2017 Citrix Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""version - version comparison methods"""
[docs]
class Version(object):
def __init__(self, ver, build = None):
self.ver = ver
self.build = build
[docs]
@staticmethod
def intify(x):
if x.isdigit():
return int(x)
return x
[docs]
@classmethod
def from_string(cls, ver_str):
""" Create an object instance from a string conforming to:
p.q. ... y.z[-b]
where:
p.q. ... y.z are integer arcs
b is a build identifier"""
build = None
if '-' in ver_str:
ver_str, build = ver_str.split('-', 1)
ver = [cls.intify(i) for i in ver_str.split('.')]
return cls(ver, build)
[docs]
def ver_as_string(self):
return '.'.join(map(str, self.ver))
[docs]
def build_as_string(self):
return self.build if self.build else ''
def __str__(self):
build = self.build_as_string()
if build != '':
return self.ver_as_string() + '-' + build
return self.ver_as_string()
#************************************************************
#
# NOTE: Comparisons are performed as follows
#
# The version is always compared.
#
# Build identifiers are ignored.
#
#************************************************************
[docs]
@classmethod
def arc_cmp(cls, l, r):
# type:(int, int) -> int
return l - r
[docs]
@classmethod
def ver_cmp(cls, l, r):
# type:(list[int], list[int]) -> int
assert isinstance(l, list) and isinstance(r, list)
# iterate over arcs in turn, zip() returns min(len(l), len(r)) tuples
for la, ra in zip(l, r):
ret = cls.arc_cmp(la, ra)
if ret != 0:
return ret
# equal to this point, down to list length
return (len(l) - len(r))
def __eq__(self, v):
return self.ver_cmp(self.ver, v.ver) == 0
# The Python3 datamodel requires to implement __hash__ when __eq__
# is implemented:
# https://docs.python.org/3/reference/datamodel.html#object.__hash__
# Example:https://github.com/swagger-api/swagger-codegen/issues/6475
# Python2 pylint --py3k warns about it, and Pylint3 without .pylintrc
# now too:
def __hash__(self): # type:() -> int
return hash(str(self.ver))
def __ne__(self, v):
return self.ver_cmp(self.ver, v.ver) != 0
def __lt__(self, v):
return self.ver_cmp(self.ver, v.ver) < 0
def __gt__(self, v):
return self.ver_cmp(self.ver, v.ver) > 0
def __le__(self, v):
return self.ver_cmp(self.ver, v.ver) <= 0
def __ge__(self, v):
return self.ver_cmp(self.ver, v.ver) >= 0