diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b79b552..93843031 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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.4.1] +### Improvements +- retrieving some Snaps data (icon, description and confinement) through Ubuntu API instead of Snap Store + ## [0.4.0] - 2019-07-25 ### Features - supporting snaps diff --git a/fpakman/core/snap/constants.py b/fpakman/core/snap/constants.py index 10a2c460..50b11b69 100644 --- a/fpakman/core/snap/constants.py +++ b/fpakman/core/snap/constants.py @@ -1,4 +1,4 @@ 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) diff --git a/fpakman/core/snap/controller.py b/fpakman/core/snap/controller.py index 4f53ee27..6c03e147 100644 --- a/fpakman/core/snap/controller.py +++ b/fpakman/core/snap/controller.py @@ -114,7 +114,7 @@ class SnapManager(ApplicationManager): return [] 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: return snap.is_installed() diff --git a/fpakman/core/snap/model.py b/fpakman/core/snap/model.py index 2b8c32dd..0daa9f27 100644 --- a/fpakman/core/snap/model.py +++ b/fpakman/core/snap/model.py @@ -5,13 +5,13 @@ 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, 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) self.publisher = publisher self.rev = rev self.notes = notes self.type = app_type - self.install_cmd = install_cmd + self.confinement = confinement def has_history(self): return False @@ -46,7 +46,7 @@ class SnapApplication(Application): def get_data_to_cache(self): return { "icon_url": self.base_data.icon_url, - 'install_cmd': self.install_cmd, + 'confinement': self.confinement, 'description': self.base_data.description } @@ -56,5 +56,5 @@ class SnapApplication(Application): if data.get(base_attr): setattr(self.base_data, base_attr, data[base_attr]) - if data.get('install_cmd'): - self.install_cmd = data['install_cmd'] + if data.get('confinement'): + self.confinement = data['confinement'] diff --git a/fpakman/core/snap/snap.py b/fpakman/core/snap/snap.py index ea2da302..bc8520fa 100644 --- a/fpakman/core/snap/snap.py +++ b/fpakman/core/snap/snap.py @@ -2,11 +2,7 @@ import re import subprocess from typing import List -import requests -from bs4 import BeautifulSoup - from fpakman.core import system -from fpakman.core.snap.constants import SNAP_STORE_URL 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) -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 - if custom_install_cmd: - install_cmd = custom_install_cmd.split(' ') - 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(' ') + if confinement == 'classic': + install_cmd.append('--classic') return system.cmd_as_root(install_cmd, root_password) diff --git a/fpakman/core/snap/worker.py b/fpakman/core/snap/worker.py index 7c9d775e..27679353 100644 --- a/fpakman/core/snap/worker.py +++ b/fpakman/core/snap/worker.py @@ -1,13 +1,12 @@ import time import traceback -from bs4 import BeautifulSoup 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_STORE_URL +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 @@ -28,34 +27,39 @@ class SnapAsyncDataLoader(AsyncDataLoader): def run(self): if self.app: 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): try: - res = self.http_session.get('{}/{}'.format(SNAP_STORE_URL, self.app.base_data.name), - timeout=self.timeout) + 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: - 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 = { - 'install_cmd': input_install_cmd.get("value").strip(), - 'description': self.app.base_data.description + 'confinement': snap_data.get('confinement'), + '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.app.install_cmd = api_data['install_cmd'] - self.app.base_data.icon_url = api_data.get('icon_url') + 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 if self.app.supports_disk_cache(): @@ -65,7 +69,7 @@ class SnapAsyncDataLoader(AsyncDataLoader): 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(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() time.sleep(0.5) diff --git a/requirements.txt b/requirements.txt index 256d8361..3415a156 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ pyqt5>=5.12 requests>=2.22 -colorama>=0.4.1 -beautifulsoup4>=4.7 \ No newline at end of file +colorama>=0.4.1 \ No newline at end of file