Example #1
0
def compareRelease(a: Release, b: Release) -> int:
    if b.lessThan(a):
        return -1
    elif b.equals(a):
        return 0
    else:
        return 1
Example #2
0
 def downloadRelease(self, rls: Release):
     worker = Worker(self.makeDownloadRequest, rls.getDownloadUrl())
     worker.signals.result.connect(self.handleDownloadFinished)
     worker.signals.progress.connect(self.handleDownloadProgress)
     worker.signals.error.connect(self.handleDownloadError)
     self.last_release = rls
     threadpool.start(worker)
Example #3
0
 def makeLoadRequest(self, url, progress_callback=None):
     releases = requests.get(url)
     result = []
     for rls in releases.json():
         new_release = Release.fromJson(rls)
         if new_release.download_size:
             result.append(new_release)
     return result
Example #4
0
 def getLatestRelease(self):
     release = Release(QApplication.applicationVersion())
     _updates = self.getUpdates(release)
     if len(_updates) > 0:
         last_release = _updates[0]
         skip_release = setting_service.getSettingsValue(SKIP_RELEASE) == last_release.getVersion()
         if not skip_release:
             return last_release
     return None
Example #5
0
    def handleFeedReady(self):
        release = Release(QApplication.applicationVersion())
        self._updates = self.feed.getUpdates(release)
        if len(self._updates) > 0:
            self._latest_release = self._updates[0]

        if len(self._updates) == 0:
            self.setupNoUpdatesUi()
            logger.info("No release found.")
            return

        latest_version = self._latest_release.getVersion()
        skip_release = setting_service.getSettingsValue(
            SKIP_RELEASE) == latest_version
        if latest_version:
            self.setupUpdateUi()
            if self._silent and not skip_release:
                self._showDialog()
Example #6
0
 def getUpdates(self, min_release: Release) -> List[Release]:
     updates = []
     for rls in self.all_releases:
         if min_release.lessThan(rls):
             updates.append(rls)
     return updates
