mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-09 23:34:17 +02:00
0.10.4
This commit is contained in:
30
CHANGELOG.md
30
CHANGELOG.md
@@ -4,6 +4,36 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [0.10.4] 2022-11-05
|
||||
|
||||
### Improvements
|
||||
- Arch
|
||||
- replaced some system calls by Python calls
|
||||
|
||||
### Fixes
|
||||
- AppImage
|
||||
- some desktop entries not being displayed on the desktop environment menu (requires the AppImage to be reinstalled) [#287](https://github.com/vinifmor/bauh/issues/287)
|
||||
- Arch
|
||||
- not detecting some package replacements when upgrading due to conflict information having logic operators (e.g: `at-spi2-core: 2.44.1 -> 2.46.0` should replace the installed `at-spi2-atk: 2.38`)
|
||||
- not considering some conflict expressions when retrieving upgrade requirements (it could lead to a system breakage depending on the conflict)
|
||||
- Debian
|
||||
- not properly handling packages with names ending with `:i386` [#298](https://github.com/vinifmor/bauh/issues/298)
|
||||
- Packaging
|
||||
- AppImage: download certificate issue [#280](https://github.com/vinifmor/bauh/issues/280)
|
||||
- GUI
|
||||
- initialization panel size not based on the current display device size
|
||||
- management panel:
|
||||
- not fully maximizing
|
||||
- not maximizing based on the current display device size (for multiple display setups)
|
||||
- not respecting a minimal/maximum width based on the current display device size (for multiple display setup)
|
||||
- dialogs not respecting the current display device width
|
||||
- not readjusting size after maximizing/minimizing
|
||||
|
||||
### Localization (i18n)
|
||||
- Italian ([@albanobattistella](https://github.com/albanobattistella), [@luca-digrazia](https://github.com/luca-digrazia))
|
||||
- Turkish ([@agahemir](https://github.com/agahemir))
|
||||
|
||||
|
||||
## [0.10.3] 2022-05-30
|
||||
|
||||
### Features
|
||||
|
||||
@@ -554,6 +554,7 @@ the `view` code is only attached to them (it does not know how the `gems` handle
|
||||
- Separate modules for each packaging technology
|
||||
- Memory and performance improvements
|
||||
- Improve user experience
|
||||
- The current development changes can be checked [here](https://github.com/vinifmor/bauh/blob/staging/CHANGELOG.md)
|
||||
|
||||
#### <a name="donations">Donations</a>
|
||||
- You can support this project through [ko-fi](https://ko-fi.com/vinifmor).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '0.10.3'
|
||||
__version__ = '0.10.4'
|
||||
__app_name__ = 'bauh'
|
||||
|
||||
import os
|
||||
|
||||
@@ -528,13 +528,13 @@ class AppImageManager(SoftwareManager, SettingsController):
|
||||
finally:
|
||||
releases_con.close()
|
||||
|
||||
def _find_desktop_file(self, folder: str) -> str:
|
||||
def _find_desktop_file(self, folder: str) -> Optional[str]:
|
||||
for r, d, files in os.walk(folder):
|
||||
for f in files:
|
||||
if f.endswith('.desktop'):
|
||||
return f
|
||||
|
||||
def _find_icon_file(self, folder: str) -> str:
|
||||
def _find_icon_file(self, folder: str) -> Optional[str]:
|
||||
for f in glob.glob(folder + ('/**' if not folder.endswith('/') else '**'), recursive=True):
|
||||
if RE_ICON_ENDS_WITH.match(f):
|
||||
return f
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import os
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
RE_DESKTOP_EXEC = re.compile(r'(Exec\s*=(.+)(\n?))')
|
||||
RE_DESKTOP_EXEC = re.compile(r'(\n?\s*\w*Exec\s*=(.+))')
|
||||
RE_MANY_SPACES = re.compile(r'\s+')
|
||||
|
||||
|
||||
def find_appimage_file(folder: str) -> str:
|
||||
def find_appimage_file(folder: str) -> Optional[str]:
|
||||
for r, d, files in os.walk(folder):
|
||||
for f in files:
|
||||
if f.lower().endswith('.appimage'):
|
||||
return '{}/{}'.format(folder, f)
|
||||
return f'{folder}/{f}'
|
||||
|
||||
|
||||
def replace_desktop_entry_exec_command(desktop_entry: str, appname: str, file_path: str) -> str:
|
||||
@@ -23,6 +24,11 @@ def replace_desktop_entry_exec_command(desktop_entry: str, appname: str, file_pa
|
||||
|
||||
for exec_groups in execs:
|
||||
full_match = exec_groups[0]
|
||||
|
||||
if full_match.strip().startswith("TryExec"): # TryExec cause issues in some DE to display the app icon
|
||||
final_entry = final_entry.replace(full_match, "")
|
||||
continue
|
||||
|
||||
cmd = RE_MANY_SPACES.sub(' ', exec_groups[1].strip())
|
||||
if cmd:
|
||||
words = cmd.split(' ')
|
||||
@@ -30,12 +36,12 @@ def replace_desktop_entry_exec_command(desktop_entry: str, appname: str, file_pa
|
||||
|
||||
for idx in range(len(words)):
|
||||
if words[idx].lower() == treated_name:
|
||||
words[idx] = '"{}"'.format(file_path)
|
||||
words[idx] = f'"{file_path}"'
|
||||
changed = True
|
||||
break
|
||||
|
||||
if not changed:
|
||||
words = ['"{}"'.format(file_path)]
|
||||
words = [f'"{file_path}"']
|
||||
|
||||
final_entry = final_entry.replace(full_match, full_match.replace(exec_groups[1], ' '.join(words)))
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import re
|
||||
import traceback
|
||||
from logging import Logger
|
||||
from threading import Thread
|
||||
from typing import Set, List, Tuple, Dict, Iterable, Optional, Generator
|
||||
from typing import Set, List, Tuple, Dict, Iterable, Optional, Generator, Pattern
|
||||
|
||||
from bauh.api.abstract.handler import ProcessWatcher
|
||||
from bauh.gems.arch import pacman, message, sorting, confirmation
|
||||
@@ -14,12 +14,20 @@ from bauh.view.util.translation import I18n
|
||||
|
||||
class DependenciesAnalyser:
|
||||
|
||||
_re_dep_operator: Optional[Pattern] = None
|
||||
|
||||
def __init__(self, aur_client: AURClient, i18n: I18n, logger: Logger):
|
||||
self.aur_client = aur_client
|
||||
self.i18n = i18n
|
||||
self.re_dep_operator = re.compile(r'([<>=]+)')
|
||||
self._log = logger
|
||||
|
||||
@classmethod
|
||||
def re_dep_operator(cls) -> Pattern:
|
||||
if not cls._re_dep_operator:
|
||||
cls._re_dep_operator = re.compile(r'([<>=]+)')
|
||||
|
||||
return cls._re_dep_operator
|
||||
|
||||
def _fill_repository(self, name: str, output: List[Tuple[str, str]]):
|
||||
|
||||
repository = pacman.read_repository_from_info(name)
|
||||
@@ -225,7 +233,7 @@ class DependenciesAnalyser:
|
||||
raise Exception(f"Could not retrieve information from providers: "
|
||||
f"{', '.join(data_not_found)}")
|
||||
|
||||
split_informed_dep = self.re_dep_operator.split(dep_exp)
|
||||
split_informed_dep = self.re_dep_operator().split(dep_exp)
|
||||
|
||||
version_required = split_informed_dep[2]
|
||||
exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '=='
|
||||
@@ -237,7 +245,7 @@ class DependenciesAnalyser:
|
||||
info = missing_providers_data[p]
|
||||
|
||||
for provided_exp in info['p']:
|
||||
split_dep = self.re_dep_operator.split(provided_exp)
|
||||
split_dep = self.re_dep_operator().split(provided_exp)
|
||||
|
||||
if len(split_dep) == 3 and split_dep[0] == dep_name:
|
||||
version_provided = split_dep[2]
|
||||
@@ -253,7 +261,7 @@ class DependenciesAnalyser:
|
||||
return
|
||||
else:
|
||||
for _, dep_data in self.aur_client.gen_updates_data((dep_name,)):
|
||||
split_informed_dep = self.re_dep_operator.split(dep_exp)
|
||||
split_informed_dep = self.re_dep_operator().split(dep_exp)
|
||||
version_required = split_informed_dep[2]
|
||||
exp_op = split_informed_dep[1].strip()
|
||||
|
||||
@@ -270,7 +278,7 @@ class DependenciesAnalyser:
|
||||
if dep_name == dep_exp:
|
||||
version_required, exp_op = None, None
|
||||
else:
|
||||
split_informed_dep = self.re_dep_operator.split(dep_exp)
|
||||
split_informed_dep = self.re_dep_operator().split(dep_exp)
|
||||
version_required = split_informed_dep[2]
|
||||
exp_op = split_informed_dep[1] if split_informed_dep[1] != '=' else '=='
|
||||
|
||||
@@ -405,7 +413,7 @@ class DependenciesAnalyser:
|
||||
if dep in pkgs_data:
|
||||
continue
|
||||
if dep not in provided_map:
|
||||
dep_split = self.re_dep_operator.split(dep)
|
||||
dep_split = self.re_dep_operator().split(dep)
|
||||
dep_name = dep_split[0].strip()
|
||||
|
||||
if dep_name not in deps_checked:
|
||||
|
||||
@@ -5,7 +5,7 @@ import shutil
|
||||
import traceback
|
||||
from io import StringIO
|
||||
from threading import Thread
|
||||
from typing import List, Set, Tuple, Dict, Iterable, Optional, Any
|
||||
from typing import List, Set, Tuple, Dict, Iterable, Optional, Any, Pattern, Collection
|
||||
|
||||
from colorama import Fore
|
||||
|
||||
@@ -26,6 +26,7 @@ RE_REMOVE_TRANSITIVE_DEPS = re.compile(r'removing\s([\w\-_]+)\s.+required\sby\s(
|
||||
RE_AVAILABLE_MIRRORS = re.compile(r'.+\s+OK\s+.+\s+(\d+:\d+)\s+.+(http.+)')
|
||||
RE_PACMAN_SYNC_FIRST = re.compile(r'SyncFirst\s*=\s*(.+)')
|
||||
RE_DESKTOP_FILES = re.compile(r'\n?([\w\-_]+)\s+(/usr/share/.+\.desktop)')
|
||||
RE_IGNORED_PACKAGES: Optional[Pattern] = None
|
||||
|
||||
|
||||
def is_available() -> bool:
|
||||
@@ -234,22 +235,27 @@ def sign_key(key: str, root_password: Optional[str]) -> SystemProcess:
|
||||
|
||||
def list_ignored_packages(config_path: str = '/etc/pacman.conf') -> Set[str]:
|
||||
ignored = set()
|
||||
|
||||
try:
|
||||
pacman_conf = new_subprocess(['cat', config_path])
|
||||
grep = new_subprocess(['grep', '-Eo', r'\s*#*\s*ignorepkg\s*=\s*.+'], stdin=pacman_conf.stdout)
|
||||
for o in grep.stdout:
|
||||
if o:
|
||||
line = o.decode().strip()
|
||||
with open(config_path, 'r') as f:
|
||||
file_content = f.read()
|
||||
|
||||
if not line.startswith('#'):
|
||||
ignored.add(line.split('=')[1].strip())
|
||||
global RE_IGNORED_PACKAGES
|
||||
|
||||
pacman_conf.terminate()
|
||||
grep.terminate()
|
||||
return ignored
|
||||
except:
|
||||
if not RE_IGNORED_PACKAGES:
|
||||
RE_IGNORED_PACKAGES = re.compile(r'[\s#]*ignorepkg\s*=\s*.+', re.IGNORECASE)
|
||||
|
||||
for raw_line in RE_IGNORED_PACKAGES.findall(file_content):
|
||||
line = raw_line.strip()
|
||||
|
||||
if line and not line.startswith("#"):
|
||||
ignored.add(line.split("=")[1].strip())
|
||||
except (FileNotFoundError, OSError):
|
||||
pass
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
return ignored
|
||||
|
||||
return ignored
|
||||
|
||||
|
||||
def check_missing(names: Set[str]) -> Set[str]:
|
||||
@@ -1075,3 +1081,18 @@ def map_available_packages() -> Optional[Dict[str, Any]]:
|
||||
'r': package_data[0].strip(),
|
||||
'i': len(package_data) == 4 and 'installed' in package_data[3]}
|
||||
return res
|
||||
|
||||
|
||||
def map_installed(pkgs: Optional[Collection[str]] = None) -> Optional[Dict[str, str]]:
|
||||
output = run_cmd(f"pacman -Q {' '.join({*pkgs} if pkgs else '')}".strip(), print_error=False)
|
||||
|
||||
if output:
|
||||
res = dict()
|
||||
for raw_line in output.split("\n"):
|
||||
line = raw_line.strip()
|
||||
|
||||
if line:
|
||||
pkg_version = line.split(" ")
|
||||
if len(pkg_version) == 2:
|
||||
res[pkg_version[0]] = pkg_version[1]
|
||||
return res
|
||||
|
||||
@@ -22,7 +22,7 @@ class UpdateRequirementsContext:
|
||||
aur_to_update: Dict[str, ArchPackage], repo_to_install: Dict[str, ArchPackage],
|
||||
aur_to_install: Dict[str, ArchPackage], to_install: Dict[str, ArchPackage],
|
||||
pkgs_data: Dict[str, dict], cannot_upgrade: Dict[str, UpgradeRequirement],
|
||||
to_remove: Dict[str, UpgradeRequirement], installed_names: Set[str], provided_map: Dict[str, Set[str]],
|
||||
to_remove: Dict[str, UpgradeRequirement], installed_names: Dict[str, str], provided_map: Dict[str, Set[str]],
|
||||
aur_index: Set[str], arch_config: dict, remote_provided_map: Dict[str, Set[str]], remote_repo_map: Dict[str, str],
|
||||
root_password: Optional[str], aur_supported: bool):
|
||||
self.to_update = to_update
|
||||
@@ -33,7 +33,7 @@ class UpdateRequirementsContext:
|
||||
self.pkgs_data = pkgs_data
|
||||
self.cannot_upgrade = cannot_upgrade
|
||||
self.root_password = root_password
|
||||
self.installed_names = installed_names
|
||||
self.installed = installed_names
|
||||
self.provided_map = provided_map
|
||||
self.to_remove = to_remove
|
||||
self.to_install = to_install
|
||||
@@ -149,12 +149,21 @@ class UpdatesSummarizer:
|
||||
for p, data in context.pkgs_data.items():
|
||||
if data['c']:
|
||||
for c in data['c']:
|
||||
if c and c != p and c in context.installed_names:
|
||||
# source = provided_map[c]
|
||||
root_conflict[c] = p
|
||||
if c:
|
||||
name_op_exp = DependenciesAnalyser.re_dep_operator().split(c)
|
||||
conflict_name = name_op_exp[0]
|
||||
|
||||
if (p, c) in root_conflict.items():
|
||||
mutual_conflicts[c] = p
|
||||
if conflict_name != p:
|
||||
conflict_version = context.installed.get(conflict_name)
|
||||
|
||||
if conflict_version:
|
||||
if len(name_op_exp) == 1 or match_required_version(conflict_version,
|
||||
name_op_exp[1],
|
||||
name_op_exp[2]):
|
||||
root_conflict[conflict_name] = p
|
||||
|
||||
if (p, conflict_name) in root_conflict.items():
|
||||
mutual_conflicts[conflict_name] = p
|
||||
|
||||
if mutual_conflicts:
|
||||
for pkg1, pkg2 in mutual_conflicts.items():
|
||||
@@ -278,8 +287,8 @@ class UpdatesSummarizer:
|
||||
ti = time.time()
|
||||
self.logger.info("Filling provided names")
|
||||
|
||||
if not context.installed_names:
|
||||
context.installed_names = pacman.list_installed_names()
|
||||
if not context.installed:
|
||||
context.installed = pacman.map_installed()
|
||||
|
||||
installed_to_ignore = set()
|
||||
|
||||
@@ -305,8 +314,8 @@ class UpdatesSummarizer:
|
||||
if len(split_provided) > 1 and split_provided[0] != p:
|
||||
pacman.fill_provided_map(split_provided[0], pkgname, context.provided_map)
|
||||
|
||||
if installed_to_ignore: # filling the provided names of the installed
|
||||
installed_to_query = context.installed_names.difference(installed_to_ignore)
|
||||
if context.installed and installed_to_ignore: # filling the provided names of the installed
|
||||
installed_to_query = {*context.installed}.difference(installed_to_ignore)
|
||||
|
||||
if installed_to_query:
|
||||
context.provided_map.update(pacman.map_provided(remote=False, pkgs=installed_to_query))
|
||||
@@ -374,7 +383,7 @@ class UpdatesSummarizer:
|
||||
remote_repo_map = pacman.map_repositories()
|
||||
context = UpdateRequirementsContext(to_update={}, repo_to_update={}, aur_to_update={}, repo_to_install={},
|
||||
aur_to_install={}, to_install={}, pkgs_data={}, cannot_upgrade={},
|
||||
to_remove={}, installed_names=set(), provided_map={}, aur_index=set(),
|
||||
to_remove={}, installed_names=dict(), provided_map={}, aur_index=set(),
|
||||
arch_config=arch_config, root_password=root_password,
|
||||
remote_provided_map=remote_provided_map, remote_repo_map=remote_repo_map,
|
||||
aur_supported=self.aur_supported)
|
||||
@@ -604,7 +613,7 @@ class UpdatesSummarizer:
|
||||
for r in reqs:
|
||||
if r in transaction_pkgs:
|
||||
reqs_in_transaction.add(r)
|
||||
elif r in context.installed_names:
|
||||
elif r in context.installed:
|
||||
reqs_not_in_transaction.add(r)
|
||||
|
||||
if not reqs_not_in_transaction and not reqs_in_transaction:
|
||||
|
||||
@@ -241,7 +241,7 @@ class Aptitude:
|
||||
@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\-_@~.+:]+)'
|
||||
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
|
||||
|
||||
@@ -76,7 +76,6 @@ def new_manage_panel(app_args: Namespace, app_config: dict, logger: logging.Logg
|
||||
manage_window = ManageWindow(i18n=i18n,
|
||||
manager=manager,
|
||||
icon_cache=icon_cache,
|
||||
screen_size=screen_size,
|
||||
config=app_config,
|
||||
context=context,
|
||||
http_client=http_client,
|
||||
@@ -84,8 +83,7 @@ def new_manage_panel(app_args: Namespace, app_config: dict, logger: logging.Logg
|
||||
force_suggestions=force_suggestions,
|
||||
logger=logger)
|
||||
|
||||
prepare = PreparePanel(screen_size=screen_size,
|
||||
context=context,
|
||||
prepare = PreparePanel(context=context,
|
||||
manager=manager,
|
||||
i18n=i18n,
|
||||
manage_window=manage_window,
|
||||
|
||||
@@ -86,7 +86,7 @@ class AdaptableFileDownloader(FileDownloader):
|
||||
return SimpleProcess(cmd=cmd, cwd=cwd, root_password=root_password)
|
||||
|
||||
def _get_wget_process(self, url: str, output_path: str, cwd: str, root_password: Optional[str]) -> SimpleProcess:
|
||||
cmd = ['wget', url, '-c', '--retry-connrefused', '-t', '10', '--no-config', '-nc']
|
||||
cmd = ['wget', url, '-c', '--retry-connrefused', '-t', '10', '-nc']
|
||||
|
||||
if not self.check_ssl:
|
||||
cmd.append('--no-check-certificate')
|
||||
|
||||
@@ -15,6 +15,7 @@ from bauh.api.abstract.model import PackageStatus, CustomSoftwareAction
|
||||
from bauh.commons.html import strip_html, bold
|
||||
from bauh.view.qt.components import IconButton, QCustomMenuAction, QCustomToolbar
|
||||
from bauh.view.qt.dialog import ConfirmationDialog
|
||||
from bauh.view.qt.qt_utils import get_current_screen_geometry
|
||||
from bauh.view.qt.view_model import PackageView
|
||||
from bauh.view.util.translation import I18n
|
||||
|
||||
@@ -68,9 +69,8 @@ class PackagesTable(QTableWidget):
|
||||
COL_NUMBER = 9
|
||||
DEFAULT_ICON_SIZE = QSize(16, 16)
|
||||
|
||||
def __init__(self, parent: QWidget, icon_cache: MemoryCache, download_icons: bool, screen_width: int):
|
||||
def __init__(self, parent: QWidget, icon_cache: MemoryCache, download_icons: bool):
|
||||
super(PackagesTable, self).__init__()
|
||||
self.screen_width = screen_width
|
||||
self.setObjectName('table_packages')
|
||||
self.setParent(parent)
|
||||
self.window = parent
|
||||
@@ -180,15 +180,16 @@ class PackagesTable(QTableWidget):
|
||||
action=custom_action)
|
||||
|
||||
def refresh(self, pkg: PackageView):
|
||||
self._update_row(pkg, update_check_enabled=False, change_update_col=False)
|
||||
screen_width = get_current_screen_geometry(self.parent()).width()
|
||||
self._update_row(pkg, screen_width, update_check_enabled=False, change_update_col=False)
|
||||
|
||||
def update_package(self, pkg: PackageView, change_update_col: bool = False):
|
||||
def update_package(self, pkg: PackageView, screen_width: int, change_update_col: bool = False):
|
||||
if self.download_icons and pkg.model.icon_url:
|
||||
icon_request = QNetworkRequest(QUrl(pkg.model.icon_url))
|
||||
icon_request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True)
|
||||
self.network_man.get(icon_request)
|
||||
|
||||
self._update_row(pkg, change_update_col=change_update_col)
|
||||
self._update_row(pkg, screen_width, change_update_col=change_update_col)
|
||||
|
||||
def _uninstall(self, pkg: PackageView):
|
||||
if ConfirmationDialog(title=self.i18n['manage_window.apps_table.row.actions.uninstall.popup.title'],
|
||||
@@ -255,6 +256,7 @@ class PackagesTable(QTableWidget):
|
||||
self.setEnabled(True)
|
||||
|
||||
if pkgs:
|
||||
screen_width = get_current_screen_geometry(self.parent()).width()
|
||||
self.setColumnCount(self.COL_NUMBER if update_check_enabled else self.COL_NUMBER - 1)
|
||||
self.setRowCount(len(pkgs))
|
||||
|
||||
@@ -266,16 +268,17 @@ class PackagesTable(QTableWidget):
|
||||
icon_request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True)
|
||||
self.network_man.get(icon_request)
|
||||
|
||||
self._update_row(pkg, update_check_enabled)
|
||||
self._update_row(pkg, screen_width, update_check_enabled)
|
||||
|
||||
self.scrollToTop()
|
||||
|
||||
def _update_row(self, pkg: PackageView, update_check_enabled: bool = True, change_update_col: bool = True):
|
||||
def _update_row(self, pkg: PackageView, screen_width: int,
|
||||
update_check_enabled: bool = True, change_update_col: bool = True):
|
||||
self._set_col_icon(0, pkg)
|
||||
self._set_col_name(1, pkg)
|
||||
self._set_col_version(2, pkg)
|
||||
self._set_col_description(3, pkg)
|
||||
self._set_col_publisher(4, pkg)
|
||||
self._set_col_name(1, pkg, screen_width)
|
||||
self._set_col_version(2, pkg, screen_width)
|
||||
self._set_col_description(3, pkg, screen_width)
|
||||
self._set_col_publisher(4, pkg, screen_width)
|
||||
self._set_col_type(5, pkg)
|
||||
self._set_col_installed(6, pkg)
|
||||
self._set_col_actions(7, pkg)
|
||||
@@ -355,7 +358,7 @@ class PackagesTable(QTableWidget):
|
||||
col_type_icon.setToolTip(icon_data['tip'])
|
||||
self.setCellWidget(pkg.table_index, col, col_type_icon)
|
||||
|
||||
def _set_col_version(self, col: int, pkg: PackageView):
|
||||
def _set_col_version(self, col: int, pkg: PackageView, screen_width: int):
|
||||
label_version = QLabel(str(pkg.model.version if pkg.model.version else '?'))
|
||||
label_version.setObjectName('app_version')
|
||||
label_version.setAlignment(Qt.AlignCenter)
|
||||
@@ -383,7 +386,7 @@ class PackagesTable(QTableWidget):
|
||||
f"{self.i18n['version.latest']}: {pkg.model.latest_version})"
|
||||
label_version.setText(f"{label_version.text()} > {pkg.model.latest_version}")
|
||||
|
||||
if label_version.sizeHint().width() / self.screen_width > 0.22:
|
||||
if label_version.sizeHint().width() / screen_width > 0.22:
|
||||
label_version.setText(pkg.model.latest_version)
|
||||
|
||||
item.setToolTip(tooltip)
|
||||
@@ -426,7 +429,7 @@ class PackagesTable(QTableWidget):
|
||||
self._update_icon(col_icon, icon)
|
||||
self.setCellWidget(pkg.table_index, col, col_icon)
|
||||
|
||||
def _set_col_name(self, col: int, pkg: PackageView):
|
||||
def _set_col_name(self, col: int, pkg: PackageView, screen_width: int):
|
||||
col_name = QLabel()
|
||||
col_name.setObjectName('app_name')
|
||||
col_name.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
|
||||
@@ -439,7 +442,7 @@ class PackagesTable(QTableWidget):
|
||||
col_name.setToolTip(self.i18n['app.name'].lower())
|
||||
|
||||
col_name.setText(name)
|
||||
screen_perc = col_name.sizeHint().width() / self.screen_width
|
||||
screen_perc = col_name.sizeHint().width() / screen_width
|
||||
|
||||
if screen_perc > 0.15:
|
||||
max_chars = int(len(name) * 0.15 / screen_perc) - 3
|
||||
@@ -454,7 +457,7 @@ class PackagesTable(QTableWidget):
|
||||
sizes = icon.availableSizes()
|
||||
return sizes[-1] if sizes else self.DEFAULT_ICON_SIZE
|
||||
|
||||
def _set_col_description(self, col: int, pkg: PackageView):
|
||||
def _set_col_description(self, col: int, pkg: PackageView, screen_width: int):
|
||||
item = QLabel()
|
||||
item.setObjectName('app_description')
|
||||
|
||||
@@ -468,7 +471,7 @@ class PackagesTable(QTableWidget):
|
||||
|
||||
item.setText(desc)
|
||||
|
||||
current_width_perc = item.sizeHint().width() / self.screen_width
|
||||
current_width_perc = item.sizeHint().width() / screen_width
|
||||
if current_width_perc > 0.18:
|
||||
max_width = int(len(desc) * 0.18 / current_width_perc) - 3
|
||||
desc = desc[0:max_width] + '...'
|
||||
@@ -479,7 +482,7 @@ class PackagesTable(QTableWidget):
|
||||
|
||||
self.setCellWidget(pkg.table_index, col, item)
|
||||
|
||||
def _set_col_publisher(self, col: int, pkg: PackageView):
|
||||
def _set_col_publisher(self, col: int, pkg: PackageView, screen_width: int):
|
||||
item = QToolBar()
|
||||
|
||||
publisher = pkg.model.get_publisher()
|
||||
@@ -494,7 +497,7 @@ class PackagesTable(QTableWidget):
|
||||
|
||||
if publisher:
|
||||
lb_name.setText(publisher)
|
||||
screen_perc = lb_name.sizeHint().width() / self.screen_width
|
||||
screen_perc = lb_name.sizeHint().width() / screen_width
|
||||
|
||||
if screen_perc > 0.12:
|
||||
max_chars = int(len(publisher) * 0.12 / screen_perc) - 3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from collections.abc import Iterable
|
||||
|
||||
from PyQt5.QtCore import QSize, Qt
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QIcon, QCursor
|
||||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QGroupBox, \
|
||||
QLineEdit, QLabel, QGridLayout, QPushButton, QPlainTextEdit, QScrollArea, QFrame, QWidget, QSizePolicy, \
|
||||
@@ -8,6 +8,7 @@ from PyQt5.QtWidgets import QDialog, QVBoxLayout, QGroupBox, \
|
||||
|
||||
from bauh.api.abstract.cache import MemoryCache
|
||||
from bauh.view.qt.components import new_spacer
|
||||
from bauh.view.qt.qt_utils import get_current_screen_geometry
|
||||
from bauh.view.util.translation import I18n
|
||||
|
||||
IGNORED_ATTRS = {'name', '__app__'}
|
||||
@@ -15,10 +16,9 @@ IGNORED_ATTRS = {'name', '__app__'}
|
||||
|
||||
class InfoDialog(QDialog):
|
||||
|
||||
def __init__(self, pkg_info: dict, icon_cache: MemoryCache, i18n: I18n, screen_size: QSize):
|
||||
def __init__(self, pkg_info: dict, icon_cache: MemoryCache, i18n: I18n):
|
||||
super(InfoDialog, self).__init__()
|
||||
self.setWindowTitle(str(pkg_info['__app__']))
|
||||
self.screen_size = screen_size
|
||||
self.i18n = i18n
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
@@ -108,7 +108,9 @@ class InfoDialog(QDialog):
|
||||
lower_container.layout().addWidget(self.bt_close)
|
||||
layout.addWidget(lower_container)
|
||||
self.setMinimumWidth(int(self.gbox_info.sizeHint().width() * 1.2))
|
||||
self.setMaximumHeight(int(screen_size.height() * 0.8))
|
||||
|
||||
screen_height = get_current_screen_geometry().height()
|
||||
self.setMaximumHeight(int(screen_height * 0.8))
|
||||
self.adjustSize()
|
||||
|
||||
def _gen_show_button(self, idx: int, val):
|
||||
|
||||
@@ -15,7 +15,7 @@ from bauh.api.abstract.controller import SoftwareManager, SoftwareAction
|
||||
from bauh.api.abstract.handler import TaskManager
|
||||
from bauh.api import user
|
||||
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, get_current_screen_geometry
|
||||
from bauh.view.qt.root import RootDialog
|
||||
from bauh.view.qt.thread import AnimateProgress
|
||||
from bauh.view.util.translation import I18n
|
||||
@@ -145,7 +145,7 @@ class PreparePanel(QWidget, TaskManager):
|
||||
signal_status = pyqtSignal(int)
|
||||
signal_password_response = pyqtSignal(bool, str)
|
||||
|
||||
def __init__(self, context: ApplicationContext, manager: SoftwareManager, screen_size: QSize,
|
||||
def __init__(self, context: ApplicationContext, manager: SoftwareManager,
|
||||
i18n: I18n, manage_window: QWidget, app_config: dict, force_suggestions: bool = False):
|
||||
super(PreparePanel, self).__init__(flags=Qt.CustomizeWindowHint | Qt.WindowTitleHint)
|
||||
self.i18n = i18n
|
||||
@@ -153,9 +153,7 @@ class PreparePanel(QWidget, TaskManager):
|
||||
self.app_config = app_config
|
||||
self.manage_window = manage_window
|
||||
self.setWindowTitle('{} ({})'.format(__app_name__, self.i18n['prepare_panel.title.start'].lower()))
|
||||
self.setMinimumWidth(int(screen_size.width() * 0.5))
|
||||
self.setMinimumHeight(int(screen_size.height() * 0.35))
|
||||
self.setMaximumHeight(int(screen_size.height() * 0.95))
|
||||
|
||||
self.setLayout(QVBoxLayout())
|
||||
self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
|
||||
self.manager = manager
|
||||
@@ -292,6 +290,10 @@ class PreparePanel(QWidget, TaskManager):
|
||||
super(PreparePanel, self).show()
|
||||
self.prepare_thread.start()
|
||||
centralize(self)
|
||||
screen_size = get_current_screen_geometry()
|
||||
self.setMinimumWidth(int(screen_size.width() * 0.5))
|
||||
self.setMinimumHeight(int(screen_size.height() * 0.35))
|
||||
self.setMaximumHeight(int(screen_size.height() * 0.95))
|
||||
|
||||
def start(self, tasks: int):
|
||||
self.started_at = time.time()
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
from PyQt5.QtCore import Qt
|
||||
from typing import Optional, Union
|
||||
|
||||
from PyQt5.QtCore import Qt, QRect, QPoint
|
||||
from PyQt5.QtGui import QIcon, QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QApplication
|
||||
from PyQt5.QtWidgets import QWidget, QApplication, QDesktopWidget
|
||||
|
||||
from bauh.view.util import resource
|
||||
|
||||
desktop: Optional[QDesktopWidget] = None
|
||||
|
||||
|
||||
def centralize(widget: QWidget):
|
||||
geo = widget.frameGeometry()
|
||||
screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
|
||||
center_point = QApplication.desktop().screenGeometry(screen).center()
|
||||
geo.moveCenter(center_point)
|
||||
widget.move(geo.topLeft())
|
||||
screen_geometry = get_current_screen_geometry()
|
||||
widget.frameGeometry().moveCenter(screen_geometry.center())
|
||||
widget.move(widget.frameGeometry().topLeft())
|
||||
|
||||
|
||||
def load_icon(path: str, width: int, height: int = None) -> QIcon:
|
||||
@@ -27,3 +29,13 @@ def measure_based_on_width(percent: float) -> int:
|
||||
|
||||
def measure_based_on_height(percent: float) -> int:
|
||||
return round(percent * QApplication.primaryScreen().size().height())
|
||||
|
||||
|
||||
def get_current_screen_geometry(source_widget: Optional[Union[QWidget, QPoint]] = None) -> QRect:
|
||||
global desktop
|
||||
|
||||
if not desktop:
|
||||
desktop = QDesktopWidget()
|
||||
|
||||
current_screen_idx = desktop.screenNumber(source_widget if source_widget else desktop.cursor().pos())
|
||||
return desktop.screen(current_screen_idx).geometry()
|
||||
|
||||
@@ -29,6 +29,7 @@ from bauh.view.core import timeshift
|
||||
from bauh.view.core.config import CoreConfigManager, BACKUP_REMOVE_METHODS, BACKUP_DEFAULT_REMOVE_METHOD
|
||||
from bauh.view.qt import commons
|
||||
from bauh.view.qt.commons import sort_packages
|
||||
from bauh.view.qt.qt_utils import get_current_screen_geometry
|
||||
from bauh.view.qt.view_model import PackageView, PackageViewStatus
|
||||
from bauh.view.util.translation import I18n
|
||||
|
||||
@@ -231,12 +232,12 @@ class UpgradeSelected(AsyncAction):
|
||||
SUMMARY_FILE = UPGRADE_LOGS_DIR + '/{}_summary.txt'
|
||||
|
||||
def __init__(self, manager: SoftwareManager, internet_checker: InternetChecker, i18n: I18n,
|
||||
screen_width: int, pkgs: List[PackageView] = None):
|
||||
parent_widget: QWidget, pkgs: List[PackageView] = None):
|
||||
super(UpgradeSelected, self).__init__(i18n=i18n)
|
||||
self.pkgs = pkgs
|
||||
self.manager = manager
|
||||
self.internet_checker = internet_checker
|
||||
self.screen_width = screen_width
|
||||
self._parent_widget = parent_widget
|
||||
|
||||
def _req_as_option(self, req: UpgradeRequirement, tooltip: bool = True, custom_tooltip: str = None, required_size: bool = True, display_sizes: bool = True,
|
||||
positive_size_symbol: bool = False) -> InputOption:
|
||||
@@ -495,9 +496,10 @@ class UpgradeSelected(AsyncAction):
|
||||
comps.insert(0, TextComponent(f'{disc_size_text} ({download_size_text})', size=14))
|
||||
comps.insert(1, TextComponent(''))
|
||||
|
||||
screen_width = get_current_screen_geometry(self._parent_widget).width()
|
||||
if not self.request_confirmation(title=self.i18n['action.update.summary'].capitalize(), body='', components=comps,
|
||||
confirmation_label=self.i18n['proceed'].capitalize(), deny_label=self.i18n['cancel'].capitalize(),
|
||||
confirmation_button=can_upgrade, min_width=int(0.45 * self.screen_width)):
|
||||
confirmation_button=can_upgrade, min_width=int(0.45 * screen_width)):
|
||||
self.notify_finished({'success': success, 'updated': updated, 'types': updated_types, 'id': None})
|
||||
self.pkgs = None
|
||||
return
|
||||
|
||||
@@ -2,12 +2,11 @@ import logging
|
||||
import operator
|
||||
import os.path
|
||||
import time
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from typing import List, Type, Set, Tuple, Optional
|
||||
|
||||
from PyQt5.QtCore import QEvent, Qt, pyqtSignal, QSize
|
||||
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QCursor
|
||||
from PyQt5.QtCore import QEvent, Qt, pyqtSignal, QRect
|
||||
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QCursor, QMoveEvent
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QCheckBox, QHeaderView, QToolBar, \
|
||||
QLabel, QPlainTextEdit, QProgressBar, QPushButton, QComboBox, QApplication, QListView, QSizePolicy, \
|
||||
QMenu, QHBoxLayout
|
||||
@@ -34,6 +33,7 @@ from bauh.view.qt.components import new_spacer, IconButton, QtComponentsManager,
|
||||
from bauh.view.qt.dialog import ConfirmationDialog
|
||||
from bauh.view.qt.history import HistoryDialog
|
||||
from bauh.view.qt.info import InfoDialog
|
||||
from bauh.view.qt.qt_utils import get_current_screen_geometry
|
||||
from bauh.view.qt.root import RootDialog
|
||||
from bauh.view.qt.screenshots import ScreenshotsDialog
|
||||
from bauh.view.qt.settings import SettingsWindow
|
||||
@@ -96,7 +96,7 @@ class ManageWindow(QWidget):
|
||||
signal_table_update = pyqtSignal()
|
||||
signal_stop_notifying = pyqtSignal()
|
||||
|
||||
def __init__(self, i18n: I18n, icon_cache: MemoryCache, manager: SoftwareManager, screen_size: QSize, config: dict,
|
||||
def __init__(self, i18n: I18n, icon_cache: MemoryCache, manager: SoftwareManager, config: dict,
|
||||
context: ApplicationContext, http_client: HttpClient, logger: logging.Logger, icon: QIcon,
|
||||
force_suggestions: bool = False):
|
||||
super(ManageWindow, self).__init__()
|
||||
@@ -112,7 +112,6 @@ class ManageWindow(QWidget):
|
||||
self.pkgs_installed = [] # cached installed packages
|
||||
self.display_limit = config['ui']['table']['max_displayed']
|
||||
self.icon_cache = icon_cache
|
||||
self.screen_size = screen_size
|
||||
self.config = config
|
||||
self.context = context
|
||||
self.http_client = http_client
|
||||
@@ -279,8 +278,7 @@ class ManageWindow(QWidget):
|
||||
self.table_container.layout().setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.table_apps = PackagesTable(self, self.icon_cache,
|
||||
download_icons=bool(self.config['download']['icons']),
|
||||
screen_width=int(screen_size.width()))
|
||||
download_icons=bool(self.config['download']['icons']))
|
||||
self.table_apps.change_headers_policy()
|
||||
self.table_container.layout().addWidget(self.table_apps)
|
||||
|
||||
@@ -333,7 +331,7 @@ class ManageWindow(QWidget):
|
||||
|
||||
self.thread_update = self._bind_async_action(UpgradeSelected(manager=self.manager, i18n=self.i18n,
|
||||
internet_checker=context.internet_checker,
|
||||
screen_width=screen_size.width()),
|
||||
parent_widget=self),
|
||||
finished_call=self._finish_upgrade_selected)
|
||||
self.thread_refresh = self._bind_async_action(RefreshApps(i18n, self.manager), finished_call=self._finish_refresh_packages, only_finished=True)
|
||||
self.thread_uninstall = self._bind_async_action(UninstallPackage(self.manager, self.icon_cache, self.i18n), finished_call=self._finish_uninstall)
|
||||
@@ -433,8 +431,6 @@ class ManageWindow(QWidget):
|
||||
self.container_progress.add_space()
|
||||
self.layout.addWidget(self.container_progress)
|
||||
|
||||
qt_utils.centralize(self)
|
||||
|
||||
self.filter_only_apps = True
|
||||
self.type_filter = self.any_type_filter
|
||||
self.category_filter = self.any_category_filter
|
||||
@@ -457,11 +453,8 @@ class ManageWindow(QWidget):
|
||||
|
||||
self.thread_load_installed = NotifyInstalledLoaded()
|
||||
self.thread_load_installed.signal_loaded.connect(self._finish_loading_installed)
|
||||
self.setMinimumHeight(int(screen_size.height() * 0.5))
|
||||
self.setMaximumHeight(int(screen_size.height()))
|
||||
self.setMinimumWidth(int(screen_size.width() * 0.5))
|
||||
self.setMaximumWidth(int(screen_size.width() - screen_size.width() * 0.015))
|
||||
self._register_groups()
|
||||
self._screen_geometry: Optional[QRect] = None
|
||||
|
||||
def _register_groups(self):
|
||||
common_filters = (CHECK_APPS, CHECK_UPDATES, COMBO_CATEGORIES, COMBO_TYPES, INP_NAME)
|
||||
@@ -597,6 +590,8 @@ class ManageWindow(QWidget):
|
||||
self.thread_warnings.start()
|
||||
|
||||
qt_utils.centralize(self)
|
||||
self._screen_geometry = get_current_screen_geometry()
|
||||
self._update_size_limits()
|
||||
|
||||
def verify_warnings(self):
|
||||
self.thread_warnings.start()
|
||||
@@ -671,7 +666,8 @@ class ManageWindow(QWidget):
|
||||
if self.table_apps.isEnabled() and self.pkgs is not None and 0 <= idx < len(self.pkgs):
|
||||
pkg = self.pkgs[idx]
|
||||
pkg.status = PackageViewStatus.READY
|
||||
self.table_apps.update_package(pkg)
|
||||
screen_width = get_current_screen_geometry(self).width()
|
||||
self.table_apps.update_package(pkg, screen_width=screen_width)
|
||||
|
||||
def _reload_categories(self):
|
||||
categories = set()
|
||||
@@ -687,11 +683,33 @@ class ManageWindow(QWidget):
|
||||
if categories:
|
||||
self._update_categories(categories, keep_selected=True)
|
||||
|
||||
def _update_size_limits(self):
|
||||
self.setMinimumHeight(int(self._screen_geometry.height() * 0.5))
|
||||
self.setMinimumWidth(int(self._screen_geometry.width() * 0.5))
|
||||
self.setMaximumWidth(int(self._screen_geometry.width()))
|
||||
|
||||
def changeEvent(self, e: QEvent):
|
||||
if isinstance(e, QWindowStateChangeEvent):
|
||||
self._maximized = self.isMaximized()
|
||||
self.table_apps.change_headers_policy(maximized=self._maximized)
|
||||
|
||||
if not self._maximized:
|
||||
self._reorganize()
|
||||
self.adjustSize()
|
||||
|
||||
def event(self, e: QEvent) -> bool:
|
||||
res = super(ManageWindow, self).event(e)
|
||||
|
||||
if self.isVisible() and e.type() == 216: # drop event
|
||||
current_geometry = get_current_screen_geometry()
|
||||
if current_geometry != self._screen_geometry: # only if the display device has changed
|
||||
self._screen_geometry = current_geometry
|
||||
self._update_size_limits()
|
||||
self._reorganize()
|
||||
self.adjustSize()
|
||||
|
||||
return res
|
||||
|
||||
def _handle_console(self, checked: bool):
|
||||
if checked:
|
||||
self.textarea_details.show()
|
||||
@@ -780,6 +798,7 @@ class ManageWindow(QWidget):
|
||||
util.notify_user('{} ({}) {}'.format(src_pkg.model.name, src_pkg.model.get_type(), self.i18n['uninstalled']))
|
||||
|
||||
if res['removed']:
|
||||
screen_width = get_current_screen_geometry(self).width()
|
||||
for list_idx, pkg_list in enumerate((self.pkgs_available, self.pkgs, self.pkgs_installed)):
|
||||
if pkg_list:
|
||||
removed_idxs = []
|
||||
@@ -796,7 +815,9 @@ class ManageWindow(QWidget):
|
||||
removed_idxs.append(pkgv_idx)
|
||||
|
||||
if self.search_performed and list_idx == 1: # only for displayed
|
||||
self.table_apps.update_package(pkgv, change_update_col=True)
|
||||
self.table_apps.update_package(pkgv,
|
||||
screen_width=screen_width,
|
||||
change_update_col=True)
|
||||
|
||||
break # as the model has been found, stops the loop
|
||||
|
||||
@@ -1286,8 +1307,7 @@ class ManageWindow(QWidget):
|
||||
|
||||
if pkg_info:
|
||||
if len(pkg_info) > 1:
|
||||
dialog_info = InfoDialog(pkg_info=pkg_info, icon_cache=self.icon_cache,
|
||||
i18n=self.i18n, screen_size=self.screen_size)
|
||||
dialog_info = InfoDialog(pkg_info=pkg_info, icon_cache=self.icon_cache, i18n=self.i18n)
|
||||
dialog_info.exec_()
|
||||
else:
|
||||
dialog.show_message(title=self.i18n['warning'].capitalize(),
|
||||
@@ -1462,10 +1482,11 @@ class ManageWindow(QWidget):
|
||||
self.pkgs_available.insert(new_idx, data[2])
|
||||
|
||||
# updating the respective table rows:
|
||||
screen_width = get_current_screen_geometry(self).width()
|
||||
for displayed in self.pkgs:
|
||||
for model in models_updated:
|
||||
if displayed.model == model:
|
||||
self.table_apps.update_package(displayed, change_update_col=True)
|
||||
self.table_apps.update_package(displayed, screen_width=screen_width, change_update_col=True)
|
||||
|
||||
self.update_bt_upgrade()
|
||||
|
||||
@@ -1565,7 +1586,8 @@ class ManageWindow(QWidget):
|
||||
self.settings_window.handle_display()
|
||||
else:
|
||||
self.settings_window = SettingsWindow(manager=self.manager, i18n=self.i18n, window=self)
|
||||
self.settings_window.setMinimumWidth(int(self.screen_size.width() / 4))
|
||||
screen_width = get_current_screen_geometry(self).width()
|
||||
self.settings_window.setMinimumWidth(int(screen_width / 4))
|
||||
self.settings_window.resize(self.size())
|
||||
self.settings_window.adjustSize()
|
||||
qt_utils.centralize(self.settings_window)
|
||||
@@ -1628,10 +1650,11 @@ class ManageWindow(QWidget):
|
||||
self._update_table_indexes()
|
||||
self.update_bt_upgrade()
|
||||
else:
|
||||
screen_width = get_current_screen_geometry(self).width()
|
||||
for pkg in self.pkgs:
|
||||
if pkg == res['pkg']:
|
||||
pkg.update_model(res['pkg'].model)
|
||||
self.table_apps.update_package(pkg, change_update_col=not any([self.search_performed, self.suggestions_requested]))
|
||||
self.table_apps.update_package(pkg, screen_width=screen_width, change_update_col=not any([self.search_performed, self.suggestions_requested]))
|
||||
self.update_bt_upgrade()
|
||||
break
|
||||
|
||||
|
||||
22
linux_dist/appimage/Dockerfile
Normal file
22
linux_dist/appimage/Dockerfile
Normal file
@@ -0,0 +1,22 @@
|
||||
FROM ubuntu:20.04
|
||||
|
||||
ARG bauh_commit
|
||||
ENV BAUH_VERSION=$bauh_commit
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get upgrade && \
|
||||
apt-get install python3-pip python3-setuptools python3-wheel wget fuse binutils coreutils desktop-file-utils fakeroot patchelf squashfs-tools strace zsync libgdk-pixbuf2.0-dev gtk-update-icon-cache -y && \
|
||||
mkdir /build && cd /build && \
|
||||
wget https://github.com/AppImageCrafters/appimage-builder/releases/download/v0.9.2/appimage-builder-0.9.2-35e3eab-x86_64.AppImage -O appimage-builder && \
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -O appimage-tool && \
|
||||
chmod +x appimage-tool && \
|
||||
chmod +x appimage-builder && \
|
||||
mv /build/appimage-builder /usr/local/bin/appimage-builder && \
|
||||
mv /build/appimage-tool /usr/local/bin/appimage-tool
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
COPY AppImageBuilder.yml /build
|
||||
|
||||
CMD [ "appimage-builder", "--skip-tests"]
|
||||
3
linux_dist/appimage/build.sh
Executable file
3
linux_dist/appimage/build.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
docker build -t bauh-appimage --build-arg bauh_commit=$BAUH_COMMIT .
|
||||
docker run --cap-add=SYS_ADMIN --device /dev/fuse --mount type=bind,source="$(pwd)",target=/build bauh-appimage
|
||||
@@ -1,4 +1,3 @@
|
||||
import time
|
||||
from unittest import TestCase
|
||||
|
||||
from bauh.commons.util import size_to_byte, sanitize_command_input
|
||||
|
||||
@@ -8,7 +8,7 @@ class GetHumanSizeStrTest(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
try:
|
||||
locale.setlocale(locale.LC_NUMERIC, None)
|
||||
locale.setlocale(locale.LC_NUMERIC, "C")
|
||||
except:
|
||||
print("Error: could not set locale.LC_NUMERIC to None")
|
||||
|
||||
|
||||
@@ -79,6 +79,45 @@ class TestUtil(TestCase):
|
||||
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test_replace_desktop_entry_exec_command__exec_as_the_first_field(self):
|
||||
desktop_entry = """
|
||||
Exec=myapp %f
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
"""
|
||||
|
||||
res = replace_desktop_entry_exec_command(desktop_entry=desktop_entry,
|
||||
appname='myapp',
|
||||
file_path='/path/to/myapp.appimage')
|
||||
|
||||
expected = """
|
||||
Exec="/path/to/myapp.appimage" %f
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
"""
|
||||
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test_replace_desktop_entry_exec_command__try_exec_as_the_first_field(self):
|
||||
desktop_entry = """
|
||||
TryExec=MyApp
|
||||
Exec=myapp %f
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
"""
|
||||
|
||||
res = replace_desktop_entry_exec_command(desktop_entry=desktop_entry,
|
||||
appname='myapp',
|
||||
file_path='/path/to/myapp.appimage')
|
||||
|
||||
expected = """
|
||||
Exec="/path/to/myapp.appimage" %f
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
"""
|
||||
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test_replace_desktop_entry_exec_command__only_one_exec_field_with_spaces_and_params(self):
|
||||
desktop_entry = """
|
||||
Name=MyApp
|
||||
@@ -136,7 +175,7 @@ class TestUtil(TestCase):
|
||||
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test_replace_desktop_entry_exec_command__only_one_tryexec_field_with_spaces_and_params(self):
|
||||
def test_replace_desktop_entry_exec_command__must_remove_try_exec_field(self):
|
||||
desktop_entry = """
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
@@ -150,12 +189,11 @@ class TestUtil(TestCase):
|
||||
expected = """
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
TryExec ="/path/to/myapp.appimage" %f --a
|
||||
"""
|
||||
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test_replace_desktop_entry_exec_command__exec_and_tryexec_fields(self):
|
||||
def test_replace_desktop_entry_exec_command__must_replace_exec_and_remove_tryexec_fields(self):
|
||||
desktop_entry = """
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
@@ -171,14 +209,13 @@ class TestUtil(TestCase):
|
||||
expected = """
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
TryExec ="/path/to/myapp.appimage" %f
|
||||
Exec="/path/to/myapp.appimage" --a
|
||||
Terminal=false
|
||||
"""
|
||||
|
||||
self.assertEqual(expected, res)
|
||||
|
||||
def test_replace_desktop_entry_exec_command__exec_and_tryexec_fields_with_envvars_and_params(self):
|
||||
def test_replace_desktop_entry_exec_command__exec_field_with_envvars_and_params(self):
|
||||
desktop_entry = """
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
@@ -194,7 +231,6 @@ class TestUtil(TestCase):
|
||||
expected = """
|
||||
Name=MyApp
|
||||
Icon=MyApp
|
||||
TryExec=__MY_VAR=1 "/path/to/myapp.appimage" %f
|
||||
Exec=NEW_VAR=abc "/path/to/myapp.appimage" --a
|
||||
Terminal=false
|
||||
"""
|
||||
@@ -228,7 +264,6 @@ Name=RPCS3
|
||||
GenericName=PlayStation 3 Emulator
|
||||
Comment=An open-source PlayStation 3 emulator/debugger written in C++.
|
||||
Icon=rpcs3
|
||||
TryExec="/path/to/rpcs3.appimage"
|
||||
Exec="/path/to/rpcs3.appimage" %f
|
||||
Terminal=false
|
||||
Categories=Game;Emulator;
|
||||
|
||||
@@ -98,4 +98,4 @@ Include = /etc/pacman.d/mirrorlist
|
||||
#Server = file:///home/custompkgs
|
||||
ignorepkg=google-chrome
|
||||
# ignorepkg=abc
|
||||
ignorepkg = firefox
|
||||
IgnorePkg = firefox
|
||||
@@ -166,3 +166,33 @@ Description: GNU C compiler
|
||||
]
|
||||
|
||||
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})
|
||||
|
||||
Reference in New Issue
Block a user