mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-06 22:54:16 +02:00
[appimage] fix: uninstalling the application when an update download fails
This commit is contained in:
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
|
|
||||||
- AppImage
|
- AppImage
|
||||||
- displaying updates without the associated download URL for some applications [#207](https://github.com/vinifmor/bauh/issues/207)
|
- displaying updates without the associated download URL for some applications [#207](https://github.com/vinifmor/bauh/issues/207)
|
||||||
|
- uninstalling the application when an update download fails [#207](https://github.com/vinifmor/bauh/issues/207)
|
||||||
|
|
||||||
- Flatpak
|
- Flatpak
|
||||||
- not displaying update components not associated with installed packages
|
- not displaying update components not associated with installed packages
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from bauh.api.constants import CONFIG_PATH, CACHE_PATH
|
from bauh.api.constants import CONFIG_PATH, CACHE_PATH, TEMP_DIR
|
||||||
from bauh.commons import resource
|
from bauh.commons import resource
|
||||||
|
|
||||||
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
@@ -21,6 +21,7 @@ DATABASES_TS_FILE = '{}/dbs.ts'.format(APPIMAGE_CACHE_PATH)
|
|||||||
DESKTOP_ENTRIES_PATH = '{}/.local/share/applications'.format(str(Path.home()))
|
DESKTOP_ENTRIES_PATH = '{}/.local/share/applications'.format(str(Path.home()))
|
||||||
SUGGESTIONS_CACHED_FILE = '{}/suggestions.txt'.format(APPIMAGE_CACHE_PATH)
|
SUGGESTIONS_CACHED_FILE = '{}/suggestions.txt'.format(APPIMAGE_CACHE_PATH)
|
||||||
SUGGESTIONS_CACHED_TS_FILE = '{}/suggestions.ts'.format(APPIMAGE_CACHE_PATH)
|
SUGGESTIONS_CACHED_TS_FILE = '{}/suggestions.ts'.format(APPIMAGE_CACHE_PATH)
|
||||||
|
DOWNLOAD_DIR = f'{TEMP_DIR}/appimage/download'
|
||||||
|
|
||||||
|
|
||||||
def get_icon_path() -> str:
|
def get_icon_path() -> str:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from bauh.commons.html import bold
|
|||||||
from bauh.commons.system import SystemProcess, new_subprocess, ProcessHandler, run_cmd, SimpleProcess
|
from bauh.commons.system import SystemProcess, new_subprocess, ProcessHandler, run_cmd, SimpleProcess
|
||||||
from bauh.gems.appimage import query, INSTALLATION_PATH, LOCAL_PATH, ROOT_DIR, \
|
from bauh.gems.appimage import query, INSTALLATION_PATH, LOCAL_PATH, ROOT_DIR, \
|
||||||
CONFIG_DIR, UPDATES_IGNORED_FILE, util, get_default_manual_installation_file_dir, DATABASE_APPS_FILE, \
|
CONFIG_DIR, UPDATES_IGNORED_FILE, util, get_default_manual_installation_file_dir, DATABASE_APPS_FILE, \
|
||||||
DATABASE_RELEASES_FILE, DESKTOP_ENTRIES_PATH, APPIMAGE_CACHE_PATH, get_icon_path
|
DATABASE_RELEASES_FILE, DESKTOP_ENTRIES_PATH, APPIMAGE_CACHE_PATH, get_icon_path, DOWNLOAD_DIR
|
||||||
from bauh.gems.appimage.config import AppImageConfigManager
|
from bauh.gems.appimage.config import AppImageConfigManager
|
||||||
from bauh.gems.appimage.model import AppImage
|
from bauh.gems.appimage.model import AppImage
|
||||||
from bauh.gems.appimage.util import replace_desktop_entry_exec_command
|
from bauh.gems.appimage.util import replace_desktop_entry_exec_command
|
||||||
@@ -356,6 +356,11 @@ class AppImageManager(SoftwareManager):
|
|||||||
for req in requirements.to_upgrade:
|
for req in requirements.to_upgrade:
|
||||||
watcher.change_status("{} {} ({})...".format(self.i18n['manage_window.status.upgrading'], req.pkg.name, req.pkg.version))
|
watcher.change_status("{} {} ({})...".format(self.i18n['manage_window.status.upgrading'], req.pkg.name, req.pkg.version))
|
||||||
|
|
||||||
|
download_data = self._download(req.pkg, watcher)
|
||||||
|
|
||||||
|
if not download_data:
|
||||||
|
return False
|
||||||
|
|
||||||
if not self.uninstall(req.pkg, root_password, watcher).success:
|
if not self.uninstall(req.pkg, root_password, watcher).success:
|
||||||
watcher.show_message(title=self.i18n['error'],
|
watcher.show_message(title=self.i18n['error'],
|
||||||
body=self.i18n['appimage.error.uninstall_current_version'],
|
body=self.i18n['appimage.error.uninstall_current_version'],
|
||||||
@@ -363,7 +368,7 @@ class AppImageManager(SoftwareManager):
|
|||||||
watcher.change_substatus('')
|
watcher.change_substatus('')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if not self.install(req.pkg, root_password, None, watcher).success:
|
if not self._install(pkg=req.pkg, watcher=watcher, pre_downloaded_file=download_data).success:
|
||||||
watcher.change_substatus('')
|
watcher.change_substatus('')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -488,9 +493,38 @@ class AppImageManager(SoftwareManager):
|
|||||||
if RE_ICON_ENDS_WITH.match(f):
|
if RE_ICON_ENDS_WITH.match(f):
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def install(self, pkg: AppImage, root_password: str, disk_loader: Optional[DiskCacheLoader], watcher: ProcessWatcher) -> TransactionResult:
|
def _download(self, pkg: AppImage, watcher: ProcessWatcher) -> Optional[Tuple[str, str]]:
|
||||||
handler = ProcessHandler(watcher)
|
appimage_url = pkg.url_download_latest_version if pkg.update else pkg.url_download
|
||||||
|
file_name = appimage_url.split('/')[-1]
|
||||||
|
pkg.version = pkg.latest_version
|
||||||
|
pkg.url_download = appimage_url
|
||||||
|
|
||||||
|
try:
|
||||||
|
Path(DOWNLOAD_DIR).mkdir(exist_ok=True, parents=True)
|
||||||
|
except OSError:
|
||||||
|
watcher.show_message(title=self.i18n['error'],
|
||||||
|
body=self.i18n['error.mkdir'].format(dir=bold(DOWNLOAD_DIR)),
|
||||||
|
type_=MessageType.ERROR)
|
||||||
|
return
|
||||||
|
|
||||||
|
file_path = f'{DOWNLOAD_DIR}/{file_name}'
|
||||||
|
downloaded = self.file_downloader.download(file_url=pkg.url_download, watcher=watcher,
|
||||||
|
output_path=file_path, cwd=str(Path.home()))
|
||||||
|
|
||||||
|
if not downloaded:
|
||||||
|
watcher.show_message(title=self.i18n['error'],
|
||||||
|
body=self.i18n['appimage.install.download.error'].format(bold(pkg.url_download)),
|
||||||
|
type_=MessageType.ERROR)
|
||||||
|
return
|
||||||
|
|
||||||
|
return file_name, file_path
|
||||||
|
|
||||||
|
def install(self, pkg: AppImage, root_password: str, disk_loader: Optional[DiskCacheLoader], watcher: ProcessWatcher) -> TransactionResult:
|
||||||
|
return self._install(pkg=pkg, watcher=watcher)
|
||||||
|
|
||||||
|
def _install(self, pkg: AppImage, watcher: ProcessWatcher, pre_downloaded_file: Optional[Tuple[str, str]] = None):
|
||||||
|
|
||||||
|
handler = ProcessHandler(watcher)
|
||||||
out_dir = INSTALLATION_PATH + pkg.get_clean_name()
|
out_dir = INSTALLATION_PATH + pkg.get_clean_name()
|
||||||
counter = 0
|
counter = 0
|
||||||
while True:
|
while True:
|
||||||
@@ -518,35 +552,45 @@ class AppImageManager(SoftwareManager):
|
|||||||
|
|
||||||
if not moved:
|
if not moved:
|
||||||
watcher.show_message(title=self.i18n['error'].capitalize(),
|
watcher.show_message(title=self.i18n['error'].capitalize(),
|
||||||
body=self.i18n['appimage.install.imported.rename_error'].format(bold(pkg.local_file_path.split('/')[-1]), bold(output)),
|
body=self.i18n['appimage.install.imported.rename_error'].format(
|
||||||
|
bold(pkg.local_file_path.split('/')[-1]), bold(output)),
|
||||||
type_=MessageType.ERROR)
|
type_=MessageType.ERROR)
|
||||||
|
|
||||||
return TransactionResult.fail()
|
return TransactionResult.fail()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
appimage_url = pkg.url_download_latest_version if pkg.update else pkg.url_download
|
download_data = pre_downloaded_file if pre_downloaded_file else self._download(pkg, watcher)
|
||||||
file_name = appimage_url.split('/')[-1]
|
|
||||||
pkg.version = pkg.latest_version
|
|
||||||
pkg.url_download = appimage_url
|
|
||||||
|
|
||||||
file_path = out_dir + '/' + file_name
|
if not download_data:
|
||||||
downloaded = self.file_downloader.download(file_url=pkg.url_download, watcher=watcher,
|
return TransactionResult.fail()
|
||||||
output_path=file_path, cwd=str(Path.home()))
|
|
||||||
|
file_name, download_path = download_data[0], download_data[1]
|
||||||
|
|
||||||
|
install_file_path = f'{out_dir}/{file_name}'
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.move(download_path, install_file_path)
|
||||||
|
except OSError:
|
||||||
|
watcher.show_message(title=self.i18n['error'],
|
||||||
|
body=self.i18n['error.mvfile'].formmat(src=bold(download_path),
|
||||||
|
dest=bold(install_file_path)))
|
||||||
|
return TransactionResult.fail()
|
||||||
|
|
||||||
if downloaded:
|
|
||||||
watcher.change_substatus(self.i18n['appimage.install.permission'].format(bold(file_name)))
|
watcher.change_substatus(self.i18n['appimage.install.permission'].format(bold(file_name)))
|
||||||
permission_given = handler.handle(SystemProcess(new_subprocess(['chmod', 'a+x', file_path])))
|
permission_given = handler.handle(SystemProcess(new_subprocess(['chmod', 'a+x', install_file_path])))
|
||||||
|
|
||||||
if permission_given:
|
if permission_given:
|
||||||
|
|
||||||
watcher.change_substatus(self.i18n['appimage.install.extract'].format(bold(file_name)))
|
watcher.change_substatus(self.i18n['appimage.install.extract'].format(bold(file_name)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
res, output = handler.handle_simple(SimpleProcess([file_path, '--appimage-extract'], cwd=out_dir))
|
res, output = handler.handle_simple(
|
||||||
|
SimpleProcess([install_file_path, '--appimage-extract'], cwd=out_dir))
|
||||||
|
|
||||||
if 'Error: Failed to register AppImage in AppImageLauncherFS' in output:
|
if 'Error: Failed to register AppImage in AppImageLauncherFS' in output:
|
||||||
watcher.show_message(title=self.i18n['error'],
|
watcher.show_message(title=self.i18n['error'],
|
||||||
body=self.i18n['appimage.install.appimagelauncher.error'].format(appimgl=bold('AppImageLauncher'), app=bold(pkg.name)),
|
body=self.i18n['appimage.install.appimagelauncher.error'].format(
|
||||||
|
appimgl=bold('AppImageLauncher'), app=bold(pkg.name)),
|
||||||
type_=MessageType.ERROR)
|
type_=MessageType.ERROR)
|
||||||
handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
|
handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
|
||||||
return TransactionResult.fail()
|
return TransactionResult.fail()
|
||||||
@@ -570,7 +614,7 @@ class AppImageManager(SoftwareManager):
|
|||||||
if de_content:
|
if de_content:
|
||||||
de_content = replace_desktop_entry_exec_command(desktop_entry=de_content,
|
de_content = replace_desktop_entry_exec_command(desktop_entry=de_content,
|
||||||
appname=pkg.name,
|
appname=pkg.name,
|
||||||
file_path=file_path)
|
file_path=install_file_path)
|
||||||
extracted_icon = self._find_icon_file(extracted_folder)
|
extracted_icon = self._find_icon_file(extracted_folder)
|
||||||
|
|
||||||
if extracted_icon:
|
if extracted_icon:
|
||||||
@@ -595,20 +639,18 @@ class AppImageManager(SoftwareManager):
|
|||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
SymlinksVerifier.create_symlink(app=pkg, file_path=file_path, logger=self.logger, watcher=watcher)
|
SymlinksVerifier.create_symlink(app=pkg, file_path=install_file_path, logger=self.logger,
|
||||||
|
watcher=watcher)
|
||||||
return TransactionResult(success=True, installed=[pkg], removed=[])
|
return TransactionResult(success=True, installed=[pkg], removed=[])
|
||||||
else:
|
else:
|
||||||
watcher.show_message(title=self.i18n['error'],
|
watcher.show_message(title=self.i18n['error'],
|
||||||
body='Could extract content from {}'.format(bold(file_name)),
|
body='Could extract content from {}'.format(bold(file_name)),
|
||||||
type_=MessageType.ERROR)
|
type_=MessageType.ERROR)
|
||||||
else:
|
|
||||||
watcher.show_message(title=self.i18n['error'],
|
|
||||||
body=self.i18n['appimage.install.download.error'].format(bold(pkg.url_download)),
|
|
||||||
type_=MessageType.ERROR)
|
|
||||||
|
|
||||||
handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
|
handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
|
||||||
return TransactionResult.fail()
|
return TransactionResult.fail()
|
||||||
|
|
||||||
|
|
||||||
def _gen_desktop_entry_path(self, app: AppImage) -> str:
|
def _gen_desktop_entry_path(self, app: AppImage) -> str:
|
||||||
return '{}/bauh_appimage_{}.desktop'.format(DESKTOP_ENTRIES_PATH, app.get_clean_name())
|
return '{}/bauh_appimage_{}.desktop'.format(DESKTOP_ENTRIES_PATH, app.get_clean_name())
|
||||||
|
|
||||||
|
|||||||
@@ -255,6 +255,8 @@ downgraded=revertida
|
|||||||
download=download
|
download=download
|
||||||
downloading=S’està baixant
|
downloading=S’està baixant
|
||||||
error=error
|
error=error
|
||||||
|
error.mkdir=Could not create directory {dir}
|
||||||
|
error.mvfile=Could not move {src} to {dest}
|
||||||
example.short=e.g
|
example.short=e.g
|
||||||
exit=surt
|
exit=surt
|
||||||
file=file
|
file=file
|
||||||
|
|||||||
@@ -254,6 +254,8 @@ downgraded=gedowngraded
|
|||||||
download=Download
|
download=Download
|
||||||
downloading=Download
|
downloading=Download
|
||||||
error=Fehler
|
error=Fehler
|
||||||
|
error.mkdir=Could not create directory {dir}
|
||||||
|
error.mvfile=Could not move {src} to {dest}
|
||||||
example.short=z.B.
|
example.short=z.B.
|
||||||
exit=Beenden
|
exit=Beenden
|
||||||
file=file
|
file=file
|
||||||
|
|||||||
@@ -254,6 +254,8 @@ downgraded=downgraded
|
|||||||
download=download
|
download=download
|
||||||
downloading=Downloading
|
downloading=Downloading
|
||||||
error=error
|
error=error
|
||||||
|
error.mkdir=Could not create directory {dir}
|
||||||
|
error.mvfile=Could not move {src} to {dest}
|
||||||
example.short=e.g
|
example.short=e.g
|
||||||
exit=exit
|
exit=exit
|
||||||
file=file
|
file=file
|
||||||
|
|||||||
@@ -255,6 +255,8 @@ downgraded=versión revertida
|
|||||||
download=descarga
|
download=descarga
|
||||||
downloading=Descargando
|
downloading=Descargando
|
||||||
error=error
|
error=error
|
||||||
|
error.mkdir=No se pudo crear el directorio {dir}
|
||||||
|
error.mvfile=No se pudo mover {src} a {dest}
|
||||||
example.short=p.ej
|
example.short=p.ej
|
||||||
exit=salir
|
exit=salir
|
||||||
file=archivo
|
file=archivo
|
||||||
|
|||||||
@@ -252,6 +252,8 @@ downgraded=downgradé
|
|||||||
download=télécharger
|
download=télécharger
|
||||||
downloading=Téléchargement en cours
|
downloading=Téléchargement en cours
|
||||||
error=erreur
|
error=erreur
|
||||||
|
error.mkdir=Could not create directory {dir}
|
||||||
|
error.mvfile=Could not move {src} to {dest}
|
||||||
example.short=ex
|
example.short=ex
|
||||||
exit=sortir
|
exit=sortir
|
||||||
file=fichier
|
file=fichier
|
||||||
|
|||||||
@@ -256,6 +256,8 @@ downgraded=downgraded
|
|||||||
download=download
|
download=download
|
||||||
downloading=Scaricamento
|
downloading=Scaricamento
|
||||||
error=errore
|
error=errore
|
||||||
|
error.mkdir=Could not create directory {dir}
|
||||||
|
error.mvfile=Could not move {src} to {dest}
|
||||||
example.short=e.g
|
example.short=e.g
|
||||||
exit=esci
|
exit=esci
|
||||||
file=file
|
file=file
|
||||||
|
|||||||
@@ -254,6 +254,8 @@ downgraded=versão revertida
|
|||||||
download=download
|
download=download
|
||||||
downloading=Baixando
|
downloading=Baixando
|
||||||
error=erro
|
error=erro
|
||||||
|
error.mkdir=Não foi possível criar o diretório {dir}
|
||||||
|
error.mvfile=Não foi possível mover {src} para {dest}
|
||||||
example.short=ex
|
example.short=ex
|
||||||
exit=sair
|
exit=sair
|
||||||
file=arquivo
|
file=arquivo
|
||||||
|
|||||||
@@ -254,6 +254,8 @@ downgraded=Произведён откат
|
|||||||
download=Загрузка
|
download=Загрузка
|
||||||
downloading=Загрузка
|
downloading=Загрузка
|
||||||
error=Ошибка
|
error=Ошибка
|
||||||
|
error.mkdir=Could not create directory {dir}
|
||||||
|
error.mvfile=Could not move {src} to {dest}
|
||||||
example.short=К примеру
|
example.short=К примеру
|
||||||
exit=Выход
|
exit=Выход
|
||||||
file=файл
|
file=файл
|
||||||
|
|||||||
@@ -254,6 +254,8 @@ downgraded=düşürüldü
|
|||||||
download=indir
|
download=indir
|
||||||
downloading=İndiriliyor
|
downloading=İndiriliyor
|
||||||
error=hata
|
error=hata
|
||||||
|
error.mkdir=Could not create directory {dir}
|
||||||
|
error.mvfile=Could not move {src} to {dest}
|
||||||
example.short=e.g
|
example.short=e.g
|
||||||
exit=çıkış
|
exit=çıkış
|
||||||
file=dosya
|
file=dosya
|
||||||
|
|||||||
Reference in New Issue
Block a user