From 5f6bac501422dd0380d1390361957d765bca0545 Mon Sep 17 00:00:00 2001 From: Ivan Titov Date: Thu, 16 Apr 2020 01:52:47 +0500 Subject: [PATCH] 0.4 beta --- package.setup | 2 +- python2.7libs/package_manager/github.py | 4 +- .../package_manager/new_version_dialog.py | 38 ++++ python2.7libs/package_manager/path_text.py | 4 +- python2.7libs/package_manager/update.py | 16 ++ python2.7libs/package_manager/version.py | 204 ++++++++++++++---- .../package_manager/web_package_content.py | 4 + python2.7libs/pythonrc.py | 5 +- 8 files changed, 225 insertions(+), 52 deletions(-) create mode 100644 python2.7libs/package_manager/new_version_dialog.py create mode 100644 python2.7libs/package_manager/update.py diff --git a/package.setup b/package.setup index af3883a..b335fe0 100644 --- a/package.setup +++ b/package.setup @@ -1,7 +1,7 @@ { "name": "Package Manager", "author": "Ivan Titov", - "version": "0.3-beta", + "version": "0.4-beta", "source": "Houdini-Packages/Houdini-Package-Manager", "source_type": "github" } diff --git a/python2.7libs/package_manager/github.py b/python2.7libs/package_manager/github.py index b73d811..9562e6d 100644 --- a/python2.7libs/package_manager/github.py +++ b/python2.7libs/package_manager/github.py @@ -226,8 +226,8 @@ def installFromGitHubRepo(web_package_or_link, dst_location='$HOUDINI_USER_PREF_ api_releases_url = api_repo_url + '/releases' versions = [] for release_data in GitHubAPICache.get(api_releases_url): - if not release_data['prerelease']: - versions.append(Version(release_data['tag_name'])) + # if not release_data['prerelease']: + versions.append(Version(release_data['tag_name'])) if versions: version_type = 'version' else: diff --git a/python2.7libs/package_manager/new_version_dialog.py b/python2.7libs/package_manager/new_version_dialog.py new file mode 100644 index 0000000..a8f8498 --- /dev/null +++ b/python2.7libs/package_manager/new_version_dialog.py @@ -0,0 +1,38 @@ +try: + from PyQt5.QtWidgets import * + from PyQt5.QtGui import * + from PyQt5.QtCore import * +except ImportError: + from PySide2.QtWidgets import * + from PySide2.QtGui import * + from PySide2.QtCore import * + + +class NewVersionDialog(QDialog): + def __init__(self, parent=None): + super(NewVersionDialog, self).__init__(parent) + + self.setWindowTitle('New version') + + layout = QFormLayout(self) + layout.setContentsMargins(4, 4, 4, 4) + layout.setSpacing(4) + + self.current_version_label = QLabel() + layout.addRow('Current version', self.current_version_label) + + self.next_version_label = QLabel() + layout.addRow('Next version', self.next_version_label) + + self.update_info_label = QLabel() + layout.addRow('Info', self.update_info_label) + + # Data + self.__package = None + + def updateFromCurrentPackage(self): + pass + + @classmethod + def getUserChoice(cls): + pass diff --git a/python2.7libs/package_manager/path_text.py b/python2.7libs/package_manager/path_text.py index 572dc8d..fcabd69 100644 --- a/python2.7libs/package_manager/path_text.py +++ b/python2.7libs/package_manager/path_text.py @@ -15,8 +15,8 @@ def truncateMid(value, length): return '…' mid = (length - 1) / 2 - pre = value[:math.floor(mid)] - post = value[len(value) - math.ceil(mid):] + pre = value[:int(mid)] + post = value[int(len(value) - math.ceil(mid)):] return '{}…{}'.format(pre, post) diff --git a/python2.7libs/package_manager/update.py b/python2.7libs/package_manager/update.py new file mode 100644 index 0000000..e945bae --- /dev/null +++ b/python2.7libs/package_manager/update.py @@ -0,0 +1,16 @@ +from .local_package import findInstalledPackages +from .github import installFromGitHubRepo +from .new_version_dialog import NewVersionDialog + + +def checkForUpdates(): + dialog = NewVersionDialog() + packages = [] + for package in findInstalledPackages(): + if package.source and package.version: + if package.source_type == 'github': + if package.hasUpdates(): + packages.append(package) + if packages: + dialog.setPackageList(packages) + dialog.exec_() diff --git a/python2.7libs/package_manager/version.py b/python2.7libs/package_manager/version.py index 0245d7a..da83b77 100644 --- a/python2.7libs/package_manager/version.py +++ b/python2.7libs/package_manager/version.py @@ -9,11 +9,14 @@ def __new__(cls, source): return super(Token, cls).__new__(cls) def __init__(self, source): - self.__raw = str(source) + if isinstance(source, Token): + return + + self.__raw = source if source.isdigit(): self.__value = int(source) else: # source.isalpha() - self.__value = str(source) + self.__value = str(source).strip().lower() @property def raw(self): @@ -23,39 +26,129 @@ def raw(self): def value(self): return self.__value + def __repr__(self): + return 'Token("{0}")'.format(self.raw) + + def __str__(self): + return self.__raw + def __eq__(self, other): if isinstance(other, Token) and isinstance(other.value, int): return self.value == other.value - elif isinstance(self.value, int) and isinstance(other, int): + elif isinstance(other, int) and isinstance(self.value, int): return self.value == other - elif isinstance(other, Token) and isinstance(other.value, basestring): - pass # Todo - else: - return NotImplemented + elif isinstance(self.value, basestring): + if isinstance(other, Token) and isinstance(other.value, basestring) \ + or isinstance(other, basestring): + other = Token(other) + return self.value == other.value + return NotImplemented def __ne__(self, other): if isinstance(other, Token) and isinstance(other.value, int): return self.value != other.value elif isinstance(self.value, int) and isinstance(other, int): return self.value != other - else: - return NotImplemented + elif isinstance(self.value, basestring): + if isinstance(other, Token) and isinstance(other.value, basestring) \ + or isinstance(other, basestring): + other = Token(other) + return self.value != other.value + return NotImplemented def __lt__(self, other): if isinstance(other, Token) and isinstance(other.value, int): return self.value < other.value elif isinstance(self.value, int) and isinstance(other, int): return self.value < other - else: - return NotImplemented + elif isinstance(self.value, basestring): + if isinstance(other, Token) and isinstance(other.value, basestring) \ + or isinstance(other, basestring): + other = Token(other) + self_len = len(self.value) + other_len = len(other.value) + for i in range(min(self_len, other_len)): + self_char = self.value[i] + other_char = other.value[i] + if self_char < other_char: + return True + return False + return NotImplemented def __gt__(self, other): if isinstance(other, Token) and isinstance(other.value, int): return self.value > other.value elif isinstance(self.value, int) and isinstance(other, int): return self.value > other + elif isinstance(self.value, basestring): + if isinstance(other, Token) and isinstance(other.value, basestring) \ + or isinstance(other, basestring): + other = Token(other) + self_len = len(self.value) + other_len = len(other.value) + for i in range(min(self_len, other_len)): + self_char = self.value[i] + other_char = other.value[i] + if self_char > other_char: + return True + return False + return NotImplemented + + +def parseVersion(version_string): + """Returns ((), (), )""" + # Find end of the redundant characters at the beginning + start_index = -1 + for index, char in enumerate(version_string): + if char.isdigit(): + start_index = index + break + + if start_index == -1: + return + # Cut redundant characters at the beginning + version_string = version_string[start_index:] + + # Get build metadata substring and cut it + try: + plus_index = version_string.index('+') + build_metadata = version_string[plus_index + 1:].strip() + version_string = version_string[:plus_index] + except ValueError: + build_metadata = '' + + # Get qualifier substring and cut it + try: + hyphen_index = version_string.index('-') + qualifier_string = version_string[hyphen_index + 1:] + version_string = version_string[:hyphen_index] + except ValueError: + qualifier_string = '' + + num_tokens = [] + buffer = '' + for char in version_string: + if char.isdigit(): + buffer += char else: - return NotImplemented + num_tokens.append(Token(buffer)) + buffer = '' + if buffer: + num_tokens.append(Token(buffer)) + + qualifier_tokens = [] + if qualifier_string: + buffer = '' + for char in qualifier_string: + if char.isalpha() or char.isdigit(): + buffer += char + else: + qualifier_tokens.append(Token(buffer)) + buffer = '' + if buffer: + qualifier_tokens.append(Token(buffer)) + + return tuple(num_tokens), tuple(qualifier_tokens), build_metadata class Version(object): @@ -66,28 +159,36 @@ def __new__(cls, source): return super(Version, cls).__new__(cls) def __init__(self, source): - self.__raw = str(source) - try: # Ignoring build metadata - source = self.__raw[:source.index('+')] - except (ValueError, AttributeError): - source = self.__raw - self.__tokens = tuple(map(lambda pair: Token(pair[1]), - re.findall(r'(^\D)?(\d+)',source))) # |\w+ + if isinstance(source, Version): + return + + self.__raw = source + self.__num_tokens, self.__qualifier_tokens, _ = parseVersion(source) first_nonzero_index = -1 - for index, token in enumerate(reversed(self.__tokens), 0): + for index, token in enumerate(reversed(self.__num_tokens), 0): if token != 0: first_nonzero_index = index break if first_nonzero_index > 0: - self.__tokens = self.__tokens[:-first_nonzero_index] + self.__num_tokens = self.__num_tokens[:-first_nonzero_index] + + self.__is_stable = bool(self.__qualifier_tokens) @property def raw(self): return self.__raw @property - def tokens(self): - return self.__tokens + def num_tokens(self): + return self.__num_tokens + + @property + def qualifier_tokens(self): + return self.__qualifier_tokens + + @property + def is_stable(self): + return self.__is_stable def __repr__(self): return 'Version("{}")'.format(self.__raw) @@ -98,23 +199,25 @@ def __str__(self): def __eq__(self, other): if isinstance(other, (basestring, Version)): other = Version(other) - return self.tokens == other.tokens + return self.num_tokens == other.num_tokens and \ + self.qualifier_tokens == other.qualifier_tokens else: return NotImplemented def __ne__(self, other): other = Version(other) - return self.tokens != other.tokens + return self.num_tokens != other.num_tokens or \ + self.qualifier_tokens != other.qualifier_tokens def __lt__(self, other): other = Version(other) - self_len = len(self.__tokens) - other_len = len(other.tokens) - other_tokens = other.tokens + self_len = len(self.__num_tokens) + other_len = len(other.num_tokens) + other_tokens = other.num_tokens if self == other: return False for i in range(min(self_len, other_len)): - self_value = self.__tokens[i] + self_value = self.__num_tokens[i] other_value = other_tokens[i] if self_value == other_value: continue @@ -124,18 +227,18 @@ def __lt__(self, other): return False if self_len < other_len: return True - else: + elif self_len > other_len: return False def __gt__(self, other): other = Version(other) - self_len = len(self.__tokens) - other_len = len(other.tokens) - other_tokens = other.tokens + self_len = len(self.__num_tokens) + other_len = len(other.num_tokens) + other_tokens = other.num_tokens if self == other: return False for i in range(min(self_len, other_len)): - self_value = self.__tokens[i] + self_value = self.__num_tokens[i] other_value = other_tokens[i] if self_value == other_value: continue @@ -145,8 +248,24 @@ def __gt__(self, other): return False if self_len > other_len: return True - else: + elif self_len < other_len: + return False + + self_len = len(self.__qualifier_tokens) + other_len = len(other.qualifier_tokens) + other_tokens = other.qualifier_tokens + if self_len < other_len: + return True + elif self_len > other_len: return False + for i in range(min(self_len, other_len)): + self_value = self.__qualifier_tokens[i] + other_value = other_tokens[i] + if self_value == other_value: + continue + elif self_value > other_value: + return True + return False def __le__(self, other): other = Version(other) @@ -156,15 +275,6 @@ def __ge__(self, other): other = Version(other) return self == other or self > other - def increment(self, component): - pass - - def __add__(self, other): - pass - - def __iadd__(self, other): - pass - class VersionRange(object): def __init__(self, low_version=None, high_version=None): @@ -255,9 +365,13 @@ def __eq__(self, other): raise TypeError -if __name__ == '__main__': +if False: assert Version('2.7') < '3.3' assert Version('3.3.0') == '3.3' assert Version('6') < Version('10') assert '10.2.305' in VersionRange.fromPattern('6-10.3') assert '18.5' in VersionPattern('18+') + assert Version('0.3-beta') == Version('0.3.0-beta') + assert Version('0.4-beta') > Version('0.4-alpha') + assert Version('0.4-beta.alpha') < Version('0.4-alpha') + print('All ok') diff --git a/python2.7libs/package_manager/web_package_content.py b/python2.7libs/package_manager/web_package_content.py index a243d9b..a40a77b 100644 --- a/python2.7libs/package_manager/web_package_content.py +++ b/python2.7libs/package_manager/web_package_content.py @@ -9,6 +9,8 @@ from PySide2.QtGui import * from PySide2.QtCore import * +import hou + from .link_label import LinkLabel from .github import ownerAndRepoName, repoURL, installFromGitHubRepo from .web_package import WebPackage @@ -107,4 +109,6 @@ def _onInstall(self): installFromGitHubRepo(self.web_package) self.web_package = None self.updateFromCurrentPackage() + hou.ui.setStatusMessage('Successfully installed', + hou.severityType.ImportantMessage) self.installed.emit() diff --git a/python2.7libs/pythonrc.py b/python2.7libs/pythonrc.py index 363f1e0..fd9325c 100644 --- a/python2.7libs/pythonrc.py +++ b/python2.7libs/pythonrc.py @@ -1,5 +1,6 @@ if hou.isUIAvailable(): import hdefereval - from package_manager.github import checkUpdates - hdefereval.executeDeferred(checkUpdates) + from package_manager.update import checkForUpdates + + hdefereval.executeDeferred(checkForUpdates)