This commit is contained in:
Vinicius Moreira
2019-07-26 19:03:23 -03:00
parent 8f9f8d04db
commit 8bbe894e87
20 changed files with 21 additions and 790 deletions

View File

@@ -4,6 +4,10 @@ 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.5.0]
### Comments
- Env variables / arguments FPAKMAN_SNAP / FPAKMAN_FLATPAK were removed. To disable a supported type, just uninstall its module.
## [0.4.2]
### Fixes:
- [Snaps read index error](https://github.com/vinifmor/fpakman/issues/30)

View File

@@ -49,14 +49,9 @@ You can change some application settings via environment variables or arguments
- **FPAKMAN_ICON_EXPIRATION**: define a custom expiration time in SECONDS for cached icons. Default: 300 (5 minutes).
- **FPAKMAN_DISK_CACHE**: enables / disables disk cache. When disk cache is enabled, the installed applications data are loaded faster. Use **0** (disable) or **1** (enable, default).
- **FPAKMAN_DOWNLOAD_ICONS**: Enables / disables app icons download. It may improve the application speed depending on how applications data are being retrieved. Use **0** (disable) or **1** (enable, default).
- **FPAKMAN_FLATPAK**: enables / disables flatpak usage. Use **0** (disable) or **1** (enabled, default)
- **FPAKMAN_SNAP**: enables / disables snap usage. Use **0** (disable) or **1** (enabled, default)
- **FPAKMAN_CHECK_PACKAGING_ONCE**: If the available supported packaging types should be checked ONLY once. It improves the application speed if enabled, but can generate errors if you uninstall any packaging technology while using it, and every time a supported packaging type is installed it will only be available after a restart. Use **0** (disable, default) or **1** (enable).
### How to improve the application performance
- If you don't care about a specific packaging technology and don't want **fpakman** to deal with it, just disable it via the specific argument or environment variable. For instance, if I don't care
about **snaps**, I can initialize the application setting "snap=0" (**fpakman --snap=0**). This will improve the application response time, since it won't need to do any verifications associated
with the technology that I don't care every time an action is executed.
- If you don't care about restarting **fpakman** every time a new supported packaging technology is installed, set "check-packaging-once=1" (**fpakman --check-packaging-once=1**). This can reduce the application response time up to 80% in some scenarios, since it won't need to recheck if the packaging type is available for every action you request.
- If you don't mind to see the applications icons, you can set "download-icons=0" (**fpakman --download-icons=0**). The application may have a slight response improvement, since it will reduce the parallelism within it.

View File

@@ -11,13 +11,10 @@ from colorama import Fore
from fpakman import __version__, __app_name__
from fpakman.core import resource
from fpakman.core.controller import GenericApplicationManager
from fpakman.core.disk import DiskCacheLoaderFactory
from fpakman_api.util.disk import DiskCacheLoaderFactory
from fpakman.core.flatpak.constants import FLATPAK_CACHE_PATH
from fpakman.core.flatpak.controller import FlatpakManager
from fpakman.core.flatpak.model import FlatpakApplication
from fpakman.core.snap.constants import SNAP_CACHE_PATH
from fpakman.core.snap.controller import SnapManager
from fpakman.core.snap.model import SnapApplication
from fpakman.util import util
from fpakman.util.cache import Cache
from fpakman.util.memory import CacheCleaner
@@ -42,7 +39,6 @@ parser.add_argument('-n', '--update-notification', action="store", choices=[0, 1
parser.add_argument('-dc', '--disk-cache', action="store", choices=[0, 1], default=os.getenv('FPAKMAN_DISK_CACHE', 1), type=int, help='Enables / disables disk cache. When disk cache is enabled, the installed applications data are loaded faster. Default: %(default)s')
parser.add_argument('-di', '--download-icons', action="store", choices=[0, 1], default=os.getenv('FPAKMAN_DOWNLOAD_ICONS', 1), type=int, help='Enables / disables app icons download. It may improve the application speed, depending of how applications data are retrieved by their extensions.')
parser.add_argument('--flatpak', action="store", default=os.getenv('FPAKMAN_FLATPAK', 1), choices=[0, 1], type=int, help='Enables / disables flatpak usage. Default: %(default)s')
parser.add_argument('--snap', action="store", default=os.getenv('FPAKMAN_SNAP', 1), choices=[0, 1], type=int, help='Enables / disables snap usage. Default: %(default)s')
parser.add_argument('-co', '--check-packaging-once', action="store", default=os.getenv('FPAKMAN_CHECK_PACKAGING_ONCE', 0), choices=[0, 1], type=int, help='If the available supported packaging types should be checked ONLY once. It improves the application speed if enabled, but can generate errors if you uninstall any packaging technology while using it, and every time a supported packaging type is installed it will only be available after a restart. Default: %(default)s')
args = parser.parse_args()
@@ -92,13 +88,14 @@ if args.flatpak:
Path(FLATPAK_CACHE_PATH).mkdir(parents=True, exist_ok=True)
if args.snap:
snap_api_cache = Cache(expiration_time=args.cache_exp)
cache_map[SnapApplication] = snap_api_cache
managers.append(SnapManager(app_args=args, disk_cache=args.disk_cache, api_cache=snap_api_cache, http_session=http_session))
caches.append(snap_api_cache)
if args.disk_cache:
Path(SNAP_CACHE_PATH).mkdir(parents=True, exist_ok=True)
pass
# snap_api_cache = Cache(expiration_time=args.cache_exp)
# cache_map[SnapApplication] = snap_api_cache
# managers.append(SnapManager(app_args=args, disk_cache=args.disk_cache, api_cache=snap_api_cache, http_session=http_session))
# caches.append(snap_api_cache)
#
# if args.disk_cache:
# Path(SNAP_CACHE_PATH).mkdir(parents=True, exist_ok=True)
icon_cache = Cache(expiration_time=args.icon_exp)
caches.append(icon_cache)

View File

@@ -1,6 +0,0 @@
from pathlib import Path
from fpakman import __app_name__
HOME_PATH = Path.home()
CACHE_PATH = '{}/.cache/{}'.format(HOME_PATH, __app_name__)

View File

@@ -1,88 +1,11 @@
from abc import ABC, abstractmethod
from argparse import Namespace
from typing import List, Dict
from fpakman.core.disk import DiskCacheLoader, DiskCacheLoaderFactory
from fpakman.core.model import Application, ApplicationUpdate
from fpakman.core.system import FpakmanProcess
class ApplicationManager(ABC):
def __init__(self, app_args):
self.app_args = app_args
@abstractmethod
def search(self, word: str, disk_loader: DiskCacheLoader) -> Dict[str, List[Application]]:
pass
@abstractmethod
def read_installed(self, disk_loader: DiskCacheLoader) -> List[Application]:
pass
@abstractmethod
def downgrade_app(self, app: Application, root_password: str) -> FpakmanProcess:
pass
@abstractmethod
def clean_cache_for(self, app: Application):
pass
@abstractmethod
def can_downgrade(self):
pass
@abstractmethod
def update_and_stream(self, app: Application) -> FpakmanProcess:
pass
@abstractmethod
def uninstall_and_stream(self, app: Application, root_password: str) -> FpakmanProcess:
pass
@abstractmethod
def get_app_type(self):
pass
@abstractmethod
def get_info(self, app: Application) -> dict:
pass
@abstractmethod
def get_history(self, app: Application) -> List[dict]:
pass
@abstractmethod
def install_and_stream(self, app: Application, root_password: str) -> FpakmanProcess:
pass
@abstractmethod
def is_enabled(self) -> bool:
pass
@abstractmethod
def cache_to_disk(self, app: Application, icon_bytes: bytes, only_icon: bool):
pass
@abstractmethod
def requires_root(self, action: str, app: Application):
pass
@abstractmethod
def refresh(self, app: Application, root_password: str) -> FpakmanProcess:
pass
@abstractmethod
def prepare(self):
"""
Callback executed before the ApplicationManager starts to work.
:return:
"""
pass
@abstractmethod
def list_updates(self) -> List[ApplicationUpdate]:
pass
from fpakman_api.abstract.controller import ApplicationManager
from fpakman_api.abstract.model import Application, ApplicationUpdate
from fpakman_api.util.disk import DiskCacheLoader
from fpakman_api.util.disk import DiskCacheLoaderFactory
from fpakman_api.util.system import FpakmanProcess
class GenericApplicationManager(ApplicationManager):
@@ -143,7 +66,7 @@ class GenericApplicationManager(ApplicationManager):
disk_loader = self.disk_loader_factory.new()
disk_loader.start()
apps_found = man.search(word=norm_word, disk_loader=disk_loader)
apps_found = man.search(words=norm_word, disk_loader=disk_loader)
res['installed'].extend(apps_found['installed'])
res['new'].extend(apps_found['new'])

View File

@@ -1,75 +0,0 @@
import json
import os
from pathlib import Path
from threading import Thread, Lock
from typing import List, Dict
from fpakman.core.model import Application
from fpakman.util.cache import Cache
class DiskCacheLoader(Thread):
def __init__(self, enabled: bool, cache_map: Dict[type, Cache], apps: List[Application] = []):
super(DiskCacheLoader, self).__init__(daemon=True)
self.apps = apps
self.stop = False
self.lock = Lock()
self.cache_map = cache_map
self.enabled = enabled
def run(self):
if self.enabled:
while True:
if self.apps:
self.lock.acquire()
app = self.apps[0]
del self.apps[0]
self.lock.release()
self.fill_cached_data(app)
elif self.stop:
break
def add(self, app: Application):
if self.enabled:
if app and app.supports_disk_cache():
self.lock.acquire()
self.apps.append(app)
self.lock.release()
def fill_cached_data(self, app: Application):
if self.enabled:
if os.path.exists(app.get_disk_data_path()):
with open(app.get_disk_data_path()) as f:
cached_data = json.loads(f.read())
app.fill_cached_data(cached_data)
self.cache_map.get(app.__class__).add_non_existing(app.base_data.id, cached_data)
class DiskCacheLoaderFactory:
def __init__(self, disk_cache: bool, cache_map: Dict[type, Cache]):
self.disk_cache = disk_cache
self.cache_map = cache_map
def new(self):
return DiskCacheLoader(enabled=self.disk_cache, cache_map=self.cache_map)
def save(app: Application, icon_bytes: bytes = None, only_icon: bool = False):
if app.supports_disk_cache():
if not only_icon:
Path(app.get_disk_cache_path()).mkdir(parents=True, exist_ok=True)
data = app.get_data_to_cache()
with open(app.get_disk_data_path(), 'w+') as f:
f.write(json.dumps(data))
if icon_bytes:
Path(app.get_disk_cache_path()).mkdir(parents=True, exist_ok=True)
with open(app.get_disk_icon_path(), 'wb+') as f:
f.write(icon_bytes)

View File

@@ -1,3 +0,0 @@
class NoInternetException(Exception):
pass

View File

@@ -1,5 +0,0 @@
from fpakman.core.constants import CACHE_PATH
FLATHUB_URL = 'https://flathub.org'
FLATHUB_API_URL = FLATHUB_URL + '/api/v1'
FLATPAK_CACHE_PATH = '{}/flatpak/installed'.format(CACHE_PATH)

View File

@@ -1,99 +0,0 @@
from abc import ABC, abstractmethod
from enum import Enum
from fpakman.core import resource
class ApplicationStatus(Enum):
READY = 1
LOADING_DATA = 2
class ApplicationData:
def __init__(self, id: str, version: str, name: str = None, description: str = None, latest_version: str = None, icon_url: str = None):
self.id = id
self.name = name
self.version = version
self.description = description
self.latest_version = latest_version
self.icon_url = icon_url
class Application(ABC):
def __init__(self, base_data: ApplicationData, status: ApplicationStatus = ApplicationStatus.READY, installed: bool = False, update: bool = False):
self.base_data = base_data
self.status = status
self.installed = installed
self.update = update
@abstractmethod
def has_history(self):
pass
@abstractmethod
def has_info(self):
pass
@abstractmethod
def can_be_downgraded(self):
pass
@abstractmethod
def can_be_uninstalled(self):
pass
@abstractmethod
def can_be_installed(self):
pass
@abstractmethod
def can_be_refreshed(self):
return self.installed
@abstractmethod
def get_type(self):
pass
def get_default_icon_path(self):
return resource.get_path('img/logo.svg')
@abstractmethod
def is_library(self):
pass
def supports_disk_cache(self):
return self.installed and not self.is_library()
@abstractmethod
def get_disk_cache_path(self):
pass
def get_disk_icon_path(self):
return '{}/icon.png'.format(self.get_disk_cache_path())
def get_disk_data_path(self):
return '{}/data.json'.format(self.get_disk_cache_path())
@abstractmethod
def get_data_to_cache(self):
pass
@abstractmethod
def fill_cached_data(self, data: dict):
pass
def __str__(self):
return '{} (id={}, name={})'.format(self.__class__.__name__, self.base_data.id, self.base_data.name)
class ApplicationUpdate:
def __init__(self, app_id: str, version: str, app_type: str):
self.id = app_id
self.version = version
self.type = app_type
def __str__(self):
return '{} (id={}, type={}, new_version={})'.format(self.__class__.__name__, self.id, self.type, self.type)

View File

@@ -1,4 +1,3 @@
from fpakman import ROOT_DIR

View File

@@ -1,4 +0,0 @@
from fpakman.core.constants import CACHE_PATH
SNAP_API_URL = 'https://search.apps.ubuntu.com/api/v1'
SNAP_CACHE_PATH = '{}/snap/installed'.format(CACHE_PATH)

View File

@@ -1,135 +0,0 @@
import os
import shutil
from argparse import Namespace
from datetime import datetime
from typing import Dict, List
from fpakman.core import disk
from fpakman.core.controller import ApplicationManager
from fpakman.core.disk import DiskCacheLoader
from fpakman.core.model import ApplicationData, Application, ApplicationUpdate
from fpakman.core.snap import snap
from fpakman.core.snap.model import SnapApplication
from fpakman.core.snap.worker import SnapAsyncDataLoader
from fpakman.core.system import FpakmanProcess
from fpakman.util.cache import Cache
class SnapManager(ApplicationManager):
def __init__(self, app_args: Namespace, api_cache: Cache, disk_cache: bool, http_session):
super(SnapManager, self).__init__(app_args=app_args)
self.api_cache = api_cache
self.http_session = http_session
self.disk_cache = disk_cache
def map_json(self, app_json: dict, installed: bool, disk_loader: DiskCacheLoader) -> SnapApplication:
app = SnapApplication(publisher=app_json.get('publisher'),
rev=app_json.get('rev'),
notes=app_json.get('notes'),
app_type=app_json.get('type'),
base_data=ApplicationData(id=app_json.get('name'),
name=app_json.get('name'),
version=app_json.get('version'),
latest_version=app_json.get('version'),
description=app_json.get('description')
))
if app.publisher:
app.publisher = app.publisher.replace('*', '')
app.installed = installed
api_data = self.api_cache.get(app_json['name'])
expired_data = api_data and api_data.get('expires_at') and api_data['expires_at'] <= datetime.utcnow()
if (not api_data or expired_data) and not app.is_library():
if disk_loader and app.installed:
disk_loader.add(app)
SnapAsyncDataLoader(app=app, api_cache=self.api_cache, manager=self, http_session=self.http_session, download_icons=self.app_args.download_icons).start()
else:
app.fill_cached_data(api_data)
return app
def search(self, word: str, disk_loader: DiskCacheLoader) -> Dict[str, List[SnapApplication]]:
installed = self.read_installed(disk_loader)
res = {'installed': [], 'new': []}
for app_json in snap.search(word):
already_installed = None
if installed:
already_installed = [i for i in installed if i.base_data.id == app_json.get('name')]
already_installed = already_installed[0] if already_installed else None
if already_installed:
res['installed'].append(already_installed)
else:
res['new'].append(self.map_json(app_json, installed=False, disk_loader=disk_loader))
return res
def read_installed(self, disk_loader: DiskCacheLoader) -> List[SnapApplication]:
return [self.map_json(app_json, installed=True, disk_loader=disk_loader) for app_json in snap.read_installed()]
def downgrade_app(self, app: Application, root_password: str) -> FpakmanProcess:
return FpakmanProcess(subproc=snap.downgrade_and_stream(app.base_data.name, root_password), wrong_error_phrase=None)
def clean_cache_for(self, app: SnapApplication):
self.api_cache.delete(app.base_data.name)
if app.supports_disk_cache() and os.path.exists(app.get_disk_cache_path()):
shutil.rmtree(app.get_disk_cache_path())
def can_downgrade(self):
return True
def update_and_stream(self, app: SnapApplication) -> FpakmanProcess:
pass
def uninstall_and_stream(self, app: SnapApplication, root_password: str) -> FpakmanProcess:
return FpakmanProcess(subproc=snap.uninstall_and_stream(app.base_data.name, root_password))
def get_app_type(self):
return SnapApplication
def get_info(self, app: SnapApplication) -> dict:
info = snap.get_info(app.base_data.name, attrs=('license', 'contact', 'commands', 'snap-id', 'tracking', 'installed'))
info['description'] = app.base_data.description
info['publisher'] = app.publisher
info['revision'] = app.rev
info['name'] = app.base_data.name
if info.get('commands'):
info['commands'] = ' '.join(info['commands'])
return info
def get_history(self, app: Application) -> List[dict]:
return []
def install_and_stream(self, app: SnapApplication, root_password: str) -> FpakmanProcess:
return FpakmanProcess(subproc=snap.install_and_stream(app.base_data.name, app.confinement, root_password))
def is_enabled(self) -> bool:
return snap.is_installed()
def cache_to_disk(self, app: Application, icon_bytes: bytes, only_icon: bool):
if self.disk_cache and app.supports_disk_cache():
disk.save(app, icon_bytes, only_icon)
def requires_root(self, action: str, app: SnapApplication):
return action != 'search'
def refresh(self, app: SnapApplication, root_password: str) -> FpakmanProcess:
return FpakmanProcess(subproc=snap.refresh_and_stream(app.base_data.name, root_password))
def prepare(self):
pass
def list_updates(self) -> List[ApplicationUpdate]:
return []

View File

@@ -1,60 +0,0 @@
from fpakman.core import resource
from fpakman.core.model import Application, ApplicationData
from fpakman.core.snap.constants import SNAP_CACHE_PATH
class SnapApplication(Application):
def __init__(self, base_data: ApplicationData, publisher: str, rev: str, notes: str, app_type: str, confinement: str = None):
super(SnapApplication, self).__init__(base_data=base_data)
self.publisher = publisher
self.rev = rev
self.notes = notes
self.type = app_type
self.confinement = confinement
def has_history(self):
return False
def has_info(self):
return True
def can_be_downgraded(self):
return self.installed
def can_be_uninstalled(self):
return self.installed
def can_be_installed(self):
return not self.installed
def can_be_refreshed(self):
return self.installed
def get_type(self):
return 'snap'
def get_default_icon_path(self):
return resource.get_path('img/snapcraft.png')
def is_library(self):
return self.type in ('core', 'base', 'snapd') or self.base_data.name.startswith('gtk-') or self.base_data.name.startswith('gnome-')
def get_disk_cache_path(self):
return '{}/{}'.format(SNAP_CACHE_PATH, self.base_data.name)
def get_data_to_cache(self):
return {
"icon_url": self.base_data.icon_url,
'confinement': self.confinement,
'description': self.base_data.description
}
def fill_cached_data(self, data: dict):
if data:
for base_attr in ('icon_url', 'description'):
if data.get(base_attr):
setattr(self.base_data, base_attr, data[base_attr])
if data.get('confinement'):
self.confinement = data['confinement']

View File

@@ -1,134 +0,0 @@
import re
import subprocess
from typing import List
from fpakman.core import system
BASE_CMD = 'snap'
def is_installed():
version = get_snapd_version()
return False if version is None else True
def get_version():
res = system.run_cmd('{} --version'.format(BASE_CMD), print_error=False)
return res.split('\n')[0].split(' ')[-1].strip() if res else None
def get_snapd_version():
res = system.run_cmd('{} --version'.format(BASE_CMD), print_error=False)
if not res:
return None
else:
lines = res.split('\n')
if lines and len(lines) >= 2:
version = lines[1].split(' ')[-1].strip()
return version if version and version.lower() != 'unavailable' else None
else:
return None
def app_str_to_json(app: str) -> dict:
app_data = [word for word in app.split(' ') if word]
app_json = {
'name': app_data[0],
'version': app_data[1],
'rev': app_data[2],
'tracking': app_data[3],
'publisher': app_data[4] if len(app_data) >= 5 else None,
'notes': app_data[5] if len(app_data) >= 6 else None
}
app_json.update(get_info(app_json['name'], ('summary', 'type', 'description')))
return app_json
def get_info(app_name: str, attrs: tuple = None):
full_info_lines = system.run_cmd('{} info {}'.format(BASE_CMD, app_name))
data = {}
if full_info_lines:
re_attrs = r'\w+' if not attrs else '|'.join(attrs)
info_map = re.findall(r'({}):\s+(.+)'.format(re_attrs), full_info_lines)
for info in info_map:
data[info[0]] = info[1].strip()
if not attrs or 'description' in attrs:
desc = re.findall(r'\|\n+((\s+.+\n+)+)', full_info_lines)
data['description'] = ''.join([w.strip() for w in desc[0][0].strip().split('\n')]).replace('.', '.\n') if desc else None
if not attrs or 'commands' in attrs:
commands = re.findall(r'commands:\s*\n*((\s+-\s.+\s*\n)+)', full_info_lines)
data['commands'] = commands[0][0].replace('-', '').strip().split('\n') if commands else None
return data
def read_installed() -> List[dict]:
res = system.run_cmd('{} list'.format(BASE_CMD), print_error=False)
apps = []
if res and len(res) > 0:
lines = res.split('\n')
if not lines[0].startswith('error'):
for idx, app_str in enumerate(lines):
if idx > 0 and app_str:
apps.append(app_str_to_json(app_str))
return apps
def search(word: str) -> List[dict]:
apps = []
res = system.run_cmd('{} find "{}"'.format(BASE_CMD, word), print_error=False)
if res:
res = res.split('\n')
if not res[0].startswith('No matching'):
for idx, app_str in enumerate(res):
if idx > 0 and app_str:
app_data = [word for word in app_str.split(' ') if word]
apps.append({
'name': app_data[0],
'version': app_data[1],
'publisher': app_data[2],
'notes': app_data[3] if app_data[3] != '-' else None,
'summary': app_data[4] if len(app_data) == 5 else '',
'rev': None,
'tracking': None,
'type': None
})
return apps
def uninstall_and_stream(app_name: str, root_password: str):
return system.cmd_as_root([BASE_CMD, 'remove', app_name], root_password)
def install_and_stream(app_name: str, confinement: str, root_password: str) -> subprocess.Popen:
install_cmd = [BASE_CMD, 'install', app_name] # default
if confinement == 'classic':
install_cmd.append('--classic')
return system.cmd_as_root(install_cmd, root_password)
def downgrade_and_stream(app_name: str, root_password: str) -> subprocess.Popen:
return system.cmd_as_root([BASE_CMD, 'revert', app_name], root_password)
def refresh_and_stream(app_name: str, root_password: str) -> subprocess.Popen:
return system.cmd_as_root([BASE_CMD, 'refresh', app_name], root_password)

View File

@@ -1,85 +0,0 @@
import time
import traceback
from colorama import Fore
from fpakman.core.controller import ApplicationManager
from fpakman.core.model import ApplicationStatus
from fpakman.core.snap import snap
from fpakman.core.snap.constants import SNAP_API_URL
from fpakman.core.snap.model import SnapApplication
from fpakman.core.worker import AsyncDataLoader
from fpakman.util.cache import Cache
class SnapAsyncDataLoader(AsyncDataLoader):
def __init__(self, app: SnapApplication, manager: ApplicationManager, http_session, api_cache: Cache, download_icons: bool, attempts: int = 2, timeout: int = 30):
super(SnapAsyncDataLoader, self).__init__(app=app)
self.manager = manager
self.http_session = http_session
self.attempts = attempts
self.api_cache = api_cache
self.timeout = timeout
self.persist = False
self.download_icons = download_icons
def run(self):
if self.app:
self.app.status = ApplicationStatus.LOADING_DATA
for _ in range(0, self.attempts):
try:
res = self.http_session.get('{}/search?q={}'.format(SNAP_API_URL, self.app.base_data.name), timeout=self.timeout)
if res.status_code == 200 and res.text:
try:
snap_list = res.json()['_embedded']['clickindex:package']
except:
self.log_msg('Snap API response responded differently from expected for app: {}'.format(self.app.base_data.name))
break
if not snap_list:
break
snap_data = snap_list[0]
api_data = {
'confinement': snap_data.get('confinement'),
'description': snap_data.get('description'),
'icon_url': snap_data.get('icon_url') if self.download_icons else None
}
self.api_cache.add(self.app.base_data.id, api_data)
self.app.confinement = api_data['confinement']
self.app.base_data.icon_url = api_data['icon_url']
if not api_data.get('description'):
api_data['description'] = snap.get_info(self.app.base_data.name, ('description',)).get('description')
self.app.base_data.description = api_data['description']
self.app.status = ApplicationStatus.READY
self.persist = self.app.supports_disk_cache()
break
else:
self.log_msg("Could not retrieve app data for id '{}'. Server response: {}. Body: {}".format(self.app.base_data.id, res.status_code, res.content.decode()), Fore.RED)
except:
self.log_msg("Could not retrieve app data for id '{}'".format(self.app.base_data.id), Fore.YELLOW)
traceback.print_exc()
time.sleep(0.5)
self.app.status = ApplicationStatus.READY
if self.persist:
self.manager.cache_to_disk(app=self.app, icon_bytes=None, only_icon=False)
def clone(self) -> "SnapAsyncDataLoader":
return SnapAsyncDataLoader(manager=self.manager,
api_cache=self.api_cache,
attempts=self.attempts,
http_session=self.http_session,
timeout=self.timeout,
app=self.app)

View File

@@ -1,51 +0,0 @@
import os
import subprocess
from typing import List
from fpakman import __app_name__
from fpakman.core import resource
class FpakmanProcess:
def __init__(self, subproc: subprocess.Popen, success_phrase: str = None, wrong_error_phrase: str = '[sudo] password for'):
self.subproc = subproc
self.success_pgrase = success_phrase
self.wrong_error_phrase = wrong_error_phrase
def run_cmd(cmd: str, expected_code: int = 0, ignore_return_code: bool = False, print_error: bool = True) -> str:
args = {
"shell": True,
"stdout": subprocess.PIPE,
"env": {'LANG': 'en'}
}
if not print_error:
args["stderr"] = subprocess.DEVNULL
res = subprocess.run(cmd, **args)
return res.stdout.decode() if ignore_return_code or res.returncode == expected_code else None
def stream_cmd(cmd: List[str]):
return cmd_to_subprocess(cmd).stdout
def cmd_to_subprocess(cmd: List[str]):
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env={'LANG': 'en'})
def notify_user(msg: str, icon_path: str = resource.get_path('img/logo.svg')):
os.system("notify-send -a {} {} '{}'".format(__app_name__, "-i {}".format(icon_path) if icon_path else '', msg))
def cmd_as_root(cmd: List[str], root_password: str) -> subprocess.Popen:
pwdin, final_cmd = None, []
if root_password is not None:
final_cmd.extend(['sudo', '-S'])
pwdin = stream_cmd(['echo', root_password])
final_cmd.extend(cmd)
return subprocess.Popen(final_cmd, stdin=pwdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

View File

@@ -1,31 +0,0 @@
from io import StringIO
from threading import Thread
from colorama import Fore
from fpakman.core.model import Application
class AsyncDataLoader(Thread):
def __init__(self, app: Application):
super(AsyncDataLoader, self).__init__(daemon=True)
self.id_ = '{}#{}'.format(self.__class__.__name__, id(self))
self.app = app
def log_msg(self, msg: str, color: int = None):
final_msg = StringIO()
if color:
final_msg.write(str(color))
final_msg.write('[{}] '.format(self.id_))
final_msg.write(msg)
if color:
final_msg.write(Fore.RESET)
final_msg.seek(0)
print(final_msg.read())

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,3 +1,4 @@
pyqt5>=5.12
requests>=2.22
colorama>=0.4.1
fpakman_api==0.1.0