mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-09 14:24:16 +02:00
[arch] improvement -> upgrade: checking specific version requirements and marking packages as 'cannot upgrade' when these requirements are not met
This commit is contained in:
14
CHANGELOG.md
14
CHANGELOG.md
@@ -37,9 +37,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- only removing packages after downloading the required ones
|
||||
- summary: displaying the reason a given package must be installed
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/vinifmor/bauh-files/master/pictures/releases/0.9.7/arch_install_reason.png">
|
||||
<img src="https://raw.githubusercontent.com/vinifmor/bauh-files/master/pictures/releases/0.9.7/arch_install_reason.png">
|
||||
</p>
|
||||
|
||||
|
||||
- checking specific version requirements and marking packages as "cannot upgrade" when these requirements are not met (e.g: package A depends on version 1.0 of B. If A and B were selected to upgrade, and B would be upgrade to 2.0, then B would be excluded from the transaction. This new checking behavior can be disabled through the property (**check_dependency_breakage**):
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/vinifmor/bauh-files/master/pictures/releases/0.9.7/arch_dep_break_settings.png">
|
||||
</p>
|
||||
|
||||
- AUR
|
||||
- caching the PKGBUILD file used for the package installation/upgrade/downgrade (**~/.cache/bauh/arch/installed/$pkgname/PKGBUILD**)
|
||||
- new settings property **aur_build_dir** -> it allows to define a custom build dir.
|
||||
@@ -77,6 +82,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- upgrade summary
|
||||
- not displaying all packages that must be uninstalled
|
||||
- displaying "required size" for packages that must be uninstalled
|
||||
- not displaying packages that cannot upgrade due to specific version requirements (e.g: package A requires version 1.0 of package B, however package B will be upgrade to version 2.0)
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/vinifmor/bauh-files/master/pictures/releases/0.9.7/arch_dep_break.png">
|
||||
</p>
|
||||
|
||||
- some conflict resolution scenarios when upgrading several packages
|
||||
- not handling conflicting files errors during the installation process
|
||||
- AUR
|
||||
|
||||
@@ -197,6 +197,7 @@ edit_aur_pkgbuild: false # if the AUR PKGBUILD file should be displayed for edi
|
||||
aur_build_dir: null # defines a custom build directory for AUR packages (a null value will point to /tmp/bauh/arch (non-root user) or /tmp/bauh_root/arch (root user)). Default: null.
|
||||
aur_remove_build_dir: true # it defines if a package's generated build directory should be removed after the operation is finished (installation, upgrading, ...). Options: true, false (default: true).
|
||||
aur_build_only_chosen : true # some AUR packages have a common file definition declaring several packages to be built. When this property is 'true' only the package the user select to install will be built (unless its name is different from those declared in the PKGBUILD base). With a 'null' value a popup asking if the user wants to build all of them will be displayed. 'false' will build and install all packages. Default: true.
|
||||
check_dependency_breakage: true # If, during the verification of the update requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B. If A and B were selected to upgrade, and B would be upgrade to 2.0, then B would be excluded from the transaction. Default: true.
|
||||
```
|
||||
- Required dependencies:
|
||||
- **pacman**
|
||||
|
||||
@@ -30,18 +30,24 @@ class SearchResult:
|
||||
|
||||
class UpgradeRequirement:
|
||||
|
||||
def __init__(self, pkg: SoftwarePackage, reason: str = None, required_size: int = None, extra_size: int = None):
|
||||
def __init__(self, pkg: SoftwarePackage, reason: str = None, required_size: int = None, extra_size: int = None, sorting_priority: int = 0):
|
||||
"""
|
||||
|
||||
:param pkg:
|
||||
:param reason:
|
||||
:param required_size: size in BYTES required to upgrade the package
|
||||
:param extra_size: the extra size IN BYTES the upgrade will allocate in relation to the already allocated
|
||||
:param sorting_priority: an int representing the sorting priority (higher numbers = higher priority)
|
||||
"""
|
||||
self.pkg = pkg
|
||||
self.reason = reason
|
||||
self.required_size = required_size
|
||||
self.extra_size = extra_size
|
||||
self.sorting_priority = sorting_priority
|
||||
|
||||
@staticmethod
|
||||
def sort_by_priority(req: "UpgradeRequirement") -> Tuple[int, str]:
|
||||
return -req.sorting_priority, req.pkg.name
|
||||
|
||||
|
||||
class UpgradeRequirements:
|
||||
|
||||
@@ -18,7 +18,8 @@ def read_config(update_file: bool = False) -> dict:
|
||||
'edit_aur_pkgbuild': False,
|
||||
'aur_build_dir': None,
|
||||
'aur_remove_build_dir': True,
|
||||
'aur_build_only_chosen': True}
|
||||
'aur_build_only_chosen': True,
|
||||
'check_dependency_breakage': True}
|
||||
return read(CONFIG_FILE, template, update_file=update_file)
|
||||
|
||||
|
||||
|
||||
@@ -2554,6 +2554,11 @@ class ArchManager(SoftwareManager):
|
||||
tooltip_key='arch.config.automatch_providers.tip',
|
||||
value=bool(local_config['automatch_providers']),
|
||||
max_width=max_width),
|
||||
self._gen_bool_selector(id_='check_dependency_breakage',
|
||||
label_key='arch.config.check_dependency_breakage',
|
||||
tooltip_key='arch.config.check_dependency_breakage.tip',
|
||||
value=bool(local_config['check_dependency_breakage']),
|
||||
max_width=max_width),
|
||||
self._gen_bool_selector(id_='mthread_download',
|
||||
label_key='arch.config.pacman_mthread_download',
|
||||
tooltip_key='arch.config.pacman_mthread_download.tip',
|
||||
@@ -2639,6 +2644,7 @@ class ArchManager(SoftwareManager):
|
||||
config['aur_remove_build_dir'] = form_install.get_component('aur_remove_build_dir').get_selected()
|
||||
config['aur_build_dir'] = form_install.get_component('aur_build_dir').file_path
|
||||
config['aur_build_only_chosen'] = form_install.get_component('aur_build_only_chosen').get_selected()
|
||||
config['check_dependency_breakage'] = form_install.get_component('check_dependency_breakage').get_selected()
|
||||
|
||||
if not config['aur_build_dir']:
|
||||
config['aur_build_dir'] = None
|
||||
|
||||
@@ -180,3 +180,8 @@ class ArchPackage(SoftwarePackage):
|
||||
else:
|
||||
return ACTIONS_AUR_ENABLE_PKGBUILD_EDITION
|
||||
|
||||
def __hash__(self):
|
||||
if self.view_name is not None:
|
||||
return hash((self.view_name, self.repository))
|
||||
else:
|
||||
return hash((self.name, self.repository))
|
||||
|
||||
@@ -914,8 +914,8 @@ def get_cache_dir() -> str:
|
||||
return '/var/cache/pacman/pkg'
|
||||
|
||||
|
||||
def map_required_by(names: Iterable[str] = None) -> Dict[str, Set[str]]:
|
||||
output = run_cmd('pacman -Qi {}'.format(' '.join(names) if names else ''))
|
||||
def map_required_by(names: Iterable[str] = None, remote: bool = False) -> Dict[str, Set[str]]:
|
||||
output = run_cmd('pacman -{} {}'.format('Sii' if remote else 'Qi', ' '.join(names) if names else ''), print_error=False)
|
||||
|
||||
if output:
|
||||
res = {}
|
||||
|
||||
@@ -42,6 +42,8 @@ arch.config.aur_remove_build_dir=Remove build directory (AUR)
|
||||
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
|
||||
arch.config.clean_cache=Elimina les versions antigues
|
||||
arch.config.clean_cache.tip=Si cal eliminar les versions antigues d'un paquet emmagatzemat al disc durant la desinstal·lació
|
||||
arch.config.check_dependency_breakage=Check dependency version breakage
|
||||
arch.config.check_dependency_breakage.tip=If, during the verification of upgrade requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B.
|
||||
arch.config.edit_aur_pkgbuild=Edit PKGBUILD (AUR)
|
||||
arch.config.edit_aur_pkgbuild.tip=If the PKGBUILD file of an AUR package should be displayed for editing before its installation/upgrade/downgrade
|
||||
arch.config.mirrors_sort_limit=Mirrors sort limit
|
||||
@@ -196,6 +198,7 @@ arch.substatus.integrity=Checking packages integrity
|
||||
arch.substatus.keyring=Checking keyring
|
||||
arch.substatus.loading_files=Loading package files
|
||||
arch.substatus.pre_hooks=Running pre-transaction hooks
|
||||
arch.sync.dep_breakage.reason={} requires {}
|
||||
arch.sync_databases.substatus=Synchronizing package databases
|
||||
arch.sync_databases.substatus.error=It was not possible to synchronize the package database
|
||||
arch.task.disk_cache=Indexing packages data
|
||||
|
||||
@@ -42,6 +42,8 @@ arch.config.aur_remove_build_dir=Remove build directory (AUR)
|
||||
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
|
||||
arch.config.clean_cache=Remove old versions
|
||||
arch.config.clean_cache.tip=Whether old versions of a package stored on disk should be removed during uninstall
|
||||
arch.config.check_dependency_breakage=Check dependency version breakage
|
||||
arch.config.check_dependency_breakage.tip=If, during the verification of upgrade requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B.
|
||||
arch.config.edit_aur_pkgbuild=Edit PKGBUILD (AUR)
|
||||
arch.config.edit_aur_pkgbuild.tip=If the PKGBUILD file of an AUR package should be displayed for editing before its installation/upgrade/downgrade
|
||||
arch.config.mirrors_sort_limit=Mirrors sort limit
|
||||
@@ -196,6 +198,7 @@ arch.substatus.integrity=Checking packages integrity
|
||||
arch.substatus.keyring=Checking keyring
|
||||
arch.substatus.loading_files=Loading package files
|
||||
arch.substatus.pre_hooks=Running pre-transaction hooks
|
||||
arch.sync.dep_breakage.reason={} requires {}
|
||||
arch.sync_databases.substatus=Synchronizing package databases
|
||||
arch.sync_databases.substatus.error=It was not possible to synchronize the package database
|
||||
arch.task.disk_cache=Indexing packages data
|
||||
|
||||
@@ -43,6 +43,8 @@ arch.config.aur_remove_build_dir=Remove build directory (AUR)
|
||||
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
|
||||
arch.config.clean_cache=Remove old versions
|
||||
arch.config.clean_cache.tip=Whether old versions of a package stored on disk should be removed during uninstall
|
||||
arch.config.check_dependency_breakage=Check dependency version breakage
|
||||
arch.config.check_dependency_breakage.tip=If, during the verification of upgrade requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B.
|
||||
arch.config.edit_aur_pkgbuild=Edit PKGBUILD (AUR)
|
||||
arch.config.edit_aur_pkgbuild.tip=If the PKGBUILD file of an AUR package should be displayed for editing before its installation/upgrade/downgrade
|
||||
arch.config.mirrors_sort_limit=Mirrors sort limit
|
||||
@@ -197,6 +199,7 @@ arch.substatus.integrity=Checking packages integrity
|
||||
arch.substatus.keyring=Checking keyring
|
||||
arch.substatus.loading_files=Loading package files
|
||||
arch.substatus.pre_hooks=Running pre-transaction hooks
|
||||
arch.sync.dep_breakage.reason={} requires {}
|
||||
arch.sync_databases.substatus=Synchronizing package databases
|
||||
arch.sync_databases.substatus.error=It was not possible to synchronize the package database
|
||||
arch.task.disk_cache=Indexing packages data
|
||||
|
||||
@@ -42,6 +42,8 @@ arch.config.aur_remove_build_dir=Eliminar directorio de compilación (AUR)
|
||||
arch.config.aur_remove_build_dir.tip=Si el directorio de compilación generado para un paquete debe ser eliminado una vez finalizada la operación.
|
||||
arch.config.clean_cache=Eliminar versiones antiguas
|
||||
arch.config.clean_cache.tip=Si las versiones antiguas de un paquete almacenado en el disco deben ser eliminadas durante la desinstalación
|
||||
arch.config.check_dependency_breakage=Verificar rotura de versión de dependencia
|
||||
arch.config.check_dependency_breakage.tip=Si, durante la verificación de los requisitos de actualización, también se deben verificar versiones específicas de las dependencias. Ejemplo: el paquete A depende de la versión 1.0 de B.
|
||||
arch.config.edit_aur_pkgbuild=Editar PKGBUILD (AUR)
|
||||
arch.config.edit_aur_pkgbuild.tip=Si el archivo PKGBUILD de un paquete AUR debe ser exhibido para edición antes de su instalación/actualización/degradación
|
||||
arch.config.mirrors_sort_limit=Límite de ordenación de espejos
|
||||
@@ -196,6 +198,7 @@ arch.substatus.integrity=Verificando la integridad de los paquetes
|
||||
arch.substatus.keyring=Verificando keyring
|
||||
arch.substatus.loading_files=Cargando archivos de los paquetes
|
||||
arch.substatus.pre_hooks=Ejecutando ganchos pre-transacción
|
||||
arch.sync.dep_breakage.reason={} necesita de {}
|
||||
arch.sync_databases.substatus=Sincronizando bases de paquetes
|
||||
arch.sync_databases.substatus.error=No fue posible sincronizar la base de paquetes
|
||||
arch.task.disk_cache=Indexando datos de paquetes
|
||||
|
||||
@@ -42,6 +42,8 @@ arch.config.aur_remove_build_dir=Remove build directory (AUR)
|
||||
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
|
||||
arch.config.clean_cache=Rimuovi le vecchie versioni
|
||||
arch.config.clean_cache.tip=Se le vecchie versioni di un pacchetto memorizzate sul disco devono essere rimosse durante la disinstallazione
|
||||
arch.config.check_dependency_breakage=Check dependency version breakage
|
||||
arch.config.check_dependency_breakage.tip=If, during the verification of upgrade requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B.
|
||||
arch.config.edit_aur_pkgbuild=Edit PKGBUILD (AUR)
|
||||
arch.config.edit_aur_pkgbuild.tip=If the PKGBUILD file of an AUR package should be displayed for editing before its installation/upgrade/downgrade
|
||||
arch.config.mirrors_sort_limit=Mirrors sort limit
|
||||
@@ -196,6 +198,7 @@ arch.substatus.integrity=Checking packages integrity
|
||||
arch.substatus.keyring=Checking keyring
|
||||
arch.substatus.loading_files=Loading package files
|
||||
arch.substatus.pre_hooks=Running pre-transaction hooks
|
||||
arch.sync.dep_breakage.reason={} requires {}
|
||||
arch.sync_databases.substatus=Synchronizing package databases
|
||||
arch.sync_databases.substatus.error=It was not possible to synchronize the package database
|
||||
arch.task.disk_cache=Indexing packages data
|
||||
|
||||
@@ -43,6 +43,8 @@ arch.config.aur_remove_build_dir=Remover diretório de construção (AUR)
|
||||
arch.config.aur_remove_build_dir.tip=Se o diretório gerado para a construção de um pacote do AUR deve ser removido após a operação ser finalizada.
|
||||
arch.config.clean_cache=Remover versões antigas
|
||||
arch.config.clean_cache.tip=Se versões antigas de um pacote armazenadas em disco devem ser removidas durante a desinstalação
|
||||
arch.config.check_dependency_breakage=Verificar quebra de dependência de versão
|
||||
arch.config.check_dependency_breakage.tip=Se durante a verificação dos requisitos de atualização deve-se verificar também versões específicas de dependências. Exemplo: pacote A depende da versão 1.0 de B.
|
||||
arch.config.edit_aur_pkgbuild=Editar PKGBUILD (AUR)
|
||||
arch.config.edit_aur_pkgbuild.tip=Se o arquivo PKGBUILD de um pacote do AUR deve ser exibido para edição antes da instalação/atualização/reversão
|
||||
arch.config.mirrors_sort_limit=Limite de ordenação de espelhos
|
||||
@@ -196,6 +198,7 @@ arch.substatus.integrity=Verificando a integridade dos pacotes
|
||||
arch.substatus.keyring=Verificando o keyring
|
||||
arch.substatus.loading_files=Carregando os arquivos dos pacotes
|
||||
arch.substatus.pre_hooks=Executando ganchos pré-transação
|
||||
arch.sync.dep_breakage.reason={} precisa de {}
|
||||
arch.sync_databases.substatus=Sincronizando bases de pacotes
|
||||
arch.sync_databases.substatus.error=Não foi possível sincronizar as bases de pacotes
|
||||
arch.task.disk_cache=Indexando dados de pacotes
|
||||
|
||||
@@ -42,6 +42,8 @@ arch.config.aur_remove_build_dir=Remove build directory (AUR)
|
||||
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
|
||||
arch.config.clean_cache=Remove old versions
|
||||
arch.config.clean_cache.tip=Whether old versions of a package stored on disk should be removed during uninstall
|
||||
arch.config.check_dependency_breakage=Check dependency version breakage
|
||||
arch.config.check_dependency_breakage.tip=If, during the verification of upgrade requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B.
|
||||
arch.config.edit_aur_pkgbuild=Edit PKGBUILD (AUR)
|
||||
arch.config.edit_aur_pkgbuild.tip=If the PKGBUILD file of an AUR package should be displayed for editing before its installation/upgrade/downgrade
|
||||
arch.config.mirrors_sort_limit=Ограничение сортировки зеркал
|
||||
@@ -196,6 +198,7 @@ arch.substatus.integrity=Checking packages integrity
|
||||
arch.substatus.keyring=Checking keyring
|
||||
arch.substatus.loading_files=Loading package files
|
||||
arch.substatus.pre_hooks=Running pre-transaction hooks
|
||||
arch.sync.dep_breakage.reason={} requires {}
|
||||
arch.sync_databases.substatus=Синхронизация баз данных пакетов
|
||||
arch.sync_databases.substatus.error=Синхронизировать базу данных пакета не удалось
|
||||
arch.task.disk_cache=Indexing packages data
|
||||
|
||||
@@ -42,6 +42,8 @@ arch.config.aur_remove_build_dir=Remove build directory (AUR)
|
||||
arch.config.aur_remove_build_dir.tip=If a package's generated build directory should be removed after the operations is finished.
|
||||
arch.config.clean_cache=Önbelleği temizle
|
||||
arch.config.clean_cache.tip=Disk üzerinde kurulu bir paketin eski sürümlerinin kaldırma sırasında kaldırılıp kaldırılmayacağı
|
||||
arch.config.check_dependency_breakage=Check dependency version breakage
|
||||
arch.config.check_dependency_breakage.tip=If, during the verification of upgrade requirements, specific versions of dependencies must also be checked. Example: package A depends on version 1.0 of B.
|
||||
arch.config.edit_aur_pkgbuild=Edit PKGBUILD (AUR)
|
||||
arch.config.edit_aur_pkgbuild.tip=If the PKGBUILD file of an AUR package should be displayed for editing before its installation/upgrade/downgrade
|
||||
arch.config.mirrors_sort_limit=Yansı sıralama sınırı
|
||||
@@ -196,6 +198,7 @@ arch.substatus.integrity=Checking packages integrity
|
||||
arch.substatus.keyring=Checking keyring
|
||||
arch.substatus.loading_files=Loading package files
|
||||
arch.substatus.pre_hooks=Running pre-transaction hooks
|
||||
arch.sync.dep_breakage.reason={} requires {}
|
||||
arch.sync_databases.substatus=Paket veritabanı eşitleniyor
|
||||
arch.sync_databases.substatus.error=Paket veritabanı eşitlenemedi
|
||||
arch.task.disk_cache=Indexing packages data
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import logging
|
||||
import time
|
||||
from distutils.version import LooseVersion
|
||||
from threading import Thread
|
||||
from typing import Dict, Set, List, Tuple, Iterable
|
||||
from typing import Dict, Set, List, Tuple, Iterable, Optional
|
||||
|
||||
from bauh.api.abstract.controller import UpgradeRequirements, UpgradeRequirement
|
||||
from bauh.api.abstract.handler import ProcessWatcher
|
||||
@@ -261,38 +262,53 @@ class UpdatesSummarizer:
|
||||
context.pkgs_data.update(all_to_install_data)
|
||||
self._fill_conflicts(context, context.to_remove.keys())
|
||||
|
||||
if context.to_install:
|
||||
self.__fill_provided_map(context=context, pkgs=context.to_install, fill_installed=False)
|
||||
|
||||
tf = time.time()
|
||||
self.logger.info("It took {0:.2f} seconds to retrieve required upgrade packages".format(tf - ti))
|
||||
return True
|
||||
|
||||
def __fill_provided_map(self, context: UpdateRequirementsContext):
|
||||
ti = time.time()
|
||||
self.logger.info("Filling provided names")
|
||||
context.installed_names = pacman.list_installed_names()
|
||||
installed_to_ignore = set()
|
||||
def __fill_provided_map(self, context: UpdateRequirementsContext, pkgs: Dict[str, ArchPackage], fill_installed: bool = True):
|
||||
if pkgs:
|
||||
ti = time.time()
|
||||
self.logger.info("Filling provided names")
|
||||
|
||||
for pkgname in context.to_update:
|
||||
pacman.fill_provided_map(pkgname, pkgname, context.provided_map)
|
||||
installed_to_ignore.add(pkgname)
|
||||
if not context.installed_names:
|
||||
context.installed_names = pacman.list_installed_names()
|
||||
|
||||
pdata = context.pkgs_data.get(pkgname)
|
||||
if pdata and pdata['p']:
|
||||
pacman.fill_provided_map('{}={}'.format(pkgname, pdata['v']), pkgname, context.provided_map)
|
||||
for p in pdata['p']:
|
||||
pacman.fill_provided_map(p, pkgname, context.provided_map)
|
||||
split_provided = p.split('=')
|
||||
installed_to_ignore = set()
|
||||
|
||||
if len(split_provided) > 1 and split_provided[0] != p:
|
||||
pacman.fill_provided_map(split_provided[0], pkgname, context.provided_map)
|
||||
for pkgname in pkgs:
|
||||
pacman.fill_provided_map(pkgname, 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 fill_installed:
|
||||
installed_to_ignore.add(pkgname)
|
||||
|
||||
if installed_to_query:
|
||||
context.provided_map.update(pacman.map_provided(remote=False, pkgs=installed_to_query))
|
||||
pdata = context.pkgs_data.get(pkgname)
|
||||
if pdata and pdata['p']:
|
||||
pacman.fill_provided_map('{}={}'.format(pkgname, pdata['v']), pkgname, context.provided_map)
|
||||
|
||||
tf = time.time()
|
||||
self.logger.info("Filling provided names took {0:.2f} seconds".format(tf - ti))
|
||||
ver_split = pdata['v'].split('-')
|
||||
|
||||
if len(ver_split) > 1:
|
||||
pacman.fill_provided_map('{}={}'.format(pkgname, '-'.join(ver_split[0:-1])), pkgname, context.provided_map)
|
||||
|
||||
for p in pdata['p']:
|
||||
pacman.fill_provided_map(p, pkgname, context.provided_map)
|
||||
split_provided = p.split('=')
|
||||
|
||||
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 installed_to_query:
|
||||
context.provided_map.update(pacman.map_provided(remote=False, pkgs=installed_to_query))
|
||||
|
||||
tf = time.time()
|
||||
self.logger.info("Filling provided names took {0:.2f} seconds".format(tf - ti))
|
||||
|
||||
def __fill_aur_index(self, context: UpdateRequirementsContext):
|
||||
if context.arch_config['aur']:
|
||||
@@ -381,7 +397,7 @@ class UpdatesSummarizer:
|
||||
if aur_data:
|
||||
context.pkgs_data.update(aur_data)
|
||||
|
||||
self.__fill_provided_map(context)
|
||||
self.__fill_provided_map(context=context, pkgs=context.to_update)
|
||||
|
||||
if context.pkgs_data:
|
||||
self._fill_conflicts(context)
|
||||
@@ -394,6 +410,9 @@ class UpdatesSummarizer:
|
||||
self.logger.error("Package '{}' not found".format(e.name))
|
||||
return
|
||||
|
||||
if context.pkgs_data:
|
||||
self._fill_dependency_breakage(context)
|
||||
|
||||
self.__update_context_based_on_to_remove(context)
|
||||
|
||||
if context.to_update:
|
||||
@@ -558,3 +577,166 @@ class UpdatesSummarizer:
|
||||
self._add_to_remove(pkgs_to_sync, {dep: {n} for dep in all_deps}, context, blacklist)
|
||||
else:
|
||||
self.logger.warning("Package '{}' could not be removed from the transaction context because its data was not loaded")
|
||||
|
||||
def _fill_dependency_breakage(self, context: UpdateRequirementsContext):
|
||||
if bool(context.arch_config['check_dependency_breakage']) and (context.to_update or context.to_install):
|
||||
ti = time.time()
|
||||
self.logger.info("Begin: checking dependency breakage")
|
||||
|
||||
required_by = pacman.map_required_by(context.to_update.keys()) if context.to_update else {}
|
||||
|
||||
if context.to_install:
|
||||
required_by.update(pacman.map_required_by(context.to_install.keys(), remote=True))
|
||||
|
||||
reqs_not_in_transaction = set()
|
||||
reqs_in_transaction = set()
|
||||
|
||||
transaction_pkgs = {*context.to_update.keys(), *context.to_install.keys()}
|
||||
|
||||
for reqs in required_by.values():
|
||||
for r in reqs:
|
||||
if r in transaction_pkgs:
|
||||
reqs_in_transaction.add(r)
|
||||
elif r in context.installed_names:
|
||||
reqs_not_in_transaction.add(r)
|
||||
|
||||
if not reqs_not_in_transaction and not reqs_in_transaction:
|
||||
return
|
||||
|
||||
provided_versions = {}
|
||||
|
||||
for p in context.provided_map:
|
||||
pkg_split = p.split('=')
|
||||
|
||||
if len(pkg_split) > 1:
|
||||
versions = provided_versions.get(pkg_split[0])
|
||||
|
||||
if versions is None:
|
||||
versions = set()
|
||||
provided_versions[pkg_split[0]] = versions
|
||||
|
||||
versions.add(pkg_split[1])
|
||||
|
||||
if not provided_versions:
|
||||
return
|
||||
|
||||
cannot_upgrade = set()
|
||||
|
||||
for pkg, deps in pacman.map_required_dependencies(*reqs_not_in_transaction).items():
|
||||
self._add_dependency_breakage(pkgname=pkg,
|
||||
pkgdeps=deps,
|
||||
provided_versions=provided_versions,
|
||||
cannot_upgrade=cannot_upgrade,
|
||||
context=context)
|
||||
|
||||
for pkg in reqs_in_transaction:
|
||||
data = context.pkgs_data[pkg]
|
||||
|
||||
if data and data['d']:
|
||||
self._add_dependency_breakage(pkgname=pkg,
|
||||
pkgdeps=data['d'],
|
||||
provided_versions=provided_versions,
|
||||
cannot_upgrade=cannot_upgrade,
|
||||
context=context)
|
||||
|
||||
if cannot_upgrade:
|
||||
cannot_upgrade.update(self._add_dependents_as_cannot_upgrade(context=context,
|
||||
names=cannot_upgrade,
|
||||
pkgs_available={*context.to_update.values(), *context.to_install.values()}))
|
||||
|
||||
for p in cannot_upgrade:
|
||||
if p in context.to_update:
|
||||
del context.to_update[p]
|
||||
|
||||
if p in context.repo_to_update:
|
||||
del context.repo_to_update[p]
|
||||
|
||||
if p in context.aur_to_update:
|
||||
del context.aur_to_update[p]
|
||||
|
||||
if p in context.pkgs_data:
|
||||
del context.pkgs_data[p]
|
||||
|
||||
if p in context.to_install:
|
||||
del context.to_install[p]
|
||||
|
||||
if p in context.repo_to_install:
|
||||
del context.repo_to_install[p]
|
||||
|
||||
if p in context.aur_to_install:
|
||||
del context.aur_to_install[p]
|
||||
|
||||
tf = time.time()
|
||||
self.logger.info("End: checking dependency breakage. Time: {0:.2f} seconds".format(tf - ti))
|
||||
|
||||
def _add_dependents_as_cannot_upgrade(self, context: UpdateRequirementsContext, names: Iterable[str], pkgs_available: Set[ArchPackage], already_removed: Optional[Set[str]] = None, iteration_level: int = 0) -> Set[str]:
|
||||
removed = set() if already_removed is None else already_removed
|
||||
removed.update(names)
|
||||
|
||||
available = {p for p in pkgs_available if p.name not in removed}
|
||||
to_remove = set()
|
||||
|
||||
if available:
|
||||
for pkg in available:
|
||||
if pkg.name not in removed:
|
||||
data = context.pkgs_data.get(pkg.name)
|
||||
|
||||
if data and data['d']:
|
||||
for dep in data['d']:
|
||||
dep_providers = context.provided_map.get(dep)
|
||||
|
||||
if dep_providers:
|
||||
for p in dep_providers:
|
||||
if p in names:
|
||||
to_remove.add(pkg.name)
|
||||
|
||||
if pkg.name not in context.cannot_upgrade:
|
||||
reason = "{} {}".format(self.i18n['arch.info.depends on'].capitalize(), p)
|
||||
context.cannot_upgrade[pkg.name] = UpgradeRequirement(pkg=pkg,
|
||||
reason=reason,
|
||||
sorting_priority=iteration_level - 1)
|
||||
|
||||
break
|
||||
|
||||
if to_remove:
|
||||
removed.update(to_remove)
|
||||
self._add_dependents_as_cannot_upgrade(context=context, names=to_remove, pkgs_available=available,
|
||||
already_removed=to_remove, iteration_level=iteration_level-1)
|
||||
|
||||
return to_remove
|
||||
|
||||
def _add_dependency_breakage(self, pkgname: str, pkgdeps: Optional[Set[str]], provided_versions: Dict[str, Set[str]], cannot_upgrade: Set[str], context: UpdateRequirementsContext):
|
||||
if pkgdeps:
|
||||
for dep in pkgdeps:
|
||||
dep_split = RE_DEP_OPERATORS.split(dep)
|
||||
|
||||
if len(dep_split) > 1 and dep_split[1]:
|
||||
real_providers = context.provided_map.get(dep_split[0])
|
||||
|
||||
if real_providers:
|
||||
versions = provided_versions.get(dep_split[0])
|
||||
|
||||
if versions:
|
||||
op = ''.join(RE_DEP_OPERATORS.findall(dep))
|
||||
|
||||
if op == '=':
|
||||
op = '=='
|
||||
|
||||
version_match = False
|
||||
|
||||
for v in versions:
|
||||
provided_version, required_version = LooseVersion(v), LooseVersion(dep_split[1])
|
||||
|
||||
if eval('provided_version {} required_version'.format(op)):
|
||||
version_match = True
|
||||
break
|
||||
|
||||
if not version_match:
|
||||
for pname in real_providers:
|
||||
if pname not in cannot_upgrade:
|
||||
provider = context.to_update.get(pname)
|
||||
if provider:
|
||||
cannot_upgrade.add(pname)
|
||||
reason = self.i18n['arch.sync.dep_breakage.reason'].format(pkgname, dep)
|
||||
context.cannot_upgrade[pname] = UpgradeRequirement(pkg=provider,
|
||||
reason=reason)
|
||||
|
||||
@@ -619,6 +619,7 @@ class FormMultipleSelectQt(QWidget):
|
||||
help_icon = QLabel()
|
||||
help_icon.setPixmap(pixmap_help)
|
||||
help_icon.setToolTip(op.tooltip)
|
||||
help_icon.setCursor(QCursor(Qt.PointingHandCursor))
|
||||
widget.layout().addWidget(help_icon)
|
||||
|
||||
self._layout.addWidget(widget, line, col)
|
||||
|
||||
@@ -193,7 +193,7 @@ class UpgradeSelected(AsyncAction):
|
||||
self.manager = manager
|
||||
self.i18n = i18n
|
||||
|
||||
def _req_as_option(self, req: UpgradeRequirement, tooltip: bool = True, custom_tooltip: str = None, required_size: bool = True) -> InputOption:
|
||||
def _req_as_option(self, req: UpgradeRequirement, tooltip: bool = True, custom_tooltip: str = None, required_size: bool = True, display_sizes: bool = True) -> InputOption:
|
||||
if req.pkg.installed:
|
||||
icon_path = req.pkg.get_disk_icon_path()
|
||||
|
||||
@@ -205,15 +205,19 @@ class UpgradeSelected(AsyncAction):
|
||||
else:
|
||||
icon_path = req.pkg.get_type_icon_path()
|
||||
|
||||
size_str = '{}: {}'.format(self.i18n['size'].capitalize(),
|
||||
'?' if req.extra_size is None else get_human_size_str(req.extra_size))
|
||||
if required_size and req.extra_size != req.required_size:
|
||||
size_str += ' ( {}: {} )'.format(self.i18n['action.update.pkg.required_size'].capitalize(),
|
||||
'?' if req.required_size is None else get_human_size_str(req.required_size))
|
||||
size_str = None
|
||||
if display_sizes:
|
||||
size_str = '{}: {}'.format(self.i18n['size'].capitalize(),
|
||||
'?' if req.extra_size is None else get_human_size_str(req.extra_size))
|
||||
if required_size and req.extra_size != req.required_size:
|
||||
size_str += ' ( {}: {} )'.format(self.i18n['action.update.pkg.required_size'].capitalize(),
|
||||
'?' if req.required_size is None else get_human_size_str(req.required_size))
|
||||
|
||||
label = '{}{} - {}'.format(req.pkg.name,
|
||||
' ( {} )'.format(req.pkg.latest_version) if req.pkg.latest_version else '',
|
||||
size_str)
|
||||
label = '{}{}'.format(req.pkg.name,
|
||||
' ( {} )'.format(req.pkg.latest_version) if req.pkg.latest_version else '')
|
||||
|
||||
if size_str:
|
||||
label += ' - {}'.format(size_str)
|
||||
|
||||
return InputOption(label=label,
|
||||
value=None,
|
||||
@@ -232,11 +236,14 @@ class UpgradeSelected(AsyncAction):
|
||||
|
||||
return required, extra
|
||||
|
||||
def _gen_cannot_update_form(self, reqs: List[UpgradeRequirement]) -> FormComponent:
|
||||
opts = [self._req_as_option(r, False, r.reason) for r in reqs]
|
||||
def _gen_cannot_upgrade_form(self, reqs: List[UpgradeRequirement]) -> FormComponent:
|
||||
reqs.sort(key=UpgradeRequirement.sort_by_priority)
|
||||
opts = [self._req_as_option(req=r, tooltip=False, custom_tooltip=r.reason, display_sizes=False) for r in reqs]
|
||||
comps = [MultipleSelectComponent(label='', options=opts, default_options=set(opts))]
|
||||
|
||||
return FormComponent(label=self.i18n['action.update.cannot_update_label'], components=comps)
|
||||
return FormComponent(label='{} ( {}: {} )'.format(self.i18n['action.update.cannot_update_label'],
|
||||
self.i18n['amount'].capitalize(), len(opts)),
|
||||
components=comps)
|
||||
|
||||
def _gen_to_install_form(self, reqs: List[UpgradeRequirement]) -> Tuple[FormComponent, Tuple[int, int]]:
|
||||
opts = [self._req_as_option(r, custom_tooltip=r.reason) for r in reqs]
|
||||
@@ -396,7 +403,7 @@ class UpgradeSelected(AsyncAction):
|
||||
comps, required_size, extra_size = [], 0, 0
|
||||
|
||||
if requirements.cannot_upgrade:
|
||||
comps.append(self._gen_cannot_update_form(requirements.cannot_upgrade))
|
||||
comps.append(self._gen_cannot_upgrade_form(requirements.cannot_upgrade))
|
||||
|
||||
if requirements.to_install:
|
||||
req_form, reqs_size = self._gen_to_install_form(requirements.to_install)
|
||||
|
||||
Reference in New Issue
Block a user