[improvement][appimage] creating a symlink for the installed applications at '~.local/bin'

This commit is contained in:
Vinicius Moreira
2020-06-16 17:42:10 -03:00
parent 5701c95d2e
commit 20d6f0fa35
13 changed files with 91 additions and 7 deletions

View File

@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.9.6] 2020
### Improvements
- AppImage
- creating a symlink for the installed applications at **~.local/bin** (the link will have the same name of the application. if the link already exists, it will be named as 'app_name-appimage') [#122](https://github.com/vinifmor/bauh/issues/122)
- able to update AppImages with continuous releases
- UI
- not performing a full table refresh after installing and uninstalling packages

View File

@@ -128,6 +128,7 @@ installation_level: null # defines a default installation level: user or system.
- Supported sources: [AppImageHub](https://appimage.github.io) ( **applications with no releases published to GitHub are currently not available** )
- Installed applications are store at **~/.local/share/bauh/appimage/installed**
- Desktop entries ( menu shortcuts ) of the installed applications are stored at **~/.local/share/applications**
- Symlinks are created at **~/.local/bin**. They have the same name of the application (if the name already exists, it will be created as 'app_name-appimage'. e.g: 'rpcs3-appimage')
- Downloaded database files are stored at **~/.local/share/bauh/appimage** as **apps.db** and **releases.db**
- Databases are always updated when bauh starts
- Databases updater daemon running every 20 minutes ( it can be customized via the configuration file described below )

View File

@@ -11,6 +11,7 @@ SUGGESTIONS_FILE = 'https://raw.githubusercontent.com/vinifmor/bauh-files/master
CONFIG_FILE = '{}/appimage.yml'.format(CONFIG_PATH)
CONFIG_DIR = '{}/appimage'.format(CONFIG_PATH)
UPDATES_IGNORED_FILE = '{}/updates_ignored.txt'.format(CONFIG_DIR)
SYMLINKS_DIR = '{}/.local/bin'.format(str(Path.home()))
def get_icon_path() -> str:

View File

@@ -29,7 +29,7 @@ from bauh.commons.config import save_config
from bauh.commons.html import bold
from bauh.commons.system import SystemProcess, new_subprocess, ProcessHandler, run_cmd, SimpleProcess
from bauh.gems.appimage import query, INSTALLATION_PATH, LOCAL_PATH, SUGGESTIONS_FILE, CONFIG_FILE, ROOT_DIR, \
CONFIG_DIR, UPDATES_IGNORED_FILE
CONFIG_DIR, UPDATES_IGNORED_FILE, SYMLINKS_DIR
from bauh.gems.appimage.config import read_config
from bauh.gems.appimage.model import AppImage
from bauh.gems.appimage.worker import DatabaseUpdater
@@ -330,6 +330,19 @@ class AppImageManager(SoftwareManager):
self.revert_ignored_update(pkg)
if pkg.symlink and os.path.islink(pkg.symlink):
self.logger.info("Removing symlink '{}'".format(pkg.symlink))
try:
os.remove(pkg.symlink)
self.logger.info("symlink '{}' successfully removed".format(pkg.symlink))
except:
msg = "could not remove symlink '{}'".format(pkg.symlink)
self.logger.error(msg)
if watcher:
watcher.print("[error] {}".format(msg))
return TransactionResult(success=True, installed=None, removed=[pkg])
def get_managed_types(self) -> Set[Type[SoftwarePackage]]:
@@ -351,6 +364,9 @@ class AppImageManager(SoftwareManager):
if categories:
data['categories'] = [self.i18n.get('category.{}'.format(c.lower()), self.i18n.get(c, c)).capitalize() for c in data['categories']]
if data.get('symlink') and not os.path.islink(data['symlink']):
del data['symlink']
return data
def get_history(self, pkg: AppImage) -> PackageHistory:
@@ -442,7 +458,7 @@ class AppImageManager(SoftwareManager):
body=self.i18n['appimage.install.imported.rename_error'].format(bold(pkg.local_file_path.split('/')[-1]), bold(output)),
type_=MessageType.ERROR)
return TransactionResult(success=False, installed=[], removed=[])
return TransactionResult.fail()
else:
appimage_url = pkg.url_download_latest_version if pkg.update else pkg.url_download
@@ -470,14 +486,14 @@ class AppImageManager(SoftwareManager):
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(success=False, installed=[], removed=[])
return TransactionResult.fail()
except:
watcher.show_message(title=self.i18n['error'],
body=traceback.format_exc(),
type_=MessageType.ERROR)
traceback.print_exc()
handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
return TransactionResult(success=False, installed=[], removed=[])
return TransactionResult.fail()
watcher.change_substatus(self.i18n['appimage.install.desktop_entry'])
extracted_folder = '{}/{}'.format(out_dir, 'squashfs-root')
@@ -508,6 +524,8 @@ class AppImageManager(SoftwareManager):
except:
traceback.print_exc()
self._add_symlink(pkg, file_path, watcher)
return TransactionResult(success=True, installed=[pkg], removed=[])
else:
watcher.show_message(title=self.i18n['error'],
@@ -519,7 +537,60 @@ class AppImageManager(SoftwareManager):
type_=MessageType.ERROR)
handler.handle(SystemProcess(new_subprocess(['rm', '-rf', out_dir])))
return TransactionResult(success=False, installed=[], removed=[])
return TransactionResult.fail()
def _add_symlink(self, app: AppImage, file_path: str, watcher: ProcessWatcher = None):
possible_names = (app.name.lower(), '{}-appimage'.format(app.name.lower()))
if os.path.exists(SYMLINKS_DIR) and not os.path.isdir(SYMLINKS_DIR):
self.logger.warning("'{}' is not a directory. It will not be possible to create a symlink for '{}'".format(SYMLINKS_DIR, app.name))
return
available_system_dirs = (SYMLINKS_DIR, *(l for l in ('/usr/bin', '/usr/local/bin') if os.path.isdir(l)))
# checking if the link already exists:
available_name = None
for name in possible_names:
available_name = name
for sysdir in available_system_dirs:
if os.path.exists('{}/{}'.format(sysdir, name)):
available_name = None
break
if available_name:
break
if not available_name:
msg = "It was not possible to create a symlink for '{}' because the names {} are already available on the system".format(app.name,
possible_names)
self.logger.warning(msg)
if watcher:
watcher.print('[warning] {}'.format(msg))
else:
try:
Path(SYMLINKS_DIR).mkdir(parents=True, exist_ok=True)
except:
self.logger.error("Could not create symlink directory '{}'".format(SYMLINKS_DIR))
return
symlink_path = '{}/{}'.format(SYMLINKS_DIR, available_name)
try:
os.symlink(src=file_path, dst=symlink_path)
app.symlink = symlink_path
msg = "symlink successfully created at {}".format(symlink_path)
self.logger.info(msg)
if watcher:
watcher.print(msg)
except:
msg = "Could not create the symlink '{}'".format(symlink_path)
self.logger.error(msg)
if watcher:
watcher.print('[error] {}'.format(msg))
def _gen_desktop_entry_path(self, app: AppImage) -> str:
return '{}/bauh_appimage_{}.desktop'.format(DESKTOP_ENTRIES_PATH, app.name.lower())

View File

@@ -6,7 +6,7 @@ from bauh.gems.appimage import ROOT_DIR, INSTALLATION_PATH
from bauh.view.util.translation import I18n
CACHED_ATTRS = {'name', 'description', 'version', 'url_download', 'author', 'license', 'source',
'icon_path', 'github', 'categories', 'imported', 'install_dir'}
'icon_path', 'github', 'categories', 'imported', 'install_dir', 'symlink'}
class AppImage(SoftwarePackage):
@@ -15,7 +15,8 @@ class AppImage(SoftwarePackage):
url_download: str = None, url_icon: str = None, url_screenshot: str = None, license: str = None, author: str = None,
categories=None, icon_path: str = None, installed: bool = False,
url_download_latest_version: str = None, local_file_path: str = None, imported: bool = False,
i18n: I18n = None, install_dir: str = None, custom_actions: List[CustomSoftwareAction] = None, updates_ignored: bool = False, **kwargs):
i18n: I18n = None, install_dir: str = None, custom_actions: List[CustomSoftwareAction] = None, updates_ignored: bool = False,
symlink: str = None, **kwargs):
super(AppImage, self).__init__(id=name, name=name, version=version, latest_version=version,
icon_url=url_icon, license=license, description=description,
installed=installed)
@@ -33,6 +34,7 @@ class AppImage(SoftwarePackage):
self.install_dir = install_dir
self.custom_actions = custom_actions
self.updates_ignored = updates_ignored
self.symlink = symlink
def __repr__(self):
return "{} (name={}, github={})".format(self.__class__.__name__, self.name, self.github)

