mirror of
https://github.com/fergalmoran/picard.git
synced 2026-02-23 16:15:02 +00:00
PICARD-1045: Add program update checking
This commit is contained in:
@@ -97,6 +97,8 @@ from picard.ui.searchdialog.album import AlbumSearchDialog
|
||||
from picard.ui.searchdialog.artist import ArtistSearchDialog
|
||||
from picard.ui.searchdialog.track import TrackSearchDialog
|
||||
|
||||
from picard.util.checkupdate import UpdateCheckManager
|
||||
|
||||
|
||||
# A "fix" for https://bugs.python.org/issue1438480
|
||||
def _patched_shutil_copystat(src, dst, *, follow_symlinks=True):
|
||||
@@ -244,6 +246,9 @@ class Tagger(QtWidgets.QApplication):
|
||||
self.exit_cleanup = []
|
||||
self.stopping = False
|
||||
|
||||
# Load release version information
|
||||
self.updatecheckmanager = UpdateCheckManager()
|
||||
|
||||
def register_cleanup(self, func):
|
||||
self.exit_cleanup.append(func)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
from collections import OrderedDict
|
||||
import datetime
|
||||
from functools import partial
|
||||
import os.path
|
||||
|
||||
@@ -174,6 +175,9 @@ class MainWindow(QtWidgets.QMainWindow, PreserveGeometry):
|
||||
def show(self):
|
||||
self.restoreWindowState()
|
||||
super().show()
|
||||
if config.setting['check_for_updates'] and datetime.date.today().toordinal() >= config.persist['last_update_check'] + config.setting['update_check_days']:
|
||||
log.debug(_("Initiating start-up check for program updates."))
|
||||
self.tagger.updatecheckmanager.check_update(show_always=False, update_level='dev' if config.setting["include_beta_versions"] else 'final')
|
||||
self.metadata_box.restore_state()
|
||||
|
||||
def closeEvent(self, event):
|
||||
@@ -535,6 +539,9 @@ class MainWindow(QtWidgets.QMainWindow, PreserveGeometry):
|
||||
self.open_folder_action.setEnabled(False)
|
||||
self.open_folder_action.triggered.connect(self.open_folder)
|
||||
|
||||
self.check_update_action = QtWidgets.QAction(_("&Check for Update"), self)
|
||||
self.check_update_action.triggered.connect(self.check_for_update)
|
||||
|
||||
def toggle_rename_files(self, checked):
|
||||
config.setting["rename_files"] = checked
|
||||
|
||||
@@ -608,6 +615,8 @@ class MainWindow(QtWidgets.QMainWindow, PreserveGeometry):
|
||||
menu.addSeparator()
|
||||
menu.addAction(self.view_history_action)
|
||||
menu.addSeparator()
|
||||
menu.addAction(self.check_update_action)
|
||||
menu.addSeparator()
|
||||
menu.addAction(self.support_forum_action)
|
||||
menu.addAction(self.report_bug_action)
|
||||
menu.addAction(self.view_log_action)
|
||||
@@ -1087,3 +1096,6 @@ class MainWindow(QtWidgets.QMainWindow, PreserveGeometry):
|
||||
target = selected_objects[0]
|
||||
self.tagger.paste_files(target)
|
||||
self.paste_action.setEnabled(False)
|
||||
|
||||
def check_for_update(self):
|
||||
self.tagger.updatecheckmanager.check_update(show_always=True, update_level='dev' if config.setting["include_beta_versions"] else 'final')
|
||||
|
||||
@@ -50,6 +50,10 @@ class GeneralOptionsPage(OptionsPage):
|
||||
config.TextOption("persist", "oauth_access_token", ""),
|
||||
config.IntOption("persist", "oauth_access_token_expires", 0),
|
||||
config.TextOption("persist", "oauth_username", ""),
|
||||
config.BoolOption("setting", "check_for_updates", False),
|
||||
config.BoolOption("setting", "include_beta_versions", False),
|
||||
config.IntOption("setting", "update_check_days", 0),
|
||||
config.IntOption("persist", "last_update_check", 0),
|
||||
]
|
||||
|
||||
def __init__(self, parent=None):
|
||||
@@ -66,12 +70,18 @@ class GeneralOptionsPage(OptionsPage):
|
||||
self.ui.server_port.setValue(config.setting["server_port"])
|
||||
self.ui.analyze_new_files.setChecked(config.setting["analyze_new_files"])
|
||||
self.ui.ignore_file_mbids.setChecked(config.setting["ignore_file_mbids"])
|
||||
self.ui.check_for_updates.setChecked(config.setting["check_for_updates"])
|
||||
self.ui.include_beta_versions.setChecked(config.setting["include_beta_versions"])
|
||||
self.ui.update_check_days.setValue(config.setting["update_check_days"])
|
||||
|
||||
def save(self):
|
||||
config.setting["server_host"] = self.ui.server_host.currentText().strip()
|
||||
config.setting["server_port"] = self.ui.server_port.value()
|
||||
config.setting["analyze_new_files"] = self.ui.analyze_new_files.isChecked()
|
||||
config.setting["ignore_file_mbids"] = self.ui.ignore_file_mbids.isChecked()
|
||||
config.setting["check_for_updates"] = self.ui.check_for_updates.isChecked()
|
||||
config.setting["include_beta_versions"] = self.ui.include_beta_versions.isChecked()
|
||||
config.setting["update_check_days"] = self.ui.update_check_days.value()
|
||||
|
||||
def update_login_logout(self):
|
||||
if self.tagger.webservice.oauth_manager.is_logged_in():
|
||||
|
||||
@@ -67,8 +67,52 @@ class Ui_GeneralOptionsPage(object):
|
||||
self.ignore_file_mbids.setObjectName("ignore_file_mbids")
|
||||
self.verticalLayout.addWidget(self.ignore_file_mbids)
|
||||
self.vboxlayout.addWidget(self.groupBox_2)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(181, 21, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.vboxlayout.addItem(spacerItem1)
|
||||
self.groupBox_3 = QtWidgets.QGroupBox(GeneralOptionsPage)
|
||||
self.groupBox_3.setEnabled(True)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.groupBox_3.sizePolicy().hasHeightForWidth())
|
||||
self.groupBox_3.setSizePolicy(sizePolicy)
|
||||
self.groupBox_3.setObjectName("groupBox_3")
|
||||
self.gridLayout = QtWidgets.QGridLayout(self.groupBox_3)
|
||||
self.gridLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
|
||||
self.gridLayout.setContentsMargins(9, -1, -1, -1)
|
||||
self.gridLayout.setHorizontalSpacing(6)
|
||||
self.gridLayout.setObjectName("gridLayout")
|
||||
self.include_beta_versions = QtWidgets.QCheckBox(self.groupBox_3)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.include_beta_versions.sizePolicy().hasHeightForWidth())
|
||||
self.include_beta_versions.setSizePolicy(sizePolicy)
|
||||
self.include_beta_versions.setObjectName("include_beta_versions")
|
||||
self.gridLayout.addWidget(self.include_beta_versions, 1, 0, 1, 2)
|
||||
self.update_check_days = QtWidgets.QSpinBox(self.groupBox_3)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.update_check_days.sizePolicy().hasHeightForWidth())
|
||||
self.update_check_days.setSizePolicy(sizePolicy)
|
||||
self.update_check_days.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
|
||||
self.update_check_days.setObjectName("update_check_days")
|
||||
self.gridLayout.addWidget(self.update_check_days, 2, 1, 1, 1)
|
||||
self.check_for_updates = QtWidgets.QCheckBox(self.groupBox_3)
|
||||
self.check_for_updates.setObjectName("check_for_updates")
|
||||
self.gridLayout.addWidget(self.check_for_updates, 0, 0, 1, 2)
|
||||
self.label_2 = QtWidgets.QLabel(self.groupBox_3)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth())
|
||||
self.label_2.setSizePolicy(sizePolicy)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.gridLayout.addItem(spacerItem1, 2, 2, 1, 1)
|
||||
self.vboxlayout.addWidget(self.groupBox_3)
|
||||
spacerItem2 = QtWidgets.QSpacerItem(181, 21, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.vboxlayout.addItem(spacerItem2)
|
||||
|
||||
self.retranslateUi(GeneralOptionsPage)
|
||||
QtCore.QMetaObject.connectSlotsByName(GeneralOptionsPage)
|
||||
@@ -85,4 +129,8 @@ class Ui_GeneralOptionsPage(object):
|
||||
self.groupBox_2.setTitle(_("General"))
|
||||
self.analyze_new_files.setText(_("Automatically scan all new files"))
|
||||
self.ignore_file_mbids.setText(_("Ignore MBIDs when loading new files"))
|
||||
self.groupBox_3.setTitle(_("Update Checking"))
|
||||
self.include_beta_versions.setText(_("Include beta versions in update checks"))
|
||||
self.check_for_updates.setText(_("Check for updates during start-up"))
|
||||
self.label_2.setText(_("Days between update checks:"))
|
||||
|
||||
|
||||
@@ -496,3 +496,42 @@ def restore_method(func):
|
||||
return func_wrapper
|
||||
|
||||
builtins.__dict__['string_'] = convert_to_string
|
||||
|
||||
|
||||
def compare_version_tuples(version1, version2):
|
||||
'''Compare Versions
|
||||
|
||||
Compares two Picard version tuples to determine whether the second tuple
|
||||
contains a higher version number than the first tuple.
|
||||
|
||||
Args:
|
||||
version1: The first version tuple to compare. This will be used as
|
||||
the base for the comparison.
|
||||
version2: The version tuple to be compared to the base version.
|
||||
|
||||
Returns:
|
||||
-1 if version2 is lower than version1
|
||||
0 if version2 is the same as version1
|
||||
1 if version2 is higher than version1
|
||||
|
||||
Raises:
|
||||
none
|
||||
'''
|
||||
|
||||
# Create test copies that can be modified
|
||||
test1 = list(version1)
|
||||
test2 = list(version2)
|
||||
|
||||
# Set sort order for release type element
|
||||
test1[3] = 1 if test1[3] == 'final' else 0
|
||||
if test1[3]:
|
||||
test1[4] = 0
|
||||
test2[3] = 1 if test2[3] == 'final' else 0
|
||||
if test2[3]:
|
||||
test2[4] = 0
|
||||
|
||||
# Compare elements in order
|
||||
for x in range(0, 5):
|
||||
if test1[x] != test2[x]:
|
||||
return 1 if test1[x] < test2[x] else -1
|
||||
return 0
|
||||
|
||||
152
picard/util/checkupdate.py
Normal file
152
picard/util/checkupdate.py
Normal file
@@ -0,0 +1,152 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Picard, the next-generation MusicBrainz tagger
|
||||
# Copyright (C) 2018 Bob Swift
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
from picard import (PICARD_VERSION, tagger, log, version_from_string, version_to_string, config)
|
||||
import picard.util.webbrowser2 as wb2
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
from picard.util import load_json, compare_version_tuples
|
||||
from functools import partial
|
||||
import re
|
||||
import datetime
|
||||
|
||||
|
||||
# Used to strip leading and trailing text from version string.
|
||||
_RE_CLEAN_VERSION = re.compile('^[^0-9]*(.*)[^0-9]*$', re.IGNORECASE)
|
||||
|
||||
|
||||
# GitHub API information
|
||||
GITHUB_API = {
|
||||
'host': 'api.github.com',
|
||||
'port': 443,
|
||||
'endpoint': {
|
||||
'releases': '/repos/metabrainz/picard/releases',
|
||||
'tags': '/repos/metabrainz/picard/git/refs/tags'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UpdateCheckManager(QtCore.QObject):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# Version tuple format: str.key: ( str.version, ( int.major, int.minor, int.micro, str.type, int.development ), str.title, str.url )
|
||||
self._available_versions = {
|
||||
'stable': ('', (0, 0, 0, 'dev', 0), '', ''),
|
||||
'beta': ('', (0, 0, 0, 'dev', 0), '', ''),
|
||||
'dev': ('', (0, 0, 0, 'dev', 0), '', ''),
|
||||
}
|
||||
self._show_always = False
|
||||
self._update_level = 'dev'
|
||||
|
||||
def check_update(self, show_always=False, update_level='dev', callback=None):
|
||||
'''Checks if an update is available.
|
||||
|
||||
Compares the version number of the currently running instance of Picard
|
||||
and displays a dialog box informing the user if an update is available,
|
||||
with an option of opening the Picard site in the browser to download the
|
||||
update. If there is no update available, no dialog will be shown unless
|
||||
the "show_always" parameter has been set to True. This allows for silent
|
||||
checking during startup if so configured.
|
||||
|
||||
Args:
|
||||
show_always: Boolean value indicating whether the results dialog
|
||||
should be shown even when there is no update available.
|
||||
update_level: Determines what type of updates to check. If set to
|
||||
'final' only stable release versions are checked. If set to
|
||||
'dev' both beta and stable releases are checked.
|
||||
callback: Optional callback function.
|
||||
|
||||
Returns:
|
||||
none.
|
||||
|
||||
Raises:
|
||||
none.
|
||||
'''
|
||||
self._show_always = show_always
|
||||
self._update_level = update_level
|
||||
|
||||
# Gets list of releases from GitHub website api.
|
||||
self.query_available_updates()
|
||||
|
||||
@property
|
||||
def available_versions(self):
|
||||
'''Provide a list of the latest version tuples for each type.'''
|
||||
return self._available_versions
|
||||
|
||||
def query_available_updates(self, callback=None):
|
||||
'''Gets list of releases from GitHub website api.'''
|
||||
output_text = _("Getting release information from GitHub.")
|
||||
log.debug(output_text)
|
||||
self.tagger.webservice.get(
|
||||
GITHUB_API['host'],
|
||||
GITHUB_API['port'],
|
||||
GITHUB_API['endpoint']['releases'],
|
||||
partial(self._releases_json_loaded, callback=callback),
|
||||
parse_response_type=None,
|
||||
priority=True,
|
||||
important=True
|
||||
)
|
||||
|
||||
def _releases_json_loaded(self, response, reply, error, callback=None):
|
||||
'''Processes response from GitHub api query.'''
|
||||
if error:
|
||||
tagger.window.set_statusbar_message(
|
||||
N_("Error loading releases list: %(error)s"),
|
||||
{'error': reply.errorString()},
|
||||
echo=log.error
|
||||
)
|
||||
else:
|
||||
config.persist['last_update_check'] = datetime.date.today().toordinal()
|
||||
releases = load_json(response)
|
||||
|
||||
for release in releases:
|
||||
ver = version_from_string(
|
||||
_RE_CLEAN_VERSION.findall(release['tag_name'])[0])
|
||||
key = 'beta' if release['prerelease'] else 'stable'
|
||||
if compare_version_tuples(self._available_versions[key][1], ver) > 0:
|
||||
self._available_versions[key] = (version_to_string(
|
||||
ver, short=True), ver, release['name'], release['html_url'],)
|
||||
for key in self._available_versions.keys():
|
||||
log.debug("Version key '%s' --> %s" %
|
||||
(key, self._available_versions[key],))
|
||||
|
||||
# Display results to user.
|
||||
msg_title = _("Picard Update")
|
||||
if (compare_version_tuples(PICARD_VERSION, self._available_versions['stable'][1]) > 0) | (
|
||||
(compare_version_tuples(PICARD_VERSION, self._available_versions['beta'][1]) > 0) & (self._update_level == 'dev')):
|
||||
key = 'beta' if (compare_version_tuples(self._available_versions['stable'][1],
|
||||
self._available_versions['beta'][1]) > 0) & (self._update_level == 'dev') else 'stable'
|
||||
if self.available_versions[key][2]:
|
||||
new_version = "%s (%s)" & (self._available_versions[key][2], self._available_versions[key][0])
|
||||
else:
|
||||
new_version = self.available_versions[key][0]
|
||||
msg_text = _("A new version of Picard is available.\n\nNew version: %s\n\n"
|
||||
"Would you like to download the new version?") % (new_version,)
|
||||
if QMessageBox.information(None, msg_title, msg_text, QMessageBox.Ok | QMessageBox.Cancel,
|
||||
QMessageBox.Cancel) == QMessageBox.Ok:
|
||||
wb2.open(self._available_versions[key][3])
|
||||
else:
|
||||
if self._show_always:
|
||||
msg_text = _("There is no update currently available.")
|
||||
QMessageBox.information(
|
||||
None, msg_title, msg_text, QMessageBox.Ok, QMessageBox.Ok)
|
||||
if callback:
|
||||
callback()
|
||||
217
test/test_versioncompare.py
Normal file
217
test/test_versioncompare.py
Normal file
@@ -0,0 +1,217 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import unittest
|
||||
from picard.util import compare_version_tuples
|
||||
|
||||
|
||||
class CompareVersionsTest(unittest.TestCase):
|
||||
'''Unit tests for compare_version_tuples() function.'''
|
||||
|
||||
def test_compare_version_01(self):
|
||||
a, b, r = (0, 0, 1, 'dev', 1), (0, 0, 1, 'dev', 1), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_02(self):
|
||||
a, b, r = (0, 1, 0, 'dev', 1), (0, 1, 0, 'dev', 1), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_03(self):
|
||||
a, b, r = (0, 1, 1, 'dev', 1), (0, 1, 1, 'dev', 1), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_04(self):
|
||||
a, b, r = (1, 0, 0, 'dev', 1), (1, 0, 0, 'dev', 1), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_05(self):
|
||||
a, b, r = (1, 0, 1, 'dev', 1), (1, 0, 1, 'dev', 1), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_06(self):
|
||||
a, b, r = (1, 1, 0, 'dev', 1), (1, 1, 0, 'dev', 1), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_07(self):
|
||||
a, b, r = (1, 1, 1, 'dev', 1), (1, 1, 1, 'dev', 1), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_08(self):
|
||||
a, b, r = (0, 0, 1, 'dev', 2), (0, 0, 1, 'dev', 1), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_09(self):
|
||||
a, b, r = (0, 0, 2, 'dev', 1), (0, 0, 1, 'dev', 2), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_10(self):
|
||||
a, b, r = (0, 1, 0, 'dev', 1), (0, 0, 1, 'dev', 2), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_11(self):
|
||||
a, b, r = (1, 0, 0, 'dev', 1), (0, 1, 1, 'dev', 2), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_12(self):
|
||||
a, b, r = (0, 0, 1, 'dev', 1), (0, 0, 1, 'dev', 2), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_13(self):
|
||||
a, b, r = (0, 0, 1, 'dev', 2), (0, 0, 2, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_14(self):
|
||||
a, b, r = (0, 0, 1, 'dev', 2), (0, 1, 0, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_15(self):
|
||||
a, b, r = (0, 1, 1, 'dev', 2), (1, 0, 0, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_16(self):
|
||||
a, b, r = (0, 0, 1, 'final', 0), (0, 0, 1, 'final', 0), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_17(self):
|
||||
a, b, r = (0, 0, 1, 'final', 0), (0, 0, 1, 'final', 1), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_18(self):
|
||||
a, b, r = (0, 0, 1, 'final', 1), (0, 0, 1, 'final', 0), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_19(self):
|
||||
a, b, r = (0, 1, 0, 'final', 0), (0, 1, 0, 'final', 0), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_20(self):
|
||||
a, b, r = (0, 1, 1, 'final', 0), (0, 1, 1, 'final', 0), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_21(self):
|
||||
a, b, r = (1, 0, 0, 'final', 0), (1, 0, 0, 'final', 0), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_22(self):
|
||||
a, b, r = (1, 0, 1, 'final', 0), (1, 0, 1, 'final', 0), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_23(self):
|
||||
a, b, r = (1, 1, 0, 'final', 0), (1, 1, 0, 'final', 0), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_24(self):
|
||||
a, b, r = (1, 1, 1, 'final', 0), (1, 1, 1, 'final', 0), 0
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_25(self):
|
||||
a, b, r = (0, 0, 2, 'final', 0), (0, 0, 1, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_26(self):
|
||||
a, b, r = (0, 1, 0, 'final', 0), (0, 0, 1, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_27(self):
|
||||
a, b, r = (1, 0, 0, 'final', 0), (0, 1, 1, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_28(self):
|
||||
a, b, r = (0, 0, 1, 'final', 0), (0, 0, 2, 'final', 0), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_29(self):
|
||||
a, b, r = (0, 0, 1, 'final', 0), (0, 1, 0, 'final', 0), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_30(self):
|
||||
a, b, r = (0, 1, 1, 'final', 0), (1, 0, 0, 'final', 0), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_31(self):
|
||||
a, b, r = (0, 0, 1, 'dev', 1), (0, 0, 1, 'final', 0), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_32(self):
|
||||
a, b, r = (0, 0, 2, 'dev', 1), (0, 0, 1, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_33(self):
|
||||
a, b, r = (0, 0, 2, 'dev', 1), (0, 1, 0, 'final', 0), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_34(self):
|
||||
a, b, r = (0, 1, 1, 'dev', 1), (0, 1, 0, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_35(self):
|
||||
a, b, r = (0, 2, 0, 'dev', 1), (0, 1, 0, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_36(self):
|
||||
a, b, r = (0, 2, 0, 'dev', 1), (0, 1, 1, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_37(self):
|
||||
a, b, r = (0, 2, 0, 'dev', 1), (0, 2, 0, 'final', 0), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_38(self):
|
||||
a, b, r = (0, 2, 1, 'dev', 1), (0, 2, 0, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_39(self):
|
||||
a, b, r = (0, 2, 1, 'dev', 1), (0, 2, 1, 'final', 0), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_40(self):
|
||||
a, b, r = (1, 0, 0, 'dev', 1), (0, 1, 0, 'final', 0), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_41(self):
|
||||
a, b, r = (1, 0, 0, 'dev', 1), (1, 0, 0, 'final', 0), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_42(self):
|
||||
a, b, r = (0, 0, 1, 'final', 0), (0, 0, 1, 'dev', 1), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_43(self):
|
||||
a, b, r = (0, 0, 1, 'final', 0), (0, 0, 2, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_44(self):
|
||||
a, b, r = (0, 1, 0, 'final', 0), (0, 0, 2, 'dev', 1), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_45(self):
|
||||
a, b, r = (0, 1, 0, 'final', 0), (0, 1, 1, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_46(self):
|
||||
a, b, r = (0, 1, 0, 'final', 0), (0, 2, 0, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_47(self):
|
||||
a, b, r = (0, 1, 1, 'final', 0), (0, 2, 0, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_48(self):
|
||||
a, b, r = (0, 2, 0, 'final', 0), (0, 2, 0, 'dev', 1), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_49(self):
|
||||
a, b, r = (0, 2, 0, 'final', 0), (0, 2, 1, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_50(self):
|
||||
a, b, r = (0, 2, 1, 'final', 0), (0, 2, 1, 'dev', 1), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_51(self):
|
||||
a, b, r = (0, 1, 0, 'final', 0), (1, 0, 0, 'dev', 1), 1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
def test_compare_version_52(self):
|
||||
a, b, r = (1, 0, 0, 'final', 0), (1, 0, 0, 'dev', 1), -1
|
||||
self.assertEqual(compare_version_tuples(a, b), r)
|
||||
|
||||
@@ -132,6 +132,92 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Update Checking</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="include_beta_versions">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Include beta versions in update checks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="update_check_days">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="check_for_updates">
|
||||
<property name="text">
|
||||
<string>Check for updates during start-up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Days between update checks:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
|
||||
Reference in New Issue
Block a user