From e40fe27bd1fd6e068cd26db2e5153b9ecc4ad1ac Mon Sep 17 00:00:00 2001 From: Vinicius Moreira Date: Tue, 12 Apr 2022 12:29:56 -0300 Subject: [PATCH] [flatpak] fix: not displaying new required runtimes as updates --- CHANGELOG.md | 5 ++- bauh/commons/system.py | 4 ++- bauh/gems/flatpak/controller.py | 55 +++++++++++++++++++++++++++++---- bauh/gems/flatpak/flatpak.py | 55 +++++++++++++++++++++++++-------- bauh/gems/flatpak/model.py | 14 +++++---- 5 files changed, 106 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a35452a..914194b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

- + +- Flatpak + - faster updates reading (threaded) - Debian - install: installation/download sizes order (to follow the upgrade dialog order) @@ -47,6 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Flatpak - some updates not being displayed when there are new required runtimes for installed Flatpaks + - not displaying new required runtimes as updates (requires Flatpak >= 1.12) - UI - not displaying the right unit symbol for byte based sizes (kB, MB, TB, ...) [#250](https://github.com/vinifmor/bauh/issues/250) diff --git a/bauh/commons/system.py b/bauh/commons/system.py index bbab5e09..980c898e 100644 --- a/bauh/commons/system.py +++ b/bauh/commons/system.py @@ -26,7 +26,9 @@ USE_GLOBAL_INTERPRETER = bool(os.getenv('VIRTUAL_ENV')) RE_SUDO_OUTPUT = re.compile(r'[sudo]\s*[\w\s]+:\s*') -def gen_env(global_interpreter: bool, lang: Optional[str] = DEFAULT_LANG, extra_paths: Optional[Set[str]] = None) -> dict: +def gen_env(global_interpreter: bool = USE_GLOBAL_INTERPRETER, lang: Optional[str] = DEFAULT_LANG, + extra_paths: Optional[Set[str]] = None) -> dict: + custom_env = dict(os.environ) if lang is not None: diff --git a/bauh/gems/flatpak/controller.py b/bauh/gems/flatpak/controller.py index 0921ba48..c88fa10f 100644 --- a/bauh/gems/flatpak/controller.py +++ b/bauh/gems/flatpak/controller.py @@ -5,7 +5,7 @@ from datetime import datetime from math import floor from pathlib import Path from threading import Thread -from typing import List, Set, Type, Tuple, Optional, Generator +from typing import List, Set, Type, Tuple, Optional, Generator, Dict from packaging.version import Version @@ -23,7 +23,7 @@ from bauh.commons.html import strip_html, bold from bauh.commons.system import ProcessHandler from bauh.gems.flatpak import flatpak, SUGGESTIONS_FILE, CONFIG_FILE, UPDATES_IGNORED_FILE, FLATPAK_CONFIG_DIR, \ EXPORTS_PATH, \ - get_icon_path, VERSION_1_5, VERSION_1_2 + get_icon_path, VERSION_1_5, VERSION_1_2, VERSION_1_12 from bauh.gems.flatpak.config import FlatpakConfigManager from bauh.gems.flatpak.constants import FLATHUB_API_URL from bauh.gems.flatpak.model import FlatpakApplication @@ -124,17 +124,38 @@ class FlatpakManager(SoftwareManager, SettingsController): def _add_updates(self, version: Version, output: list): output.append(flatpak.list_updates_as_str(version)) + def _fill_required_runtimes(self, installation: str, output: List[Tuple[str, str]]): + runtimes = flatpak.list_required_runtime_updates(installation=installation) + + if runtimes: + output.extend(runtimes) + + def _fill_required_runtime_updates(self, output: Dict[str, List[Tuple[str, str]]]): + threads = [] + for installation in ('system', 'user'): + runtimes = list() + output[installation] = runtimes + t = Thread(target=self._fill_required_runtimes, args=(installation, runtimes)) + t.start() + threads.append(t) + + for t in threads: + t.join() + def read_installed(self, disk_loader: Optional[DiskCacheLoader], limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None, wait_async_data: bool = False) -> SearchResult: version = flatpak.get_version() - updates = [] + updates, required_runtimes = list(), dict() + thread_updates, thread_runtimes = None, None if internet_available: thread_updates = Thread(target=self._add_updates, args=(version, updates)) thread_updates.start() - else: - thread_updates = None + + if version >= VERSION_1_12: + thread_runtimes = Thread(target=self._fill_required_runtime_updates, args=(required_runtimes,)) + thread_runtimes.start() installed = flatpak.list_installed(version) @@ -192,6 +213,28 @@ class FlatpakManager(SoftwareManager, SettingsController): models[partial_update_id] = partial_model break + if thread_runtimes: + thread_runtimes.join() + + if required_runtimes: + for installation in ('system', 'user'): + installation_runtimes = required_runtimes.get(installation) + + if installation_runtimes: + for ref, origin in installation_runtimes: + ref_split = ref.split('/') + models[f'{installation}.'] = FlatpakApplication(id=ref_split[1], + ref=ref, + origin=origin, + name=ref_split[1], + version=ref_split[-1], + latest_version=ref_split[-1], + runtime=True, + installation=installation, + installed=True, + update_component=True, + update=True) + if models: ignored = self._read_ignored_updates() @@ -307,7 +350,7 @@ class FlatpakManager(SoftwareManager, SettingsController): 'origin': app.origin, 'arch': app.arch, 'ref': app.ref, - 'type': self.i18n['unknown']} + 'type': 'runtime' if app.runtime else self.i18n['unknown']} else: version = flatpak.get_version() id_ = app.base_id if app.partial and version < VERSION_1_5 else app.id diff --git a/bauh/gems/flatpak/flatpak.py b/bauh/gems/flatpak/flatpak.py index 1314c9ca..d8cb597f 100755 --- a/bauh/gems/flatpak/flatpak.py +++ b/bauh/gems/flatpak/flatpak.py @@ -3,12 +3,14 @@ import re import subprocess import traceback from datetime import datetime -from typing import List, Dict, Set, Iterable, Optional +from threading import Thread +from typing import List, Dict, Set, Iterable, Optional, Tuple from packaging.version import Version from packaging.version import parse as parse_version from bauh.api.exception import NoInternetException +from bauh.commons import system from bauh.commons.system import new_subprocess, run_cmd, SimpleProcess, ProcessHandler, DEFAULT_LANG from bauh.commons.util import size_to_byte from bauh.gems.flatpak import EXPORTS_PATH, VERSION_1_3, VERSION_1_2, VERSION_1_5, VERSION_1_12 @@ -16,6 +18,7 @@ from bauh.gems.flatpak.constants import FLATHUB_URL RE_SEVERAL_SPACES = re.compile(r'\s+') RE_COMMIT = re.compile(r'(Latest commit|Commit)\s*:\s*(.+)') +RE_REQUIRED_RUNTIME = re.compile(f'Required\s+runtime\s+.+\(([\w./]+)\)\s*.+\s+remote\s+([\w+./]+)') OPERATION_UPDATE_SYMBOLS = {'i', 'u'} @@ -184,18 +187,46 @@ def uninstall(app_ref: str, installation: str, version: Version) -> SimpleProces shell=True) -def list_updates_as_str(version: Version) -> Dict[str, set]: - updates = read_updates(version, 'system') - user_updates = read_updates(version, 'user') - - for attr in ('full', 'partial'): - updates[attr].update(user_updates[attr]) - - return updates +def _new_updates() -> Dict[str, Set[str]]: + return {'full': set(), 'partial': set()} -def read_updates(version: Version, installation: str) -> Dict[str, set]: - res = {'partial': set(), 'full': set()} +def list_updates_as_str(version: Version) -> Dict[str, Set[str]]: + sys_updates, user_updates = _new_updates(), _new_updates() + + threads = [] + for type_, output in (('system', sys_updates), ('user', user_updates)): + fill = Thread(target=fill_updates, args=(version, type_, output)) + fill.start() + threads.append(fill) + + for t in threads: + t.join() + + all_updates = _new_updates() + + for updates in (sys_updates, user_updates): + if updates: + for key, val in updates.items(): + if val: + all_updates[key].update(val) + + return all_updates + + +def list_required_runtime_updates(installation: str) -> Optional[List[Tuple[str, str]]]: + """ + Return a list of tuples composed by the reference and the origin. + e.g: ('runtime/org.gnome.Desktop/42/x86_64', 'flathub') + """ + _, updates = system.execute(f'flatpak update --{installation}', shell=True, + custom_env=system.gen_env()) + + if updates: + return RE_REQUIRED_RUNTIME.findall(updates) + + +def fill_updates(version: Version, installation: str, res: Dict[str, Set[str]]): if version < VERSION_1_2: try: output = run_cmd(f'flatpak update --no-related --no-deps --{installation}', ignore_return_code=True) @@ -235,8 +266,6 @@ def read_updates(version: Version, installation: str) -> Dict[str, set]: except: traceback.print_exc() - return res - def downgrade(app_ref: str, commit: str, installation: str, root_password: Optional[str], version: Version) -> SimpleProcess: cmd = ('flatpak', 'update', '--no-related', '--no-deps', f'--commit={commit}', app_ref, '-y', f'--{installation}') diff --git a/bauh/gems/flatpak/model.py b/bauh/gems/flatpak/model.py index 7a6a8d9c..0e10a282 100644 --- a/bauh/gems/flatpak/model.py +++ b/bauh/gems/flatpak/model.py @@ -8,11 +8,13 @@ from bauh.view.util.translation import I18n class FlatpakApplication(SoftwarePackage): - def __init__(self, id: str = None, name: str = None, version: str = None, latest_version: str = None, description: str = None, - branch: str = None, arch: str = None, origin: str = None, runtime: bool = False, ref: str = None, commit: str = None, - installation: str = None, i18n: I18n = None, partial: bool = False, updates_ignored: bool = False): - super(FlatpakApplication, self).__init__(id=id, name=name, version=version, - latest_version=latest_version, description=description) + def __init__(self, id: str = None, name: str = None, version: str = None, latest_version: str = None, + description: str = None, branch: str = None, arch: str = None, origin: str = None, + runtime: bool = False, ref: str = None, commit: str = None, installation: str = None, + i18n: I18n = None, partial: bool = False, updates_ignored: bool = False, installed: bool = False, + update: bool = False, update_component: bool = False): + super(FlatpakApplication, self).__init__(id=id, name=name, version=version, latest_version=latest_version, + description=description, installed=installed, update=update) self.ref = ref self.branch = branch self.arch = arch @@ -25,7 +27,7 @@ class FlatpakApplication(SoftwarePackage): self.base_id = None self.base_ref = None self.updates_ignored = updates_ignored - self.update_component = False # if it is a new app/runtime that has come as an update + self.update_component = update_component # if it is a new app/runtime that has come as an update if runtime: self.categories = ['runtime']