diff --git a/README.md b/README.md index 117787f0..00f3378a 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,9 @@ Bearhub is currently focused on: Large architectural changes or feature redesigns are not the immediate priority. -Backends outside the Arch-focused scope remain in the codebase for now, but they are not the primary maintenance target of this fork. +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). It currently supports the following formats: AppImage, Debian and Arch Linux packages (including AUR), Flatpak, Snap 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, Snap, AppImage and Web applications. Key features - A management panel where you can: search, install, uninstall, upgrade, downgrade and launch your applications @@ -54,7 +54,6 @@ Key features ## Index 1. [Installation](#installation) - [AppImage](#inst_appimage) - - [Ubuntu 20.04 based distros (Linux Mint, PopOS, ...)](#inst_ubuntu) - [Arch-based distros](#inst_arch) 2. [Isolated installation](#inst_iso) 3. [Desktop entry / menu shortcut](#desk_entry) @@ -63,7 +62,6 @@ Key features 6. [Supported types](#types) - [AppImage](#type_appimage) - [Arch packages/AUR](#type_arch) - - [Debian](#type_deb) - [Flatpak](#type_flatpak) - [Snap](#type_snap) - [Native Web applications](#type_web) @@ -103,52 +101,6 @@ Key features

-#### Ubuntu 20.04 based distros (Linux Mint, PopOS, ...) - -##### Required dependencies - -`sudo apt-get install python3 python3-pip python3-yaml python3-dateutil python3-pyqt5 python3-packaging python3-requests` - -##### Installing bauh - -`sudo pip3 install bauh` - - -##### Optional dependencies (they should be installed with apt-get/apt) - -- `aptitude`: Debian package management -- `timeshift`: system backup -- `aria2`: multi-threaded downloads -- `axel`: multi-threaded downloads alternative -- `libappindicator3-1`: tray-mode -- `sqlite3`, `fuse`: AppImage support -- `flatpak`: Flatpaks support -- `snapd`: Snaps support -- `python3-lxml`, `python3-bs4`: Web apps support -- `python3-venv`: [isolated installation](#inst_iso) -- `xdg-utils`: to open URLs in the browsers (`xdg-open`) - -##### Updating bauh - -Method 1 - -`sudo pip3 install bauh --upgrade` - -Method 2 - -``` -sudo pip3 uninstall bauh -sudo pip3 install bauh -``` - -##### Uninstalling bauh - -``` -bauh --reset # removes cache and configurations files from HOME -sudo pip3 uninstall bauh -``` - - #### Arch-based distros ##### Using yay @@ -341,24 +293,6 @@ suggestions_exp: 24 # it defines the period (in hours) in which the suggestions ``` - Cached package suggestions: `~/.cache/bauh/arch/suggestions.txt` (or `/var/cache/bauh/arch/suggestions.yml` for **root**) -##### Debian packages -- Basic actions supported: **search**, **install**, **uninstall**, **upgrade** -- Custom actions supported: - - **synchronize packages**: synchronize the available packages on the repository (`aptitude update`) - - **index applications**: maps runnable installed packages (automatically done during initialization) - - **software sources**: launches the application responsible for managing software sources (at the moment only `software-properties-gtk` is supported) -- Custom package actions supported: - - **purge**: removes the packages and all related configuration files -- Files: - - runnable applications index: `~/.cache/bauh/debian/apps_idx.json` (or `/var/cache/bauh/debian/apps_idx.json` for **root**) - - cached package suggestions: `~/.cache/bauh/debian/suggestions.txt` (or `/var/cache/bauh/debian/suggestions.txt` for **root**) - - configuration: `~/.config/bauh/debian.yml` or `/etc/bauh/debian.yml` - - `index_apps.exp`: time period (**in minutes**) in which the installed applications cache is considered up-to-date during startup (default: `1440` -> 24 hours) - - `sync_pkgs.time`: time period (**in minutes**) in which the packages synchronization must be done on startup (default: `1440` -> 24 hours) - - `suggestions.exp`: it defines the period (**in hours**) in which the suggestions stored in disc will be considered up to date. Use 0 if you always want to update them. - - `pkg_sources.app`: it defines the application for managing the software sources. A `null` value detects one of the supported applications automatically. - - `remove.purge`: if the package configurations should be removed during the uninstallation process (purge). Default: false. - ##### Flatpak - Applications with ignored updates are defined at `~/.config/bauh/flatpak/updates_ignored.txt` @@ -517,7 +451,6 @@ appimage - The software suggestions are download from [bauh-files](https://github.com/vinifmor/bauh-files) by default - [appimage](https://github.com/vinifmor/bauh-files/blob/master/appimage/suggestions.txt) - [arch](https://github.com/vinifmor/bauh-files/blob/master/appimage/suggestions.txt) - - [debian](https://github.com/vinifmor/bauh-files/blob/master/debian/suggestions_v1.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) diff --git a/bauh/gems/debian/__init__.py b/bauh/gems/debian/__init__.py deleted file mode 100644 index e4121fd3..00000000 --- a/bauh/gems/debian/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -import os - -from bauh.api.paths import CACHE_DIR, CONFIG_DIR -from bauh.commons import resource - -ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) - -DEBIAN_CACHE_DIR = f'{CACHE_DIR}/debian' -APP_INDEX_FILE = f'{DEBIAN_CACHE_DIR}/apps_idx.json' -CONFIG_FILE = f'{CONFIG_DIR}/debian.yml' -PACKAGE_SYNC_TIMESTAMP_FILE = f'{DEBIAN_CACHE_DIR}/sync_pkgs.ts' -DEBIAN_ICON_PATH = resource.get_path('img/debian.svg', ROOT_DIR) diff --git a/bauh/gems/debian/aptitude.py b/bauh/gems/debian/aptitude.py deleted file mode 100644 index 097ea5df..00000000 --- a/bauh/gems/debian/aptitude.py +++ /dev/null @@ -1,430 +0,0 @@ -import re -import time -from contextlib import contextmanager -from enum import Enum -from logging import Logger -from math import ceil -from queue import Queue -from threading import Thread -from typing import Iterable, Optional, Pattern, Dict, Set, Tuple, Generator, Collection - -from bauh.api.abstract.handler import ProcessWatcher -from bauh.commons import system -from bauh.commons.html import bold -from bauh.commons.system import SimpleProcess -from bauh.commons.util import size_to_byte -from bauh.gems.debian.common import strip_maintainer_email, strip_section -from bauh.gems.debian.model import DebianPackage, DebianTransaction -from bauh.view.util.translation import I18n - - -def map_package_name(string: str): - name_split = string.split(':') - - if len(name_split) > 2: - return ':'.join(name_split[0:-1]) - - return name_split[0] - - -class AptitudeAction(Enum): - INSTALL = 0 - UPGRADE = 1 - REMOVE = 3 - - -class Aptitude: - - def __init__(self, logger: Logger): - self._log = logger - self._re_show_attr: Optional[Pattern] = None - self._env: Optional[Dict[str, str]] = None - self._list_attrs: Optional[Set[str]] = None - self._re_to_install: Optional[Pattern] = None - self._re_transaction_pkg: Optional[Pattern] = None - self._size_attrs: Optional[Tuple[str]] = None - self._default_lang = '' - self._ignored_fields: Optional[Set[str]] = None - self._re_none: Optional[Pattern] = None - self._vars_fixes: Optional[Dict[str, str]] = None - self._preserve_env = {'DEBIAN_FRONTEND'} - - def show(self, pkgs: Iterable[str], attrs: Optional[Collection[str]] = None, verbose: bool = False) \ - -> Optional[Dict[str, Dict[str, object]]]: - - if pkgs: - force_verbose = verbose if verbose else ('compressed size' in attrs if attrs else False) - code, output = system.execute(f"aptitude show -q {' '.join(pkgs)}{' -v' if force_verbose else ''}", - shell=True, custom_env=self.env) - - if code == 0 and output: - info, pkg = dict(), None - for field, val in self.re_show_attr.findall('\n' + output): - final_field, final_val = field.strip().lower(), val.strip() - - if final_field == 'package': - pkg = {} - info[final_val] = pkg - elif final_field not in self.ignored_fields and (not attrs or final_field in attrs): - if final_val: - if final_field in self.list_attrs: - final_val = tuple((v.strip() for v in final_val.split(',') if v)) - elif final_field in self.size_attrs: - size_split = final_val.split(' ') - - if len(size_split) >= 1: - unit = size_split[1].upper() if len(size_split) >= 2 else 'B' - final_val = size_to_byte(size_split[0], unit, self._log) - else: - self._log.warning(f"Unhandled value ({val}) for attribute '{field}'") - final_val = None - - pkg[final_field] = final_val - - return info - - def simulate_removal(self, packages: Iterable[str], purge: bool = False) -> Optional[DebianTransaction]: - code, output = system.execute(self.gen_remove_cmd(packages, purge, simulate=True), shell=True, - custom_env=self.env) - - if code == 0 and output: - return self.map_transaction_output(output) - - def map_transaction_output(self, output: str) -> DebianTransaction: - to_install, to_upgrade, to_remove = None, None, None - current_collection = None - - for line in output.split('\n'): - if line.startswith('The following NEW packages will be installed:'): - to_install = set() - current_collection = to_install - elif line.startswith('The following packages will be upgraded:'): - to_upgrade = set() - current_collection = to_upgrade - elif line.startswith('The following packages will be REMOVED:'): - to_remove = set() - current_collection = to_remove - elif line.startswith('Would download/install/remove packages'): - break - elif current_collection is not None and line.startswith(' '): - for n, _, v, __, lv, ___, size in self.re_transaction_pkg.findall(line): - pkg = DebianPackage(name=n, version=v, latest_version=lv if lv else v, transaction_size=0) - - if size: - size_split = size.strip().split(' ') - unit = size_split[1][0].upper() if len(size_split) >= 2 else 'B' - pkg.transaction_size = size_to_byte(size_split[0], unit, self._log) - - current_collection.add(pkg) - - return DebianTransaction(to_install=tuple(to_install) if to_install else tuple(), - to_remove=tuple(to_remove) if to_remove else tuple(), - to_upgrade=tuple(to_upgrade) if to_upgrade else tuple()) - - def simulate_upgrade(self, packages: Iterable[str]) -> DebianTransaction: - code, output = system.execute(self.gen_transaction_cmd('upgrade', packages, simulate=True), - shell=True, custom_env=self.env) - - if code == 0 and output: - return self.map_transaction_output(output) - - def upgrade(self, packages: Iterable[str], root_password: Optional[str]) -> SimpleProcess: - cmd = self.gen_transaction_cmd('upgrade', packages).split(' ') - return SimpleProcess(cmd=cmd, shell=True, root_password=root_password, extra_env=self.vars_fixes, - preserve_env=self._preserve_env) - - def update(self, root_password: Optional[str]) -> SimpleProcess: - return SimpleProcess(('aptitude', 'update'), root_password=root_password, shell=True) - - def simulate_installation(self, packages: Iterable[str]) -> Optional[DebianTransaction]: - code, output = system.execute(self.gen_transaction_cmd('install', packages, simulate=True), - shell=True, custom_env=self.env) - - if code == 0 and output: - return self.map_transaction_output(output) - - def install(self, packages: Iterable[str], root_password: Optional[str]) -> SimpleProcess: - cmd = self.gen_transaction_cmd('install', packages).split(' ') - return SimpleProcess(cmd=cmd, root_password=root_password, extra_env=self.vars_fixes, - preserve_env=self._preserve_env) - - def read_installed(self) -> Generator[DebianPackage, None, None]: - yield from self.search(query='~i') - - def read_updates(self) -> Generator[Tuple[str, str], None, None]: - _, output = system.execute(f"aptitude search ~U -q -F '%p^%V' --disable-columns --no-gui", - shell=True, - custom_env=self.env) - - if output: - for line in output.split('\n'): - line_split = line.strip().split('^') - - if len(line_split) == 2 and line_split[1] != '': - yield line_split[0], line_split[1] - - def search(self, query: str, fill_size: bool = False) -> Generator[DebianPackage, None, None]: - attrs = f"%p^%v^%V^%m^%s^{'%I^' if fill_size else ''}%d" - _, output = system.execute(f"aptitude search {query} -q -F '{attrs}' --disable-columns", shell=True) - - if output: - no_attrs = 7 if fill_size else 6 - - for line in output.split('\n'): - line_split = line.strip().split('^', maxsplit=no_attrs - 1) - - if len(line_split) == no_attrs: - latest_version = line_split[2] if not self.re_none.match(line_split[2]) else None - - size = None - - if fill_size: - size_split = line_split[no_attrs - 2].split(' ') - unit = size_split[1][0].upper() if len(size_split) >= 2 else 'B' - size = size_to_byte(size_split[0], unit, self._log) - - if latest_version is not None: - installed_version = line_split[1] if not self.re_none.match(line_split[1]) else None - section = strip_section(line_split[4]) - - yield DebianPackage(name=line_split[0], - version=installed_version if installed_version else latest_version, - latest_version=latest_version, - installed=bool(installed_version), - update=installed_version is not None and installed_version != latest_version, - maintainer=strip_maintainer_email(line_split[3]), - categories=(section,) if section else None, - uncompressed_size=size, - description=line_split[no_attrs - 1]) - - def search_by_name(self, names: Iterable[str], fill_size: bool = False) -> Generator[DebianPackage, None, None]: - query = f"'({'|'.join(f'?exact-name({n})' for n in names)})'" - yield from self.search(query=query, fill_size=fill_size) - - def remove(self, packages: Iterable[str], root_password: Optional[str], purge: bool = False) -> SimpleProcess: - return SimpleProcess(cmd=self.gen_remove_cmd(packages, purge).split(' '), shell=True, - root_password=root_password, extra_env=self.vars_fixes, preserve_env=self._preserve_env) - - def read_installed_names(self) -> Generator[str, None, None]: - code, output = system.execute("aptitude search ~i -q -F '%p' --disable-columns", - shell=True, - custom_env=self.env) - - if output: - for line in output.split('\n'): - if line: - yield line - - @property - def re_show_attr(self) -> Pattern: - if self._re_show_attr is None: - self._re_show_attr = re.compile(r'(\n\w+[a-zA-Z0-9\-\s]*):\s+(.+)') - - return self._re_show_attr - - @property - def env(self) -> Dict[str, str]: - if self._env is None: - self._env = system.gen_env(global_interpreter=system.USE_GLOBAL_INTERPRETER) - self._env['LC_NUMERIC'] = '' - - return self._env - - @property - def list_attrs(self) -> Set[str]: - if self._list_attrs is None: - self._list_attrs = {'depends', 'provides', 'replaces', 'recommends', 'suggests', 'conflicts', - 'state', 'predepends', 'breaks'} - - return self._list_attrs - - @property - def re_transaction_pkg(self) -> Pattern: - if self._re_transaction_pkg is None: - self._re_transaction_pkg = re.compile(r'([a-zA-Z0-9\-_@~.+:]+)({\w+})?\s*\[([a-zA-Z0-9\-_@~.+:]+)' - r'(\s+->\s+([a-zA-Z0-9\-_@~.+:]+))?](\s*<([\-+]?[0-9.,]+\s+\w+)>)?') - - return self._re_transaction_pkg - - @property - def size_attrs(self) -> Tuple[str]: - if self._size_attrs is None: - self._size_attrs = {'compressed size', 'uncompressed size'} - - return self._size_attrs - - @property - def ignored_fields(self) -> Set[str]: - if self._ignored_fields is None: - self._ignored_fields = {'sha1', 'sha256', 'sha512', 'checksum-filesize'} - - return self._ignored_fields - - @classmethod - def gen_remove_cmd(cls, packages: Iterable[str], purge: bool, simulate: bool = False) -> str: - return cls.gen_transaction_cmd(type_='purge' if purge else 'remove', packages=packages, - simulate=simulate) - - @staticmethod - def gen_transaction_cmd(type_: str, packages: Iterable[str], simulate: bool = False, - delete_unused: bool = False) -> str: - return f"aptitude {type_} -q -y --no-gui --full-resolver {' '.join(packages)}" \ - f" -o Aptitude::ProblemResolver::RemoveScore=9999999" \ - f" -o Aptitude::ProblemResolver::EssentialRemoveScore=9999999" \ - f" -o Aptitude::Delete-Unused={str(delete_unused).lower()}" \ - f"{' -V -s -Z' if simulate else ''}" - - @property - def re_none(self) -> Pattern: - if self._re_none is None: - self._re_none = re.compile(r'^<\w+>$') - - return self._re_none - - @property - def vars_fixes(self) -> Dict[str, str]: - if self._vars_fixes is None: - self._vars_fixes = {'LC_NUMERIC': '', 'DEBIAN_FRONTEND': 'noninteractive'} - - return self._vars_fixes - - -class AptitudeOutputHandler(Thread): - - def __init__(self, i18n: I18n, targets: Iterable[str], re_download: Pattern, watcher: ProcessWatcher, - action: AptitudeAction): - super(AptitudeOutputHandler, self).__init__() - self._i18n = i18n - self._re_download = re_download - self._watcher = watcher - self._targets = set(targets) if targets is not None else None - self._unpacking = 0 - self._removing = 0 - self._downloading = 0 - self._to_process = Queue() - self._work = True - self._action = action - - def stop_working(self): - self._work = False - - def handle(self, string: str): - self._to_process.put(string) - - @property - def total_targets(self) -> int: - return len(self._targets) if self._targets else 0 - - @property - def processed(self) -> int: - return self._removing if self._action == AptitudeAction.REMOVE else self._unpacking - - def _get_progress(self, current: int) -> str: - if self.total_targets > 0: - if self._action == AptitudeAction.REMOVE: - total = self._removing - else: - if self.total_targets == self._unpacking: - total = self.total_targets - else: - total = ceil((self._unpacking + self._downloading) / 2) - - return f'({total / self.total_targets * 100:.2f}%) [{current}/{self.total_targets}] ' - - return '' - - def run(self): - while self._work: - time.sleep(0.001) - - if self._to_process.empty(): - continue - - string = self._to_process.get() - - if self.total_targets > 0 and self.total_targets == self._unpacking: - self._watcher.change_substatus(self._i18n['debian.output.finishing']) - continue - - if string: - if self._action != AptitudeAction.REMOVE and string.startswith('Unpacking '): - unpacking = string.split(' ') - - if len(unpacking) >= 2 and unpacking[1]: - pkg = map_package_name(unpacking[1].strip()) - - if self._targets and pkg in self._targets: - self._unpacking += 1 - - msg = f"{self._get_progress(self._unpacking)}" \ - f"{self._i18n['debian.output.unpacking'].format(pkg=bold(pkg))}" - - self._watcher.change_substatus(msg) - - continue - - if self._action == AptitudeAction.REMOVE and string.startswith('Removing '): - unpacking = string.split(' ') - - if len(unpacking) >= 2 and unpacking[1]: - pkg = unpacking[1].strip() - - if self._targets and pkg in self._targets: - self._removing += 1 - - msg = f"{self._get_progress(self._removing)}" \ - f"{self._i18n['debian.output.removing'].format(pkg=bold(pkg))}" - - self._watcher.change_substatus(msg) - - continue - - download = self._re_download.findall(string) - - if download: - data = download[0].split(' ') - - if len(data) >= 4: - pkg = data[3].strip() - - if self._targets and pkg in self._targets: - self._downloading += 1 - - msg = f"{self._get_progress(self._downloading)}" \ - f"{self._i18n['debian.output.downloading'].format(pkg=bold(pkg))}" - - self._watcher.change_substatus(msg) - - continue - - _processed = self.processed - if self._targets and _processed > 0: - self._watcher.change_substatus(self._get_progress(_processed).strip()) - continue - - self._watcher.change_substatus(' ') - - -class AptitudeOutputHandlerFactory: - - def __init__(self, i18n: I18n): - self._i18n = i18n - self._re_download: Optional[Pattern] = None - - @property - def re_download(self) -> Pattern: - if self._re_download is None: - self._re_download = re.compile(r'Get:\s+\d+\s+https?://(.+)') - - return self._re_download - - @contextmanager - def start(self, watcher: ProcessWatcher, targets: Iterable[str], action: AptitudeAction): - handler = AptitudeOutputHandler(i18n=self._i18n, re_download=self.re_download, - watcher=watcher, targets=targets, action=action) - handler.start() - - yield handler.handle - - handler.stop_working() - handler.join() diff --git a/bauh/gems/debian/common.py b/bauh/gems/debian/common.py deleted file mode 100644 index 910525ea..00000000 --- a/bauh/gems/debian/common.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Dict, Optional - -from bauh.gems.debian.model import DebianPackage - - -def strip_maintainer_email(maintainer: str) -> str: - return maintainer.split('<')[0].strip() - - -def strip_section(section: str) -> Optional[str]: - if section: - section_split = section.split('/') - return section_split[1] if len(section_split) > 1 else section - - -def fill_show_data(pkg: DebianPackage, data: Dict[str, object]): - if data: - for attr, val in data.items(): - final_attr = attr.replace(' ', '_') - - if not val or val == '': - final_val = None - else: - if attr == 'maintainer': - final_val = strip_maintainer_email(str(val)) - elif attr == 'section': - final_attr = 'categories' - final_val = (strip_section(str(val)),) - else: - final_val = val - - setattr(pkg, final_attr, final_val) diff --git a/bauh/gems/debian/config.py b/bauh/gems/debian/config.py deleted file mode 100644 index a81ccd3d..00000000 --- a/bauh/gems/debian/config.py +++ /dev/null @@ -1,17 +0,0 @@ -from bauh.commons.config import YAMLConfigManager -from bauh.gems.debian import CONFIG_FILE - - -class DebianConfigManager(YAMLConfigManager): - - def __init__(self): - super(DebianConfigManager, self).__init__(config_file_path=CONFIG_FILE) - - def get_default_config(self) -> dict: - return { - 'suggestions.exp': 24, # hours - 'index_apps.exp': 1440, # 24 hours - 'sync_pkgs.time': 1440, # 24 hours - 'pkg_sources.app': None, - 'remove.purge': False - } diff --git a/bauh/gems/debian/controller.py b/bauh/gems/debian/controller.py deleted file mode 100644 index 5f1182a5..00000000 --- a/bauh/gems/debian/controller.py +++ /dev/null @@ -1,903 +0,0 @@ -import os.path -import shutil -import traceback -from operator import attrgetter -from pathlib import Path -from shutil import which -from subprocess import Popen -from threading import Thread -from typing import List, Optional, Tuple, Set, Type, Dict, Iterable, Generator - -from bauh.api.abstract.context import ApplicationContext -from bauh.api.abstract.controller import SoftwareManager, SoftwareAction, TransactionResult, UpgradeRequirements, \ - SearchResult, UpgradeRequirement, SettingsView, SettingsController -from bauh.api.abstract.disk import DiskCacheLoader -from bauh.api.abstract.handler import TaskManager, ProcessWatcher -from bauh.api.abstract.model import SoftwarePackage, PackageSuggestion, PackageUpdate, PackageHistory, \ - CustomSoftwareAction -from bauh.api.abstract.view import TextInputComponent, PanelComponent, FormComponent, MessageType, \ - SingleSelectComponent, InputOption, SelectViewType, ViewComponentAlignment -from bauh.api.paths import CONFIG_DIR -from bauh.commons.html import bold -from bauh.commons.system import ProcessHandler -from bauh.commons.util import NullLoggerFactory -from bauh.commons.view_utils import get_human_size_str -from bauh.gems.debian import DEBIAN_ICON_PATH -from bauh.gems.debian.aptitude import Aptitude, AptitudeOutputHandlerFactory, AptitudeAction -from bauh.gems.debian.common import fill_show_data -from bauh.gems.debian.config import DebianConfigManager -from bauh.gems.debian.gui import DebianViewBridge -from bauh.gems.debian.index import ApplicationIndexer, ApplicationIndexError, ApplicationsMapper -from bauh.gems.debian.model import DebianPackage, DebianApplication -from bauh.gems.debian.suggestions import DebianSuggestionsDownloader -from bauh.gems.debian.tasks import UpdateApplicationIndex, MapApplications, SynchronizePackages - - -class DebianPackageManager(SoftwareManager, SettingsController): - - def __init__(self, context: ApplicationContext): - super(DebianPackageManager, self).__init__(context) - self._i18n = context.i18n - self._log = context.logger - self._types: Optional[Set[Type[SoftwarePackage]]] = None - self._enabled = True - self._app_indexer: Optional[ApplicationIndexer] = None - self._apps_index: Optional[Dict[str, DebianApplication]] = None - self._configman: Optional[DebianConfigManager] = None - self._action_launch_sources: Optional[CustomSoftwareAction] = None - self._default_actions: Optional[Iterable[CustomSoftwareAction]] = None - self._view: Optional[DebianViewBridge] = None - self._app_mapper: Optional[ApplicationsMapper] = None - self._aptitude: Optional[Aptitude] = None - self._output_handler: Optional[AptitudeOutputHandlerFactory] = None - self._known_sources_apps: Optional[Tuple[str, ...]] = None - self._install_show_attrs: Optional[Set[str]] = None - self._file_ignored_updates: Optional[str] = None - self._suggestions_downloader: Optional[DebianSuggestionsDownloader] = None - - def _update_apps_index(self, apps: Iterable[DebianApplication]): - self._apps_index = {app.name: app for app in apps} if apps else dict() - - def search(self, words: str, disk_loader: Optional[DiskCacheLoader], limit: int, is_url: bool) -> SearchResult: - config_ = dict() - fill_config = Thread(target=self._fill_config, args=(config_,), daemon=True) - fill_config.start() - - res = SearchResult.empty() - - if not is_url: - for pkg in self.aptitude.search(words): - if fill_config.is_alive(): - fill_config.join() - - pkg.global_purge = bool(config_.get('remove.purge', False)) - if pkg.installed: - pkg.bind_app(self.apps_index.get(pkg.name)) - res.installed.append(pkg) - else: - res.new.append(pkg) - - return res - - def _fill_ignored_updates(self, output: Set[str]): - - try: - with open(self.file_ignored_updates) as f: - ignored_str = f.read() - except FileNotFoundError: - return - - if ignored_str: - for line in ignored_str.split('\n'): - line_clean = line.strip() - - if line_clean: - output.add(line_clean) - - def _fill_config(self, config_: dict): - config_.update(self.configman.get_config()) - - def read_installed(self, disk_loader: Optional[DiskCacheLoader], pkg_types: Optional[Set[Type[SoftwarePackage]]], - internet_available: bool, limit: int = -1, only_apps: bool = False, - names: Optional[Iterable[str]] = None) -> SearchResult: - - config_ = dict() - fill_config = Thread(target=self._fill_config, args=(config_,), daemon=True) - fill_config.start() - - ignored_updates = set() - fill_ignored_updates = Thread(target=self._fill_ignored_updates, args=(ignored_updates,), daemon=True) - fill_ignored_updates.start() - - threads = (fill_config, fill_ignored_updates) - - res = SearchResult(installed=[], new=None, total=0) - - for pkg in self.aptitude.read_installed(): - for t in threads: - if t.is_alive(): - t.join() - - pkg.bind_app(self.apps_index.get(pkg.name)) - pkg.global_purge = bool(config_.get('remove.purge', False)) - pkg.updates_ignored = bool(ignored_updates and pkg.name in ignored_updates) - res.installed.append(pkg) - - return res - - def downgrade(self, pkg: SoftwarePackage, root_password: str, handler: ProcessWatcher) -> bool: - return False - - def upgrade(self, requirements: UpgradeRequirements, root_password: str, watcher: ProcessWatcher) -> bool: - handler = ProcessHandler(watcher) - - targets = (r.pkg.name for r in (*requirements.to_upgrade, *(requirements.to_install or ()))) - - with self.output_handler.start(watcher=watcher, targets=targets, action=AptitudeAction.UPGRADE) as handle: - to_upgrade = (r.pkg.name for r in requirements.to_upgrade) - success, _ = handler.handle_simple(self.aptitude.upgrade(packages=to_upgrade, - root_password=root_password), - output_handler=handle) - return success - - def _fill_updates(self, output: Dict[str, str]): - for name, version in self.aptitude.read_updates(): - output[name] = version - - def uninstall(self, pkg: DebianPackage, root_password: str, watcher: ProcessWatcher, - disk_loader: Optional[DiskCacheLoader], purge: bool = False) -> TransactionResult: - - config_ = self.configman.get_config() - purge_ = purge or config_.get('remove.purge', False) - - watcher.change_substatus(self._i18n['debian.simulate_operation']) - - transaction = self.aptitude.simulate_removal((pkg.name,), purge=purge_) - - if not transaction or not transaction.to_remove: - return TransactionResult.fail() - - if pkg not in transaction.to_remove: - watcher.show_message(title=self._i18n['popup.title.error'], - body=self._i18n['debian.remove.impossible'].format(pkg=bold(pkg.name)), - type_=MessageType.ERROR) - return TransactionResult.fail() - - watcher.change_substatus('') - - deps = tuple(p for p in transaction.to_remove if p.name != pkg.name) - - if deps: - # updates are required to be filled in case the dependencies are currently displayed on the view - updates = dict() - fill_updates = Thread(target=self._fill_updates, args=(updates,), daemon=True) - fill_updates.start() - - deps_data = self.aptitude.show((p.name for p in deps), attrs=('description', 'maintainer', 'section')) - - if deps_data: - for p in deps: - fill_show_data(p, deps_data.get(p.name)) - - if not self.view.confirm_removal(source_pkg=pkg.name, dependencies=deps, watcher=watcher): - return TransactionResult.fail() - - fill_updates.join() - - if updates: - for p in deps: - latest_version = updates.get(p.name) - - if latest_version is not None and p.version != latest_version: - p.latest_version = latest_version - p.update = True - - watcher.change_substatus(self._i18n['debian.uninstall.removing']) - - handler = ProcessHandler(watcher) - to_remove = tuple(p.name for p in transaction.to_remove) - with self.output_handler.start(watcher=watcher, targets=to_remove, action=AptitudeAction.REMOVE) as handle: - removed, _ = handler.handle_simple(self.aptitude.remove(packages=to_remove, root_password=root_password, - purge=purge_), - output_handler=handle) - - if not removed: - return TransactionResult.fail() - - watcher.change_substatus(self._i18n['debian.uninstall.validating']) - - current_installed_names = set(self.aptitude.read_installed_names()) - - watcher.change_substatus('') - - all_removed, apps_removed, not_removed_names = [], set(), set() - - for p in transaction.to_remove: - if p.name not in current_installed_names: - instance = p if p != pkg else pkg - - all_removed.append(instance) - - if instance.app: - apps_removed.add(instance.app) - - instance.installed = False - instance.version = instance.latest_version - instance.update = False - instance.bind_app(None) - else: - not_removed_names.add(p.name) - - if apps_removed: # updating apps index - watcher.print(self._i18n['debian.app_index.updating'] + ' ...') - watcher.change_substatus(self._i18n['debian.app_index.updating']) - indexed_apps = set(self.app_indexer.read_index()) - - if indexed_apps: - new_index = indexed_apps.difference(apps_removed) - try: - self.app_indexer.update_index(new_index, update_timestamp=False) - self._update_apps_index(new_index) - self._log.info(f"Debian applications removed from the index: " - f"{', '.join((a.name for a in apps_removed))}") - except ApplicationIndexError: - pass - - watcher.change_substatus('') - - success = True - if not_removed_names: - success = pkg.name not in not_removed_names - not_removed_str = ', '.join((bold(p) for p in sorted(not_removed_names))) - watcher.show_message(title=self._i18n[f"popup.title.{'warning' if success else 'error'}"], - body=self._i18n['debian.uninstall.failed_to_remove'].format(no=len(not_removed_names), - pkgs=not_removed_str), - type_=MessageType.WARNING if success else MessageType.ERROR) - - return TransactionResult(success=success, installed=None, removed=all_removed) - - def _map_dependents(self, packages_data: Dict[str, Dict[str, object]]) -> Optional[Dict[str, Set[str]]]: - if packages_data: - dependents = None - if packages_data: - dependents = dict() - - for p, data in packages_data.items(): - for attr in ('depends', 'predepends'): - dep_exps = data.get(attr) - - if isinstance(dep_exps, tuple): - for exp in dep_exps: - dep = exp.split(' ')[0].strip() - dep_dependents = dependents.get(dep) - if dep_dependents is None: - dep_dependents = set() - dependents[dep] = dep_dependents - - dep_dependents.add(p) - - return dependents - - def get_upgrade_requirements(self, pkgs: List[DebianPackage], root_password: str, watcher: ProcessWatcher) \ - -> UpgradeRequirements: - - transaction = self.aptitude.simulate_upgrade((p.name for p in pkgs)) - - if transaction: - size_to_query = (f'{p.name}={p.latest_version}' for p in (*transaction.to_upgrade, - *transaction.to_install, - *transaction.to_remove)) - - update_extra_attrs = ('compressed size', *(('depends', 'predepends') if transaction.to_install else ())) - update_data = self.aptitude.show(pkgs=size_to_query, attrs=update_extra_attrs) - - to_install = None - if transaction.to_install: - dependents = self._map_dependents(update_data) - - to_install = [] - for p in transaction.to_install: - p_data = update_data.get(p.name) if update_data else None - req_size = p_data.get('compressed size') if p_data else None - - reason = None - if dependents: - p_dependents = dependents.get(p.name) - - if p_dependents: - deps_str = ', '.join((bold(d) for d in p_dependents)) - reason = self._i18n['debian.transaction.dependency_of'].format(pkgs=deps_str) - - to_install.append(UpgradeRequirement(pkg=p, reason=reason, required_size=req_size, - extra_size=p.transaction_size)) - - to_install.sort(key=attrgetter('pkg.name')) - to_install = tuple(to_install) - - to_remove = None - if transaction.to_remove: - to_remove = [] - - for p in transaction.to_remove: - to_remove.append(UpgradeRequirement(pkg=p, required_size=0, extra_size=p.transaction_size)) - - to_remove.sort(key=attrgetter('pkg.name')) - to_remove = tuple(to_remove) - - to_upgrade = None - - if transaction.to_upgrade: - to_upgrade = [] - - for p in transaction.to_upgrade: - p_data = update_data.get(p.name) if update_data else None - - if p_data: - req_size = p_data.get('compressed size') - else: - req_size = None - - to_upgrade.append(UpgradeRequirement(pkg=p, required_size=req_size, extra_size=p.transaction_size)) - - to_upgrade.sort(key=attrgetter('pkg.name')) - to_upgrade = tuple(to_upgrade) - - return UpgradeRequirements(to_install=to_install, to_upgrade=to_upgrade, - to_remove=to_remove, cannot_upgrade=None) - else: - cannot_upgrade = [UpgradeRequirement(pkg=p, reason=self._i18n['error']) for p in pkgs] - cannot_upgrade.sort(key=attrgetter('pkg.name')) - return UpgradeRequirements(cannot_upgrade=cannot_upgrade, to_install=None, to_remove=None, - to_upgrade=[]) - - def get_managed_types(self) -> Set[Type[SoftwarePackage]]: - if self._types is None: - self._types = {DebianPackage} - - return self._types - - def get_info(self, pkg: DebianPackage) -> Optional[dict]: - info = {'00.name': pkg.name, '01.version': pkg.version, - "02.description": pkg.description} - - if pkg.installed and pkg.app: - info['03.exec'] = pkg.app.exe_path - - extra_info = self.aptitude.show((f'{pkg.name}={pkg.version}',), verbose=True) - - if extra_info: - extra_info = extra_info.get(pkg.name) - - if extra_info: - ignored_fields = {'package', 'version', 'description'} - - for field, val in extra_info.items(): - if field not in ignored_fields and not field.startswith('description'): - final_val = get_human_size_str(val) if field in self.aptitude.size_attrs else val - final_field = f'04.{field}' - - if final_field not in self._i18n: - self._i18n.default[final_field] = field - - info[final_field] = final_val # for sorting - - return info - - def get_history(self, pkg: SoftwarePackage) -> PackageHistory: - pass - - def install(self, pkg: SoftwarePackage, root_password: str, disk_loader: Optional[DiskCacheLoader], - watcher: ProcessWatcher) -> TransactionResult: - - watcher.change_substatus(self._i18n['debian.simulate_operation']) - transaction = self.aptitude.simulate_installation((pkg.name, )) - - if transaction is None or not transaction.to_install: - return TransactionResult.fail() - - if transaction.to_remove or (transaction.to_install and len(transaction.to_install) > 1): - watcher.change_substatus(self._i18n['debian.transaction.get_data']) - - deps = tuple(p for p in transaction.to_install or () if p.name != pkg.name) - removal = tuple(p for p in transaction.to_remove or ()) - all_pkgs = [*deps, *removal] - - pkgs_data = self.aptitude.show(pkgs=(f'{d.name}={d.version}' for d in all_pkgs), - attrs=self.install_show_attrs) - - if pkgs_data: - for p in all_pkgs: - fill_show_data(p, pkgs_data.get(p.name)) - - if not self.view.confirm_transaction(to_install=deps, removal=removal, watcher=watcher): - return TransactionResult.fail() - - watcher.change_substatus(self._i18n['debian.installing_pkgs']) - handler = ProcessHandler(watcher) - - targets = (p.name for p in transaction.to_install) - with self.output_handler.start(watcher=watcher, targets=targets, action=AptitudeAction.INSTALL) as handle: - installed, _ = handler.handle_simple(self.aptitude.install(packages=(pkg.name,), - root_password=root_password), - output_handler=handle) - - if installed: - self._refresh_apps_index(watcher) - - watcher.change_substatus(self._i18n['debian.install.validating']) - - currently_installed = set(self.aptitude.read_installed_names()) - - installed_instances = [] - if currently_installed: - for p in transaction.to_install: - instance = p if p != pkg else pkg - if instance.name in currently_installed: - instance.installed = True - instance.bind_app(self.apps_index.get(instance.name)) - installed_instances.append(instance) - - removed = None - - if transaction.to_remove: - removed = [p for p in transaction.to_remove if p.name not in currently_installed] - - not_removed = set(transaction.to_remove).difference(removed) - - if not_removed: - not_removed_str = ' '.join(p.name for p in not_removed) - self._log.warning(f"The following packages were not removed: {not_removed_str}") - - return TransactionResult(installed=installed_instances, removed=removed, - success=bool(installed_instances and pkg in installed_instances)) - else: - watcher.change_substatus('') - return TransactionResult.fail() - - def _refresh_apps_index(self, watcher: ProcessWatcher): - watcher.change_substatus(self._i18n['debian.app_index.checking']) - self._log.info("Reading the cached Debian applications") - indexed_apps = self.app_indexer.read_index() - self._log.info("Mapping the Debian applications") - current_apps = self.app_mapper.map_executable_applications() - - if current_apps != indexed_apps: - watcher.print(self._i18n['debian.app_index.updating'] + '...') - watcher.change_substatus(self._i18n['debian.app_index.updating']) - - try: - self.app_indexer.update_index(current_apps) - self._update_apps_index(current_apps) - - if indexed_apps is not None: - new_apps = current_apps.difference(indexed_apps) - - if new_apps: - self._log.info(f"Debian applications added to the index: " - f"{','.join((a.name for a in new_apps))}") - - except ApplicationIndexError: - pass - - 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]]: - if not which('aptitude'): - return False, self._i18n['missing_dep'].format(dep=bold('aptitude')) - - return True, None - - def requires_root(self, action: SoftwareAction, pkg: Optional[SoftwarePackage]) -> bool: - if action == action.PREPARE: - deb_config = self.configman.get_config() - return SynchronizePackages.should_synchronize(deb_config, NullLoggerFactory.logger()) - - return action != SoftwareAction.SEARCH - - def prepare(self, task_manager: Optional[TaskManager], root_password: Optional[str], - internet_available: Optional[bool]): - - deb_config = self.configman.get_config() - - if SynchronizePackages.should_synchronize(deb_config, self._log): - sync_pkgs = SynchronizePackages(taskman=task_manager, i18n=self._i18n, logger=self._log, - root_password=root_password, aptitude=self.aptitude) - sync_pkgs.start() - - if self.suggestions_downloader.should_download(deb_config, only_positive_exp=True): - self.suggestions_downloader.register_task(task_manager) - self.suggestions_downloader.start() - - self.index_apps(root_password=root_password, watcher=None, taskman=task_manager, - deb_config=deb_config, check_expiration=True) - - def list_updates(self, internet_available: bool) -> List[PackageUpdate]: - ignored_updates = set() - fill_ignored_updates = Thread(target=self._fill_ignored_updates, args=(ignored_updates,), daemon=True) - fill_ignored_updates.start() - - updates = list() - for name, version in self.aptitude.read_updates(): - if fill_ignored_updates.is_alive(): - fill_ignored_updates.join() - - if name not in ignored_updates: - updates.append(PackageUpdate(pkg_id=name, name=name, version=version, pkg_type='debian')) - - return updates - - def list_warnings(self, internet_available: bool) -> Optional[List[str]]: - pass - - def _fill_installed_names(self, output: Set[str]): - output.update(self.aptitude.read_installed_names()) - - def _fill_suggestions(self, output: Dict[str, int]): - self.suggestions_downloader.register_task(None) - suggestions = self.suggestions_downloader.read(self.configman.read_config()) - - if suggestions: - output.update(suggestions) - - def list_suggestions(self, limit: int, filter_installed: bool) -> Optional[List[PackageSuggestion]]: - name_priority = dict() - - fill_suggestions = Thread(target=self._fill_suggestions, args=(name_priority,)) - fill_suggestions.start() - - if filter_installed: - installed = set() - fill_installed = Thread(target=self._fill_installed_names, args=(installed,), daemon=True) - fill_installed.start() - else: - installed, fill_installed = None, None - - fill_suggestions.join() - - if fill_installed: - fill_installed.join() - - if not name_priority: - self._log.info("No Debian package suggestions found") - return [] - - self._log.info(f"Found {len(name_priority)} Debian package suggestions") - - to_load = tuple(name_priority.keys()) if not installed else {*name_priority.keys()}.difference(installed) - - if not to_load: - return [] - - suggestions = [] - - for pkg in self.aptitude.search_by_name(to_load): - prio = name_priority.get(pkg.name) - - if prio: - suggestions.append(PackageSuggestion(package=pkg, priority=prio)) - - return suggestions - - def is_default_enabled(self) -> bool: - return True - - def launch(self, pkg: SoftwarePackage): - if isinstance(pkg, DebianPackage): - final_cmd = pkg.app.exe_path.replace('%U', '') - Popen(final_cmd, shell=True) - - def get_settings(self) -> Optional[Generator[SettingsView, None, None]]: - config_ = self.configman.get_config() - - purge_opts = [InputOption(label=self._i18n['yes'].capitalize(), value=True), - InputOption(label=self._i18n['no'].capitalize(), value=False)] - - purge_current = tuple(o for o in purge_opts if o.value == bool(config_['remove.purge']))[0] - sel_purge = SingleSelectComponent(id_='remove.purge', - label=self._i18n['debian.config.remove.purge'], - tooltip=self._i18n['debian.config.remove.purge.tip'], - options=purge_opts, - default_option=purge_current, - type_=SelectViewType.RADIO, - max_per_line=2) - - sources_app = config_.get('pkg_sources.app') - - if isinstance(sources_app, str) and sources_app not in self.known_sources_apps: - self._log.warning(f"'pkg_sources.app' ({sources_app}) is not supported. A 'None' value will be considered") - sources_app = None - - lb_source_auto = self._i18n['debian.config.pkg_sources.app.auto'] - source_opts = [InputOption(id_='auto', value=None, label=lb_source_auto)] - - source_opts.extend((InputOption(id_=a, value=a, label=a) for a in self.known_sources_apps if which(a))) - - source_auto_tip = self._i18n['debian.config.pkg_sources.app.tip'].format(auto=f'"{lb_source_auto}"') - input_sources = SingleSelectComponent(id_='pkg_sources.app', - label=self._i18n['debian.config.pkg_sources.app'], - tooltip=source_auto_tip, - options=source_opts, - default_option=next(o for o in source_opts if o.value == sources_app), - alignment=ViewComponentAlignment.CENTER, - type_=SelectViewType.COMBO) - - try: - app_cache_exp = int(config_.get('index_apps.exp', 0)) - except ValueError: - self._log.error(f"Unexpected value form Debian configuration property 'index_apps.exp': " - f"{config_['index_apps.exp']}. Zero (0) will be considered instead.") - app_cache_exp = 0 - - ti_index_apps_exp = TextInputComponent(id_='index_apps.exp', - label=self._i18n['debian.config.index_apps.exp'], - tooltip=self._i18n['debian.config.index_apps.exp.tip'], - value=str(app_cache_exp), only_int=True) - - try: - sync_pkgs_time = int(config_.get('sync_pkgs.time', 0)) - except ValueError: - self._log.error(f"Unexpected value form Debian configuration property 'sync_pkgs.time': {config_['sync_pkgs.time']}. " - f"Zero (0) will be considered instead.") - sync_pkgs_time = 0 - - ti_sync_pkgs = TextInputComponent(id_='sync_pkgs.time', - label=self._i18n['debian.config.sync_pkgs.time'], - tooltip=self._i18n['debian.config.sync_pkgs.time.tip'], - value=str(sync_pkgs_time), only_int=True) - - try: - suggestions_exp = int(config_.get('suggestions.exp', 0)) - except ValueError: - self._log.error(f"Unexpected value form Debian configuration property 'suggestions.exp': {config_['suggestions.exp']}. " - f"Zero (0) will be considered instead.") - suggestions_exp = 0 - - ti_suggestions_exp = TextInputComponent(id_='suggestions.exp', - label=self._i18n['debian.config.suggestions.exp'], - tooltip=self._i18n['debian.config.suggestions.exp.tip'], - value=str(suggestions_exp), only_int=True) - - panel = PanelComponent([FormComponent([input_sources, sel_purge, ti_sync_pkgs, ti_index_apps_exp, - ti_suggestions_exp])]) - yield SettingsView(self, panel) - - def save_settings(self, component: PanelComponent) -> Tuple[bool, Optional[List[str]]]: - config_ = self.configman.get_config() - - container = component.get_component_by_idx(0, FormComponent) - - for prop, type_ in {'remove.purge': SingleSelectComponent, - 'pkg_sources.app': SingleSelectComponent, - 'index_apps.exp': TextInputComponent, - 'sync_pkgs.time': TextInputComponent, - 'suggestions.exp': TextInputComponent}.items(): - comp = container.get_component(prop, type_) - - val = None - if isinstance(comp, SingleSelectComponent): - val = comp.get_selected() - elif isinstance(comp, TextInputComponent): - val = comp.get_int_value() - - config_[prop] = val - - try: - self.configman.save_config(config_) - return True, None - except Exception: - return False, [traceback.format_exc()] - - def gen_custom_actions(self) -> Generator[CustomSoftwareAction, None, None]: - if self._default_actions is None: - self._default_actions = (CustomSoftwareAction(i18n_label_key='debian.action.sync_pkgs', - i18n_status_key='debian.task.sync_pkgs.status', - i18n_description_key='debian.action.sync_pkgs.desc', - icon_path=DEBIAN_ICON_PATH, - manager_method='synchronize_packages', - requires_root=True), - CustomSoftwareAction(i18n_label_key='debian.action.index_apps', - i18n_status_key='debian.task.app_index.status', - i18n_description_key='debian.action.index_apps.desc', - icon_path=DEBIAN_ICON_PATH, - manager_method='index_apps', - requires_root=False) - ) - - yield from self._default_actions - - for _ in self.get_installed_source_apps(): - yield self.action_launch_sources - break - - def _write_ignored_updates(self, packages: Iterable[str]): - Path(os.path.dirname(self.file_ignored_updates)).mkdir(parents=True, exist_ok=True) - - with open(self.file_ignored_updates, 'w+') as f: - f.write('\n'.join(n for n in sorted(packages))) - - def ignore_update(self, pkg: DebianPackage): - ignored_packages = set() - self._fill_ignored_updates(ignored_packages) - - if pkg.name not in ignored_packages: - pkg.updates_ignored = True - ignored_packages.add(pkg.name) - self._write_ignored_updates(ignored_packages) - - def revert_ignored_update(self, pkg: DebianPackage): - ignored_packages = set() - self._fill_ignored_updates(ignored_packages) - - if pkg.name in ignored_packages: - pkg.updates_ignored = False - ignored_packages.remove(pkg.name) - self._write_ignored_updates(ignored_packages) - - def synchronize_packages(self, root_password: Optional[str], watcher: ProcessWatcher) -> bool: - return SynchronizePackages(i18n=self._i18n, logger=self._log, root_password=root_password, watcher=watcher, - aptitude=self.aptitude, taskman=TaskManager()).run() - - def index_apps(self, root_password: Optional[str], watcher: Optional[ProcessWatcher], - taskman: Optional[TaskManager] = None, deb_config: Optional[dict] = None, - check_expiration: bool = False) -> bool: - _config = deb_config if deb_config else self.configman.get_config() - _taskman = taskman if taskman else TaskManager() - - map_apps = MapApplications(taskman=_taskman, app_indexer=self.app_indexer, - i18n=self._i18n, logger=self._log, deb_config=deb_config, - app_mapper=self.app_mapper, check_expiration=check_expiration, - watcher=watcher) - map_apps.start() - - gen_app_index = UpdateApplicationIndex(taskman=_taskman, app_indexer=self.app_indexer, - i18n=self._i18n, logger=self._log, - mapping_apps=map_apps) - gen_app_index.start() - - map_apps.join() - self._update_apps_index(map_apps.apps) - gen_app_index.join() - return True - - def purge(self, pkg: DebianPackage, root_password: str, watcher: ProcessWatcher) -> bool: - if not self.view.confirm_purge(pkg.name, watcher): - return False - - res = self.uninstall(pkg=pkg, root_password=root_password, watcher=watcher, disk_loader=None, purge=True) - return res.success - - def launch_sources_app(self, root_password: str, watcher: ProcessWatcher) -> bool: - deb_config = self.configman.get_config() - - sources_app = deb_config.get('pkg_sources.app') - - if isinstance(sources_app, str) and sources_app not in self.known_sources_apps: - watcher.show_message(title=self._i18n['popup.title.error'], - body=self._i18n['debian.action.sources.unsupported'].format(app=bold(sources_app))) - return False - - if sources_app: - if not which(sources_app): - watcher.show_message(title=self._i18n['popup.title.error'], - body=self._i18n['debian.action.sources.not_installed'], - type_=MessageType.ERROR) - return False - - Popen(sources_app, shell=True) - return True - - for app in self.get_installed_source_apps(): - Popen(app, shell=True) - return True - - watcher.show_message(title=self._i18n['popup.title.error'], - body=self._i18n['debian.action.sources.not_installed'], - type_=MessageType.ERROR) - return False - - @property - def app_indexer(self) -> ApplicationIndexer: - if self._app_indexer is None: - self._app_indexer = ApplicationIndexer(self._log) - - return self._app_indexer - - @property - def apps_index(self) -> Dict[str, DebianApplication]: - if self._apps_index is None: - self._update_apps_index(self.app_indexer.read_index()) - - return self._apps_index - - @property - def install_show_attrs(self) -> Set[str]: - if self._install_show_attrs is None: - self._install_show_attrs = {'description', 'maintainer', 'section', 'compressed size'} - - return self._install_show_attrs - - @property - def configman(self) -> DebianConfigManager: - if self._configman is None: - self._configman = DebianConfigManager() - - return self._configman - - @property - def view(self) -> DebianViewBridge: - if self._view is None: - self._view = DebianViewBridge(screen_width=self.context.screen_width, - screen_heigth=self.context.screen_height, - i18n=self._i18n) - - return self._view - - @property - def app_mapper(self) -> ApplicationsMapper: - if self._app_mapper is None: - self._app_mapper = ApplicationsMapper(logger=self._log) - - return self._app_mapper - - @property - def aptitude(self) -> Aptitude: - if self._aptitude is None: - self._aptitude = Aptitude(self._log) - - return self._aptitude - - @property - def output_handler(self) -> AptitudeOutputHandlerFactory: - if self._output_handler is None: - self._output_handler = AptitudeOutputHandlerFactory(i18n=self._i18n) - - return self._output_handler - - @property - def action_launch_sources(self) -> CustomSoftwareAction: - if self._action_launch_sources is None: - self._action_launch_sources = CustomSoftwareAction(i18n_label_key='debian.action.sources', - i18n_status_key='debian.task.sources.status', - i18n_description_key='debian.action.sources.desc', - icon_path=DEBIAN_ICON_PATH, - manager_method='launch_sources_app', - requires_confirmation=False, - requires_root=False) - - return self._action_launch_sources - - @property - def known_sources_apps(self) -> Tuple[str, ...]: - if self._known_sources_apps is None: - self._known_sources_apps = ('software-properties-gtk',) - - return self._known_sources_apps - - @property - def file_ignored_updates(self) -> str: - if self._file_ignored_updates is None: - self._file_ignored_updates = f'{CONFIG_DIR}/debian/updates_ignored.txt' - - return self._file_ignored_updates - - @property - def suggestions_downloader(self) -> DebianSuggestionsDownloader: - if not self._suggestions_downloader: - file_url = self.context.get_suggestion_url(self.__module__) - self._suggestions_downloader = DebianSuggestionsDownloader(i18n=self._i18n, logger=self._log, - http_client=self.context.http_client, - file_url=file_url) - - if self._suggestions_downloader.is_local_suggestions_file(): - self._log.info(f"Local Debian suggestions file mapped: {file_url}") - - return self._suggestions_downloader - - def get_installed_source_apps(self) -> Generator[str, None, None]: - for app in self.known_sources_apps: - if shutil.which(app): - yield app diff --git a/bauh/gems/debian/gui.py b/bauh/gems/debian/gui.py deleted file mode 100644 index 8d7af964..00000000 --- a/bauh/gems/debian/gui.py +++ /dev/null @@ -1,142 +0,0 @@ -from operator import attrgetter -from typing import Collection, Optional, Tuple, List - -from bauh.api.abstract.handler import ProcessWatcher -from bauh.api.abstract.view import InputOption, MultipleSelectComponent, TextComponent -from bauh.commons.html import bold -from bauh.commons.view_utils import get_human_size_str -from bauh.gems.debian import DEBIAN_ICON_PATH -from bauh.gems.debian.model import DebianPackage -from bauh.view.util.translation import I18n - - -class DebianViewBridge: - - def __init__(self, screen_width: int, screen_heigth: int, i18n: I18n): - self._i18n = i18n - self._width = screen_width - self._height = screen_heigth - - @staticmethod - def _map_to_install(pkgs: Optional[Collection[DebianPackage]]) -> Optional[Tuple[List[InputOption], str, str]]: - if pkgs: - download_size, install_size = 0, 0 - - views = [] - for p in pkgs: - if p.compressed_size is not None and p.compressed_size >= 0: - compressed = get_human_size_str(p.compressed_size) - download_size += p.compressed_size - - else: - compressed = '?' - - if p.transaction_size is not None: - install_size += p.transaction_size - uncompressed = get_human_size_str(p.transaction_size) - else: - uncompressed = '?' - - views.append(InputOption(label=f"{p.name} ({uncompressed} | {compressed})", - value=p.name, read_only=True, icon_path=DEBIAN_ICON_PATH, - tooltip=p.description if p.description else '?')) - - dsize = get_human_size_str(download_size) if download_size > 0 else '?' - isize = get_human_size_str(install_size) if install_size > 0 else '?' - return views, isize, dsize - - def _map_to_remove(self, pkgs: Optional[Collection[DebianPackage]]) -> Optional[Tuple[List[InputOption], str]]: - if pkgs: - freed_space = 0 - - views = [] - for p in pkgs: - if p.transaction_size is not None: - size = p.transaction_size * (-1 if p.transaction_size < 0 else 1) - freed_space += size - uncompressed = get_human_size_str(size) - else: - uncompressed = '?' - - views.append(InputOption(label=f"{p.name} (-{uncompressed})", - value=p.name, read_only=True, icon_path=DEBIAN_ICON_PATH, - tooltip=p.description if p.description else '?')) - - return views, f'-{get_human_size_str(freed_space)}' if freed_space > 0 else '?' - - def confirm_transaction(self, to_install: Optional[Collection[DebianPackage]], - removal: Optional[Collection[DebianPackage]], - watcher: ProcessWatcher) -> bool: - - components = [] - - to_remove_data = self._map_to_remove(removal) - - text_width, select_width = 672, 595 - - if to_remove_data: - to_remove_data[0].sort(key=attrgetter('label')) - lb_rem = self._i18n['debian.transaction.to_remove'].format(no=bold(str(len(to_remove_data[0]))), - fspace=bold(to_remove_data[1])) - - components.append(TextComponent(html=lb_rem, min_width=text_width)) - components.append(MultipleSelectComponent(id_='rem', options=to_remove_data[0], label=None, - default_options={*to_remove_data[0]}, - max_width=select_width)) - - to_install_data = self._map_to_install(to_install) - - if to_install_data: - to_install_data[0].sort(key=attrgetter('label')) - lb_deps = self._i18n['debian.transaction.to_install'].format(no=bold(str(len(to_install_data[0]))), - dsize=bold(to_install_data[2]), - isize=bold(to_install_data[1])) - - components.append(TextComponent(html=f'
{lb_deps}', min_width=text_width)) - components.append(MultipleSelectComponent(id_='inst', label='', options=to_install_data[0], - default_options={*to_install_data[0]}, - max_width=select_width)) - - return watcher.request_confirmation(title=self._i18n['debian.transaction.title'], - components=components, - confirmation_label=self._i18n['popup.button.continue'], - deny_label=self._i18n['popup.button.cancel'], - body=None, - min_width=text_width, - min_height=54) - - def confirm_removal(self, source_pkg: str, dependencies: Collection[DebianPackage], watcher: ProcessWatcher) -> bool: - dep_views = [] - freed_space = 0 - for p in sorted(dependencies, key=attrgetter('name')): - if p.transaction_size is not None: - size = p.transaction_size * (-1 if p.transaction_size < 0 else 1) - freed_space += size - size_str = get_human_size_str(size) - else: - size_str = '?' - - dep_views.append(InputOption(label=f"{p.name}: -{size_str}", value=p.name, read_only=True, - icon_path=DEBIAN_ICON_PATH, tooltip=p.description)) - - deps_container = MultipleSelectComponent(id_='deps', label='', options=dep_views, default_options={*dep_views}, - max_width=537) - - freed_space_str = bold('-' + get_human_size_str(freed_space)) - body_text = TextComponent(html=self._i18n['debian.remove_deps'].format(no=bold(str(len(dependencies))), - pkg=bold(source_pkg), - fspace=freed_space_str), - min_width=653) - - return watcher.request_confirmation(title=self._i18n['debian.transaction.title'], - components=[body_text, deps_container], - confirmation_label=self._i18n['popup.button.continue'], - deny_label=self._i18n['popup.button.cancel'], - min_height=200, - body=None) - - def confirm_purge(self, pkg_name: str, watcher: ProcessWatcher) -> bool: - msg = self._i18n['debian.action.purge.confirmation'].format(pkg=bold(pkg_name)) - return watcher.request_confirmation(title=self._i18n['debian.action.purge'], - body=msg, - confirmation_label=self._i18n['popup.button.continue']) diff --git a/bauh/gems/debian/index.py b/bauh/gems/debian/index.py deleted file mode 100644 index 75e1d855..00000000 --- a/bauh/gems/debian/index.py +++ /dev/null @@ -1,223 +0,0 @@ -import json -import os -import re -import traceback -from concurrent.futures import ThreadPoolExecutor -from datetime import datetime, timedelta, timezone -from json import JSONDecodeError -from logging import Logger -from pathlib import Path -from typing import Optional, Set, Generator, Iterable - -from bauh.commons import system -from bauh.gems.debian import APP_INDEX_FILE -from bauh.gems.debian.model import DebianApplication - - -class ApplicationIndexError(Exception): - - def __init__(self, cause: Optional[str] = None): - self.cause = cause - - -class ApplicationIndexer: - - def __init__(self, logger: Logger, index_file_path: str = APP_INDEX_FILE): - self._log = logger - self._file_path = index_file_path - self._file_timestamp_path = f'{self._file_path}.ts' - - def is_expired(self, deb_config: dict) -> bool: - - try: - exp_minutes = int(deb_config.get('index_apps.exp', 0)) - except ValueError: - self._log.error(f"Invalid value for Debian configuration property 'index_apps.exp': " - f"{deb_config['index_apps.exp']}") - return True - - if exp_minutes <= 0: - self._log.warning("Debian applications index will always be updated ('index_apps.exp' <= 0 )'") - return True - - if not os.path.exists(self._file_path): - self._log.info(f"Debian applications index not found. A new one must be generated ({self._file_path})") - return True - - try: - with open(self._file_timestamp_path) as f: - timestamp_str = f.read().strip() - except FileNotFoundError: - self._log.info(f"Debian applications index timestamp not found ({self._file_timestamp_path})") - return True - - try: - timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc) - except Exception: - self._log.error(f'Could not parse the Debian applications index timestamp: {timestamp_str} ' - f'({self._file_timestamp_path})') - traceback.print_exc() - return True - - expired = timestamp + timedelta(minutes=exp_minutes) <= datetime.now(timezone.utc) - - if expired: - self._log.info("Debian applications index has expired. A new one must be generated.") - else: - self._log.info("Debian applications index is up-to-date") - - return expired - - def read_index(self) -> Generator[DebianApplication, None, None]: - try: - with open(self._file_path) as f: - idx_str = f.read().strip() - - if not idx_str: - self._log.warning(f"Debian applications index is empty ({self._file_path})") - else: - try: - for name, data in json.loads(idx_str).items(): - exe_path, icon_path = data.get('exe_path'), data.get('icon_path') - - if not all((name, exe_path, icon_path)): - self._log.warning(f"Invalid entry in the Debian applications index ({self._file_path}): name={name}, exe_path={exe_path}, icon_path={icon_path}") - else: - categories = data.get('categories') - yield DebianApplication(name=name, exe_path=exe_path, icon_path=icon_path, - categories=tuple(categories) if categories else None) - - except JSONDecodeError: - self._log.error(f"The Debian applications index is corrupted ({self._file_path}). " - f"Could not decode the JSON.") - - except FileNotFoundError: - self._log.warning(f"Debian applications index not found ({self._file_path})") - except OSError as e: - self._log.error(f"Debian applications index could not be read ({self._file_path}). OSError: {e.errno}") - - def update_index(self, apps: Set[DebianApplication], update_timestamp: bool = True): - idx_dir = os.path.dirname(self._file_path) - - try: - Path(idx_dir).mkdir(exist_ok=True, parents=True) - except OSError: - self._log.error(f"Could not create directory '{idx_dir}'") - raise ApplicationIndexError() - - idx = {} - if apps: - for app in apps: - idx.update(app.to_index()) - - try: - with open(self._file_path, 'w+') as f: - if idx: - f.write(json.dumps(idx, sort_keys=True, indent=4)) - else: - f.write('') - - except OSError: - self._log.error(f"Could not write to the Debian applications index file: {self._file_path}") - raise ApplicationIndexError() - - if update_timestamp: - index_timestamp = datetime.now(timezone.utc).timestamp() - try: - with open(self._file_timestamp_path, 'w+') as f: - f.write(str(index_timestamp)) - - self._log.info("Debian applications index timestamp updated") - - except OSError: - self._log.error(f"Could not write to the Debian applications index timestamp file: " - f"{self._file_timestamp_path}") - raise ApplicationIndexError() - - -class ApplicationsMapper: - - def __init__(self, logger: Logger, workers: int = 10): - self._log = logger - self._re_desktop_file = re.compile(r'(.+):\s+(/usr/share/applications/.+\.desktop)') - self._re_desktop_file_fields = re.compile(r'(Exec|TryExec|Icon|Categories|NoDisplay|Terminal)\s*=\s*(.+)') - self._workers = workers - - def _read_file(self, file_path: str) -> Optional[str]: - try: - with open(file_path) as file: - return file.read() - except (FileNotFoundError, OSError) as e: - self._log.error(f"Error when checking desktop file '{file_path}' ({file_path}):" - f" {e.__class__.__name__}") - - def _add_if_application_desktop_file(self, pkg_name: str, desktop_files: Iterable[str], output: Set[DebianApplication]): - for file_path in sorted(desktop_files): - content = self._read_file(file_path) - - if content: - data = {} - - gui_app = True - - for f, v in self._re_desktop_file_fields.findall(content): - if f in ('NoDisplay', 'Terminal') and v.strip().lower() == 'true': - gui_app = False - break - - if f not in data: - data[f.strip()] = v.strip() - - if not gui_app: - continue - - exe = data.get('Exec') - - if not exe: - exe = data.get('TryExec') - - if not exe: - continue - - icon = data.get('Icon') - - if not icon: - continue - - categories = data.get('Categories') - - if categories: - categories = tuple(sorted({c.strip() for c in categories.split(';') if c})) - - output.add(DebianApplication(name=pkg_name, exe_path=exe, icon_path=icon, categories=categories)) - break - - def map_executable_applications(self) -> Optional[Set[DebianApplication]]: - exitcode, output = system.execute('dpkg-query -S .desktop', shell=True) - - if exitcode == 0 and output: - - pkg_files = dict() - - for found in self._re_desktop_file.findall(output): - pkg_name = found[0].strip() - files = pkg_files.get(pkg_name) - - if files is None: - files = set() - pkg_files[pkg_name] = files - - files.add(found[1].strip()) - - if pkg_files: - apps_found, check_jobs = set(), [] - - with ThreadPoolExecutor(self._workers) as pool: - for pkg_name, files in pkg_files.items(): - check_jobs.append(pool.submit(self._add_if_application_desktop_file, - pkg_name, files, apps_found)) - - for job in check_jobs: - job.done() - - return apps_found diff --git a/bauh/gems/debian/model.py b/bauh/gems/debian/model.py deleted file mode 100644 index e506a373..00000000 --- a/bauh/gems/debian/model.py +++ /dev/null @@ -1,172 +0,0 @@ -from typing import Optional, Tuple, Collection, Iterable, Generator - -from bauh.api.abstract.model import SoftwarePackage, CustomSoftwareAction -from bauh.commons import resource -from bauh.gems.debian import DEBIAN_ICON_PATH, ROOT_DIR - - -class DebianApplication: - """ - For packages that represent applications - """ - - def __init__(self, name: str, exe_path: str, icon_path: str, categories: Optional[Tuple] = None): - self.name = name - self.exe_path = exe_path - self.icon_path = icon_path - self.categories = categories - - def __eq__(self, other): - if isinstance(other, DebianApplication): - return self.__dict__ == other.__dict__ - - return False - - def __hash__(self) -> int: - hash_sum = 0 - - for k, v in self.__dict__.items(): - hash_sum += hash(v) - - return hash_sum - - def __repr__(self): - return f"{self.__class__.__name__} ({', '.join((f'{k}={v}' for k, v in self.__dict__.items()))})" - - def to_index(self) -> dict: - return {self.name: {f: v for f, v in self.__dict__.items() if f != 'name'}} - - -class DebianPackage(SoftwarePackage): - - __actions_purge: Optional[Tuple[CustomSoftwareAction, ...]] = None - - @classmethod - def actions_purge(cls) -> Tuple[CustomSoftwareAction, ...]: - if cls.__actions_purge is None: - cls.__actions_purge = (CustomSoftwareAction(i18n_label_key='debian.action.purge', - i18n_status_key='debian.action.purge.status', - i18n_description_key='debian.action.purge.desc', - icon_path=resource.get_path('img/clean.svg', ROOT_DIR), - manager_method='purge', - requires_root=True, - requires_confirmation=False),) - - return cls.__actions_purge - - def __init__(self, name: str = None, version: Optional[str] = None, latest_version: Optional[str] = None, - description: Optional[str] = None, maintainer: Optional[str] = None, installed: bool = False, - update: bool = False, app: Optional[DebianApplication] = None, compressed_size: Optional[int] = None, - uncompressed_size: Optional[int] = None, categories: Tuple[str] = None, - updates_ignored: Optional[bool] = None, transaction_size: Optional[float] = None, - global_purge: bool = False): - super(DebianPackage, self).__init__(id=name, name=name, version=version, installed=installed, - description=description, update=update, - latest_version=latest_version if latest_version is not None else version) - self.maintainer = maintainer - self.compressed_size = compressed_size - self.uncompressed_size = uncompressed_size - self.categories = categories - self.app = app - self.bind_app(app) - self.updates_ignored = updates_ignored - self.transaction_size = transaction_size # size in bytes related to a transaction (install, upgrade, remove) - self.global_purge = global_purge # if global purge is already enabled - - def bind_app(self, app: Optional[DebianApplication]): - self.app = app - - if app and app.categories: - self.categories = app.categories - - def has_history(self) -> bool: - return False - - def has_screenshots(self) -> bool: - return False - - def has_info(self) -> bool: - return True - - def can_be_downgraded(self) -> bool: - return False - - def get_type(self): - return 'debian' - - def get_default_icon_path(self) -> str: - return self.get_type_icon_path() - - def get_type_icon_path(self) -> str: - return DEBIAN_ICON_PATH - - def is_application(self): - return bool(self.app) - - def get_data_to_cache(self) -> dict: - pass - - def fill_cached_data(self, data: dict): - pass - - def can_be_run(self) -> bool: - return bool(self.app) - - def get_publisher(self) -> str: - return self.maintainer - - def supports_backup(self) -> bool: - return True - - def get_disk_icon_path(self) -> Optional[str]: - if self.app: - return self.app.icon_path - - def get_custom_actions(self) -> Optional[Iterable[CustomSoftwareAction]]: - if self.installed and not self.global_purge: - return self.actions_purge() - - def is_update_ignored(self) -> bool: - return bool(self.updates_ignored) - - def supports_ignored_updates(self) -> bool: - return True - - def is_trustable(self) -> bool: - return True - - def __eq__(self, other): - if isinstance(other, DebianPackage): - return self.name == other.name - - return False - - def __hash__(self): - return hash(self.name) - - def __repr__(self) -> str: - attrs = ', '.join((f'{p}={v}' for p, v in sorted(self.__dict__.items()))) - return f"{self.__class__.__name__} ({attrs})" - - -class DebianTransaction: - - def __init__(self, to_install: Optional[Collection[DebianPackage]], - to_remove: Optional[Collection[DebianPackage]], - to_upgrade: Optional[Collection[DebianPackage]]): - - self.to_install = to_install - self.to_remove = to_remove - self.to_upgrade = to_upgrade - - @property - def all_packages(self) -> Generator[DebianPackage, None, None]: - for pkgs in (self.to_install, self.to_remove, self.to_upgrade): - if pkgs: - yield from pkgs - - def __eq__(self, other) -> bool: - return self.__dict__ == other.__dict__ if isinstance(other, DebianTransaction) else False - - def __hash__(self) -> int: - return sum((hash(v)for v in self.__dict__.values())) diff --git a/bauh/gems/debian/resources/__init__.py b/bauh/gems/debian/resources/__init__.py deleted file mode 100755 index e69de29b..00000000 diff --git a/bauh/gems/debian/resources/img/__init__.py b/bauh/gems/debian/resources/img/__init__.py deleted file mode 100755 index e69de29b..00000000 diff --git a/bauh/gems/debian/resources/img/clean.svg b/bauh/gems/debian/resources/img/clean.svg deleted file mode 100644 index fba112a9..00000000 --- a/bauh/gems/debian/resources/img/clean.svg +++ /dev/null @@ -1,158 +0,0 @@ - -image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bauh/gems/debian/resources/img/debian.svg b/bauh/gems/debian/resources/img/debian.svg deleted file mode 100644 index c112ee02..00000000 --- a/bauh/gems/debian/resources/img/debian.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/__init__.py b/bauh/gems/debian/resources/locale/__init__.py deleted file mode 100755 index e69de29b..00000000 diff --git a/bauh/gems/debian/resources/locale/ca b/bauh/gems/debian/resources/locale/ca deleted file mode 100644 index efbe7fc8..00000000 --- a/bauh/gems/debian/resources/locale/ca +++ /dev/null @@ -1,87 +0,0 @@ -debian.action.index_apps=Index applications -debian.action.index_apps.desc=Identifies all installed packages associated with .desktop files and maps them as applications -debian.action.purge=Remove completely -debian.action.purge.confirmation=The complete removal of {pkg} will erase the software files and also the configuration ones -debian.action.purge.desc=Removes all software and configuration files associated with the package -debian.action.purge.status=Removing {} completely -debian.action.sync_pkgs=Synchronize packages -debian.action.sync_pkgs.desc=Synchronizes the available software packages on the repositories -debian.action.sync_pkgs.status=Synchronizing packages -debian.action.sources=Software sources -debian.action.sources.desc=Starts the application for managing software sources -debian.action.sources.not_installed=The application for managing software sources is not installed -debian.action.sources.status=Launching application -debian.action.sources.unsupported=The application {app} is not supported and will not be started -debian.app_index.checking=Checking the apps index -debian.app_index.updating=Updating the apps index -debian.config.index_apps.exp=Apps cache expiration -debian.config.index_apps.exp.tip=Time period in MINUTES in which the installed applications cache is considered up-to-date during startup -debian.config.pkg_sources.app=Software sources -debian.config.pkg_sources.app.tip=Application for managing the software sources. {auto} detects one of the supported applications automatically. -debian.config.pkg_sources.app.auto=Auto -debian.config.remove.purge=Complete removal -debian.config.remove.purge.tip=If the package configurations should be removed during the uninstallation process -debian.config.suggestions.exp=Suggestions expiration -debian.config.suggestions.exp.tip=It defines the period (in hours) in which the suggestions stored in disc will be considered up to date. Use 0 if you always want to update them. -debian.config.sync_pkgs.time=Packages synchronization period -debian.config.sync_pkgs.time.tip=Time period in MINUTES in which the packages synchronization must be done on startup -debian.info.00.name=name -debian.info.01.version=version -debian.info.02.description=description -debian.info.03.exec=executable -debian.info.04.architecture=architecture -debian.info.04.architecture.all=all -debian.info.04.archive=archive -debian.info.04.automatically installed=automatically installed -debian.info.04.automatically installed.no=no -debian.info.04.automatically installed.yes=yes -debian.info.04.breaks=breaks -debian.info.04.compressed size=Download size -debian.info.04.conflicts=conflicts -debian.info.04.depends=dependencies -debian.info.04.filename=file -debian.info.04.homepage=web page -debian.info.04.maintainer=maintainer -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=multi-architecture -debian.info.04.multi-arch.foreign=foreign -debian.info.04.multi-arch.same=same -debian.info.04.replaces=replaces -debian.info.04.predepends=pre dependencies -debian.info.04.priority=priority -debian.info.04.priority.important=important -debian.info.04.priority.optional=optional -debian.info.04.provided by=provided by -debian.info.04.provides=provides -debian.info.04.recommends=recommends -debian.info.04.section=section -debian.info.04.state=state -debian.info.04.state.installed=installed -debian.info.04.state.not installed=not installed -debian.info.04.state.not installed (configuration files remain)=not installed (configuration files installed) -debian.info.04.suggests=suggests -debian.info.04.uncompressed size=installation size -debian.install.validating=Validating installed packages -debian.installing_pkgs=Installing packages -debian.output.downloading=Downloading {pkg} -debian.output.removing=Removing {pkg} -debian.output.finishing=Finishing -debian.output.unpacking=Unpacking {pkg} -debian.remove.impossible=It is not possible to remove the package {pkg} -debian.remove_deps=The following {no} dependent packages of {pkg} will be removed as well ({fspace}) -debian.simulate_operation=Simulating the operation -debian.task.app_index.status=Indexing installed applications -debian.task.map_apps.check_files=Checking {type} files -debian.task.map_apps.read_cache=Reading apps from the index (cache) -debian.task.map_apps.status=Mapping installed applications -debian.task.update_apps_idx.status=Updating index -debian.task.sync_pkgs.status=Synchronizing packages -debian.transaction.dependency_of=Dependency of {pkgs} -debian.transaction.get_data=Retrieving the operation's data -debian.transaction.title=Operation details -debian.transaction.to_install=The following additional packages ({no}) will be installed (Installation: {isize} | Download: {dsize}) -debian.transaction.to_remove=The following packages ({no}) will be removed (Freed space: {fspace}) -debian.uninstall.failed_to_remove=It was not possible to remove the following {no} packages: {pkgs} -debian.uninstall.removing=Removing packages -debian.uninstall.validating=Validating removed packages -gem.debian.info=Software packages for Debian-based systems \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/de b/bauh/gems/debian/resources/locale/de deleted file mode 100644 index 498f71cc..00000000 --- a/bauh/gems/debian/resources/locale/de +++ /dev/null @@ -1,87 +0,0 @@ -debian.action.index_apps=Anwendungen indexieren -debian.action.index_apps.desc=Identifiziert alle installierten Pakete, die mit .desktop-Dateien verbunden sind, und ordnet sie als Anwendungen zu -debian.action.purge=Vollständig entfernen -debian.action.purge.confirmation=Das vollständige Entfernen von {pkg} löscht sowohl die Software- als auch die Konfigurationsdateien -debian.action.purge.desc=Entfernt alle Software- und Konfigurationsdateien, die mit dem Paket zusammenhängen -debian.action.purge.status=Vollständiges Entfernen von {} -debian.action.sync_pkgs=Pakete synchronisieren -debian.action.sync_pkgs.desc=Synchronisiert die verfügbaren Softwarepakete mit den Repositories -debian.action.sync_pkgs.status=Synchronisierung der Pakete -debian.action.sources=Software-Quellen -debian.action.sources.desc=Startet die Anwendung zur Verwaltung von Softwarequellen -debian.action.sources.not_installed=Die Anwendung zur Verwaltung von Softwarequellen ist nicht installiert -debian.action.sources.status=Starten der Anwendung -debian.action.sources.unsupported=Die Anwendung {app} wird nicht unterstützt und kann nicht gestartet werden -debian.app_index.checking=Überprüfen des Apps-Index -debian.app_index.updating=Aktualisieren des Apps-Index -debian.config.index_apps.exp=Ablauf des Apps-Caches -debian.config.index_apps.exp.tip=Zeitspanne in MINUTEN, in der der Cache der installierten Anwendungen beim Starten als aktuell angesehen wird -debian.config.pkg_sources.app=Softwarequellen -debian.config.pkg_sources.app.tip=Anwendung zur Verwaltung der Softwarequellen. {auto} erkennt eine der unterstützten Anwendungen automatisch. -debian.config.pkg_sources.app.auto=Auto -debian.config.remove.purge=Vollständige Entfernung -debian.config.remove.purge.tip=Ob die Paketkonfigurationen während des Deinstallationsvorgangs entfernt werden sollen -debian.config.suggestions.exp=Ablauf der Vorschläge -debian.config.suggestions.exp.tip=Er definiert den Zeitraum (in Stunden), in dem die, auf dem Datenträger gespeicherten, Vorschläge als aktuell angesehen werden. Verwenden Sie 0, wenn Sie sie immer aktualisieren wollen. -debian.config.sync_pkgs.time=Zeitraum für die Synchronisierung der Pakete -debian.config.sync_pkgs.time.tip=Zeitspanne in MINUTEN, in der die Pakete beim Start synchronisiert werden müssen -debian.info.00.name=Name -debian.info.01.version=Version -debian.info.02.description=Beschreibung -debian.info.03.exec=ausführbar -debian.info.04.architecture=Architektur -debian.info.04.architecture.all=alle -debian.info.04.archive=Archiv -debian.info.04.automatically installed=automatisch installiert -debian.info.04.automatically installed.no=nein -debian.info.04.automatically installed.yes=ja -debian.info.04.breaks=bricht -debian.info.04.compressed size=Download-Größe -debian.info.04.conflicts=Konflikte -debian.info.04.depends=Abhängigkeiten -debian.info.04.filename=Datei -debian.info.04.homepage=Internetseite -debian.info.04.maintainer=Verwalter -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=Multi-Architektur -debian.info.04.multi-arch.foreign=fremd -debian.info.04.multi-arch.same=gleich -debian.info.04.replaces=ersetzt -debian.info.04.predepends=Vorabhängigkeiten -debian.info.04.priority=Priorität -debian.info.04.priority.important=wichtig -debian.info.04.priority.optional=optional -debian.info.04.provided by=bereitgestellt von -debian.info.04.provides=bietet -debian.info.04.recommends=empfiehlt -debian.info.04.section=Abschnitt -debian.info.04.state=Status -debian.info.04.state.installed=installiert -debian.info.04.state.not installed=nicht installiert -debian.info.04.state.not installed (configuration files remain)=nicht installiert (Konfigurationsdateien installiert) -debian.info.04.suggests=empfiehlt -debian.info.04.uncompressed size=Installationsgröße -debian.install.validating=Überprüfung der installierten Pakete -debian.installing_pkgs=Installieren von Paketen -debian.output.downloading=Herunterladen von {pkg} -debian.output.finishing=Fertigstellung -debian.output.removing=Entfernen von {pkg} -debian.output.unpacking=Entpacken {pkg} -debian.remove.impossible=Es ist nicht möglich, das Paket {pkg} zu entfernen -debian.remove_deps=Die folgenden {no} abhängigen Pakete von {pkg} werden ebenfalls entfernt ({fspace}) -debian.simulate_operation=Simulation des Vorgangs -debian.task.app_index.status=Indexierung der installierten Anwendungen -debian.task.map_apps.check_files=Überprüfung von {type} Dateien -debian.task.map_apps.read_cache=Lesen von Anwendungen aus dem Index (Cache) -debian.task.map_apps.status=Zuordnung der installierten Anwendungen -debian.task.update_apps_idx.status=Aktualisieren des Index -debian.task.sync_pkgs.status=Synchronisierung der Pakete -debian.transaction.dependency_of=Abhängigkeit von {pkgs} -debian.transaction.get_data=Abrufen der Daten des Vorgangs -debian.transaction.title=Details zum Vorgang -debian.transaction.to_install=Die folgenden zusätzlichen Pakete ({no}) werden installiert (Installation: {isize} | Download: {dsize}) -debian.transaction.to_remove=Die folgenden Pakete ({no}) werden entfernt (Freigegebener Speicherplatz: {fspace}) -debian.uninstall.failed_to_remove=Es war nicht möglich, die folgenden Pakete ({no}) zu entfernen: {pkgs} -debian.uninstall.removing=Entfernen von Paketen -debian.uninstall.validating=Validierung entfernter Pakete -gem.debian.info=Softwarepakete für Debian-basierte Systeme \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/en b/bauh/gems/debian/resources/locale/en deleted file mode 100644 index 401e485a..00000000 --- a/bauh/gems/debian/resources/locale/en +++ /dev/null @@ -1,87 +0,0 @@ -debian.action.index_apps=Index applications -debian.action.index_apps.desc=Identifies all installed packages associated with .desktop files and maps them as applications -debian.action.purge=Remove completely -debian.action.purge.confirmation=The complete removal of {pkg} will erase the software files and also the configuration ones -debian.action.purge.desc=Removes all software and configuration files associated with the package -debian.action.purge.status=Removing {} completelydebian.config.pkg_sources.app.auto= -debian.action.sync_pkgs=Synchronize packages -debian.action.sync_pkgs.desc=Synchronizes the available software packages on the repositories -debian.action.sync_pkgs.status=Synchronizing packages -debian.action.sources=Software sources -debian.action.sources.desc=Starts the application for managing software sources -debian.action.sources.not_installed=The application for managing software sources is not installed -debian.action.sources.status=Launching application -debian.action.sources.unsupported=The application {app} is not supported and will not be started -debian.app_index.checking=Checking the apps index -debian.app_index.updating=Updating the apps index -debian.config.index_apps.exp=Apps cache expiration -debian.config.index_apps.exp.tip=Time period in MINUTES in which the installed applications cache is considered up-to-date during startup -debian.config.pkg_sources.app=Software sources -debian.config.pkg_sources.app.tip=Application for managing the software sources. {auto} detects one of the supported applications automatically. -debian.config.pkg_sources.app.auto=Auto -debian.config.remove.purge=Complete removal -debian.config.remove.purge.tip=If the package configurations should be removed during the uninstallation process -debian.config.suggestions.exp=Suggestions expiration -debian.config.suggestions.exp.tip=It defines the period (in hours) in which the suggestions stored in disc will be considered up to date. Use 0 if you always want to update them. -debian.config.sync_pkgs.time=Packages synchronization period -debian.config.sync_pkgs.time.tip=Time period in MINUTES in which the packages synchronization must be done on startup -debian.info.00.name=name -debian.info.01.version=version -debian.info.02.description=description -debian.info.03.exec=executable -debian.info.04.architecture=architecture -debian.info.04.architecture.all=all -debian.info.04.archive=archive -debian.info.04.automatically installed=automatically installed -debian.info.04.automatically installed.no=no -debian.info.04.automatically installed.yes=yes -debian.info.04.breaks=breaks -debian.info.04.compressed size=Download size -debian.info.04.conflicts=conflicts -debian.info.04.depends=dependencies -debian.info.04.filename=file -debian.info.04.homepage=web page -debian.info.04.maintainer=maintainer -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=multi-architecture -debian.info.04.multi-arch.foreign=foreign -debian.info.04.multi-arch.same=same -debian.info.04.replaces=replaces -debian.info.04.predepends=pre dependencies -debian.info.04.priority=priority -debian.info.04.priority.important=important -debian.info.04.priority.optional=optional -debian.info.04.provided by=provided by -debian.info.04.provides=provides -debian.info.04.recommends=recommends -debian.info.04.section=section -debian.info.04.state=state -debian.info.04.state.installed=installed -debian.info.04.state.not installed=not installed -debian.info.04.state.not installed (configuration files remain)=not installed (configuration files installed) -debian.info.04.suggests=suggests -debian.info.04.uncompressed size=installation size -debian.install.validating=Validating installed packages -debian.installing_pkgs=Installing packages -debian.output.downloading=Downloading {pkg} -debian.output.finishing=Finishing -debian.output.removing=Removing {pkg} -debian.output.unpacking=Unpacking {pkg} -debian.remove.impossible=It is not possible to remove the package {pkg} -debian.remove_deps=The following {no} dependent packages of {pkg} will be removed as well ({fspace}) -debian.simulate_operation=Simulating the operation -debian.task.app_index.status=Indexing installed applications -debian.task.map_apps.check_files=Checking {type} files -debian.task.map_apps.read_cache=Reading apps from the index (cache) -debian.task.map_apps.status=Mapping installed applications -debian.task.update_apps_idx.status=Updating index -debian.task.sync_pkgs.status=Synchronizing packages -debian.transaction.dependency_of=Dependency of {pkgs} -debian.transaction.get_data=Retrieving the operation's data -debian.transaction.title=Operation details -debian.transaction.to_install=The following additional packages ({no}) will be installed (Installation: {isize} | Download: {dsize}) -debian.transaction.to_remove=The following packages ({no}) will be removed (Freed space: {fspace}) -debian.uninstall.failed_to_remove=It was not possible to remove the following {no} packages: {pkgs} -debian.uninstall.removing=Removing packages -debian.uninstall.validating=Validating removed packages -gem.debian.info=Software packages for Debian-based systems \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/es b/bauh/gems/debian/resources/locale/es deleted file mode 100644 index 0bfde98a..00000000 --- a/bauh/gems/debian/resources/locale/es +++ /dev/null @@ -1,87 +0,0 @@ -debian.action.index_apps=Indexar aplicaciones -debian.action.index_apps.desc=Identifica todos los paquetes instalados asociados con archivos .desktop y los mapea como aplicaciones -debian.action.purge=Eliminar completamente -debian.action.purge.confirmation=La eliminación completa de {pkg} borrará los archivos de software y también los de configuración -debian.action.purge.desc=Elimina los archivos de software y configuración asociados al paquete -debian.action.purge.status=Eliminando {} completamente -debian.action.sync_pkgs=Sincronizar paquetes -debian.action.sync_pkgs.desc=Sincroniza los paquetes de software disponibles en los repositorios -debian.action.sync_pkgs.status=Sincronizando paquetes -debian.action.sources=Fuentes de software -debian.action.sources.desc=Inicia la aplicación para administrar fuentes de software -debian.action.sources.not_installed=La aplicación para administrar fuentes de software no está instalada -debian.action.sources.status=Iniciando la aplicación -debian.action.sources.unsupported=La aplicación {app} no es compatible y no se iniciará -debian.app_index.checking=Verificando el índice de applicationes -debian.app_index.updating=Actualizando el índice de aplicaciones -debian.config.index_apps.exp=Caducidad de caché de aplicaciones -debian.config.index_apps.exp.tip=Periodo de tiempo en MINUTOS en que el cache de las aplicaciones instaladas es considerado actualizado durante la inicialización -debian.config.pkg_sources.app=Fuentes de software -debian.config.pkg_sources.app.tip=Aplicación para administrar las fuentes de software. {auto} detecta una de las aplicaciones compatibles automáticamente. -debian.config.pkg_sources.app.auto=Auto -debian.config.remove.purge=Eliminación completa -debian.config.remove.purge.tip=Si las configuraciones del paquete deben ser eliminadas durante el proceso de desinstalación -debian.config.suggestions.exp=Expiración de sugerencias -debian.config.suggestions.exp.tip=Define el período (en horas) en el que la sugerencias almacenadas en disco seran consideradas actualizadas. Use 0 si desea siempre actualizarlas. -debian.config.sync_pkgs.time=Período de sincronización de paquetes -debian.config.sync_pkgs.time.tip=Período de tiempo en MINUTOS en que se debe realizar la sincronización de paquetes durante la inicialización -debian.info.00.name=nombre -debian.info.01.version=versión -debian.info.02.description=descripción -debian.info.03.exec=ejecutable -debian.info.04.architecture=arquitectura -debian.info.04.architecture.all=todas -debian.info.04.archive=archivamiento -debian.info.04.automatically installed=instalado automáticamente -debian.info.04.automatically installed.no=no -debian.info.04.automatically installed.yes=si -debian.info.04.breaks=roturas -debian.info.04.compressed size=Tamaño de descarga -debian.info.04.conflicts=conflictos -debian.info.04.depends=dependencias -debian.info.04.filename=archivo -debian.info.04.homepage=página web -debian.info.04.maintainer=mantenedor -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=multi-arquitectura -debian.info.04.multi-arch.foreign=diferente -debian.info.04.multi-arch.same=misma -debian.info.04.replaces=reemplaza -debian.info.04.predepends=pre dependencias -debian.info.04.priority=prioridad -debian.info.04.priority.important=importante -debian.info.04.priority.opcional=opcional -debian.info.04.provided by=proporcionado por -debian.info.04.provides=proporciona -debian.info.04.recommends=recomienda -debian.info.04.section=sección -debian.info.04.state=estado -debian.info.04.state.installed=instalado -debian.info.04.state.not installed=no instalado -debian.info.04.state.not installed (configuration files remain)=no instalado (archivos de configuración instalados) -debian.info.04.suggests=sugiere -debian.info.04.uncompressed size=tamaño de instalación -debian.install.validating=Validando paquetes instalados -debian.installing_pkgs=Instalando paquetes -debian.output.downloading=Descargando {pkg} -debian.output.finishing=Finalizando -debian.output.removing=Eliminando {pkg} -debian.output.unpacking=Desempacando {pkg} -debian.remove.impossible=No es posible eliminar el paquete {pkg} -debian.remove_deps=Los siguientes {no} paquetes dependientes de {pkg} serán eliminados también ({fspace}) -debian.simulate_operation=Simulando la operación -debian.task.app_index.status=Indexando aplicaciones instaladas -debian.task.map_apps.check_files=Comprobando archivos {type} -debian.task.map_apps.read_cache=Leyendo aplicaciones del índice (cache) -debian.task.map_apps.status=Mapeando las aplicaciones instaladas -debian.task.update_apps_idx.status=Actualizando índice -debian.task.sync_pkgs.status=Sincronizando paquetes -debian.transaction.dependency_of=Dependencia de {pkgs} -debian.transaction.get_data=Recuperando datos de la operación -debian.transaction.title=Detalles de la operación -debian.transaction.to_install=Los siguientes paquetes adicionales ({no}) serán instalados (Instalación: {isize} | Descarga: {dsize}) -debian.transaction.to_remove=Los siguientes paquetes ({no}) serán eliminados (Espacio liberado: {fspace}) -debian.uninstall.failed_to_remove=No fue posible eliminar los siguientes {no} paquetes: {pkgs} -debian.uninstall.removing=Removendo paquetes -debian.uninstall.validating=Validando paquetes eliminados -gem.debian.info=Paquetes de software para sistemas basados en Debian \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/fr b/bauh/gems/debian/resources/locale/fr deleted file mode 100644 index bfcf4b83..00000000 --- a/bauh/gems/debian/resources/locale/fr +++ /dev/null @@ -1,86 +0,0 @@ -debian.action.index_apps=Index applications -debian.action.index_apps.desc=Identifies all installed packages associated with .desktop files and maps them as applications -debian.action.purge=Remove completely -debian.action.purge.confirmation=The complete removal of {pkg} will erase the software files and also the configuration ones -debian.action.purge.desc=Removes all software and configuration files associated with the package -debian.action.purge.status=Removing {} completely -debian.action.sync_pkgs=Synchronize packages -debian.action.sync_pkgs.desc=Synchronizes the available software packages on the repositories -debian.action.sync_pkgs.status=Synchronizing packages -debian.action.sources=Software sources -debian.action.sources.desc=Starts the application for managing software sources -debian.action.sources.not_installed=The application for managing software sources is not installed -debian.action.sources.status=Launching application -debian.action.sources.unsupported=The application {app} is not supported and will not be started -debian.app_index.checking=Checking the apps index -debian.app_index.updating=Updating the apps index -debian.config.index_apps.exp=Apps cache expiration -debian.config.index_apps.exp.tip=Time period in MINUTES in which the installed applications cache is considered up-to-date during startup -debian.config.pkg_sources.app=Software sources -debian.config.pkg_sources.app.tip=Application for managing the software sources. {auto} detects one of the supported applications automatically. -debian.config.pkg_sources.app.auto=Auto -debian.config.remove.purge=Complete removal -debian.config.remove.purge.tip=If the package configurations should be removed during the uninstallation process -debian.config.suggestions.exp=Suggestions expiration -debian.config.suggestions.exp.tip=It defines the period (in hours) in which the suggestions stored in disc will be considered up to date. Use 0 if you always want to update them. -debian.config.sync_pkgs.time=Packages synchronization period -debian.config.sync_pkgs.time.tip=Time period in MINUTES in which the packages synchronization must be done on startup -debian.info.00.name=name -debian.info.01.version=version -debian.info.02.description=description -debian.info.03.exec=executable -debian.info.04.architecture=architecture -debian.info.04.architecture.all=all -debian.info.04.archive=archive -debian.info.04.automatically installed=automatically installed -debian.info.04.automatically installed.no=no -debian.info.04.automatically installed.yes=yes -debian.info.04.breaks=breaks -debian.info.04.compressed size=Download size -debian.info.04.conflicts=conflicts -debian.info.04.depends=dependencies -debian.info.04.filename=file -debian.info.04.homepage=web page -debian.info.04.maintainer=maintainer -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=multi-architecture -debian.info.04.multi-arch.foreign=foreign -debian.info.04.multi-arch.same=same -debian.info.04.replaces=replaces -debian.info.04.predepends=pre dependencies -debian.info.04.priority=priority -debian.info.04.priority.important=important -debian.info.04.priority.optional=optional -debian.info.04.provided by=provided by -debian.info.04.provides=provides -debian.info.04.recommends=recommends -debian.info.04.section=section -debian.info.04.state=state -debian.info.04.state.installed=installed -debian.info.04.state.not installed=not installed -debian.info.04.state.not installed (configuration files remain)=not installed (configuration files installed) -debian.info.04.suggests=suggests -debian.info.04.uncompressed size=installation size -debian.install.validating=Validating installed packages -debian.output.downloading=Downloading {pkg} -debian.output.finishing=Finishing -debian.output.removing=Removing {pkg} -debian.output.unpacking=Unpacking {pkg} -debian.remove.impossible=It is not possible to remove the package {pkg} -debian.remove_deps=The following {no} dependent packages of {pkg} will be removed as well ({fspace}) -debian.simulate_operation=Simulating the operation -debian.task.app_index.status=Indexing installed applications -debian.task.map_apps.check_files=Checking {type} files -debian.task.map_apps.read_cache=Reading apps from the index (cache) -debian.task.map_apps.status=Mapping installed applications -debian.task.update_apps_idx.status=Updating index -debian.task.sync_pkgs.status=Synchronizing packages -debian.transaction.dependency_of=Dependency of {pkgs} -debian.transaction.get_data=Retrieving the operation's data -debian.transaction.title=Operation details -debian.transaction.to_install=The following additional packages ({no}) will be installed (Installation: {isize} | Download: {dsize}) -debian.transaction.to_remove=The following packages ({no}) will be removed (Freed space: {fspace}) -debian.uninstall.failed_to_remove=It was not possible to remove the following {no} packages: {pkgs} -debian.uninstall.removing=Removing packages -debian.uninstall.validating=Validating removed packages -gem.debian.info=Software packages for Debian-based systems \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/it b/bauh/gems/debian/resources/locale/it deleted file mode 100644 index 1adcd6f7..00000000 --- a/bauh/gems/debian/resources/locale/it +++ /dev/null @@ -1,87 +0,0 @@ -debian.action.index_apps=Index applications -debian.action.index_apps.desc=Identifies all installed packages associated with .desktop files and maps them as applications -debian.action.purge=Remove completely -debian.action.purge.confirmation=The complete removal of {pkg} will erase the software files and also the configuration ones -debian.action.purge.desc=Removes all software and configuration files associated with the package -debian.action.purge.status=Removing {} completely -debian.action.sync_pkgs=Synchronize packages -debian.action.sync_pkgs.desc=Synchronizes the available software packages on the repositories -debian.action.sync_pkgs.status=Synchronizing packages -debian.action.sources=Software sources -debian.action.sources.desc=Starts the application for managing software sources -debian.action.sources.not_installed=The application for managing software sources is not installed -debian.action.sources.status=Launching application -debian.action.sources.unsupported=The application {app} is not supported and will not be started -debian.app_index.checking=Checking the apps index -debian.app_index.updating=Updating the apps index -debian.config.index_apps.exp=Apps cache expiration -debian.config.index_apps.exp.tip=Time period in MINUTES in which the installed applications cache is considered up-to-date during startup -debian.config.pkg_sources.app=Software sources -debian.config.pkg_sources.app.tip=Application for managing the software sources. {auto} detects one of the supported applications automatically. -debian.config.pkg_sources.app.auto=Auto -debian.config.remove.purge=Complete removal -debian.config.remove.purge.tip=If the package configurations should be removed during the uninstallation process -debian.config.suggestions.exp=Suggestions expiration -debian.config.suggestions.exp.tip=It defines the period (in hours) in which the suggestions stored in disc will be considered up to date. Use 0 if you always want to update them. -debian.config.sync_pkgs.time=Packages synchronization period -debian.config.sync_pkgs.time.tip=Time period in MINUTES in which the packages synchronization must be done on startup -debian.info.00.name=name -debian.info.01.version=version -debian.info.02.description=description -debian.info.03.exec=executable -debian.info.04.architecture=architecture -debian.info.04.architecture.all=all -debian.info.04.archive=archive -debian.info.04.automatically installed=automatically installed -debian.info.04.automatically installed.no=no -debian.info.04.automatically installed.yes=yes -debian.info.04.breaks=breaks -debian.info.04.compressed size=Download size -debian.info.04.conflicts=conflicts -debian.info.04.depends=dependencies -debian.info.04.filename=file -debian.info.04.homepage=web page -debian.info.04.maintainer=maintainer -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=multi-architecture -debian.info.04.multi-arch.foreign=foreign -debian.info.04.multi-arch.same=same -debian.info.04.replaces=replaces -debian.info.04.predepends=pre dependencies -debian.info.04.priority=priority -debian.info.04.priority.important=important -debian.info.04.priority.optional=optional -debian.info.04.provided by=provided by -debian.info.04.provides=provides -debian.info.04.recommends=recommends -debian.info.04.section=section -debian.info.04.state=state -debian.info.04.state.installed=installed -debian.info.04.state.not installed=not installed -debian.info.04.state.not installed (configuration files remain)=not installed (configuration files installed) -debian.info.04.suggests=suggests -debian.info.04.uncompressed size=installation size -debian.install.validating=Validating installed packages -debian.installing_pkgs=Installing packages -debian.output.downloading=Downloading {pkg} -debian.output.finishing=Finishing -debian.output.removing=Removing {pkg} -debian.output.unpacking=Unpacking {pkg} -debian.remove.impossible=It is not possible to remove the package {pkg} -debian.remove_deps=The following {no} dependent packages of {pkg} will be removed as well ({fspace}) -debian.simulate_operation=Simulating the operation -debian.task.app_index.status=Indexing installed applications -debian.task.map_apps.check_files=Checking {type} files -debian.task.map_apps.read_cache=Reading apps from the index (cache) -debian.task.map_apps.status=Mapping installed applications -debian.task.update_apps_idx.status=Updating index -debian.task.sync_pkgs.status=Synchronizing packages -debian.transaction.dependency_of=Dependency of {pkgs} -debian.transaction.get_data=Retrieving the operation's data -debian.transaction.title=Operation details -debian.transaction.to_install=The following additional packages ({no}) will be installed (Installation: {isize} | Download: {dsize}) -debian.transaction.to_remove=The following packages ({no}) will be removed (Freed space: {fspace}) -debian.uninstall.failed_to_remove=It was not possible to remove the following {no} packages: {pkgs} -debian.uninstall.removing=Removing packages -debian.uninstall.validating=Validating removed packages -gem.debian.info=Software packages for Debian-based systems \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/pt b/bauh/gems/debian/resources/locale/pt deleted file mode 100644 index cb6276a2..00000000 --- a/bauh/gems/debian/resources/locale/pt +++ /dev/null @@ -1,87 +0,0 @@ -debian.action.index_apps=Indexar aplicações -debian.action.index_apps.desc=Identifica todos os pacotes instalados associados a arquivos .desktop e os mapeia como aplicações -debian.action.purge=Remover completamente -debian.action.purge.confirmation=A remoção completa de {pkg} apagará os arquivos de software e também os de configuração -debian.action.purge.desc=Remove todos os arquivos de software e configuração associados ao pacote -debian.action.purge.status=Removendo {} completamente -debian.action.sync_pkgs=Sincronizar pacotes -debian.action.sync_pkgs.desc=Sincroniza os pacotes de software disponíveis nos repositórios -debian.action.sync_pkgs.status=Sincronizando pacotes -debian.action.sources=Fontes de software -debian.action.sources.desc=Inicia a aplicação detectada para gerenciamento de fontes de software -debian.action.sources.not_installed=A aplicação para gerenciamento de fontes de software não está instalada -debian.action.sources.status=Iniciando aplicação -debian.action.sources.unsupported=A aplicação {app} não é suportada e não será inicializada -debian.app_index.checking=Veriricando o índice de aplicações -debian.app_index.updating=Atualizando o índice de aplicações -debian.config.index_apps.exp=Validade do cache de aplicações -debian.config.index_apps.exp.tip=Período de tempo em MINUTOS em que o cache das aplicações instaladas é considerado válido durante a inicialização -debian.config.pkg_sources.app=Fontes de software -debian.config.pkg_sources.app.tip=Aplicação para gerenciamento de fontes de software. {auto} detecta uma das aplicações suportadas automaticamente. -debian.config.pkg_sources.app.auto=Auto -debian.config.remove.purge=Remoção completa -debian.config.remove.purge.tip=Se as configurações do pacote devem ser removidas durante o processo de desinstalação -debian.config.suggestions.exp=Validade de sugestões -debian.config.suggestions.exp.tip=Define o período (em horas) no qual as sugestões armazenadas em disco serão consideradas atualizadas. Use 0 se quiser que elas sempre sejam atualizadas. -debian.config.sync_pkgs.time=Período de sincronização de pacotes -debian.config.sync_pkgs.time.tip=Período de tempo em MINUTOS em que a sincronização de pacotes deve ocorrer durante a inicialização -debian.info.00.name=nome -debian.info.01.version=versão -debian.info.02.description=descrição -debian.info.03.exec=executável -debian.info.04.architecture=arquitetura -debian.info.04.architecture.all=todas -debian.info.04.archive=arquivamento -debian.info.04.automatically installed=instalado automaticamente -debian.info.04.automatically installed.no=não -debian.info.04.automatically installed.yes=sim -debian.info.04.breaks=Quebra -debian.info.04.compressed size=Tamanho de download -debian.info.04.conflicts=Conflita -debian.info.04.depends=dependências -debian.info.04.filename=arquivo -debian.info.04.homepage=página web -debian.info.04.maintainer=mantenedor -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=multi-arquitetura -debian.info.04.multi-arch.foreign=diferente -debian.info.04.multi-arch.same=mesma -debian.info.04.replaces=substitui -debian.info.04.predepends=pré-dependências -debian.info.04.priority=prioridade -debian.info.04.priority.important=importante -debian.info.04.priority.optional=opcional -debian.info.04.provided by=provido por -debian.info.04.provides=provê -debian.info.04.recommends=recomenda -debian.info.04.section=seção -debian.info.04.state=estado -debian.info.04.state.installed=instalado -debian.info.04.state.not installed=não instalado -debian.info.04.state.not installed (configuration files remain)=não instalado (arquivos de configuração instalados) -debian.info.04.suggests=sugere -debian.info.04.uncompressed size=tamanho de instalação -debian.install.validating=Validando pacotes instalados -debian.installing_pkgs=Instalando pacotes -debian.output.downloading=Baixando {pkg} -debian.output.finishing=Finalizando -debian.output.removing=Removendo {pkg} -debian.output.unpacking=Desempacotando {pkg} -debian.remove.impossible=Não é possível remover o pacote {pkg} -debian.remove_deps=Os seguintes {no} pacotes dependentes de {pkg} serão removidos também ({fspace}) -debian.simulate_operation=Simulando a operação -debian.task.app_index.status=Indexando aplicações instaladas -debian.task.map_apps.check_files=Verificando arquivos {type} -debian.task.map_apps.read_cache=Lendo aplicações do índice (cache) -debian.task.map_apps.status=Mapeando aplicações instaladas -debian.task.update_apps_idx.status=Atualizando índice -debian.task.sync_pkgs.status=Sincronizando pacotes -debian.transaction.dependency_of=Dependência de {pkgs} -debian.transaction.get_data=Obtendo dados da operação -debian.transaction.title=Detalhes da operação -debian.transaction.to_install=Os seguintes pacotes adicionais ({no}) serão instaladas (Instalação: {isize} | Download: {dsize}) -debian.transaction.to_remove=Os seguintes pacotes ({no}) serão removidos (Espaço liberado: {fspace}) -debian.uninstall.failed_to_remove=Não foi possível remover os seguintes {no} pacotes: {pkgs} -debian.uninstall.removing=Removendo pacotes -debian.uninstall.validating=Validando pacotes removidos -gem.debian.info=Pacotes de software para sistemas baseados em Debian \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/ru b/bauh/gems/debian/resources/locale/ru deleted file mode 100644 index 87417577..00000000 --- a/bauh/gems/debian/resources/locale/ru +++ /dev/null @@ -1,87 +0,0 @@ -debian.action.index_apps=Сопоставлять приложения -debian.action.index_apps.desc=Идентифицирует все установленные пакеты, связанные с файлами .desktop, и сопоставляет их с приложениями -debian.action.purge=Удалить полностью -debian.action.purge.confirmation=Полное удаление {pkg} приведет к удалению программных файлов, а также файлов конфигурации -debian.action.purge.desc=Удаление всех программных и конфигурационных файлов, связанных с пакетом -debian.action.purge.status=Полное удаление {} -debian.action.sync_pkgs=Синхронизация пакетов -debian.action.sync_pkgs.desc=Синхронизация доступных программных пакетов в репозиториях -debian.action.sync_pkgs.status=Синхронизация пакетов -debian.action.sources=Источники ПО -debian.action.sources.desc=Запуск приложения для управления источниками ПО -debian.action.sources.not_installed=Приложение для управления источниками ПО не установлено -debian.action.sources.status=Запуск приложения -debian.action.sources.unsupported=Приложение {app} не поддерживается и не запускается -debian.app_index.checking=Проверка индекса приложений -debian.app_index.updating=Обновление индекса приложений -debian.config.index_apps.exp=Истечение срока действия кэша приложений -debian.config.index_apps.exp.tip=Период времени (в минутах) в течение которого кэш установленных приложений считается обновленным при запуске -debian.config.pkg_sources.app=Источники ПО -debian.config.pkg_sources.app.tip=Приложение для управления источниками ПО. {auto} автоматически определяет одно из поддерживаемых приложений. -debian.config.pkg_sources.app.auto=Автоматически -debian.config.remove.purge=Полное удаление -debian.config.remove.purge.tip=Если конфигурации пакета должны быть удалены в процессе удаления -debian.config.suggestions.exp=Срок действия предложений -debian.config.suggestions.exp.tip=Он определяет период (в часах), в течение которого предложения, хранящиеся на диске, будут считаться актуальными. Используйте 0, если вы хотите обновлять их всегда. -debian.config.sync_pkgs.time=Период синхронизации пакетов -debian.config.sync_pkgs.time.tip=Период времени (в минутах) в течение которого должна быть выполнена синхронизация пакетов при запуске -debian.info.00.name=имя -debian.info.01.version=версия -debian.info.02.description=описание -debian.info.03.exec=исполняемый файл -debian.info.04.architecture=архитектура -debian.info.04.architecture.all=все -debian.info.04.archive=архив -debian.info.04.automatically installed=автоматически установленный -debian.info.04.automatically installed.no=нет -debian.info.04.automatically installed.yes=да -debian.info.04.breaks=нарушает -debian.info.04.compressed size=Размер загрузки -debian.info.04.conflicts=конфликты -debian.info.04.depends=зависимости -debian.info.04.filename=файл -debian.info.04.homepage=веб-страница -debian.info.04.maintainer=сопровождающий -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=мультиархитектура -debian.info.04.multi-arch.foreign=внешний -debian.info.04.multi-arch.same=тот же -debian.info.04.replaces=заменяет -debian.info.04.predepends=предзависимости -debian.info.04.priority=приоритет -debian.info.04.priority.important=важно -debian.info.04.priority.optional=опционально -debian.info.04.provided by=предоставленный -debian.info.04.provides=предоставляет -debian.info.04.recommends=рекомендует -debian.info.04.section=раздел -debian.info.04.state=состояние -debian.info.04.state.installed=установлен -debian.info.04.state.not installed=не установлен -debian.info.04.state.not installed (configuration files remain)=не установлен (файлы конфигурации установлены) -debian.info.04.suggests=предлагает -debian.info.04.uncompressed size=установочный размер -debian.install.validating=Проверка установленных пакетов -debian.installing_pkgs=Установка пакетов -debian.output.downloading=Загрузка {pkg} -debian.output.finishing=Завершение -debian.output.removing=Удаление {pkg} -debian.output.unpacking=Распаковка {pkg} -debian.remove.impossible=Невозможно удалить пакет {pkg} -debian.remove_deps=Также будут удалены следующие {no} зависимые пакеты {pkg} ({fspace}) -debian.simulate_operation=Симулирование работы -debian.task.app_index.status=Индексирование установленных приложений -debian.task.map_apps.check_files=Проверка {type} файлов -debian.task.map_apps.read_cache=Чтение приложений из индекса (кэша) -debian.task.map_apps.status=Сопоставление установленных приложений -debian.task.update_apps_idx.status=Обновление индекса -debian.task.sync_pkgs.status=Синхронизация пакетов -debian.transaction.dependency_of=Зависимость от {pkgs} -debian.transaction.get_data=Получение данных операции -debian.transaction.title=Детали операции -debian.transaction.to_install=Будут установлены следующие дополнительные пакеты ({no}) (Установка: {isize} | Загрузка: {dsize}) -debian.transaction.to_remove=Следующие пакеты ({no}) будут удалены (Освобожденное пространство: {fspace}) -debian.uninstall.failed_to_remove=Не удалось удалить следующие пакеты {no}: {pkgs} -debian.uninstall.removing=Удаление пакетов -debian.uninstall.validating=Проверка подлинности удаленных пакетов -gem.debian.info=Пакеты ПО для систем на базе Debian diff --git a/bauh/gems/debian/resources/locale/tr b/bauh/gems/debian/resources/locale/tr deleted file mode 100644 index f4042c76..00000000 --- a/bauh/gems/debian/resources/locale/tr +++ /dev/null @@ -1,86 +0,0 @@ -debian.action.index_apps=Index applications -debian.action.index_apps.desc=Identifies all installed packages associated with .desktop files and maps them as applications -debian.action.purge=Remove completely -debian.action.purge.confirmation=The complete removal of {pkg} will erase the software files and also the configuration ones -debian.action.purge.desc=Removes all software and configuration files associated with the package -debian.action.purge.status=Removing {} completely -debian.action.sync_pkgs=Synchronize packages -debian.action.sync_pkgs.desc=Synchronizes the available software packages on the repositories -debian.action.sync_pkgs.status=Synchronizing packages -debian.action.sources=Software sources -debian.action.sources.desc=Starts the application for managing software sources -debian.action.sources.not_installed=The application for managing software sources is not installed -debian.action.sources.status=Launching application -debian.action.sources.unsupported=The application {app} is not supported and will not be started -debian.app_index.checking=Checking the apps index -debian.app_index.updating=Updating the apps index -debian.config.index_apps.exp=Apps cache expiration -debian.config.index_apps.exp.tip=Time period in MINUTES in which the installed applications cache is considered up-to-date during startup -debian.config.pkg_sources.app=Software sources -debian.config.pkg_sources.app.tip=Application for managing the software sources. {auto} detects one of the supported applications automatically. -debian.config.pkg_sources.app.auto=Auto -debian.config.remove.purge=Complete removal -debian.config.remove.purge.tip=If the package configurations should be removed during the uninstallation process -debian.config.suggestions.exp=Suggestions expiration -debian.config.suggestions.exp.tip=It defines the period (in hours) in which the suggestions stored in disc will be considered up to date. Use 0 if you always want to update them. -debian.config.sync_pkgs.time=Packages synchronization period -debian.config.sync_pkgs.time.tip=Time period in MINUTES in which the packages synchronization must be done on startup -debian.info.00.name=name -debian.info.01.version=version -debian.info.02.description=description -debian.info.03.exec=executable -debian.info.04.architecture=architecture -debian.info.04.architecture.all=all -debian.info.04.archive=archive -debian.info.04.automatically installed=automatically installed -debian.info.04.automatically installed.no=no -debian.info.04.automatically installed.yes=yes -debian.info.04.breaks=breaks -debian.info.04.compressed size=Download size -debian.info.04.conflicts=conflicts -debian.info.04.depends=dependencies -debian.info.04.homepage=web page -debian.info.04.maintainer=maintainer -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=multi-architecture -debian.info.04.multi-arch.foreign=foreign -debian.info.04.multi-arch.same=same -debian.info.04.replaces=replaces -debian.info.04.predepends=pre dependencies -debian.info.04.priority=priority -debian.info.04.priority.important=important -debian.info.04.priority.optional=optional -debian.info.04.provided by=provided by -debian.info.04.provides=provides -debian.info.04.recommends=recommends -debian.info.04.section=section -debian.info.04.state=state -debian.info.04.state.installed=installed -debian.info.04.state.not installed=not installed -debian.info.04.state.not installed (configuration files remain)=not installed (configuration files installed) -debian.info.04.suggests=suggests -debian.info.04.uncompressed size=installation size -debian.install.validating=Validating installed packages -debian.installing_pkgs=Installing packages -debian.output.downloading=Downloading {pkg} -debian.output.finishing=Finishing -debian.output.removing=Removing {pkg} -debian.output.unpacking=Unpacking {pkg} -debian.remove.impossible=It is not possible to remove the package {pkg} -debian.remove_deps=The following {no} dependent packages of {pkg} will be removed as well ({fspace}) -debian.simulate_operation=Simulating the operation -debian.task.app_index.status=Indexing installed applications -debian.task.map_apps.check_files=Checking {type} files -debian.task.map_apps.read_cache=Reading apps from the index (cache) -debian.task.map_apps.status=Mapping installed applications -debian.task.update_apps_idx.status=Updating index -debian.task.sync_pkgs.status=Synchronizing packages -debian.transaction.dependency_of=Dependency of {pkgs} -debian.transaction.get_data=Retrieving the operation's data -debian.transaction.title=Operation details -debian.transaction.to_install=The following additional packages ({no}) will be installed (Installation: {isize} | Download: {dsize}) -debian.transaction.to_remove=The following packages ({no}) will be removed (Freed space: {fspace}) -debian.uninstall.failed_to_remove=It was not possible to remove the following {no} packages: {pkgs} -debian.uninstall.removing=Removing packages -debian.uninstall.validating=Validating removed packages -gem.debian.info=Software packages for Debian-based systems \ No newline at end of file diff --git a/bauh/gems/debian/resources/locale/zh b/bauh/gems/debian/resources/locale/zh deleted file mode 100644 index 95b6df4b..00000000 --- a/bauh/gems/debian/resources/locale/zh +++ /dev/null @@ -1,87 +0,0 @@ -debian.action.index_apps=索引应用程序 -debian.action.index_apps.desc=识别与 .desktop 文件关联的所有已安装软件包,并将它们映射为应用程序 -debian.action.purge=完全删除 -debian.action.purge.confirmation=完全删除 {pkg} 将擦除软件文件以及配置文件 -debian.action.purge.desc=删除与软件包关联的所有软件和配置文件 -debian.action.purge.status=完全删除 {} -debian.action.sync_pkgs=同步软件包 -debian.action.sync_pkgs.desc=同步可用的软件包在仓库中 -debian.action.sync_pkgs.status=正在同步软件包 -debian.action.sources=软件源 -debian.action.sources.desc=启动管理软件源的应用程序 -debian.action.sources.not_installed=未安装管理软件源的应用程序 -debian.action.sources.status=启动应用程序 -debian.action.sources.unsupported=不支持应用程序 {app},将不会启动 -debian.app_index.checking=检查应用程序索引 -debian.app_index.updating=正在更新应用程序索引 -debian.config.index_apps.exp=应用程序缓存过期 -debian.config.index_apps.exp.tip=启动期间安装的应用程序缓存被视为最新的分钟数 -debian.config.pkg_sources.app=软件源 -debian.config.pkg_sources.app.tip=管理软件源的应用程序。 {auto} 自动检测支持的应用程序之一。 -debian.config.pkg_sources.app.auto=自动 -debian.config.remove.purge=完全删除 -debian.config.remove.purge.tip=是否应在卸载过程中删除软件包配置 -debian.config.suggestions.exp=建议过期时间 -debian.config.suggestions.exp.tip=定义建议在磁盘上存储的期间(以小时为单位)被视为最新的时间。如果始终希望更新它们,请使用 0。 -debian.config.sync_pkgs.time=软件包同步周期 -debian.config.sync_pkgs.time.tip=启动时进行软件包同步的分钟数 -debian.info.00.name=名称 -debian.info.01.version=版本 -debian.info.02.description=描述 -debian.info.03.exec=可执行文件 -debian.info.04.architecture=架构 -debian.info.04.architecture.all=全部 -debian.info.04.archive=存档 -debian.info.04.automatically installed=自动安装 -debian.info.04.automatically installed.no=否 -debian.info.04.automatically installed.yes=是 -debian.info.04.breaks=破坏 -debian.info.04.compressed size=下载大小 -debian.info.04.conflicts=冲突 -debian.info.04.depends=依赖项 -debian.info.04.filename=文件名 -debian.info.04.homepage=网页 -debian.info.04.maintainer=维护者 -debian.info.04.md5sum=MD5 -debian.info.04.multi-arch=多架构 -debian.info.04.multi-arch.foreign=外部 -debian.info.04.multi-arch.same=相同 -debian.info.04.replaces=替代 -debian.info.04.predepends=预先依赖 -debian.info.04.priority=优先级 -debian.info.04.priority.important=重要 -debian.info.04.priority.optional=可选 -debian.info.04.provided by=提供者 -debian.info.04.provides=提供 -debian.info.04.recommends=建议 -debian.info.04.section=部分 -debian.info.04.state=状态 -debian.info.04.state.installed=已安装 -debian.info.04.state.not installed=未安装 -debian.info.04.state.not installed (configuration files remain)=未安装 (配置文件已安装) -debian.info.04.suggests=建议 -debian.info.04.uncompressed size=安装大小 -debian.install.validating=验证已安装的软件包 -debian.installing_pkgs=正在安装软件包 -debian.output.downloading=下载 {pkg} -debian.output.finishing=完成 -debian.output.removing=删除 {pkg} -debian.output.unpacking=解压 {pkg} -debian.remove.impossible=无法删除软件包 {pkg} -debian.remove_deps=以下 {no} 个与 {pkg} 有关的依赖软件包也将被删除(已释放空间:{fspace}) -debian.simulate_operation=模拟操作 -debian.task.app_index.status=正在索引已安装的应用程序 -debian.task.map_apps.check_files=检查 {type} 文件 -debian.task.map_apps.read_cache=从索引 (缓存) 读取应用程序 -debian.task.map_apps.status=映射已安装的应用程序 -debian.task.update_apps_idx.status=更新索引 -debian.task.sync_pkgs.status=正在同步软件包 -debian.transaction.dependency_of={pkgs} 的依赖项 -debian.transaction.get_data=检索操作的数据 -debian.transaction.title=操作详细信息 -debian.transaction.to_install=将安装以下额外的软件包({no})(安装:{isize} | 下载:{dsize}) -debian.transaction.to_remove=将删除以下软件包({no})(释放空间:{fspace}) -debian.uninstall.failed_to_remove=无法删除以下 {no} 个软件包:{pkgs} -debian.uninstall.removing=正在删除软件包 -debian.uninstall.validating=正在验证已删除的软件包 -gem.debian.info=基于 Debian 的系统的软件包 diff --git a/bauh/gems/debian/suggestions.py b/bauh/gems/debian/suggestions.py deleted file mode 100644 index 2091356d..00000000 --- a/bauh/gems/debian/suggestions.py +++ /dev/null @@ -1,209 +0,0 @@ -import os -import traceback -from datetime import datetime, timedelta, timezone -from logging import Logger -from pathlib import Path -from threading import Thread -from typing import Optional, Dict - -from bauh.api.abstract.handler import TaskManager -from bauh.api.abstract.model import SuggestionPriority -from bauh.api.http import HttpClient -from bauh.commons.suggestions import parse -from bauh.gems.debian import DEBIAN_ICON_PATH, DEBIAN_CACHE_DIR -from bauh.view.util.translation import I18n - - -class DebianSuggestionsDownloader(Thread): - - _file_suggestions: Optional[str] = None - _file_suggestions_ts: Optional[str] = None - _url_suggestions: Optional[str] = None - - @classmethod - def file_suggestions(cls) -> str: - if cls._file_suggestions is None: - cls._file_suggestions = f'{DEBIAN_CACHE_DIR}/suggestions.txt' - - return cls._file_suggestions - - @classmethod - def file_suggestions_timestamp(cls) -> str: - if cls._file_suggestions_ts is None: - cls._file_suggestions_ts = f'{cls.file_suggestions()}.ts' - - return cls._file_suggestions_ts - - def __init__(self, logger: Logger, http_client: HttpClient, i18n: I18n, file_url: Optional[str]): - super(DebianSuggestionsDownloader, self).__init__() - self._log = logger - self.i18n = i18n - self.http_client = http_client - self._taskman: Optional[TaskManager] = None - - if file_url: - self._file_url = file_url - else: - self._file_url = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master/debian/suggestions_v1.txt' - - self.task_id = 'debian.suggs' - - def register_task(self, taskman: Optional[TaskManager]): - self._taskman = taskman - if taskman: - self._taskman.register_task(id_=self.task_id, label=self.i18n['task.download_suggestions'], - icon_path=DEBIAN_ICON_PATH) - - def is_local_suggestions_file(self) -> bool: - return self._file_url and self._file_url.startswith('/') - - @property - def taskman(self) -> TaskManager: - if self._taskman is None: - self._taskman = TaskManager() - - return self._taskman - - def should_download(self, debian_config: dict, only_positive_exp: bool = False) -> bool: - if not self._file_url: - self._log.error("No Debian suggestions file URL defined") - return False - - if self.is_local_suggestions_file(): - return False - - try: - exp_hours = int(debian_config['suggestions.exp']) - except ValueError: - self._log.error(f"The Debian configuration property 'suggestions.expiration' has a non int value set: " - f"{debian_config['suggestions']['expiration']}") - return not only_positive_exp - - if exp_hours <= 0: - self._log.info("Suggestions cache is disabled") - return not only_positive_exp - - if not os.path.exists(self.file_suggestions()): - self._log.info(f"'{self.file_suggestions()}' not found. It must be downloaded") - return True - - if not os.path.exists(self.file_suggestions()): - self._log.info(f"'{self.file_suggestions()}' not found. The suggestions file must be downloaded.") - return True - - with open(self.file_suggestions_timestamp()) as f: - timestamp_str = f.read() - - try: - suggestions_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc) - except Exception: - self._log.error(f'Could not parse the Debian cached suggestions timestamp: {timestamp_str}') - traceback.print_exc() - return True - - update = suggestions_timestamp + timedelta(hours=exp_hours) <= datetime.now(timezone.utc) - return update - - def _save(self, text: str, timestamp: float): - if not self._file_url: - self._log.error("No Debian suggestions file URL defined") - return - - if self.is_local_suggestions_file(): - return False - - self._log.info(f"Caching suggestions to '{self.file_suggestions()}'") - - cache_dir = os.path.dirname(self.file_suggestions()) - - try: - Path(cache_dir).mkdir(parents=True, exist_ok=True) - cache_dir_ok = True - except OSError: - self._log.error(f"Could not create cache directory '{cache_dir}'") - traceback.print_exc() - cache_dir_ok = False - - if cache_dir_ok: - try: - with open(self.file_suggestions(), 'w+') as f: - f.write(text) - except Exception: - self._log.error(f"An exception happened while writing the file '{self.file_suggestions()}'") - traceback.print_exc() - - try: - with open(self.file_suggestions_timestamp(), 'w+') as f: - f.write(str(timestamp)) - except Exception: - self._log.error(f"An exception happened while writing the file '{self.file_suggestions_timestamp()}'") - traceback.print_exc() - - def read_cached(self) -> Optional[Dict[str, SuggestionPriority]]: - if not self._file_url: - self._log.error("No Debian suggestions file URL defined") - return - - if self.is_local_suggestions_file(): - file_path, log_ref = self._file_url, 'local' - else: - file_path, log_ref = self.file_suggestions(), 'cached' - - self._log.info(f"Reading {log_ref} suggestions file {file_path}") - - try: - with open(file_path) as f: - sugs_str = f.read() - except FileNotFoundError: - self._log.warning(f"The {log_ref} suggestions file does not exist ({file_path})") - return - except OSError: - self._log.warning(f"Could not read from the {log_ref} suggestions file ({file_path})") - traceback.print_exc() - return - - if not sugs_str: - self._log.warning(f"The {log_ref} suggestions file '{file_path}' is empty") - return - - return parse(sugs_str, self._log, 'Debian') - - def download(self) -> Optional[Dict[str, SuggestionPriority]]: - if not self._file_url: - self._log.error("No Debian suggestions file URL defined") - return - - self.taskman.update_progress(self.task_id, progress=1, substatus=None) - - self._log.info(f"Downloading Debian suggestions from {self._file_url}") - res = self.http_client.get(self._file_url) - - suggestions = None - if res.status_code == 200 and res.text: - self.taskman.update_progress(self.task_id, progress=50, substatus=None) - suggestions = parse(res.text, self._log, 'Debian') - - if suggestions: - self._save(text=res.text, timestamp=datetime.now(timezone.utc).timestamp()) - else: - self._log.warning("No Debian suggestions to cache") - else: - self._log.warning(f"Could not retrieve Debian suggestions. " - f"Response (status={res.status_code}, text={res.text})") - - self.taskman.update_progress(self.task_id, progress=100, substatus=None) - self.taskman.finish_task(self.task_id) - return suggestions - - def read(self, debian_config: dict) -> Optional[Dict[str, int]]: - if not self._file_url: - self._log.error("No Debian suggestions file URL defined") - return - - if self.is_local_suggestions_file() or not self.should_download(debian_config=debian_config): - return self.read_cached() - - return self.download() - - def run(self): - self.download() diff --git a/bauh/gems/debian/tasks.py b/bauh/gems/debian/tasks.py deleted file mode 100644 index edddf6b6..00000000 --- a/bauh/gems/debian/tasks.py +++ /dev/null @@ -1,196 +0,0 @@ -import time -import traceback -from datetime import datetime, timedelta, timezone -from logging import Logger -from threading import Thread -from typing import Optional, Set - -from bauh.api.abstract.handler import TaskManager, ProcessWatcher -from bauh.commons.html import bold -from bauh.commons.system import ProcessHandler -from bauh.gems.debian import DEBIAN_ICON_PATH, PACKAGE_SYNC_TIMESTAMP_FILE -from bauh.gems.debian.aptitude import Aptitude -from bauh.gems.debian.index import ApplicationIndexer, ApplicationsMapper -from bauh.gems.debian.model import DebianApplication -from bauh.view.util.translation import I18n - - -class MapApplications(Thread): - - def __init__(self, taskman: TaskManager, app_indexer: ApplicationIndexer, i18n: I18n, logger: Logger, - deb_config: dict, app_mapper: ApplicationsMapper, check_expiration: bool = True, - watcher: Optional[ProcessWatcher] = None): - super(MapApplications, self).__init__() - self._taskman = taskman - self._i18n = i18n - self._log = logger - self._id = 'debian.map_apps' - self._indexer = app_indexer - self._config = deb_config - self._app_mapper = app_mapper - self._taskman.register_task(self._id, self._i18n['debian.task.map_apps.status'], DEBIAN_ICON_PATH) - self.apps: Optional[Set[DebianApplication]] = None - self.cached: Optional[bool] = None - self._check_expiration = check_expiration - self._watcher = watcher - - def _change_substatus(self, msg: str): - if self._watcher: - self._watcher.change_substatus(msg) - - def run(self): - ti = time.time() - self._log.info("Begin: mapping Debian applications") - - self._taskman.update_progress(self._id, 1, None) - - if not self._check_expiration or self._indexer.is_expired(self._config): - status = self._i18n['debian.task.map_apps.check_files'].format(type="'.desktop") - self._taskman.update_progress(self._id, 1, status) - self._change_substatus(status) - self.apps = self._app_mapper.map_executable_applications() - self.cached = False - else: - status = self._i18n['debian.task.map_apps.read_cache'] - self._taskman.update_progress(self._id, 1, status) - self._change_substatus(status) - self.apps = {app for app in self._indexer.read_index()} - self.cached = True - - self._log.info(f"Number of Debian applications found: {len(self.apps) if self.apps else 0}") - self._taskman.update_progress(self._id, 100, None) - self._taskman.finish_task(self._id) - - tf = time.time() - self._log.info(f"Finish: mapping Debian applications ({tf - ti:.4f} seconds)") - - -class UpdateApplicationIndex(Thread): - - def __init__(self, taskman: TaskManager, app_indexer: ApplicationIndexer, - i18n: I18n, logger: Logger, mapping_apps: MapApplications, - watcher: Optional[ProcessWatcher] = None): - super(UpdateApplicationIndex, self).__init__() - self._taskman = taskman - self._i18n = i18n - self._log = logger - self._id = 'debian.app_idx' - self._indexer = app_indexer - self._mapping_apps = mapping_apps - self._taskman.register_task(self._id, self._i18n['debian.task.app_index.status'], DEBIAN_ICON_PATH) - self._watcher = watcher - - def _change_substatus(self, msg: str): - if self._watcher: - self._watcher.change_substatus(msg) - - def run(self): - ti = time.time() - self._log.info("Begin: Debian applications indexation") - - self._taskman.update_progress(self._id, 1, self._i18n['task.waiting_task'].format(bold(self._i18n['debian.task.map_apps.status']))) - self._mapping_apps.join() - - finish_msg = None - if self._mapping_apps.cached: - finish_msg = self._i18n['task.canceled'] - else: - status = self._i18n['debian.task.update_apps_idx.status'] - self._taskman.update_progress(self._id, 50, status) - self._change_substatus(status) - - try: - self._indexer.update_index(self._mapping_apps.apps) - except Exception: - finish_msg = self._i18n['error'] - - self._taskman.update_progress(self._id, 100, finish_msg) - self._taskman.finish_task(self._id) - - tf = time.time() - self._log.info(f"Finish: Debian applications indexation ({tf - ti:.4f} seconds)") - - -class SynchronizePackages(Thread): - - def __init__(self, taskman: TaskManager, i18n: I18n, logger: Logger, root_password: Optional[str], - aptitude: Aptitude, watcher: Optional[ProcessWatcher] = None): - super(SynchronizePackages, self).__init__() - self._id = 'debian.sync_pkgs' - self._taskman = taskman - self._i18n = i18n - self._log = logger - self._root_password = root_password - self._watcher = watcher - self._aptitude = aptitude - self._taskman.register_task(self._id, self._i18n['debian.task.sync_pkgs.status'], DEBIAN_ICON_PATH) - - def _notify_output(self, output: str): - self._taskman.update_output(self._id, output) - - @staticmethod - def should_synchronize(deb_config: dict, logger: Logger) -> bool: - try: - period = int(deb_config.get('sync_pkgs.time', 0)) - except ValueError: - logger.error(f"Invalid value for Debian configuration property 'sync_pkgs.time': " - f"{deb_config['sync_pkgs.time']}") - return True - - if period <= 0: - logger.warning("Packages synchronization will always be done ('sync_pkgs.time' <= 0 )'") - return True - - try: - with open(PACKAGE_SYNC_TIMESTAMP_FILE) as f: - timestamp_str = f.read().strip() - except FileNotFoundError: - logger.info(f"No packages synchronization timestamp found ({PACKAGE_SYNC_TIMESTAMP_FILE})") - return True - - try: - last_timestamp = datetime.fromtimestamp(float(timestamp_str), tz=timezone.utc) - except Exception: - logger.error(f'Could not parse the packages synchronization timestamp: {timestamp_str} ' - f'({PACKAGE_SYNC_TIMESTAMP_FILE})') - traceback.print_exc() - return True - - expired = last_timestamp + timedelta(minutes=period) <= datetime.now(timezone.utc) - - if expired: - logger.info("Packages synchronization is outdated") - else: - logger.info("Packages synchronization is up-to-date") - - return expired - - def run(self) -> bool: - ti = time.time() - self._log.info("Begin: packages synchronization") - self._taskman.update_progress(self._id, 1, None) - - handler = ProcessHandler(self._watcher) - updated, _ = handler.handle_simple(self._aptitude.update(self._root_password), - output_handler=self._notify_output) - self._taskman.update_progress(self._id, 99, None) - - if updated: - index_timestamp = datetime.now(timezone.utc).timestamp() - finish_msg = None - try: - with open(PACKAGE_SYNC_TIMESTAMP_FILE, 'w+') as f: - f.write(str(index_timestamp)) - except OSError: - finish_msg = self._i18n['error'] - self._log.error(f"Could not write the packages synchronization timestamp to file " - f"'{PACKAGE_SYNC_TIMESTAMP_FILE}'") - else: - finish_msg = self._i18n['error'] - - self._taskman.update_progress(self._id, 100, finish_msg) - self._taskman.finish_task(self._id) - - tf = time.time() - self._log.info(f"Finish: packages synchronization ({tf - ti:.4f} seconds)") - return updated diff --git a/tests/gems/debian/__init__.py b/tests/gems/debian/__init__.py deleted file mode 100644 index a2b38d41..00000000 --- a/tests/gems/debian/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import os - -DEBIAN_TESTS_DIR = os.path.dirname(os.path.abspath(__file__)) diff --git a/tests/gems/debian/resources/app_idx_full.json b/tests/gems/debian/resources/app_idx_full.json deleted file mode 100644 index bd3d4989..00000000 --- a/tests/gems/debian/resources/app_idx_full.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "firefox": { - "categories": [ - "GNOME", - "GTK", - "Network", - "WebBrowser" - ], - "exe_path": "firefox %u", - "icon_path": "firefox" - }, - - "synaptic": { - "exe_path": "synaptic-pkexec", - "icon_path": "synaptic" - } -} diff --git a/tests/gems/debian/test_aptitude.py b/tests/gems/debian/test_aptitude.py deleted file mode 100644 index 87dcb3a4..00000000 --- a/tests/gems/debian/test_aptitude.py +++ /dev/null @@ -1,198 +0,0 @@ -from unittest import TestCase -from unittest.mock import Mock, patch - -from bauh import __app_name__ -from bauh.commons import system -from bauh.commons.system import USE_GLOBAL_INTERPRETER -from bauh.gems.debian.aptitude import Aptitude, map_package_name -from bauh.gems.debian.model import DebianPackage - - -class MapPackageNameTest(TestCase): - - def test__it_must_return_the_same_input_when_no_colon(self): - self.assertEqual('my_package', map_package_name('my_package')) - - def test__it_must_return_the_only_the_word_before_the_first_colon(self): - self.assertEqual('my_package', map_package_name('my_package:i386')) - - def test__it_must_return_a_name_with_colon_when_several_colons_are_present(self): - self.assertEqual('my_package:i386', map_package_name('my_package:i386:amd64')) - - -class AptitudeTest(TestCase): - - def setUp(self): - self.aptitude = Aptitude(Mock()) - - @patch(f'{__app_name__}.gems.debian.aptitude.system.execute', return_value=(0, """ -gimp-cbmplugs^^1.2.2-1build1^Distro Developers ^universe/graphics^plugins for The GIMP to import/export Commodore 64 files -gimp-gmic^2.4.5-1.0^2.4.5-1.1^Distro Developers ^plugin^GREYC's Magic for Image Computing - GIMP Plugin -gimp-gutenprint^5.3.3-4^5.3.3-4^Distro Developers ^plugin^print plugin for the GIMP -gimp-help^^^^^ - """)) - def test_search__must_return_installed_and_not_installed_packages_with_updates(self, execute: Mock): - query = 'gimp' - res = [p for p in self.aptitude.search(query=query)] - - execute.assert_called_once_with(f"aptitude search {query} -q -F '%p^%v^%V^%m^%s^%d' --disable-columns", shell=True) - - exp = [ - DebianPackage(name='gimp-cbmplugs', version='1.2.2-1build1', latest_version='1.2.2-1build1', - maintainer='Distro Developers', - description='plugins for The GIMP to import/export Commodore 64 files', - categories=('graphics',), - installed=False, update=False), - DebianPackage(name='gimp-gmic', version='2.4.5-1.0', latest_version='2.4.5-1.1', - maintainer='Distro Developers', - description="GREYC's Magic for Image Computing - GIMP Plugin", - categories=('plugin',), - installed=True, update=True), - DebianPackage(name='gimp-gutenprint', version='5.3.3-4', latest_version='5.3.3-4', - maintainer='Distro Developers', - description="print plugin for the GIMP", - categories=('plugin',), - installed=True, update=False), - ] - - self.assertEqual([p.__dict__ for p in exp], [p.__dict__ for p in res]) - - @patch(f'{__app_name__}.gems.debian.aptitude.system.execute', return_value=(0, """ -Package: firefox -Version: 97.0+distro1+una -State: installed (95.0.1+distro1.1+una), upgrade available (97.0+distro1+una) -Automatically installed: no -Priority: optional -Section: web -Maintainer: Distro Dev -Architecture: amd64 -Uncompressed Size: 236 M -PreDepends: distro-system-adjustments (>= 2021.12.16) -Breaks: firefox-dbg (< 95.0.1+distro1+una), firefox-dev (< 95.0.1+distro1+una), firefox-geckodriver (< 95.0.1+distro1+una), firefox-mozsymbols (< 95.0.1+distro1+una) -Replaces: firefox-dbg (< 95.0.1+distro1+una), firefox-dev (< 95.0.1+distro1+una), firefox-geckodriver (< 95.0.1+distro1+una), firefox-mozsymbols (< 95.0.1+distro1+una) -Provides: gnome-www-browser, www-browser -Description: The Firefox web browser - The Mozilla Firefox Web Browser. - -Package: gcc -Version: 4:9.3.0-1distro2 -State: installed -Automatically installed: no -Priority: optional -Section: devel -Maintainer: Distro Developers -Architecture: amd64 -Uncompressed Size: 51,2 k -Depends: cpp (= 4:9.3.0-1distro2), gcc-9 (>= 9.3.0-3~) -Recommends: libc6-dev | libc-dev -Suggests: gcc-multilib, make, manpages-dev, autoconf, automake, libtool, flex, bison, gdb, gcc-doc -Conflicts: gcc-doc (< 1:2.95.3), gcc-doc:i386 (< 1:2.95.3), gcc:i386 -Provides: c-compiler, gcc-x86-64-linux-gnu (= 4:9.3.0-1distro2), gcc:amd64 (= 4:9.3.0-1distro2) -Description: GNU C compiler - This is the GNU C compiler, a fairly portable optimizing compiler for C. - - This is a dependency package providing the default GNU C compiler. - -""")) - def test_show__all_attributes(self, execute: Mock): - info = self.aptitude.show(('firefox', 'gcc')) - execute.assert_called_once_with('aptitude show -q firefox gcc', shell=True, - custom_env={**system.gen_env(global_interpreter=system.USE_GLOBAL_INTERPRETER, - lang=''), 'LC_NUMERIC': ''}) - - expected = { - 'firefox': { - 'version': '97.0+distro1+una', - 'state': ('installed (95.0.1+distro1.1+una)', 'upgrade available (97.0+distro1+una)'), - 'automatically installed': 'no', - 'priority': 'optional', - 'section': 'web', - 'maintainer': 'Distro Dev ', - 'architecture': 'amd64', - 'uncompressed size': 236000000, - 'predepends': ('distro-system-adjustments (>= 2021.12.16)', ), - 'breaks': ('firefox-dbg (< 95.0.1+distro1+una)', 'firefox-dev (< 95.0.1+distro1+una)', - 'firefox-geckodriver (< 95.0.1+distro1+una)', 'firefox-mozsymbols (< 95.0.1+distro1+una)'), - 'replaces': ('firefox-dbg (< 95.0.1+distro1+una)', 'firefox-dev (< 95.0.1+distro1+una)', - 'firefox-geckodriver (< 95.0.1+distro1+una)', 'firefox-mozsymbols (< 95.0.1+distro1+una)'), - 'provides': ('gnome-www-browser', 'www-browser'), - 'description': 'The Firefox web browser' - }, - 'gcc': { - 'version': '4:9.3.0-1distro2', - 'state': ('installed', ), - 'automatically installed': 'no', - 'priority': 'optional', - 'section': 'devel', - 'maintainer': 'Distro Developers ', - 'architecture': 'amd64', - 'uncompressed size': 51200, - 'depends': ('cpp (= 4:9.3.0-1distro2)', 'gcc-9 (>= 9.3.0-3~)'), - 'recommends': ('libc6-dev | libc-dev', ), - 'suggests': ('gcc-multilib', 'make', 'manpages-dev', 'autoconf', 'automake', - 'libtool', 'flex', 'bison', 'gdb', 'gcc-doc'), - 'conflicts': ('gcc-doc (< 1:2.95.3)', 'gcc-doc:i386 (< 1:2.95.3)', 'gcc:i386'), - 'provides': ('c-compiler', 'gcc-x86-64-linux-gnu (= 4:9.3.0-1distro2)', 'gcc:amd64 (= 4:9.3.0-1distro2)'), - 'description': 'GNU C compiler' - } - } - - self.assertEqual(expected, info) - - @patch(f'{__app_name__}.gems.debian.aptitude.system.execute', return_value=(0, """ - gir1.2-javascriptcoregtk-4.0^2.34.1-0distro0.20.04.1^2.34.4-0distro0.20.04.1^Distro Developers ^library^JavaScript engine library from WebKitGTK - GObject introspection data - gir1.2-nm-1.0^1.22.10-1distro2.2^1.22.10-1distro2.3^Distro Developers ^library^GObject introspection data for the libnm library - xwayland^2:1.20.13-1distro1~20.04.2^2:1.20.13-1distro1~20.04.2^Distro X-SWAT ^X11^Xwayland X server - """)) - def test_read_installed__with_updates_available(self, execute: Mock): - returned = [p for p in self.aptitude.read_installed()] - execute.assert_called_once() - - expected = [DebianPackage(name='gir1.2-javascriptcoregtk-4.0', version='2.34.1-0distro0.20.04.1', - latest_version='2.34.4-0distro0.20.04.1', - maintainer='Distro Developers', update=True, installed=True, - categories=('library',), - description='JavaScript engine library from WebKitGTK - GObject introspection data'), - DebianPackage(name='gir1.2-nm-1.0', version='1.22.10-1distro2.2', - latest_version='1.22.10-1distro2.3', - maintainer='Distro Developers', update=True, installed=True, - categories=('library',), - description='GObject introspection data for the libnm library'), - DebianPackage(name='xwayland', version='2:1.20.13-1distro1~20.04.2', - latest_version='2:1.20.13-1distro1~20.04.2', - maintainer='Distro X-SWAT', update=False, installed=True, - categories=('X11',), - description='Xwayland X server') - ] - - self.assertEqual([p.__dict__ for p in expected], [p.__dict__ for p in returned]) - - def test_map_transaction_output__it_should_map_i386_packages(self): - output = "\nThe following NEW packages will be installed:\n" \ - " gcc-12-base:i386{a} [12.1.0-2distro~22.04] <+272 kB> glib-networking:i386{a} [2.72.0-1] <+242 kB>\n" \ - "\nThe following packages will be REMOVED:\n" \ - " celluloid{a} [0.21-linux+distro] <-1066 kB> libpcre3:i386{a} [2:8.39-13distro0.22.04.1] <-714 kB>" - - transaction = self.aptitude.map_transaction_output(output) - to_install = { - DebianPackage(name="gcc-12-base:i386", - version="12.1.0-2distro~22.04", - latest_version="12.1.0-2distro~22.04", - transaction_size=272000.0 - ), - DebianPackage(name="glib-networking:i386", version="2.72.0-1", - latest_version="2.72.0-1", transaction_size=242000.0) - } - self.assertEqual(to_install, {*transaction.to_install}) - - to_remove = { - DebianPackage(name="celluloid", - version="0.21-linux+distro", - latest_version="0.21-linux+distro", - transaction_size=-1066000.0 - ), - DebianPackage(name="libpcre3:i386", version="2:8.39-13distro0.22.04.1", - latest_version="2:8.39-13distro0.22.04.1", transaction_size=-714000.0) - } - - self.assertEqual(to_remove, {*transaction.to_remove}) diff --git a/tests/gems/debian/test_controller.py b/tests/gems/debian/test_controller.py deleted file mode 100644 index 23bc2a47..00000000 --- a/tests/gems/debian/test_controller.py +++ /dev/null @@ -1,99 +0,0 @@ -from unittest import TestCase -from unittest.mock import MagicMock, patch, Mock - -from bauh import __app_name__ -from bauh.api.abstract.controller import SearchResult -from bauh.gems.debian.controller import DebianPackageManager -from bauh.gems.debian.model import DebianPackage, DebianApplication - - -class DebianPackageManagerTest(TestCase): - - def setUp(self): - self.controller = DebianPackageManager(MagicMock()) - self.controller._apps_index = {} - - @patch(f'{__app_name__}.gems.debian.controller.Aptitude.read_installed', return_value=iter(( - DebianPackage(name='gir1.2-javascriptcoregtk-4.0', version='2.34.1-0distro0.20.04.1', - latest_version='2.34.1-0distro0.20.04.1', - maintainer='Distro Developers', update=False, installed=True, - description='JavaScript engine library from WebKitGTK - GObject introspection data'), - DebianPackage(name='xwayland', version='2:1.20.13-1distro1~20.04.2', - latest_version='2:1.20.13-1distro1~20.04.2', - maintainer='Distro X-SWAT', update=False, installed=True, - description='Xwayland X server') - ))) - def test_read_installed__must_associated_packages_found_to_applications_if_appliable(self, read_installed: Mock): - app = DebianApplication(name='xwayland', exe_path='xwayland', icon_path='xwayland', categories=('app',)) - - self.controller.__apps_index = {'xwayland': app} - - result = self.controller.read_installed(disk_loader=None, pkg_types=None, internet_available=False) - read_installed.assert_called_once() - - self.assertIsNone(result.new) - - expected = [DebianPackage(name='gir1.2-javascriptcoregtk-4.0', version='2.34.1-0distro0.20.04.1', latest_version='2.34.1-0distro0.20.04.1', - maintainer='Distro Developers', update=False, installed=True, - description='JavaScript engine library from WebKitGTK - GObject introspection data'), - DebianPackage(name='xwayland', version='2:1.20.13-1distro1~20.04.2', latest_version='2:1.20.13-1distro1~20.04.2', - maintainer='Distro X-SWAT', update=False, installed=True, - description='Xwayland X server', app=app) - ] - - self.assertEqual(expected, result.installed) - - @patch(f'{__app_name__}.gems.debian.controller.Aptitude.read_installed', return_value=iter(( - DebianPackage(name='gir1.2-javascriptcoregtk-4.0', version='2.34.1-0distro0.20.04.1', - latest_version='2.34.1-0distro0.20.04.1', - maintainer='Distro Developers', update=False, installed=True, - description='JavaScript engine library from WebKitGTK - GObject introspection data'), - DebianPackage(name='xwayland', version='2:1.20.13-1distro1~20.04.2', - latest_version='2:1.20.13-1distro1~20.04.2', - maintainer='Distro X-SWAT', update=False, installed=True, - description='Xwayland X server') - ))) - def test_read_installed__internet_not_available(self, read_installed: Mock): - result = self.controller.read_installed(disk_loader=None, pkg_types=None, internet_available=False) - read_installed.assert_called_once() - - self.assertIsNone(result.new) - - expected = [DebianPackage(name='gir1.2-javascriptcoregtk-4.0', version='2.34.1-0distro0.20.04.1', latest_version='2.34.1-0distro0.20.04.1', - maintainer='Distro Developers', update=False, installed=True, - description='JavaScript engine library from WebKitGTK - GObject introspection data'), - DebianPackage(name='xwayland', version='2:1.20.13-1distro1~20.04.2', latest_version='2:1.20.13-1distro1~20.04.2', - maintainer='Distro X-SWAT', update=False, installed=True, - description='Xwayland X server') - ] - - self.assertEqual(expected, result.installed) - - @patch(f'{__app_name__}.gems.debian.controller.Aptitude.read_installed') - def test_search__must_return_empty_result_when_url(self, read_installed: Mock): - words = 'i' - res = self.controller.search(words=words, disk_loader=None, limit=-1, is_url=True) - read_installed.assert_not_called() - self.assertEqual(SearchResult.empty(), res) - - @patch(f'{__app_name__}.gems.debian.controller.Aptitude.search', return_value=iter(( - DebianPackage(name='xpto', version='1.0', latest_version='1.0', installed=True, update=False, description=''), - DebianPackage(name='test', version='1.0', latest_version='1.0', installed=False, update=False, description=''), - DebianPackage(name='myapp', version='1.0', latest_version='1.0', installed=True, update=False, description=''), - ))) - def test_search__returned_packages_should_be_associated_with_apps_if_appliable(self, search: Mock): - app = DebianApplication(name='myapp', exe_path='myapp', icon_path='myapp', - categories=('app',)) - self.controller._apps_index = {'myapp': app} - - words = 'test' - res = self.controller.search(words=words, disk_loader=None, limit=-1, is_url=False) - search.assert_called_once_with(words) - - self.assertEqual([DebianPackage(name='xpto', version='1.0', latest_version='1.0', installed=True, update=False, description=''), - DebianPackage(name='myapp', version='1.0', latest_version='1.0', installed=True, update=False, - description='', app=app) - ], res.installed) - - self.assertEqual([DebianPackage(name='test', version='1.0', latest_version='1.0', installed=False, update=False, description='')], - res.new) diff --git a/tests/gems/debian/test_index.py b/tests/gems/debian/test_index.py deleted file mode 100644 index b43d55c2..00000000 --- a/tests/gems/debian/test_index.py +++ /dev/null @@ -1,172 +0,0 @@ -import json -import os.path -from unittest import TestCase -from unittest.mock import Mock, patch, call - -from bauh import __app_name__ -from bauh.gems.debian.index import ApplicationsMapper, ApplicationIndexer -from bauh.gems.debian.model import DebianApplication -from tests.gems.debian import DEBIAN_TESTS_DIR - - -def mock_read_file(fpath: str): - if fpath.endswith('firefox.desktop'): - return """ - [Desktop Entry] - Version=1.0 - Name=Firefox Web Browser - Comment=Browse the World Wide Web - GenericName=Web Browser - Keywords=Internet;WWW;Browser;Web;Explorer - Exec=firefox %u - Terminal=false - X-MultipleArgs=false - Type=Application - Icon=firefox - Categories=GNOME;GTK;Network;WebBrowser; - """ - elif fpath.endswith('synaptic.desktop'): - return """ - [Desktop Entry] - Name=Synaptic Package Manager - GenericName=Package Manager - Comment=Install, remove and upgrade software packages - Exec=synaptic-pkexec - Icon=synaptic - Terminal=false - Type=Application - """ - elif fpath.endswith('no-icon.desktop'): - return """ - [Desktop Entry] - Name=No-icon - Exec=no-icon - Terminal=false - Type=Application - Categories=PackageManager;GTK;System;Settings; - """ - elif fpath.endswith('no-exe.desktop'): - return """ - [Desktop Entry] - Name=No-exe - Terminal=false - Type=Application - Icon=no-exe - Categories=PackageManager;GTK;System;Settings; - """ - elif fpath.endswith('no-display.desktop'): - return """ - [Desktop Entry] - Name=No-display - Exec=no-display - Terminal=false - Type=Application - Icon=no-display - NoDisplay=true - Categories=PackageManager;GTK;System;Settings; - """ - elif fpath.endswith('terminal-app.desktop'): - return """ - [Desktop Entry] - Name=Terminal-App - Exec=terminal-app - Terminal=true - Type=Application - Icon=terminal-app - Categories=PackageManager;GTK;System;Settings; - """ - - -class ApplicationsMapperTest(TestCase): - - def setUp(self): - self.mapper = ApplicationsMapper(logger=Mock(), workers=1) - - @patch(f'{__app_name__}.gems.debian.index.ApplicationsMapper._read_file', side_effect=mock_read_file) - @patch(f'{__app_name__}.gems.debian.index.system.execute', return_value=(0, """ - firefox: /usr/share/applications/firefox.desktop - app-install-data: /usr/share/app-install/desktop/firefox-launchpad-plugin.desktop - app-install-data: /usr/share/app-install/desktop/firefox:firefox.desktop - xfce4-helpers: /usr/share/xfce4/helpers/firefox.desktop - synaptic: /usr/share/applications/synaptic.desktop - no-icon: /usr/share/applications/no-icon.desktop - no-exe: /usr/share/applications/no-exe.desktop - no-display: /usr/share/applications/no-display.desktop - terminal-app: /usr/share/applications/terminal-app.desktop - """)) - def test_map_executable_applications__return_applications_with_exec_and_icon(self, execute: Mock, read_file: Mock): - apps = self.mapper.map_executable_applications() - execute.assert_called_once_with('dpkg-query -S .desktop', shell=True) - read_file.assert_has_calls([call('/usr/share/applications/firefox.desktop'), - call('/usr/share/applications/synaptic.desktop'), - call('/usr/share/applications/no-icon.desktop'), - call('/usr/share/applications/no-exe.desktop')], any_order=True) - - self.assertEqual({ - DebianApplication(name='firefox', exe_path='firefox %u', icon_path='firefox', - categories=('GNOME', 'GTK', 'Network', 'WebBrowser')), - DebianApplication(name='synaptic', exe_path='synaptic-pkexec', icon_path='synaptic', - categories=None) - }, apps) - - -class ApplicationIndexerTest(TestCase): - - def setUp(self): - self.update_idx_file_path = f'{DEBIAN_TESTS_DIR}/resources/apps_idx.json' - self.update_idx_ts_file_path = f'{self.update_idx_file_path}.ts' - self.app_indexer = ApplicationIndexer(logger=Mock(), - index_file_path=self.update_idx_file_path) - - if os.path.exists(self.update_idx_file_path): - os.remove(self.update_idx_file_path) - - def tearDown(self) -> None: - if os.path.exists(self.update_idx_file_path): - os.remove(self.update_idx_file_path) - - if os.path.exists(self.update_idx_ts_file_path): - os.remove(self.update_idx_ts_file_path) - - def test_update_index(self): - apps = { - DebianApplication(name='firefox', exe_path='firefox %u', icon_path='firefox', - categories=('GNOME', 'GTK', 'Network', 'WebBrowser')), - DebianApplication(name='synaptic', exe_path='synaptic-pkexec', icon_path='synaptic', - categories=None) - } - - self.app_indexer.update_index(apps) - - self.assertTrue(os.path.exists(self.update_idx_file_path)) - - with open(self.update_idx_file_path) as f: - index_content = f.read() - - self.assertEqual({'firefox': {'exe_path': 'firefox %u', 'icon_path': 'firefox', - 'categories': ['GNOME', 'GTK', 'Network', 'WebBrowser']}, - 'synaptic': {'exe_path': 'synaptic-pkexec', 'icon_path': 'synaptic', - 'categories': None} - }, json.loads(index_content)) - - self.assertTrue(os.path.isfile(self.update_idx_ts_file_path)) - - with open(self.update_idx_ts_file_path) as f: - ts_str = f.read() - - try: - float(ts_str) - except ValueError: - self.assertFalse(False, "index timestamp must be a float number") - - def test_read_index(self): - self.app_indexer._file_path = f'{DEBIAN_TESTS_DIR}/resources/app_idx_full.json' - - expected = { - DebianApplication(name='firefox', exe_path='firefox %u', icon_path='firefox', - categories=('GNOME', 'GTK', 'Network', 'WebBrowser')), - DebianApplication(name='synaptic', exe_path='synaptic-pkexec', icon_path='synaptic', - categories=None) - } - - self.assertEqual(expected, {app for app in self.app_indexer.read_index()})