AUR bearhub: fix stale source cache collision (pkgrel=10)

Use tag-specific tarball name bearhub-0.10.7-bearhub.6.tar.gz so makepkg
and AUR helpers do not reuse an outdated bearhub-0.10.7.tar.gz from cache.
Ignore makepkg artifacts under packaging/aur/.
This commit is contained in:
Sebastian Palencsar
2026-06-27 10:02:45 +02:00
parent c56b8a2473
commit da377aecdc
198 changed files with 4543 additions and 4644 deletions

View File

@@ -1,22 +0,0 @@
import os
from pathlib import Path
from bauh.api import user
from bauh.api.paths import CONFIG_DIR
from bauh.commons import resource
from bauh.commons.version_util import map_str_version
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
CONFIG_FILE = f'{CONFIG_DIR}/flatpak.yml'
FLATPAK_CONFIG_DIR = f'{CONFIG_DIR}/flatpak'
UPDATES_IGNORED_FILE = f'{FLATPAK_CONFIG_DIR}/updates_ignored.txt'
EXPORTS_PATH = '/usr/share/flatpak/exports/share' if user.is_root() else f'{Path.home()}/.local/share/flatpak/exports/share'
VERSION_1_2 = map_str_version("1.2")
VERSION_1_3 = map_str_version("1.3")
VERSION_1_4 = map_str_version("1.4")
VERSION_1_5 = map_str_version("1.5")
VERSION_1_12 = map_str_version("1.12")
def get_icon_path() -> str:
return resource.get_path('img/flatpak.svg', ROOT_DIR)

View File

@@ -1,11 +0,0 @@
from bauh.commons.config import YAMLConfigManager
from bauh.gems.flatpak import CONFIG_FILE
class FlatpakConfigManager(YAMLConfigManager):
def __init__(self):
super(FlatpakConfigManager, self).__init__(config_file_path=CONFIG_FILE)
def get_default_config(self) -> dict:
return {'installation_level': None}

View File

@@ -1,2 +0,0 @@
FLATHUB_URL = 'https://flathub.org'
FLATHUB_API_URL = FLATHUB_URL + '/api/v1'

View File

