From 1d3feeae63335eef48ef57d2c4031b80e6157ee8 Mon Sep 17 00:00:00 2001 From: Sebastian Palencsar Date: Thu, 28 May 2026 06:00:37 +0200 Subject: [PATCH] Remove Snap support from Bearhub --- README.md | 21 +- bauh/desktop/bauh.desktop | 16 +- bauh/desktop/bauh_tray.desktop | 16 +- bauh/gems/arch/controller.py | 95 ---- bauh/gems/arch/pacman.py | 4 - bauh/gems/snap/__init__.py | 14 - bauh/gems/snap/config.py | 11 - bauh/gems/snap/controller.py | 573 -------------------- bauh/gems/snap/model.py | 130 ----- bauh/gems/snap/resources/__init__.py | 0 bauh/gems/snap/resources/img/__init__.py | 0 bauh/gems/snap/resources/img/refresh.svg | 128 ----- bauh/gems/snap/resources/img/snap.svg | 70 --- bauh/gems/snap/resources/locale/__init__.py | 0 bauh/gems/snap/resources/locale/ca | 34 -- bauh/gems/snap/resources/locale/de | 34 -- bauh/gems/snap/resources/locale/en | 34 -- bauh/gems/snap/resources/locale/es | 34 -- bauh/gems/snap/resources/locale/fr | 34 -- bauh/gems/snap/resources/locale/it | 34 -- bauh/gems/snap/resources/locale/pt | 34 -- bauh/gems/snap/resources/locale/ru | 34 -- bauh/gems/snap/resources/locale/tr | 34 -- bauh/gems/snap/resources/locale/zh | 34 -- bauh/gems/snap/snap.py | 65 --- bauh/gems/snap/snapd.py | 120 ---- 26 files changed, 19 insertions(+), 1584 deletions(-) delete mode 100644 bauh/gems/snap/__init__.py delete mode 100644 bauh/gems/snap/config.py delete mode 100644 bauh/gems/snap/controller.py delete mode 100644 bauh/gems/snap/model.py delete mode 100755 bauh/gems/snap/resources/__init__.py delete mode 100755 bauh/gems/snap/resources/img/__init__.py delete mode 100755 bauh/gems/snap/resources/img/refresh.svg delete mode 100644 bauh/gems/snap/resources/img/snap.svg delete mode 100755 bauh/gems/snap/resources/locale/__init__.py delete mode 100644 bauh/gems/snap/resources/locale/ca delete mode 100644 bauh/gems/snap/resources/locale/de delete mode 100644 bauh/gems/snap/resources/locale/en delete mode 100644 bauh/gems/snap/resources/locale/es delete mode 100644 bauh/gems/snap/resources/locale/fr delete mode 100644 bauh/gems/snap/resources/locale/it delete mode 100644 bauh/gems/snap/resources/locale/pt delete mode 100644 bauh/gems/snap/resources/locale/ru delete mode 100644 bauh/gems/snap/resources/locale/tr delete mode 100644 bauh/gems/snap/resources/locale/zh delete mode 100644 bauh/gems/snap/snap.py delete mode 100644 bauh/gems/snap/snapd.py diff --git a/README.md b/README.md index 00f3378a..5491f656 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Large architectural changes or feature redesigns are not the immediate priority. Debian / Apt support is intentionally removed from Bearhub. Other non-Arch backends that remain in the codebase are secondary to the Arch-focused maintenance target. -**bauh** (baoo), formerly known as [fpakman](https://github.com/vinifmor/fpakman), is a graphical interface for managing your Linux software (packages/applications). In Bearhub, the maintained package formats are Arch Linux packages (including AUR), Flatpak, Snap, AppImage and Web applications. +**bauh** (baoo), formerly known as [fpakman](https://github.com/vinifmor/fpakman), is a graphical interface for managing your Linux software (packages/applications). In Bearhub, the maintained package formats are Arch Linux packages (including AUR), Flatpak, AppImage and Web applications. Key features - A management panel where you can: search, install, uninstall, upgrade, downgrade and launch your applications @@ -63,7 +63,7 @@ Key features - [AppImage](#type_appimage) - [Arch packages/AUR](#type_arch) - [Flatpak](#type_flatpak) - - [Snap](#type_snap) + - [Native Web applications](#type_web) 7. [General settings](#settings) - [Forbidden packaging formats](#forbidden_gems) @@ -126,7 +126,6 @@ makepkg -si - `xdg-utils`: to open URLs in the browser (`xdg-open`) - `sqlite`, `fuse2`, `fuse3`: AppImage support - `flatpak`: Flatpak support -- `snapd`: Snap support - `pacman`: ArchLinux package management support - `python-lxml`, `python-beautifulsoup4`: Web apps support - `python-venv`: [isolated installation](#inst_iso) @@ -252,7 +251,6 @@ suggestions: - `Unmark PKGBUILD as editable`: reverts the action described above. Action only available when the configuration property `edit_aur_pkgbuild` is not `false`. - `Allow reinstallation check`: it allows to check if a given AUR packages requires to be rebuilt - `Ignore reinstallation check`: it does not to check if a given AUR packages requires to be rebuilt - - `Check Snaps support`: checks if the Snapd services are properly enabled. - `Reinstall` (AUR only): rebuilds an installed package. - If you have AUR added as a repository on you pacman configuration, make sure to disable bauh's support (through the settings described below) @@ -303,19 +301,6 @@ installation_level: null # defines a default installation level: "user" or "syst - Custom actions supported: - **Full update**: it completely updates the Flatpak apps and components. Useful if you are having issues with runtime updates. -#### Snap - -- Make sure **snapd** is properly installed and enabled on your system: https://snapcraft.io/docs/installing-snapd -- Extra actions: - - `Refresh`: tries to update the current Snap application revision - - `Change channel`: allows to change the Snap application channel -- The configuration file is located at `~/.config/bauh/snap.yml` and it allows the following customizations: -``` -install_channel: false # it allows to select an available channel during the application installation. Default: false -categories_exp: 24 # It defines the expiration time (in HOURS) of the Snaps categories mapping file stored in disc. Use 0 so that it is always updated during initialization. -``` - - #### Native Web applications - It allows the installation of Web applications by typing their addresses/URLs on the search bar @@ -452,7 +437,7 @@ appimage - [appimage](https://github.com/vinifmor/bauh-files/blob/master/appimage/suggestions.txt) - [arch](https://github.com/vinifmor/bauh-files/blob/master/appimage/suggestions.txt) - [flatpak](https://github.com/vinifmor/bauh-files/blob/master/flatpak/suggestions.txt) - - [snap](https://github.com/vinifmor/bauh-files/blob/master/snap/suggestions.txt) + - [web](https://github.com/vinifmor/bauh-files/blob/master/web/env/v2/suggestions.yml) - Most of the files follow the pattern: `{priority_number}=${id or name}` diff --git a/bauh/desktop/bauh.desktop b/bauh/desktop/bauh.desktop index 5bc41863..bfd88a3a 100644 --- a/bauh/desktop/bauh.desktop +++ b/bauh/desktop/bauh.desktop @@ -9,13 +9,13 @@ Name[de]=Anwendungen (Bearhub) Name[ru]=Приложения (Bearhub) Name[tr]=Paket Yönetici (Bearhub) Categories=System; -Comment=Install and remove applications (AppImage, Arch, Flatpak, Snap, Web) -Comment[pt]=Instale e remova aplicativos (AppImage, Arch, Flatpak, Snap, Web) -Comment[es]=Instalar y eliminar aplicaciones (AppImage, Arch, Flatpak, Snap, Web) -Comment[it]=Installa e rimuovi applicazioni (AppImage, Arch, Flatpak, Snap, Web) -Comment[de]=Anwendungen installieren und entfernen (AppImage, Arch, Flatpak, Snap, Web) -Comment[ca]=Instal·lar i eliminar aplicacions (AppImage, Arch, Flatpak, Snap, Web) -Comment[ru]=Установка и удаление приложений (AppImage, Arch, Flatpak, Snap, Web) -Comment[tr]=Uygulama yükle/kaldır (AppImage, Arch, Flatpak, Snap, Web) +Comment=Install and remove applications (AppImage, Arch, Flatpak, Web) +Comment[pt]=Instale e remova aplicativos (AppImage, Arch, Flatpak, Web) +Comment[es]=Instalar y eliminar aplicaciones (AppImage, Arch, Flatpak, Web) +Comment[it]=Installa e rimuovi applicazioni (AppImage, Arch, Flatpak, Web) +Comment[de]=Anwendungen installieren und entfernen (AppImage, Arch, Flatpak, Web) +Comment[ca]=Instal·lar i eliminar aplicacions (AppImage, Arch, Flatpak, Web) +Comment[ru]=Установка и удаление приложений (AppImage, Arch, Flatpak, Web) +Comment[tr]=Uygulama yükle/kaldır (AppImage, Arch, Flatpak, Web) Exec=/usr/bin/bearhub Icon=bearhub diff --git a/bauh/desktop/bauh_tray.desktop b/bauh/desktop/bauh_tray.desktop index c80960c0..ffe43333 100644 --- a/bauh/desktop/bauh_tray.desktop +++ b/bauh/desktop/bauh_tray.desktop @@ -9,13 +9,13 @@ Name[de]=Anwendungen (Bearhub tray) Name[ru]=Приложения (Bearhub tray) Name[tr]=Paket Yönetici (Bearhub tray) Categories=System; -Comment=Install and remove applications (AppImage, Arch, Flatpak, Snap, Web) -Comment[pt]=Instale e remova aplicativos (AppImage, Arch, Flatpak, Snap, Web) -Comment[es]=Instalar y eliminar aplicaciones (AppImage, Arch, Flatpak, Snap, Web) -Comment[it]=Installa e rimuovi applicazioni (AppImage, Arch, Flatpak, Snap, Web) -Comment[de]=Anwendungen installieren und entfernen (AppImage, Arch, Flatpak, Snap, Web) -Comment[ca]=Instal·lar i eliminar aplicacions (AppImage, Arch, Flatpak, Snap, Web) -Comment[ru]=Установка и удаление приложений (AppImage, Arch, Flatpak, Snap, Web) -Comment[tr]=Uygulama yükle/kaldır (AppImage, Arch, Flatpak, Snap, Web) +Comment=Install and remove applications (AppImage, Arch, Flatpak, Web) +Comment[pt]=Instale e remova aplicativos (AppImage, Arch, Flatpak, Web) +Comment[es]=Instalar y eliminar aplicaciones (AppImage, Arch, Flatpak, Web) +Comment[it]=Installa e rimuovi applicazioni (AppImage, Arch, Flatpak, Web) +Comment[de]=Anwendungen installieren und entfernen (AppImage, Arch, Flatpak, Web) +Comment[ca]=Instal·lar i eliminar aplicacions (AppImage, Arch, Flatpak, Web) +Comment[ru]=Установка и удаление приложений (AppImage, Arch, Flatpak, Web) +Comment[tr]=Uygulama yükle/kaldır (AppImage, Arch, Flatpak, Web) Exec=/usr/bin/bearhub-tray Icon=bearhub diff --git a/bauh/gems/arch/controller.py b/bauh/gems/arch/controller.py index cba9b674..7ef1c993 100644 --- a/bauh/gems/arch/controller.py +++ b/bauh/gems/arch/controller.py @@ -3203,15 +3203,6 @@ class ArchManager(SoftwareManager, SettingsController): requires_root=True, refresh=False, manager=self, - requires_confirmation=False), - 'setup_snapd': CustomSoftwareAction(i18n_label_key='arch.custom_action.setup_snapd', - i18n_status_key='arch.custom_action.setup_snapd.status', - i18n_description_key='arch.custom_action.setup_snapd.desc', - manager_method='setup_snapd', - icon_path=get_icon_path(), - requires_root=False, - refresh=False, - manager=self, requires_confirmation=False) } @@ -3226,9 +3217,6 @@ class ArchManager(SoftwareManager, SettingsController): if bool(arch_config['repositories']): yield self._custom_actions['sys_up'] - if pacman.is_snapd_installed(): - yield self._custom_actions['setup_snapd'] - def fill_sizes(self, pkgs: List[ArchPackage]): installed, new, all_names, installed_names = [], [], [], [] @@ -3475,89 +3463,6 @@ class ArchManager(SoftwareManager, SettingsController): if self._remove_from_editable_pkgbuilds(pkg.name): pkg.pkgbuild_editable = False - def setup_snapd(self, root_password: Optional[str], watcher: ProcessWatcher) -> bool: - # checking services - missing_items = [] - for serv, active in system.check_enabled_services('snapd.service', 'snapd.socket').items(): - if not active: - missing_items.append(InputOption(label=self.i18n['snap.custom_action.setup_snapd.service_disabled'].format("'{}'".format(serv)), - value='enable:{}'.format(serv), - read_only=True)) - - for serv, active in system.check_active_services('snapd.service', 'snapd.socket').items(): - if not active: - missing_items.append(InputOption(label=self.i18n['snap.custom_action.setup_snapd.service_inactive'].format("'{}'".format(serv)), - value='start:{}'.format(serv), - read_only=True)) - - link = '/snap' - link_dest = '/var/lib/snapd/snap' - if not os.path.exists('/snap'): - missing_items.append(InputOption(label=self.i18n['snap.custom_action.setup_snapd.missing_link'].format("'{}'".format(link), "'{}'".format(link_dest)), - value='link:{}:{}'.format(link, link_dest), - read_only=True)) - - if missing_items: - actions = MultipleSelectComponent(label=self.i18n['snap.custom_action.setup_snapd.required_actions'], - options=missing_items, - default_options=set(missing_items), - max_per_line=1, - spaces=False) - if watcher.request_confirmation(title=self.i18n['confirmation'].capitalize(), - body='', - components=[actions], - confirmation_label=self.i18n['proceed'].capitalize(), - deny_label=self.i18n['cancel'].capitalize()): - - valid_pwd, pwd = watcher.request_root_password() - - if valid_pwd: - handler = ProcessHandler(watcher) - for a in missing_items: - action = a.value.split(':') - - if action[0] == 'enable': - msg = 'Enabling service {}'.format(action[1]) - watcher.print(msg) - self.logger.info(msg) - proc = SimpleProcess(['systemctl', 'enable', '--now', action[1]], root_password=pwd) - elif action[0] == 'start': - msg = 'Starting service {}'.format(action[1]) - watcher.print(msg) - self.logger.info(msg) - proc = SimpleProcess(['systemctl', 'start', action[1]], root_password=pwd) - elif action[0] == 'link': - msg = 'Creating symbolic link {} for {}'.format(action[1], action[2]) - watcher.print(msg) - self.logger.info(msg) - proc = SimpleProcess(['ln', '-s', action[2], action[1]], root_password=pwd) - else: - msg = "Wrong action '{}'".format(action) - watcher.print(msg) - self.logger.warning(msg) - proc = None - - if not proc: - return False - - success, output = handler.handle_simple(proc) - - if not success: - watcher.show_message(title=self.i18n['error'].capitalize(), - body=output, - type_=MessageType.ERROR) - return False - - watcher.show_message(title=self.i18n['snap.custom_action.setup_snapd.ready'], - body=self.i18n['snap.custom_action.setup_snapd.ready.body'], - type_=MessageType.INFO) - return True - else: - watcher.show_message(title=self.i18n['snap.custom_action.setup_snapd.ready'], - body=self.i18n['snap.custom_action.setup_snapd.ready.body'], - type_=MessageType.INFO) - return True - def _gen_custom_pkgbuild_if_required(self, context: TransactionContext) -> Optional[str]: build_only_chosen = context.config.get('aur_build_only_chosen') diff --git a/bauh/gems/arch/pacman.py b/bauh/gems/arch/pacman.py index e760f9e8..6e184c01 100644 --- a/bauh/gems/arch/pacman.py +++ b/bauh/gems/arch/pacman.py @@ -1002,10 +1002,6 @@ def get_packages_to_sync_first() -> Set[str]: return set() -def is_snapd_installed() -> bool: - return bool(run_cmd('pacman -Qq snapd', print_error=False)) - - def list_hard_requirements(name: str, logger: Optional[logging.Logger] = None, assume_installed: Optional[Set[str]] = None) -> Optional[Set[str]]: cmd = StringIO() diff --git a/bauh/gems/snap/__init__.py b/bauh/gems/snap/__init__.py deleted file mode 100644 index 978c1d33..00000000 --- a/bauh/gems/snap/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -import os - -from bauh.api.paths import CONFIG_DIR, CACHE_DIR -from bauh.commons import resource - -ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) -SNAP_CACHE_DIR = f'{CACHE_DIR}/snap' -CONFIG_FILE = f'{CONFIG_DIR}/snap.yml' -CATEGORIES_FILE_PATH = f'{SNAP_CACHE_DIR}/categories.txt' -URL_CATEGORIES_FILE = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master/snap/categories.txt' - - -def get_icon_path() -> str: - return resource.get_path('img/snap.svg', ROOT_DIR) diff --git a/bauh/gems/snap/config.py b/bauh/gems/snap/config.py deleted file mode 100644 index 5a44d04d..00000000 --- a/bauh/gems/snap/config.py +++ /dev/null @@ -1,11 +0,0 @@ -from bauh.commons.config import YAMLConfigManager -from bauh.gems.snap import CONFIG_FILE - - -class SnapConfigManager(YAMLConfigManager): - - def __init__(self): - super(SnapConfigManager, self).__init__(config_file_path=CONFIG_FILE) - - def get_default_config(self) -> dict: - return {'install_channel': False, 'categories_exp': 24} diff --git a/bauh/gems/snap/controller.py b/bauh/gems/snap/controller.py deleted file mode 100644 index beb07b67..00000000 --- a/bauh/gems/snap/controller.py +++ /dev/null @@ -1,573 +0,0 @@ -import re -import time -import traceback -from threading import Thread -from typing import List, Set, Type, Optional, Tuple, Generator - -from bauh.api.abstract.controller import SoftwareManager, SearchResult, ApplicationContext, UpgradeRequirements, \ - 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 SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \ - SuggestionPriority, PackageStatus -from bauh.api.abstract.view import SingleSelectComponent, SelectViewType, InputOption, PanelComponent, \ - FormComponent, TextInputComponent -from bauh.api.exception import NoInternetException -from bauh.commons import suggestions -from bauh.commons.boot import CreateConfigFile -from bauh.commons.category import CategoriesDownloader -from bauh.commons.html import bold -from bauh.commons.system import SystemProcess, ProcessHandler, new_root_subprocess -from bauh.commons.view_utils import new_select, get_human_size_str -from bauh.gems.snap import snap, URL_CATEGORIES_FILE, CATEGORIES_FILE_PATH, \ - get_icon_path, snapd -from bauh.gems.snap.config import SnapConfigManager -from bauh.gems.snap.model import SnapApplication -from bauh.gems.snap.snapd import SnapdClient - -RE_AVAILABLE_CHANNELS = re.compile(re.compile(r'(\w+)\s+(snap install.+)')) - - -class SnapManager(SoftwareManager, SettingsController): - - def __init__(self, context: ApplicationContext): - super(SnapManager, self).__init__(context=context) - self.i18n = context.i18n - self.api_cache = context.cache_factory.new() - context.disk_loader_factory.map(SnapApplication, self.api_cache) - self.enabled = True - self.http_client = context.http_client - self.logger = context.logger - self.ubuntu_distro = context.distro == 'ubuntu' - self.categories = {} - self.suggestions_cache = context.cache_factory.new() - self.info_path = None - self.configman = SnapConfigManager() - self._suggestions_url: Optional[str] = None - - def _fill_categories(self, app: SnapApplication): - categories = self.categories.get(app.name.lower()) - - if categories: - app.categories = categories - - if not app.is_application(): - categories = app.categories - - if categories is None: - categories = [] - app.categories = categories - - if 'runtime' not in categories: - categories.append('runtime') - - def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult: - if is_url or (not snap.is_installed() and not snapd.is_running()): - return SearchResult([], [], 0) - - snapd_client = SnapdClient(self.logger) - apps_found = snapd_client.query(words) - - res = SearchResult([], [], 0) - - if apps_found: - installed = self.read_installed(disk_loader).installed - - for app_json in apps_found: - already_installed = None - - if installed: - already_installed = [i for i in installed if i.id == app_json.get('id')] - already_installed = already_installed[0] if already_installed else None - - if already_installed: - res.installed.append(already_installed) - else: - res.new.append(self._map_to_app(app_json, installed=False)) - - res.total = len(res.installed) + len(res.new) - return res - - def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult: - if snap.is_installed() and snapd.is_running(): - snapd_client = SnapdClient(self.logger) - app_names = {a['snap'] for a in snapd_client.list_only_apps()} - installed = [self._map_to_app(app_json=appjson, - installed=True, - disk_loader=disk_loader, - is_application=app_names and appjson['name'] in app_names) for appjson in snapd_client.list_all_snaps()] - return SearchResult(installed, None, len(installed)) - else: - return SearchResult([], None, 0) - - def downgrade(self, pkg: SnapApplication, root_password: Optional[str], watcher: ProcessWatcher) -> bool: - if not snap.is_installed(): - watcher.print("'snap' seems not to be installed") - return False - if not snapd.is_running(): - watcher.print("'snapd' seems not to be running") - return False - - return ProcessHandler(watcher).handle_simple(snap.downgrade_and_stream(pkg.name, root_password))[0] - - def upgrade(self, requirements: UpgradeRequirements, root_password: Optional[str], watcher: ProcessWatcher) -> SystemProcess: - raise Exception(f"'upgrade' is not supported by {SnapManager.__class__.__name__}") - - def uninstall(self, pkg: SnapApplication, root_password: Optional[str], watcher: ProcessWatcher, disk_loader: DiskCacheLoader) -> TransactionResult: - if snap.is_installed() and snapd.is_running(): - uninstalled = ProcessHandler(watcher).handle_simple(snap.uninstall_and_stream(pkg.name, root_password))[0] - - if uninstalled: - if self.suggestions_cache: - self.suggestions_cache.delete(pkg.name) - - return TransactionResult(success=True, installed=None, removed=[pkg]) - - return TransactionResult.fail() - - def get_managed_types(self) -> Set[Type[SoftwarePackage]]: - return {SnapApplication} - - def clean_cache_for(self, pkg: SnapApplication): - super(SnapManager, self).clean_cache_for(pkg) - self.api_cache.delete(pkg.id) - - def get_info(self, pkg: SnapApplication) -> dict: - info = { - 'description': pkg.description, - 'developer': pkg.developer, - 'license': pkg.license, - 'contact': pkg.contact, - 'snap-id': pkg.id, - 'name': pkg.name, - 'publisher': pkg.publisher, - 'revision': pkg.rev, - 'tracking': pkg.tracking, - 'channel': pkg.channel, - 'type': pkg.type - } - - if pkg.installed: - commands = [*{c['name'] for c in SnapdClient(self.logger).list_commands(pkg.name)}] - commands.sort() - info['commands'] = commands - - if pkg.installed_size: - info['installed_size']: get_human_size_str(pkg.installed_size) - elif pkg.download_size: - info['download_size'] = get_human_size_str(pkg.download_size) - - return info - - def get_history(self, pkg: SnapApplication) -> PackageHistory: - raise Exception(f"'get_history' is not supported by {pkg.__class__.__name__}") - - def install(self, pkg: SnapApplication, root_password: Optional[str], disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult: - # retrieving all installed so it will be possible to know the additional installed runtimes after the operation succeeds - if not snap.is_installed(): - watcher.print("'snap' seems not to be installed") - return TransactionResult.fail() - - if not snapd.is_running(): - watcher.print("'snapd' seems not to be running") - return TransactionResult.fail() - - installed_names = {s['name'] for s in SnapdClient(self.logger).list_all_snaps()} - - client = SnapdClient(self.logger) - snap_config = self.configman.get_config() - - try: - channel = self._request_channel_installation(pkg=pkg, snap_config=snap_config, snapd_client=client, watcher=watcher) - pkg.channel = channel - except Exception: - watcher.print('Aborted by user') - return TransactionResult.fail() - - res, output = ProcessHandler(watcher).handle_simple(snap.install_and_stream(app_name=pkg.name, - confinement=pkg.confinement, - root_password=root_password, - channel=channel)) - - if 'error:' in output: - res = False - if 'not available on stable' in output: - channels = RE_AVAILABLE_CHANNELS.findall(output) - - if channels: - opts = [InputOption(label=c[0], value=c[1]) for c in channels] - channel_select = SingleSelectComponent(type_=SelectViewType.RADIO, label='', options=opts, default_option=opts[0]) - body = f"

{self.i18n['snap.install.available_channels.message'].format(bold(self.i18n['stable']), bold(pkg.name))}.

" - body += f"

{self.i18n['snap.install.available_channels.help']}:

" - - if watcher.request_confirmation(title=self.i18n['snap.install.available_channels.title'], - body=body, - components=[channel_select], - confirmation_label=self.i18n['continue'], - deny_label=self.i18n['cancel']): - self.logger.info(f"Installing '{pkg.name}' with the custom command '{channel_select.value}'") - res = ProcessHandler(watcher).handle(SystemProcess(new_root_subprocess(channel_select.value.value.split(' '), root_password=root_password))) - return self._gen_installation_response(success=res, pkg=pkg, - installed=installed_names, disk_loader=disk_loader) - else: - self.logger.error(f"Could not find available channels in the installation output: {output}") - - return self._gen_installation_response(success=res, pkg=pkg, installed=installed_names, disk_loader=disk_loader) - - def _gen_installation_response(self, success: bool, pkg: SnapApplication, installed: Set[str], disk_loader: DiskCacheLoader): - if success: - new_installed = [] - try: - net_available = self.context.internet_checker.is_available() - current_installed = self.read_installed(disk_loader=disk_loader, internet_available=net_available).installed - except Exception: - new_installed = [pkg] - traceback.print_exc() - current_installed = None - - if current_installed: - for p in current_installed: - if p.name == pkg.name or (not installed or p.name not in installed): - new_installed.append(p) - - return TransactionResult(success=success, installed=new_installed, removed=[]) - else: - return TransactionResult.fail() - - def is_enabled(self) -> bool: - return self.enabled - - def set_enabled(self, enabled: bool): - self.enabled = enabled - - def can_work(self) -> Tuple[bool, Optional[str]]: - return (True, None) if snap.is_installed() else (False, self.i18n['missing_dep'].format(dep=bold('snap'))) - - def requires_root(self, action: SoftwareAction, pkg: SnapApplication) -> bool: - return action not in (SoftwareAction.PREPARE, SoftwareAction.SEARCH) - - def refresh(self, pkg: SnapApplication, root_password: Optional[str], watcher: ProcessWatcher) -> bool: - return ProcessHandler(watcher).handle_simple(snap.refresh_and_stream(pkg.name, root_password))[0] - - def change_channel(self, pkg: SnapApplication, root_password: Optional[str], watcher: ProcessWatcher) -> bool: - if not self.context.internet_checker.is_available(): - raise NoInternetException() - - try: - channel = self._request_channel_installation(pkg=pkg, - snap_config=None, - snapd_client=SnapdClient(self.logger), - watcher=watcher, - exclude_current=True) - - if not channel: - watcher.show_message(title=self.i18n['snap.action.channel.label'], - body=self.i18n['snap.action.channel.error.no_channel']) - return False - - return ProcessHandler(watcher).handle_simple(snap.refresh_and_stream(app_name=pkg.name, - root_password=root_password, - channel=channel))[0] - except Exception: - return False - - def _start_category_task(self, taskman: TaskManager, create_config: CreateConfigFile, downloader: CategoriesDownloader): - if taskman: - taskman.update_progress('snap_cats', 0, self.i18n['task.waiting_task'].format(bold(create_config.task_name))) - create_config.join() - - categories_exp = create_config.config['categories_exp'] - downloader.expiration = categories_exp if isinstance(categories_exp, int) else None - taskman.update_progress('snap_cats', 1, None) - - def _finish_category_task(self, taskman: TaskManager): - if taskman: - taskman.update_progress('snap_cats', 100, None) - taskman.finish_task('snap_cats') - - def prepare(self, task_manager: TaskManager, root_password: Optional[str], internet_available: bool): - create_config = CreateConfigFile(taskman=task_manager, configman=self.configman, i18n=self.i18n, - task_icon_path=get_icon_path(), logger=self.logger) - create_config.start() - - task_manager.register_task('snap_cats', self.i18n['task.download_categories'], get_icon_path()) - category_downloader = CategoriesDownloader(id_='snap', manager=self, http_client=self.http_client, - logger=self.logger, - url_categories_file=URL_CATEGORIES_FILE, - categories_path=CATEGORIES_FILE_PATH, - internet_connection=internet_available, - internet_checker=self.context.internet_checker, - after=lambda: self._finish_category_task(task_manager)) - category_downloader.before = lambda: self._start_category_task(task_manager, create_config, category_downloader) - category_downloader.start() - - def list_updates(self, internet_available: bool) -> List[PackageUpdate]: - pass - - def list_warnings(self, internet_available: bool) -> Optional[List[str]]: - if not snapd.is_running(): - snap_bold = bold('Snap') - return [self.i18n['snap.notification.snapd_unavailable'].format(bold('snapd'), snap_bold), - self.i18n['snap.notification.snap.disable'].format(snap_bold, - bold(f"{self.i18n['settings'].capitalize()} > {self.i18n['core.config.tab.types']}"))] - elif internet_available: - available, output = snap.is_api_available() - - if not available: - self.logger.warning(f'It seems Snap API is not available. Search output: {output}') - return [self.i18n['snap.notifications.api.unavailable'].format(bold('Snaps'), bold('Snap'))] - - def _fill_suggestion(self, name: str, priority: SuggestionPriority, snapd_client: SnapdClient, - out: List[PackageSuggestion]): - res = snapd_client.find_by_name(name) - - if res: - if len(res) == 1: - app_json = res[0] - else: - jsons_found = [p for p in res if p['name'] == name] - app_json = jsons_found[0] if jsons_found else None - - if app_json: - sug = PackageSuggestion(self._map_to_app(app_json, False), priority) - self.suggestions_cache.add(name, sug) - out.append(sug) - return - - self.logger.warning(f"Could not retrieve suggestion '{name}'") - - def _map_to_app(self, app_json: dict, installed: bool, disk_loader: Optional[DiskCacheLoader] = None, is_application: bool = False) -> SnapApplication: - app = SnapApplication(id=app_json.get('id'), - name=app_json.get('name'), - license=app_json.get('license'), - version=app_json.get('version'), - latest_version=app_json.get('version'), - description=app_json.get('description', app_json.get('summary')), - installed=installed, - rev=app_json.get('revision'), - publisher=app_json['publisher'].get('display-name', app_json['publisher'].get('username')), - verified_publisher=app_json['publisher'].get('validation') == 'verified', - icon_url=app_json.get('icon'), - screenshots={m['url'] for m in app_json.get('media', []) if m['type'] == 'screenshot'}, - download_size=app_json.get('download-size'), - channel=app_json.get('channel'), - confinement=app_json.get('confinement'), - app_type=app_json.get('type'), - app=is_application, - installed_size=app_json.get('installed-size')) - - if disk_loader and app.installed: - disk_loader.fill(app) - - self._fill_categories(app) - - app.status = PackageStatus.READY - return app - - def _read_local_suggestions_file(self) -> Optional[str]: - try: - with open(self.suggestions_url) as f: - suggestions_str = f.read() - - return suggestions_str - except FileNotFoundError: - self.logger.error(f"Local Snap suggestions file not found: {self.suggestions_url}") - except OSError: - self.logger.error(f"Could not read local Snap suggestions file: {self.suggestions_url}") - traceback.print_exc() - - def _download_remote_suggestions_file(self) -> Optional[str]: - self.logger.info(f"Downloading the Snap suggestions from {self.suggestions_url}") - file = self.http_client.get(self.suggestions_url) - - if file: - return file.text - - def list_suggestions(self, limit: int, filter_installed: bool) -> Optional[List[PackageSuggestion]]: - if limit == 0 or not snapd.is_running(): - 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 Snap suggestion found in {self.suggestions_url}") - return - - ids_prios = suggestions.parse(suggestions_str, self.logger, 'Snap') - - if not ids_prios: - self.logger.warning(f"No Snap suggestion could be parsed from {self.suggestions_url}") - return - - suggestion_by_priority = suggestions.sort_by_priority(ids_prios) - snapd_client = SnapdClient(self.logger) - - if filter_installed: - installed = {s['name'].lower() for s in snapd_client.list_all_snaps()} - - if installed: - suggestion_by_priority = tuple(n for n in suggestion_by_priority if n 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 Snap suggestions: {len(suggestion_by_priority)}') - - if not suggestion_by_priority: - return - - self.logger.info("Mapping Snap suggestions") - - instances, threads = [], [] - - res, cached_count = [], 0 - for name in suggestion_by_priority: - cached_sug = self.suggestions_cache.get(name) - - if cached_sug: - res.append(cached_sug) - cached_count += 1 - else: - t = Thread(target=self._fill_suggestion, args=(name, ids_prios[name], snapd_client, res), daemon=True) - t.start() - threads.append(t) - time.sleep(0.001) # to avoid being blocked - - for t in threads: - t.join() - - if cached_count > 0: - self.logger.info(f"Returning {cached_count} cached Snap suggestions") - - return res - - def is_default_enabled(self) -> bool: - return True - - def launch(self, pkg: SnapApplication): - commands = SnapdClient(self.logger).list_commands(pkg.name) - - if commands: - if len(commands) == 1: - cmd = commands[0]['name'] - else: - desktop_cmd = [c for c in commands if 'desktop-file' in c] - - if desktop_cmd: - cmd = desktop_cmd[0]['name'] - else: - cmd = commands[0]['name'] - - self.logger.info(f"Running '{pkg.name}': {cmd}") - snap.run(cmd) - - def get_screenshots(self, pkg: SnapApplication) -> Generator[str, None, None]: - if pkg.screenshots: - yield from pkg.screenshots - - def get_settings(self) -> Optional[Generator[SettingsView, None, None]]: - snap_config = self.configman.get_config() - - install_channel = new_select(label=self.i18n['snap.config.install_channel'], - opts=[(self.i18n['yes'].capitalize(), True, None), - (self.i18n['no'].capitalize(), False, None)], - value=bool(snap_config['install_channel']), - id_='snap_install_channel', - tip=self.i18n['snap.config.install_channel.tip']) - - cat_exp_val = snap_config['categories_exp'] if isinstance(snap_config['categories_exp'], int) else '' - categories_exp = TextInputComponent(id_='snap_cat_exp', - value=cat_exp_val, - only_int=True, - label=self.i18n['snap.config.categories_exp'], - tooltip=self.i18n['snap.config.categories_exp.tip']) - - panel = PanelComponent([FormComponent([install_channel, categories_exp], self.i18n['installation'].capitalize())]) - yield SettingsView(self, panel) - - def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]: - config_ = self.configman.get_config() - - form = component.get_component_by_idx(0, FormComponent) - config_['install_channel'] = form.get_component('snap_install_channel', SingleSelectComponent).get_selected() - config_['categories_exp'] = form.get_component('snap_cat_exp', TextInputComponent).get_int_value() - - try: - self.configman.save_config(config_) - return True, None - except Exception: - return False, [traceback.format_exc()] - - def _request_channel_installation(self, pkg: SnapApplication, snap_config: Optional[dict], snapd_client: SnapdClient, watcher: ProcessWatcher, exclude_current: bool = False) -> Optional[str]: - if snap_config is None or snap_config['install_channel']: - try: - data = [r for r in snapd_client.find_by_name(pkg.name) if r['name'] == pkg.name] - except Exception: - self.logger.warning(f"snapd client could not retrieve channels for '{pkg.name}'") - return - - if not data: - self.logger.warning(f"snapd client could find a match for name '{pkg.name}' when retrieving its channels") - else: - if not data[0].get('channels'): - self.logger.info(f"No channel available for '{pkg.name}'. Skipping selection.") - else: - if pkg.channel: - current_channel = pkg.channel if '/' in pkg.channel else f'latest/{pkg.channel}' - else: - current_channel = f"latest/{data[0].get('channel', 'stable')}" - - opts = [] - def_opt = None - for channel in sorted(data[0]['channels'].keys()): - if exclude_current: - if channel != current_channel: - opts.append(InputOption(label=channel, value=channel)) - else: - op = InputOption(label=channel, value=channel) - opts.append(op) - - if not def_opt and channel == current_channel: - def_opt = op - - if not opts: - self.logger.info(f"No different channel available for '{pkg.name}'. Skipping selection.") - return - - select = SingleSelectComponent(label='', - options=opts, - default_option=def_opt if def_opt else opts[0], - type_=SelectViewType.RADIO) - - if not watcher.request_confirmation(title=self.i18n['snap.install.available_channels.title'], - body=self.i18n['snap.install.channel.body'] + ':', - components=[select], - confirmation_label=self.i18n['proceed'].capitalize(), - deny_label=self.i18n['cancel'].capitalize()): - raise Exception('aborted') - else: - return select.get_selected() - - @property - def suggestions_url(self) -> str: - if not self._suggestions_url: - file_url = self.context.get_suggestion_url(self.__module__) - - if not file_url: - file_url = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master/snap/suggestions.txt' - - self._suggestions_url = file_url - - if file_url.startswith('/'): - self.logger.info(f"Local Snap suggestions file mapped: {file_url}") - - return self._suggestions_url - - def is_local_suggestions_file_mapped(self) -> bool: - return self.suggestions_url.startswith('/') diff --git a/bauh/gems/snap/model.py b/bauh/gems/snap/model.py deleted file mode 100644 index 25a4f5ba..00000000 --- a/bauh/gems/snap/model.py +++ /dev/null @@ -1,130 +0,0 @@ -from typing import Optional, Set, Iterable, Tuple - -from bauh.api.abstract.model import SoftwarePackage, CustomSoftwareAction -from bauh.commons import resource -from bauh.gems.snap import ROOT_DIR - - -class SnapApplication(SoftwarePackage): - - __actions: Optional[Tuple[CustomSoftwareAction, CustomSoftwareAction]] = None - - @classmethod - def actions(cls) -> Tuple[CustomSoftwareAction, CustomSoftwareAction]: - if cls.__actions is None: - cls.__actions = ( - CustomSoftwareAction(i18n_status_key='snap.action.refresh.status', - i18n_label_key='snap.action.refresh.label', - i18n_description_key='snap.action.refresh.desc', - icon_path=resource.get_path('img/refresh.svg', ROOT_DIR), - manager_method='refresh', - requires_root=True, - i18n_confirm_key='snap.action.refresh.confirm'), - CustomSoftwareAction(i18n_status_key='snap.action.channel.status', - i18n_label_key='snap.action.channel.label', - i18n_confirm_key='snap.action.channel.confirm', - i18n_description_key='snap.action.channel.desc', - icon_path=resource.get_path('img/refresh.svg', ROOT_DIR), - manager_method='change_channel', - requires_root=True, - requires_confirmation=False) - ) - - return cls.__actions - - def __init__(self, id: str = None, name: str = None, version: str = None, latest_version: str = None, - description: str = None, publisher: str = None, rev: str = None, notes: str = None, - confinement: str = None, verified_publisher: bool = False, - screenshots: Optional[Set[str]] = None, - license: Optional[str] = None, - installed: bool = False, - icon_url: Optional[str] = None, - download_size: Optional[int] = None, - developer: Optional[str] = None, - contact: Optional[str] = None, - tracking: Optional[str] = None, - app_type: Optional[str] = None, - channel: Optional[str] = None, - app: bool = False, - installed_size: Optional[int] = None): - super(SnapApplication, self).__init__(id=id, name=name, version=version, - latest_version=latest_version, description=description, - license=license, installed=installed, icon_url=icon_url) - self.publisher = publisher - self.rev = rev - self.notes = notes - self.confinement = confinement - self.verified_publisher = verified_publisher - self.screenshots = screenshots - self.download_size = download_size - self.developer = developer - self.contact = contact - self.tracking = tracking - self.type = app_type - self.channel = channel - self.app = app - self.installed_size = installed_size - - def supports_disk_cache(self): - return self.installed - - def has_history(self): - return False - - def has_info(self): - return True - - def can_be_downgraded(self): - return self.installed - - def get_type(self): - return 'snap' - - def get_default_icon_path(self): - return resource.get_path('img/snap.svg', ROOT_DIR) - - def get_type_icon_path(self): - return self.get_default_icon_path() - - def is_application(self) -> bool: - if self.installed: - return self.app - else: - return self.type == 'app' - - def get_disk_cache_path(self): - return f'{super(SnapApplication, self).get_disk_cache_path()}/installed/{self.name}' - - def is_trustable(self) -> bool: - return self.verified_publisher - - def get_data_to_cache(self): - return { - 'categories': self.categories - } - - def fill_cached_data(self, data: dict): - if data: - for base_attr in self.get_data_to_cache().keys(): - if data.get(base_attr): - setattr(self, base_attr, data[base_attr]) - - def can_be_run(self) -> bool: - return bool(self.installed and self.is_application()) - - def get_publisher(self): - return self.publisher - - def get_custom_actions(self) -> Optional[Iterable[CustomSoftwareAction]]: - if self.installed: - return self.actions() - - def supports_backup(self) -> bool: - return True - - def has_screenshots(self) -> bool: - return not self.installed and self.screenshots - - def __eq__(self, other): - if isinstance(other, SnapApplication): - return self.name == other.name diff --git a/bauh/gems/snap/resources/__init__.py b/bauh/gems/snap/resources/__init__.py deleted file mode 100755 index e69de29b..00000000 diff --git a/bauh/gems/snap/resources/img/__init__.py b/bauh/gems/snap/resources/img/__init__.py deleted file mode 100755 index e69de29b..00000000 diff --git a/bauh/gems/snap/resources/img/refresh.svg b/bauh/gems/snap/resources/img/refresh.svg deleted file mode 100755 index 60e9d79d..00000000 --- a/bauh/gems/snap/resources/img/refresh.svg +++ /dev/null @@ -1,128 +0,0 @@ - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bauh/gems/snap/resources/img/snap.svg b/bauh/gems/snap/resources/img/snap.svg deleted file mode 100644 index 7f247ab9..00000000 --- a/bauh/gems/snap/resources/img/snap.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/bauh/gems/snap/resources/locale/__init__.py b/bauh/gems/snap/resources/locale/__init__.py deleted file mode 100755 index e69de29b..00000000 diff --git a/bauh/gems/snap/resources/locale/ca b/bauh/gems/snap/resources/locale/ca deleted file mode 100644 index 8a5e7d38..00000000 --- a/bauh/gems/snap/resources/locale/ca +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=Aplicacions publicades a https://snapcraft.io/store -snap.action.channel.confirm=Change channel of {} ? -snap.action.channel.error.no_channel=No available channel for {} -snap.action.channel.label=Change channel -snap.action.channel.desc=Allows to change the application channel (if available) -snap.action.channel.status=Changing channel of -snap.action.refresh.confirm=Actualitza {} ? -snap.action.refresh.desc=Updates the application for the latest version -snap.action.refresh.label=Actualitza -snap.action.refresh.status=S’està actualitzant -snap.config.categories_exp=Categories expiration -snap.config.categories_exp.tip=It defines the expiration time (in HOURS) of the Snaps categories mapping file stored in disc. Use 0 so that it is always updated during initialization. -snap.config.install_channel=Display channels -snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed -snap.info.channel=channel -snap.info.commands=ordres -snap.info.contact=contacte -snap.info.description=descripció -snap.info.download_size=Size (Download) -snap.info.installed=instal·lada -snap.info.installed_size=Size (Instalattion) -snap.info.license=llicència -snap.info.publisher=publicador -snap.info.revision=revisió -snap.info.tracking=seguiment -snap.info.type=type -snap.info.version=versió -snap.install.available_channels.help=Seleccioneu-ne un si voleu continuar -snap.install.available_channels.message=No hi ha un canal {} (stable) disponible per a {}. Però més avall n’hi ha els següents -snap.install.available_channels.title=Canals disponibles -snap.install.channel.body=Select a channel to proceed -snap.notification.snap.disable=Si no voleu utilitzar aplicacions snap, desmarqueu {} a {} -snap.notification.snapd_unavailable=Sembla que no s’ha iniciat o activat {}. Els paquets {} no estaran disponibles. -snap.notifications.api.unavailable=Sembla que l’API de {} no està disponible en aquests moments. No podreu cercar aplicacions {} noves. \ No newline at end of file diff --git a/bauh/gems/snap/resources/locale/de b/bauh/gems/snap/resources/locale/de deleted file mode 100644 index 2b90be33..00000000 --- a/bauh/gems/snap/resources/locale/de +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=Auf https://snapcraft.io/store veröffentlichte Anwendungen -snap.action.channel.confirm=Kanal von {} ändern? -snap.action.channel.error.no_channel=Kein verfügbarer Kanal für {} -snap.action.channel.label=Kanal ändern -snap.action.channel.desc=Ermöglicht das Ändern des Anwendungskanals (falls verfügbar) -snap.action.channel.status=Ändern des Kanals von -snap.action.refresh.confirm=Aktualisieren {} ? -snap.action.refresh.desc=Aktualisiert die Anwendung auf die neueste Version -snap.action.refresh.label=Aktualisieren -snap.action.refresh.status=Aktualisieren -snap.config.categories_exp=Gültigkeitszeitraum der Kategorien -snap.config.categories_exp.tip=Legt den Gültigkeitszeitraum (in Stunden) der auf dem Datenträger gespeicherten Kategorien-Zuordnungsdatei der Snaps fest. Verwenden Sie 0, damit die Datei während der Initialisierung immer aktualisiert wird. -snap.config.install_channel=Kanäle anzeigen -snap.config.install_channel.tip=Hier können Sie einen der verfügbaren Kanäle für die zu installierende Anwendung auswählen -snap.info.channel=Kanal -snap.info.commands=Befehle -snap.info.contact=Kontakt -snap.info.description=Beschreibung -snap.info.download_size=Größe (Download) -snap.info.installed=installiert -snap.info.installed_size=Größe (Installation) -snap.info.license=Lizenz -snap.info.publisher=Herausgeber -snap.info.revision=Revision -snap.info.tracking=Verfolgung -snap.info.type=Typ -snap.info.version=Version -snap.install.available_channels.help=Wählen Sie eine aus, wenn Sie fortfahren möchten -snap.install.available_channels.message=Es ist kein {} Kanal für {} verfügbar. Aber es gibt diese untenstehenden -snap.install.available_channels.title=Verfügbare Kanäle -snap.install.channel.body=Wählen Sie einen Kanal, um fortzufahren -snap.notification.snap.disable=Wenn Sie keine Snap-Anwendungen verwenden möchten, deaktivieren Sie {} in {} -snap.notification.snapd_unavailable={} scheint nicht gestartet oder aktiviert zu sein. {} Pakete werden nicht verfügbar sein. -snap.notifications.api.unavailable=Es scheint, dass die {} API im Moment nicht verfügbar ist. Es wird nicht möglich sein, nach neuen {} Anwendungen zu suchen. \ No newline at end of file diff --git a/bauh/gems/snap/resources/locale/en b/bauh/gems/snap/resources/locale/en deleted file mode 100644 index 4f7c5391..00000000 --- a/bauh/gems/snap/resources/locale/en +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=Applications published at https://snapcraft.io/store -snap.action.channel.confirm=Change channel of {}? -snap.action.channel.error.no_channel=No available channel for {} -snap.action.channel.label=Change channel -snap.action.channel.desc=Allows to change the application channel (if available) -snap.action.channel.status=Changing channel of -snap.action.refresh.confirm=Refresh {}? -snap.action.refresh.desc=Updates the application for the latest version -snap.action.refresh.label=Refresh -snap.action.refresh.status=Refreshing -snap.config.categories_exp=Categories expiration -snap.config.categories_exp.tip=It defines the expiration time (in HOURS) of the Snaps categories mapping file stored in disc. Use 0 so that it is always updated during initialization. -snap.config.install_channel=Display channels -snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed -snap.info.channel=channel -snap.info.commands=commands -snap.info.contact=contact -snap.info.description=description -snap.info.download_size=Size (Download) -snap.info.installed=installed -snap.info.installed_size=Size (Installation) -snap.info.license=license -snap.info.publisher=publisher -snap.info.revision=revision -snap.info.tracking=tracking -snap.info.type=type -snap.info.version=version -snap.install.available_channels.help=Select one if you want to continue -snap.install.available_channels.message=There is no {} channel available for {}. But there are these below -snap.install.available_channels.title=Available channels -snap.install.channel.body=Select a channel to proceed -snap.notification.snap.disable=If you do not want to use Snap applications, uncheck {} in {} -snap.notification.snapd_unavailable={} seems not to be started or enabled. {} packages will not be available. -snap.notifications.api.unavailable=It seems the {} API is unavailable at the moment. It will not be possible to search for new {} applications. diff --git a/bauh/gems/snap/resources/locale/es b/bauh/gems/snap/resources/locale/es deleted file mode 100644 index 78d8158f..00000000 --- a/bauh/gems/snap/resources/locale/es +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=Aplicativos publicados en https://snapcraft.io/store -snap.action.channel.confirm=Cambiar canal de {}? -snap.action.channel.desc=Permite cambiar el canal de la aplicación (si disponible) -snap.action.channel.error.no_channel=No hay canal disponible para {} -snap.action.channel.status=Cambiando canal de -snap.action.channel.label=Cambiar canal -snap.action.refresh.confirm=Actualizar {} ? -snap.action.refresh.desc=Actualiza la aplicación para la versión más reciente -snap.action.refresh.label=Actualizar -snap.action.refresh.status=Actualizando -snap.config.categories_exp=Expiración de categorías -snap.config.categories_exp.tip=Define el tiempo de vencimiento (en HORAS) del archivo de mapeo de categorías de Snaps almacenado en el disco. Utilice 0 para que siempre se actualice durante la inicialización. -snap.config.install_channel=Mostrar canales -snap.config.install_channel.tip=Permite seleccionar uno de los canales disponibles para la aplicación a instalar -snap.info.channel=canal -snap.info.commands=comandos -snap.info.contact=contacto -snap.info.description=descripción -snap.info.download_size=Tamaño (Descarga) -snap.info.installed=instalado -snap.info.installed_size=Tamaño (Instalación) -snap.info.license=licencia -snap.info.publisher=publicador -snap.info.revision=revisión -snap.info.tracking=tracking -snap.info.type=tipo -snap.info.version=versión -snap.install.available_channels.help=Seleccione uno si desea continuar -snap.install.available_channels.message=No hay un canal {} ( stable ) disponible para {}. Pero hay estos otros abajo -snap.install.available_channels.title=Canales disponibles -snap.install.channel.body=Seleccione un canal para continuar -snap.notification.snap.disable=Si no desea usar aplicativos Snap, desmarque {} en {} -snap.notification.snapd_unavailable={} parece no estar inicializado o habilitado. Los paquetes {} estarán indisponibles. -snap.notifications.api.unavailable=Parece que la API de {} no está disponible en este momento. No será posible buscar nuevos aplicativos {}. \ No newline at end of file diff --git a/bauh/gems/snap/resources/locale/fr b/bauh/gems/snap/resources/locale/fr deleted file mode 100644 index f1eeaccd..00000000 --- a/bauh/gems/snap/resources/locale/fr +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=Applications publiées à https://snapcraft.io/store -snap.action.channel.confirm=Changer le canal de {} ? -snap.action.channel.desc=Allows to change the application channel (if available) -snap.action.channel.error.no_channel=Aucun canal disponible pour {} -snap.action.channel.label=Changer de canal -snap.action.channel.status=Changement de canal de -snap.action.refresh.confirm=Actualiser {} ? -snap.action.refresh.desc=Updates the application for the latest version -snap.action.refresh.label=Actualiser -snap.action.refresh.status=Actualisation -snap.config.categories_exp=Categories expiration -snap.config.categories_exp.tip=It defines the expiration time (in HOURS) of the Snaps categories mapping file stored in disc. Use 0 so that it is always updated during initialization. -snap.config.install_channel=Afficher les canaux -snap.config.install_channel.tip=Permet de sélectionner un des canaux disponibles pour l'application à installer -snap.info.channel=canal -snap.info.commands=commandes -snap.info.contact=contact -snap.info.description=description -snap.info.download_size=Taille (Téléchargement) -snap.info.installed=installé -snap.info.installed_size=Size (Installation) -snap.info.license=licence -snap.info.publisher=éditeur -snap.info.revision=révision -snap.info.tracking=pisteur -snap.info.type=type -snap.info.version=version -snap.install.available_channels.help=Selectionnez pour continuer -snap.install.available_channels.message=Pas de canal {} disponible pour {}. Mais les suivants existent -snap.install.available_channels.title=Canaux disponibles -snap.install.channel.body=Choisissez un canal pour continuer -snap.notification.snap.disable=Si vous ne voulez pas utiliser des applications Snap, décochez {} dans {} -snap.notification.snapd_unavailable={} a l'air de n'être ni démarré ni activé. Les paquets {} ne seront pas disponibles. -snap.notifications.api.unavailable=L'API {} a l'air d'être momentanément indisponible. Impossible de chercher de nouvelles applications {}. diff --git a/bauh/gems/snap/resources/locale/it b/bauh/gems/snap/resources/locale/it deleted file mode 100644 index 6bbcea0c..00000000 --- a/bauh/gems/snap/resources/locale/it +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=Applicazioni pubblicate su https://snapcraft.io/store -snap.action.channel.confirm=Cambia canale di {} ? -snap.action.channel.desc=Allows to change the application channel (if available) -snap.action.channel.error.no_channel=Nessun canale disponibile per {} -snap.action.channel.label=Cambia canale -snap.action.channel.status=Cambiare canale di -snap.action.refresh.confirm=Ripristina {} ? -snap.action.refresh.desc=Updates the application for the latest version -snap.action.refresh.label=Ripristina -snap.action.refresh.status=Ripristinare -snap.config.categories_exp=Scadenza delle categorie -snap.config.categories_exp.tip=Definisce il tempo di scadenza (in ORE) del file di mappatura delle categorie di Snap archiviato nel disco. Utilizzare 0 in modo che venga sempre aggiornato durante l'inizializzazione. -snap.config.install_channel=Visualizza i canali -snap.config.install_channel.tip=Permette di selezionare uno dei canali disponibili per la data applicazione da installare -snap.info.channel=canale -snap.info.commands=comandi -snap.info.contact=contatto -snap.info.description=descrizione -snap.info.download_size=dimensione (Download) -snap.info.installed=installato -snap.info.installed_size=Dimensione (Installazione) -snap.info.license=licenza -snap.info.publisher=editore -snap.info.revision=revisione -snap.info.tracking=tracking -snap.info.type=tipo -snap.info.version=versione -snap.install.available_channels.help=Selezionane uno se vuoi continuare -snap.install.available_channels.message=Non esiste un {} canale disponibile per {}. Ma ci sono questi sotto -snap.install.available_channels.title=Canali disponibili -snap.install.channel.body=Seleziona un canale per procedere -snap.notification.snap.disable=Se non si desidera utilizzare le applicazioni Snap, deselezionare {} in {} -snap.notification.snapd_unavailable={} sembra non essere avviato o abilitato. {} i pacchetti non saranno disponibili. -snap.notifications.api.unavailable=Sembra che l'API {} non sia al momento disponibile. Non sarà possibile cercare nuove {} applicazioni. diff --git a/bauh/gems/snap/resources/locale/pt b/bauh/gems/snap/resources/locale/pt deleted file mode 100644 index 8a261506..00000000 --- a/bauh/gems/snap/resources/locale/pt +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=Aplicativos publicados em https://snapcraft.io/store -snap.action.channel.confirm=Alterar canal de {} ? -snap.action.channel.desc=Permite trocar o canal do aplicativo (se disponível) -snap.action.channel.error.no_channel=Nenhum canal disponível para {} -snap.action.channel.label=Alterar canal -snap.action.channel.status=Alterando canal de -snap.action.refresh.confirm=Atualizar {} ? -snap.action.refresh.desc=Atualiza o aplicativo para a versão mais recente -snap.action.refresh.label=Atualizar -snap.action.refresh.status=Atualizando -snap.config.categories_exp=Expiração de categorias -snap.config.categories_exp.tip=Define o tempo de expiração (em HORAS) do arquivo de mapeamento de categorias Snap armazenado em disco. Utilize 0 para que ele seja sempre atualizado durante a inicialização. -snap.config.install_channel=Exibir canais -snap.config.install_channel.tip=Permite-se selecionar um dos canais disponíveis para o aplicativo a ser instalado -snap.info.channel=canal -snap.info.commands=comandos -snap.info.contact=contato -snap.info.description=descrição -snap.info.download_size=Tamanho (Download) -snap.info.installed=instalado -snap.info.installed_size=Tamanho (Instalação) -snap.info.license=licença -snap.info.publisher=publicador -snap.info.revision=revisão -snap.info.tracking=tracking -snap.info.type=tipo -snap.info.version=versão -snap.install.available_channels.help=Selecione algum se quiser continuar -snap.install.available_channels.message=Não há um canal {} ( stable ) disponível para {}. Porém existem estes outros abaixo -snap.install.available_channels.title=Canais disponíveis -snap.install.channel.body=Selecione um canal para continuar -snap.notification.snap.disable=Se não deseja usar aplicativos Snap, desmarque {} em {} -snap.notification.snapd_unavailable={} parece não estar inicializado ou habilitado. Os pacotes {} estarão indisponíveis. -snap.notifications.api.unavailable=Parece que a API de {} está indisponível no momento. Não será possível buscar novos aplicativos {}. \ No newline at end of file diff --git a/bauh/gems/snap/resources/locale/ru b/bauh/gems/snap/resources/locale/ru deleted file mode 100644 index cbaf340b..00000000 --- a/bauh/gems/snap/resources/locale/ru +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=Приложения, опубликованные на https://snapcraft.io/store -snap.action.channel.confirm=Изменить канал на {} ? -snap.action.channel.desc=Позволяет изменить канал приложения (если он доступен) -snap.action.channel.error.no_channel=Нет доступного канала для {} -snap.action.channel.label=Изменить канал -snap.action.channel.status=Изменение канала на -snap.action.refresh.confirm=Обновить {} ? -snap.action.refresh.desc=Обновление приложения до последней версии -snap.action.refresh.label=Обновить -snap.action.refresh.status=Обновляется -snap.config.categories_exp=Срок действия категорий -snap.config.categories_exp.tip=Определяет время действия (в часах) файла отображения категорий Snaps, хранящегося на диске. Используйте 0, чтобы он всегда обновлялся при инициализации. -snap.config.install_channel=Отображение каналов -snap.config.install_channel.tip=Позволяет выбрать один из доступных каналов для устанавливаемого приложения -snap.info.channel=Канал -snap.info.commands=Команды -snap.info.contact=Контакт -snap.info.description=Описание -snap.info.download_size=Размер (Загрузки) -snap.info.installed=Размер установки -snap.info.installed_size=Размер (Установки) -snap.info.license=Лицензия -snap.info.publisher=Издатель -snap.info.revision=Ревизия -snap.info.tracking=Отслеживание -snap.info.type=тип -snap.info.version=Версия -snap.install.available_channels.help=Выберите один, если вы хотите продолжить -snap.install.available_channels.message=Нет одного канала {}, доступного для {}. Но есть такие ниже -snap.install.available_channels.title=Доступные каналы -snap.install.channel.body=Выберите канал для продолжения операции -snap.notification.snap.disable=Если вы не хотите использовать приложения Snap, снимите флажок {} в {} -snap.notification.snapd_unavailable={} кажется, не запускается и не включается. {} пакеты будут недоступны. -snap.notifications.api.unavailable=Похоже, что API {} в данный момент недоступен. Невозможно будет искать новые приложения {}. diff --git a/bauh/gems/snap/resources/locale/tr b/bauh/gems/snap/resources/locale/tr deleted file mode 100644 index d1fc27bc..00000000 --- a/bauh/gems/snap/resources/locale/tr +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=https://snapcraft.io/store adresinde yayınlanan uygulamalar -snap.action.channel.confirm=Change channel of {} ? -snap.action.channel.desc=Allows to change the application channel (if available) -snap.action.channel.error.no_channel=No available channel for {} -snap.action.channel.label=Change channel -snap.action.channel.status=Changing channel of -snap.action.refresh.confirm=Yenile {} ? -snap.action.refresh.desc=Updates the application for the latest version -snap.action.refresh.label=Yenile -snap.action.refresh.status=Yenileniyor -snap.config.categories_exp=Categories expiration -snap.config.categories_exp.tip=It defines the expiration time (in HOURS) of the Snaps categories mapping file stored in disc. Use 0 so that it is always updated during initialization. -snap.config.install_channel=Display channels -snap.config.install_channel.tip=It allows to select one of the available channels for the given application to be installed -snap.info.channel=channel -snap.info.commands=komutlar -snap.info.contact=iletişim -snap.info.description=açıklama -snap.info.download_size=Size (Download) -snap.info.installed=yüklü -snap.info.installed_size=Size (Instalattion) -snap.info.license=lisans -snap.info.publisher=yayıncı -snap.info.revision=revizyon -snap.info.tracking=izleme -snap.info.type=type -snap.info.version=sürüm -snap.install.available_channels.help=Devam etmek istiyorsanız birini seçin -snap.install.available_channels.message={} için hiçbir {} kanalı yok. Ama aşağıda bunlar var -snap.install.available_channels.title=Kullanılabilir kanallar -snap.install.channel.body=Select a channel to proceed -snap.notification.snap.disable=Snap uygulamalarını kullanmak istemiyorsanız, {} içindeki {} işaretini kaldırın -snap.notification.snapd_unavailable={} başlatılmamış veya etkinleştirilmemiş gibi görünüyor. {} paketler mevcut olmayacak. -snap.notifications.api.unavailable=Görünüşe göre {} API şu anda kullanılamıyor. Yeni {} uygulamaları aramak mümkün olmayacak. diff --git a/bauh/gems/snap/resources/locale/zh b/bauh/gems/snap/resources/locale/zh deleted file mode 100644 index dd138914..00000000 --- a/bauh/gems/snap/resources/locale/zh +++ /dev/null @@ -1,34 +0,0 @@ -gem.snap.info=在 https://snapcraft.io/store 上发布的应用程序 -snap.action.channel.confirm=更改 {} 的频道? -snap.action.channel.error.no_channel=没有可用于 {} 的频道 -snap.action.channel.label=更改频道 -snap.action.channel.desc=允许更改应用程序的频道(如果可用) -snap.action.channel.status=更改 -snap.action.refresh.confirm=刷新 {}? -snap.action.refresh.desc=将应用程序更新到最新版本 -snap.action.refresh.label=刷新 -snap.action.refresh.status=刷新 -snap.config.categories_exp=类别过期时间 -snap.config.categories_exp.tip=它定义了 Snap 分类映射文件在磁盘上存储的过期时间(以小时为单位)。在初始化期间始终更新,使用 0。 -snap.config.install_channel=显示频道 -snap.config.install_channel.tip=允许为给定应用程序选择可用频道进行安装 -snap.info.channel=频道 -snap.info.commands=命令 -snap.info.contact=联系 -snap.info.description=描述 -snap.info.download_size=大小(下载) -snap.info.installed=已安装 -snap.info.installed_size=大小(安装) -snap.info.license=许可证 -snap.info.publisher=发布者 -snap.info.revision=修订版 -snap.info.tracking=追踪 -snap.info.type=类型 -snap.info.version=版本 -snap.install.available_channels.help=如果要继续,请选择一个 -snap.install.available_channels.message=没有 {} 的可用频道供 {} 使用。但下面有这些 -snap.install.available_channels.title=可用频道 -snap.install.channel.body=选择一个频道以继续 -snap.notification.snap.disable=如果您不想使用 Snap 应用程序,请取消选中 {} -snap.notification.snapd_unavailable={} 似乎没有启动或启用。{} 包将不可用。 -snap.notifications.api.unavailable=目前似乎 {} API 不可用。将无法搜索新的 {} 应用程序。 diff --git a/bauh/gems/snap/snap.py b/bauh/gems/snap/snap.py deleted file mode 100644 index f3d4f2ed..00000000 --- a/bauh/gems/snap/snap.py +++ /dev/null @@ -1,65 +0,0 @@ -import os -import shutil -import subprocess -from io import StringIO -from typing import Tuple, Optional - -from bauh.commons.system import SimpleProcess - - -def is_installed() -> bool: - return bool(shutil.which('snap')) - - -def uninstall_and_stream(app_name: str, root_password: Optional[str]) -> SimpleProcess: - return SimpleProcess(cmd=('snap', 'remove', app_name), - root_password=root_password, - lang=None, - shell=True) - - -def install_and_stream(app_name: str, confinement: str, root_password: Optional[str], channel: Optional[str] = None) -> SimpleProcess: - - install_cmd = ['snap', 'install', app_name] # default - - if confinement == 'classic': - install_cmd.append('--classic') - - if channel: - install_cmd.append(f'--channel={channel}') - - return SimpleProcess(install_cmd, root_password=root_password, shell=True, lang=None) - - -def downgrade_and_stream(app_name: str, root_password: Optional[str]) -> SimpleProcess: - return SimpleProcess(cmd=('snap', 'revert', app_name), - root_password=root_password, - shell=True, - lang=None) - - -def refresh_and_stream(app_name: str, root_password: Optional[str], channel: Optional[str] = None) -> SimpleProcess: - cmd = ['snap', 'refresh', app_name] - - if channel: - cmd.append(f'--channel={channel}') - - return SimpleProcess(cmd=cmd, - root_password=root_password, - lang=None, - shell=True) - - -def run(cmd: str): - subprocess.Popen((f'snap run {cmd}',), shell=True, env={**os.environ}) - - -def is_api_available() -> Tuple[bool, str]: - output = StringIO() - for o in SimpleProcess(('snap', 'search'), lang=None).instance.stdout: - if o: - output.write(o.decode()) - - output.seek(0) - output = output.read() - return 'error:' not in output, output diff --git a/bauh/gems/snap/snapd.py b/bauh/gems/snap/snapd.py deleted file mode 100644 index 50e08b72..00000000 --- a/bauh/gems/snap/snapd.py +++ /dev/null @@ -1,120 +0,0 @@ -import socket -import traceback -from logging import Logger -from typing import Optional, List - -from requests import Session -from requests.adapters import HTTPAdapter -from urllib3.connection import HTTPConnection -from urllib3.connectionpool import HTTPConnectionPool - -from bauh.commons.system import run_cmd - -URL_BASE = 'http://snapd/v2' - - -class SnapdConnection(HTTPConnection): - def __init__(self): - super(SnapdConnection, self).__init__('localhost') - - def connect(self): - self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.sock.connect("/run/snapd.socket") - - -class SnapdConnectionPool(HTTPConnectionPool): - def __init__(self): - super(SnapdConnectionPool, self).__init__('localhost') - - def _new_conn(self): - return SnapdConnection() - - -class SnapdAdapter(HTTPAdapter): - - def get_connection(self, url, proxies=None): - return SnapdConnectionPool() - - -class SnapdClient: - - def __init__(self, logger: Logger): - self.logger = logger - self.session = self._new_session() - - def _new_session(self) -> Optional[Session]: - try: - session = Session() - session.mount("http://snapd/", SnapdAdapter()) - return session - except Exception: - self.logger.error("Could not establish a connection to 'snapd.socker'") - traceback.print_exc() - - def query(self, query: str) -> Optional[List[dict]]: - final_query = query.strip() - - if final_query and self.session: - res = self.session.get(url=f'{URL_BASE}/find', params={'q': final_query}) - - if res.status_code == 200: - json_res = res.json() - - if json_res['status-code'] == 200: - return json_res['result'] - - def find_by_name(self, name: str) -> Optional[List[dict]]: - if name and self.session: - res = self.session.get(f'{URL_BASE}/find?name={name}') - - if res.status_code == 200: - json_res = res.json() - - if json_res['status-code'] == 200: - return json_res['result'] - - def list_all_snaps(self) -> List[dict]: - if self.session: - res = self.session.get(f'{URL_BASE}/snaps') - - if res.status_code == 200: - json_res = res.json() - - if json_res['status-code'] == 200: - return json_res['result'] - - return [] - - def list_only_apps(self) -> List[dict]: - if self.session: - res = self.session.get(f'{URL_BASE}/apps') - - if res.status_code == 200: - json_res = res.json() - - if json_res['status-code'] == 200: - return json_res['result'] - return [] - - def list_commands(self, name: str) -> List[dict]: - if self.session: - res = self.session.get(f'{URL_BASE}/apps?names={name}') - - if res.status_code == 200: - json_res = res.json() - - if json_res['status-code'] == 200: - return [r for r in json_res['result'] if r['snap'] == name] - return [] - - -def is_running() -> bool: - status = run_cmd('systemctl is-active snapd.service snapd.socket', print_error=False) - if not status: - return False - else: - for status in status.split('\n'): - if status.strip().lower() == 'active': - return True - - return False