mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 02:24:16 +02:00
[improvement][appimage] creating a symlink for the installed applications at '~.local/bin'
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 d’instal·lar {app}.
|
||||
appimage.install.desktop_entry=S’està creant una drecera del menú
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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ú
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=Создать ярлык в меню
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user