@@ -1,869 +0,0 @@
import os
import re
import traceback
from datetime import datetime, timezone
from operator import attrgetter
from pathlib import Path
from threading import Thread
from typing import List, Set, Type, Tuple, Optional, Generator, Dict
from bauh.api import user
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext, UpgradeRequirements, \
UpgradeRequirement, TransactionResult, SoftwareAction, SettingsView, SettingsController
from bauh.api.abstract.disk import DiskCacheLoader
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
from bauh.api.abstract.model import PackageHistory, PackageUpdate, SoftwarePackage, PackageSuggestion, \
PackageStatus, CustomSoftwareAction, SuggestionPriority
from bauh.api.abstract.view import MessageType, FormComponent, SingleSelectComponent, InputOption, SelectViewType, \
PanelComponent, ViewComponentAlignment
from bauh.commons import suggestions
from bauh.commons.boot import CreateConfigFile
from bauh.commons.html import strip_html, bold
from bauh.commons.system import ProcessHandler
from bauh.gems.flatpak import flatpak, CONFIG_FILE, UPDATES_IGNORED_FILE, FLATPAK_CONFIG_DIR, \
EXPORTS_PATH, \
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
from bauh.gems.flatpak.worker import FlatpakAsyncDataLoader
DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.000Z'
RE_INSTALL_REFS = re.compile(r'\d+\)\s+(.+)')
class FlatpakManager(SoftwareManager, SettingsController):
def __init__(self, context: ApplicationContext):
super(FlatpakManager, self).__init__(context=context)
self.i18n = context.i18n
self.api_cache = context.cache_factory.new(None)
self.category_cache = context.cache_factory.new(None)
context.disk_loader_factory.map(FlatpakApplication, self.api_cache)
self.enabled = True
self.http_client = context.http_client
self.suggestions_cache = context.cache_factory.new(None)
self.logger = context.logger
self.configman = FlatpakConfigManager()
self._action_full_update: Optional[CustomSoftwareAction] = None
self._suggestions_file_url: Optional[str] = None
def get_managed_types(self) -> Set["type"]:
return {FlatpakApplication}
def _map_to_model(self, app_json: dict, installed: bool, disk_loader: Optional[DiskCacheLoader], internet: bool = True) -> Tuple[FlatpakApplication, Optional[FlatpakAsyncDataLoader]]:
app = FlatpakApplication(**app_json, i18n=self.i18n)
app.installed = installed
api_data = self.api_cache.get(app_json['id'])
if app.runtime and app.latest_version is None:
app.latest_version = app.version
expired_data = api_data and api_data.get('expires_at') and api_data['expires_at'] <= datetime.now(timezone.utc)
data_loader: Optional[FlatpakAsyncDataLoader] = None
if not api_data or expired_data:
if not app.runtime:
if disk_loader:
disk_loader.fill(app) # preloading cached disk data
if internet:
data_loader = FlatpakAsyncDataLoader(app=app, api_cache=self.api_cache, manager=self,
context=self.context, category_cache=self.category_cache)
data_loader.start()
else:
app.fill_cached_data(api_data)
app.status = PackageStatus.READY
return app, data_loader
def _get_search_remote(self) -> str:
remotes = flatpak.list_remotes()
if remotes['system']:
remote_level = 'system'
elif remotes['user']:
remote_level = 'user'
else:
remote_level = 'user'
ProcessHandler().handle_simple(flatpak.set_default_remotes(remote_level))
return remote_level
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult:
if is_url:
return SearchResult([], [], 0)
remote_level = self._get_search_remote()
res = SearchResult([], [], 0)
apps_found = flatpak.search(flatpak.get_version(), words, remote_level)
if apps_found:
already_read = set()
installed_apps = self.read_installed(disk_loader=disk_loader, internet_available=True).installed
if installed_apps:
for app_found in apps_found:
for installed_app in installed_apps:
if app_found['id'] == installed_app.id:
res.installed.append(installed_app)
already_read.add(app_found['id'])
if len(apps_found) > len(already_read):
for app_found in apps_found:
if app_found['id'] not in already_read:
res.new.append(self._map_to_model(app_found, False, disk_loader)[0])
res.total = len(res.installed) + len(res.new)
return res
def _add_updates(self, version: Tuple[str, ...], 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), daemon=True)
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, required_runtimes = list(), dict()
thread_updates, thread_runtimes = None, None
if internet_available:
thread_updates = Thread(target=self._add_updates, args=(version, updates), daemon=True)
thread_updates.start()
if version >= VERSION_1_12:
thread_runtimes = Thread(target=self._fill_required_runtime_updates,
args=(required_runtimes,),
daemon=True)
thread_runtimes.start()
installed = flatpak.list_installed(version)
update_map = None
if thread_updates:
thread_updates.join()
update_map = updates[0]
models = {}
data_loaders: Optional[List[FlatpakAsyncDataLoader]] = [] if wait_async_data else None
if installed:
for app_json in installed:
model, loader = self._map_to_model(app_json=app_json, installed=True,
disk_loader=disk_loader, internet=internet_available)
model.update = False
models[model.get_update_id(version)] = model
if loader and data_loaders is not None:
data_loaders.append(loader)
if update_map:
for update_id in update_map['full']:
model_with_update = models.get(update_id)
if model_with_update:
model_with_update.update = True
else:
# it is a new component that must be installed
update_id_split = update_id.split('/')
new_app = FlatpakApplication(id=update_id_split[0],
branch=update_id_split[1],
installation=update_id_split[2],
name=update_id_split[0].split('.')[-1].strip(),
version=update_id_split[1],
arch='x86_64' if self.context.is_system_x86_64() else 'x86',
origin=update_id_split[3] if len(update_id_split) == 4 else None)
new_app.update_component = True # mark as "update component"
new_app.installed = True # faking the "installed" status to be displayed as an update
new_app.update = True
new_app.update_ref()
models[update_id] = new_app
if version >= VERSION_1_2:
for partial_update_id in update_map['partial']:
partial_data = partial_update_id.split('/')
for model in models.values():
if model.installation == partial_data[2] and model.branch == partial_data[1]:
if model.id == partial_data[0]:
model.update = True
break
elif model.id in partial_data[0]:
partial_model = model.gen_partial(partial_data[0])
partial_model.update = True
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=False,
update_component=True,
update=True)
if models:
ignored = self._read_ignored_updates()
if ignored:
for model in models.values():
if model.get_update_ignore_key() in ignored:
model.updates_ignored = True
if data_loaders:
for loader in data_loaders:
loader.join()
return SearchResult([*models.values()], None, len(models))
def downgrade(self, pkg: FlatpakApplication, root_password: Optional[str], watcher: ProcessWatcher) -> bool:
if not self._make_exports_dir(watcher):
return False
watcher.change_progress(10)
watcher.change_substatus(self.i18n['flatpak.downgrade.commits'])
history = self.get_history(pkg, full_commit_str=True)
# downgrade is not possible if the app current commit in the first one:
if history.pkg_status_idx == len(history.history) - 1:
watcher.show_message(self.i18n['flatpak.downgrade.impossible.title'],
self.i18n['flatpak.downgrade.impossible.body'].format(bold(pkg.name)),
MessageType.ERROR)
return False
commit = history.history[history.pkg_status_idx + 1]['commit']
watcher.change_substatus(self.i18n['flatpak.downgrade.reverting'])
watcher.change_progress(50)
success, _ = ProcessHandler(watcher).handle_simple(flatpak.downgrade(app_ref=pkg.ref,
commit=commit,
installation=pkg.installation,
root_password=root_password,
version=flatpak.get_version()))
watcher.change_progress(100)
return success
def clean_cache_for(self, pkg: FlatpakApplication):
super(FlatpakManager, self).clean_cache_for(pkg)
self.api_cache.delete(pkg.id)
def upgrade(self, requirements: UpgradeRequirements, root_password: Optional[str], watcher: ProcessWatcher) -> bool:
flatpak_version = flatpak.get_version()
if not self._make_exports_dir(watcher):
return False
for req in requirements.to_upgrade:
watcher.change_status("{} {} ({})...".format(self.i18n['manage_window.status.upgrading'], req.pkg.name, req.pkg.version))
related, deps = False, False
ref = req.pkg.ref
if req.pkg.partial and flatpak_version < VERSION_1_5:
related, deps = True, True
ref = req.pkg.base_ref
try:
if req.pkg.update_component:
self.logger.info(f"Installing {req.pkg}")
res, _ = ProcessHandler(watcher).handle_simple(flatpak.install(app_id=ref,
installation=req.pkg.installation,
origin=req.pkg.origin,
version=flatpak_version))
else:
self.logger.info(f"Updating {req.pkg}")
res, _ = ProcessHandler(watcher).handle_simple(flatpak.update(app_ref=ref,
installation=req.pkg.installation,
related=related,
deps=deps,
version=flatpak_version))
watcher.change_substatus('')
if not res:
self.logger.warning("Could not upgrade '{}'".format(req.pkg.id))
return False
except Exception:
watcher.change_substatus('')
self.logger.error("An error occurred while upgrading '{}'".format(req.pkg.id))
traceback.print_exc()
return False
watcher.change_substatus('')
return True
def uninstall(self, pkg: FlatpakApplication, root_password: Optional[str], watcher: ProcessWatcher, disk_loader: DiskCacheLoader) -> TransactionResult:
if not self._make_exports_dir(watcher):
return TransactionResult.fail()
flatpak_version = flatpak.get_version()
uninstalled, _ = ProcessHandler(watcher).handle_simple(flatpak.uninstall(pkg.ref, pkg.installation,
flatpak_version))
if uninstalled:
if self.suggestions_cache:
self.suggestions_cache.delete(pkg.id)
self.revert_ignored_update(pkg)
return TransactionResult(success=True, installed=None, removed=[pkg])
return TransactionResult.fail()
def get_info(self, app: FlatpakApplication) -> dict:
if app.installed:
if app.update_component:
app_info = {'id': app.id,
'name': app.name,
'branch': app.branch,
'installation': app.installation,
'origin': app.origin,
'arch': app.arch,
'ref': app.ref,
'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
app_info = flatpak.get_app_info_fields(id_, app.branch, app.installation)
if app.partial and version < VERSION_1_5:
app_info['id'] = app.id
app_info['ref'] = app.ref
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 ''
if app.installation:
app_info['installation'] = app.installation
if app_info.get('installed'):
app_info['installed'] = app_info['installed'].replace('?', ' ')
return app_info
else:
res = self.http_client.get_json('{}/apps/{}'.format(FLATHUB_API_URL, app.id))
if res:
if res.get('categories'):
res['categories'] = [c.get('name') for c in res['categories']]
for to_del in ('screenshots', 'iconMobileUrl', 'iconDesktopUrl'):
if res.get(to_del):
del res[to_del]
for to_strip in ('description', 'currentReleaseDescription'):
if res.get(to_strip):
res[to_strip] = strip_html(res[to_strip])
for to_date in ('currentReleaseDate', 'inStoreSinceDate'):
if res.get(to_date):
try:
res[to_date] = datetime.strptime(res[to_date], DATE_FORMAT)
except Exception:
self.context.logger.error('Could not convert date string {} as {}'.format(res[to_date], DATE_FORMAT))
pass
return res
else:
return {}
def get_history(self, pkg: FlatpakApplication, full_commit_str: bool = False) -> PackageHistory:
pkg.commit = flatpak.get_commit(pkg.id, pkg.branch, pkg.installation)
pkg_commit = pkg.commit if pkg.commit else None
if pkg_commit and not full_commit_str:
pkg_commit = pkg_commit[0:8]
commits = flatpak.get_app_commits_data(pkg.ref, pkg.origin, pkg.installation, full_str=full_commit_str)
status_idx = 0
commit_found = False
if pkg_commit is None and len(commits) > 1 and commits[0]['commit'] == '(null)':
del commits[0]
pkg_commit = commits[0]
commit_found = True
if not commit_found:
for idx, data in enumerate(commits):
if data['commit'] == pkg_commit:
status_idx = idx
commit_found = True
break
if not commit_found and pkg_commit and commits[0]['commit'] == '(null)':
commits[0]['commit'] = pkg_commit
return PackageHistory(pkg=pkg, history=commits, pkg_status_idx=status_idx)
def _make_exports_dir(self, watcher: ProcessWatcher) -> bool:
if not os.path.exists(EXPORTS_PATH):
self.logger.info("Creating dir '{}'".format(EXPORTS_PATH))
watcher.print('Creating dir {}'.format(EXPORTS_PATH))
try:
Path(EXPORTS_PATH).mkdir(parents=True, exist_ok=True)
except Exception:
watcher.print('Error while creating the directory {}'.format(EXPORTS_PATH))
return False
return True
def install(self, pkg: FlatpakApplication, root_password: Optional[str], disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult:
if not self.context.root_user:
flatpak_config = self.configman.get_config()
install_level = flatpak_config['installation_level']
else:
install_level = 'system'
if install_level is not None:
self.logger.info("Default Flaptak installation level defined: {}".format(install_level))
if install_level not in ('user', 'system'):
watcher.show_message(title=self.i18n['error'].capitalize(),
body=self.i18n['flatpak.install.bad_install_level.body'].format(field=bold('installation_level'),
file=bold(CONFIG_FILE)),
type_=MessageType.ERROR)
return TransactionResult(success=False, installed=[], removed=[])
pkg.installation = install_level
else:
user_level = watcher.request_confirmation(title=self.i18n['flatpak.install.install_level.title'],
body=self.i18n['flatpak.install.install_level.body'].format(bold(pkg.name)),
confirmation_label=self.i18n['no'].capitalize(),
deny_label=self.i18n['yes'].capitalize())
pkg.installation = 'user' if user_level else 'system'
remotes = flatpak.list_remotes()
handler = ProcessHandler(watcher)
if pkg.installation == 'user' and not remotes['user']:
handler.handle_simple(flatpak.set_default_remotes('user'))
elif pkg.installation == 'system' and not remotes['system']:
if user.is_root():
handler.handle_simple(flatpak.set_default_remotes('system'))
else:
valid, user_password = watcher.request_root_password()
if not valid:
watcher.print('Operation aborted')
return TransactionResult(success=False, installed=[], removed=[])
else:
if not handler.handle_simple(flatpak.set_default_remotes('system', user_password))[0]:
watcher.show_message(title=self.i18n['error'].capitalize(),
body=self.i18n['flatpak.remotes.system_flathub.error'],
type_=MessageType.ERROR)
watcher.print("Operation cancelled")
return TransactionResult(success=False, installed=[], removed=[])
# retrieving all installed so it will be possible to know the additional installed runtimes after the operation succeeds
flatpak_version = flatpak.get_version()
installed = flatpak.list_installed(flatpak_version)
installed_by_level = {'{}:{}:{}'.format(p['id'], p['name'], p['branch']) for p in installed if p['installation'] == pkg.installation} if installed else None
if not self._make_exports_dir(handler.watcher):
return TransactionResult(success=False, installed=[], removed=[])
installed, output = handler.handle_simple(flatpak.install(str(pkg.id), pkg.origin, pkg.installation,
flatpak_version))
if not installed and 'error: No ref chosen to resolve matches' in output:
ref_opts = RE_INSTALL_REFS.findall(output)
if ref_opts and len(ref_opts) > 1:
view_opts = [InputOption(label=o, value=o.strip()) for o in ref_opts if o]
ref_select = SingleSelectComponent(type_=SelectViewType.RADIO, options=view_opts, default_option=view_opts[0], label='')
if watcher.request_confirmation(title=self.i18n['flatpak.install.ref_choose.title'],
body=self.i18n['flatpak.install.ref_choose.body'].format(bold(pkg.name)),
components=[ref_select],
confirmation_label=self.i18n['proceed'].capitalize(),
deny_label=self.i18n['cancel'].capitalize()):
ref = ref_select.get_selected()
installed, output = handler.handle_simple(flatpak.install(ref, pkg.origin, pkg.installation,
flatpak_version))
pkg.ref = ref
pkg.runtime = 'runtime' in ref
else:
watcher.print('Aborted by the user')
return TransactionResult.fail()
else:
return TransactionResult.fail()
if installed:
try:
fields = flatpak.get_fields(str(pkg.id), pkg.branch, ['Ref', 'Branch'])
if fields:
pkg.ref = fields[0]
pkg.branch = fields[1]
except Exception:
traceback.print_exc()
if installed:
new_installed = [pkg]
current_installed = flatpak.list_installed(flatpak_version)
current_installed_by_level = [p for p in current_installed if p['installation'] == pkg.installation] if current_installed else None
if current_installed_by_level and (not installed_by_level or len(current_installed_by_level) > len(installed_by_level) + 1):
pkg_key = '{}:{}:{}'.format(pkg.id, pkg.name, pkg.branch)
net_available = self.context.is_internet_available()
for p in current_installed_by_level:
current_key = '{}:{}:{}'.format(p['id'], p['name'], p['branch'])
if current_key != pkg_key and (not installed_by_level or current_key not in installed_by_level):
new_installed.append(self._map_to_model(app_json=p, installed=True,
disk_loader=disk_loader, internet=net_available)[0])
return TransactionResult(success=installed, installed=new_installed, removed=[])
else:
return TransactionResult.fail()
def is_enabled(self):
return self.enabled
def set_enabled(self, enabled: bool):
self.enabled = enabled
def can_work(self) -> Tuple[bool, Optional[str]]:
return (True, None) if flatpak.is_installed() else (False, self.i18n['missing_dep'].format(dep=bold('flatpak')))
def requires_root(self, action: SoftwareAction, pkg: FlatpakApplication) -> bool:
return action == SoftwareAction.DOWNGRADE and pkg.installation == 'system'
def prepare(self, task_manager: TaskManager, root_password: Optional[str], internet_available: bool):
CreateConfigFile(taskman=task_manager, configman=self.configman, i18n=self.i18n,
task_icon_path=get_icon_path(), logger=self.logger).start()
def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
updates = []
installed = self.read_installed(None, internet_available=internet_available, wait_async_data=True).installed
if installed:
for p in installed:
if isinstance(p, FlatpakApplication) and p.update and not p.is_update_ignored():
updates.append(PackageUpdate(pkg_id=f'{p.id}:{p.branch}:{p.installation}',
pkg_type='Flatpak',
name=p.name,
version=p.latest_version))
return updates
def list_warnings(self, internet_available: bool) -> Optional[List[str]]:
pass
def _read_local_suggestions_file(self) -> Optional[str]:
try:
with open(self.suggestions_file_url) as f:
suggestions_str = f.read()
return suggestions_str
except FileNotFoundError:
self.logger.error(f"Local Flatpak suggestions file not found: {self.suggestions_file_url}")
except OSError:
self.logger.error(f"Could not read local Flatpak suggestions file: {self.suggestions_file_url}")
traceback.print_exc()
def _download_remote_suggestions_file(self) -> Optional[str]:
self.logger.info(f"Downloading the Flatpak suggestions from {self.suggestions_file_url}")
file = self.http_client.get(self.suggestions_file_url)
if file:
return file.text
def _fill_suggestion(self, appid: str, priority: SuggestionPriority, flatpak_version: Tuple[str, ...], remote: str,
output: List[PackageSuggestion]):
app_json = flatpak.search(flatpak_version, appid, remote, app_id=True)
if app_json:
model = PackageSuggestion(self._map_to_model(app_json[0], False, None)[0], priority)
self.suggestions_cache.add(appid, model)
output.append(model)
else:
self.logger.warning(f"Could not find Flatpak suggestions '{appid}'")
def list_suggestions(self, limit: int, filter_installed: bool) -> Optional[List[PackageSuggestion]]:
if limit == 0:
return
if self.is_local_suggestions_file_mapped():
suggestions_str = self._read_local_suggestions_file()
else:
suggestions_str = self._download_remote_suggestions_file()
if suggestions_str is None:
return
if not suggestions_str:
self.logger.warning(f"No Flatpak suggestion found in {self.suggestions_file_url}")
return
ids_prios = suggestions.parse(suggestions_str, self.logger, 'Flatpak')
if not ids_prios:
self.logger.warning(f"No Flatpak suggestion could be parsed from {self.suggestions_file_url}")
return
suggestion_by_priority = suggestions.sort_by_priority(ids_prios)
if filter_installed:
installed = {i.id for i in self.read_installed(disk_loader=None).installed}
if installed:
suggestion_by_priority = tuple(id_ for id_ in suggestion_by_priority if id_ not in installed)
if suggestion_by_priority and 0 < limit < len(suggestion_by_priority):
suggestion_by_priority = suggestion_by_priority[0:limit]
self.logger.info(f'Available Flatpak suggestions: {len(suggestion_by_priority)}')
if not suggestion_by_priority:
return
flatpak_version = flatpak.get_version()
remote = self._get_search_remote()
self.logger.info("Mapping Flatpak suggestions")
res, fill_suggestions = [], []
cached_count = 0
for appid in suggestion_by_priority:
cached_instance = self.suggestions_cache.get(appid)
if cached_instance:
res.append(cached_instance)
cached_count += 1
else:
fill = Thread(target=self._fill_suggestion, args=(appid, ids_prios[appid], flatpak_version,
remote, res), daemon=True)
fill.start()
fill_suggestions.append(fill)
for fill in fill_suggestions:
fill.join()
if cached_count > 0:
self.logger.info(f"Returning {cached_count} cached Flatpak suggestions")
return res
def is_default_enabled(self) -> bool:
return True
def launch(self, pkg: FlatpakApplication):
flatpak.run(str(pkg.id))
def get_screenshots(self, pkg: FlatpakApplication) -> Generator[str, None, None]:
screenshots_url = f'{FLATHUB_API_URL}/apps/{pkg.id}'
try:
res = self.http_client.get_json(screenshots_url)
if res and res.get('screenshots'):
for s in res['screenshots']:
if s.get('imgDesktopUrl'):
yield s['imgDesktopUrl']
except Exception as e:
if e.__class__.__name__ == 'JSONDecodeError':
self.context.logger.error("Could not decode json from '{}'".format(screenshots_url))
else:
traceback.print_exc()
def get_settings(self) -> Optional[Generator[SettingsView, None, None]]:
if not self.context.root_user:
fields = []
flatpak_config = self.configman.get_config()
install_opts = [InputOption(label=self.i18n['flatpak.config.install_level.system'].capitalize(),
value='system',
tooltip=self.i18n['flatpak.config.install_level.system.tip']),
InputOption(label=self.i18n['flatpak.config.install_level.user'].capitalize(),
value='user',
tooltip=self.i18n['flatpak.config.install_level.user.tip']),
InputOption(label=self.i18n['ask'].capitalize(),
value=None,
tooltip=self.i18n['flatpak.config.install_level.ask.tip'].format(app=self.context.app_name))]
fields.append(SingleSelectComponent(label=self.i18n['flatpak.config.install_level'],
options=install_opts,
default_option=[o for o in install_opts if o.value == flatpak_config['installation_level']][0],
max_per_line=len(install_opts),
type_=SelectViewType.COMBO,
alignment=ViewComponentAlignment.CENTER,
id_='install'))
yield SettingsView(self, PanelComponent([FormComponent(fields, self.i18n['installation'].capitalize())]))
def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]:
flatpak_config = self.configman.get_config()
form = component.get_component_by_idx(0, FormComponent)
flatpak_config['installation_level'] = form.get_component('install', SingleSelectComponent).get_selected()
try:
self.configman.save_config(flatpak_config)
return True, None
except Exception:
return False, [traceback.format_exc()]
def get_upgrade_requirements(self, pkgs: List[FlatpakApplication], root_password: Optional[str], watcher: ProcessWatcher) -> UpgradeRequirements:
flatpak_version = flatpak.get_version()
user_pkgs, system_pkgs = [], []
for pkg in pkgs:
if pkg.installation == 'user':
user_pkgs.append(pkg)
else:
system_pkgs.append(pkg)
for apps_by_install in ((user_pkgs, 'user'), (system_pkgs, 'system')):
if apps_by_install[0]:
sizes = flatpak.map_update_download_size([str(p.id) for p in apps_by_install[0]], apps_by_install[1], flatpak_version)
if sizes:
for p in apps_by_install[0]:
p.size = sizes.get(str(p.id))
to_update = [UpgradeRequirement(pkg=p, extra_size=0, required_size=p.size) for p in self.sort_update_order(pkgs)]
return UpgradeRequirements(None, None, to_update, [])
def sort_update_order(self, pkgs: List[FlatpakApplication]) -> List[FlatpakApplication]:
runtimes, apps = set(), set()
for p in pkgs:
if p.runtime:
runtimes.add(p)
else:
apps.add(p)
sorted_list = []
for comps in (runtimes, apps):
if comps:
comp_list = list(comps)
comp_list.sort(key=attrgetter('installation', 'name', 'id'))
sorted_list.extend(comp_list)
return sorted_list
def _read_ignored_updates(self) -> Set[str]:
ignored = set()
if os.path.exists(UPDATES_IGNORED_FILE):
with open(UPDATES_IGNORED_FILE) as f:
ignored_txt = f.read()
for l in ignored_txt.split('\n'):
if l:
line_clean = l.strip()
if line_clean:
ignored.add(line_clean)
return ignored
def _write_ignored_updates(self, keys: Set[str]):
Path(FLATPAK_CONFIG_DIR).mkdir(parents=True, exist_ok=True)
ignored_list = [*keys]
ignored_list.sort()
with open(UPDATES_IGNORED_FILE, 'w+') as f:
if ignored_list:
for ignored in ignored_list:
f.write('{}\n'.format(ignored))
else:
f.write('')
def ignore_update(self, pkg: FlatpakApplication):
ignored_keys = self._read_ignored_updates()
pkg_key = pkg.get_update_ignore_key()
if pkg_key not in ignored_keys:
ignored_keys.add(pkg_key)
self._write_ignored_updates(ignored_keys)
pkg.updates_ignored = True
def revert_ignored_update(self, pkg: FlatpakApplication):
ignored_keys = self._read_ignored_updates()
if ignored_keys:
pkg_key = pkg.get_update_ignore_key()
if pkg_key in ignored_keys:
ignored_keys.remove(pkg_key)
self._write_ignored_updates(ignored_keys)
pkg.updates_ignored = False
def gen_custom_actions(self) -> Generator[CustomSoftwareAction, None, None]:
yield self.action_full_update
def full_update(self, root_password: Optional[str], watcher: ProcessWatcher) -> bool:
handler = ProcessHandler(watcher)
return handler.handle_simple(flatpak.full_update(flatpak.get_version()))[0]
@property
def action_full_update(self) -> CustomSoftwareAction:
if self._action_full_update is None:
self._action_full_update = CustomSoftwareAction(i18n_label_key='flatpak.action.full_update',
i18n_description_key='flatpak.action.full_update.description',
i18n_status_key='flatpak.action.full_update.status',
backup=True,
manager=self,
requires_internet=True,
icon_path=get_icon_path(),
manager_method='full_update',
requires_root=False)
return self._action_full_update
@property
def suggestions_file_url(self) -> str:
if self._suggestions_file_url is None:
file_url = self.context.get_suggestion_url(self.__module__)
if not file_url:
file_url = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master/flatpak/suggestions.txt'
self._suggestions_file_url = file_url
if file_url.startswith('/'):
self.logger.info(f"Local Flatpak suggestions file mapped: {file_url}")
return self._suggestions_file_url
def is_local_suggestions_file_mapped(self) -> bool:
return self.suggestions_file_url.startswith('/')

View File

@@ -1,505 +0,0 @@
import os
import re
import subprocess
import traceback
from datetime import datetime
from threading import Thread
from typing import List, Dict, Set, Iterable, Optional, Tuple
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.commons.version_util import map_str_version
from bauh.gems.flatpak import EXPORTS_PATH, VERSION_1_3, VERSION_1_2, VERSION_1_5, VERSION_1_12
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(r'Required\s+runtime\s+.+\(([\w./]+)\)\s*.+\s+remote\s+([\w+./]+)')
OPERATION_UPDATE_SYMBOLS = {'i', 'u'}
def get_app_info_fields(app_id: str, branch: str, installation: str, fields: List[str] = [], check_runtime: bool = False):
info = get_app_info(app_id, branch, installation)
if not info:
return {}
info = re.findall(r'\w+:\s.+', info)
data = {}
fields_to_retrieve = len(fields) + (1 if check_runtime and 'ref' not in fields else 0)
for field in info:
if fields and fields_to_retrieve == 0:
break
field_val = field.split(':')
field_name = field_val[0].lower()
if not fields or field_name in fields or (check_runtime and field_name == 'ref'):
data[field_name] = field_val[1].strip()
if fields:
fields_to_retrieve -= 1
if check_runtime and field_name == 'ref':
data['runtime'] = data['ref'].startswith('runtime/')
return data
def get_fields(app_id: str, branch: str, fields: List[str]) -> List[str]:
cmd = ['flatpak', 'info', app_id]
if branch:
cmd.append(branch)
info = run_cmd(' '.join(cmd), print_error=False)
if not info:
return []
res = []
for line in info.splitlines():
if not line or ':' not in line:
continue
field_name, field_value = line.split(':', 1)
if field_name.strip() in fields:
res.append(field_value.strip())
return res
def is_installed():
version = get_version()
return False if version is None else True
def get_version() -> Optional[Tuple[str, ...]]:
res = run_cmd('flatpak --version', print_error=False)
return map_str_version(res.split(' ')[1].strip()) if res else None
def get_app_info(app_id: str, branch: str, installation: str) -> Optional[str]:
try:
return run_cmd(f'flatpak info {app_id} {branch} --{installation}')
except Exception:
traceback.print_exc()
return ''
def get_commit(app_id: str, branch: str, installation: str) -> Optional[str]:
info = run_cmd(f'flatpak info {app_id} {branch} --{installation}')
if info:
commits = RE_COMMIT.findall(info)
if commits:
return commits[0][1].strip()
def list_installed(version: Tuple[str, ...]) -> List[dict]:
apps = []
if version < VERSION_1_2:
app_list = run_cmd('flatpak list -d', print_error=False, lang=None)
if not app_list:
return apps
for line in app_list.splitlines():
if line:
data = line.strip().split('\t')
ref_split = data[0].split('/')
runtime = 'runtime' in data[5]
apps.append({
'id': ref_split[0],
'name': ref_split[0].split('.')[-1].capitalize(),
'ref': data[0],
'arch': ref_split[1],
'branch': ref_split[2],
'description': None,
'origin': data[1],
'runtime': runtime,
'installation': 'user' if 'user' in data[5] else 'system',
'version': ref_split[2] if runtime else None
})
else:
name_col = '' if version < VERSION_1_3 else 'name,'
cols = f'application,ref,arch,branch,description,origin,options,{name_col}version'
app_list = run_cmd(f'flatpak list --columns={cols}', print_error=False, lang=None)
if not app_list:
return apps
for line in app_list.splitlines():
if line:
data = line.strip().split('\t')
runtime = 'runtime' in data[6]
if version < VERSION_1_3:
name = data[0].split('.')[-1]
if len(data) > 7 and data[7]:
app_ver = data[7]
elif runtime:
app_ver = data[3]
else:
app_ver = None
else:
name = data[7]
if len(data) > 8 and data[8]:
app_ver = data[8]
elif runtime:
app_ver = data[3]
else:
app_ver = None
apps.append({'id': data[0],
'name': name,
'ref': data[1],
'arch': data[2],
'branch': data[3],
'description': data[4],
'origin': data[5],
'runtime': runtime,
'installation': 'user' if 'user' in data[6] else 'system',
'version': app_ver})
return apps
def update(app_ref: str, installation: str, version: Tuple[str, ...], related: bool = False, deps: bool = False) \
-> SimpleProcess:
cmd = ['flatpak', 'update', '-y', app_ref, f'--{installation}']
if not related:
cmd.append('--no-related')
if not deps:
cmd.append('--no-deps')
return SimpleProcess(cmd=cmd, extra_paths={EXPORTS_PATH}, shell=True,
lang=DEFAULT_LANG if version < VERSION_1_12 else None)
def full_update(version: VERSION_1_12) -> SimpleProcess:
return SimpleProcess(cmd=('flatpak', 'update', '-y'), extra_paths={EXPORTS_PATH}, shell=True,
lang=DEFAULT_LANG if version < VERSION_1_12 else None)
def uninstall(app_ref: str, installation: str, version: Tuple[str, ...]) -> SimpleProcess:
return SimpleProcess(cmd=('flatpak', 'uninstall', app_ref, '-y', f'--{installation}'),
extra_paths={EXPORTS_PATH},
lang=DEFAULT_LANG if version < VERSION_1_12 else None,
shell=True)
def _new_updates() -> Dict[str, Set[str]]:
return {'full': set(), 'partial': set()}
def list_updates_as_str(version: Tuple[str, ...]) -> 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), daemon=True)
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: Tuple[str, ...], 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)
if f'Updating in {installation}' in output:
for line in output.split(f'Updating in {installation}:\n')[1].split('\n'):
if not line.startswith('Is this ok'):
res['full'].add('{}/{}'.format(installation, line.split('\t')[0].strip()))
except Exception:
traceback.print_exc()
else:
reg = r'[0-9]+\.\s+.+'
try:
output = run_cmd(f'flatpak update --{installation} --no-deps', ignore_return_code=True, print_error=False)
if not output:
return
for line in output.splitlines():
if re.match(reg, line):
line_split = line.strip().split('\t')
if len(line_split) >= 5:
if version >= VERSION_1_5:
update_id = f'{line_split[2]}/{line_split[3]}/{installation}'
if len(line_split) >= 6:
update_id = f'{update_id}/{line_split[5]}'
elif version >= VERSION_1_2:
update_id = f'{line_split[2]}/{line_split[4]}/{installation}'
if len(line_split) >= 6:
update_id = f'{update_id}/{line_split[5]}'
else:
update_id = f'{line_split[2]}/{line_split[4]}/{installation}'
if version >= VERSION_1_3 and len(line_split) >= 6:
if line_split[4].strip().lower() in OPERATION_UPDATE_SYMBOLS:
if '(partial)' in line_split[-1]:
res['partial'].add(update_id)
else:
res['full'].add(update_id)
else:
res['full'].add(update_id)
except Exception:
traceback.print_exc()
def downgrade(app_ref: str, commit: str, installation: str, root_password: Optional[str], version: Tuple[str, ...]) -> SimpleProcess:
cmd = ('flatpak', 'update', '--no-related', '--no-deps', f'--commit={commit}', app_ref, '-y', f'--{installation}')
return SimpleProcess(cmd=cmd,
root_password=root_password if installation == 'system' else None,
extra_paths={EXPORTS_PATH},
lang=DEFAULT_LANG if version < VERSION_1_12 else None,
success_phrases={'Changes complete.', 'Updates complete.'} if version < VERSION_1_12 else None,
wrong_error_phrases={'Warning'} if version < VERSION_1_12 else None)
def get_app_commits(app_ref: str, origin: str, installation: str, handler: ProcessHandler) -> Optional[List[str]]:
try:
p = SimpleProcess(('flatpak', 'remote-info', '--log', origin, app_ref, f'--{installation}'))
success, output = handler.handle_simple(p)
if output.startswith('error:'):
return
else:
return re.findall(r'Commit+:\s(.+)', output)
except Exception:
raise NoInternetException()
def get_app_commits_data(app_ref: str, origin: str, installation: str, full_str: bool = True) -> List[dict]:
log = run_cmd(f'flatpak remote-info --log {origin} {app_ref} --{installation}')
if not log:
raise NoInternetException()
res = re.findall(r'(Commit|Subject|Date):\s(.+)', log)
commits = []
commit = {}
for idx, data in enumerate(res):
attr = data[0].strip().lower()
commit[attr] = data[1].strip()
if attr == 'commit':
commit[attr] = commit[attr] if full_str else commit[attr][0:8]
if attr == 'date':
commit[attr] = datetime.strptime(commit[attr], '%Y-%m-%d %H:%M:%S +0000')
if (idx + 1) % 3 == 0:
commits.append(commit)
commit = {}
return commits
def search(version: Tuple[str, ...], word: str, installation: str, app_id: bool = False) -> Optional[List[dict]]:
res = run_cmd(f'flatpak search {word} --{installation}', lang=None)
if not res:
return
found = None
split_res = res.strip().split('\n')
if split_res and '\t' in split_res[0]:
found = []
for info in split_res:
if info:
info_list = info.split('\t')
if version >= VERSION_1_3:
id_ = info_list[2].strip()
if app_id and id_ != word:
continue
pkg_ver = info_list[3].strip()
app = {
'name': info_list[0].strip(),
'description': info_list[1].strip(),
'id': id_,
'version': pkg_ver,
'latest_version': pkg_ver,
'branch': info_list[4].strip(),
'origin': info_list[5].strip(),
'runtime': False,
'arch': None, # unknown at this moment,
'ref': None # unknown at this moment
}
elif version >= VERSION_1_2:
id_ = info_list[1].strip()
if app_id and id_ != word:
continue
desc = info_list[0].split('-')
pkg_ver = info_list[2].strip()
app = {
'name': desc[0].strip(),
'description': desc[1].strip(),
'id': id_,
'version': pkg_ver,
'latest_version': pkg_ver,
'branch': info_list[3].strip(),
'origin': info_list[4].strip(),
'runtime': False,
'arch': None, # unknown at this moment,
'ref': None # unknown at this moment
}
else:
id_ = info_list[0].strip()
if app_id and id_ != word:
continue
pkg_ver = info_list[1].strip()
app = {
'name': '',
'description': info_list[4].strip(),
'id': id_,
'version': pkg_ver,
'latest_version': pkg_ver,
'branch': info_list[2].strip(),
'origin': info_list[3].strip(),
'runtime': False,
'arch': None, # unknown at this moment,
'ref': None # unknown at this moment
}
found.append(app)
if app_id and len(found) > 0:
break
return found
def install(app_id: str, origin: str, installation: str, version: Tuple[str, ...]) -> SimpleProcess:
return SimpleProcess(cmd=('flatpak', 'install', origin, app_id, '-y', f'--{installation}'),
extra_paths={EXPORTS_PATH},
lang=DEFAULT_LANG if version < VERSION_1_12 else None,
wrong_error_phrases={'Warning'} if version < VERSION_1_12 else None,
shell=True)
def set_default_remotes(installation: str, root_password: Optional[str] = None) -> SimpleProcess:
cmd = ('flatpak', 'remote-add', '--if-not-exists', 'flathub', f'{FLATHUB_URL}/repo/flathub.flatpakrepo',
f'--{installation}')
return SimpleProcess(cmd, root_password=root_password)
def has_remotes_set() -> bool:
return bool(run_cmd('flatpak remotes').strip())
def list_remotes() -> Dict[str, Set[str]]:
res = {'system': set(), 'user': set()}
output = run_cmd('flatpak remotes').strip()
if output:
lines = output.split('\n')
for line in lines:
remote = line.split('\t')
if 'system' in remote[1]:
res['system'].add(remote[0].strip())
elif 'user' in remote[1]:
res['user'].add(remote[0].strip())
return res
def run(app_id: str):
subprocess.Popen((f'flatpak run {app_id}',), shell=True, env={**os.environ})
def map_update_download_size(app_ids: Iterable[str], installation: str, version: Tuple[str, ...]) -> Dict[str, float]:
success, output = ProcessHandler().handle_simple(SimpleProcess(('flatpak', 'update', f'--{installation}',
'--no-deps')))
if version >= VERSION_1_2:
res = {}
p = re.compile(r'^\d+.\t')
p2 = re.compile(r'([0-9.?a-zA-Z]+\s?)')
for l in output.split('\n'):
if l:
line = l.strip()
if line:
found = p.match(line)
if found:
line_split = line.split('\t')
line_id = line_split[2].strip()
related_id = [appid for appid in app_ids if appid == line_id]
if related_id and len(line_split) >= 7:
size_tuple = p2.findall(line_split[6])
if size_tuple:
if version >= VERSION_1_5:
size = size_tuple[0].split('?')
if size and len(size) > 1:
try:
res[related_id[0].strip()] = size_to_byte(size[0], size[1].strip())
except Exception:
traceback.print_exc()
else:
try:
res[related_id[0].strip()] = size_to_byte(size_tuple[0], size_tuple[1].strip())
except Exception:
traceback.print_exc()
return res