Example #7
0
class Updater(QObject):
    installed = pyqtSignal()
    _latest_release: Release = Release()
    _releases: List[Release] = []
    _updates: List[Release] = []
    _silent = False

    def __init__(self, parent, feed: Feed) -> None:
        super().__init__(parent)
        self._parent = parent
        self.dialog = QDialog(parent)
        self.ui = UpdaterUi(self.dialog)
        self.dialog.ui = self.ui
        self.feed = feed

    def _showDialog(self):
        screen_geometry = QApplication.desktop().screenGeometry()
        x = (screen_geometry.width() - self.dialog.width()) / 2
        y = (screen_geometry.height() - self.dialog.height()) / 2.8
        self.dialog.move(x, y)
        self.dialog.show()

    def checkForUpdate(self, silent=False):
        """
        Check for new update, if yes, then show the update confirmation window
        :param silent: whether or not we show the loading window
        """
        self._silent = silent
        if not silent:
            self._showDialog()
        self.setupLoadingUi()
        self.feed.ready.connect(self.handleFeedReady)
        logger.info("Starting to fetch update info...")
        self.feed.load()

    def handleFeedReady(self):
        release = Release(QApplication.applicationVersion())
        self._updates = self.feed.getUpdates(release)
        if len(self._updates) > 0:
            self._latest_release = self._updates[0]

        if len(self._updates) == 0:
            self.setupNoUpdatesUi()
            logger.info("No release found.")
            return

        latest_version = self._latest_release.getVersion()
        skip_release = setting_service.getSettingsValue(
            SKIP_RELEASE) == latest_version
        if latest_version:
            self.setupUpdateUi()
            if self._silent and not skip_release:
                self._showDialog()

    def setIcon(self, pixmap: QPixmap):
        self.ui.label_icon.setPixmap(pixmap)
        self.ui.label_icon.setHidden(False)

    def setupNoUpdatesUi(self):
        if self._silent:
            return
        self.resetUi()
        self.dialog.setMinimumSize(QSize(rt(500), rt(120)))
        self.dialog.resize(rt(500), rt(120))
        show_widgets = [
            self.ui.label_info_no_updates, self.ui.button_confirm,
            self.ui.label_headline_no_updates, self.ui.main_container,
            self.ui.label_icon
        ]
        for widget in show_widgets:
            widget.show()
        self.ui.button_confirm.setFocus()
        self.ui.label_headline_no_updates.setText(
            self.replaceAppVars(self.ui.label_headline_no_updates.text()))
        self.ui.button_confirm.clicked.connect(self.dialog.accept)
        self.dialog.adjustSize()

    def startDownload(self):
        logger.info("Starting to download release %s..." %
                    self._latest_release.version)
        self.feed.downloadRelease(self._latest_release)
        self.disableButtons(True)

    def setupUpdateUi(self):
        self.resetUi()
        self.ui.label_icon.show()
        self.dialog.setMinimumSize(QSize(rt(346 * 2), rt(346)))
        self.dialog.resize(rt(346 * 2), rt(346))
        show_widgets = [
            self.ui.main_container, self.ui.label_changelog,
            self.ui.button_skip, self.ui.button_cancel, self.ui.button_install,
            self.ui.label_info, self.ui.release_notes, self.ui.label_headline
        ]
        for widget in show_widgets:
            widget.show()
        labels = [self.ui.label_headline, self.ui.label_info]
        for label in labels:
            label.setText(self.replaceAppVars(label.text()))
        self.ui.label_changelog.setHtml(
            release_utils.generateChangelogDocument(self._updates))
        self.ui.label_changelog.setOpenExternalLinks(True)
        self.ui.label_changelog.setReadOnly(True)

        self.ui.button_confirm.clicked.connect(self.dialog.accept)
        self.ui.button_skip.clicked.connect(self.skipRelease)
        self.ui.button_cancel.clicked.connect(self.dialog.reject)

        self.ui.button_install.setFocus()
        self.ui.button_install.clicked.connect(self.onButtonInstall)
        self.dialog.adjustSize()

    def onButtonInstall(self):
        self.setupDownloadingUi()
        self.feed.download_finished.connect(self.handleDownloadFinished)
        self.feed.download_error.connect(self.handleDownloadError)
        self.feed.download_progress.connect(self.updateProgressBar)
        self.startDownload()

    def skipRelease(self):
        setting_service.setSettingsValue(SKIP_RELEASE,
                                         self._latest_release.getVersion())
        self.dialog.reject()

    def handleDownloadFinished(self):
        self.setupInstallingUi()

    def handleDownloadError(self, message):
        message_box = QMessageBox(self.dialog)
        message_box.setIcon(QMessageBox.Warning)
        message_box.setText(
            self.tr("There was an error while downloading the update."))
        message_box.setInformativeText(message)
        message_box.show()
        self.dialog.reject()

    def disableButtons(self, disable: bool):
        buttons = [
            self.ui.button_cancel, self.ui.button_confirm,
            self.ui.button_install, self.ui.button_skip
        ]

        for button in buttons:
            button.setDisabled(disable)

    def setupLoadingUi(self):
        if self._silent:
            return
        self.resetUi()
        self.dialog.setMinimumSize(QSize(rt(500), rt(120)))
        self.dialog.resize(rt(500), rt(120))
        self.ui.main_container.show()
        self.ui.label_headline_loading.show()
        self.ui.progress_bar.show()
        self.ui.progress_bar.setMaximum(0)
        self.ui.progress_bar.setMinimum(0)
        self.ui.label_icon.show()
        self.dialog.adjustSize()

    def setupDownloadingUi(self):
        self.resetUi()
        self.dialog.setWindowTitle(
            self.tr("Updating") + " %s…" % QApplication.applicationName())
        self.dialog.setMinimumSize(QSize(rt(500), rt(120)))
        self.dialog.resize(rt(500), rt(120))
        show_widgets = [
            self.ui.main_container, self.ui.label_icon, self.ui.progress_bar,
            self.ui.label_downloading, self.ui.button_cancel_loading,
            self.ui.progress_label
        ]
        for widget in show_widgets:
            widget.show()

        self.ui.button_cancel_loading.setEnabled(True)
        self.ui.button_cancel_loading.setFocus()
        self.ui.button_cancel_loading.clicked.connect(self.dialog.reject)
        self.dialog.adjustSize()

    def setupInstallingUi(self):
        self.resetUi()
        self.dialog.setWindowTitle(
            self.tr("Updating") + " %s…" % QApplication.applicationName())
        self.dialog.setMinimumSize(QSize(rt(500), rt(120)))
        self.dialog.resize(rt(500), rt(120))
        show_widgets = [
            self.ui.main_container, self.ui.label_icon,
            self.ui.button_install_and_relaunch,
            self.ui.label_install_and_relaunch
        ]
        for widget in show_widgets:
            widget.show()

        self.updateProgressBar(self._latest_release.download_size,
                               self._latest_release.download_size)

        self.ui.button_install_and_relaunch.setEnabled(True)
        self.ui.button_install_and_relaunch.setFocus()
        self.ui.button_install_and_relaunch.clicked.connect(self.installUpdate)
        self.dialog.adjustSize()

    def installUpdate(self):
        logger.info("Starting to install update...")
        file = self.feed.getDownloadFile()
        worker = Worker(core.installUpdate, file)
        worker.signals.result.connect(self.onInstalled)
        worker.signals.error.connect(lambda x: self.setupInstallFailedUi())
        threadpool.start(worker)

    def onInstalled(self):
        self.installed.emit()
        self.dialog.accept()

    def setupInstallFailedUi(self):
        self.resetUi()
        self.dialog.setMinimumSize(QSize(rt(500), rt(120)))
        self.dialog.resize(rt(500), rt(120))
        show_widgets = [
            self.ui.main_container, self.ui.label_icon,
            self.ui.label_info_unable_update,
            self.ui.label_headline_unable_update
        ]
        for widget in show_widgets:
            widget.show()
        self.ui.label_info_unable_update.setText(
            self.replaceAppVars(self.ui.label_info_unable_update.text()))
        self.dialog.adjustSize()

    def resetUi(self):
        hidden_widgets = [
            self.ui.main_container, self.ui.label_icon,
            self.ui.label_headline_loading, self.ui.label_info,
            self.ui.release_notes, self.ui.button_install_and_relaunch,
            self.ui.label_headline, self.ui.label_downloading,
            self.ui.label_install_and_relaunch, self.ui.label_info_no_updates,
            self.ui.label_headline_no_updates,
            self.ui.label_headline_unable_update,
            self.ui.label_info_unable_update, self.ui.label_changelog,
            self.ui.progress_bar, self.ui.button_skip, self.ui.button_cancel,
            self.ui.button_cancel_loading, self.ui.button_confirm,
            self.ui.button_install, self.ui.progress_label
        ]

        for widget in hidden_widgets:
            widget.hide()
            pyqt_utils.disconnectAllSignals(widget)
        self.ui.progress_bar.reset()
        self.dialog.adjustSize()

    def replaceAppVars(self, string):
        new_str = string.replace("$APP_NAME$",
                                 QCoreApplication.applicationName())
        new_str = new_str.replace("$CURRENT_VERSION$",
                                  QCoreApplication.applicationVersion())
        new_str = new_str.replace("$UPDATE_VERSION$",
                                  self._latest_release.getVersion())
        new_str = new_str.replace("$UPDATE_LINK$",
                                  self._latest_release.getDownloadUrl())
        return new_str

    def updateProgressBar(self, bytes_received, bytes_total):
        self.ui.progress_bar.show()
        self.ui.progress_bar.setMaximum(bytes_total / 1024)
        self.ui.progress_bar.setValue(bytes_received / 1024)
        self.ui.progress_label.show()
        mb_received = bytes_received / 1024 / 1024
        mb_total = bytes_total / 1024 / 1024
        self.ui.progress_label.setText("%.2f MB of %.2f MB" %
                                       (mb_received, mb_total))