mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 00:04:15 +02:00
[arch] improvement: missing dependencies dialog now displays the packages sizes and descriptions (only from repositories)
This commit is contained in:
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
### Improvements
|
### Improvements
|
||||||
- Arch
|
- Arch
|
||||||
- install:
|
- install:
|
||||||
|
- missing dependencies dialog now displays the packages sizes and descriptions (only from repositories)
|
||||||
- optional packages installation dialog appearance (aligned with other dependencies dialogs)
|
- optional packages installation dialog appearance (aligned with other dependencies dialogs)
|
||||||
- uninstall:
|
- uninstall:
|
||||||
- displaying hard and unnecessary requirements versions and descriptions
|
- displaying hard and unnecessary requirements versions and descriptions
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from io import StringIO
|
||||||
from typing import Set, Tuple, Dict, Collection
|
from typing import Set, Tuple, Dict, Collection
|
||||||
|
|
||||||
from bauh.api.abstract.handler import ProcessWatcher
|
from bauh.api.abstract.handler import ProcessWatcher
|
||||||
@@ -47,27 +48,64 @@ def request_optional_deps(pkgname: str, pkg_repos: dict, watcher: ProcessWatcher
|
|||||||
return {o.value for o in view_opts.values}
|
return {o.value for o in view_opts.values}
|
||||||
|
|
||||||
|
|
||||||
def request_install_missing_deps(deps: Collection[Tuple[str, str]], watcher: ProcessWatcher, i18n: I18n) -> bool:
|
def confirm_missing_deps(deps: Collection[Tuple[str, str]], watcher: ProcessWatcher, i18n: I18n) -> bool:
|
||||||
msg = f"<p>{i18n['arch.missing_deps.body'].format(deps=bold(str(len(deps))))}:</p>"
|
|
||||||
|
|
||||||
opts = []
|
opts = []
|
||||||
|
|
||||||
repo_deps = [d[0] for d in deps if d[1] != 'aur']
|
total_isize, total_dsize = None, None
|
||||||
sizes = pacman.map_update_sizes(repo_deps) if repo_deps else {}
|
pkgs_data = pacman.map_updates_data(pkgs=tuple(d[0] for d in deps if d[1] != 'aur'), description=True) or dict()
|
||||||
|
|
||||||
for dep in deps:
|
for dep in deps:
|
||||||
size = sizes.get(dep[0])
|
ver, desc, isize, dsize = None, None, None, None
|
||||||
op = InputOption('{} ({}: {}) - {}: {}'.format(dep[0],
|
data = pkgs_data.get(dep[0])
|
||||||
i18n['repository'],
|
|
||||||
dep[1].lower(),
|
if data:
|
||||||
i18n['size'].capitalize(),
|
desc, isize, dsize = (data.get(f) for f in ('des', 's', 'ds'))
|
||||||
get_human_size_str(size) if size is not None else '?'), dep[0])
|
|
||||||
|
if isize is not None:
|
||||||
|
if total_isize is None:
|
||||||
|
total_isize = 0
|
||||||
|
|
||||||
|
total_isize += isize
|
||||||
|
|
||||||
|
if dsize is not None:
|
||||||
|
if total_dsize is None:
|
||||||
|
total_dsize = 0
|
||||||
|
|
||||||
|
total_dsize += dsize
|
||||||
|
|
||||||
|
label = f"{dep[0]} ({i18n['repository']}: {dep[1].lower()}) | " \
|
||||||
|
f"{i18n['size'].capitalize()}: {get_human_size_str(isize) if isize is not None else '?'}" \
|
||||||
|
f"{' ({}: {})'.format(i18n['download'].capitalize(), get_human_size_str(dsize)) if dsize else ''}"
|
||||||
|
|
||||||
|
op = InputOption(label=label, value=dep[0], tooltip=desc)
|
||||||
op.read_only = True
|
op.read_only = True
|
||||||
op.icon_path = _get_repo_icon(dep[1])
|
op.icon_path = _get_repo_icon(dep[1])
|
||||||
opts.append(op)
|
opts.append(op)
|
||||||
|
|
||||||
comp = MultipleSelectComponent(label='', options=opts, default_options=set(opts))
|
comp = MultipleSelectComponent(label='', options=opts, default_options=set(opts))
|
||||||
return watcher.request_confirmation(i18n['arch.missing_deps.title'], msg, [comp], confirmation_label=i18n['continue'].capitalize(), deny_label=i18n['cancel'].capitalize(),
|
|
||||||
|
body = StringIO()
|
||||||
|
body.write('<p>')
|
||||||
|
body.write(i18n['arch.missing_deps.body'].format(deps=bold(str(len(deps)))))
|
||||||
|
|
||||||
|
if total_isize is not None or total_dsize is not None:
|
||||||
|
body.write(' (')
|
||||||
|
|
||||||
|
if total_isize is not None:
|
||||||
|
body.write(f"{i18n['size'].capitalize()}: {bold(get_human_size_str(total_isize))} | ")
|
||||||
|
|
||||||
|
if total_dsize is not None:
|
||||||
|
body.write(f"{i18n['download'].capitalize()}: {bold(get_human_size_str(total_dsize))}")
|
||||||
|
|
||||||
|
body.write(')')
|
||||||
|
|
||||||
|
body.write(':</p>')
|
||||||
|
|
||||||
|
return watcher.request_confirmation(title=i18n['arch.missing_deps.title'],
|
||||||
|
body=body.getvalue(),
|
||||||
|
components=[comp],
|
||||||
|
confirmation_label=i18n['continue'].capitalize(),
|
||||||
|
deny_label=i18n['cancel'].capitalize(),
|
||||||
min_width=600)
|
min_width=600)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ from bauh.gems.arch import aur, pacman, message, confirmation, disk, git, \
|
|||||||
ARCH_CONFIG_DIR, EDITABLE_PKGBUILDS_FILE, URL_GPG_SERVERS, rebuild_detector, makepkg, sshell, get_repo_icon_path
|
ARCH_CONFIG_DIR, EDITABLE_PKGBUILDS_FILE, URL_GPG_SERVERS, rebuild_detector, makepkg, sshell, get_repo_icon_path
|
||||||
from bauh.gems.arch.aur import AURClient
|
from bauh.gems.arch.aur import AURClient
|
||||||
from bauh.gems.arch.config import get_build_dir, ArchConfigManager
|
from bauh.gems.arch.config import get_build_dir, ArchConfigManager
|
||||||
|
from bauh.gems.arch.confirmation import confirm_missing_deps
|
||||||
from bauh.gems.arch.dependencies import DependenciesAnalyser
|
from bauh.gems.arch.dependencies import DependenciesAnalyser
|
||||||
from bauh.gems.arch.download import MultithreadedDownloadService, ArchDownloadException
|
from bauh.gems.arch.download import MultithreadedDownloadService, ArchDownloadException
|
||||||
from bauh.gems.arch.exceptions import PackageNotFoundException, PackageInHoldException
|
from bauh.gems.arch.exceptions import PackageNotFoundException, PackageInHoldException
|
||||||
@@ -2114,7 +2115,7 @@ class ArchManager(SoftwareManager):
|
|||||||
def _ask_and_install_missing_deps(self, context: TransactionContext, missing_deps: List[Tuple[str, str]]) -> bool:
|
def _ask_and_install_missing_deps(self, context: TransactionContext, missing_deps: List[Tuple[str, str]]) -> bool:
|
||||||
context.watcher.change_substatus(self.i18n['arch.missing_deps_found'].format(bold(context.name)))
|
context.watcher.change_substatus(self.i18n['arch.missing_deps_found'].format(bold(context.name)))
|
||||||
|
|
||||||
if not confirmation.request_install_missing_deps(missing_deps, context.watcher, self.i18n):
|
if not confirm_missing_deps(missing_deps, context.watcher, self.i18n):
|
||||||
context.watcher.print(self.i18n['action.cancelled'])
|
context.watcher.print(self.i18n['action.cancelled'])
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -2304,8 +2305,7 @@ class ArchManager(SoftwareManager):
|
|||||||
|
|
||||||
sorted_deps = sorting.sort(to_sort, {**deps_data, **subdeps_data}, provided_map)
|
sorted_deps = sorting.sort(to_sort, {**deps_data, **subdeps_data}, provided_map)
|
||||||
|
|
||||||
if display_deps_dialog and not confirmation.request_install_missing_deps(sorted_deps, context.watcher,
|
if display_deps_dialog and not confirm_missing_deps(sorted_deps, context.watcher, self.i18n):
|
||||||
self.i18n):
|
|
||||||
context.watcher.print(self.i18n['action.cancelled'])
|
context.watcher.print(self.i18n['action.cancelled'])
|
||||||
return True # because the main package installation was successful
|
return True # because the main package installation was successful
|
||||||
|
|
||||||
|
|||||||
@@ -599,40 +599,87 @@ def list_download_data(pkgs: Iterable[str]) -> List[Dict[str, str]]:
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def map_updates_data(pkgs: Iterable[str], files: bool = False) -> dict:
|
def map_updates_data(pkgs: Iterable[str], files: bool = False, description: bool = False) -> Optional[Dict[str, Dict[str, object]]]:
|
||||||
if files:
|
if pkgs:
|
||||||
output = run_cmd('pacman -Qi -p {}'.format(' '.join(pkgs)))
|
if files:
|
||||||
else:
|
output = run_cmd('pacman -Qi -p {}'.format(' '.join(pkgs)))
|
||||||
output = run_cmd('pacman -Si {}'.format(' '.join(pkgs)))
|
else:
|
||||||
|
output = run_cmd('pacman -Si {}'.format(' '.join(pkgs)))
|
||||||
|
|
||||||
res = {}
|
res = {}
|
||||||
if output:
|
if output:
|
||||||
latest_name = None
|
latest_name = None
|
||||||
data = {'ds': None, 's': None, 'v': None, 'c': None, 'p': None, 'd': None, 'r': None}
|
data = {'ds': None, 's': None, 'v': None, 'c': None, 'p': None, 'd': None, 'r': None, 'des': None}
|
||||||
latest_field = None
|
latest_field = None
|
||||||
|
|
||||||
for l in output.split('\n'):
|
for l in output.split('\n'):
|
||||||
if l:
|
if l:
|
||||||
if l[0] != ' ':
|
if l[0] != ' ':
|
||||||
line = l.strip()
|
line = l.strip()
|
||||||
field_sep_idx = line.index(':')
|
field_sep_idx = line.index(':')
|
||||||
field = line[0:field_sep_idx].strip()
|
field = line[0:field_sep_idx].strip()
|
||||||
val = line[field_sep_idx + 1:].strip()
|
val = line[field_sep_idx + 1:].strip()
|
||||||
|
|
||||||
if field == 'Repository':
|
if field == 'Repository':
|
||||||
data['r'] = val
|
data['r'] = val
|
||||||
latest_field = 'r'
|
latest_field = 'r'
|
||||||
elif field == 'Name':
|
elif field == 'Name':
|
||||||
latest_name = val
|
latest_name = val
|
||||||
latest_field = 'n'
|
latest_field = 'n'
|
||||||
elif field == 'Version':
|
elif field == 'Version':
|
||||||
data['v'] = val.split('=')[0]
|
data['v'] = val.split('=')[0]
|
||||||
latest_field = 'v'
|
latest_field = 'v'
|
||||||
elif field == 'Provides':
|
elif description and field == 'Description':
|
||||||
latest_field = 'p'
|
data['des'] = val
|
||||||
data['p'] = {latest_name, '{}={}'.format(latest_name, data['v'])}
|
latest_field = 'des'
|
||||||
if val != 'None':
|
elif field == 'Provides':
|
||||||
for w in val.split(' '):
|
latest_field = 'p'
|
||||||
|
data['p'] = {latest_name, '{}={}'.format(latest_name, data['v'])}
|
||||||
|
if val != 'None':
|
||||||
|
for w in val.split(' '):
|
||||||
|
if w:
|
||||||
|
word = w.strip()
|
||||||
|
data['p'].add(word)
|
||||||
|
|
||||||
|
word_split = word.split('=')
|
||||||
|
|
||||||
|
if word_split[0] != word:
|
||||||
|
data['p'].add(word_split[0])
|
||||||
|
elif field == 'Depends On':
|
||||||
|
val = val.strip()
|
||||||
|
|
||||||
|
if val == 'None':
|
||||||
|
data['d'] = None
|
||||||
|
else:
|
||||||
|
data['d'] = {w.strip() for w in val.split(' ') if w}
|
||||||
|
latest_field = 'd'
|
||||||
|
elif field == 'Conflicts With':
|
||||||
|
if val == 'None':
|
||||||
|
data['c'] = None
|
||||||
|
else:
|
||||||
|
data['c'] = {w.strip() for w in val.split(' ') if w}
|
||||||
|
|
||||||
|
latest_field = 'c'
|
||||||
|
elif field == 'Download Size':
|
||||||
|
size = val.split(' ')
|
||||||
|
data['ds'] = size_to_byte(size[0], size[1])
|
||||||
|
latest_field = 'ds'
|
||||||
|
elif field == 'Installed Size':
|
||||||
|
size = val.split(' ')
|
||||||
|
data['s'] = size_to_byte(size[0], size[1])
|
||||||
|
latest_field = 's'
|
||||||
|
elif latest_name and latest_field == 's':
|
||||||
|
res[latest_name] = data
|
||||||
|
latest_name = None
|
||||||
|
latest_field = None
|
||||||
|
data = {'ds': None, 's': None, 'c': None, 'p': None, 'd': None,
|
||||||
|
'r': None, 'v': None, 'des': None}
|
||||||
|
else:
|
||||||
|
latest_field = None
|
||||||
|
|
||||||
|
elif latest_field and latest_field in ('p', 'c', 'd'):
|
||||||
|
if latest_field == 'p':
|
||||||
|
for w in l.split(' '):
|
||||||
if w:
|
if w:
|
||||||
word = w.strip()
|
word = w.strip()
|
||||||
data['p'].add(word)
|
data['p'].add(word)
|
||||||
@@ -641,52 +688,10 @@ def map_updates_data(pkgs: Iterable[str], files: bool = False) -> dict:
|
|||||||
|
|
||||||
if word_split[0] != word:
|
if word_split[0] != word:
|
||||||
data['p'].add(word_split[0])
|
data['p'].add(word_split[0])
|
||||||
elif field == 'Depends On':
|
|
||||||
val = val.strip()
|
|
||||||
|
|
||||||
if val == 'None':
|
|
||||||
data['d'] = None
|
|
||||||
else:
|
else:
|
||||||
data['d'] = {w.strip() for w in val.split(' ') if w}
|
data[latest_field].update((w.strip() for w in l.split(' ') if w))
|
||||||
latest_field = 'd'
|
|
||||||
elif field == 'Conflicts With':
|
|
||||||
if val == 'None':
|
|
||||||
data['c'] = None
|
|
||||||
else:
|
|
||||||
data['c'] = {w.strip() for w in val.split(' ') if w}
|
|
||||||
|
|
||||||
latest_field = 'c'
|
return res
|
||||||
elif field == 'Download Size':
|
|
||||||
size = val.split(' ')
|
|
||||||
data['ds'] = size_to_byte(size[0], size[1])
|
|
||||||
latest_field = 'ds'
|
|
||||||
elif field == 'Installed Size':
|
|
||||||
size = val.split(' ')
|
|
||||||
data['s'] = size_to_byte(size[0], size[1])
|
|
||||||
latest_field = 's'
|
|
||||||
elif latest_name and latest_field == 's':
|
|
||||||
res[latest_name] = data
|
|
||||||
latest_name = None
|
|
||||||
latest_field = None
|
|
||||||
data = {'ds': None, 's': None, 'c': None, 'p': None, 'd': None, 'r': None, 'v': None}
|
|
||||||
else:
|
|
||||||
latest_field = None
|
|
||||||
|
|
||||||
elif latest_field and latest_field in ('p', 'c', 'd'):
|
|
||||||
if latest_field == 'p':
|
|
||||||
for w in l.split(' '):
|
|
||||||
if w:
|
|
||||||
word = w.strip()
|
|
||||||
data['p'].add(word)
|
|
||||||
|
|
||||||
word_split = word.split('=')
|
|
||||||
|
|
||||||
if word_split[0] != word:
|
|
||||||
data['p'].add(word_split[0])
|
|
||||||
else:
|
|
||||||
data[latest_field].update((w.strip() for w in l.split(' ') if w))
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
def upgrade_several(pkgnames: Iterable[str], root_password: Optional[str], overwrite_conflicting_files: bool = False, skip_dependency_checks: bool = False) -> SimpleProcess:
|
def upgrade_several(pkgnames: Iterable[str], root_password: Optional[str], overwrite_conflicting_files: bool = False, skip_dependency_checks: bool = False) -> SimpleProcess:
|
||||||
|
|||||||
Reference in New Issue
Block a user