View File

@@ -1,170 +0,0 @@
from typing import Tuple
from bauh.api.abstract.model import SoftwarePackage, PackageStatus
from bauh.commons import resource
from bauh.gems.flatpak import ROOT_DIR, VERSION_1_2
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, 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
self.origin = origin
self.runtime = runtime
self.commit = commit
self.partial = partial
self.installation = installation if installation else 'system'
self.i18n = i18n
self.base_id = None
self.base_ref = None
self.updates_ignored = updates_ignored
self.update_component = update_component # if it is a new app/runtime that has come as an update
if runtime:
self.categories = ['runtime']
def is_incomplete(self):
return self.description is None and self.icon_url
def has_history(self) -> bool:
return not self.partial and not self.update_component and self.installed and self.ref
def has_info(self):
return bool(self.id)
def can_be_downgraded(self):
return not self.partial and not self.update_component and self.installed and self.ref
def get_type(self):
return 'flatpak'
def get_default_icon_path(self):
return resource.get_path('img/flatpak.svg', ROOT_DIR)
def get_type_icon_path(self):
return self.get_default_icon_path()
def is_application(self):
return not self.runtime and not self.partial and not self.update_component
def get_disk_cache_path(self):
return super(FlatpakApplication, self).get_disk_cache_path() + '/installed/' + self.id
def get_data_to_cache(self):
if not self.update_component:
return {
'description': self.description,
'icon_url': self.icon_url,
'latest_version': self.latest_version,
'version': self.version,
'name': self.name,
'categories': self.categories
}
def fill_cached_data(self, data: dict):
for attr in self.get_data_to_cache().keys():
if data.get(attr) and not getattr(self, attr):
setattr(self, attr, data[attr])
def can_be_run(self) -> bool:
return self.installed and not self.runtime and not self.partial and not self.update_component
def get_publisher(self):
return self.origin
def gen_partial(self, partial_id: str) -> "FlatpakApplication":
partial = FlatpakApplication()
partial.partial = True
partial.id = partial_id
partial.base_id = self.id
partial.installation = self.installation
partial.origin = self.origin
partial.branch = self.branch
partial.i18n = self.i18n
partial.arch = self.arch
partial.name = self.name
partial.version = self.version
partial.latest_version = self.latest_version
partial.installed = self.installed
partial.runtime = True
if self.ref:
partial.base_ref = self.ref
partial.ref = '/'.join((partial_id, *self.ref.split('/')[1:]))
partial.status = PackageStatus.READY
partial.name += ' ({})'.format(partial_id.split('.')[-1])
return partial
def get_name_tooltip(self) -> str:
if self.installed and self.installation and self.i18n is not None:
return '{} ({})'.format(self.name, self.i18n['flatpak.info.installation.{}'.format(self.installation.lower().strip())])
return self.name
def supports_backup(self) -> bool:
return True
def supports_ignored_updates(self) -> bool:
return self.installed
def is_update_ignored(self) -> bool:
return self.updates_ignored
def get_update_ignore_key(self) -> str:
return '{}:{}:{}'.format(self.installation, self.id, self.branch)
def __eq__(self, other):
if isinstance(other, FlatpakApplication):
return self.id == other.id and self.installation == other.installation and self.branch == other.branch \
and self.runtime == other.runtime and self.partial == other.partial and \
self.update_component == other.update_component
def __hash__(self) -> int:
hash_sum = 0
for attr in ('id', 'installation', 'branch', 'runtime', 'partial', 'update_component'):
hash_sum += hash(getattr(self, attr))
return hash_sum
def get_disk_icon_path(self) -> str:
if not self.runtime:
return super(FlatpakApplication, self).get_disk_icon_path()
def get_update_id(self, flatpak_version: Tuple[str, ...]) -> str:
if flatpak_version >= VERSION_1_2:
return f'{self.id}/{self.branch}/{self.installation}/{self.origin}'
else:
return f'{self.installation}/{self.ref}'
def can_be_installed(self) -> bool:
return not self.update_component and not self.installed
def can_be_updated(self) -> bool:
return self.update_component or super(FlatpakApplication, self).can_be_updated()
def can_be_uninstalled(self) -> bool:
return not self.update_component and super(FlatpakApplication, self).can_be_uninstalled()
def update_ref(self):
if self.id and self.arch and self.branch:
self.ref = f'{self.id}/{self.arch}/{self.branch}'
def is_trustable(self) -> bool:
return False
def __repr__(self) -> str:
return f'Flatpak (id={self.id}, branch={self.branch}, origin={self.origin}, installation={self.installation},' \
f' partial={self.partial}, update_component={self.update_component})'
def __str__(self):
return self.__repr__()

