mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-12 03:04:16 +02:00
[ui] fix: upgrading: only requesting the root password if required | [flatpak] fix -> crashing when trying to downgrade
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -27,11 +27,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
### Fixes
|
### Fixes
|
||||||
- AppImage
|
- AppImage
|
||||||
- missing **Exec** parameters on generated desktop entries [#152](https://github.com/vinifmor/bauh/issues/152)
|
- missing **Exec** parameters on generated desktop entries [#152](https://github.com/vinifmor/bauh/issues/152)
|
||||||
- Core
|
- crashing when trying to retrieve an AppImage history not available on the database anymore (downgrade is affected as well)
|
||||||
|
- Flatpak
|
||||||
|
- crashing when trying to downgrade (regression introduced in **0.9.9**)
|
||||||
|
- UI
|
||||||
|
- upgrading: only requesting the root password if required [#151](https://github.com/vinifmor/bauh/issues/151)
|
||||||
|
- install/uninstall/downgrade + specific backup settings could lead to crashing
|
||||||
- bauh release notification not working properly
|
- bauh release notification not working properly
|
||||||
- Web:
|
- Web
|
||||||
- installation options window size
|
- installation options window size
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- UI
|
||||||
|
- "backup" dialog is displayed before the "trim" dialog during the upgrade process (if both are enabled)
|
||||||
|
|
||||||
|
|
||||||
## [0.9.9] 2020-12-02
|
## [0.9.9] 2020-12-02
|
||||||
### Features
|
### Features
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import json
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Set, Type, Tuple, Optional
|
from typing import List, Set, Type, Tuple, Optional
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ class UpgradeRequirement:
|
|||||||
class UpgradeRequirements:
|
class UpgradeRequirements:
|
||||||
|
|
||||||
def __init__(self, to_install: Optional[List[UpgradeRequirement]], to_remove: Optional[List[UpgradeRequirement]],
|
def __init__(self, to_install: Optional[List[UpgradeRequirement]], to_remove: Optional[List[UpgradeRequirement]],
|
||||||
to_upgrade: List[UpgradeRequirement], cannot_upgrade: List[UpgradeRequirement]):
|
to_upgrade: List[UpgradeRequirement], cannot_upgrade: Optional[List[UpgradeRequirement]]):
|
||||||
"""
|
"""
|
||||||
:param to_install: additional packages that must be installed with the upgrade
|
:param to_install: additional packages that must be installed with the upgrade
|
||||||
:param to_remove: non upgrading packages that should be removed due to conflicts with upgrading packages
|
:param to_remove: non upgrading packages that should be removed due to conflicts with upgrading packages
|
||||||
@@ -82,6 +83,15 @@ class TransactionResult:
|
|||||||
return TransactionResult(success=False, installed=None, removed=None)
|
return TransactionResult(success=False, installed=None, removed=None)
|
||||||
|
|
||||||
|
|
||||||
|
class SoftwareAction(Enum):
|
||||||
|
PREPARE = 0
|
||||||
|
SEARCH = 1
|
||||||
|
INSTALL = 2
|
||||||
|
UNINSTALL = 3
|
||||||
|
UPGRADE = 4
|
||||||
|
DOWNGRADE = 5
|
||||||
|
|
||||||
|
|
||||||
class SoftwareManager(ABC):
|
class SoftwareManager(ABC):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@@ -95,7 +105,7 @@ class SoftwareManager(ABC):
|
|||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int, is_url: bool) -> SearchResult:
|
def search(self, words: str, disk_loader: Optional[DiskCacheLoader], limit: int, is_url: bool) -> SearchResult:
|
||||||
"""
|
"""
|
||||||
:param words: the words typed by the user
|
:param words: the words typed by the user
|
||||||
:param disk_loader: a running disk loader thread that loads package data from the disk asynchronously
|
:param disk_loader: a running disk loader thread that loads package data from the disk asynchronously
|
||||||
@@ -157,7 +167,7 @@ class SoftwareManager(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def uninstall(self, pkg: SoftwarePackage, root_password: str, watcher: ProcessWatcher, disk_loader: DiskCacheLoader) -> TransactionResult:
|
def uninstall(self, pkg: SoftwarePackage, root_password: str, watcher: ProcessWatcher, disk_loader: Optional[DiskCacheLoader]) -> TransactionResult:
|
||||||
"""
|
"""
|
||||||
:param pkg:
|
:param pkg:
|
||||||
:param root_password: the root user password (if required)
|
:param root_password: the root user password (if required)
|
||||||
@@ -192,7 +202,7 @@ class SoftwareManager(ABC):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def install(self, pkg: SoftwarePackage, root_password: str, disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult:
|
def install(self, pkg: SoftwarePackage, root_password: str, disk_loader: Optional[DiskCacheLoader], watcher: ProcessWatcher) -> TransactionResult:
|
||||||
"""
|
"""
|
||||||
:param pkg:
|
:param pkg:
|
||||||
:param root_password: the root user password (if required)
|
:param root_password: the root user password (if required)
|
||||||
@@ -264,9 +274,9 @@ class SoftwareManager(ABC):
|
|||||||
f.write(icon_bytes)
|
f.write(icon_bytes)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def requires_root(self, action: str, pkg: Optional[SoftwarePackage]):
|
def requires_root(self, action: SoftwareAction, pkg: Optional[SoftwarePackage]) -> bool:
|
||||||
"""
|
"""
|
||||||
if a given action requires root privileges to be executed. Current actions are: 'install', 'uninstall', 'downgrade', 'search', 'refresh', 'prepare'
|
if a given action requires root privileges to be executed. 'install', 'uninstall', 'downgrade', 'search', 'prepare'
|
||||||
:param action:
|
:param action:
|
||||||
:param pkg:
|
:param pkg:
|
||||||
:return:
|
:return:
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from pkg_resources import parse_version
|
|||||||
|
|
||||||
from bauh.api.abstract.context import ApplicationContext
|
from bauh.api.abstract.context import ApplicationContext
|
||||||
from bauh.api.abstract.controller import SoftwareManager, SearchResult, UpgradeRequirements, UpgradeRequirement, \
|
from bauh.api.abstract.controller import SoftwareManager, SearchResult, UpgradeRequirements, UpgradeRequirement, \
|
||||||
TransactionResult
|
TransactionResult, SoftwareAction
|
||||||
from bauh.api.abstract.disk import DiskCacheLoader
|
from bauh.api.abstract.disk import DiskCacheLoader
|
||||||
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
||||||
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
|
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
|
||||||
@@ -416,7 +416,8 @@ class AppImageManager(SoftwareManager):
|
|||||||
app_tuple = cursor.fetchone()
|
app_tuple = cursor.fetchone()
|
||||||
|
|
||||||
if not app_tuple:
|
if not app_tuple:
|
||||||
raise Exception("Could not retrieve {} from the database {}".format(pkg, DB_APPS_PATH))
|
self.logger.warning("Could not retrieve {} from the database {}".format(pkg, DB_APPS_PATH))
|
||||||
|
return res
|
||||||
finally:
|
finally:
|
||||||
self._close_connection(DB_APPS_PATH, connection)
|
self._close_connection(DB_APPS_PATH, connection)
|
||||||
|
|
||||||
@@ -582,7 +583,7 @@ class AppImageManager(SoftwareManager):
|
|||||||
def can_work(self) -> bool:
|
def can_work(self) -> bool:
|
||||||
return self._is_sqlite3_available() and self.file_downloader.can_work()
|
return self._is_sqlite3_available() and self.file_downloader.can_work()
|
||||||
|
|
||||||
def requires_root(self, action: str, pkg: AppImage):
|
def requires_root(self, action: SoftwareAction, pkg: AppImage) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
|
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ appimage.downgrade.first_version={} is in its first published version
|
|||||||
appimage.downgrade.impossible.body={} has only one published version.
|
appimage.downgrade.impossible.body={} has only one published version.
|
||||||
appimage.downgrade.impossible.title=Impossible to downgrade
|
appimage.downgrade.impossible.title=Impossible to downgrade
|
||||||
appimage.downgrade.install_version=It was not possible to install the version {} ({})
|
appimage.downgrade.install_version=It was not possible to install the version {} ({})
|
||||||
appimage.downgrade.unknown_version.body=It was not possible to identify {} current version in its versions history
|
appimage.downgrade.unknown_version.body={} current version was not found in its release history
|
||||||
appimage.error.uninstall_current_version=It was not possible to uninstall the current version of {}
|
appimage.error.uninstall_current_version=It was not possible to uninstall the current version of {}
|
||||||
appimage.history.0_version=version
|
appimage.history.0_version=version
|
||||||
appimage.history.1_published_at=date
|
appimage.history.1_published_at=date
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from typing import List, Set, Type, Tuple, Dict, Iterable, Optional
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext, UpgradeRequirements, \
|
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext, UpgradeRequirements, \
|
||||||
TransactionResult
|
TransactionResult, SoftwareAction
|
||||||
from bauh.api.abstract.disk import DiskCacheLoader
|
from bauh.api.abstract.disk import DiskCacheLoader
|
||||||
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
||||||
from bauh.api.abstract.model import PackageUpdate, PackageHistory, SoftwarePackage, PackageSuggestion, PackageStatus, \
|
from bauh.api.abstract.model import PackageUpdate, PackageHistory, SoftwarePackage, PackageSuggestion, PackageStatus, \
|
||||||
@@ -2476,8 +2476,8 @@ class ArchManager(SoftwareManager):
|
|||||||
def cache_to_disk(self, pkg: ArchPackage, icon_bytes: bytes, only_icon: bool):
|
def cache_to_disk(self, pkg: ArchPackage, icon_bytes: bytes, only_icon: bool):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def requires_root(self, action: str, pkg: ArchPackage):
|
def requires_root(self, action: SoftwareAction, pkg: ArchPackage) -> bool:
|
||||||
if action == 'prepare':
|
if action == SoftwareAction.PREPARE:
|
||||||
arch_config = read_config()
|
arch_config = read_config()
|
||||||
|
|
||||||
if arch_config['refresh_mirrors_startup'] and mirrors.should_sync(self.logger):
|
if arch_config['refresh_mirrors_startup'] and mirrors.should_sync(self.logger):
|
||||||
@@ -2485,7 +2485,7 @@ class ArchManager(SoftwareManager):
|
|||||||
|
|
||||||
return arch_config['sync_databases_startup'] and database.should_sync(arch_config, None, self.logger)
|
return arch_config['sync_databases_startup'] and database.should_sync(arch_config, None, self.logger)
|
||||||
|
|
||||||
return action != 'search'
|
return action != SoftwareAction.SEARCH
|
||||||
|
|
||||||
def _start_category_task(self, task_man: TaskManager):
|
def _start_category_task(self, task_man: TaskManager):
|
||||||
task_man.register_task('arch_aur_cats', self.i18n['task.download_categories'].format('Arch'), get_icon_path())
|
task_man.register_task('arch_aur_cats', self.i18n['task.download_categories'].format('Arch'), get_icon_path())
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from threading import Thread
|
|||||||
from typing import List, Set, Type, Tuple, Optional
|
from typing import List, Set, Type, Tuple, Optional
|
||||||
|
|
||||||
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext, UpgradeRequirements, \
|
from bauh.api.abstract.controller import SearchResult, SoftwareManager, ApplicationContext, UpgradeRequirements, \
|
||||||
UpgradeRequirement, TransactionResult
|
UpgradeRequirement, TransactionResult, SoftwareAction
|
||||||
from bauh.api.abstract.disk import DiskCacheLoader
|
from bauh.api.abstract.disk import DiskCacheLoader
|
||||||
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
||||||
from bauh.api.abstract.model import PackageHistory, PackageUpdate, SoftwarePackage, PackageSuggestion, \
|
from bauh.api.abstract.model import PackageHistory, PackageUpdate, SoftwarePackage, PackageSuggestion, \
|
||||||
@@ -112,7 +112,7 @@ class FlatpakManager(SoftwareManager):
|
|||||||
def _add_updates(self, version: str, output: list):
|
def _add_updates(self, version: str, output: list):
|
||||||
output.append(flatpak.list_updates_as_str(version))
|
output.append(flatpak.list_updates_as_str(version))
|
||||||
|
|
||||||
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult:
|
def read_installed(self, disk_loader: Optional[DiskCacheLoader], limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult:
|
||||||
version = flatpak.get_version()
|
version = flatpak.get_version()
|
||||||
|
|
||||||
updates = []
|
updates = []
|
||||||
@@ -174,7 +174,7 @@ class FlatpakManager(SoftwareManager):
|
|||||||
watcher.change_progress(10)
|
watcher.change_progress(10)
|
||||||
watcher.change_substatus(self.i18n['flatpak.downgrade.commits'])
|
watcher.change_substatus(self.i18n['flatpak.downgrade.commits'])
|
||||||
|
|
||||||
history = self.get_history(pkg)
|
history = self.get_history(pkg, full_commit_str=True)
|
||||||
|
|
||||||
# downgrade is not possible if the app current commit in the first one:
|
# downgrade is not possible if the app current commit in the first one:
|
||||||
if history.pkg_status_idx == len(history.history) - 1:
|
if history.pkg_status_idx == len(history.history) - 1:
|
||||||
@@ -295,9 +295,9 @@ class FlatpakManager(SoftwareManager):
|
|||||||
else:
|
else:
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def get_history(self, pkg: FlatpakApplication) -> PackageHistory:
|
def get_history(self, pkg: FlatpakApplication, full_commit_str: bool = False) -> PackageHistory:
|
||||||
pkg.commit = flatpak.get_commit(pkg.id, pkg.branch, pkg.installation)
|
pkg.commit = flatpak.get_commit(pkg.id, pkg.branch, pkg.installation)
|
||||||
commits = flatpak.get_app_commits_data(pkg.ref, pkg.origin, pkg.installation)
|
commits = flatpak.get_app_commits_data(pkg.ref, pkg.origin, pkg.installation, full_str=full_commit_str)
|
||||||
|
|
||||||
status_idx = 0
|
status_idx = 0
|
||||||
commit_found = False
|
commit_found = False
|
||||||
@@ -444,8 +444,8 @@ class FlatpakManager(SoftwareManager):
|
|||||||
def can_work(self) -> bool:
|
def can_work(self) -> bool:
|
||||||
return flatpak.is_installed()
|
return flatpak.is_installed()
|
||||||
|
|
||||||
def requires_root(self, action: str, pkg: FlatpakApplication):
|
def requires_root(self, action: SoftwareAction, pkg: FlatpakApplication) -> bool:
|
||||||
return action == 'downgrade' and pkg.installation == 'system'
|
return action == SoftwareAction.DOWNGRADE and pkg.installation == 'system'
|
||||||
|
|
||||||
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
|
def prepare(self, task_manager: TaskManager, root_password: str, internet_available: bool):
|
||||||
Thread(target=read_config, args=(True,), daemon=True).start()
|
Thread(target=read_config, args=(True,), daemon=True).start()
|
||||||
|
|||||||
@@ -233,7 +233,7 @@ def downgrade(app_ref: str, commit: str, installation: str, root_password: str)
|
|||||||
wrong_error_phrases={'Warning'})
|
wrong_error_phrases={'Warning'})
|
||||||
|
|
||||||
|
|
||||||
def get_app_commits(app_ref: str, origin: str, installation: str, handler: ProcessHandler) -> List[str]:
|
def get_app_commits(app_ref: str, origin: str, installation: str, handler: ProcessHandler) -> Optional[List[str]]:
|
||||||
try:
|
try:
|
||||||
p = SimpleProcess(['flatpak', 'remote-info', '--log', origin, app_ref, '--{}'.format(installation)])
|
p = SimpleProcess(['flatpak', 'remote-info', '--log', origin, app_ref, '--{}'.format(installation)])
|
||||||
success, output = handler.handle_simple(p)
|
success, output = handler.handle_simple(p)
|
||||||
@@ -245,7 +245,7 @@ def get_app_commits(app_ref: str, origin: str, installation: str, handler: Proce
|
|||||||
raise NoInternetException()
|
raise NoInternetException()
|
||||||
|
|
||||||
|
|
||||||
def get_app_commits_data(app_ref: str, origin: str, installation: str) -> List[dict]:
|
def get_app_commits_data(app_ref: str, origin: str, installation: str, full_str: bool = True) -> List[dict]:
|
||||||
log = run_cmd('{} remote-info --log {} {} --{}'.format('flatpak', origin, app_ref, installation))
|
log = run_cmd('{} remote-info --log {} {} --{}'.format('flatpak', origin, app_ref, installation))
|
||||||
|
|
||||||
if not log:
|
if not log:
|
||||||
@@ -262,7 +262,7 @@ def get_app_commits_data(app_ref: str, origin: str, installation: str) -> List[d
|
|||||||
commit[attr] = data[1].strip()
|
commit[attr] = data[1].strip()
|
||||||
|
|
||||||
if attr == 'commit':
|
if attr == 'commit':
|
||||||
commit[attr] = commit[attr][0:8]
|
commit[attr] = commit[attr] if full_str else commit[attr][0:8]
|
||||||
|
|
||||||
if attr == 'date':
|
if attr == 'date':
|
||||||
commit[attr] = datetime.strptime(commit[attr], '%Y-%m-%d %H:%M:%S +0000')
|
commit[attr] = datetime.strptime(commit[attr], '%Y-%m-%d %H:%M:%S +0000')
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from threading import Thread
|
|||||||
from typing import List, Set, Type, Optional, Tuple
|
from typing import List, Set, Type, Optional, Tuple
|
||||||
|
|
||||||
from bauh.api.abstract.controller import SoftwareManager, SearchResult, ApplicationContext, UpgradeRequirements, \
|
from bauh.api.abstract.controller import SoftwareManager, SearchResult, ApplicationContext, UpgradeRequirements, \
|
||||||
TransactionResult
|
TransactionResult, SoftwareAction
|
||||||
from bauh.api.abstract.disk import DiskCacheLoader
|
from bauh.api.abstract.disk import DiskCacheLoader
|
||||||
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
||||||
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
|
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion, \
|
||||||
@@ -255,8 +255,8 @@ class SnapManager(SoftwareManager):
|
|||||||
def can_work(self) -> bool:
|
def can_work(self) -> bool:
|
||||||
return snap.is_installed()
|
return snap.is_installed()
|
||||||
|
|
||||||
def requires_root(self, action: str, pkg: SnapApplication):
|
def requires_root(self, action: SoftwareAction, pkg: SnapApplication) -> bool:
|
||||||
return action not in ('search', 'prepare')
|
return action not in (SoftwareAction.PREPARE, SoftwareAction.SEARCH)
|
||||||
|
|
||||||
def refresh(self, pkg: SnapApplication, root_password: str, watcher: ProcessWatcher) -> bool:
|
def refresh(self, pkg: SnapApplication, root_password: str, watcher: ProcessWatcher) -> bool:
|
||||||
return ProcessHandler(watcher).handle_simple(snap.refresh_and_stream(pkg.name, root_password))[0]
|
return ProcessHandler(watcher).handle_simple(snap.refresh_and_stream(pkg.name, root_password))[0]
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ from colorama import Fore
|
|||||||
from requests import exceptions, Response
|
from requests import exceptions, Response
|
||||||
|
|
||||||
from bauh.api.abstract.context import ApplicationContext
|
from bauh.api.abstract.context import ApplicationContext
|
||||||
from bauh.api.abstract.controller import SoftwareManager, SearchResult, UpgradeRequirements, TransactionResult
|
from bauh.api.abstract.controller import SoftwareManager, SearchResult, UpgradeRequirements, TransactionResult, \
|
||||||
|
SoftwareAction
|
||||||
from bauh.api.abstract.disk import DiskCacheLoader
|
from bauh.api.abstract.disk import DiskCacheLoader
|
||||||
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
||||||
from bauh.api.abstract.model import SoftwarePackage, CustomSoftwareAction, PackageSuggestion, PackageUpdate, \
|
from bauh.api.abstract.model import SoftwarePackage, CustomSoftwareAction, PackageSuggestion, PackageUpdate, \
|
||||||
@@ -801,7 +802,7 @@ class WebApplicationManager(SoftwareManager):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def requires_root(self, action: str, pkg: SoftwarePackage):
|
def requires_root(self, action: SoftwareAction, pkg: SoftwarePackage) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _update_env_settings(self, task_manager: TaskManager = None):
|
def _update_env_settings(self, task_manager: TaskManager = None):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from threading import Thread
|
|||||||
from typing import List, Set, Type, Tuple, Dict
|
from typing import List, Set, Type, Tuple, Dict
|
||||||
|
|
||||||
from bauh.api.abstract.controller import SoftwareManager, SearchResult, ApplicationContext, UpgradeRequirements, \
|
from bauh.api.abstract.controller import SoftwareManager, SearchResult, ApplicationContext, UpgradeRequirements, \
|
||||||
UpgradeRequirement, TransactionResult
|
UpgradeRequirement, TransactionResult, SoftwareAction
|
||||||
from bauh.api.abstract.disk import DiskCacheLoader
|
from bauh.api.abstract.disk import DiskCacheLoader
|
||||||
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
||||||
from bauh.api.abstract.model import SoftwarePackage, PackageUpdate, PackageHistory, PackageSuggestion, \
|
from bauh.api.abstract.model import SoftwarePackage, PackageUpdate, PackageHistory, PackageSuggestion, \
|
||||||
@@ -151,14 +151,14 @@ class GenericSoftwareManager(SoftwareManager):
|
|||||||
res.installed.extend(apps_found.installed)
|
res.installed.extend(apps_found.installed)
|
||||||
res.new.extend(apps_found.new)
|
res.new.extend(apps_found.new)
|
||||||
|
|
||||||
def search(self, word: str, disk_loader: DiskCacheLoader = None, limit: int = -1, is_url: bool = False) -> SearchResult:
|
def search(self, words: str, disk_loader: DiskCacheLoader = None, limit: int = -1, is_url: bool = False) -> SearchResult:
|
||||||
ti = time.time()
|
ti = time.time()
|
||||||
self._wait_to_be_ready()
|
self._wait_to_be_ready()
|
||||||
|
|
||||||
res = SearchResult([], [], 0)
|
res = SearchResult([], [], 0)
|
||||||
|
|
||||||
if self.context.is_internet_available():
|
if self.context.is_internet_available():
|
||||||
norm_word = word.strip().lower()
|
norm_word = words.strip().lower()
|
||||||
|
|
||||||
url_words = RE_IS_URL.match(norm_word)
|
url_words = RE_IS_URL.match(norm_word)
|
||||||
disk_loader = self.disk_loader_factory.new()
|
disk_loader = self.disk_loader_factory.new()
|
||||||
@@ -385,7 +385,7 @@ class GenericSoftwareManager(SoftwareManager):
|
|||||||
if man:
|
if man:
|
||||||
return man.cache_to_disk(pkg, icon_bytes=icon_bytes, only_icon=only_icon)
|
return man.cache_to_disk(pkg, icon_bytes=icon_bytes, only_icon=only_icon)
|
||||||
|
|
||||||
def requires_root(self, action: str, app: SoftwarePackage) -> bool:
|
def requires_root(self, action: SoftwareAction, app: SoftwarePackage) -> bool:
|
||||||
if app is None:
|
if app is None:
|
||||||
if self.managers:
|
if self.managers:
|
||||||
for man in self.managers:
|
for man in self.managers:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QSizePolicy, QTableWid
|
|||||||
|
|
||||||
from bauh import __app_name__
|
from bauh import __app_name__
|
||||||
from bauh.api.abstract.context import ApplicationContext
|
from bauh.api.abstract.context import ApplicationContext
|
||||||
from bauh.api.abstract.controller import SoftwareManager
|
from bauh.api.abstract.controller import SoftwareManager, SoftwareAction
|
||||||
from bauh.api.abstract.handler import TaskManager
|
from bauh.api.abstract.handler import TaskManager
|
||||||
from bauh.view.qt.components import new_spacer, QCustomToolbar
|
from bauh.view.qt.components import new_spacer, QCustomToolbar
|
||||||
from bauh.view.qt.qt_utils import centralize
|
from bauh.view.qt.qt_utils import centralize
|
||||||
@@ -51,7 +51,7 @@ class Prepare(QThread, TaskManager):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
root_pwd = None
|
root_pwd = None
|
||||||
if self.manager.requires_root('prepare', None):
|
if self.manager.requires_root(SoftwareAction.PREPARE, None):
|
||||||
ok, root_pwd = self.ask_password()
|
ok, root_pwd = self.ask_password()
|
||||||
|
|
||||||
if not ok:
|
if not ok:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from PyQt5.QtWidgets import QWidget
|
|||||||
|
|
||||||
from bauh import LOGS_PATH
|
from bauh import LOGS_PATH
|
||||||
from bauh.api.abstract.cache import MemoryCache
|
from bauh.api.abstract.cache import MemoryCache
|
||||||
from bauh.api.abstract.controller import SoftwareManager, UpgradeRequirement, UpgradeRequirements
|
from bauh.api.abstract.controller import SoftwareManager, UpgradeRequirement, UpgradeRequirements, SoftwareAction
|
||||||
from bauh.api.abstract.handler import ProcessWatcher
|
from bauh.api.abstract.handler import ProcessWatcher
|
||||||
from bauh.api.abstract.model import PackageStatus, SoftwarePackage, CustomSoftwareAction
|
from bauh.api.abstract.model import PackageStatus, SoftwarePackage, CustomSoftwareAction
|
||||||
from bauh.api.abstract.view import MessageType, MultipleSelectComponent, InputOption, TextComponent, \
|
from bauh.api.abstract.view import MessageType, MultipleSelectComponent, InputOption, TextComponent, \
|
||||||
@@ -29,7 +29,7 @@ from bauh.view.qt import commons
|
|||||||
from bauh.view.qt.view_model import PackageView, PackageViewStatus
|
from bauh.view.qt.view_model import PackageView, PackageViewStatus
|
||||||
from bauh.view.util.translation import I18n
|
from bauh.view.util.translation import I18n
|
||||||
|
|
||||||
RE_VERSION_IN_NAME = re.compile(r'\s+version\s+[\w\.]+\s*$')
|
RE_VERSION_IN_NAME = re.compile(r'\s+version\s+[\w.]+\s*$')
|
||||||
|
|
||||||
|
|
||||||
class AsyncAction(QThread, ProcessWatcher):
|
class AsyncAction(QThread, ProcessWatcher):
|
||||||
@@ -48,7 +48,7 @@ class AsyncAction(QThread, ProcessWatcher):
|
|||||||
super(AsyncAction, self).__init__()
|
super(AsyncAction, self).__init__()
|
||||||
self.wait_confirmation = False
|
self.wait_confirmation = False
|
||||||
self.confirmation_res = None
|
self.confirmation_res = None
|
||||||
self.root_password = None
|
self.root_password = root_password
|
||||||
self.stop = False
|
self.stop = False
|
||||||
|
|
||||||
def request_confirmation(self, title: str, body: str, components: List[ViewComponent] = None,
|
def request_confirmation(self, title: str, body: str, components: List[ViewComponent] = None,
|
||||||
@@ -123,64 +123,78 @@ class AsyncAction(QThread, ProcessWatcher):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _generate_backup(self, app_config: dict, i18n: I18n, root_password: str) -> bool:
|
def _generate_backup(self, app_config: dict, i18n: I18n, root_password: Optional[str]) -> bool:
|
||||||
if timeshift.is_available():
|
|
||||||
if app_config['backup']['mode'] not in ('only_one', 'incremental'):
|
if app_config['backup']['mode'] not in ('only_one', 'incremental'):
|
||||||
self.show_message(title=self.i18n['error'].capitalize(),
|
self.show_message(title=self.i18n['error'].capitalize(),
|
||||||
body='{}: {}'.format(self.i18n['action.backup.invalid_mode'], bold(app_config['backup']['mode'])),
|
body='{}: {}'.format(self.i18n['action.backup.invalid_mode'],bold(app_config['backup']['mode'])),
|
||||||
type_=MessageType.ERROR)
|
type_=MessageType.ERROR)
|
||||||
return False
|
self.change_substatus('')
|
||||||
|
|
||||||
if not user.is_root() and not root_password:
|
|
||||||
root_pwd, valid = self.request_root_password()
|
|
||||||
else:
|
|
||||||
root_pwd, valid = root_password, True
|
|
||||||
|
|
||||||
if not valid:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
handler = ProcessHandler(self)
|
handler = ProcessHandler(self)
|
||||||
if app_config['backup']['mode'] == 'only_one':
|
if app_config['backup']['mode'] == 'only_one':
|
||||||
self.change_substatus('[{}] {}'.format(i18n['core.config.tab.backup'].lower(), i18n['action.backup.substatus.delete']))
|
self.change_substatus('[{}] {}'.format(i18n['core.config.tab.backup'].lower(), i18n['action.backup.substatus.delete']))
|
||||||
deleted, _ = handler.handle_simple(timeshift.delete_all_snapshots(root_pwd))
|
deleted, _ = handler.handle_simple(timeshift.delete_all_snapshots(root_password))
|
||||||
|
|
||||||
if not deleted and not self.request_confirmation(title=i18n['core.config.tab.backup'],
|
if not deleted and not self.request_confirmation(title=i18n['core.config.tab.backup'],
|
||||||
body='{}. {}'.format(i18n['action.backup.error.delete'], i18n['action.backup.error.proceed']),
|
body='{}. {}'.format(i18n['action.backup.error.delete'],
|
||||||
|
i18n['action.backup.error.proceed']),
|
||||||
confirmation_label=i18n['yes'].capitalize(),
|
confirmation_label=i18n['yes'].capitalize(),
|
||||||
deny_label=i18n['no'].capitalize()):
|
deny_label=i18n['no'].capitalize()):
|
||||||
|
self.change_substatus('')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.change_substatus('[{}] {}'.format(i18n['core.config.tab.backup'].lower(), i18n['action.backup.substatus.create']))
|
self.change_substatus('[{}] {}'.format(i18n['core.config.tab.backup'].lower(), i18n['action.backup.substatus.create']))
|
||||||
created, _ = handler.handle_simple(timeshift.create_snapshot(root_pwd, app_config['backup']['type']))
|
created, _ = handler.handle_simple(timeshift.create_snapshot(root_password, app_config['backup']['type']))
|
||||||
|
|
||||||
if not created and not self.request_confirmation(title=i18n['core.config.tab.backup'],
|
if not created and not self.request_confirmation(title=i18n['core.config.tab.backup'],
|
||||||
body='{}. {}'.format(i18n['action.backup.error.create'],
|
body='{}. {}'.format(i18n['action.backup.error.create'],
|
||||||
i18n['action.backup.error.proceed']),
|
i18n['action.backup.error.proceed']),
|
||||||
confirmation_label=i18n['yes'].capitalize(),
|
confirmation_label=i18n['yes'].capitalize(),
|
||||||
deny_label=i18n['no'].capitalize()):
|
deny_label=i18n['no'].capitalize()):
|
||||||
|
self.change_substatus('')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
self.change_substatus('')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def request_backup(self, app_config: dict, key: str, i18n: I18n, root_password: str = None) -> bool:
|
def _check_backup_requirements(self, app_config: dict, pkg: Optional[PackageView], action_key: Optional[str]) -> bool:
|
||||||
if bool(app_config['backup']['enabled']) and timeshift.is_available():
|
if pkg and not pkg.model.supports_backup():
|
||||||
val = app_config['backup'][key] if key else None
|
return False
|
||||||
|
|
||||||
if val is None: # ask mode
|
if action_key and app_config['backup'][action_key] is False:
|
||||||
if self.request_confirmation(title=i18n['core.config.tab.backup'],
|
return False
|
||||||
|
|
||||||
|
return bool(app_config['backup']['enabled']) and timeshift.is_available()
|
||||||
|
|
||||||
|
def _should_backup(self, action_key: str, app_config: dict, i18n: I18n) -> bool:
|
||||||
|
# backup -> true: do not ask, only execute | false: do not ask or execute | None: ask
|
||||||
|
backup = app_config['backup'][action_key] if action_key else None
|
||||||
|
|
||||||
|
if backup is None:
|
||||||
|
return self.request_confirmation(title=i18n['core.config.tab.backup'],
|
||||||
body=i18n['action.backup.msg'],
|
body=i18n['action.backup.msg'],
|
||||||
confirmation_label=i18n['yes'].capitalize(),
|
confirmation_label=i18n['yes'].capitalize(),
|
||||||
deny_label=i18n['no'].capitalize()):
|
deny_label=i18n['no'].capitalize())
|
||||||
res = self._generate_backup(app_config, i18n, root_password)
|
else:
|
||||||
self.change_substatus('')
|
return backup
|
||||||
return res
|
|
||||||
|
|
||||||
elif val is True: # direct mode
|
def request_backup(self, action_key: Optional[str], pkg: Optional[PackageView], i18n: I18n, app_config: dict, root_password: Optional[str], backup_only: bool = False) -> Tuple[bool, Optional[str]]:
|
||||||
res = self._generate_backup(app_config, i18n, root_password)
|
if not backup_only:
|
||||||
self.change_substatus('')
|
if not self._check_backup_requirements(app_config=app_config, pkg=pkg, action_key=action_key):
|
||||||
return res
|
return True, root_password
|
||||||
|
|
||||||
return True
|
if not self._should_backup(action_key=action_key, app_config=app_config, i18n=i18n):
|
||||||
|
return True, root_password
|
||||||
|
|
||||||
|
pwd = root_password
|
||||||
|
if not user.is_root() and pwd is None:
|
||||||
|
valid_password, pwd = self.request_root_password()
|
||||||
|
|
||||||
|
if not valid_password:
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
return self._generate_backup(app_config=app_config, i18n=i18n, root_password=pwd), pwd
|
||||||
|
|
||||||
|
|
||||||
class UpgradeSelected(AsyncAction):
|
class UpgradeSelected(AsyncAction):
|
||||||
@@ -373,15 +387,29 @@ class UpgradeSelected(AsyncAction):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
root_user = user.is_root()
|
||||||
|
to_update, upgrade_requires_root, bkp_supported = [], False, False
|
||||||
|
|
||||||
|
for pkg in self.pkgs:
|
||||||
|
if pkg.model.update and not pkg.model.is_update_ignored() and pkg.update_checked:
|
||||||
|
to_update.append(pkg)
|
||||||
|
|
||||||
|
if not bkp_supported and pkg.model.supports_backup():
|
||||||
|
bkp_supported = True
|
||||||
|
|
||||||
|
if not root_user and not upgrade_requires_root and self.manager.requires_root(SoftwareAction.UPGRADE, pkg.model):
|
||||||
|
upgrade_requires_root = True
|
||||||
|
|
||||||
|
if upgrade_requires_root:
|
||||||
valid_password, root_password = self._request_password()
|
valid_password, root_password = self._request_password()
|
||||||
|
else:
|
||||||
|
valid_password, root_password = True, None
|
||||||
|
|
||||||
if not valid_password:
|
if not valid_password:
|
||||||
self.notify_finished({'success': False, 'updated': 0, 'types': set(), 'id': None})
|
self.notify_finished({'success': False, 'updated': 0, 'types': set(), 'id': None})
|
||||||
self.pkgs = None
|
self.pkgs = None
|
||||||
return
|
return
|
||||||
|
|
||||||
to_update = [pkg for pkg in self.pkgs if pkg.model.update and not pkg.model.is_update_ignored() and pkg.update_checked]
|
|
||||||
|
|
||||||
if len(to_update) > 1:
|
if len(to_update) > 1:
|
||||||
self.disable_progress_controll()
|
self.disable_progress_controll()
|
||||||
else:
|
else:
|
||||||
@@ -440,24 +468,35 @@ class UpgradeSelected(AsyncAction):
|
|||||||
|
|
||||||
app_config = read_config()
|
app_config = read_config()
|
||||||
|
|
||||||
# trim dialog
|
# backup dialog ( if enabled, supported and accepted )
|
||||||
|
should_backup = bkp_supported
|
||||||
|
should_backup = should_backup and self._check_backup_requirements(app_config=app_config, pkg=None, action_key='upgrade')
|
||||||
|
should_backup = should_backup and self._should_backup(action_key='upgrade', app_config=app_config, i18n=self.i18n)
|
||||||
|
|
||||||
|
# trim dialog ( if enabled and accepted )
|
||||||
if app_config['disk']['trim']['after_upgrade'] is not False:
|
if app_config['disk']['trim']['after_upgrade'] is not False:
|
||||||
should_trim = app_config['disk']['trim']['after_upgrade'] or self._ask_for_trim()
|
should_trim = app_config['disk']['trim']['after_upgrade'] or self._ask_for_trim()
|
||||||
else:
|
else:
|
||||||
should_trim = False
|
should_trim = False
|
||||||
|
|
||||||
# backup process ( if enabled, supported and accepted )
|
if should_trim and not root_user and root_password is None: # trim requires root and the password might have not being asked yet
|
||||||
if bool(app_config['backup']['enabled']) and app_config['backup']['upgrade'] in (True, None) and timeshift.is_available():
|
valid_password, root_password = self._request_password()
|
||||||
any_requires_bkp = False
|
|
||||||
|
|
||||||
for dep in requirements.to_upgrade:
|
if not valid_password:
|
||||||
if dep.pkg.supports_backup():
|
self.notify_finished({'success': False, 'updated': 0, 'types': set(), 'id': None})
|
||||||
any_requires_bkp = True
|
self.pkgs = None
|
||||||
break
|
return
|
||||||
|
|
||||||
if any_requires_bkp:
|
# performing backup
|
||||||
if not self.request_backup(app_config, 'upgrade', self.i18n, root_password):
|
if should_backup:
|
||||||
self.notify_finished({'success': success, 'updated': updated, 'types': updated_types, 'id': None})
|
proceed, root_password = self.request_backup(action_key='upgrade',
|
||||||
|
app_config=app_config,
|
||||||
|
i18n=self.i18n,
|
||||||
|
root_password=root_password,
|
||||||
|
pkg=None,
|
||||||
|
backup_only=True)
|
||||||
|
if not proceed:
|
||||||
|
self.notify_finished({'success': False, 'updated': 0, 'types': set(), 'id': None})
|
||||||
self.pkgs = None
|
self.pkgs = None
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -497,7 +536,8 @@ class RefreshApps(AsyncAction):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
res = self.manager.read_installed(pkg_types=self.pkg_types)
|
res = self.manager.read_installed(pkg_types=self.pkg_types, disk_loader=None, only_apps=False,
|
||||||
|
internet_available=True, limit=-1)
|
||||||
refreshed_types = set()
|
refreshed_types = set()
|
||||||
|
|
||||||
if res:
|
if res:
|
||||||
@@ -528,9 +568,13 @@ class UninstallPackage(AsyncAction):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.pkg:
|
if self.pkg:
|
||||||
if self.pkg.model.supports_backup():
|
proceed, _ = self.request_backup(action_key='uninstall',
|
||||||
if not self.request_backup(read_config(), 'uninstall', self.i18n, self.root_pwd):
|
pkg=self.pkg,
|
||||||
self.notify_finished(False)
|
i18n=self.i18n,
|
||||||
|
root_password=self.root_pwd,
|
||||||
|
app_config=read_config())
|
||||||
|
if not proceed:
|
||||||
|
self.notify_finished({'success': False, 'removed': None, 'pkg': self.pkg})
|
||||||
self.pkg = None
|
self.pkg = None
|
||||||
self.root_pwd = None
|
self.root_pwd = None
|
||||||
return
|
return
|
||||||
@@ -567,8 +611,13 @@ class DowngradePackage(AsyncAction):
|
|||||||
if self.pkg:
|
if self.pkg:
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
if self.pkg.model.supports_backup():
|
proceed, _ = self.request_backup(action_key='downgrade',
|
||||||
if not self.request_backup(read_config(), 'downgrade', self.i18n, self.root_pwd):
|
pkg=self.pkg,
|
||||||
|
i18n=self.i18n,
|
||||||
|
root_password=self.root_pwd,
|
||||||
|
app_config=read_config())
|
||||||
|
|
||||||
|
if not proceed:
|
||||||
self.notify_finished({'app': self.pkg, 'success': success})
|
self.notify_finished({'app': self.pkg, 'success': success})
|
||||||
self.pkg = None
|
self.pkg = None
|
||||||
self.root_pwd = None
|
self.root_pwd = None
|
||||||
@@ -630,7 +679,7 @@ class SearchPackages(AsyncAction):
|
|||||||
|
|
||||||
if self.word:
|
if self.word:
|
||||||
try:
|
try:
|
||||||
res = self.manager.search(self.word)
|
res = self.manager.search(words=self.word, disk_loader=None, limit=-1, is_url=False)
|
||||||
search_res['pkgs_found'].extend(res.installed)
|
search_res['pkgs_found'].extend(res.installed)
|
||||||
search_res['pkgs_found'].extend(res.new)
|
search_res['pkgs_found'].extend(res.new)
|
||||||
except NoInternetException:
|
except NoInternetException:
|
||||||
@@ -654,9 +703,16 @@ class InstallPackage(AsyncAction):
|
|||||||
if self.pkg:
|
if self.pkg:
|
||||||
res = {'success': False, 'installed': None, 'removed': None, 'pkg': self.pkg}
|
res = {'success': False, 'installed': None, 'removed': None, 'pkg': self.pkg}
|
||||||
|
|
||||||
if self.pkg.model.supports_backup():
|
proceed, _ = self.request_backup(action_key='install',
|
||||||
if not self.request_backup(read_config(), 'install', self.i18n, self.root_pwd):
|
pkg=self.pkg,
|
||||||
|
i18n=self.i18n,
|
||||||
|
root_password=self.root_pwd,
|
||||||
|
app_config=read_config())
|
||||||
|
|
||||||
|
if not proceed:
|
||||||
self.signal_finished.emit(res)
|
self.signal_finished.emit(res)
|
||||||
|
self.pkg = None
|
||||||
|
self.root_pwd = None
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -834,7 +890,7 @@ class ListWarnings(QThread):
|
|||||||
self.man = man
|
self.man = man
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
warnings = self.man.list_warnings()
|
warnings = self.man.list_warnings(internet_available=True)
|
||||||
if warnings:
|
if warnings:
|
||||||
self.signal_warnings.emit(warnings)
|
self.signal_warnings.emit(warnings)
|
||||||
|
|
||||||
@@ -949,8 +1005,12 @@ class CustomAction(AsyncAction):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if self.custom_action.backup:
|
if self.custom_action.backup:
|
||||||
app_config = read_config()
|
proceed, _ = self.request_backup(app_config=read_config(),
|
||||||
if not self.request_backup(app_config, None, self.i18n, self.root_pwd):
|
action_key=None,
|
||||||
|
i18n=self.i18n,
|
||||||
|
root_password=self.root_pwd,
|
||||||
|
pkg=self.pkg)
|
||||||
|
if not proceed:
|
||||||
self.notify_finished({'success': False, 'pkg': self.pkg, 'action': self.custom_action})
|
self.notify_finished({'success': False, 'pkg': self.pkg, 'action': self.custom_action})
|
||||||
self.pkg = None
|
self.pkg = None
|
||||||
self.custom_action = None
|
self.custom_action = None
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QCheckBox, QHeaderView, QToolB
|
|||||||
from bauh import LOGS_PATH
|
from bauh import LOGS_PATH
|
||||||
from bauh.api.abstract.cache import MemoryCache
|
from bauh.api.abstract.cache import MemoryCache
|
||||||
from bauh.api.abstract.context import ApplicationContext
|
from bauh.api.abstract.context import ApplicationContext
|
||||||
from bauh.api.abstract.controller import SoftwareManager
|
from bauh.api.abstract.controller import SoftwareManager, SoftwareAction
|
||||||
from bauh.api.abstract.model import SoftwarePackage
|
from bauh.api.abstract.model import SoftwarePackage
|
||||||
from bauh.api.abstract.view import MessageType
|
from bauh.api.abstract.view import MessageType
|
||||||
from bauh.api.http import HttpClient
|
from bauh.api.http import HttpClient
|
||||||
@@ -712,7 +712,7 @@ class ManageWindow(QWidget):
|
|||||||
self._finish_search(res)
|
self._finish_search(res)
|
||||||
|
|
||||||
def begin_uninstall(self, pkg: PackageView):
|
def begin_uninstall(self, pkg: PackageView):
|
||||||
pwd, proceed = self._ask_root_password('uninstall', pkg)
|
pwd, proceed = self._ask_root_password(SoftwareAction.UNINSTALL, pkg)
|
||||||
|
|
||||||
if not proceed:
|
if not proceed:
|
||||||
return
|
return
|
||||||
@@ -1160,7 +1160,7 @@ class ManageWindow(QWidget):
|
|||||||
self.progress_controll_enabled = True
|
self.progress_controll_enabled = True
|
||||||
|
|
||||||
def begin_downgrade(self, pkg: PackageView):
|
def begin_downgrade(self, pkg: PackageView):
|
||||||
pwd, proceed = self._ask_root_password('downgrade', pkg)
|
pwd, proceed = self._ask_root_password(SoftwareAction.DOWNGRADE, pkg)
|
||||||
|
|
||||||
if not proceed:
|
if not proceed:
|
||||||
return
|
return
|
||||||
@@ -1281,7 +1281,7 @@ class ManageWindow(QWidget):
|
|||||||
self.comp_manager.restore_state(ACTION_SEARCH)
|
self.comp_manager.restore_state(ACTION_SEARCH)
|
||||||
dialog.show_message(title=self.i18n['warning'].capitalize(), body=self.i18n[res['error']], type_=MessageType.WARNING)
|
dialog.show_message(title=self.i18n['warning'].capitalize(), body=self.i18n[res['error']], type_=MessageType.WARNING)
|
||||||
|
|
||||||
def _ask_root_password(self, action: str, pkg: PackageView) -> Tuple[Optional[str], bool]:
|
def _ask_root_password(self, action: SoftwareAction, pkg: PackageView) -> Tuple[Optional[str], bool]:
|
||||||
pwd = None
|
pwd = None
|
||||||
requires_root = self.manager.requires_root(action, pkg.model)
|
requires_root = self.manager.requires_root(action, pkg.model)
|
||||||
|
|
||||||
@@ -1293,7 +1293,7 @@ class ManageWindow(QWidget):
|
|||||||
return pwd, True
|
return pwd, True
|
||||||
|
|
||||||
def install(self, pkg: PackageView):
|
def install(self, pkg: PackageView):
|
||||||
pwd, proceed = self._ask_root_password('install', pkg)
|
pwd, proceed = self._ask_root_password(SoftwareAction.INSTALL, pkg)
|
||||||
|
|
||||||
if not proceed:
|
if not proceed:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ action.cancelled=l’usuari ha cancel·lat l’operació
|
|||||||
action.disk_trim=Optimizing disc (TRIM)
|
action.disk_trim=Optimizing disc (TRIM)
|
||||||
action.disk_trim.error=There was a problem while optimizing the disk
|
action.disk_trim.error=There was a problem while optimizing the disk
|
||||||
action.failed=L'acció ha fallat
|
action.failed=L'acció ha fallat
|
||||||
action.history.no_history.body=There is no available history for {}
|
action.history.no_history.body=There is no history available for {}
|
||||||
action.history.no_history.title=No history
|
action.history.no_history.title=No history
|
||||||
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
||||||
action.ignore_updates.success=Updates from {} will be ignored from now on
|
action.ignore_updates.success=Updates from {} will be ignored from now on
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ action.cancelled=Aktion vom Nutzer abgebrochen
|
|||||||
action.disk_trim=Optimizing disc (TRIM)
|
action.disk_trim=Optimizing disc (TRIM)
|
||||||
action.disk_trim.error=There was a problem while optimizing the disk
|
action.disk_trim.error=There was a problem while optimizing the disk
|
||||||
action.failed=Aktion fehlgeschlagen
|
action.failed=Aktion fehlgeschlagen
|
||||||
action.history.no_history.body=There is no available history for {}
|
action.history.no_history.body=There is no history available for {}
|
||||||
action.history.no_history.title=No history
|
action.history.no_history.title=No history
|
||||||
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
||||||
action.ignore_updates.success=Updates from {} will be ignored from now on
|
action.ignore_updates.success=Updates from {} will be ignored from now on
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ action.cancelled=operation cancelled by the user
|
|||||||
action.disk_trim.error=There was a problem while optimizing the disk
|
action.disk_trim.error=There was a problem while optimizing the disk
|
||||||
action.disk_trim=Optimizing disc (TRIM)
|
action.disk_trim=Optimizing disc (TRIM)
|
||||||
action.failed=Action failed
|
action.failed=Action failed
|
||||||
action.history.no_history.body=There is no available history for {}
|
action.history.no_history.body=There is no history available for {}
|
||||||
action.history.no_history.title=No history
|
action.history.no_history.title=No history
|
||||||
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
||||||
action.ignore_updates.success=Updates from {} will be ignored from now on
|
action.ignore_updates.success=Updates from {} will be ignored from now on
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ action.cancelled=operación cancelada por el usuario
|
|||||||
action.disk_trim=Optimizando el disco (TRIM)
|
action.disk_trim=Optimizando el disco (TRIM)
|
||||||
action.disk_trim.error=Hubo un problema al optimizar el disco
|
action.disk_trim.error=Hubo un problema al optimizar el disco
|
||||||
action.failed=Acción fallida
|
action.failed=Acción fallida
|
||||||
action.history.no_history.body=There is no available history for {}
|
action.history.no_history.body=No hay historial disponible para {}
|
||||||
action.history.no_history.title=No history
|
action.history.no_history.title=No history
|
||||||
action.ignore_updates.fail=No fue posible ignorar las actualizaciones de {}
|
action.ignore_updates.fail=No fue posible ignorar las actualizaciones de {}
|
||||||
action.ignore_updates.success=Las actualizaciones de {} serán ignoradas de ahora en adelante
|
action.ignore_updates.success=Las actualizaciones de {} serán ignoradas de ahora en adelante
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ action.cancelled=operazione annullata dall'utente
|
|||||||
action.disk_trim=Optimizing disc (TRIM)
|
action.disk_trim=Optimizing disc (TRIM)
|
||||||
action.disk_trim.error=There was a problem while optimizing the disk
|
action.disk_trim.error=There was a problem while optimizing the disk
|
||||||
action.failed=Azione non riuscita
|
action.failed=Azione non riuscita
|
||||||
action.history.no_history.body=There is no available history for {}
|
action.history.no_history.body=There is no history available for {}
|
||||||
action.history.no_history.title=No history
|
action.history.no_history.title=No history
|
||||||
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
||||||
action.ignore_updates.success=Updates from {} will be ignored from now on
|
action.ignore_updates.success=Updates from {} will be ignored from now on
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ action.cancelled=Операция отменена пользователем
|
|||||||
action.disk_trim=Optimizing disc (TRIM)
|
action.disk_trim=Optimizing disc (TRIM)
|
||||||
action.disk_trim.error=There was a problem while optimizing the disk
|
action.disk_trim.error=There was a problem while optimizing the disk
|
||||||
action.failed=Действие не удалось
|
action.failed=Действие не удалось
|
||||||
action.history.no_history.body=There is no available history for {}
|
action.history.no_history.body=There is no history available for {}
|
||||||
action.history.no_history.title=No history
|
action.history.no_history.title=No history
|
||||||
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
action.ignore_updates.fail=It was not possible to ignore updates from {}
|
||||||
action.ignore_updates.success=Updates from {} will be ignored from now on
|
action.ignore_updates.success=Updates from {} will be ignored from now on
|
||||||
|
|||||||
Reference in New Issue
Block a user