diff --git a/CHANGELOG.md b/CHANGELOG.md index 014cc8c7..64f6f003 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [0.9.19] 2021-08-23 +### Improvements +- AppImage + - manual installation: adding generic file filter extension (.*) since some desktop environments filters are case sensitive [#185](https://github.com/vinifmor/bauh/issues/185) + - installation: generating a default **.desktop** file for AppImages that provide empty desktop entries [#186](https://github.com/vinifmor/bauh/issues/186) + - hiding the app's launching output +- Arch + - AUR: **rebuild-detector** integration disabled by default since it has a great impact on the overall refresh time (it can be enabled through the settings panel -> "Check reinstallation need") +- UI + - not using native dialogs for file/directory choosing to prevent unexpected behaviors and wrong theming + +### Fixes +- AppImage + - search: not matching manually installed applications + - info button remains "clickable" after an imported Appimage is uninstalled + + ## [0.9.18] 2021-06-18 ### Fixes - Arch diff --git a/bauh/__init__.py b/bauh/__init__.py index 1cf69e8d..af228711 100644 --- a/bauh/__init__.py +++ b/bauh/__init__.py @@ -1,4 +1,4 @@ -__version__ = '0.9.18' +__version__ = '0.9.19' __app_name__ = 'bauh' import os diff --git a/bauh/gems/appimage/controller.py b/bauh/gems/appimage/controller.py index b789c6de..dcbac937 100644 --- a/bauh/gems/appimage/controller.py +++ b/bauh/gems/appimage/controller.py @@ -98,7 +98,7 @@ class AppImageManager(SoftwareManager): def install_file(self, root_password: str, watcher: ProcessWatcher) -> bool: file_chooser = FileChooserComponent(label=self.i18n['file'].capitalize(), - allowed_extensions={'AppImage'}, + allowed_extensions={'AppImage', '*'}, search_path=get_default_manual_installation_file_dir()) input_name = TextInputComponent(label=self.i18n['name'].capitalize()) input_version = TextInputComponent(label=self.i18n['version'].capitalize()) @@ -118,7 +118,7 @@ class AppImageManager(SoftwareManager): components=[form], confirmation_label=self.i18n['proceed'].capitalize(), deny_label=self.i18n['cancel'].capitalize()): - if not file_chooser.file_path or not os.path.isfile(file_chooser.file_path): + if not file_chooser.file_path or not os.path.isfile(file_chooser.file_path) or not file_chooser.file_path.lower().strip().endswith('.appimage'): watcher.request_confirmation(title=self.i18n['error'].capitalize(), body=self.i18n['appimage.custom_action.install_file.invalid_file'], deny_button=False) @@ -214,27 +214,30 @@ class AppImageManager(SoftwareManager): except: self.logger.error("An exception happened while querying the 'apps' database") traceback.print_exc() - apps_conn.close() - return SearchResult.empty() + + try: + installed = self.read_installed(connection=apps_conn, disk_loader=disk_loader, limit=limit, only_apps=False, pkg_types=None, internet_available=True).installed + except: + installed = None installed_found = [] - if not_installed: - installed = self.read_installed(disk_loader=disk_loader, limit=limit, - only_apps=False, - pkg_types=None, - connection=apps_conn, - internet_available=True).installed - if installed: - for appim in installed: - key = self._gen_app_key(appim) + if installed: + lower_words = words.lower() + for appim in installed: + found = False + if not_installed and found_map: + key = self._gen_app_key(appim) new_found = found_map.get(key) if new_found: del not_installed[new_found['idx']] installed_found.append(appim) + found = True + if not found and lower_words in appim.name.lower() or (appim.description and lower_words in appim.description.lower()): + installed_found.append(appim) try: apps_conn.close() except: @@ -561,18 +564,24 @@ class AppImageManager(SoftwareManager): with open('{}/{}'.format(extracted_folder, desktop_entry)) as f: de_content = f.read() - de_content = replace_desktop_entry_exec_command(desktop_entry=de_content, - appname=pkg.name, - file_path=file_path) - + if de_content: + de_content = replace_desktop_entry_exec_command(desktop_entry=de_content, + appname=pkg.name, + file_path=file_path) extracted_icon = self._find_icon_file(extracted_folder) if extracted_icon: icon_path = out_dir + '/logo.' + extracted_icon.split('/')[-1].split('.')[-1] shutil.copy(extracted_icon, icon_path) - de_content = RE_DESKTOP_ICON.sub('Icon={}\n'.format(icon_path), de_content) + + if de_content: + de_content = RE_DESKTOP_ICON.sub('Icon={}\n'.format(icon_path), de_content) + pkg.icon_path = icon_path + if not de_content: + de_content = pkg.to_desktop_entry() + Path(DESKTOP_ENTRIES_PATH).mkdir(parents=True, exist_ok=True) with open(self._gen_desktop_entry_path(pkg), 'w+') as f: @@ -706,7 +715,8 @@ class AppImageManager(SoftwareManager): appimag_path = util.find_appimage_file(installation_dir) if appimag_path: - subprocess.Popen(args=[appimag_path], shell=True, env={**os.environ}) + subprocess.Popen(args=[appimag_path], shell=True, env={**os.environ}, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL) else: self.logger.error("Could not find the AppImage file of '{}' in '{}'".format(pkg.name, installation_dir)) diff --git a/bauh/gems/appimage/model.py b/bauh/gems/appimage/model.py index d5a65142..c77921a0 100644 --- a/bauh/gems/appimage/model.py +++ b/bauh/gems/appimage/model.py @@ -1,4 +1,5 @@ import re +from io import StringIO from typing import List, Optional from bauh.api.abstract.model import SoftwarePackage, CustomSoftwareAction @@ -49,7 +50,7 @@ class AppImage(SoftwarePackage): return self.installed and not self.imported def has_info(self): - return True + return self.installed if self.imported else True def can_be_downgraded(self): return self.installed and not self.imported @@ -127,3 +128,23 @@ class AppImage(SoftwarePackage): def get_clean_name(self) -> Optional[str]: if self.name: return RE_MANY_SPACES.sub('-', self.name.lower().strip()) + + def to_desktop_entry(self) -> str: + de = StringIO() + de.write("[Desktop Entry]\nType=Application\nName={}\n".format(self.name)) + + if self.description: + de.write("Comment={}\n".format(self.description.replace('\n', ' '))) + + if self.install_dir and self.local_file_path: + de.write('Exec="{}/{}"\n'.format(self.install_dir, self.local_file_path.split('/')[-1])) + + if self.icon_path: + de.write('Icon={}\n'.format(self.icon_path)) + + if self.categories: + de.write('Categories={};\n'.format(';'.join((c for c in self.categories if c.lower() != 'imported')))) + + de.write('Terminal=false') + de.seek(0) + return de.read() diff --git a/bauh/gems/arch/config.py b/bauh/gems/arch/config.py index d1261f83..72280920 100644 --- a/bauh/gems/arch/config.py +++ b/bauh/gems/arch/config.py @@ -39,5 +39,5 @@ class ArchConfigManager(YAMLConfigManager): 'suggest_optdep_uninstall': False, 'aur_idx_exp': 1, 'categories_exp': 24, - 'aur_rebuild_detector': True, + 'aur_rebuild_detector': False, "aur_rebuild_detector_no_bin": True} diff --git a/bauh/view/qt/components.py b/bauh/view/qt/components.py index e389207e..b43abeae 100644 --- a/bauh/view/qt/components.py +++ b/bauh/view/qt/components.py @@ -870,9 +870,11 @@ class FormQt(QGroupBox): cur_path = str(Path.home()) if c.directory: - file_path = QFileDialog.getExistingDirectory(self, self.i18n['file_chooser.title'], cur_path, options=QFileDialog.Options()) + opts = QFileDialog.DontUseNativeDialog + opts |= QFileDialog.ShowDirsOnly + file_path = QFileDialog.getExistingDirectory(self, self.i18n['file_chooser.title'], cur_path, options=opts) else: - file_path, _ = QFileDialog.getOpenFileName(self, self.i18n['file_chooser.title'], cur_path, exts, options=QFileDialog.Options()) + file_path, _ = QFileDialog.getOpenFileName(self, self.i18n['file_chooser.title'], cur_path, exts, options=QFileDialog.DontUseNativeDialog) if file_path: c.set_file_path(file_path)