View File

@@ -1,179 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24.007744"
height="23.836931"
viewBox="0 0 6.3520486 6.3068546"
version="1.1"
id="svg3871"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="flatpak.svg">
<defs
id="defs3865" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="8.3644404"
inkscape:cy="118.27981"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
showborder="false"
inkscape:window-width="1360"
inkscape:window-height="703"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-bottom="-0.2"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
units="px" />
<metadata
id="metadata3868">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-12.150001,-173.82134)">
<g
transform="matrix(0.04446643,0,0,0.05717234,-22.737812,126.67341)"
id="g10674"
style="stroke-width:0.77710575">
<path
sodipodi:nodetypes="ccccccccccc"
inkscape:connector-curvature="0"
id="path10642"
d="m 856.01397,830.22631 -66.76365,43.44891 v 34.93973 l 33.38182,21.72315 33.37926,-21.72315 v -0.005 l 0.003,0.003 33.38183,21.72574 33.37925,-21.72315 v -34.93979 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:9.3252697;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
style="stroke-width:0.58728963"
transform="matrix(0.50221552,0,0,0.50636711,429.63205,432.90461)"
id="g10652">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect10644"
width="79.110413"
height="79.110413"
x="1289.9076"
y="279.42584"
rx="0"
ry="0"
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
id="path10648"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path10650"
d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
ry="0"
rx="0"
y="215.8064"
x="1226.2882"
height="79.110413"
width="79.110413"
id="rect10646"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
style="stroke-width:0.58728963"
transform="matrix(0.50221552,0,0,0.50636711,463.01368,454.62849)"
id="g10662">
<rect
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
ry="0"
rx="0"
y="279.42584"
x="1289.9076"
height="79.110413"
width="79.110413"
id="rect10654"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect10656"
width="79.110413"
height="79.110413"
x="1226.2882"
y="215.8064"
rx="0"
ry="0"
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
<path
inkscape:connector-curvature="0"
id="path10658"
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 783.00003,826.54445 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
id="path10660"
inkscape:connector-curvature="0" />
</g>
<g
style="stroke-width:0.58728963"
id="g10672"
transform="matrix(0.50221552,0,0,0.50636711,396.25042,454.62849)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect10664"
width="79.110413"
height="79.110413"
x="1289.9076"
y="279.42584"
rx="0"
ry="0"
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
<rect
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
ry="0"
rx="0"
y="215.8064"
x="1226.2882"
height="79.110413"
width="79.110413"
id="rect10666"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
id="path10668"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path10670"
d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Full update
flatpak.action.full_update.description=It completely updates the Flatpak apps and components. Useful if you are having issues with runtime updates.
flatpak.action.full_update.status=Updating Flatpak apps and components
flatpak.config.install_level=level
flatpak.config.install_level.ask.tip={app} will ask the level that should be applied during the app installation
flatpak.config.install_level.system=system
flatpak.config.install_level.system.tip=Applications will be installed for all the device users
flatpak.config.install_level.user=user
flatpak.config.install_level.user.tip=Application will be installed only for the current user
flatpak.downgrade.commits=Sestan llegint les revisions del paquet
flatpak.downgrade.impossible.body=No sha pogut revertir la versió: {} és a la seva primera versió
flatpak.downgrade.impossible.title=Error
flatpak.downgrade.reverting=Sestà revertint la versió
flatpak.history.commit=revisió
flatpak.history.date=data
flatpak.history.subject=tema
flatpak.info.arch=arquitectura
flatpak.info.branch=branca
flatpak.info.bugtrackerurl=informe derrors
flatpak.info.collection=col·lecció
flatpak.info.commit=revisió
flatpak.info.currentreleasedate=data de publicació
flatpak.info.currentreleasedescription=descripció de la versió
flatpak.info.currentreleaseversion=versió
flatpak.info.date=data
flatpak.info.description=descripció
flatpak.info.developername=desenvolupador
flatpak.info.donationurl=donatius
flatpak.info.downloadflatpakrefurl=ref
flatpak.info.flatpakappid=id
flatpak.info.helpurl=ajuda
flatpak.info.homepageurl=pàgina
flatpak.info.id=id
flatpak.info.installation=instal·lació
flatpak.info.installation.system=sistema
flatpak.info.installation.user=usuari
flatpak.info.installed=instal·lat
flatpak.info.instoresincedate=afegit el
flatpak.info.license=llicència
flatpak.info.name=nom
flatpak.info.origin=origen
flatpak.info.parent=pare
flatpak.info.projectlicense=llicència
flatpak.info.ref=ref
flatpak.info.runtime=entorn dexecució
flatpak.info.sdk=sdk
flatpak.info.subject=tema
flatpak.info.translateurl=Traducció
flatpak.info.type=tipus
flatpak.info.version=versió
flatpak.install.bad_install_level.body=Valor invàlid per a {field} al fitxer de configuració {file}
flatpak.install.install_level.body=S'ha d'instal·lar {} per a tots els usuaris del dispositiu (sistema) ?
flatpak.install.install_level.title=Tipus d'instal·lació
flatpak.install.ref_choose.title=Multiple references
flatpak.install.ref_choose.body=There are multiple references for {}. Select one to proceed:
flatpak.notification.disable=Si no voleu utilitzar aplicacions Flatpak, desmarqueu {} a {}
flatpak.notification.no_remotes=No hi ha dipòsits («remotes») del Flatpak configurats. No podreu cercar aplicacions Flatpak.
flatpak.remotes.system_flathub.error=No s'ha pogut afegir Flathub com a dipòsit del sistema (remote)
gem.flatpak.info=Aplicacions disponibles a Flathub i altres repositoris configurats al vostre sistema

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Vollständige Aktualisierung
flatpak.action.full_update.description=Aktualisiert die Flatpak-Anwendungen und -Komponenten vollständig. Nützlich, wenn Sie Probleme mit Laufzeitaktualisierungen haben.
flatpak.action.full_update.status=Aktualisierung der Flatpak-Anwendungen und -Komponenten
flatpak.config.install_level=Ebene
flatpak.config.install_level.ask.tip={app} fragt nach der Ebene, die bei der Installation der App angewendet werden soll
flatpak.config.install_level.system=System
flatpak.config.install_level.system.tip=Anwendungen werden für alle Benutzer des Geräts installiert
flatpak.config.install_level.user=Benutzer
flatpak.config.install_level.user.tip=Die Anwendung wird nur für den aktuellen Benutzer installiert
flatpak.downgrade.commits=Lesen von Paket-Commits
flatpak.downgrade.impossible.body=Downgrade nicht möglich: {} ist in seiner ersten Version
flatpak.downgrade.impossible.title=Fehler
flatpak.downgrade.reverting=Version zurücksetzen
flatpak.history.commit=Commit
flatpak.history.date=Datum
flatpak.history.subject=Betreff
flatpak.info.arch=Architektur
flatpak.info.branch=Branch
flatpak.info.bugtrackerurl=Bug-Tracker-URL
flatpak.info.collection=Sammlung
flatpak.info.commit=Commit
flatpak.info.currentreleasedate=Veröffentlichungsdatum
flatpak.info.currentreleasedescription=Versionsbeschreibung
flatpak.info.currentreleaseversion=Version
flatpak.info.date=Datum
flatpak.info.description=Beschreibung
flatpak.info.developername=Entwickler
flatpak.info.donationurl=URL für Spenden
flatpak.info.downloadflatpakrefurl=Ref
flatpak.info.flatpakappid=ID
flatpak.info.helpurl=URL für Hilfe
flatpak.info.homepageurl=URL der Internetseite
flatpak.info.id=ID
flatpak.info.installation=Installation
flatpak.info.installation.system=System
flatpak.info.installation.user=Benutzer
flatpak.info.installed=installiert
flatpak.info.instoresincedate=hinzugefügt in
flatpak.info.license=Lizenz
flatpak.info.name=Name
flatpak.info.origin=Herkunft
flatpak.info.parent=übergeordnete
flatpak.info.projectlicense=Lizenz
flatpak.info.ref=ref
flatpak.info.runtime=Laufzeit
flatpak.info.sdk=SDK
flatpak.info.subject=Thema
flatpak.info.translateurl=URL der Übersetzung
flatpak.info.type=Typ
flatpak.info.version=Version
flatpak.install.bad_install_level.body=Ungültiger Wert für {field} in der Konfigurationsdatei {file}
flatpak.install.install_level.body=Soll {} für alle Gerätebenutzer (System) installiert werden?
flatpak.install.install_level.title=Installationsart
flatpak.install.ref_choose.title=Mehrere Referenzen
flatpak.install.ref_choose.body=Es gibt mehrere Referenzen für {}. Wählen Sie eine aus, um fortzufahren:
flatpak.notification.disable=Wenn Sie keine Flatpak-Anwendungen verwenden möchten, deaktivieren Sie {} in {}
flatpak.notification.no_remotes=Keine Flatpak-Remotes konfiguriert. Es wird nicht möglich sein, nach Flatpak-Anwendungen zu suchen.
flatpak.remotes.system_flathub.error=Es war nicht möglich, Flathub als Systemrepository (remote) hinzuzufügen
gem.flatpak.info=Auf Flathub verfügbare Anwendungen und andere auf Ihrem System konfigurierte Repositories

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Full update
flatpak.action.full_update.description=It completely updates the Flatpak apps and components. Useful if you are having issues with runtime updates.
flatpak.action.full_update.status=Updating Flatpak apps and components
flatpak.config.install_level=level
flatpak.config.install_level.ask.tip={app} will ask the level that should be applied during the app installation
flatpak.config.install_level.system=system
flatpak.config.install_level.system.tip=Applications will be installed for all the device users
flatpak.config.install_level.user=user
flatpak.config.install_level.user.tip=Application will be installed only for the current user
flatpak.downgrade.commits=Reading package commits
flatpak.downgrade.impossible.body=Impossible to downgrade: {} is in its first version
flatpak.downgrade.impossible.title=Error
flatpak.downgrade.reverting=Reverting version
flatpak.history.commit=commit
flatpak.history.date=date
flatpak.history.subject=subject
flatpak.info.arch=arch
flatpak.info.branch=branch
flatpak.info.bugtrackerurl=bug tracker URL
flatpak.info.collection=collection
flatpak.info.commit=commit
flatpak.info.currentreleasedate=release date
flatpak.info.currentreleasedescription=version description
flatpak.info.currentreleaseversion=version
flatpak.info.date=date
flatpak.info.description=description
flatpak.info.developername=developer
flatpak.info.donationurl=donation URL
flatpak.info.downloadflatpakrefurl=Ref
flatpak.info.flatpakappid=id
flatpak.info.helpurl=Help url
flatpak.info.homepageurl=Home url
flatpak.info.id=id
flatpak.info.installation=installation
flatpak.info.installation.system=system
flatpak.info.installation.user=user
flatpak.info.installed=installed
flatpak.info.instoresincedate=added in
flatpak.info.license=license
flatpak.info.name=name
flatpak.info.origin=origin
flatpak.info.parent=parent
flatpak.info.projectlicense=license
flatpak.info.ref=ref
flatpak.info.runtime=runtime
flatpak.info.sdk=sdk
flatpak.info.subject=subject
flatpak.info.translateurl=translate url
flatpak.info.type=type
flatpak.info.version=version
flatpak.install.bad_install_level.body=Invalid value for {field} in the configuration file {file}
flatpak.install.install_level.body=Should {} be installed for all the device users (system)?
flatpak.install.install_level.title=Installation type
flatpak.install.ref_choose.title=Multiple references
flatpak.install.ref_choose.body=There are multiple references for {}. Select one to proceed:
flatpak.notification.disable=If you do not want to use Flatpak applications, uncheck {} in {}
flatpak.notification.no_remotes=No Flatpak remotes set. It will not be possible to search for Flatpak apps.
flatpak.remotes.system_flathub.error=It was not possible to add Flathub as a system repository (remote)
gem.flatpak.info=Applications available on Flathub and other repositories configured on your system

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Actualización completa
flatpak.action.full_update.description=Actualiza completamente las aplicaciones y componentes Flatpak. Útil si hay problemas con las actualizaciones de runtimes.
flatpak.action.full_update.status=Actualizando las aplicaciones y componentes Flatpak
flatpak.config.install_level=nivel
flatpak.config.install_level.ask.tip={app} preguntará el nivel que debe aplicarse durante la instalación de la aplicación
flatpak.config.install_level.system=sistema
flatpak.config.install_level.system.tip=Se instalarán aplicaciones para todos los usuarios del dispositivo
flatpak.config.install_level.user=usuario
flatpak.config.install_level.user.tip=La aplicación se instalará solo para el usuario actual
flatpak.downgrade.commits=Leyendo commits del paquete
flatpak.downgrade.impossible.body=Imposible revertir la versión: {} está en su primera versión
flatpak.downgrade.impossible.title=Error
flatpak.downgrade.reverting=Revirtiendo la versión
flatpak.history.commit=commit
flatpak.history.date=fecha
flatpak.history.subject=tema
flatpak.info.arch=arquitectura
flatpak.info.branch=rama
flatpak.info.bugtrackerurl=reporte de errores
flatpak.info.collection=colección
flatpak.info.commit=commit
flatpak.info.currentreleasedate=fecha de lanzamiento
flatpak.info.currentreleasedescription=descripción de la versión
flatpak.info.currentreleaseversion=versión
flatpak.info.date=fecha
flatpak.info.description=descripción
flatpak.info.developername=desarrollador
flatpak.info.donationurl=donaciones
flatpak.info.downloadflatpakrefurl=ref
flatpak.info.flatpakappid=id
flatpak.info.helpurl=ayuda
flatpak.info.homepageurl=página
flatpak.info.id=id
flatpak.info.installation=instalación
flatpak.info.installation.system=sistema
flatpak.info.installation.user=usuario
flatpak.info.installed=instalado
flatpak.info.instoresincedate=agregado en
flatpak.info.license=licencia
flatpak.info.name=nombre
flatpak.info.origin=origen
flatpak.info.parent=padre
flatpak.info.projectlicense=licencia
flatpak.info.ref=ref
flatpak.info.runtime=runtime
flatpak.info.sdk=sdk
flatpak.info.subject=tema
flatpak.info.translateurl=Traducción
flatpak.info.type=tipo
flatpak.info.version=versión
flatpak.install.bad_install_level.body=Valor inválido para {field} en el archivo de configuración {file}
flatpak.install.install_level.body=¿Debería {} estar instalado para todos los usuarios del dispositivo (sistema)?
flatpak.install.install_level.title=Tipo de instalación
flatpak.install.ref_choose.title=Varias referencias
flatpak.install.ref_choose.body=Hay varias referencias para {}. Seleccione una para proceder:
flatpak.notification.disable=Si no desea usar aplicativos Flatpak, desmarque {} en {}
flatpak.notification.no_remotes=No hay repositorios (remotes) Flatpak configurados. No será posible buscar aplicativos Flatpak.
flatpak.remotes.system_flathub.error=No fue posible agregar Flathub como repositorio del sistema (remote)
gem.flatpak.info=Aplicaciones disponibles en Flathub y otros repositorios configurados en su sistema

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Full update
flatpak.action.full_update.description=It completely updates the Flatpak apps and components. Useful if you are having issues with runtime updates.
flatpak.action.full_update.status=Updating Flatpak apps and components
flatpak.config.install_level=niveau
flatpak.config.install_level.ask.tip={app} va demander le niveau à appliquer durant l'installation
flatpak.config.install_level.system=système
flatpak.config.install_level.system.tip=Les applications seront installées pour tous les utilisateurs
flatpak.config.install_level.user=utilisateurs
flatpak.config.install_level.user.tip=L'application sera installée uniquement pour l'utilisateur actuel
flatpak.downgrade.commits=Lecture des commits du paquet
flatpak.downgrade.impossible.body=Impossible de downgrader: {} est à sa première version
flatpak.downgrade.impossible.title=Erreur
flatpak.downgrade.reverting=Revert de version
flatpak.history.commit=commit
flatpak.history.date=date
flatpak.history.subject=sujet
flatpak.info.arch=architecture
flatpak.info.branch=branche
flatpak.info.bugtrackerurl=URL du traceur de bug
flatpak.info.collection=collection
flatpak.info.commit=commit
flatpak.info.currentreleasedate=date de parution
flatpak.info.currentreleasedescription=description de version
flatpak.info.currentreleaseversion=version
flatpak.info.date=date
flatpak.info.description=description
flatpak.info.developername=développeur
flatpak.info.donationurl=URL pour donner
flatpak.info.downloadflatpakrefurl=Ref
flatpak.info.flatpakappid=id
flatpak.info.helpurl=URL d'aide
flatpak.info.homepageurl=URL d'accueil
flatpak.info.id=id
flatpak.info.installation=installation
flatpak.info.installation.system=système
flatpak.info.installation.user=utilisateur
flatpak.info.installed=installé
flatpak.info.instoresincedate=ajouté dans
flatpak.info.license=licence
flatpak.info.name=nom
flatpak.info.origin=origin
flatpak.info.parent=parent
flatpak.info.projectlicense=licence
flatpak.info.ref=ref
flatpak.info.runtime=exécution
flatpak.info.sdk=sdk
flatpak.info.subject=sujet
flatpak.info.translateurl=URL de traduction
flatpak.info.type=type
flatpak.info.version=version
flatpak.install.bad_install_level.body=Valeur invalide pour {field} dans le fichier de configuration {file}
flatpak.install.install_level.body=Installer {} pour tous les utilisateurs?
flatpak.install.install_level.title=type d'installation
flatpak.install.ref_choose.title=Référence multiple
flatpak.install.ref_choose.body=Il y a des références multiples pour {}. Choisissez en une pour continuer:
flatpak.notification.disable=Si vous ne voulez pas d'applications Flatpak, décochez {} dans {}
flatpak.notification.no_remotes=Pas d'hôtes Flatpak définis. Il sera impossible de chercher des applications Flatpak.
flatpak.remotes.system_flathub.error=Impossible d'ajouter Flathub comme répo distant système
gem.flatpak.info=Applications disponibles sur Flathub et autres répos définis sur votre système

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Aggiornamento completo
flatpak.action.full_update.description=Aggiorna completamente le app e i componenti Flatpak. Utile se riscontri problemi con gli aggiornamenti di runtime.
flatpak.action.full_update.status=Aggiornamento delle app e dei componenti Flatpak
flatpak.config.install_level=livello
flatpak.config.install_level.ask.tip={app} chiederà il livello da applicare durante l'installazione dell'app
flatpak.config.install_level.system=sistema
flatpak.config.install_level.system.tip=Le applicazioni verranno installate per tutti gli utenti del dispositivo
flatpak.config.install_level.user=utente
flatpak.config.install_level.user.tip=L'applicazione verrà installata solo per l'utente corrente
flatpak.downgrade.commits=lettura commits del pacchetto
flatpak.downgrade.impossible.body=Iimpossibile effettuare il downgrade: {} è nella sua prima versione
flatpak.downgrade.impossible.title=Errore
flatpak.downgrade.reverting=Ripristino versione
flatpak.history.commit=commit
flatpak.history.date=data
flatpak.history.subject=soggetto
flatpak.info.arch=arch
flatpak.info.branch=branch
flatpak.info.bugtrackerurl=URL del tracciatore di bug
flatpak.info.collection=raccolta
flatpak.info.commit=commit
flatpak.info.currentreleasedate=data di rilascio
flatpak.info.currentreleasedescription=descrizione della versione
flatpak.info.currentreleaseversion=versione
flatpak.info.date=data
flatpak.info.description=descrizione
flatpak.info.developername=sviluppatore
flatpak.info.donationurl=donazioni URL
flatpak.info.downloadflatpakrefurl=Rif
flatpak.info.flatpakappid=id
flatpak.info.helpurl=Aiuto url
flatpak.info.homepageurl=Home url
flatpak.info.id=id
flatpak.info.installation=installazione
flatpak.info.installation.system=sistema
flatpak.info.installation.user=utente
flatpak.info.installed=installato
flatpak.info.instoresincedate=aggiunto in
flatpak.info.license=licenza
flatpak.info.name=nome
flatpak.info.origin=origine
flatpak.info.parent=genitore
flatpak.info.projectlicense=licenza
flatpak.info.ref=ref
flatpak.info.runtime=runtime
flatpak.info.sdk=sdk
flatpak.info.subject=subject
flatpak.info.translateurl=traduci url
flatpak.info.type=tipo
flatpak.info.version=versione
flatpak.install.bad_install_level.body=Valore non valido per {field} nel file di configurazione {file}
flatpak.install.install_level.body={} deve essere installato per tutti gli utenti del dispositivo (sistema) ?
flatpak.install.install_level.title=Tipo di installazione
flatpak.install.ref_choose.title=Riferimenti multipli
flatpak.install.ref_choose.body=Sono presenti più riferimenti per {}. Selezionane uno per procedere:
flatpak.notification.disable=Se non si desidera utilizzare le applicazioni Flatpak, deselezionare {} in {}
flatpak.notification.no_remotes=Nessun set remoti Flatpak. Non sarà possibile cercare app Flatpak.
flatpak.remotes.system_flathub.error=Non è stato possibile aggiungere Flathub come repository di sistema (remote)
gem.flatpak.info=Applicazioni disponibili su Flathub e altri repository configurati sul tuo sistema

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Atualização completa
flatpak.action.full_update.description=Atualiza completamente aplicações e componentes Flatpak instalados. Útil se você estiver com problemas de atualização dos runtimes.
flatpak.action.full_update.status=Atualizando aplicações e componentes Flatpak
flatpak.config.install_level=nível
flatpak.config.install_level.ask.tip=O {app} perguntará qual o nível deverá ser aplicado durante a instalação do aplicativo
flatpak.config.install_level.system=sistema
flatpak.config.install_level.system.tip=Os aplicativos serão instalados para todos os usuários do dispositivo
flatpak.config.install_level.user=usuário
flatpak.config.install_level.user.tip=Os aplicativos serão instalados somente para o usuário atual
flatpak.downgrade.commits=Lendo os commits do pacote
flatpak.downgrade.impossible.body=Impossível reverter a versão: {} está na sua primeira versão
flatpak.downgrade.impossible.title=Erro
flatpak.downgrade.reverting=Revertendo a versão
flatpak.history.commit=commit
flatpak.history.date=data
flatpak.history.subject=assunto
flatpak.info.arch=arquitetura
flatpak.info.branch=ramo
flatpak.info.bugtrackerurl=reporte de erros
flatpak.info.collection=coleção
flatpak.info.commit=commit
flatpak.info.currentreleasedate=data de lançamento
flatpak.info.currentreleasedescription=descrição da versão
flatpak.info.currentreleaseversion=versão
flatpak.info.date=data
flatpak.info.description=descrição
flatpak.info.developername=desenvolvedor
flatpak.info.donationurl=doações
flatpak.info.downloadflatpakrefurl=ref
flatpak.info.flatpakappid=id
flatpak.info.helpurl=ajuda
flatpak.info.homepageurl=página
flatpak.info.id=id
flatpak.info.installation=instalação
flatpak.info.installation.system=sistema
flatpak.info.installation.user=usuário
flatpak.info.installed=instalado
flatpak.info.instoresincedate=adicionado em
flatpak.info.license=licença
flatpak.info.name=nome
flatpak.info.origin=origem
flatpak.info.parent=pai
flatpak.info.projectlicense=licença
flatpak.info.ref=ref
flatpak.info.runtime=runtime
flatpak.info.sdk=sdk
flatpak.info.subject=assunto
flatpak.info.translateurl=tradução
flatpak.info.type=tipo
flatpak.info.version=versão
flatpak.install.bad_install_level.body=Valor inválido para {field} no arquivo de configuração {file}
flatpak.install.install_level.body={} deve ser instalado para todos os usuários desse dispositivo (sistema) ?
flatpak.install.install_level.title=Tipo de instalação
flatpak.install.ref_choose.title=Múltiplas referências
flatpak.install.ref_choose.body=Existem múltiplas referências para {}. Selecione uma para continuar:
flatpak.notification.disable=Se não deseja usar aplicativos Flatpak, desmarque {} em {}
flatpak.notification.no_remotes=Não há repositórios (remotes) Flatpak configurados. Não será possível buscar aplicativos Flatpak.
flatpak.remotes.system_flathub.error=Não foi possível adicionar o Flathub como um repositório do sistema (remote)
gem.flatpak.info=Aplicativos disponíveis no Flathub e outros repositórios configurados no seu sistema

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Полное обновление
flatpak.action.full_update.description=Полностью обновляет приложения и компоненты Flatpak. Пригодится, если возникают проблемы с обновлениями во время выполнения.
flatpak.action.full_update.status=Обновление приложений и компонентов Flatpak
flatpak.config.install_level=Уровень
flatpak.config.install_level.ask.tip={app} запросит уровень, который должен быть применен во время установки приложения
flatpak.config.install_level.system=Система
flatpak.config.install_level.system.tip=Приложения будут установлены для всех пользователей устройства
flatpak.config.install_level.user=Пользователь
flatpak.config.install_level.user.tip=Приложение будет установлено только для текущего пользователя
flatpak.downgrade.commits=Чтение коммитов пакета
flatpak.downgrade.impossible.body=Невозможно понизить версию: {} находится в первой версии
flatpak.downgrade.impossible.title=Ошибка
flatpak.downgrade.reverting=Возврат версии
flatpak.history.commit=Коммит
flatpak.history.date=Дата
flatpak.history.subject=Cубъект
flatpak.info.arch=Архитектура
flatpak.info.branch=Ветка
flatpak.info.bugtrackerurl=Страница баг-трекера
flatpak.info.collection=Коллекция
flatpak.info.commit=Коммит
flatpak.info.currentreleasedate=Дата релиза
flatpak.info.currentreleasedescription=Описание версии
flatpak.info.currentreleaseversion=Версия
flatpak.info.date=Дата
flatpak.info.description=Описание
flatpak.info.developername=Разработчик
flatpak.info.donationurl=Страница пожертвований
flatpak.info.downloadflatpakrefurl=Ссылка
flatpak.info.flatpakappid=Идентификатор
flatpak.info.helpurl=Страница поддержки
flatpak.info.homepageurl=Домашяя страница
flatpak.info.id=Идентификатор
flatpak.info.installation=Тип установки
flatpak.info.installation.system=Система
flatpak.info.installation.user=Пользователь
flatpak.info.installed=Размер установки
flatpak.info.instoresincedate=Добавлено в
flatpak.info.license=Лицензия
flatpak.info.name=Имя
flatpak.info.origin=Происхождение
flatpak.info.parent=Разработчик
flatpak.info.projectlicense=Лицензия
flatpak.info.ref=Ссылка
flatpak.info.runtime=Среда выполнения
flatpak.info.sdk=Среда разработки
flatpak.info.subject=Субъект
flatpak.info.translateurl=Страница переводов
flatpak.info.type=Тип
flatpak.info.version=Версия
flatpak.install.bad_install_level.body=Недопустимое значение для {field} в файле конфигурации {file}
flatpak.install.install_level.body=Должен ли {} быть установлен для всех пользователей устройства (системы)?
flatpak.install.install_level.title=Тип установки
flatpak.install.ref_choose.title=Множественные ссылки
flatpak.install.ref_choose.body=Для {} существует несколько ссылок. Выберите одну, чтобы продолжить:
flatpak.notification.disable=Если вы не хотите использовать приложения Flatpak, снимите флажок {} в {}
flatpak.notification.no_remotes=Поддержка Flatpak не установлена. Поиск приложений Flatpak будет невозможен.
flatpak.remotes.system_flathub.error=Не удалось добавить Flathub в качестве системного репозитория (удаленного)
gem.flatpak.info=Приложения, доступные на Flathub и других репозиториях, настроенных в вашей системе

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=Full update
flatpak.action.full_update.description=It completely updates the Flatpak apps and components. Useful if you are having issues with runtime updates.
flatpak.action.full_update.status=Updating Flatpak apps and components
flatpak.config.install_level=seviye
flatpak.config.install_level.ask.tip={app} uygulama kurulumu sırasında uygulanması gereken seviyeyi soracak
flatpak.config.install_level.system=sistem
flatpak.config.install_level.system.tip=Uygulamalar tüm cihaz kullanıcıları için yüklenecek
flatpak.config.install_level.user=kullanıcı
flatpak.config.install_level.user.tip=Uygulama yalnızca geçerli kullanıcı için yüklenecek
flatpak.downgrade.commits=Paket notları okunuyor
flatpak.downgrade.impossible.body=Sürüm düşürme imkansız: {} zaten ilk sürümünde
flatpak.downgrade.impossible.title=Hata
flatpak.downgrade.reverting=Sürüm geri döndürülüyor
flatpak.history.commit=işlem
flatpak.history.date=tarih
flatpak.history.subject=konusu
flatpak.info.arch=arch
flatpak.info.branch=dal
flatpak.info.bugtrackerurl=hata izleme bağlantısı
flatpak.info.collection=koleksiyon
flatpak.info.commit=işlem
flatpak.info.currentreleasedate=sürüm tarihi
flatpak.info.currentreleasedescription=sürüm açıklaması
flatpak.info.currentreleaseversion=sürüm
flatpak.info.date=tarih
flatpak.info.description=açıklama
flatpak.info.developername=geliştirici
flatpak.info.donationurl=bağış bağlantısı
flatpak.info.downloadflatpakrefurl=Ref
flatpak.info.flatpakappid=kimlik
flatpak.info.helpurl=Yardım bağlantısı
flatpak.info.homepageurl=Anasayfa bağlantısı
flatpak.info.id=kimlik
flatpak.info.installation=kurulum
flatpak.info.installation.system=sistem
flatpak.info.installation.user=kullanıcı
flatpak.info.installed=kurulu
flatpak.info.instoresincedate=eklendi
flatpak.info.license=lisans
flatpak.info.name=isim
flatpak.info.origin=kökeni
flatpak.info.parent=üst
flatpak.info.projectlicense=lisans
flatpak.info.ref=ref
flatpak.info.runtime=zamanı
flatpak.info.sdk=sdk
flatpak.info.subject=konusu
flatpak.info.translateurl=çeviri bağlantısı
flatpak.info.type=türü
flatpak.info.version=sürüm
flatpak.install.bad_install_level.body={file} yapılandırma dosyasında {field} için geçersiz değer
flatpak.install.install_level.body=Tüm cihaz kullanıcıları (sistem) için {} kurulmalı mı ?
flatpak.install.install_level.title=Kurulum türü
flatpak.install.ref_choose.title=Multiple references
flatpak.install.ref_choose.body=There are multiple references for {}. Select one to proceed:
flatpak.notification.disable=If you do not want to use Flatpak applications, uncheck {} in {}
flatpak.notification.no_remotes=Flatpak uygulamalarını kullanmak istemiyorsanız, {} içindeki {} işaretini kaldırın
flatpak.remotes.system_flathub.error=Flathub sistem havuzu (uzak) olarak eklenemedi
gem.flatpak.info=Flathub ve sisteminizde yapılandırılmış diğer depolarda bulunan uygulamalar

