diff --git a/CHANGELOG.md b/CHANGELOG.md index 4595c307..70db145f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - old settings properties were dropped (**db_updater.interval**, **db_updated.enabled**) - database files (**apps.db** and **releases.db**) are now stored at **~/.cache/bauh/appimage** - displaying a warning when the cached database files could not be found + - new custom action **Update database** to perform a database update anytime: +

+ +

- Arch - AUR diff --git a/bauh/api/abstract/model.py b/bauh/api/abstract/model.py index 3cb78981..8c6dad1a 100644 --- a/bauh/api/abstract/model.py +++ b/bauh/api/abstract/model.py @@ -10,7 +10,8 @@ class CustomSoftwareAction: def __init__(self, i18n_label_key: str, i18n_status_key: str, icon_path: str, manager_method: str, requires_root: bool, manager: "SoftwareManager" = None, backup: bool = False, refresh: bool = True, - i18n_confirm_key: str = None): + i18n_confirm_key: str = None, + requires_internet: bool = False): """ :param i18n_label_key: the i18n key that will be used to display the action name :param i18n_status_key: the i18n key that will be used to display the action name being executed @@ -21,6 +22,7 @@ class CustomSoftwareAction: :param requires_root: :param refresh: if the a full app refresh should be done if the action succeeds :param i18n_confirm_key: action confirmation message + :param requires_internet: if the action requires internet connection to be executed """ self.i18n_label_key = i18n_label_key self.i18n_status_key = i18n_status_key @@ -31,6 +33,7 @@ class CustomSoftwareAction: self.backup = backup self.refresh = refresh self.i18n_confirm_key = i18n_confirm_key + self.requires_internet = requires_internet def __hash__(self): return self.i18n_label_key.__hash__() + self.i18n_status_key.__hash__() + self.manager_method.__hash__() diff --git a/bauh/gems/appimage/controller.py b/bauh/gems/appimage/controller.py index bbe4241b..e42b6ffe 100644 --- a/bauh/gems/appimage/controller.py +++ b/bauh/gems/appimage/controller.py @@ -81,7 +81,14 @@ class AppImageManager(SoftwareManager): manager=self, manager_method='install_file', icon_path=resource.get_path('img/appimage.svg', ROOT_DIR), - requires_root=False)] + requires_root=False), + CustomSoftwareAction(i18n_label_key='appimage.custom_action.update_db', + i18n_status_key='appimage.custom_action.update_db.status', + manager=self, + manager_method='update_database', + icon_path=resource.get_path('img/appimage.svg', ROOT_DIR), + requires_root=False, + requires_internet=True)] self.custom_app_actions = [CustomSoftwareAction(i18n_label_key='appimage.custom_action.manual_update', i18n_status_key='appimage.custom_action.manual_update.status', manager_method='update_file', @@ -613,7 +620,7 @@ class AppImageManager(SoftwareManager): symlink_check.start() if internet_available: - updater = DatabaseUpdater(task_man=task_manager, i18n=self.context.i18n, + updater = DatabaseUpdater(taskman=task_manager, i18n=self.context.i18n, http_client=self.context.http_client, logger=self.context.logger) if updater.should_update(read_config()): @@ -812,3 +819,10 @@ class AppImageManager(SoftwareManager): self._write_ignored_updates(current_ignored) pkg.updates_ignored = False + + def update_database(self, root_password: str, watcher: ProcessWatcher) -> bool: + db_updater = DatabaseUpdater(i18n=self.i18n, http_client=self.context.http_client, + logger=self.context.logger, watcher=watcher) + + res = db_updater.download_databases() + return res diff --git a/bauh/gems/appimage/resources/locale/ca b/bauh/gems/appimage/resources/locale/ca index 37147d06..9f3be860 100644 --- a/bauh/gems/appimage/resources/locale/ca +++ b/bauh/gems/appimage/resources/locale/ca @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=Installing AppImage file appimage.custom_action.manual_update=Upgrade file appimage.custom_action.manual_update.details=Upgrade details appimage.custom_action.manual_update.status=Upgrading +appimage.custom_action.update_db=Update database +appimage.custom_action.update_db.status=Updating database appimage.downgrade.first_version={} és a la seva primera versió publicada appimage.downgrade.impossible.body={} té només una versió publicada. appimage.downgrade.impossible.title=No s’ha pogut revertir la versió @@ -30,6 +32,9 @@ appimage.install.download.error=No s’ha pogut baixar el fitxer {}. El servidor appimage.install.extract=S’està extraient el contingut de {} appimage.install.imported.rename_error=It was not possible to move the file {} to {} appimage.install.permission=S’està concedint el permís d’execució a {} +appimage.update_database.deleting_old=Removing old files +appimage.update_database.downloading=Downloading database files +appimage.update_database.uncompressing=Uncompressing files appimage.task.db_update=Actualització de bases de dades appimage.task.symlink_check=Checking symlinks appimage.uninstall.error.remove_folder=No s’ha pogut suprimir el directori d’instal·lació de l’aplicació {} diff --git a/bauh/gems/appimage/resources/locale/de b/bauh/gems/appimage/resources/locale/de index fc365c97..c924f481 100644 --- a/bauh/gems/appimage/resources/locale/de +++ b/bauh/gems/appimage/resources/locale/de @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=Installing AppImage file appimage.custom_action.manual_update=Upgrade file appimage.custom_action.manual_update.details=Upgrade details appimage.custom_action.manual_update.status=Upgrading +appimage.custom_action.update_db=Update database +appimage.custom_action.update_db.status=Updating database appimage.downgrade.first_version={} ist in der ersten veröffentlichten Version appimage.downgrade.impossible.body={} hat nur eine veröffentliche Version appimage.downgrade.impossible.title=Downgrade nicht möglich @@ -30,6 +32,9 @@ appimage.install.download.error=Das Herunterladen der Datei {} ist fehlgeschlage appimage.install.extract=Entpacke Inhalt von {} appimage.install.imported.rename_error=It was not possible to move the file {} to {} appimage.install.permission=Ausführberechtigungen für {} +appimage.update_database.deleting_old=Removing old files +appimage.update_database.downloading=Downloading database files +appimage.update_database.uncompressing=Uncompressing files appimage.task.db_update=Updating databases appimage.task.symlink_check=Checking symlinks appimage.uninstall.error.remove_folder=Anwendungordner {} konnte nicht entfernt werden diff --git a/bauh/gems/appimage/resources/locale/en b/bauh/gems/appimage/resources/locale/en index 142f777a..e66cd0b1 100644 --- a/bauh/gems/appimage/resources/locale/en +++ b/bauh/gems/appimage/resources/locale/en @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=Installing AppImage file appimage.custom_action.manual_update=Upgrade file appimage.custom_action.manual_update.details=Upgrade details appimage.custom_action.manual_update.status=Upgrading +appimage.custom_action.update_db=Update database +appimage.custom_action.update_db.status=Updating database appimage.downgrade.first_version={} is in its first published version appimage.downgrade.impossible.body={} has only one published version. appimage.downgrade.impossible.title=Impossible to downgrade @@ -30,6 +32,9 @@ appimage.install.download.error=It was not possible to download the file {}. The appimage.install.extract=Extracting the content from {} appimage.install.imported.rename_error=It was not possible to move the file {} to {} appimage.install.permission=Giving execution permission to {} +appimage.update_database.deleting_old=Removing old files +appimage.update_database.downloading=Downloading database files +appimage.update_database.uncompressing=Uncompressing files appimage.task.db_update=Updating databases appimage.task.symlink_check=Checking symlinks appimage.uninstall.error.remove_folder=Could not remove the application installation directory {} diff --git a/bauh/gems/appimage/resources/locale/es b/bauh/gems/appimage/resources/locale/es index a7b88024..b1b97600 100644 --- a/bauh/gems/appimage/resources/locale/es +++ b/bauh/gems/appimage/resources/locale/es @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=Instalando archivo AppImage appimage.custom_action.manual_update=Actualizar archivo appimage.custom_action.manual_update.details=Detalles de actualización appimage.custom_action.manual_update.status=Actualizando +appimage.custom_action.update_db=Actualizar base de datos +appimage.custom_action.update_db.status=Actualizando base de datos appimage.downgrade.first_version={} está en su primera versión publicada appimage.downgrade.impossible.body={} solo tiene una versión publicada. appimage.downgrade.impossible.title=Imposible revertir la versión @@ -30,6 +32,9 @@ appimage.install.download.error=No fue posible descargar el archivo {}. El servi appimage.install.extract=Extrayendo el contenido de {} appimage.install.imported.rename_error=No fue posible mover el archivo {} a {} appimage.install.permission=Concediendo permiso de ejecución a {} +appimage.update_database.deleting_old=Eliminando archivos antiguos +appimage.update_database.downloading=Descargando archivos de la base de datos +appimage.update_database.uncompressing=Descomprindo archivos appimage.task.db_update=Actualizando base de datos appimage.task.symlink_check=Verificando links simbólicos appimage.uninstall.error.remove_folder=No se pudo eliminar el directorio de instalación de la aplicación {} diff --git a/bauh/gems/appimage/resources/locale/fr b/bauh/gems/appimage/resources/locale/fr index 484322d9..0efe8d4a 100644 --- a/bauh/gems/appimage/resources/locale/fr +++ b/bauh/gems/appimage/resources/locale/fr @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=Installation du fichier AppImage appimage.custom_action.manual_update=Mettre fichier à jour appimage.custom_action.manual_update.details=Détails de mise à jour appimage.custom_action.manual_update.status=Mise à jour +appimage.custom_action.update_db=Update database +appimage.custom_action.update_db.status=Updating database appimage.downgrade.first_version={} est à sa première version publiée appimage.downgrade.impossible.body={} a une seule version publiée. appimage.downgrade.impossible.title=Impossible à downgrader @@ -30,6 +32,9 @@ appimage.install.download.error=Échec du téléchargement du fichier {}. Le ser appimage.install.extract=Extractiion du contenu de {} appimage.install.imported.rename_error=Impossible de déplacer {} vers {} appimage.install.permission={} est maintenant exécutable +appimage.update_database.deleting_old=Removing old files +appimage.update_database.downloading=Downloading database files +appimage.update_database.uncompressing=Uncompressing files appimage.task.db_update=Mise à jour des bases de données appimage.task.symlink_check=Verification des symlinks appimage.uninstall.error.remove_folder=Impossible de supprimer le répertoire d'installation {} diff --git a/bauh/gems/appimage/resources/locale/it b/bauh/gems/appimage/resources/locale/it index 76bf6a6c..63f34052 100644 --- a/bauh/gems/appimage/resources/locale/it +++ b/bauh/gems/appimage/resources/locale/it @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=Installing AppImage file appimage.custom_action.manual_update=Upgrade file appimage.custom_action.manual_update.details=Upgrade details appimage.custom_action.manual_update.status=Upgrading +appimage.custom_action.update_db=Update database +appimage.custom_action.update_db.status=Updating database appimage.downgrade.first_version={} è nella sua prima versione pubblicata appimage.downgrade.impossible.body={} ha solo una versione pubblicata. appimage.downgrade.impossible.title=Impossibile eseguire il downgrade @@ -30,6 +32,9 @@ appimage.install.download.error=Non è stato possibile scaricare il file {}. Il appimage.install.extract=Estrarre il contenuto da {} appimage.install.imported.rename_error=It was not possible to move the file {} to {} appimage.install.permission=Gdare il permesso di esecuzione a {} +appimage.update_database.deleting_old=Removing old files +appimage.update_database.downloading=Downloading database files +appimage.update_database.uncompressing=Uncompressing files appimage.task.db_update=Aggiornamento dei database appimage.task.symlink_check=Checking symlinks appimage.uninstall.error.remove_folder=Impossibile rimuovere la directory di installazione dell'applicazione {} diff --git a/bauh/gems/appimage/resources/locale/pt b/bauh/gems/appimage/resources/locale/pt index 27dfbe43..6cc1060c 100644 --- a/bauh/gems/appimage/resources/locale/pt +++ b/bauh/gems/appimage/resources/locale/pt @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=Instalando arquivo AppImage appimage.custom_action.manual_update=Atualizar arquivo appimage.custom_action.manual_update.details=Detalhes de atualização appimage.custom_action.manual_update.status=Atualizando +appimage.custom_action.update_db=Atualizar banco de dados +appimage.custom_action.update_db.status=Atualizando banco de dados appimage.downgrade.first_version={} se encontra em sua primeira versão publicada appimage.downgrade.impossible.body={} tem somente uma versão publicada. appimage.downgrade.impossible.title=Impossível reverter a versão @@ -30,6 +32,9 @@ appimage.install.download.error=Não foi possível baixar o arquivo {}. O servid appimage.install.extract=Extraindo o conteúdo de {} appimage.install.imported.rename_error=Não foi possível mover o arquivo {} para {} appimage.install.permission=Concedendo permissão de execução para {} +appimage.update_database.deleting_old=Removendo arquicos antigos +appimage.update_database.downloading=Baixando arquivos do banco de dados +appimage.update_database.uncompressing=Descomprimindo arquivos appimage.task.db_update=Atualizando base de dados appimage.task.symlink_check=Verificando links simbólicos appimage.uninstall.error.remove_folder=Não foi possível remover o diretóri ode instalação do aplicativo {} diff --git a/bauh/gems/appimage/resources/locale/ru b/bauh/gems/appimage/resources/locale/ru index 2a072713..06c462d8 100644 --- a/bauh/gems/appimage/resources/locale/ru +++ b/bauh/gems/appimage/resources/locale/ru @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=Установка файла AppImag appimage.custom_action.manual_update=Обновить файл appimage.custom_action.manual_update.details=Детали обновления appimage.custom_action.manual_update.status=Обновляется... +appimage.custom_action.update_db=Update database +appimage.custom_action.update_db.status=Updating database appimage.downgrade.first_version={} первая опубликованная версия appimage.downgrade.impossible.body={} Имеет только одну опубликованную версию appimage.downgrade.impossible.title=Не удалось понизить версию @@ -30,6 +32,9 @@ appimage.install.download.error=Не удалось загрузить файл appimage.install.extract=Извлечь содержимое из {} appimage.install.imported.rename_error=Не удалось переместить файл {} в {} appimage.install.permission=Установить права на выполнение для {} +appimage.update_database.deleting_old=Removing old files +appimage.update_database.downloading=Downloading database files +appimage.update_database.uncompressing=Uncompressing files appimage.task.db_update=Обновление базы данных appimage.task.symlink_check=Checking symlinks appimage.uninstall.error.remove_folder=Не удалось удалить каталог приложения {} diff --git a/bauh/gems/appimage/resources/locale/tr b/bauh/gems/appimage/resources/locale/tr index 232ff11e..8f6c03e0 100644 --- a/bauh/gems/appimage/resources/locale/tr +++ b/bauh/gems/appimage/resources/locale/tr @@ -9,6 +9,8 @@ appimage.custom_action.install_file.status=AppImage dosyası yükleniyor appimage.custom_action.manual_update=Yükseltme dosyası appimage.custom_action.manual_update.details=Yükseltme ayrıntıları appimage.custom_action.manual_update.status=Yükseltiliyor +appimage.custom_action.update_db=Update database +appimage.custom_action.update_db.status=Updating database appimage.downgrade.first_version={} ilk yayınlanmış versiyonunda appimage.downgrade.impossible.body={} yalnızca bir yayınlanmış sürümüne sahip. appimage.downgrade.impossible.title=Sürüm düşürmek imkansız @@ -30,6 +32,9 @@ appimage.install.download.error={} dosyası indirilemedi. Dosya sunucusu kapalı appimage.install.extract={} 'den içerik ayıklanıyor appimage.install.imported.rename_error={} dosyasını {} klasörüne taşımak mümkün değildi appimage.install.permission={} için yürütme izni veriliyor +appimage.update_database.deleting_old=Removing old files +appimage.update_database.downloading=Downloading database files +appimage.update_database.uncompressing=Uncompressing files appimage.task.db_update=Veritabanları güncelleniyor appimage.task.symlink_check=Checking symlinks appimage.uninstall.error.remove_folder={} uygulama kurulum dizini kaldırılamadı diff --git a/bauh/gems/appimage/worker.py b/bauh/gems/appimage/worker.py index 678942c7..0c209d0d 100644 --- a/bauh/gems/appimage/worker.py +++ b/bauh/gems/appimage/worker.py @@ -21,12 +21,13 @@ from bauh.view.util.translation import I18n class DatabaseUpdater(Thread): COMPRESS_FILE_PATH = '{}/db.tar.gz'.format(DATABASES_DIR) - def __init__(self, task_man: TaskManager, i18n: I18n, http_client: HttpClient, logger: logging.Logger): + def __init__(self, i18n: I18n, http_client: HttpClient, logger: logging.Logger, watcher: Optional[ProcessWatcher] = None, taskman: Optional[TaskManager] = None): super(DatabaseUpdater, self).__init__(daemon=True) self.http_client = http_client self.logger = logger self.i18n = i18n - self.task_man = task_man + self.taskman = taskman + self.watcher = watcher self.task_id = 'appim_db' def should_update(self, appimage_config: dict) -> bool: @@ -75,22 +76,25 @@ class DatabaseUpdater(Thread): return update def register_task(self): - if self.task_man: - self.task_man.register_task(self.task_id, self.i18n['appimage.task.db_update'], get_icon_path()) + if self.taskman: + self.taskman.register_task(self.task_id, self.i18n['appimage.task.db_update'], get_icon_path()) def _finish_task(self): - if self.task_man: - self.task_man.update_progress(self.task_id, 100, None) - self.task_man.finish_task(self.task_id) - self.task_man = None + if self.taskman: + self.taskman.update_progress(self.task_id, 100, None) + self.taskman.finish_task(self.task_id) + self.taskman = None self.logger.info("Finished") def _update_task_progress(self, progress: float, substatus: Optional[str] = None): - if self.task_man: - self.task_man.update_progress(self.task_id, progress, substatus) + if self.taskman: + self.taskman.update_progress(self.task_id, progress, substatus) - def download_databases(self): - self._update_task_progress(1) # TODO add substatus + if self.watcher: + self.watcher.change_substatus(substatus) + + def download_databases(self) -> bool: + self._update_task_progress(1, self.i18n['appimage.update_database.downloading']) self.logger.info('Retrieving AppImage databases') database_timestamp = datetime.utcnow().timestamp() @@ -103,9 +107,8 @@ class DatabaseUpdater(Thread): if not res: self.logger.warning('Could not download the database file {}'.format(URL_COMPRESSED_DATABASES)) self._finish_task() - return + return False - self._update_task_progress(25) # TODO add substatus Path(DATABASES_DIR).mkdir(parents=True, exist_ok=True) with open(self.COMPRESS_FILE_PATH, 'wb+') as f: @@ -113,7 +116,7 @@ class DatabaseUpdater(Thread): self.logger.info("Database file saved at {}".format(self.COMPRESS_FILE_PATH)) - self._update_task_progress(50) # TODO add substatus + self._update_task_progress(50, self.i18n['appimage.update_database.deleting_old']) old_db_files = glob.glob(DATABASES_DIR + '/*.db') if old_db_files: @@ -123,7 +126,7 @@ class DatabaseUpdater(Thread): self.logger.info('Old database files deleted') - self._update_task_progress(75) # TODO add substatus + self._update_task_progress(75, self.i18n['appimage.update_database.uncompressing']) self.logger.info('Uncompressing {}'.format(self.COMPRESS_FILE_PATH)) try: @@ -133,6 +136,7 @@ class DatabaseUpdater(Thread): except: self.logger.error('Could not extract file {}'.format(self.COMPRESS_FILE_PATH)) traceback.print_exc() + return False finally: self.logger.info('Deleting {}'.format(self.COMPRESS_FILE_PATH)) os.remove(self.COMPRESS_FILE_PATH) @@ -147,6 +151,7 @@ class DatabaseUpdater(Thread): self.logger.info("Database timestamp saved") self._finish_task() + return True def run(self): self.download_databases() diff --git a/bauh/view/core/controller.py b/bauh/view/core/controller.py index 0fca3f37..b6cd284b 100755 --- a/bauh/view/core/controller.py +++ b/bauh/view/core/controller.py @@ -485,6 +485,9 @@ class GenericSoftwareManager(SoftwareManager): return [] def execute_custom_action(self, action: CustomSoftwareAction, pkg: SoftwarePackage, root_password: str, watcher: ProcessWatcher): + if action.requires_internet and not self.context.is_internet_available(): + raise NoInternetException() + man = action.manager if action.manager else self._get_manager_for(pkg) if man: diff --git a/bauh/view/qt/thread.py b/bauh/view/qt/thread.py index 444f8106..b2c75af5 100644 --- a/bauh/view/qt/thread.py +++ b/bauh/view/qt/thread.py @@ -1004,6 +1004,8 @@ class CustomAction(AsyncAction): self.i18n = i18n def run(self): + res = {'success': False, 'pkg': self.pkg, 'action': self.custom_action, 'error': None, 'error_type': MessageType.ERROR} + if self.custom_action.backup: proceed, _ = self.request_backup(app_config=read_config(), action_key=None, @@ -1011,22 +1013,24 @@ class CustomAction(AsyncAction): root_password=self.root_pwd, pkg=self.pkg) if not proceed: - self.notify_finished({'success': False, 'pkg': self.pkg, 'action': self.custom_action}) + self.notify_finished(res) self.pkg = None self.custom_action = None self.root_pwd = None return try: - success = self.manager.execute_custom_action(action=self.custom_action, - pkg=self.pkg.model if self.pkg else None, - root_password=self.root_pwd, - watcher=self) + res['success'] = self.manager.execute_custom_action(action=self.custom_action, + pkg=self.pkg.model if self.pkg else None, + root_password=self.root_pwd, + watcher=self) except (requests.exceptions.ConnectionError, NoInternetException): - success = False + res['success'] = False + res['error'] = 'internet.required' + res['error_type'] = MessageType.WARNING self.signal_output.emit(self.i18n['internet.required']) - self.notify_finished({'success': success, 'pkg': self.pkg, 'action': self.custom_action}) + self.notify_finished(res) self.pkg = None self.custom_action = None self.root_pwd = None diff --git a/bauh/view/qt/window.py b/bauh/view/qt/window.py index dfda10ec..6bd7bdc1 100755 --- a/bauh/view/qt/window.py +++ b/bauh/view/qt/window.py @@ -1433,6 +1433,11 @@ class ManageWindow(QWidget): self.comp_manager.restore_state(ACTION_CUSTOM_ACTION) self._show_console_errors() + if res['error']: + dialog.show_message(title=self.i18n['warning' if res['error_type'] == MessageType.WARNING else 'error'].capitalize(), + body=self.i18n[res['error']], + type_=res['error_type']) + def _show_console_checkbox_if_output(self): if self.textarea_details.toPlainText(): self.comp_manager.set_component_visible(CHECK_DETAILS, True)