View File

@@ -23,6 +23,7 @@ appimage.info.icon_path=icona
appimage.info.imported.false=No
appimage.info.imported.true=Yes
appimage.info.install_dir=Installation directory
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 dinstal·lar {app}.
appimage.install.desktop_entry=Sestà creant una drecera del menú

View File

@@ -23,6 +23,7 @@ appimage.info.icon_path=icon
appimage.info.imported.false=Nien
appimage.info.imported.true=Ya
appimage.info.install_dir=Installation directory
appimage.info.symlink=Symlink
appimage.info.url_download=Datei URL
appimage.install.appimagelauncher.error={appimgl} verhindert die installation von {app}. Deinstalliere {appimgl}, starte deinen Computer neu und versuche die installation von {app} erneut.
appimage.install.desktop_entry=Menü-Shortcut erstellen

View File

@@ -23,6 +23,7 @@ appimage.info.icon_path=icon
appimage.info.imported.false=No
appimage.info.imported.true=Yes
appimage.info.install_dir=Installation directory
appimage.info.symlink=Symlink
appimage.info.url_download=File URL
appimage.install.appimagelauncher.error={appimgl} is not allowing {app} to be installed. Uninstall {appimgl}, reboot your system and try to install {app} again.
appimage.install.desktop_entry=Generating a menu shortcut

