From 0fcd40a46e07759885b706a518e66ef2aa981443 Mon Sep 17 00:00:00 2001 From: Sylvia van Os Date: Sun, 5 Nov 2017 17:38:18 +0100 Subject: [PATCH] Add update checking --- CHANGELOG.md | 1 + pext/__main__.py | 46 +++++++++++++++++++++++++++++- pext/qml/UpdateAvailableDialog.qml | 32 +++++++++++++++++++++ pext/qml/main.qml | 5 ++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 pext/qml/UpdateAvailableDialog.qml diff --git a/CHANGELOG.md b/CHANGELOG.md index eeebf944..1c2cf051 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Last updated info for modules - Version info for modules - Windows support +- Support for checking for updates (stable versions only) ### Changed - Command mode no longer locks onto the first entry diff --git a/pext/__main__.py b/pext/__main__.py index d5c3d94a..c2994de1 100644 --- a/pext/__main__.py +++ b/pext/__main__.py @@ -47,6 +47,7 @@ from typing import Dict, List, Optional, Tuple except ImportError: from backports.typing import Dict, List, Optional, Tuple # type: ignore +from urllib.request import urlopen from queue import Queue, Empty import pygit2 @@ -1273,6 +1274,19 @@ def get_last_updated(directory) -> Optional[datetime]: commit = repo.revparse_single('HEAD') return datetime.fromtimestamp(commit.commit_time) + def check_core_update(self) -> Optional[str]: + """Check if there is an update of the core and if so, return the name of the new version.""" + try: + with urlopen('https://pext.hackerchick.me/version/stable') as update_url: + available_version = update_url.readline().decode("utf-8").strip() + + if self.version < available_version: + return available_version + except Exception as e: + print("Failed to check for updates: {}".format(e)) + traceback.print_exc() + + return None class ModuleThreadInitializer(threading.Thread): """Initialize a thread for the module.""" @@ -1883,6 +1897,7 @@ def __init__(self, settings: Dict, config_retriever: ConfigRetriever, parent=Non QObject, "menuQuitWithoutSaving") menu_restart_shortcut = self.window.findChild( QObject, "menuRestart") + menu_check_for_updates_shortcut = self.window.findChild(QObject, "menuCheckForUpdates") menu_homepage_shortcut = self.window.findChild(QObject, "menuHomepage") # Bind menu entries @@ -1922,6 +1937,7 @@ def __init__(self, settings: Dict, config_retriever: ConfigRetriever, parent=Non menu_quit_without_saving_shortcut.triggered.connect( self.quit_without_saving) menu_restart_shortcut.triggered.connect(self._menu_restart) + menu_check_for_updates_shortcut.triggered.connect(self._menu_check_updates) menu_homepage_shortcut.triggered.connect(self._show_homepage) # Set entry states @@ -1975,7 +1991,6 @@ def __init__(self, settings: Dict, config_retriever: ConfigRetriever, parent=Non # Save user choice updatePermissionDialog.yes.connect(lambda: self._menu_toggle_update_check(True)) updatePermissionDialog.no.connect(lambda: self._menu_toggle_update_check(False)) - self.window.windowStateChanged.connect(self._process_window_state) def _bind_context(self) -> None: """Bind the context for the module.""" @@ -2285,9 +2300,34 @@ def _menu_restart(self) -> None: os.chdir(os.getcwd()) os.execv(sys.executable, args) + def _menu_check_updates(self, verbose=True) -> None: + if verbose: + Logger._log('⇩ Pext', self.logger) + + try: + new_version = UpdateManager().check_core_update() + except Exception as e: + Logger.log_error('⇩ Pext: {}'.format(e), self.logger) + return + + if new_version: + updateAvailableDialogEngine = QQmlApplicationEngine(self) + updateAvailableDialogEngine.load(QUrl.fromLocalFile(os.path.join(AppFile.get_path(), 'qml', 'UpdateAvailableDialog.qml'))) + + updateAvailableDialog = updateAvailableDialogEngine.rootObjects()[0] + + # Show update page if user asks + updateAvailableDialog.yes.connect(self._show_download_page) + else: + if verbose: + Logger._log('✔⇩ Pext', self.logger) + def _show_homepage(self) -> None: webbrowser.open('https://pext.hackerchick.me/') + def _show_download_page(self) -> None: + webbrowser.open('https://pext.hackerchick.me/download') + def bind_logger(self, logger: 'Logger') -> None: """Bind the logger to the window and further initialize the module.""" self.logger = logger @@ -2312,6 +2352,10 @@ def bind_logger(self, logger: 'Logger') -> None: elif len(self.tab_bindings) > 1: QQmlProperty.write(self.tabs, "currentIndex", "0") + # Check for updates too + if self.settings['update_check']: + self._menu_check_updates(verbose=False) + def bind_tray(self, tray: 'Tray') -> None: """Bind the tray to the window.""" self.tray = tray diff --git a/pext/qml/UpdateAvailableDialog.qml b/pext/qml/UpdateAvailableDialog.qml new file mode 100644 index 00000000..ce25c86b --- /dev/null +++ b/pext/qml/UpdateAvailableDialog.qml @@ -0,0 +1,32 @@ +/* + Copyright (c) 2017 Sylvia van Os + + This file is part of Pext + + Pext 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 3 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, see . +*/ + +import QtQuick 2.3 +import QtQuick.Dialogs 1.2 + +MessageDialog { + title: "Pext" + icon: StandardIcon.Question + standardButtons: StandardButton.Yes | StandardButton.No + + text: qsTr("A new version of Pext is available. Do you want to open the download page?") + + Component.onCompleted: visible = true; +} + diff --git a/pext/qml/main.qml b/pext/qml/main.qml index 20a0c5d8..576fe2d6 100644 --- a/pext/qml/main.qml +++ b/pext/qml/main.qml @@ -572,6 +572,11 @@ ApplicationWindow { } } + MenuItem { + objectName: "menuCheckForUpdates" + text: qsTr("Check for updates") + } + MenuItem { objectName: "menuHomepage" text: qsTr("Visit homepage")