mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-06 22:54:16 +02:00
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:
@@ -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)
|
||||
@@ -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}
|
||||
@@ -1,2 +0,0 @@
|
||||
FLATHUB_URL = 'https://flathub.org'
|
||||
FLATHUB_API_URL = FLATHUB_URL + '/api/v1'
|
||||
@@ -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('/')
|
||||
@@ -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
|
||||
@@ -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__()
|
||||
@@ -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 |
@@ -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=S’estan llegint les revisions del paquet
|
||||
flatpak.downgrade.impossible.body=No s’ha pogut revertir la versió: {} és a la seva primera versió
|
||||
flatpak.downgrade.impossible.title=Error
|
||||
flatpak.downgrade.reverting=S’està 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 d’errors
|
||||
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 d’execució
|
||||
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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 и других репозиториях, настроенных в вашей системе
|
||||
@@ -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
|
||||
@@ -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 和您系统上配置的其他存储库中可用的应用程序
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user