diff --git a/CHANGELOG.md b/CHANGELOG.md index fa45bd9b..386beda1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,34 @@ 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.6.2] 2019-10-02 +### Improvements +- Update notifications showing the number of updates by type as well ( if there are from more than one packaging type ) +- Snap: + - **Installed** info field split into **version** and **size** +- AUR: + - Installed files available in the Info window + - Improving Arch distro checking + +### Fixes +- Update-check daemon not showing notifications +- Not retrieving the system default locale to translate the application texts +- Not updating translations when the default locale is different from 'en' +- Installed button available after a recent installation if a new search is done +- Flatpak: + - error when retrieving information ( Flatpak 1.0.X ) +- Snap: + - apps with commands different from their names do not launch +- AUR: + - ignoring downgrade warnings for different locales + ## [0.6.1] 2019-09-26 -### Improvements: +### Improvements - Better warning presentation when there are several messages - Better AUR update check handling - "Show" button available for all information fields -### Fixes: +### Fixes - Error when retrieving suggestions - snapd health check when snapd.service is available - AUR: not showing all optional dependencies ( Info ) diff --git a/README.md b/README.md index fdb561ed..ac06fdcf 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,9 @@ -## bauh - **bauh** ( ba-oo ) is a graphical user interface to manage your Linux applications ( packages ) ( old **fpakman** ). It currently supports Flatpak, Snap and AUR packaging types. When you launch **bauh** you will see a management panel where you can search, update, install, uninstall and launch applications. You can also downgrade some applications depending on the package technology. It has a **tray mode** (see **Settings** below) that attaches the application icon to the system tray providing a quick way to launch it. Also the icon will get red when updates are available. -This project has an official Twitter account ( **@bauh4linux**) so people can stay on top of its news. +This project has an official Twitter account ( **@bauh4linux** ) so people can stay on top of its news. ### Developed with: - Python3 and Qt5. @@ -94,7 +92,7 @@ You can change some application settings via environment variables or arguments - It is **not enabled by default** - The user is able to search, install, uninstall, downgrade, launch and retrieve the packages history - It handles conflicts, and missing / optional packages installations ( including from your distro mirrors ) -- If (**aria2**) [https://github.com/aria2/aria2] is installed on your system and multi-threaded downloads are enabled ( see **BAUH_DOWNLOAD_MULTITHREAD** ), the source packages +- If [**aria2**](https://github.com/aria2/aria2) is installed on your system and multi-threaded downloads are enabled ( see **BAUH_DOWNLOAD_MULTITHREAD** ), the source packages will be pre-downloaded faster ( it does **NOT** modify your **pacman** settings ). - Automatically makes simple package compilation improvements diff --git a/aur/panel_entry.py b/aur/panel_entry.py index 54cbca25..9e488211 100644 --- a/aur/panel_entry.py +++ b/aur/panel_entry.py @@ -1,24 +1,15 @@ # Generates a .desktop file based on the current python version. Used for AUR installation import os import sys -import locale - -system_locale = locale.getdefaultlocale() -system_locale = system_locale[0].split('_')[0] if system_locale and isinstance(system_locale, list) else 'en' - -if system_locale == 'pt': - comment = "Gerencie seus aplicativos Flatpak / Snap / AUR " -elif system_locale == 'es': - comment = "Administre sus aplicaciones Flatpak / Snap / AUR" -else: - comment = "Manage your Flatpak / Snap / AUR applications" desktop_file = """ [Desktop Entry] -Type = Application -Name = bauh -Categories = System; -Comment = {comment} +Type=Application +Name=bauh +Categories=System; +Comment=Manage your Flatpak / Snap / AUR applications +Comment[pt]=Gerencie seus aplicativos Flatpak / Snap / AUR +Comment[es]=Administre sus aplicaciones Flatpak / Snap / AUR Exec = {path} Icon = {lib_path}/python{version}/site-packages/bauh/view/resources/img/logo.svg """ @@ -30,5 +21,4 @@ app_cmd = os.getenv('BAUH_PATH', '/usr/bin/bauh') with open('bauh.desktop', 'w+') as f: f.write(desktop_file.format(lib_path=os.getenv('BAUH_LIB_PATH', '/usr/lib'), version=py_version, - path=app_cmd, - comment=comment)) + path=app_cmd)) diff --git a/aur/tray_entry.py b/aur/tray_entry.py index 792409ba..8e48c4d0 100644 --- a/aur/tray_entry.py +++ b/aur/tray_entry.py @@ -1,27 +1,18 @@ # Generates a .desktop file based on the current python version. Used for AUR installation -import locale import os import sys -system_locale = locale.getdefaultlocale() -system_locale = system_locale[0].split('_')[0] if system_locale and isinstance(system_locale, list) else 'en' - -if system_locale == 'pt': - comment = "Gerencie seus aplicativos Flatpak / Snap / AUR " - tray = 'bandeja' -elif system_locale == 'es': - comment = "Administre sus aplicativos Flatpak / Snap / AUR" - tray = 'bandeja' -else: - comment = "Manage your Flatpak / Snap / AUR applications" - tray = 'tray' desktop_file = """ [Desktop Entry] Type = Application -Name = bauh ( {tray} ) +Name = bauh ( tray ) +Name[pt] = bauh ( bandeja ) +Name[es] = bauh ( bandeja ) Categories = System; -Comment = {comment} +Comment=Manage your Flatpak / Snap / AUR applications +Comment[pt]=Gerencie seus aplicativos Flatpak / Snap / AUR +Comment[es]=Administre sus aplicaciones Flatpak / Snap / AUR Exec = {path} Icon = {lib_path}/python{version}/site-packages/bauh/view/resources/img/logo.svg """ @@ -33,9 +24,7 @@ app_cmd = os.getenv('BAUH_PATH', '/usr/bin/bauh') + ' --tray=1' with open('bauh_tray.desktop', 'w+') as f: f.write(desktop_file.format(lib_path=os.getenv('BAUH_LIB_PATH', '/usr/lib'), version=py_version, - path=app_cmd, - comment=comment, - tray=tray)) + path=app_cmd)) with open('bauh-tray', 'w') as f: diff --git a/bauh/__init__.py b/bauh/__init__.py index 68a0a495..3f5655f4 100644 --- a/bauh/__init__.py +++ b/bauh/__init__.py @@ -1,4 +1,4 @@ -__version__ = '0.6.1' +__version__ = '0.6.2' __app_name__ = 'bauh' import os diff --git a/bauh/api/abstract/context.py b/bauh/api/abstract/context.py index 131f35c6..581fa40a 100644 --- a/bauh/api/abstract/context.py +++ b/bauh/api/abstract/context.py @@ -32,7 +32,6 @@ class ApplicationContext: self.cache_factory = cache_factory self.disk_loader_factory = disk_loader_factory self.logger = logger - self.linux_distro = platform.linux_distribution() self.file_downloader = file_downloader self.arch_x86_64 = sys.maxsize > 2**32 diff --git a/bauh/api/abstract/controller.py b/bauh/api/abstract/controller.py index abb3d4b6..6c3b1370 100644 --- a/bauh/api/abstract/controller.py +++ b/bauh/api/abstract/controller.py @@ -196,8 +196,9 @@ class SoftwareManager(ABC): pass @abstractmethod - def list_updates(self) -> List[PackageUpdate]: + def list_updates(self, internet_available: bool) -> List[PackageUpdate]: """ + :param internet_available :return: available package updates """ pass diff --git a/bauh/app.py b/bauh/app.py index e947cafb..bab13b2a 100755 --- a/bauh/app.py +++ b/bauh/app.py @@ -25,7 +25,7 @@ def main(): logger = logs.new_logger(__app_name__, bool(args.logs)) app_args.validate(args, logger) - i18n = util.get_locale_keys(args.locale) + i18n_key, i18n = util.get_locale_keys(args.locale) cache_cleaner = CacheCleaner() cache_factory = DefaultMemoryCacheFactory(expiration_time=args.cache_exp, cleaner=cache_cleaner) @@ -53,7 +53,7 @@ def main(): if app.style().objectName().lower() not in {'fusion', 'breeze'}: app.setStyle('Fusion') - managers = gems.load_managers(context=context, locale=args.locale, config=user_config) + managers = gems.load_managers(context=context, locale=i18n_key, config=user_config) manager = GenericSoftwareManager(managers, context=context, app_args=args) manager.prepare() diff --git a/bauh/app_args.py b/bauh/app_args.py index 5460a7de..ee7ab010 100644 --- a/bauh/app_args.py +++ b/bauh/app_args.py @@ -14,8 +14,7 @@ def read() -> Namespace: help='default memory caches expiration time in SECONDS. Default: %(default)s') parser.add_argument('-ie', '--icon-exp', action="store", default=int(os.getenv('BAUH_ICON_EXPIRATION', 60 * 5)), type=int, help='cached icons expiration time in SECONDS. Default: %(default)s') - parser.add_argument('-l', '--locale', action="store", default=os.getenv('BAUH_LOCALE', 'en'), - help='Translation key. Default: %(default)s') + parser.add_argument('-l', '--locale', action="store", default=os.getenv('BAUH_LOCALE'), help='Locale key. e.g: en, es, pt, ...') parser.add_argument('-i', '--check-interval', action="store", default=int(os.getenv('BAUH_CHECK_INTERVAL', 60)), type=int, help='Updates check interval in SECONDS. Default: %(default)s') parser.add_argument('-n', '--system-notifications', action="store", choices=[0, 1], @@ -48,7 +47,7 @@ def validate(args: Namespace, logger: logging.Logger): if args.icon_exp < 0: logger.info("'icon-exp' set to '{}': cache will not expire.".format(args.cache_exp)) - if not args.locale.strip(): + if args.locale and not args.locale.strip(): logger.info("'locale' set as '{}'. You must provide a valid one. Aborting...".format(args.locale)) exit(1) diff --git a/bauh/commons/system.py b/bauh/commons/system.py index 3990a5aa..ab37903f 100644 --- a/bauh/commons/system.py +++ b/bauh/commons/system.py @@ -210,7 +210,8 @@ def new_root_subprocess(cmd: List[str], root_password: str, cwd: str = '.', pwdin = new_subprocess(['echo', root_password], global_interpreter=global_interpreter, lang=lang).stdout final_cmd.extend(cmd) - return subprocess.Popen(final_cmd, stdin=pwdin, stdout=PIPE, stderr=PIPE, cwd=cwd) + + return subprocess.Popen(final_cmd, stdin=pwdin, stdout=PIPE, stderr=PIPE, cwd=cwd, env=gen_env(global_interpreter, lang)) def notify_user(msg: str, app_name: str, icon_path: str): diff --git a/bauh/gems/arch/controller.py b/bauh/gems/arch/controller.py index 38dccd7d..9c55b258 100644 --- a/bauh/gems/arch/controller.py +++ b/bauh/gems/arch/controller.py @@ -50,7 +50,7 @@ class ArchManager(SoftwareManager): self.comp_optimizer = ArchCompilationOptimizer(context.logger) self.logger = context.logger self.enabled = True - self.arch_distro = self.context.linux_distro[0].lower() == 'arch' + self.arch_distro = os.path.exists('/etc/arch-release') def _upgrade_search_result(self, apidata: dict, installed_pkgs: dict, downgrade_enabled: bool, res: SearchResult, disk_loader: DiskCacheLoader): app = self.mapper.map_api_data(apidata, installed_pkgs['not_signed']) @@ -156,6 +156,7 @@ class ArchManager(SoftwareManager): apps = [] if installed and installed['not_signed']: self.dcache_updater.join() + self._fill_aur_pkgs(installed['not_signed'], apps, disk_loader, internet_available) return SearchResult(apps, None, len(apps)) @@ -270,6 +271,8 @@ class ArchManager(SoftwareManager): if pkg.pkgbuild: info['13_pkg_build'] = pkg.pkgbuild + info['14_installed_files'] = pacman.list_installed_files(pkg.name) + return info else: info = { @@ -295,7 +298,7 @@ class ArchManager(SoftwareManager): info['12_optdepends'] = srcinfo['optdepends'] if pkg.pkgbuild: - info['13_pkg_build'] = pkg.pkgbuild + info['00_pkg_build'] = pkg.pkgbuild else: info['11_pkg_build_url'] = pkg.get_pkg_build_url() @@ -422,7 +425,7 @@ class ArchManager(SoftwareManager): # building main package handler.watcher.change_substatus(self.i18n['arch.building.package'].format(bold(pkgname))) - pkgbuilt, output = handler.handle_simple(SimpleProcess(['makepkg', '-ALcsmf'], cwd=project_dir, lang=None)) + pkgbuilt, output = handler.handle_simple(SimpleProcess(['makepkg', '-ALcsmf'], cwd=project_dir)) self._update_progress(handler.watcher, 65, change_progress) if pkgbuilt: @@ -689,8 +692,9 @@ class ArchManager(SoftwareManager): self.comp_optimizer.start() self.aur_index_updater.start() - def list_updates(self) -> List[PackageUpdate]: - return [PackageUpdate(app.id, app.latest_version, 'aur') for app in self.read_installed(disk_loader=None).installed if app.update] + def list_updates(self, internet_available: bool) -> List[PackageUpdate]: + installed = self.read_installed(disk_loader=None, internet_available=internet_available).installed + return [PackageUpdate(p.id, p.latest_version, 'aur') for p in installed if p.update] def list_warnings(self) -> List[str]: warnings = [] diff --git a/bauh/gems/arch/pacman.py b/bauh/gems/arch/pacman.py index a08c51b4..b68ff21b 100644 --- a/bauh/gems/arch/pacman.py +++ b/bauh/gems/arch/pacman.py @@ -150,6 +150,20 @@ def list_bin_paths(pkgnames: Set[str]) -> List[str]: return bin_paths +def list_installed_files(pkgname: str) -> List[str]: + installed_files = new_subprocess(['pacman', '-Qlq', pkgname]) + + f_paths = [] + + for out in new_subprocess(['grep', '-E', '/.+\..+[^/]$'], stdin=installed_files.stdout).stdout: + if out: + line = out.decode().strip() + if line: + f_paths.append(line) + + return f_paths + + def verify_pgp_key(key: str) -> bool: list_key = new_subprocess(['pacman-key', '-l']).stdout @@ -168,3 +182,4 @@ def receive_key(key: str, root_password: str) -> SystemProcess: def sign_key(key: str, root_password: str) -> SystemProcess: return SystemProcess(new_root_subprocess(['pacman-key', '--lsign-key', key], root_password=root_password), check_error_output=False) + diff --git a/bauh/gems/arch/resources/locale/en b/bauh/gems/arch/resources/locale/en index c3af4bfa..d6ed0e17 100644 --- a/bauh/gems/arch/resources/locale/en +++ b/bauh/gems/arch/resources/locale/en @@ -22,6 +22,7 @@ arch.clone=Cloning the AUR repository {} arch.downgrade.reading_commits=Reading the repository commits arch.downgrade.version_found=Current package version found arch.downgrade.install_older=Installing older version +aur.info.00_pkg_build=pkgbuild aur.info.01_id=id aur.info.02_name=name aur.info.03_version=version @@ -36,6 +37,7 @@ aur.info.11_pkg_build_url=url pkgbuild aur.info.13_pkg_build=pkgbuild aur.info.11_dependson=dependencies aur.info.12_optdepends=optional dependencies +aur.info.14_installed_files=Installed files arch.install.dep_not_found.title=Dependency not found arch.install.dep_not_found.body=Required dependency {} was not found in AUR nor in default mirrors. Installation cancelled. arch.install.dependency.install=Installing package dependency {} diff --git a/bauh/gems/arch/resources/locale/es b/bauh/gems/arch/resources/locale/es index 5c72e2b2..6bd4da7d 100644 --- a/bauh/gems/arch/resources/locale/es +++ b/bauh/gems/arch/resources/locale/es @@ -54,6 +54,7 @@ arch.clone=Clonando el repositorio {} de AUR arch.downgrade.reading_commits=Leyendo los commits del repositorio arch.downgrade.version_found=Version actual del paquete encontrada arch.downgrade.install_older=Instalando versión anterior +aur.info.00_pkg_build=pkgbuild aur.info.01_id=id aur.info.02_name=nombre aur.info.03_version=versión @@ -68,6 +69,7 @@ aur.info.11_pkg_build_url=url pkgbuild aur.info.13_pkg_build=pkgbuild aur.info.11_dependson=dependencias aur.info.12_optdepends=dependencias opcionales +aur.info.14_installed_files=Archivos instalados arch.install.dep_not_found.title=Dependencia no encontrada arch.install.dep_not_found.body=No se encontró la dependencia requerida {} en AUR ni en los espejos predeterminados. Instalación cancelada. arch.install.dependency.install=Instalando el paquete dependiente {} diff --git a/bauh/gems/arch/resources/locale/pt b/bauh/gems/arch/resources/locale/pt index 03760cc0..d762e500 100644 --- a/bauh/gems/arch/resources/locale/pt +++ b/bauh/gems/arch/resources/locale/pt @@ -54,6 +54,7 @@ arch.clone=Clonando o repositório {} do AUR arch.downgrade.reading_commits=Lendo os commits do repositório arch.downgrade.version_found=Versão atual do pacote encontrada arch.downgrade.install_older=Instalando versão anterior +aur.info.00_pkg_build=pkgbuild aur.info.01_id=id aur.info.02_name=nome aur.info.03_version=versão @@ -68,6 +69,7 @@ aur.info.11_pkg_build_url=url pkgbuild aur.info.13_pkg_build=pkgbuild aur.info.11_dependson=dependências aur.info.12_optdepends=dependências opcionais +aur.info.14_installed_files=Arquivos instalados arch.install.dep_not_found.title=Dependência não encontrada arch.install.dep_not_found.body=A dependência {} não foi encontrado no AUR nem nos espelhos padrões. Instalação cancelada. arch.install.dependency.install=Instalando o pacote dependente {} diff --git a/bauh/gems/flatpak/controller.py b/bauh/gems/flatpak/controller.py index 0a279119..ad9dc692 100644 --- a/bauh/gems/flatpak/controller.py +++ b/bauh/gems/flatpak/controller.py @@ -139,7 +139,10 @@ class FlatpakManager(SoftwareManager): app_info['name'] = app.name app_info['type'] = 'runtime' if app.runtime else 'app' app_info['description'] = strip_html(app.description) if app.description else '' - app_info['installed'] = app_info['installed'].replace('?', ' ') + + if app_info.get('installed'): + app_info['installed'] = app_info['installed'].replace('?', ' ') + return app_info def get_history(self, pkg: FlatpakApplication) -> PackageHistory: @@ -184,26 +187,28 @@ class FlatpakManager(SoftwareManager): def prepare(self): pass - def list_updates(self) -> List[PackageUpdate]: - to_update = [app for app in self.read_installed(None).installed if app.update] + def list_updates(self, internet_available: bool) -> List[PackageUpdate]: updates = [] + installed = self.read_installed(None, internet_available=internet_available).installed + + to_update = [p for p in installed if p.update] if to_update: - loaders = [] + loaders = [] - for app in to_update: - if app.is_application(): - loader = FlatpakUpdateLoader(app=app, http_client=self.context.http_client) - loader.start() - loaders.append(loader) + for app in to_update: + if app.is_application(): + loader = FlatpakUpdateLoader(app=app, http_client=self.context.http_client) + loader.start() + loaders.append(loader) - for loader in loaders: - loader.join() + for loader in loaders: + loader.join() - for app in to_update: - updates.append(PackageUpdate(pkg_id='{}:{}'.format(app.id, app.branch), - pkg_type='flatpak', - version=app.version)) + for app in to_update: + updates.append(PackageUpdate(pkg_id='{}:{}'.format(app.id, app.branch), + pkg_type='flatpak', + version=app.version)) return updates diff --git a/bauh/gems/snap/controller.py b/bauh/gems/snap/controller.py index 1bcbd3a4..7496f730 100644 --- a/bauh/gems/snap/controller.py +++ b/bauh/gems/snap/controller.py @@ -140,7 +140,7 @@ class SnapManager(SoftwareManager): def prepare(self): pass - def list_updates(self) -> List[PackageUpdate]: + def list_updates(self, internet_available: bool) -> List[PackageUpdate]: pass def list_warnings(self) -> List[str]: diff --git a/bauh/gems/snap/resources/locale/es b/bauh/gems/snap/resources/locale/es index 1d31611a..0c7c5f7a 100644 --- a/bauh/gems/snap/resources/locale/es +++ b/bauh/gems/snap/resources/locale/es @@ -7,6 +7,8 @@ snap.info.revision=revisión snap.info.tracking=tracking snap.info.installed=instalado snap.info.publisher=publicador +snap.info.version=versión +snap.info.size=tamaño snap.notification.snapd_unavailable={} no parece estar instalado o habilitado. Los paquetes {} estarán indisponibles. snap.notification.snap.disable=Si no desea usar aplicativos Snap, desmarque {} en {} snap.action.refresh.status=Actualizando diff --git a/bauh/gems/snap/resources/locale/pt b/bauh/gems/snap/resources/locale/pt index efd0aa98..8d0c9d16 100644 --- a/bauh/gems/snap/resources/locale/pt +++ b/bauh/gems/snap/resources/locale/pt @@ -7,6 +7,8 @@ snap.info.revision=revisão snap.info.tracking=tracking snap.info.installed=instalado snap.info.publisher=publicador +snap.info.version=versão +snap.info.size=tamanho snap.notification.snapd_unavailable={} não parece estar instalado ou habilitado. Os pacotes {} estarão indisponíveis. snap.notification.snap.disable=Se não deseja usar aplicativos Snap, desmarque {} em {} snap.action.refresh.status=Atualizando diff --git a/bauh/gems/snap/snap.py b/bauh/gems/snap/snap.py index 04e20de2..7338a0f5 100644 --- a/bauh/gems/snap/snap.py +++ b/bauh/gems/snap/snap.py @@ -63,7 +63,16 @@ def get_info(app_name: str, attrs: tuple = None): info_map = re.findall(r'({}):\s+(.+)'.format(re_attrs), full_info_lines) for info in info_map: - data[info[0]] = info[1].strip() + val = info[1].strip() + + if info[0] == 'installed': + val_split = [s for s in val.split(' ') if s] + data['version'] = val_split[0] + + if len(val_split) > 2: + data['size'] = val_split[2] + else: + data[info[0]] = val if not attrs or 'description' in attrs: desc = re.findall(r'\|\n+((\s+.+\n+)+)', full_info_lines) @@ -180,7 +189,7 @@ def run(app: SnapApplication, logger: logging.Logger): break if not command: - for c in command: + for c in commands: if not c.endswith('.apm'): command = c diff --git a/bauh/view/core/controller.py b/bauh/view/core/controller.py index f7a2ff67..1ce55f1e 100755 --- a/bauh/view/core/controller.py +++ b/bauh/view/core/controller.py @@ -143,12 +143,12 @@ class GenericSoftwareManager(SoftwareManager): t.start() return t - def read_installed(self, disk_loader: DiskCacheLoader = None, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult: + def read_installed(self, disk_loader: DiskCacheLoader = None, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, net_check: bool = None) -> SearchResult: ti = time.time() self._wait_to_be_ready() - internet_available = {} - thread_internet_check = self._get_internet_check(internet_available) + net_check = {} + thread_internet_check = self._get_internet_check(net_check) res = SearchResult([], None, 0) @@ -165,7 +165,7 @@ class GenericSoftwareManager(SoftwareManager): thread_internet_check.join() mti = time.time() - man_res = man.read_installed(disk_loader=disk_loader, pkg_types=None, internet_available=internet_available['available']) + man_res = man.read_installed(disk_loader=disk_loader, pkg_types=None, internet_available=net_check['available']) mtf = time.time() self.logger.info(man.__class__.__name__ + " took {0:.2f} seconds".format(mtf - mti)) @@ -184,7 +184,7 @@ class GenericSoftwareManager(SoftwareManager): thread_internet_check.join() mti = time.time() - man_res = man.read_installed(disk_loader=disk_loader, pkg_types=None, internet_available=internet_available['available']) + man_res = man.read_installed(disk_loader=disk_loader, pkg_types=None, internet_available=net_check['available']) mtf = time.time() self.logger.info(man.__class__.__name__ + " took {0:.2f} seconds".format(mtf - mti)) @@ -286,15 +286,22 @@ class GenericSoftwareManager(SoftwareManager): self.thread_prepare = Thread(target=self._prepare) self.thread_prepare.start() - def list_updates(self) -> List[PackageUpdate]: + def list_updates(self, net_check: bool = None) -> List[PackageUpdate]: self._wait_to_be_ready() updates = [] if self.managers: + net_check = {} + thread_internet_check = self._get_internet_check(net_check) + for man in self.managers: if self._can_work(man): - man_updates = man.list_updates() + + if thread_internet_check.is_alive(): + thread_internet_check.join() + + man_updates = man.list_updates(internet_available=net_check['available']) if man_updates: updates.extend(man_updates) diff --git a/bauh/view/core/gems.py b/bauh/view/core/gems.py index b97e482f..5ee0175b 100644 --- a/bauh/view/core/gems.py +++ b/bauh/view/core/gems.py @@ -34,7 +34,7 @@ def load_managers(locale: str, context: ApplicationContext, config: Configuratio locale_path = '{}/resources/locale'.format(f.path) if os.path.exists(locale_path): - context.i18n.update(util.get_locale_keys(locale, locale_path)) + context.i18n.update(util.get_locale_keys(locale, locale_path)[1]) man = manager_class(context=context) diff --git a/bauh/view/qt/systray.py b/bauh/view/qt/systray.py index 0b5d1cab..f2d90bc7 100755 --- a/bauh/view/qt/systray.py +++ b/bauh/view/qt/systray.py @@ -1,4 +1,5 @@ import time +from io import StringIO from threading import Lock, Thread from typing import List @@ -96,7 +97,23 @@ class TrayIcon(QSystemTrayIcon): if update_keys.difference(self.last_updates): self.last_updates = update_keys n_updates = len(updates) - msg = self.i18n['notification.update{}'.format('' if n_updates == 1 else 's')].format(n_updates) + ups_by_type = {} + + for key in update_keys: + ptype = key.split(':')[0] + count = ups_by_type.get(ptype) + count = 1 if count is None else count + 1 + ups_by_type[ptype] = count + + msg = StringIO() + msg.write(self.i18n['notification.update{}'.format('' if n_updates == 1 else 's')].format(n_updates)) + + if len(ups_by_type) > 1: + for ptype, count in ups_by_type.items(): + msg.write('\n * {} ( {} )'.format(ptype.capitalize(), count)) + + msg.seek(0) + msg = msg.read() self.setToolTip(msg) if self.update_notification and notify_user: diff --git a/bauh/view/qt/window.py b/bauh/view/qt/window.py index 05693f66..39a0dee3 100755 --- a/bauh/view/qt/window.py +++ b/bauh/view/qt/window.py @@ -261,6 +261,7 @@ class ManageWindow(QWidget): self.filter_updates = False self._maximized = False self.progress_controll_enabled = True + self.recent_installation = False self.dialog_about = None self.first_refresh = suggestions @@ -403,6 +404,7 @@ class ManageWindow(QWidget): self.textarea_output.hide() def refresh_apps(self, keep_console: bool = True, top_app: PackageView = None, pkg_types: Set[Type[SoftwarePackage]] = None): + self.recent_installation = False self.type_filter = None self.input_search.clear() @@ -417,11 +419,11 @@ class ManageWindow(QWidget): self.thread_refresh.pkg_types = pkg_types self.thread_refresh.start() - def _finish_refresh_apps(self, res: dict): + def _finish_refresh_apps(self, res: dict, as_installed: bool = True): self.finish_action() self.ref_checkbox_only_apps.setVisible(bool(res['installed'])) self.ref_bt_upgrade.setVisible(True) - self.update_pkgs(res['installed'], as_installed=True, types=res['types']) + self.update_pkgs(res['installed'], as_installed=as_installed, types=res['types']) self.first_refresh = False def uninstall_app(self, app: PackageView): @@ -618,7 +620,7 @@ class ManageWindow(QWidget): self.thread_verify_models.start() if self.pkgs_installed: - self.ref_bt_installed.setVisible(not as_installed) + self.ref_bt_installed.setVisible(not as_installed and not self.recent_installation) self.resize_and_center(accept_lower_width=self.pkgs_installed) @@ -892,6 +894,7 @@ class ManageWindow(QWidget): self.textarea_output.appendPlainText("[warning] Could not write install log file to '{}'".format(log_path)) if res['success']: + self.recent_installation = True if self._can_notify_user(): util.notify_user(msg='{} ({}) {}'.format(res['pkg'].model.name, res['pkg'].model.get_type(), self.i18n['installed'])) diff --git a/bauh/view/util/util.py b/bauh/view/util/util.py index 7e1f8cc4..8c96029b 100644 --- a/bauh/view/util/util.py +++ b/bauh/view/util/util.py @@ -3,6 +3,7 @@ import locale import os import subprocess import sys +from typing import Tuple from PyQt5.QtCore import QCoreApplication @@ -10,7 +11,7 @@ from bauh import __app_name__ from bauh.view.util import resource -def get_locale_keys(key: str = None, locale_dir: str = resource.get_path('locale')): +def get_locale_keys(key: str = None, locale_dir: str = resource.get_path('locale')) -> Tuple[str, dict]: locale_path = None @@ -41,7 +42,7 @@ def get_locale_keys(key: str = None, locale_dir: str = resource.get_path('locale keyval = line.strip().split('=') locale_obj[keyval[0].strip()] = keyval[1].strip() - return locale_obj + return locale_path.split('/')[-1], locale_obj def notify_user(msg: str, icon_path: str = resource.get_path('img/logo.svg')):