View File

@@ -23,6 +23,7 @@ appimage.info.icon_path=icono
appimage.info.imported.false=No
appimage.info.imported.true=Sí
appimage.info.install_dir=Directorio de instalación
appimage.info.symlink=Link simbólico
appimage.info.url_download=URL del archivo
appimage.install.appimagelauncher.error={appimgl} no permite la instalación de {app}. Desinstale {appimgl}, reinicie su sistema e intente instalar {app} nuevamente.
appimage.install.desktop_entry=Creando un atajo en el menú

View File

@@ -23,6 +23,7 @@ appimage.info.icon_path=icona
appimage.info.imported.false=No
appimage.info.imported.true=Yes
appimage.info.install_dir=Installation directory
appimage.info.symlink=Symlink
appimage.info.url_download=File URL
appimage.install.appimagelauncher.error={appimgl} non consente l'installazione di {app}. Disinstallare {appimgl}, riavviare il sistema e provare a installare nuovamente {app}.
appimage.install.desktop_entry=Genera un collegamento al menu

View File

@@ -23,6 +23,7 @@ appimage.info.icon_path=ícone
appimage.info.imported.false=Não
appimage.info.imported.true=Sim
appimage.info.install_dir=Diretório de instalação
appimage.info.symlink=Link simbólico
appimage.info.url_download=URL do arquivo
appimage.install.appimagelauncher.error={appimgl} não está permitindo que o {app} seja instalado. Desinstale o {appimgl}, reinicie o sistema e tente instalar o {app} novamente.
appimage.install.desktop_entry=Criando um atalho no menu

View File

@@ -23,6 +23,7 @@ appimage.info.icon_path=Значок
appimage.info.imported.false=Нет
appimage.info.imported.true=Да
appimage.info.install_dir=Директория установки
appimage.info.symlink=Symlink
appimage.info.url_download=URL Файла
appimage.install.appimagelauncher.error={appimgl} не позволяет установить {app} . Удалите {appimgl}, перезагрузите ваш компьютер и попробуйте снова установить {app} .
appimage.install.desktop_entry=Создать ярлык в меню

View File

@@ -23,6 +23,7 @@ appimage.info.icon_path=simge
appimage.info.imported.false=Hayır
appimage.info.imported.true=Evet
appimage.info.install_dir=Kurulum dizini
appimage.info.symlink=Symlink
appimage.info.url_download=Dosya Bağlantısı
appimage.install.appimagelauncher.error={appimgl}, {app} uygulamasının yüklenmesine izin vermiyor. {appimgl} yazılımını kaldırın, sisteminizi yeniden başlatın ve {app} yazılımını tekrar yüklemeyi deneyin.
appimage.install.desktop_entry=Bir menü kısayolu oluşturuluyor