View File

@@ -1,59 +0,0 @@
flatpak.action.full_update=完整更新
flatpak.action.full_update.description=它完全更新 Flatpak 应用程序和组件。如果您在运行时更新方面遇到问题,这很有用。
flatpak.action.full_update.status=正在更新 Flatpak 应用程序和组件
flatpak.config.install_level=级别
flatpak.config.install_level.ask.tip={app} 在应用程序安装期间将询问应该应用的级别
flatpak.config.install_level.system=系统
flatpak.config.install_level.system.tip=应用程序将为所有设备用户安装
flatpak.config.install_level.user=用户
flatpak.config.install_level.user.tip=应用程序仅将为当前用户安装
flatpak.downgrade.commits=读取软件包提交
flatpak.downgrade.impossible.body=无法降级:{} 处于其第一个版本
flatpak.downgrade.impossible.title=错误
flatpak.downgrade.reverting=还原版本
flatpak.history.commit=提交
flatpak.history.date=日期
flatpak.history.subject=主题
flatpak.info.arch=架构
flatpak.info.branch=分支
flatpak.info.bugtrackerurl=错误追踪 URL
flatpak.info.collection=集合
flatpak.info.commit=提交
flatpak.info.currentreleasedate=发布日期
flatpak.info.currentreleasedescription=版本描述
flatpak.info.currentreleaseversion=版本
flatpak.info.date=日期
flatpak.info.description=描述
flatpak.info.developername=开发者
flatpak.info.donationurl=捐赠 URL
flatpak.info.downloadflatpakrefurl=引用
flatpak.info.flatpakappid=id
flatpak.info.helpurl=帮助 URL
flatpak.info.homepageurl=主页 URL
flatpak.info.id=id
flatpak.info.installation=安装
flatpak.info.installation.system=系统
flatpak.info.installation.user=用户
flatpak.info.installed=已安装
flatpak.info.instoresincedate=添加于
flatpak.info.license=许可证
flatpak.info.name=名称
flatpak.info.origin=来源
flatpak.info.parent=父级
flatpak.info.projectlicense=许可证
flatpak.info.ref=引用
flatpak.info.runtime=运行时
flatpak.info.sdk=sdk
flatpak.info.subject=主题
flatpak.info.translateurl=翻译 URL
flatpak.info.type=类型
flatpak.info.version=版本
flatpak.install.bad_install_level.body=在配置文件 {file} 中 {field} 的值无效
flatpak.install.install_level.body=是否应该为所有设备用户(系统)安装 {}
flatpak.install.install_level.title=安装类型
flatpak.install.ref_choose.title=多个引用
flatpak.install.ref_choose.body={} 有多个引用。选择一个以继续:
flatpak.notification.disable=如果您不想使用 Flatpak 应用程序,请在 {} 中取消选中 {}
flatpak.notification.no_remotes=未设置 Flatpak 远程。将无法搜索 Flatpak 应用程序。
flatpak.remotes.system_flathub.error=无法将 Flathub 添加为系统存储库(远程)
gem.flatpak.info=在 Flathub 和您系统上配置的其他存储库中可用的应用程序

