Source code for pimlico.core.dependencies.versions

# This file is part of Pimlico
# Copyright (C) 2020 Mark Granroth-Wilding
# Licensed under the GNU LGPL v3.0 - https://www.gnu.org/licenses/lgpl-3.0.en.html

from past.builtins import cmp
from builtins import object


[docs]class SoftwareVersion(object): """ Base class for representing version numbers / IDs of software. Different software may use different conventions to represent its versions, so it may be necessary to subclass this class to provide the appropriate parsing and comparison of versions. """ def __init__(self, string_id): self.string_id = string_id def __str__(self): return self.string_id def __eq__(self, other): if self.string_id == "unknown" and other.string_id == "unknown": return True else: return compare_dotted_versions(self.string_id, other.string_id) == 0 def __lt__(self, other): if self.string_id == "unknown": # Any known version is considered later than an unknown version return False elif other.string_id == "unknown": # Any known version is considered later than an unknown version return True else: # Compare the string IDs on the assumption that they're dotted version numbers return compare_dotted_versions(self.string_id, other.string_id) < 0
# Define here, so that it can easily be used symbolically unknown_software_version = SoftwareVersion("unknown")
[docs]def compare_dotted_versions(version0, version1): """ Comparison function for reasonably standard version numbers, with subversions to any level of nesting specified by dots. """ remaining0 = version0 remaining1 = version1 while len(remaining0): if len(remaining1) == 0: # Version 0 has the same prefix, but specifies more subversions, so is a later release return 1 version0_part, __, remaining0 = remaining0.partition(".") version1_part, __, remaining1 = remaining1.partition(".") # Don't distinguish letters by case version0_part, version1_part = version0_part.lower(), version1_part.lower() # Try converting both segments to ints try: version0_part_int = int(version0_part) except ValueError: # Version 0 isn't an int: see whether version 1 is try: int(version1_part) except ValueError: # Neither is an int: first check whether they're identical if version0_part == version1_part: # Continue to next part continue # Otherwise, compare string lexicographically and return result without looking at deeper parts return -1 if version0_part < version1_part else 1 else: # V1 is an int, V0 isn't: int wins return -1 try: version1_part_int = int(version1_part) except ValueError: # V1 isn't an int, but V0 is: int wins return 1 # Both parts are ints if version0_part_int == version1_part_int: # Equal: continue to next level continue else: # Not the same: the one that wins at this level wins the whole thing return -1 if version0_part_int < version1_part_int else 1 if len(remaining1) > 0: # Version 1 has same prefix, but more subversions, so is later return -1 else: # Got to the end of both versions without reaching a conclusion: they must be equal return 0