Source code for hal.cvs.versioning

#!/usr/bin/env python
# coding: utf-8


"""Models to version stuff"""

from abc import abstractmethod

from hal.data.linked_list import LinkedList


[docs]class VersionNumber: """Version"""
[docs] @abstractmethod def get_current_amount(self): """Gets current set amount :return: Current set amount """ pass
[docs] def can_increase(self, amount): """Checks iff can increase by such amount :param amount: Amount to increase :return: True iff this number can be increased by such amount """ return amount <= self.max_amount_allowed()
[docs] @abstractmethod def increase(self, amount=1): """Increase version by this amount :param amount: Increase number by this amount :return: True iff increase was successful """ pass
[docs] @abstractmethod def maximize(self): """Maximizes this version""" pass
[docs] @abstractmethod def reset(self): """Zeroes this number""" pass
[docs] @abstractmethod def max_amount_allowed(self): """Calculates number of increases available :return: Number of increases that can be done before reaching """ pass
[docs] @abstractmethod def max(self): """Calculates max increases :return: Number of increases that can be done before reaching """ pass
[docs]class Level(VersionNumber): """Level of version number""" def __init__(self, max_inner, start=0): """ :param max_inner: Max number of this level. If you set to 0 this level will increase never :param start: Start at this number """ self.max_inner = max_inner self.current = start def __str__(self): return str(self.current)
[docs] def get_current_amount(self): return self.current
[docs] def increase(self, amount=1): if self.can_increase(amount): self.current += amount return True return False
[docs] def maximize(self): self.current = self.max_inner
[docs] def reset(self): self.current = 0
[docs] def max_amount_allowed(self): return self.max_inner - self.current
[docs] def max(self): return self.max_inner
[docs]class Subsystem(VersionNumber): """List of levels of version system""" def __init__(self, levels, separator="."): """ :param levels: Levels in order of importance (from left to right the importance increases). The version number is the reversed :param separator: Compose version number separating with this split """ self.levels = LinkedList(levels) self.current = self.max() - self.max_amount_allowed() # inverse self.split = separator def __str__(self): out = [ str(val) for val in self.levels.to_lst() ] out = self.split.join(reversed(out)) # reverse according importance return out
[docs] def get_current_amount(self): return self.current
[docs] def reset(self): node = self.levels.head while node is not None: node.val.reset() node = node.next_node
[docs] def increase(self, amount=1): if self.levels.head.val.increase(amount): return True # head cannot increase -> reset and check for carry amount_left = amount - self.levels.head.val.max_amount_allowed() - 1 self.levels.head.val.reset() node = self.levels.head.next_node carried = False while node is not None and not carried: if node.val.increase(): carried = True else: node.val.reset() node = node.next_node if not carried: # can't broadcast carry to last level return False return self.increase(amount_left)
[docs] def maximize(self): node = self.levels.head while node is not None: node.val.maximize() node = node.next_node
[docs] def max_amount_allowed(self): amount_allowed = self.levels.head.val.max_amount_allowed() multiplier = self.levels.head.val.max() node = self.levels.head.next_node while node is not None: amount_allowed += (node.val.max_amount_allowed() - 1) * multiplier multiplier *= node.val.max_inner node = node.next_node return amount_allowed
[docs] def max(self): multiplier = 1 node = self.levels.head while node is not None: multiplier *= node.val.max() node = node.next_node return multiplier
[docs]class Version(VersionNumber): """Version""" def __init__(self, start="0.0.0", max_number=9, separator="."): """ :param start: Current version :param max_number: Max number reachable by sub-versions numbers :param separator: Compose version number separating with this split """ self.version = Version.from_str(start, max_number, separator) def __str__(self): return str(self.version)
[docs] def get_current_amount(self): return self.version.get_current_amount()
[docs] def reset(self): return self.version.reset()
[docs] def max_amount_allowed(self): return self.version.max_amount_allowed()
[docs] def increase(self, amount=1): """ :param amount: """ return self.version.increase(amount)
[docs] def increase_by_changes(self, changes_amount, ratio): """Increase version by amount of changes :param changes_amount: Number of changes done :param ratio: Ratio changes :return: Increases version accordingly to changes """ increases = round(changes_amount * ratio) return self.increase(int(increases))
[docs] def maximize(self): return self.version.maximize()
[docs] def max(self): return self.version.max()
[docs] @staticmethod def from_str(string, max_number=9, separator="."): """Parses string :param string: Version :param max_number: Max number reachable by sub :param separator: Version numbers are separated with this split :return: Parses string and returns object """ tokens = string.split(separator) tokens = list(reversed(tokens)) # reverse order of importance most_important = tokens[-1] # cannot be parsed like the others levels = [ Level(max_number, int(token)) for token in tokens[:-1] ] levels.append( Level(float("inf"), int(most_important)) ) return Subsystem(levels, separator)