installing appimage

This commit is contained in:
Vinicius Moreira
2019-10-03 19:09:31 -03:00
parent 593eb96a7e
commit 53bf6de34f
14 changed files with 230 additions and 11 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ __pycache__
dist
*.egg-info
build
*.db

View File

@@ -32,7 +32,7 @@ class SoftwarePackage(ABC):
def __init__(self, id: str = None, version: str = None, name: str = None, description: str = None, latest_version: str = None,
icon_url: str = None, status: PackageStatus = PackageStatus.READY, installed: bool = False, update: bool = False,
size: int = None, categories: List[str] = None):
size: int = None, categories: List[str] = None, license: str = None):
"""
:param id:
:param version:
@@ -57,6 +57,7 @@ class SoftwarePackage(ABC):
self.update = update
self.size = size
self.categories = categories
self.license = license
@abstractmethod
def has_history(self):

View File

@@ -31,15 +31,17 @@ def main():
cache_factory = DefaultMemoryCacheFactory(expiration_time=args.cache_exp, cleaner=cache_cleaner)
icon_cache = cache_factory.new(args.icon_exp)
http_client = HttpClient(logger)
context = ApplicationContext(i18n=i18n,
http_client=HttpClient(logger),
http_client=http_client,
disk_cache=args.disk_cache,
download_icons=args.download_icons,
app_root_dir=ROOT_DIR,
cache_factory=cache_factory,
disk_loader_factory=DefaultDiskCacheLoaderFactory(disk_cache_enabled=args.disk_cache, logger=logger),
logger=logger,
file_downloader=AdaptableFileDownloader(logger, bool(args.download_mthread)))
file_downloader=AdaptableFileDownloader(logger, bool(args.download_mthread),
i18n, http_client))
user_config = config.read()
app = QApplication(sys.argv)

View File

@@ -0,0 +1,6 @@
import os
from bauh.api.constants import HOME_PATH
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
INSTALLATION_PATH = '{}/.local/share/bauh/appimage/installed/'.format(HOME_PATH)

View File

@@ -0,0 +1,129 @@
import os
import sqlite3
from pathlib import Path
from typing import Set, Type, List
from bauh.api.abstract.context import ApplicationContext
from bauh.api.abstract.controller import SoftwareManager, SearchResult
from bauh.api.abstract.disk import DiskCacheLoader
from bauh.api.abstract.handler import ProcessWatcher
from bauh.api.abstract.model import SoftwarePackage, PackageHistory, PackageUpdate, PackageSuggestion
from bauh.api.constants import HOME_PATH
from bauh.commons.html import bold
from bauh.commons.system import SystemProcess, new_subprocess, ProcessHandler
from bauh.gems.appimage import query, INSTALLATION_PATH
from bauh.gems.appimage.model import AppImage
DB_PATH = '{}/{}'.format(HOME_PATH, '.cache/bauh/appimage/appimage.db')
class AppImageManager(SoftwareManager):
def __init__(self, context: ApplicationContext):
super(AppImageManager, self).__init__(context=context)
self.i18n = context.i18n
self.api_cache = context.cache_factory.new()
context.disk_loader_factory.map(AppImageManager, self.api_cache)
self.enabled = True
self.http_client = context.http_client
self.logger = context.logger
self.file_downloader = context.file_downloader
def _get_db_connection(self) -> sqlite3.Connection:
if os.path.exists(DB_PATH):
return sqlite3.connect(DB_PATH)
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1) -> SearchResult:
res = SearchResult([], [], 0)
connection = self._get_db_connection()
if connection:
try:
cursor = connection.cursor()
cursor.execute(query.SEARCH_BY_NAME_OR_DESCRIPTION.format(words, words))
for l in cursor.fetchall():
app = AppImage(*l)
res.new.append(app)
finally:
connection.close()
res.total = len(res.installed) + len(res.new)
return res
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None) -> SearchResult:
return SearchResult([], [], 0)
def downgrade(self, pkg: AppImage, root_password: str, watcher: ProcessWatcher) -> bool:
pass
def update(self, pkg: AppImage, root_password: str, watcher: ProcessWatcher) -> SystemProcess:
pass
def uninstall(self, pkg: AppImage, root_password: str, watcher: ProcessWatcher) -> bool:
pass
def get_managed_types(self) -> Set[Type[SoftwarePackage]]:
return {AppImage}
def clean_cache_for(self, pkg: AppImage):
# TODO
pass
def get_info(self, pkg: AppImage) -> dict:
# TODO
pass
def get_history(self, pkg: AppImage) -> PackageHistory:
# TODO
pass
def install(self, pkg: AppImage, root_password: str, watcher: ProcessWatcher) -> bool:
out_dir = INSTALLATION_PATH + pkg.name.lower()
Path(out_dir).mkdir(parents=True, exist_ok=True)
file_name = pkg.url_download.split('/')[-1]
file_path = out_dir + '/' + file_name
downloaded = self.file_downloader.download(pkg.url_download, watcher=watcher, output_path=file_path, cwd=HOME_PATH)
if downloaded:
handler = ProcessHandler(watcher)
watcher.change_substatus(self.i18n['appimage.install.permission'].format(bold(file_name)))
return handler.handle(SystemProcess(new_subprocess(['chmod', 'a+x', file_path])))
return False
def is_enabled(self) -> bool:
return self.enabled
def set_enabled(self, enabled: bool):
self.enabled = enabled
def can_work(self) -> bool:
# TODO check wget and sqlite
return True
def requires_root(self, action: str, pkg: AppImage):
return False
def prepare(self):
# TODO
pass
def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
# TODO
pass
def list_warnings(self) -> List[str]:
pass
def list_suggestions(self, limit: int) -> List[PackageSuggestion]:
# TODO
pass
def is_default_enabled(self) -> bool:
return True
def launch(self, pkg: AppImage):
# TODO
pass

View File

@@ -0,0 +1,60 @@
from typing import List
from bauh.api.abstract.model import SoftwarePackage
from bauh.commons import resource
from bauh.gems.appimage import ROOT_DIR
class AppImage(SoftwarePackage):
def __init__(self, name: str = None, description: str = None, github: str = None, source: str = None, version: str = None,
url_download: str = None, url_icon: str = None, license: str = None, pictures: List[str] = None):
super(AppImage, self).__init__(name=name, version=version, latest_version=version,
icon_url=url_icon, license=license, description=description)
self.source = source
self.github = github
self.pictures = pictures
self.url_download = url_download
def can_be_installed(self):
return not self.installed and self.url_download
def has_history(self):
# TODO
return False
def has_info(self):
# TODO
return False
def can_be_downgraded(self):
# TODO
return False
def get_type(self):
return 'AppImage'
def get_default_icon_path(self):
return self.get_type_icon_path()
def get_type_icon_path(self):
return resource.get_path('img/appimage.png', ROOT_DIR)
def is_application(self):
return True
def get_data_to_cache(self) -> dict:
# TODO
pass
def fill_cached_data(self, data: dict):
# TODO
pass
def can_be_run(self) -> str:
# TODO
return False
def get_publisher(self) -> str:
# TODO
pass

View File

@@ -0,0 +1,5 @@
ATTRS = ('name', 'description', 'github', 'source', 'version', 'url_download', 'url_icon', 'license')
_SELECT_BASE = "SELECT {} FROM apps".format(','.join(ATTRS))
SEARCH_BY_NAME_OR_DESCRIPTION = _SELECT_BASE + " WHERE lower(name) LIKE '%{}%' or lower(description) LIKE '%{}%'"

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,2 @@
gem.appimage.label=AppImage
appimage.install.permission=Giving execution permission to {}

View File

@@ -0,0 +1,2 @@
gem.appimage.label=AppImage
appimage.install.permission=Concediendo permiso de ejecución a {}

View File

@@ -0,0 +1,2 @@
gem.appimage.label=AppImage
appimage.install.permission=Concedendo permissão de execução para {}

View File

@@ -405,10 +405,6 @@ class ArchManager(SoftwareManager):
else:
args.update({'file_url': fdata[0], 'output_path': None})
file_size = self.context.http_client.get_content_length(args['file_url'])
file_size = int(file_size) / (1024 ** 2) if file_size else None
watcher.change_substatus(bold('[{}] ').format(downloader) + self.i18n['downloading'] + ' ' + bold(args['file_url'].split('/')[-1]) + ' ( {0:.2f} Mb )'.format(file_size) if file_size else '')
if not self.context.file_downloader.download(**args):
watcher.print('Could not download source file {}'.format(args['file_url']))
return False

View File

@@ -5,14 +5,18 @@ import traceback
from bauh.api.abstract.download import FileDownloader
from bauh.api.abstract.handler import ProcessWatcher
from bauh.api.http import HttpClient
from bauh.commons.html import bold
from bauh.commons.system import run_cmd, new_subprocess, ProcessHandler, SystemProcess
class AdaptableFileDownloader(FileDownloader):
def __init__(self, logger: logging.Logger, multithread_enabled: bool):
def __init__(self, logger: logging.Logger, multithread_enabled: bool, i18n: dict, http_client: HttpClient):
self.logger = logger
self.multithread_enabled = multithread_enabled
self.i18n = i18n
self.http_client = http_client
def is_aria2c_available(self) -> bool:
return bool(run_cmd('which aria2c'))
@@ -48,7 +52,7 @@ class AdaptableFileDownloader(FileDownloader):
cmd = ['wget', url]
if output_path:
cmd.append('-O')
cmd.append('-o')
cmd.append(output_path)
return SystemProcess(new_subprocess(cmd, cwd=cwd))
@@ -73,10 +77,16 @@ class AdaptableFileDownloader(FileDownloader):
if self.is_multithreaded():
ti = time.time()
process = self._get_aria2c_process(file_url, output_path, final_cwd)
downloader = 'aria2c'
else:
ti = time.time()
process = self._get_wget_process(file_url, output_path, final_cwd)
downloader = 'wget'
file_size = self.http_client.get_content_length(file_url)
file_size = int(file_size) / (1024 ** 2) if file_size else None
msg = bold('[{}] ').format(downloader) + self.i18n['downloading'] + ' ' + bold(file_url.split('/')[-1]) + (' ( {0:.2f} Mb )'.format(file_size) if file_size else '')
watcher.change_substatus(msg)
success = handler.handle(process)
except:
traceback.print_exc()
@@ -91,6 +101,8 @@ class AdaptableFileDownloader(FileDownloader):
return success
def is_multithreaded(self) -> bool:
return self.multithread_enabled and self.is_aria2c_available()

View File

@@ -4,7 +4,7 @@ from typing import List
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QPixmap, QIcon, QCursor
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
from PyQt5.QtWidgets import QTableWidget, QTableView, QMenu, QAction, QTableWidgetItem, QToolButton, QWidget, \
QHeaderView, QLabel, QHBoxLayout, QPushButton, QToolBar
@@ -175,7 +175,8 @@ class AppsTable(QTableWidget):
self.window.install(pkgv)
def _load_icon_and_cache(self, http_response):
def _load_icon_and_cache(self, http_response: QNetworkReply):
icon_url = http_response.url().toString()
icon_data = self.icon_cache.get(icon_url)