snaps: integrating with Ubuntu search API

This commit is contained in:
Vinicius Moreira
2019-07-25 16:55:49 -03:00
parent b674bb2584
commit 2db0e4c79f
7 changed files with 40 additions and 44 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/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.4.1]
### Improvements
- retrieving some Snaps data (icon, description and confinement) through Ubuntu API instead of Snap Store
## [0.4.0] - 2019-07-25 ## [0.4.0] - 2019-07-25
### Features ### Features
- supporting snaps - supporting snaps

View File

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

View File

@@ -114,7 +114,7 @@ class SnapManager(ApplicationManager):
return [] return []
def install_and_stream(self, app: SnapApplication, root_password: str) -> FpakmanProcess: def install_and_stream(self, app: SnapApplication, root_password: str) -> FpakmanProcess:
return FpakmanProcess(subproc=snap.install_and_stream(app.base_data.name, app.install_cmd, root_password)) return FpakmanProcess(subproc=snap.install_and_stream(app.base_data.name, app.confinement, root_password))
def is_enabled(self) -> bool: def is_enabled(self) -> bool:
return snap.is_installed() return snap.is_installed()

View File

@@ -5,13 +5,13 @@ from fpakman.core.snap.constants import SNAP_CACHE_PATH
class SnapApplication(Application): class SnapApplication(Application):
def __init__(self, base_data: ApplicationData, publisher: str, rev: str, notes: str, app_type: str, install_cmd: str = None): 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) super(SnapApplication, self).__init__(base_data=base_data)
self.publisher = publisher self.publisher = publisher
self.rev = rev self.rev = rev
self.notes = notes self.notes = notes
self.type = app_type self.type = app_type
self.install_cmd = install_cmd self.confinement = confinement
def has_history(self): def has_history(self):
return False return False
@@ -46,7 +46,7 @@ class SnapApplication(Application):
def get_data_to_cache(self): def get_data_to_cache(self):
return { return {
"icon_url": self.base_data.icon_url, "icon_url": self.base_data.icon_url,
'install_cmd': self.install_cmd, 'confinement': self.confinement,
'description': self.base_data.description 'description': self.base_data.description
} }
@@ -56,5 +56,5 @@ class SnapApplication(Application):
if data.get(base_attr): if data.get(base_attr):
setattr(self.base_data, base_attr, data[base_attr]) setattr(self.base_data, base_attr, data[base_attr])
if data.get('install_cmd'): if data.get('confinement'):
self.install_cmd = data['install_cmd'] self.confinement = data['confinement']

View File

@@ -2,11 +2,7 @@ import re
import subprocess import subprocess
from typing import List from typing import List
import requests
from bs4 import BeautifulSoup
from fpakman.core import system from fpakman.core import system
from fpakman.core.snap.constants import SNAP_STORE_URL
BASE_CMD = 'snap' BASE_CMD = 'snap'
@@ -120,19 +116,12 @@ def uninstall_and_stream(app_name: str, root_password: str):
return system.cmd_as_root([BASE_CMD, 'remove', app_name], root_password) return system.cmd_as_root([BASE_CMD, 'remove', app_name], root_password)
def install_and_stream(app_name: str, custom_install_cmd: str, root_password: str) -> subprocess.Popen: def install_and_stream(app_name: str, confinement: str, root_password: str) -> subprocess.Popen:
install_cmd = [BASE_CMD, 'install', app_name] # default install_cmd = [BASE_CMD, 'install', app_name] # default
if custom_install_cmd: if confinement == 'classic':
install_cmd = custom_install_cmd.split(' ') install_cmd.append('--classic')
else: # tries to retrieve the snapstore proper installation command
res = requests.get('{}/{}'.format(SNAP_STORE_URL, app_name))
if res.status_code == 200:
soup = BeautifulSoup(res.text, 'html.parser')
input_install_cmd = soup.find("input", {"id": "snap-install"})
install_cmd = input_install_cmd.get("value").strip().split(' ')
return system.cmd_as_root(install_cmd, root_password) return system.cmd_as_root(install_cmd, root_password)

View File

@@ -1,13 +1,12 @@
import time import time
import traceback import traceback
from bs4 import BeautifulSoup
from colorama import Fore from colorama import Fore
from fpakman.core.controller import ApplicationManager from fpakman.core.controller import ApplicationManager
from fpakman.core.model import ApplicationStatus from fpakman.core.model import ApplicationStatus
from fpakman.core.snap import snap from fpakman.core.snap import snap
from fpakman.core.snap.constants import SNAP_STORE_URL from fpakman.core.snap.constants import SNAP_API_URL
from fpakman.core.snap.model import SnapApplication from fpakman.core.snap.model import SnapApplication
from fpakman.core.worker import AsyncDataLoader from fpakman.core.worker import AsyncDataLoader
from fpakman.util.cache import Cache from fpakman.util.cache import Cache
@@ -28,34 +27,39 @@ class SnapAsyncDataLoader(AsyncDataLoader):
def run(self): def run(self):
if self.app: if self.app:
self.app.status = ApplicationStatus.LOADING_DATA self.app.status = ApplicationStatus.LOADING_DATA
if not self.app.base_data.description:
self.app.base_data.description = snap.get_info(self.app.base_data.name, ('description',)).get('description')
for _ in range(0, self.attempts): for _ in range(0, self.attempts):
try: try:
res = self.http_session.get('{}/{}'.format(SNAP_STORE_URL, self.app.base_data.name), res = self.http_session.get('{}/search?q={}'.format(SNAP_API_URL, self.app.base_data.name), timeout=self.timeout)
timeout=self.timeout)
if res.status_code == 200 and res.text: if res.status_code == 200 and res.text:
soup = BeautifulSoup(res.text, 'html.parser')
input_install_cmd = soup.find("input", {"id": "snap-install"}) 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 = { api_data = {
'install_cmd': input_install_cmd.get("value").strip(), 'confinement': snap_data.get('confinement'),
'description': self.app.base_data.description 'description': snap_data.get('description'),
'icon_url': snap_data.get('icon_url') if self.download_icons else None
} }
img_icon = None
if self.download_icons:
img_icon = soup.find('img', {"class": "p-snap-heading__icon"})
if img_icon and img_icon.get("src") and 'snapcraft-missing-icon' not in img_icon.get('src'):
api_data['icon_url'] = img_icon.get("src")
self.api_cache.add(self.app.base_data.id, api_data) self.api_cache.add(self.app.base_data.id, api_data)
self.app.install_cmd = api_data['install_cmd'] self.app.confinement = api_data['confinement']
self.app.base_data.icon_url = api_data.get('icon_url') 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.app.status = ApplicationStatus.READY
if self.app.supports_disk_cache(): if self.app.supports_disk_cache():
@@ -65,7 +69,7 @@ class SnapAsyncDataLoader(AsyncDataLoader):
else: 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) 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: except:
self.log_msg("Could not retrieve app data for id '{}'".format(app.base_data.id), Fore.YELLOW) self.log_msg("Could not retrieve app data for id '{}'".format(self.app.base_data.id), Fore.YELLOW)
traceback.print_exc() traceback.print_exc()
time.sleep(0.5) time.sleep(0.5)

View File

@@ -1,4 +1,3 @@
pyqt5>=5.12 pyqt5>=5.12
requests>=2.22 requests>=2.22
colorama>=0.4.1 colorama>=0.4.1
beautifulsoup4>=4.7