Skip to content

Commit

Permalink
0.9.21
Browse files Browse the repository at this point in the history
  • Loading branch information
vinifmor authored Nov 20, 2021
2 parents 6f65556 + 2cc532f commit 7cbe98f
Show file tree
Hide file tree
Showing 48 changed files with 421 additions and 234 deletions.
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@ 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.9.21] 2021-11-20
### Fixes
- General
- more fixes related to some backend commands hanging
- crashing when trying to retrieve a file size without proving its URL [#207](https://github.com/vinifmor/bauh/issues/207)

- AppImage
- displaying updates without the associated download URL for some applications [#207](https://github.com/vinifmor/bauh/issues/207)
- uninstalling the application when an update/downgrade download fails [#207](https://github.com/vinifmor/bauh/issues/207)

- Flatpak
- not displaying update components not associated with installed packages
- not displaying the updates size for Flatpak 1.2
- not displaying updates for "partials" listed as installed apps/runtimes

- UI
- upgrade summary: not displaying the icon type for some applications
- displaying initial warnings related to supported technologies even when they are not enabled or have the required dependencies
- crashing when QT components sizes are not integers [#198](https://github.com/vinifmor/bauh/issues/198)

### Improvements
- General
- multi-threaded download not enabled by default since it fails for some scenarios (still can be enabled through the settings panel/file)
- refactorings related to String concatenation

- AppImage
- not stopping the upgrade process when one of several applications have been selected to upgrade

## [0.9.20] 2021-11-05
### Improvements
- AppImage:
Expand Down
2 changes: 1 addition & 1 deletion bauh/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = '0.9.20'
__version__ = '0.9.21'
__app_name__ = 'bauh'

import os
Expand Down
2 changes: 1 addition & 1 deletion bauh/api/abstract/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
pass

@abstractmethod
def list_warnings(self, internet_available: bool) -> List[str]:
def list_warnings(self, internet_available: bool) -> Optional[List[str]]:
"""
:param internet_available
:return: a list of warnings to be shown to the user
Expand Down
3 changes: 3 additions & 0 deletions bauh/api/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ def get_yaml(self, url: str, params: dict = None, headers: dict = None, allow_re
return yaml.safe_load(res.text) if res else None

def get_content_length_in_bytes(self, url: str, session: bool = True) -> Optional[int]:
if not url:
return

params = {'url': url, 'allow_redirects': True, 'stream': True}

try:
Expand Down
8 changes: 3 additions & 5 deletions bauh/commons/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,10 @@ def new_subprocess(cmd: List[str], cwd: str = '.', shell: bool = False, stdin =
"stderr": PIPE,
"cwd": cwd,
"shell": shell,
"env": gen_env(global_interpreter, lang, extra_paths)
"env": gen_env(global_interpreter, lang, extra_paths),
"stdin": stdin if stdin else subprocess.DEVNULL
}

if input:
args['stdin'] = stdin

return subprocess.Popen(cmd, **args)


Expand Down Expand Up @@ -297,7 +295,7 @@ def get_human_size_str(size) -> str:


def run(cmd: List[str], success_code: int = 0) -> Tuple[bool, str]:
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.DEVNULL)
return p.returncode == success_code, p.stdout.decode()


Expand Down
3 changes: 2 additions & 1 deletion bauh/gems/appimage/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from pathlib import Path
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

ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
Expand All @@ -21,6 +21,7 @@
DESKTOP_ENTRIES_PATH = '{}/.local/share/applications'.format(str(Path.home()))
SUGGESTIONS_CACHED_FILE = '{}/suggestions.txt'.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:
Expand Down
143 changes: 102 additions & 41 deletions bauh/gems/appimage/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from bauh.commons.system import SystemProcess, new_subprocess, ProcessHandler, run_cmd, SimpleProcess
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, \
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.model import AppImage
from bauh.gems.appimage.util import replace_desktop_entry_exec_command
Expand Down Expand Up @@ -279,16 +279,18 @@ def read_installed(self, disk_loader: Optional[DiskCacheLoader], limit: int = -1
if app.name.lower() == tup[0].lower() and (not app.github or app.github.lower() == tup[1].lower()):
continuous_version = app.version == 'continuous'
continuous_update = tup[2] == 'continuous'
if continuous_version and not continuous_update:
app.update = True
elif continuous_update and not continuous_version:
app.update = False
else:
try:
app.update = parse_version(tup[2]) > parse_version(app.version) if tup[2] else False
except:

if tup[3]:
if continuous_version and not continuous_update:
app.update = True
elif continuous_update and not continuous_version:
app.update = False
traceback.print_exc()
else:
try:
app.update = parse_version(tup[2]) > parse_version(app.version) if tup[2] else False
except:
app.update = False
traceback.print_exc()

if app.update:
app.latest_version = tup[2]
Expand Down Expand Up @@ -331,12 +333,18 @@ def downgrade(self, pkg: AppImage, root_password: str, watcher: ProcessWatcher)
type_=MessageType.ERROR)
return False
else:
old_release = versions.history[versions.pkg_status_idx + 1]
pkg.version = old_release['0_version']
pkg.latest_version = pkg.version
pkg.url_download = old_release['2_url_download']

download_data = self._download(pkg=pkg, watcher=watcher)

if not download_data:
return False

if self.uninstall(pkg, root_password, watcher).success:
old_release = versions.history[versions.pkg_status_idx + 1]
pkg.version = old_release['0_version']
pkg.latest_version = pkg.version
pkg.url_download = old_release['2_url_download']
if self.install(pkg, root_password, None, watcher).success:
if self._install(pkg=pkg, watcher=watcher, pre_downloaded_file=download_data).success:
self.cache_to_disk(pkg, None, False)
return True
else:
Expand All @@ -351,24 +359,40 @@ def downgrade(self, pkg: AppImage, root_password: str, watcher: ProcessWatcher)
return False

def upgrade(self, requirements: UpgradeRequirements, root_password: str, watcher: ProcessWatcher) -> bool:
not_upgraded = []

for req in requirements.to_upgrade:
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:
not_upgraded.append(req.pkg)
watcher.change_substatus('')
continue

if not self.uninstall(req.pkg, root_password, watcher).success:
watcher.show_message(title=self.i18n['error'],
body=self.i18n['appimage.error.uninstall_current_version'],
type_=MessageType.ERROR)
not_upgraded.append(req.pkg)
watcher.change_substatus('')
return False
continue

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:
not_upgraded.append(req.pkg)
watcher.change_substatus('')
return False
continue

self.cache_to_disk(req.pkg, None, False)

all_failed = len(not_upgraded) == len(requirements.to_upgrade)

if not_upgraded:
pkgs_str = ''.join((f'<li>{app.name}</li>' for app in not_upgraded))
watcher.show_message(title=self.i18n['error' if all_failed else 'warning'].capitalize(),
body=self.i18n['appimage.upgrade.failed'].format(apps=f'<ul>{pkgs_str}</ul>'),
type_=MessageType.ERROR if all_failed else MessageType.WARNING)

watcher.change_substatus('')
return True
return not all_failed

def uninstall(self, pkg: AppImage, root_password: str, watcher: ProcessWatcher, disk_loader: DiskCacheLoader = None) -> TransactionResult:
if os.path.exists(pkg.get_disk_cache_path()):
Expand Down Expand Up @@ -486,9 +510,38 @@ def _find_icon_file(self, folder: str) -> str:
if RE_ICON_ENDS_WITH.match(f):
return f

def _download(self, pkg: AppImage, watcher: ProcessWatcher) -> Optional[Tuple[str, str]]:
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.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:
handler = ProcessHandler(watcher)
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()
counter = 0
while True:
Expand Down Expand Up @@ -516,35 +569,45 @@ def install(self, pkg: AppImage, root_password: str, disk_loader: Optional[DiskC

if not moved:
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)

return TransactionResult.fail()

else:
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
download_data = pre_downloaded_file if pre_downloaded_file else self._download(pkg, watcher)

file_path = out_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 download_data:
return TransactionResult.fail()

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)))
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:

watcher.change_substatus(self.i18n['appimage.install.extract'].format(bold(file_name)))

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:
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)
handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
return TransactionResult.fail()
Expand All @@ -568,7 +631,7 @@ def install(self, pkg: AppImage, root_password: str, disk_loader: Optional[DiskC
if de_content:
de_content = replace_desktop_entry_exec_command(desktop_entry=de_content,
appname=pkg.name,
file_path=file_path)
file_path=install_file_path)
extracted_icon = self._find_icon_file(extracted_folder)

if extracted_icon:
Expand All @@ -593,20 +656,18 @@ def install(self, pkg: AppImage, root_password: str, disk_loader: Optional[DiskC
except:
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=[])
else:
watcher.show_message(title=self.i18n['error'],
body='Could extract content from {}'.format(bold(file_name)),
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])))
return TransactionResult.fail()


def _gen_desktop_entry_path(self, app: AppImage) -> str:
return '{}/bauh_appimage_{}.desktop'.format(DESKTOP_ENTRIES_PATH, app.get_clean_name())

Expand Down
3 changes: 2 additions & 1 deletion bauh/gems/appimage/resources/locale/ca
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ appimage.downgrade.impossible.body={} té només una versió publicada.
appimage.downgrade.impossible.title=No s’ha pogut revertir la versió
appimage.downgrade.install_version=No s’ha pogut instal·lar la versió {} ({})
appimage.downgrade.unknown_version.body=No s’ha pogut identificar la versió actual de {} a l’historial de versions
appimage.download.error=No s’ha pogut baixar el fitxer {}. El servidor del fitxer pot estar inactiu.
appimage.error.uninstall_current_version=It was not possible to uninstall the current version of {}
appimage.history.0_version=versió
appimage.history.1_published_at=data
Expand All @@ -29,13 +30,13 @@ appimage.info.symlink=Symlink
appimage.info.url_download=URL del fitxer
appimage.install.appimagelauncher.error={appimgl} no permet la instal·lació de {app}. Desinstal·leu {appimgl}, reinicieu el sistema i torneu a provar d’instal·lar {app}.
appimage.install.desktop_entry=S’està creant una drecera del menú
appimage.install.download.error=No s’ha pogut baixar el fitxer {}. El servidor del fitxer pot estar inactiu.
appimage.install.extract=S’està extraient el contingut de {}
appimage.install.imported.rename_error=It was not possible to move the file {} to {}
appimage.install.permission=S’està concedint el permís d’execució a {}
appimage.update_database.deleting_old=Removing old files
appimage.update_database.downloading=Downloading database files
appimage.update_database.uncompressing=Uncompressing files
appimage.upgrade.failed=It was not possible to upgrade the following applications: {apps}
appimage.task.db_update=Actualització de bases de dades
appimage.task.db_update.checking=Checking for updates
appimage.task.suggestions=Downloading suggestions
Expand Down
Loading

0 comments on commit 7cbe98f

Please sign in to comment.