From 066df8628ea6700d1e4752d62345bf07dbcae40d Mon Sep 17 00:00:00 2001 From: Vinicius Moreira Date: Fri, 11 Mar 2022 10:14:42 -0300 Subject: [PATCH] [appimage] feature: new custom action to self install bauh if it is running as an AppImage --- CHANGELOG.md | 5 +- README.md | 1 + bauh/gems/appimage/controller.py | 119 ++++++++++++++++++++++++- bauh/gems/appimage/resources/locale/ca | 3 + bauh/gems/appimage/resources/locale/de | 3 + bauh/gems/appimage/resources/locale/en | 3 + bauh/gems/appimage/resources/locale/es | 5 +- bauh/gems/appimage/resources/locale/fr | 3 + bauh/gems/appimage/resources/locale/it | 3 + bauh/gems/appimage/resources/locale/pt | 5 +- bauh/gems/appimage/resources/locale/ru | 3 + bauh/gems/appimage/resources/locale/tr | 3 + bauh/view/qt/window.py | 1 + 13 files changed, 153 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9e021b4..a1681ad9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - **index applications**: maps runnable installed packages (automatically done during initialization) - **software sources**: launches the application responsible for managing software sources (at the moment only `software-properties-gtk` is supported) - custom package actions supported: - - **purge**: removes the packages and all related configuration files + - **purge**: removes the packages and all related configuration files + +- AppImage + - new custom action to self install bauh if it is running as an AppImage ### Improvements - General diff --git a/README.md b/README.md index 3900e723..bcac705a 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ bauh is officially distributed through [PyPi](https://pypi.org/project/bauh) and - `Install AppImage file`: allows to install an external AppImage file - `Upgrade file`: allows to upgrade a manually installed AppImage file - `Update database`: manually synchronize the AppImage database + - `Install bauh`: installs bauh if it is running as an AppImage - Installed applications are store at `~/.local/share/bauh/appimage/installed` (or `/usr/local/share/bauh/installed` for **root**) - Desktop entries (menu shortcuts) of the installed applications are stored at `~/.local/share/applications` (or `/usr/share/applications` for **root**). Name pattern: `bauh_appimage_appname.desktop` diff --git a/bauh/gems/appimage/controller.py b/bauh/gems/appimage/controller.py index 9cdd16fc..6aebfd7d 100644 --- a/bauh/gems/appimage/controller.py +++ b/bauh/gems/appimage/controller.py @@ -79,6 +79,8 @@ class AppImageManager(SoftwareManager): self.file_downloader = context.file_downloader self.configman = AppImageConfigManager() self._custom_actions: Optional[Iterable[CustomSoftwareAction]] = None + self._action_self_install: Optional[CustomSoftwareAction] = None + self._app_github: Optional[str] = None self._search_unfilled_attrs: Optional[Tuple[str, ...]] = None def install_file(self, root_password: Optional[str], watcher: ProcessWatcher) -> bool: @@ -414,8 +416,22 @@ class AppImageManager(SoftwareManager): if watcher: watcher.print(f"[error] {msg}") + self._add_self_latest_version(pkg) # only for self installation return TransactionResult(success=True, installed=None, removed=[pkg]) + def _add_self_latest_version(self, app: AppImage): + if app.name == self.context.app_name and app.github == self.app_github and not app.url_download_latest_version: + history = self.get_history(app) + + if not history or not history.history: + self.logger.warning(f"Could not retrieve '{app.name}' versions. " + f"It will not be possible to determine the current latest version") + else: + app.version = history.history[0]['0_version'] + app.latest_version = app.version + app.url_download = history.history[0]['2_url_download'] + app.url_download_latest_version = app.url_download + def get_managed_types(self) -> Set[Type[SoftwarePackage]]: return {AppImage} @@ -544,7 +560,8 @@ class AppImageManager(SoftwareManager): def install(self, pkg: AppImage, root_password: Optional[str], disk_loader: Optional[DiskCacheLoader], watcher: ProcessWatcher) -> TransactionResult: return self._install(pkg=pkg, watcher=watcher) - def _install(self, pkg: AppImage, watcher: ProcessWatcher, pre_downloaded_file: Optional[Tuple[str, str]] = None): + def _install(self, pkg: AppImage, watcher: ProcessWatcher, pre_downloaded_file: Optional[Tuple[str, str]] = None) \ + -> TransactionResult: handler = ProcessHandler(watcher) out_dir = f'{INSTALLATION_DIR}/{pkg.get_clean_name()}' @@ -872,6 +889,10 @@ class AppImageManager(SoftwareManager): icon_path=resource.get_path('img/appimage.svg', ROOT_DIR), requires_root=False, requires_internet=True)) + + if self._get_self_appimage_running() and not self._is_self_installed(): + yield self.action_self_install + yield from self._custom_actions def get_upgrade_requirements(self, pkgs: List[AppImage], root_password: Optional[str], watcher: ProcessWatcher) -> UpgradeRequirements: @@ -951,3 +972,99 @@ class AppImageManager(SoftwareManager): return self._search_unfilled_attrs + def self_install(self, root_password: Optional[str], watcher: ProcessWatcher) -> bool: + file_path = self._get_self_appimage_running() + + if not file_path: + return False + + if self._is_self_installed(): + return False + + app = AppImage(name=self.context.app_name, version=self.context.app_version, + categories=['system'], author=self.context.app_name, github=self.app_github, + license='zlib/libpng') + + res = self._install(pkg=app, watcher=watcher, + pre_downloaded_file=(os.path.basename(file_path), file_path)) + if res.success: + app.installed = True + + de_path = self._gen_desktop_entry_path(app) + + if de_path and os.path.exists(de_path): + with open(de_path) as f: + bauh_entry = f.read() + + if bauh_entry: + comments = re.compile(r'Comment(\[\w+])?\s*=\s*(.+)').findall(bauh_entry) + + if comments: + locale = f'{self.i18n.current_key}' if self.i18n.current_key != self.i18n.default_key else None + + for key, desc in comments: + if desc: + if not key: + app.description = desc # default description + + if not locale: + break + + elif key == locale: + app.description = desc # localized description + break + else: + self.context.logger.warning(f"Could not find the 'Comment' fields from {self.context.app_name}'s desktop entry") + else: + self.context.logger.warning(f"{self.context.app_name} desktop entry is empty. Is is not possible to determine the 'description' field") + + else: + self.context.logger.warning(f"{self.context.app_name} desktop file not found ({de_path}). It is not possible to determine the 'description' field") + + self.cache_to_disk(app, None, False) + + return res.success + + def _is_self_installed(self) -> bool: + return os.path.exists(f'{INSTALLATION_DIR}/{self.context.app_name}/data.json') + + def _get_self_appimage_running(self) -> Optional[str]: + file = os.getenv('APPIMAGE') + + if not file: + return + + app_exec = os.getenv('APPRUN_STARTUP_EXEC_ARGS') + + if not app_exec: + return + + if os.path.basename(app_exec).split(' ')[0] != self.context.app_name: + return + + if not os.path.exists(file): + return + + return file + + @property + def action_self_install(self) -> CustomSoftwareAction: + if self._action_self_install is None: + self._action_self_install = CustomSoftwareAction(i18n_label_key='appimage.custom_action.self_install', + i18n_status_key='appimage.custom_action.self_install.status', + i18n_description_key='appimage.custom_action.self_install.desc', + manager=self, + manager_method='self_install', + icon_path=resource.get_path('img/appimage.svg', ROOT_DIR), + requires_root=False, + refresh=True, + requires_internet=False) + + return self._action_self_install + + @property + def app_github(self) -> str: + if self._app_github is None: + self._app_github = f'vinifmor/{self.context.app_name}' + + return self._app_github diff --git a/bauh/gems/appimage/resources/locale/ca b/bauh/gems/appimage/resources/locale/ca index 03dad8b6..49bc7487 100644 --- a/bauh/gems/appimage/resources/locale/ca +++ b/bauh/gems/appimage/resources/locale/ca @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Upgrade file appimage.custom_action.manual_update.desc=Replaces the installed AppImage file by another one appimage.custom_action.manual_update.details=AppImage upgrade details appimage.custom_action.manual_update.status=Upgrading +appimage.custom_action.self_install=Install bauh +appimage.custom_action.self_install.desc=Installs bauh on the system and adds its icons to the menu +appimage.custom_action.self_install.status=Installing bauh appimage.custom_action.update_db=Update database appimage.custom_action.update_db.desc=Downloads updated files from the AppImage applications database appimage.custom_action.update_db.status=Updating database diff --git a/bauh/gems/appimage/resources/locale/de b/bauh/gems/appimage/resources/locale/de index f61662d3..b32dbce6 100644 --- a/bauh/gems/appimage/resources/locale/de +++ b/bauh/gems/appimage/resources/locale/de @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Upgrade file appimage.custom_action.manual_update.desc=Replaces the installed AppImage file by another one appimage.custom_action.manual_update.details=AppImage upgrade details appimage.custom_action.manual_update.status=Upgrading +appimage.custom_action.self_install=Install bauh +appimage.custom_action.self_install.desc=Installs bauh on the system and adds its icons to the menu +appimage.custom_action.self_install.status=Installing bauh appimage.custom_action.update_db=Update database appimage.custom_action.update_db.desc=Downloads updated files from the AppImage applications database appimage.custom_action.update_db.status=Updating database diff --git a/bauh/gems/appimage/resources/locale/en b/bauh/gems/appimage/resources/locale/en index 5a9fc536..487426a9 100644 --- a/bauh/gems/appimage/resources/locale/en +++ b/bauh/gems/appimage/resources/locale/en @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Upgrade file appimage.custom_action.manual_update.desc=Replaces the installed AppImage file by another one appimage.custom_action.manual_update.details=AppImage upgrade details appimage.custom_action.manual_update.status=Upgrading +appimage.custom_action.self_install=Install bauh +appimage.custom_action.self_install.desc=Installs bauh on the system and adds its icons to the menu +appimage.custom_action.self_install.status=Installing bauh appimage.custom_action.update_db=Update database appimage.custom_action.update_db.desc=Downloads updated files from the AppImage applications database appimage.custom_action.update_db.status=Updating database diff --git a/bauh/gems/appimage/resources/locale/es b/bauh/gems/appimage/resources/locale/es index 454b69d8..e98a0ccb 100644 --- a/bauh/gems/appimage/resources/locale/es +++ b/bauh/gems/appimage/resources/locale/es @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Actualizar archivo appimage.custom_action.manual_update.desc=Reemplaza el archivo AppImage instalado por otro appimage.custom_action.manual_update.details=Detalles de actualización de AppImage appimage.custom_action.manual_update.status=Actualizando +appimage.custom_action.self_install=Instalar el bauh +appimage.custom_action.self_install.desc=Instala el bauh en el sistema y agrega sus íconos al menú +appimage.custom_action.self_install.status=Instalando el bauh appimage.custom_action.update_db=Actualizar base de datos appimage.custom_action.update_db.desc=Descarga archivos actualizados de la base de datos de aplicaciones AppImage appimage.custom_action.update_db.status=Actualizando base de datos @@ -48,4 +51,4 @@ 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 {} appimage.warning.missing_db_files=No se encontraron archivos de la base de datos {appimage}. Algunas acciones no funcionarán correctamente. gem.appimage.info=Aplicativos publicados en https://appimage.github.io/ -gem.appimage.label=AppImage \ No newline at end of file +gem.appimage.label=AppImage diff --git a/bauh/gems/appimage/resources/locale/fr b/bauh/gems/appimage/resources/locale/fr index 792d2682..996bf8f9 100644 --- a/bauh/gems/appimage/resources/locale/fr +++ b/bauh/gems/appimage/resources/locale/fr @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Mettre fichier à jour appimage.custom_action.manual_update.desc=Replaces the installed AppImage file by another one appimage.custom_action.manual_update.details=Détails de mise à jour appimage.custom_action.manual_update.status=Mise à jour +appimage.custom_action.self_install=Install bauh +appimage.custom_action.self_install.desc=Installs bauh on the system and adds its icons to the menu +appimage.custom_action.self_install.status=Installing bauh appimage.custom_action.update_db=Update database appimage.custom_action.update_db.desc=Downloads updated files from the AppImage applications database appimage.custom_action.update_db.status=Updating database diff --git a/bauh/gems/appimage/resources/locale/it b/bauh/gems/appimage/resources/locale/it index cfd6b3c9..9ce0ce39 100644 --- a/bauh/gems/appimage/resources/locale/it +++ b/bauh/gems/appimage/resources/locale/it @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Upgrade file appimage.custom_action.manual_update.desc=Replaces the installed AppImage file by another one appimage.custom_action.manual_update.details=AppImage upgrade details appimage.custom_action.manual_update.status=Upgrading +appimage.custom_action.self_install=Install bauh +appimage.custom_action.self_install.desc=Installs bauh on the system and adds its icons to the menu +appimage.custom_action.self_install.status=Installing bauh appimage.custom_action.update_db=Update database appimage.custom_action.update_db.desc=Downloads updated files from the AppImage applications database appimage.custom_action.update_db.status=Updating database diff --git a/bauh/gems/appimage/resources/locale/pt b/bauh/gems/appimage/resources/locale/pt index 284dbb2f..572d8d05 100644 --- a/bauh/gems/appimage/resources/locale/pt +++ b/bauh/gems/appimage/resources/locale/pt @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Atualizar arquivo appimage.custom_action.manual_update.desc=Subsitui o arquivo AppImage instalado por outro appimage.custom_action.manual_update.details=Detalhes de atualização de AppImage appimage.custom_action.manual_update.status=Atualizando +appimage.custom_action.self_install=Instalar o bauh +appimage.custom_action.self_install.desc=Instala o bauh no sistema e adiciona os ícones no menu +appimage.custom_action.self_install.status=Instalando o bauh appimage.custom_action.update_db=Atualizar banco de dados appimage.custom_action.update_db.desc=Baixa arquivos atualizados da base de dados de aplicações AppImage appimage.custom_action.update_db.status=Atualizando banco de dados @@ -48,4 +51,4 @@ 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 {} appimage.warning.missing_db_files=Arquivos do banco de dados {appimage} não foram encontrados. Algumas ações não funcionarão corretamente. gem.appimage.info=Aplicativos publicados em https://appimage.github.io/ -gem.appimage.label=AppImage \ No newline at end of file +gem.appimage.label=AppImage diff --git a/bauh/gems/appimage/resources/locale/ru b/bauh/gems/appimage/resources/locale/ru index 3b37d2ab..0dbbd329 100644 --- a/bauh/gems/appimage/resources/locale/ru +++ b/bauh/gems/appimage/resources/locale/ru @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Обновить файл appimage.custom_action.manual_update.desc=Replaces the installed AppImage file by another one appimage.custom_action.manual_update.details=Детали обновления appimage.custom_action.manual_update.status=Обновляется... +appimage.custom_action.self_install=Install bauh +appimage.custom_action.self_install.desc=Installs bauh on the system and adds its icons to the menu +appimage.custom_action.self_install.status=Installing bauh appimage.custom_action.update_db=Update database appimage.custom_action.update_db.desc=Downloads updated files from the AppImage applications database appimage.custom_action.update_db.status=Updating database diff --git a/bauh/gems/appimage/resources/locale/tr b/bauh/gems/appimage/resources/locale/tr index 1b8f4f1c..a2b83e0f 100644 --- a/bauh/gems/appimage/resources/locale/tr +++ b/bauh/gems/appimage/resources/locale/tr @@ -12,6 +12,9 @@ appimage.custom_action.manual_update=Yükseltme dosyası appimage.custom_action.manual_update.desc=Replaces the installed AppImage file by another one appimage.custom_action.manual_update.details=Yükseltme ayrıntıları appimage.custom_action.manual_update.status=Yükseltiliyor +appimage.custom_action.self_install=Install bauh +appimage.custom_action.self_install.desc=Installs bauh on the system and adds its icons to the menu +appimage.custom_action.self_install.status=Installing bauh appimage.custom_action.update_db=Update database appimage.custom_action.update_db.desc=Downloads updated files from the AppImage applications database appimage.custom_action.update_db.status=Updating database diff --git a/bauh/view/qt/window.py b/bauh/view/qt/window.py index c4a89a2f..da1fff3d 100755 --- a/bauh/view/qt/window.py +++ b/bauh/view/qt/window.py @@ -1465,6 +1465,7 @@ class ManageWindow(QWidget): if res['success']: if res['action'].refresh: self.comp_manager.remove_saved_state(ACTION_CUSTOM_ACTION) + self.update_custom_actions() self.begin_refresh_packages(pkg_types={res['pkg'].model.__class__} if res['pkg'] else None) else: self.comp_manager.restore_state(ACTION_CUSTOM_ACTION)