View File

@@ -1,99 +0,0 @@
import traceback
from io import StringIO
from threading import Thread
from bauh.api.abstract.cache import MemoryCache
from bauh.api.abstract.context import ApplicationContext
from bauh.api.abstract.controller import SoftwareManager
from bauh.api.abstract.model import PackageStatus
from bauh.gems.flatpak.constants import FLATHUB_API_URL, FLATHUB_URL
from bauh.gems.flatpak.model import FlatpakApplication
class FlatpakAsyncDataLoader(Thread):
def __init__(self, app: FlatpakApplication, manager: SoftwareManager, context: ApplicationContext, api_cache: MemoryCache, category_cache: MemoryCache):
super(FlatpakAsyncDataLoader, self).__init__()
self.app = app
self.manager = manager
self.http_client = context.http_client
self.api_cache = api_cache
self.persist = False
self.logger = context.logger
self.category_cache = category_cache
@staticmethod
def format_category(category: str) -> str:
word = StringIO()
last_l = None
for idx, l in enumerate(category):
if idx != 0 and last_l != ' ' and l.isupper() and idx + 1 < len(category) and category[idx + 1].islower():
word.write(' ')
last_l = l.lower()
word.write(last_l)
word.seek(0)
return word.read()
def run(self):
if self.app:
self.app.status = PackageStatus.LOADING_DATA
try:
res = self.http_client.get('{}/apps/{}'.format(FLATHUB_API_URL, self.app.id))
if res and res.text:
data = res.json()
if not data:
self.logger.warning("No data returned for id {} ({})".format(self.app.id, self.app.name))
else:
if not self.app.version:
self.app.version = data.get('version')
if not self.app.name:
self.app.name = data.get('name')
if not self.app.description:
self.app.description = data.get('description', data.get('summary', None))
self.app.icon_url = data.get('iconMobileUrl', None)
self.app.latest_version = data.get('currentReleaseVersion', self.app.version)
if self.app.latest_version and (not self.app.version or not self.app.update):
self.app.version = self.app.latest_version
if not self.app.installed and self.app.latest_version:
self.app.version = self.app.latest_version
if self.app.icon_url and self.app.icon_url.startswith('/'):
self.app.icon_url = FLATHUB_URL + self.app.icon_url
if data.get('categories'):
cats = []
for c in data['categories']:
cached = self.category_cache.get(c['name'])
if not cached:
cached = self.format_category(c['name'])
self.category_cache.add_non_existing(c['name'], cached)
cats.append(cached)
self.app.categories = cats
loaded_data = self.app.get_data_to_cache()
self.api_cache.add(self.app.id, loaded_data)
self.persist = self.app.supports_disk_cache()
else:
self.logger.warning("Could not retrieve app data for id '{}'. Server response: {}. Body: {}".format(self.app.id, res.status_code if res else '?', res.content.decode() if res else '?'))
except Exception:
self.logger.error("Could not retrieve app data for id '{}'".format(self.app.id))
traceback.print_exc()
self.app.status = PackageStatus.READY
if self.persist:
self.manager.cache_to_disk(pkg=self.app, icon_bytes=None, only_icon=False)