mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-08 13:14:17 +02:00
[improvement][arch] able to handle upgrade scenarios when a package wants to overwrite files of another installed package
This commit is contained in:
@@ -25,6 +25,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- the dialog is now displayed before the upgrading process (but the operation is only executed after a successful upgrade)
|
- the dialog is now displayed before the upgrading process (but the operation is only executed after a successful upgrade)
|
||||||
- Settings
|
- Settings
|
||||||
- new option to disable the reboot dialog after a successful upgrade (`updates.ask_for_reboot`)
|
- new option to disable the reboot dialog after a successful upgrade (`updates.ask_for_reboot`)
|
||||||
|
- Arch
|
||||||
|
- able to handle upgrade scenarios when a package wants to overwrite files of another installed package
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Arch
|
- Arch
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ from bauh.api.abstract.handler import ProcessWatcher, TaskManager
|
|||||||
from bauh.api.abstract.model import PackageUpdate, PackageHistory, SoftwarePackage, PackageSuggestion, PackageStatus, \
|
from bauh.api.abstract.model import PackageUpdate, PackageHistory, SoftwarePackage, PackageSuggestion, PackageStatus, \
|
||||||
SuggestionPriority, CustomSoftwareAction
|
SuggestionPriority, CustomSoftwareAction
|
||||||
from bauh.api.abstract.view import MessageType, FormComponent, InputOption, SingleSelectComponent, SelectViewType, \
|
from bauh.api.abstract.view import MessageType, FormComponent, InputOption, SingleSelectComponent, SelectViewType, \
|
||||||
ViewComponent, PanelComponent, MultipleSelectComponent, TextInputComponent
|
ViewComponent, PanelComponent, MultipleSelectComponent, TextInputComponent, TextComponent
|
||||||
from bauh.api.constants import TEMP_DIR
|
from bauh.api.constants import TEMP_DIR
|
||||||
from bauh.commons import user
|
from bauh.commons import user
|
||||||
from bauh.commons.category import CategoriesDownloader
|
from bauh.commons.category import CategoriesDownloader
|
||||||
@@ -189,6 +189,7 @@ class ArchManager(SoftwareManager):
|
|||||||
manager=self)
|
manager=self)
|
||||||
}
|
}
|
||||||
self.index_aur = None
|
self.index_aur = None
|
||||||
|
self.re_file_conflict = re.compile(r'[\w\d\-_.]+:')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_semantic_search_map() -> Dict[str, str]:
|
def get_semantic_search_map() -> Dict[str, str]:
|
||||||
@@ -690,6 +691,66 @@ class ArchManager(SoftwareManager):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def _map_conflicting_file(self, output: str) -> List[TextComponent]:
|
||||||
|
error_idx = None
|
||||||
|
lines = output.split('\n')
|
||||||
|
for idx, l in enumerate(lines):
|
||||||
|
if l and l.strip().lower().startswith('error: failed to commit transaction (conflicting files)'):
|
||||||
|
error_idx = idx
|
||||||
|
break
|
||||||
|
|
||||||
|
files = []
|
||||||
|
|
||||||
|
if error_idx and error_idx + 1 < len(lines):
|
||||||
|
for idx in range(error_idx + 1, len(lines)):
|
||||||
|
line = lines[idx].strip()
|
||||||
|
|
||||||
|
if line and self.re_file_conflict.match(line):
|
||||||
|
files.append(TextComponent(' - {}'.format(line)))
|
||||||
|
|
||||||
|
return files
|
||||||
|
|
||||||
|
def _upgrade_repo_pkgs(self, pkgs: List[str], handler: ProcessHandler, root_password: str, overwrite_files: bool = False) -> bool:
|
||||||
|
try:
|
||||||
|
output_handler = TransactionStatusHandler(handler.watcher, self.i18n, len(pkgs), self.logger)
|
||||||
|
output_handler.start()
|
||||||
|
success, upgrade_output = handler.handle_simple(pacman.upgrade_several(pkgnames=pkgs,
|
||||||
|
root_password=root_password,
|
||||||
|
overwrite_conflicting_files=overwrite_files),
|
||||||
|
output_handler=output_handler.handle,)
|
||||||
|
output_handler.stop_working()
|
||||||
|
output_handler.join()
|
||||||
|
|
||||||
|
handler.watcher.change_substatus('')
|
||||||
|
|
||||||
|
if success:
|
||||||
|
handler.watcher.print("Repository packages successfully upgraded")
|
||||||
|
handler.watcher.change_substatus(self.i18n['arch.upgrade.caching_pkgs_data'])
|
||||||
|
repo_map = pacman.map_repositories(pkgs)
|
||||||
|
disk.save_several(pkgs, repo_map=repo_map, overwrite=True, maintainer=None)
|
||||||
|
return True
|
||||||
|
elif 'conflicting files' in upgrade_output:
|
||||||
|
files = self._map_conflicting_file(upgrade_output)
|
||||||
|
if not handler.watcher.request_confirmation(title=self.i18n['warning'].capitalize(),
|
||||||
|
body=self.i18n['arch.upgrade.error.conflicting_files'] + ':',
|
||||||
|
deny_label=self.i18n['arch.upgrade.conflicting_files.proceed'],
|
||||||
|
confirmation_label=self.i18n['arch.upgrade.conflicting_files.stop'],
|
||||||
|
components=files):
|
||||||
|
|
||||||
|
return self._upgrade_repo_pkgs(pkgs=pkgs, handler=handler, root_password=root_password, overwrite_files=True)
|
||||||
|
else:
|
||||||
|
handler.watcher.print("Aborted by the user")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
self.logger.error("'pacman' returned an unexpected response or error phrase after upgrading the repository packages")
|
||||||
|
return False
|
||||||
|
except:
|
||||||
|
handler.watcher.change_substatus('')
|
||||||
|
handler.watcher.print("An error occurred while upgrading repository packages")
|
||||||
|
self.logger.error("An error occurred while upgrading repository packages")
|
||||||
|
traceback.print_exc()
|
||||||
|
return False
|
||||||
|
|
||||||
def upgrade(self, requirements: UpgradeRequirements, root_password: str, watcher: ProcessWatcher) -> bool:
|
def upgrade(self, requirements: UpgradeRequirements, root_password: str, watcher: ProcessWatcher) -> bool:
|
||||||
self.aur_client.clean_caches()
|
self.aur_client.clean_caches()
|
||||||
watcher.change_status("{}...".format(self.i18n['manage_window.status.upgrading']))
|
watcher.change_status("{}...".format(self.i18n['manage_window.status.upgrading']))
|
||||||
@@ -733,29 +794,7 @@ class ArchManager(SoftwareManager):
|
|||||||
self.logger.info("Upgrading {} repository packages: {}".format(len(repo_pkgs_names),
|
self.logger.info("Upgrading {} repository packages: {}".format(len(repo_pkgs_names),
|
||||||
', '.join(repo_pkgs_names)))
|
', '.join(repo_pkgs_names)))
|
||||||
|
|
||||||
try:
|
if not self._upgrade_repo_pkgs(pkgs=repo_pkgs_names, handler=handler, root_password=root_password):
|
||||||
output_handler = TransactionStatusHandler(watcher, self.i18n, len(repo_pkgs_names), self.logger)
|
|
||||||
output_handler.start()
|
|
||||||
success, _ = handler.handle_simple(pacman.upgrade_several(repo_pkgs_names, root_password), output_handler=output_handler.handle)
|
|
||||||
output_handler.stop_working()
|
|
||||||
output_handler.join()
|
|
||||||
|
|
||||||
watcher.change_substatus('')
|
|
||||||
|
|
||||||
if success:
|
|
||||||
watcher.print("Repository packages successfully upgraded")
|
|
||||||
watcher.change_substatus(self.i18n['arch.upgrade.caching_pkgs_data'])
|
|
||||||
repo_map = pacman.map_repositories(repo_pkgs_names)
|
|
||||||
disk.save_several(repo_pkgs_names, repo_map=repo_map, overwrite=True, maintainer=None)
|
|
||||||
|
|
||||||
else:
|
|
||||||
self.logger.error("'pacman' returned an unexpected response or error phrase after upgrading the repository packages")
|
|
||||||
return False
|
|
||||||
except:
|
|
||||||
watcher.change_substatus('')
|
|
||||||
watcher.print("An error occurred while upgrading repository packages")
|
|
||||||
self.logger.error("An error occurred while upgrading repository packages")
|
|
||||||
traceback.print_exc()
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
watcher.change_status('{}...'.format(self.i18n['arch.upgrade.upgrade_aur_pkgs']))
|
watcher.change_status('{}...'.format(self.i18n['arch.upgrade.upgrade_aur_pkgs']))
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ def install_as_process(pkgpaths: Iterable[str], root_password: str, file: bool,
|
|||||||
return SimpleProcess(cmd=cmd,
|
return SimpleProcess(cmd=cmd,
|
||||||
root_password=root_password,
|
root_password=root_password,
|
||||||
cwd=pkgdir,
|
cwd=pkgdir,
|
||||||
error_phrases={"error: failed to prepare transaction", 'error: failed to commit transaction'})
|
error_phrases={"error: failed to prepare transaction", 'error: failed to commit transaction', 'error: target not found'})
|
||||||
|
|
||||||
|
|
||||||
def list_desktop_entries(pkgnames: Set[str]) -> List[str]:
|
def list_desktop_entries(pkgnames: Set[str]) -> List[str]:
|
||||||
@@ -693,10 +693,15 @@ def list_installed_names() -> Set[str]:
|
|||||||
return {p for p in run_cmd('pacman -Qq').split('\n') if p}
|
return {p for p in run_cmd('pacman -Qq').split('\n') if p}
|
||||||
|
|
||||||
|
|
||||||
def upgrade_several(pkgnames: Iterable[str], root_password: str) -> SimpleProcess:
|
def upgrade_several(pkgnames: Iterable[str], root_password: str, overwrite_conflicting_files: bool = False) -> SimpleProcess:
|
||||||
return SimpleProcess(cmd=['pacman', '-S', *pkgnames, '--noconfirm'],
|
cmd = ['pacman', '-S', *pkgnames, '--noconfirm']
|
||||||
|
|
||||||
|
if overwrite_conflicting_files:
|
||||||
|
cmd.append('--overwrite=*')
|
||||||
|
|
||||||
|
return SimpleProcess(cmd=cmd,
|
||||||
root_password=root_password,
|
root_password=root_password,
|
||||||
error_phrases={'error: failed to prepare transaction', 'error: failed to commit transaction'})
|
error_phrases={'error: failed to prepare transaction', 'error: failed to commit transaction', 'error: target not found'})
|
||||||
|
|
||||||
|
|
||||||
def remove_several(pkgnames: Iterable[str], root_password: str) -> SystemProcess:
|
def remove_several(pkgnames: Iterable[str], root_password: str) -> SystemProcess:
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ arch.update_summary.to_install.dep_conflict=Conflict between the dependencies {}
|
|||||||
arch.update_summary.to_update.conflicts_dep=Conflicts with the dependency {} of {}
|
arch.update_summary.to_update.conflicts_dep=Conflicts with the dependency {} of {}
|
||||||
arch.update_summary.to_update.dep_conflicts=Dependency {} conflicts with {}
|
arch.update_summary.to_update.dep_conflicts=Dependency {} conflicts with {}
|
||||||
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
||||||
|
arch.upgrade.error.conflicting_files=Some of the packages being upgraded want to overwrite files of another installed packages
|
||||||
|
arch.upgrade.conflicting_files.proceed=Allow and continue
|
||||||
|
arch.upgrade.conflicting_files.stop=Cancel upgrading
|
||||||
arch.upgrade.fail=Package {} upgrade failed
|
arch.upgrade.fail=Package {} upgrade failed
|
||||||
arch.upgrade.success=Package {} successfully upgraded
|
arch.upgrade.success=Package {} successfully upgraded
|
||||||
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ arch.update_summary.to_install.dep_conflict=Conflict between the dependencies {}
|
|||||||
arch.update_summary.to_update.conflicts_dep=Conflicts with the dependency {} of {}
|
arch.update_summary.to_update.conflicts_dep=Conflicts with the dependency {} of {}
|
||||||
arch.update_summary.to_update.dep_conflicts=Dependency {} conflicts with {}
|
arch.update_summary.to_update.dep_conflicts=Dependency {} conflicts with {}
|
||||||
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
||||||
|
arch.upgrade.error.conflicting_files=Some of the packages being upgraded want to overwrite files of another installed packages
|
||||||
|
arch.upgrade.conflicting_files.proceed=Allow and continue
|
||||||
|
arch.upgrade.conflicting_files.stop=Cancel upgrading
|
||||||
arch.upgrade.fail=Package {} upgrade failed
|
arch.upgrade.fail=Package {} upgrade failed
|
||||||
arch.upgrade.success=Package {} successfully upgraded
|
arch.upgrade.success=Package {} successfully upgraded
|
||||||
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ arch.update_summary.to_install.dep_conflict=Conflict between the dependencies {}
|
|||||||
arch.update_summary.to_update.conflicts_dep=Conflicts with the dependency {} of {}
|
arch.update_summary.to_update.conflicts_dep=Conflicts with the dependency {} of {}
|
||||||
arch.update_summary.to_update.dep_conflicts=Dependency {} conflicts with {}
|
arch.update_summary.to_update.dep_conflicts=Dependency {} conflicts with {}
|
||||||
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
||||||
|
arch.upgrade.error.conflicting_files=Some of the packages being upgraded want to overwrite files of another installed packages
|
||||||
|
arch.upgrade.conflicting_files.proceed=Allow and continue
|
||||||
|
arch.upgrade.conflicting_files.stop=Cancel upgrading
|
||||||
arch.upgrade.fail=Package {} upgrade failed
|
arch.upgrade.fail=Package {} upgrade failed
|
||||||
arch.upgrade.success=Package {} successfully upgraded
|
arch.upgrade.success=Package {} successfully upgraded
|
||||||
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ arch.update_summary.to_install.dep_conflict=Conflicto entre las dependencias {}
|
|||||||
arch.update_summary.to_update.conflicts_dep=Conflicta con la dependencia {} de {}
|
arch.update_summary.to_update.conflicts_dep=Conflicta con la dependencia {} de {}
|
||||||
arch.update_summary.to_update.dep_conflicts=La dependencia {} conflicta con {}
|
arch.update_summary.to_update.dep_conflicts=La dependencia {} conflicta con {}
|
||||||
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
||||||
|
arch.upgrade.error.conflicting_files=Algunos de los paquetes que se están actualizando desean sobrescribir archivos de otros paquetes instalados
|
||||||
|
arch.upgrade.conflicting_files.proceed=Permitir y continuar
|
||||||
|
arch.upgrade.conflicting_files.stop=Cancelar la actualización
|
||||||
arch.upgrade.fail=Falló la actualización del paquete {}
|
arch.upgrade.fail=Falló la actualización del paquete {}
|
||||||
arch.upgrade.success=Paquete {} actualizado con éxito
|
arch.upgrade.success=Paquete {} actualizado con éxito
|
||||||
arch.upgrade.upgrade_aur_pkgs=Actualizando paquetes de AUR
|
arch.upgrade.upgrade_aur_pkgs=Actualizando paquetes de AUR
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ arch.update_summary.to_install.dep_conflict=Conflict between the dependencies {}
|
|||||||
arch.update_summary.to_update.conflicts_dep=Conflicts with the dependency {} of {}
|
arch.update_summary.to_update.conflicts_dep=Conflicts with the dependency {} of {}
|
||||||
arch.update_summary.to_update.dep_conflicts=Dependency {} conflicts with {}
|
arch.update_summary.to_update.dep_conflicts=Dependency {} conflicts with {}
|
||||||
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
||||||
|
arch.upgrade.error.conflicting_files=Some of the packages being upgraded want to overwrite files of another installed packages
|
||||||
|
arch.upgrade.conflicting_files.proceed=Allow and continue
|
||||||
|
arch.upgrade.conflicting_files.stop=Cancel upgrading
|
||||||
arch.upgrade.fail=Package {} upgrade failed
|
arch.upgrade.fail=Package {} upgrade failed
|
||||||
arch.upgrade.success=Package {} successfully upgraded
|
arch.upgrade.success=Package {} successfully upgraded
|
||||||
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ arch.update_summary.to_install.dep_conflict=Conflito entre as dependências {} e
|
|||||||
arch.update_summary.to_update.conflicts_dep=Conflita com a dependência {} de {}
|
arch.update_summary.to_update.conflicts_dep=Conflita com a dependência {} de {}
|
||||||
arch.update_summary.to_update.dep_conflicts=A dependência {} conflita com {}
|
arch.update_summary.to_update.dep_conflicts=A dependência {} conflita com {}
|
||||||
arch.upgrade.caching_pkgs_data=Armazenando dados das atualizações
|
arch.upgrade.caching_pkgs_data=Armazenando dados das atualizações
|
||||||
|
arch.upgrade.error.conflicting_files=Alguns dos pacotes que estão sendo atualizados querem sobrepor arquivos de outros pacotes instalados
|
||||||
|
arch.upgrade.conflicting_files.proceed=Permitir e continuar
|
||||||
|
arch.upgrade.conflicting_files.stop=Cancelar atualização
|
||||||
arch.upgrade.fail=Atualização do pacote {} falhou
|
arch.upgrade.fail=Atualização do pacote {} falhou
|
||||||
arch.upgrade.success=Pacote {} atualizado com sucesso
|
arch.upgrade.success=Pacote {} atualizado com sucesso
|
||||||
arch.upgrade.upgrade_aur_pkgs=Atualizando pacotes do AUR
|
arch.upgrade.upgrade_aur_pkgs=Atualizando pacotes do AUR
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ arch.update_summary.to_install.dep_conflict=Конфликт между зави
|
|||||||
arch.update_summary.to_update.conflicts_dep=Конфликты с зависимостью {} от {}
|
arch.update_summary.to_update.conflicts_dep=Конфликты с зависимостью {} от {}
|
||||||
arch.update_summary.to_update.dep_conflicts=Зависимость {} конфликтует с {}
|
arch.update_summary.to_update.dep_conflicts=Зависимость {} конфликтует с {}
|
||||||
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
arch.upgrade.caching_pkgs_data=Caching upgrades data
|
||||||
|
arch.upgrade.error.conflicting_files=Some of the packages being upgraded want to overwrite files of another installed packages
|
||||||
|
arch.upgrade.conflicting_files.proceed=Allow and continue
|
||||||
|
arch.upgrade.conflicting_files.stop=Cancel upgrading
|
||||||
arch.upgrade.fail=Package {} upgrade failed
|
arch.upgrade.fail=Package {} upgrade failed
|
||||||
arch.upgrade.success=Package {} successfully upgraded
|
arch.upgrade.success=Package {} successfully upgraded
|
||||||
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
arch.upgrade.upgrade_aur_pkgs=Upgrading AUR packages
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ arch.update_summary.to_install.dep_conflict={} ve {} bağımlılıkları arasın
|
|||||||
arch.update_summary.to_update.conflicts_dep={} / {} bağımlılığıyla ilgili çakışmalar
|
arch.update_summary.to_update.conflicts_dep={} / {} bağımlılığıyla ilgili çakışmalar
|
||||||
arch.update_summary.to_update.dep_conflicts=Bağımlılık {} ile {} çakışıyor
|
arch.update_summary.to_update.dep_conflicts=Bağımlılık {} ile {} çakışıyor
|
||||||
arch.upgrade.caching_pkgs_data=Yükseltme verileri önbelleğe alınıyor
|
arch.upgrade.caching_pkgs_data=Yükseltme verileri önbelleğe alınıyor
|
||||||
|
arch.upgrade.error.conflicting_files=Some of the packages being upgraded want to overwrite files of another installed packages
|
||||||
|
arch.upgrade.conflicting_files.proceed=Allow and continue
|
||||||
|
arch.upgrade.conflicting_files.stop=Cancel upgrading
|
||||||
arch.upgrade.fail={} paketi yükseltilemedi
|
arch.upgrade.fail={} paketi yükseltilemedi
|
||||||
arch.upgrade.success={} paketi başarıyla yükseltildi
|
arch.upgrade.success={} paketi başarıyla yükseltildi
|
||||||
arch.upgrade.upgrade_aur_pkgs=AUR paketleri yükseltiliyor
|
arch.upgrade.upgrade_aur_pkgs=AUR paketleri yükseltiliyor
|
||||||
|
|||||||
Reference in New Issue
Block a user