mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 00:04:15 +02:00
sketch
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '0.7.4'
|
__version__ = '0.8.0'
|
||||||
__app_name__ = 'bauh'
|
__app_name__ = 'bauh'
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|||||||
@@ -37,11 +37,12 @@ class SoftwareManager(ABC):
|
|||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int) -> SearchResult:
|
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int, is_url: bool) -> SearchResult:
|
||||||
"""
|
"""
|
||||||
:param words: the words typed by the user
|
:param words: the words typed by the user
|
||||||
:param disk_loader: a running disk loader thread that loads package data from the disk asynchronously
|
:param disk_loader: a running disk loader thread that loads package data from the disk asynchronously
|
||||||
:param limit: the max number of packages to be retrieved. <= 1 should retrieve everything
|
:param limit: the max number of packages to be retrieved. <= 1 should retrieve everything
|
||||||
|
:param is_url: if "words" is a URL
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ class AppImageManager(SoftwareManager):
|
|||||||
def _gen_app_key(self, app: AppImage):
|
def _gen_app_key(self, app: AppImage):
|
||||||
return '{}{}'.format(app.name.lower(), app.github.lower() if app.github else '')
|
return '{}{}'.format(app.name.lower(), app.github.lower() if app.github else '')
|
||||||
|
|
||||||
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1) -> SearchResult:
|
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult:
|
||||||
|
if is_url:
|
||||||
|
return SearchResult([], [], 0)
|
||||||
|
|
||||||
res = SearchResult([], [], 0)
|
res = SearchResult([], [], 0)
|
||||||
connection = self._get_db_connection(DB_APPS_PATH)
|
connection = self._get_db_connection(DB_APPS_PATH)
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,10 @@ class ArchManager(SoftwareManager):
|
|||||||
|
|
||||||
Thread(target=self.mapper.fill_package_build, args=(app,), daemon=True).start()
|
Thread(target=self.mapper.fill_package_build, args=(app,), daemon=True).start()
|
||||||
|
|
||||||
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1) -> SearchResult:
|
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult:
|
||||||
|
if is_url:
|
||||||
|
return SearchResult([], [], 0)
|
||||||
|
|
||||||
self.comp_optimizer.join()
|
self.comp_optimizer.join()
|
||||||
|
|
||||||
downgrade_enabled = git.is_enabled()
|
downgrade_enabled = git.is_enabled()
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ class FlatpakManager(SoftwareManager):
|
|||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1) -> SearchResult:
|
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult:
|
||||||
|
if is_url:
|
||||||
|
return SearchResult([], [], 0)
|
||||||
|
|
||||||
res = SearchResult([], [], 0)
|
res = SearchResult([], [], 0)
|
||||||
apps_found = flatpak.search(flatpak.get_version(), words)
|
apps_found = flatpak.search(flatpak.get_version(), words)
|
||||||
|
|||||||
@@ -84,7 +84,10 @@ class SnapManager(SoftwareManager):
|
|||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
||||||
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1) -> SearchResult:
|
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult:
|
||||||
|
if is_url:
|
||||||
|
return SearchResult([], [], 0)
|
||||||
|
|
||||||
if snap.is_snapd_running():
|
if snap.is_snapd_running():
|
||||||
installed = self.read_installed(disk_loader).installed
|
installed = self.read_installed(disk_loader).installed
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ SNAPD_RUNNING_STATUS = {'listening', 'running'}
|
|||||||
|
|
||||||
|
|
||||||
def is_installed():
|
def is_installed():
|
||||||
res = run_cmd('which snap')
|
res = run_cmd('which snap', print_error=False)
|
||||||
return res and not res.strip().startswith('which ')
|
return res and not res.strip().startswith('which ')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3
bauh/gems/web/__init__.py
Normal file
3
bauh/gems/web/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
117
bauh/gems/web/controller.py
Normal file
117
bauh/gems/web/controller.py
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
from typing import List, Type, Set
|
||||||
|
|
||||||
|
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, PackageAction, PackageSuggestion, PackageUpdate, PackageHistory
|
||||||
|
from bauh.gems.web import npm
|
||||||
|
from bauh.gems.web.model import WebApplication
|
||||||
|
|
||||||
|
try:
|
||||||
|
from bs4 import BeautifulSoup, SoupStrainer
|
||||||
|
BS4_AVAILABLE = True
|
||||||
|
except:
|
||||||
|
BS4_AVAILABLE = False
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import lxml
|
||||||
|
LXML_AVAILABLE = True
|
||||||
|
except:
|
||||||
|
LXML_AVAILABLE = False
|
||||||
|
|
||||||
|
|
||||||
|
class WebApplicationManager(SoftwareManager):
|
||||||
|
|
||||||
|
def __init__(self, context: ApplicationContext):
|
||||||
|
super(WebApplicationManager, self).__init__(context=context)
|
||||||
|
self.http_client = context.http_client
|
||||||
|
self.enabled = True
|
||||||
|
|
||||||
|
def search(self, words: str, disk_loader: DiskCacheLoader, limit: int = -1, is_url: bool = False) -> SearchResult:
|
||||||
|
res = SearchResult([], [], 0)
|
||||||
|
|
||||||
|
if is_url:
|
||||||
|
url_res = self.http_client.get(words)
|
||||||
|
|
||||||
|
if url_res:
|
||||||
|
soup = BeautifulSoup(url_res.text, 'lxml', parse_only=SoupStrainer('head'))
|
||||||
|
|
||||||
|
name_tag = soup.head.find('meta', attrs={'name': 'application-name'})
|
||||||
|
name = name_tag.get('content') if name_tag else words.split('.')[0]
|
||||||
|
|
||||||
|
desc_tag = soup.head.find('meta', attrs={'name': 'description'})
|
||||||
|
desc = desc_tag.get('content') if desc_tag else words
|
||||||
|
|
||||||
|
icon_tag = soup.head.find('link', attrs={"rel": "icon"})
|
||||||
|
icon_url = icon_tag.get('href') if icon_tag else None
|
||||||
|
|
||||||
|
res.new = [WebApplication(url=words, name=name, description=desc, icon_url=icon_url)]
|
||||||
|
res.total = 1
|
||||||
|
else:
|
||||||
|
# TODO
|
||||||
|
pass
|
||||||
|
|
||||||
|
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 = True) -> SearchResult:
|
||||||
|
# TODO
|
||||||
|
return SearchResult([], [], 0)
|
||||||
|
|
||||||
|
def downgrade(self, pkg: SoftwarePackage, root_password: str, handler: ProcessWatcher) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update(self, pkg: SoftwarePackage, root_password: str, watcher: ProcessWatcher) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def uninstall(self, pkg: SoftwarePackage, root_password: str, watcher: ProcessWatcher) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_managed_types(self) -> Set[Type[SoftwarePackage]]:
|
||||||
|
return {WebApplication}
|
||||||
|
|
||||||
|
def get_info(self, pkg: SoftwarePackage) -> dict:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_history(self, pkg: SoftwarePackage) -> PackageHistory:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def install(self, pkg: SoftwarePackage, root_password: str, watcher: ProcessWatcher) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def is_enabled(self) -> bool:
|
||||||
|
return self.enabled
|
||||||
|
|
||||||
|
def set_enabled(self, enabled: bool):
|
||||||
|
self.enabled = enabled
|
||||||
|
|
||||||
|
def can_work(self) -> bool:
|
||||||
|
return BS4_AVAILABLE and LXML_AVAILABLE and npm.is_available()
|
||||||
|
|
||||||
|
def requires_root(self, action: str, pkg: SoftwarePackage):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def list_updates(self, internet_available: bool) -> List[PackageUpdate]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def list_warnings(self, internet_available: bool) -> List[str]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def list_suggestions(self, limit: int) -> List[PackageSuggestion]:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def execute_custom_action(self, action: PackageAction, pkg: SoftwarePackage, root_password: str, watcher: ProcessWatcher) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def is_default_enabled(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def launch(self, pkg: SoftwarePackage):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_screenshots(self, pkg: SoftwarePackage) -> List[str]:
|
||||||
|
pass
|
||||||
59
bauh/gems/web/model.py
Normal file
59
bauh/gems/web/model.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
from bauh.api.abstract.model import SoftwarePackage
|
||||||
|
from bauh.api.constants import CACHE_PATH
|
||||||
|
from bauh.commons import resource
|
||||||
|
from bauh.gems.web import ROOT_DIR
|
||||||
|
|
||||||
|
|
||||||
|
class WebApplication(SoftwarePackage):
|
||||||
|
|
||||||
|
def __init__(self, url: str, name: str, description: str, icon_url: str):
|
||||||
|
super(WebApplication, self).__init__(id=url, name=name, description=description, icon_url=icon_url)
|
||||||
|
self.url = url
|
||||||
|
|
||||||
|
def has_history(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def has_info(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def can_be_downgraded(self):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_type(self):
|
||||||
|
return 'web'
|
||||||
|
|
||||||
|
def get_type_icon_path(self) -> str:
|
||||||
|
return self.get_default_icon_path()
|
||||||
|
|
||||||
|
def get_default_icon_path(self) -> str:
|
||||||
|
return resource.get_path('img/web.png', ROOT_DIR)
|
||||||
|
|
||||||
|
def is_application(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def supports_disk_cache(self):
|
||||||
|
return self.installed and self.is_application()
|
||||||
|
|
||||||
|
def get_disk_cache_path(self):
|
||||||
|
return CACHE_PATH + '/' + self.get_type()
|
||||||
|
|
||||||
|
def get_data_to_cache(self) -> dict:
|
||||||
|
"""
|
||||||
|
:return: the application data that should be cached in disk / memory for quick access
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def fill_cached_data(self, data: dict):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def can_be_run(self) -> bool:
|
||||||
|
return self.installed
|
||||||
|
|
||||||
|
def is_trustable(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_publisher(self) -> str:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def has_screenshots(self) -> bool:
|
||||||
|
return False
|
||||||
6
bauh/gems/web/npm.py
Normal file
6
bauh/gems/web/npm.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from bauh.commons.system import run_cmd
|
||||||
|
|
||||||
|
|
||||||
|
def is_available() -> bool:
|
||||||
|
res = run_cmd('which npm', print_error=False)
|
||||||
|
return res and not res.strip().startswith('which ')
|
||||||
BIN
bauh/gems/web/resources/img/web.png
Normal file
BIN
bauh/gems/web/resources/img/web.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
1
bauh/gems/web/resources/locale/en
Normal file
1
bauh/gems/web/resources/locale/en
Normal file
@@ -0,0 +1 @@
|
|||||||
|
gem.web.info=It allows to install Web applications on your system
|
||||||
1
bauh/gems/web/resources/locale/pt
Normal file
1
bauh/gems/web/resources/locale/pt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
gem.web.info=Permite instalar aplicações Web no seu sistema
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import re
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from argparse import Namespace
|
from argparse import Namespace
|
||||||
@@ -11,6 +12,8 @@ from bauh.api.abstract.model import SoftwarePackage, PackageUpdate, PackageHisto
|
|||||||
from bauh.api.exception import NoInternetException
|
from bauh.api.exception import NoInternetException
|
||||||
from bauh.commons import internet
|
from bauh.commons import internet
|
||||||
|
|
||||||
|
RE_IS_URL = re.compile(r'^https?://.+')
|
||||||
|
|
||||||
SUGGESTIONS_LIMIT = 5
|
SUGGESTIONS_LIMIT = 5
|
||||||
|
|
||||||
|
|
||||||
@@ -79,17 +82,17 @@ class GenericSoftwareManager(SoftwareManager):
|
|||||||
|
|
||||||
return available
|
return available
|
||||||
|
|
||||||
def _search(self, word: str, man: SoftwareManager, disk_loader, res: SearchResult):
|
def _search(self, word: str, is_url: bool, man: SoftwareManager, disk_loader, res: SearchResult):
|
||||||
if self._can_work(man):
|
if self._can_work(man):
|
||||||
mti = time.time()
|
mti = time.time()
|
||||||
apps_found = man.search(words=word, disk_loader=disk_loader)
|
apps_found = man.search(words=word, disk_loader=disk_loader, is_url=is_url)
|
||||||
mtf = time.time()
|
mtf = time.time()
|
||||||
self.logger.info(man.__class__.__name__ + " took {0:.2f} seconds".format(mtf - mti))
|
self.logger.info(man.__class__.__name__ + " took {0:.2f} seconds".format(mtf - mti))
|
||||||
|
|
||||||
res.installed.extend(apps_found.installed)
|
res.installed.extend(apps_found.installed)
|
||||||
res.new.extend(apps_found.new)
|
res.new.extend(apps_found.new)
|
||||||
|
|
||||||
def search(self, word: str, disk_loader: DiskCacheLoader = None, limit: int = -1) -> SearchResult:
|
def search(self, word: str, disk_loader: DiskCacheLoader = None, limit: int = -1, is_url: bool = False) -> SearchResult:
|
||||||
ti = time.time()
|
ti = time.time()
|
||||||
self._wait_to_be_ready()
|
self._wait_to_be_ready()
|
||||||
|
|
||||||
@@ -97,13 +100,15 @@ class GenericSoftwareManager(SoftwareManager):
|
|||||||
|
|
||||||
if internet.is_available(self.context.http_client, self.context.logger):
|
if internet.is_available(self.context.http_client, self.context.logger):
|
||||||
norm_word = word.strip().lower()
|
norm_word = word.strip().lower()
|
||||||
|
|
||||||
|
url_words = RE_IS_URL.match(norm_word)
|
||||||
disk_loader = self.disk_loader_factory.new()
|
disk_loader = self.disk_loader_factory.new()
|
||||||
disk_loader.start()
|
disk_loader.start()
|
||||||
|
|
||||||
threads = []
|
threads = []
|
||||||
|
|
||||||
for man in self.managers:
|
for man in self.managers:
|
||||||
t = Thread(target=self._search, args=(norm_word, man, disk_loader, res))
|
t = Thread(target=self._search, args=(norm_word, url_words, man, disk_loader, res))
|
||||||
t.start()
|
t.start()
|
||||||
threads.append(t)
|
threads.append(t)
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ class ManageWindow(QWidget):
|
|||||||
self.toolbar_search.addWidget(label_pre_search)
|
self.toolbar_search.addWidget(label_pre_search)
|
||||||
|
|
||||||
self.input_search = QLineEdit()
|
self.input_search = QLineEdit()
|
||||||
self.input_search.setMaxLength(20)
|
|
||||||
self.input_search.setFrame(False)
|
self.input_search.setFrame(False)
|
||||||
self.input_search.setPlaceholderText(self.i18n['window_manage.input_search.placeholder'] + "...")
|
self.input_search.setPlaceholderText(self.i18n['window_manage.input_search.placeholder'] + "...")
|
||||||
self.input_search.setToolTip(self.i18n['window_manage.input_search.tooltip'])
|
self.input_search.setToolTip(self.i18n['window_manage.input_search.tooltip'])
|
||||||
|
|||||||
Reference in New Issue
Block a user